1 /* 2 * Copyright 2002-2003 Jason Edmeades 3 * Copyright 2002-2003 Raphael Junqueira 4 * Copyright 2005 Oliver Stieber 5 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers 6 * Copyright 2011 Henri Verbeet for CodeWeavers 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 23 #include "wined3d_private.h" 24 25 WINE_DEFAULT_DEBUG_CHANNEL(d3d); 26 WINE_DECLARE_DEBUG_CHANNEL(fps); 27 28 static void wined3d_swapchain_destroy_object(void *object) 29 { 30 swapchain_destroy_contexts(object); 31 } 32 33 static void swapchain_cleanup(struct wined3d_swapchain *swapchain) 34 { 35 HRESULT hr; 36 UINT i; 37 38 TRACE("Destroying swapchain %p.\n", swapchain); 39 40 wined3d_swapchain_set_gamma_ramp(swapchain, 0, &swapchain->orig_gamma); 41 42 /* Release the swapchain's draw buffers. Make sure swapchain->back_buffers[0] 43 * is the last buffer to be destroyed, FindContext() depends on that. */ 44 if (swapchain->front_buffer) 45 { 46 wined3d_texture_set_swapchain(swapchain->front_buffer, NULL); 47 if (wined3d_texture_decref(swapchain->front_buffer)) 48 WARN("Something's still holding the front buffer (%p).\n", swapchain->front_buffer); 49 swapchain->front_buffer = NULL; 50 } 51 52 if (swapchain->back_buffers) 53 { 54 i = swapchain->desc.backbuffer_count; 55 56 while (i--) 57 { 58 wined3d_texture_set_swapchain(swapchain->back_buffers[i], NULL); 59 if (wined3d_texture_decref(swapchain->back_buffers[i])) 60 WARN("Something's still holding back buffer %u (%p).\n", i, swapchain->back_buffers[i]); 61 } 62 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers); 63 swapchain->back_buffers = NULL; 64 } 65 66 wined3d_cs_destroy_object(swapchain->device->cs, wined3d_swapchain_destroy_object, swapchain); 67 swapchain->device->cs->ops->finish(swapchain->device->cs, WINED3D_CS_QUEUE_DEFAULT); 68 69 /* Restore the screen resolution if we rendered in fullscreen. 70 * This will restore the screen resolution to what it was before creating 71 * the swapchain. In case of d3d8 and d3d9 this will be the original 72 * desktop resolution. In case of d3d7 this will be a NOP because ddraw 73 * sets the resolution before starting up Direct3D, thus orig_width and 74 * orig_height will be equal to the modes in the presentation params. */ 75 if (!swapchain->desc.windowed && swapchain->desc.auto_restore_display_mode) 76 { 77 if (FAILED(hr = wined3d_set_adapter_display_mode(swapchain->device->wined3d, 78 swapchain->device->adapter->ordinal, &swapchain->original_mode))) 79 ERR("Failed to restore display mode, hr %#x.\n", hr); 80 81 if (swapchain->desc.flags & WINED3D_SWAPCHAIN_RESTORE_WINDOW_RECT) 82 { 83 wined3d_device_restore_fullscreen_window(swapchain->device, swapchain->device_window, 84 &swapchain->original_window_rect); 85 wined3d_device_release_focus_window(swapchain->device); 86 } 87 } 88 89 if (swapchain->backup_dc) 90 { 91 TRACE("Destroying backup wined3d window %p, dc %p.\n", swapchain->backup_wnd, swapchain->backup_dc); 92 93 wined3d_release_dc(swapchain->backup_wnd, swapchain->backup_dc); 94 DestroyWindow(swapchain->backup_wnd); 95 } 96 } 97 98 ULONG CDECL wined3d_swapchain_incref(struct wined3d_swapchain *swapchain) 99 { 100 ULONG refcount = InterlockedIncrement(&swapchain->ref); 101 102 TRACE("%p increasing refcount to %u.\n", swapchain, refcount); 103 104 return refcount; 105 } 106 107 ULONG CDECL wined3d_swapchain_decref(struct wined3d_swapchain *swapchain) 108 { 109 ULONG refcount = InterlockedDecrement(&swapchain->ref); 110 111 TRACE("%p decreasing refcount to %u.\n", swapchain, refcount); 112 113 if (!refcount) 114 { 115 struct wined3d_device *device = swapchain->device; 116 117 device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); 118 119 swapchain_cleanup(swapchain); 120 swapchain->parent_ops->wined3d_object_destroyed(swapchain->parent); 121 HeapFree(GetProcessHeap(), 0, swapchain); 122 } 123 124 return refcount; 125 } 126 127 void * CDECL wined3d_swapchain_get_parent(const struct wined3d_swapchain *swapchain) 128 { 129 TRACE("swapchain %p.\n", swapchain); 130 131 return swapchain->parent; 132 } 133 134 void CDECL wined3d_swapchain_set_window(struct wined3d_swapchain *swapchain, HWND window) 135 { 136 if (!window) 137 window = swapchain->device_window; 138 if (window == swapchain->win_handle) 139 return; 140 141 TRACE("Setting swapchain %p window from %p to %p.\n", 142 swapchain, swapchain->win_handle, window); 143 swapchain->win_handle = window; 144 } 145 146 HRESULT CDECL wined3d_swapchain_present(struct wined3d_swapchain *swapchain, 147 const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override, DWORD flags) 148 { 149 RECT s, d; 150 151 TRACE("swapchain %p, src_rect %s, dst_rect %s, dst_window_override %p, flags %#x.\n", 152 swapchain, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect), 153 dst_window_override, flags); 154 155 if (flags) 156 FIXME("Ignoring flags %#x.\n", flags); 157 158 if (!swapchain->back_buffers) 159 { 160 WARN("Swapchain doesn't have a backbuffer, returning WINED3DERR_INVALIDCALL\n"); 161 return WINED3DERR_INVALIDCALL; 162 } 163 164 if (!src_rect) 165 { 166 SetRect(&s, 0, 0, swapchain->desc.backbuffer_width, 167 swapchain->desc.backbuffer_height); 168 src_rect = &s; 169 } 170 171 if (!dst_rect) 172 { 173 GetClientRect(swapchain->win_handle, &d); 174 dst_rect = &d; 175 } 176 177 wined3d_cs_emit_present(swapchain->device->cs, swapchain, src_rect, 178 dst_rect, dst_window_override, flags); 179 180 return WINED3D_OK; 181 } 182 183 HRESULT CDECL wined3d_swapchain_get_front_buffer_data(const struct wined3d_swapchain *swapchain, 184 struct wined3d_texture *dst_texture, unsigned int sub_resource_idx) 185 { 186 RECT src_rect, dst_rect; 187 188 TRACE("swapchain %p, dst_texture %p, sub_resource_idx %u.\n", swapchain, dst_texture, sub_resource_idx); 189 190 SetRect(&src_rect, 0, 0, swapchain->front_buffer->resource.width, swapchain->front_buffer->resource.height); 191 dst_rect = src_rect; 192 193 if (swapchain->desc.windowed) 194 { 195 MapWindowPoints(swapchain->win_handle, NULL, (POINT *)&dst_rect, 2); 196 FIXME("Using destination rect %s in windowed mode, this is likely wrong.\n", 197 wine_dbgstr_rect(&dst_rect)); 198 } 199 200 return wined3d_texture_blt(dst_texture, sub_resource_idx, &dst_rect, 201 swapchain->front_buffer, 0, &src_rect, 0, NULL, WINED3D_TEXF_POINT); 202 } 203 204 struct wined3d_texture * CDECL wined3d_swapchain_get_back_buffer(const struct wined3d_swapchain *swapchain, 205 UINT back_buffer_idx) 206 { 207 TRACE("swapchain %p, back_buffer_idx %u.\n", 208 swapchain, back_buffer_idx); 209 210 /* Return invalid if there is no backbuffer array, otherwise it will 211 * crash when ddraw is used (there swapchain->back_buffers is always 212 * NULL). We need this because this function is called from 213 * stateblock_init_default_state() to get the default scissorrect 214 * dimensions. */ 215 if (!swapchain->back_buffers || back_buffer_idx >= swapchain->desc.backbuffer_count) 216 { 217 WARN("Invalid back buffer index.\n"); 218 /* Native d3d9 doesn't set NULL here, just as wine's d3d9. But set it 219 * here in wined3d to avoid problems in other libs. */ 220 return NULL; 221 } 222 223 TRACE("Returning back buffer %p.\n", swapchain->back_buffers[back_buffer_idx]); 224 225 return swapchain->back_buffers[back_buffer_idx]; 226 } 227 228 HRESULT CDECL wined3d_swapchain_get_raster_status(const struct wined3d_swapchain *swapchain, 229 struct wined3d_raster_status *raster_status) 230 { 231 TRACE("swapchain %p, raster_status %p.\n", swapchain, raster_status); 232 233 return wined3d_get_adapter_raster_status(swapchain->device->wined3d, 234 swapchain->device->adapter->ordinal, raster_status); 235 } 236 237 HRESULT CDECL wined3d_swapchain_get_display_mode(const struct wined3d_swapchain *swapchain, 238 struct wined3d_display_mode *mode, enum wined3d_display_rotation *rotation) 239 { 240 HRESULT hr; 241 242 TRACE("swapchain %p, mode %p, rotation %p.\n", swapchain, mode, rotation); 243 244 hr = wined3d_get_adapter_display_mode(swapchain->device->wined3d, 245 swapchain->device->adapter->ordinal, mode, rotation); 246 247 TRACE("Returning w %u, h %u, refresh rate %u, format %s.\n", 248 mode->width, mode->height, mode->refresh_rate, debug_d3dformat(mode->format_id)); 249 250 return hr; 251 } 252 253 struct wined3d_device * CDECL wined3d_swapchain_get_device(const struct wined3d_swapchain *swapchain) 254 { 255 TRACE("swapchain %p.\n", swapchain); 256 257 return swapchain->device; 258 } 259 260 void CDECL wined3d_swapchain_get_desc(const struct wined3d_swapchain *swapchain, 261 struct wined3d_swapchain_desc *desc) 262 { 263 TRACE("swapchain %p, desc %p.\n", swapchain, desc); 264 265 *desc = swapchain->desc; 266 } 267 268 HRESULT CDECL wined3d_swapchain_set_gamma_ramp(const struct wined3d_swapchain *swapchain, 269 DWORD flags, const struct wined3d_gamma_ramp *ramp) 270 { 271 HDC dc; 272 273 TRACE("swapchain %p, flags %#x, ramp %p.\n", swapchain, flags, ramp); 274 275 if (flags) 276 FIXME("Ignoring flags %#x.\n", flags); 277 278 dc = GetDCEx(swapchain->device_window, 0, DCX_USESTYLE | DCX_CACHE); 279 SetDeviceGammaRamp(dc, (void *)ramp); 280 ReleaseDC(swapchain->device_window, dc); 281 282 return WINED3D_OK; 283 } 284 285 void CDECL wined3d_swapchain_set_palette(struct wined3d_swapchain *swapchain, struct wined3d_palette *palette) 286 { 287 TRACE("swapchain %p, palette %p.\n", swapchain, palette); 288 swapchain->palette = palette; 289 } 290 291 HRESULT CDECL wined3d_swapchain_get_gamma_ramp(const struct wined3d_swapchain *swapchain, 292 struct wined3d_gamma_ramp *ramp) 293 { 294 HDC dc; 295 296 TRACE("swapchain %p, ramp %p.\n", swapchain, ramp); 297 298 dc = GetDCEx(swapchain->device_window, 0, DCX_USESTYLE | DCX_CACHE); 299 GetDeviceGammaRamp(dc, ramp); 300 ReleaseDC(swapchain->device_window, dc); 301 302 return WINED3D_OK; 303 } 304 305 /* A GL context is provided by the caller */ 306 static void swapchain_blit(const struct wined3d_swapchain *swapchain, 307 struct wined3d_context *context, const RECT *src_rect, const RECT *dst_rect) 308 { 309 struct wined3d_texture *texture = swapchain->back_buffers[0]; 310 struct wined3d_surface *back_buffer = texture->sub_resources[0].u.surface; 311 struct wined3d_device *device = swapchain->device; 312 enum wined3d_texture_filter_type filter; 313 DWORD location; 314 315 TRACE("swapchain %p, context %p, src_rect %s, dst_rect %s.\n", 316 swapchain, context, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect)); 317 318 if ((src_rect->right - src_rect->left == dst_rect->right - dst_rect->left 319 && src_rect->bottom - src_rect->top == dst_rect->bottom - dst_rect->top) 320 || is_complex_fixup(texture->resource.format->color_fixup)) 321 filter = WINED3D_TEXF_NONE; 322 else 323 filter = WINED3D_TEXF_LINEAR; 324 325 location = WINED3D_LOCATION_TEXTURE_RGB; 326 if (texture->resource.multisample_type) 327 location = WINED3D_LOCATION_RB_RESOLVED; 328 329 wined3d_texture_validate_location(texture, 0, WINED3D_LOCATION_DRAWABLE); 330 device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_COLOR_BLIT, context, back_buffer, 331 location, src_rect, back_buffer, WINED3D_LOCATION_DRAWABLE, dst_rect, NULL, filter); 332 wined3d_texture_invalidate_location(texture, 0, WINED3D_LOCATION_DRAWABLE); 333 } 334 335 /* Context activation is done by the caller. */ 336 static void wined3d_swapchain_rotate(struct wined3d_swapchain *swapchain, struct wined3d_context *context) 337 { 338 struct wined3d_texture_sub_resource *sub_resource; 339 struct wined3d_texture *texture, *texture_prev; 340 struct gl_texture tex0; 341 GLuint rb0; 342 DWORD locations0; 343 unsigned int i; 344 static const DWORD supported_locations = WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_RB_MULTISAMPLE; 345 346 if (swapchain->desc.backbuffer_count < 2 || !swapchain->render_to_fbo) 347 return; 348 349 texture_prev = swapchain->back_buffers[0]; 350 351 /* Back buffer 0 is already in the draw binding. */ 352 tex0 = texture_prev->texture_rgb; 353 rb0 = texture_prev->rb_multisample; 354 locations0 = texture_prev->sub_resources[0].locations; 355 356 for (i = 1; i < swapchain->desc.backbuffer_count; ++i) 357 { 358 texture = swapchain->back_buffers[i]; 359 sub_resource = &texture->sub_resources[0]; 360 361 if (!(sub_resource->locations & supported_locations)) 362 wined3d_texture_load_location(texture, 0, context, texture->resource.draw_binding); 363 364 texture_prev->texture_rgb = texture->texture_rgb; 365 texture_prev->rb_multisample = texture->rb_multisample; 366 367 wined3d_texture_validate_location(texture_prev, 0, sub_resource->locations & supported_locations); 368 wined3d_texture_invalidate_location(texture_prev, 0, ~(sub_resource->locations & supported_locations)); 369 370 texture_prev = texture; 371 } 372 373 texture_prev->texture_rgb = tex0; 374 texture_prev->rb_multisample = rb0; 375 376 wined3d_texture_validate_location(texture_prev, 0, locations0 & supported_locations); 377 wined3d_texture_invalidate_location(texture_prev, 0, ~(locations0 & supported_locations)); 378 379 device_invalidate_state(swapchain->device, STATE_FRAMEBUFFER); 380 } 381 382 static void swapchain_gl_present(struct wined3d_swapchain *swapchain, 383 const RECT *src_rect, const RECT *dst_rect, DWORD flags) 384 { 385 struct wined3d_texture *back_buffer = swapchain->back_buffers[0]; 386 const struct wined3d_fb_state *fb = &swapchain->device->cs->fb; 387 const struct wined3d_gl_info *gl_info; 388 struct wined3d_texture *logo_texture; 389 struct wined3d_context *context; 390 BOOL render_to_fbo; 391 392 context = context_acquire(swapchain->device, back_buffer, 0); 393 if (!context->valid) 394 { 395 context_release(context); 396 WARN("Invalid context, skipping present.\n"); 397 return; 398 } 399 400 gl_info = context->gl_info; 401 402 if ((logo_texture = swapchain->device->logo_texture)) 403 { 404 RECT rect = {0, 0, logo_texture->resource.width, logo_texture->resource.height}; 405 406 /* Blit the logo into the upper left corner of the drawable. */ 407 wined3d_texture_blt(back_buffer, 0, &rect, logo_texture, 0, &rect, 408 WINED3D_BLT_SRC_CKEY, NULL, WINED3D_TEXF_POINT); 409 } 410 411 if (swapchain->device->bCursorVisible && swapchain->device->cursor_texture 412 && !swapchain->device->hardwareCursor) 413 { 414 RECT dst_rect = 415 { 416 swapchain->device->xScreenSpace - swapchain->device->xHotSpot, 417 swapchain->device->yScreenSpace - swapchain->device->yHotSpot, 418 swapchain->device->xScreenSpace + swapchain->device->cursorWidth - swapchain->device->xHotSpot, 419 swapchain->device->yScreenSpace + swapchain->device->cursorHeight - swapchain->device->yHotSpot, 420 }; 421 RECT src_rect = 422 { 423 0, 0, 424 swapchain->device->cursor_texture->resource.width, 425 swapchain->device->cursor_texture->resource.height 426 }; 427 const RECT clip_rect = {0, 0, back_buffer->resource.width, back_buffer->resource.height}; 428 429 TRACE("Rendering the software cursor.\n"); 430 431 if (swapchain->desc.windowed) 432 MapWindowPoints(NULL, swapchain->win_handle, (POINT *)&dst_rect, 2); 433 if (wined3d_clip_blit(&clip_rect, &dst_rect, &src_rect)) 434 wined3d_texture_blt(back_buffer, 0, &dst_rect, 435 swapchain->device->cursor_texture, 0, &src_rect, 436 WINED3D_BLT_ALPHA_TEST, NULL, WINED3D_TEXF_POINT); 437 } 438 439 TRACE("Presenting HDC %p.\n", context->hdc); 440 441 if (!(render_to_fbo = swapchain->render_to_fbo) 442 && (src_rect->left || src_rect->top 443 || src_rect->right != swapchain->desc.backbuffer_width 444 || src_rect->bottom != swapchain->desc.backbuffer_height 445 || dst_rect->left || dst_rect->top 446 || dst_rect->right != swapchain->desc.backbuffer_width 447 || dst_rect->bottom != swapchain->desc.backbuffer_height)) 448 render_to_fbo = TRUE; 449 450 /* Rendering to a window of different size, presenting partial rectangles, 451 * or rendering to a different window needs help from FBO_blit or a textured 452 * draw. Render the swapchain to a FBO in the future. 453 * 454 * Note that FBO_blit from the backbuffer to the frontbuffer cannot solve 455 * all these issues - this fails if the window is smaller than the backbuffer. 456 */ 457 if (!swapchain->render_to_fbo && render_to_fbo && wined3d_settings.offscreen_rendering_mode == ORM_FBO) 458 { 459 wined3d_texture_load_location(back_buffer, 0, context, WINED3D_LOCATION_TEXTURE_RGB); 460 wined3d_texture_invalidate_location(back_buffer, 0, WINED3D_LOCATION_DRAWABLE); 461 swapchain->render_to_fbo = TRUE; 462 swapchain_update_draw_bindings(swapchain); 463 } 464 else 465 { 466 wined3d_texture_load_location(back_buffer, 0, context, back_buffer->resource.draw_binding); 467 } 468 469 if (swapchain->render_to_fbo) 470 { 471 static unsigned int once; 472 473 if (swapchain->desc.swap_effect == WINED3D_SWAP_EFFECT_FLIP && !once++) 474 FIXME("WINED3D_SWAP_EFFECT_FLIP not implemented.\n"); 475 476 swapchain_blit(swapchain, context, src_rect, dst_rect); 477 } 478 479 if (swapchain->num_contexts > 1) 480 gl_info->gl_ops.gl.p_glFinish(); 481 482 /* call wglSwapBuffers through the gl table to avoid confusing the Steam overlay */ 483 gl_info->gl_ops.wgl.p_wglSwapBuffers(context->hdc); 484 485 wined3d_swapchain_rotate(swapchain, context); 486 487 TRACE("SwapBuffers called, Starting new frame\n"); 488 /* FPS support */ 489 if (TRACE_ON(fps)) 490 { 491 DWORD time = GetTickCount(); 492 ++swapchain->frames; 493 494 /* every 1.5 seconds */ 495 if (time - swapchain->prev_time > 1500) 496 { 497 TRACE_(fps)("%p @ approx %.2ffps\n", 498 swapchain, 1000.0 * swapchain->frames / (time - swapchain->prev_time)); 499 swapchain->prev_time = time; 500 swapchain->frames = 0; 501 } 502 } 503 504 wined3d_texture_validate_location(swapchain->front_buffer, 0, WINED3D_LOCATION_DRAWABLE); 505 wined3d_texture_invalidate_location(swapchain->front_buffer, 0, ~WINED3D_LOCATION_DRAWABLE); 506 /* If the swapeffect is DISCARD, the back buffer is undefined. That means the SYSMEM 507 * and INTEXTURE copies can keep their old content if they have any defined content. 508 * If the swapeffect is COPY, the content remains the same. 509 * 510 * The FLIP swap effect is not implemented yet. We could mark WINED3D_LOCATION_DRAWABLE 511 * up to date and hope WGL flipped front and back buffers and read this data into 512 * the FBO. Don't bother about this for now. */ 513 if (swapchain->desc.swap_effect == WINED3D_SWAP_EFFECT_DISCARD) 514 wined3d_texture_validate_location(swapchain->back_buffers[swapchain->desc.backbuffer_count - 1], 515 0, WINED3D_LOCATION_DISCARDED); 516 517 if (fb->depth_stencil) 518 { 519 struct wined3d_surface *ds = wined3d_rendertarget_view_get_surface(fb->depth_stencil); 520 521 if (ds && (swapchain->desc.flags & WINED3D_SWAPCHAIN_DISCARD_DEPTHSTENCIL 522 || ds->container->flags & WINED3D_TEXTURE_DISCARD)) 523 wined3d_texture_validate_location(ds->container, 524 fb->depth_stencil->sub_resource_idx, WINED3D_LOCATION_DISCARDED); 525 } 526 527 context_release(context); 528 } 529 530 static void swapchain_gl_frontbuffer_updated(struct wined3d_swapchain *swapchain) 531 { 532 struct wined3d_texture *front_buffer = swapchain->front_buffer; 533 struct wined3d_context *context; 534 535 context = context_acquire(swapchain->device, front_buffer, 0); 536 wined3d_texture_load_location(front_buffer, 0, context, front_buffer->resource.draw_binding); 537 context_release(context); 538 SetRectEmpty(&swapchain->front_buffer_update); 539 } 540 541 static const struct wined3d_swapchain_ops swapchain_gl_ops = 542 { 543 swapchain_gl_present, 544 swapchain_gl_frontbuffer_updated, 545 }; 546 547 static void swapchain_gdi_frontbuffer_updated(struct wined3d_swapchain *swapchain) 548 { 549 struct wined3d_surface *front; 550 POINT offset = {0, 0}; 551 HDC src_dc, dst_dc; 552 RECT draw_rect; 553 HWND window; 554 555 TRACE("swapchain %p.\n", swapchain); 556 557 front = swapchain->front_buffer->sub_resources[0].u.surface; 558 if (swapchain->palette) 559 wined3d_palette_apply_to_dc(swapchain->palette, front->dc); 560 561 if (front->container->resource.map_count) 562 ERR("Trying to blit a mapped surface.\n"); 563 564 TRACE("Copying surface %p to screen.\n", front); 565 566 src_dc = front->dc; 567 window = swapchain->win_handle; 568 dst_dc = GetDCEx(window, 0, DCX_CLIPSIBLINGS | DCX_CACHE); 569 570 /* Front buffer coordinates are screen coordinates. Map them to the 571 * destination window if not fullscreened. */ 572 if (swapchain->desc.windowed) 573 ClientToScreen(window, &offset); 574 575 TRACE("offset %s.\n", wine_dbgstr_point(&offset)); 576 577 SetRect(&draw_rect, 0, 0, swapchain->front_buffer->resource.width, 578 swapchain->front_buffer->resource.height); 579 IntersectRect(&draw_rect, &draw_rect, &swapchain->front_buffer_update); 580 581 BitBlt(dst_dc, draw_rect.left - offset.x, draw_rect.top - offset.y, 582 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top, 583 src_dc, draw_rect.left, draw_rect.top, SRCCOPY); 584 ReleaseDC(window, dst_dc); 585 586 SetRectEmpty(&swapchain->front_buffer_update); 587 } 588 589 static void swapchain_gdi_present(struct wined3d_swapchain *swapchain, 590 const RECT *src_rect, const RECT *dst_rect, DWORD flags) 591 { 592 struct wined3d_surface *front, *back; 593 HBITMAP bitmap; 594 void *data; 595 HDC dc; 596 597 front = swapchain->front_buffer->sub_resources[0].u.surface; 598 back = swapchain->back_buffers[0]->sub_resources[0].u.surface; 599 600 /* Flip the surface data. */ 601 dc = front->dc; 602 bitmap = front->bitmap; 603 data = front->container->resource.heap_memory; 604 605 front->dc = back->dc; 606 front->bitmap = back->bitmap; 607 front->container->resource.heap_memory = back->container->resource.heap_memory; 608 609 back->dc = dc; 610 back->bitmap = bitmap; 611 back->container->resource.heap_memory = data; 612 613 /* FPS support */ 614 if (TRACE_ON(fps)) 615 { 616 static LONG prev_time, frames; 617 DWORD time = GetTickCount(); 618 619 ++frames; 620 621 /* every 1.5 seconds */ 622 if (time - prev_time > 1500) 623 { 624 TRACE_(fps)("@ approx %.2ffps\n", 1000.0 * frames / (time - prev_time)); 625 prev_time = time; 626 frames = 0; 627 } 628 } 629 630 SetRect(&swapchain->front_buffer_update, 0, 0, 631 swapchain->front_buffer->resource.width, 632 swapchain->front_buffer->resource.height); 633 swapchain_gdi_frontbuffer_updated(swapchain); 634 } 635 636 static const struct wined3d_swapchain_ops swapchain_gdi_ops = 637 { 638 swapchain_gdi_present, 639 swapchain_gdi_frontbuffer_updated, 640 }; 641 642 static void swapchain_update_render_to_fbo(struct wined3d_swapchain *swapchain) 643 { 644 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) 645 return; 646 647 if (!swapchain->desc.backbuffer_count) 648 { 649 TRACE("Single buffered rendering.\n"); 650 swapchain->render_to_fbo = FALSE; 651 return; 652 } 653 654 TRACE("Rendering to FBO.\n"); 655 swapchain->render_to_fbo = TRUE; 656 } 657 658 static void wined3d_swapchain_apply_sample_count_override(const struct wined3d_swapchain *swapchain, 659 enum wined3d_format_id format_id, enum wined3d_multisample_type *type, DWORD *quality) 660 { 661 const struct wined3d_gl_info *gl_info; 662 const struct wined3d_format *format; 663 enum wined3d_multisample_type t; 664 665 if (wined3d_settings.sample_count == ~0u) 666 return; 667 668 gl_info = &swapchain->device->adapter->gl_info; 669 if (!(format = wined3d_get_format(gl_info, format_id, WINED3DUSAGE_RENDERTARGET))) 670 return; 671 672 if ((t = min(wined3d_settings.sample_count, gl_info->limits.samples))) 673 while (!(format->multisample_types & 1u << (t - 1))) 674 ++t; 675 TRACE("Using sample count %u.\n", t); 676 *type = t; 677 *quality = 0; 678 } 679 680 static void wined3d_swapchain_update_swap_interval_cs(void *object) 681 { 682 struct wined3d_swapchain *swapchain = object; 683 const struct wined3d_gl_info *gl_info; 684 struct wined3d_context *context; 685 int swap_interval; 686 687 context = context_acquire(swapchain->device, swapchain->front_buffer, 0); 688 gl_info = context->gl_info; 689 690 switch (swapchain->desc.swap_interval) 691 { 692 case WINED3DPRESENT_INTERVAL_IMMEDIATE: 693 swap_interval = 0; 694 break; 695 case WINED3DPRESENT_INTERVAL_DEFAULT: 696 case WINED3DPRESENT_INTERVAL_ONE: 697 swap_interval = 1; 698 break; 699 case WINED3DPRESENT_INTERVAL_TWO: 700 swap_interval = 2; 701 break; 702 case WINED3DPRESENT_INTERVAL_THREE: 703 swap_interval = 3; 704 break; 705 case WINED3DPRESENT_INTERVAL_FOUR: 706 swap_interval = 4; 707 break; 708 default: 709 FIXME("Unhandled present interval %#x.\n", swapchain->desc.swap_interval); 710 swap_interval = 1; 711 } 712 713 if (gl_info->supported[WGL_EXT_SWAP_CONTROL]) 714 { 715 if (!GL_EXTCALL(wglSwapIntervalEXT(swap_interval))) 716 ERR("wglSwapIntervalEXT failed to set swap interval %d for context %p, last error %#x\n", 717 swap_interval, context, GetLastError()); 718 } 719 720 context_release(context); 721 } 722 723 static void wined3d_swapchain_cs_init(void *object) 724 { 725 struct wined3d_swapchain *swapchain = object; 726 const struct wined3d_gl_info *gl_info; 727 unsigned int i; 728 729 static const enum wined3d_format_id formats[] = 730 { 731 WINED3DFMT_D24_UNORM_S8_UINT, 732 WINED3DFMT_D32_UNORM, 733 WINED3DFMT_R24_UNORM_X8_TYPELESS, 734 WINED3DFMT_D16_UNORM, 735 WINED3DFMT_S1_UINT_D15_UNORM, 736 }; 737 738 gl_info = &swapchain->device->adapter->gl_info; 739 740 /* Without ORM_FBO, switching the depth/stencil format is hard. Always 741 * request a depth/stencil buffer in the likely case it's needed later. */ 742 for (i = 0; i < ARRAY_SIZE(formats); ++i) 743 { 744 swapchain->ds_format = wined3d_get_format(gl_info, formats[i], WINED3DUSAGE_DEPTHSTENCIL); 745 if ((swapchain->context[0] = context_create(swapchain, swapchain->front_buffer, swapchain->ds_format))) 746 break; 747 TRACE("Depth stencil format %s is not supported, trying next format.\n", debug_d3dformat(formats[i])); 748 } 749 750 if (!swapchain->context[0]) 751 { 752 WARN("Failed to create context.\n"); 753 return; 754 } 755 swapchain->num_contexts = 1; 756 757 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO 758 && (!swapchain->desc.enable_auto_depth_stencil 759 || swapchain->desc.auto_depth_stencil_format != swapchain->ds_format->id)) 760 FIXME("Add OpenGL context recreation support.\n"); 761 762 context_release(swapchain->context[0]); 763 764 wined3d_swapchain_update_swap_interval_cs(swapchain); 765 } 766 767 static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3d_device *device, 768 struct wined3d_swapchain_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops) 769 { 770 const struct wined3d_adapter *adapter = device->adapter; 771 struct wined3d_resource_desc texture_desc; 772 BOOL displaymode_set = FALSE; 773 DWORD texture_flags = 0; 774 RECT client_rect; 775 HWND window; 776 HRESULT hr; 777 UINT i; 778 779 if (desc->backbuffer_count > 1) 780 { 781 FIXME("The application requested more than one back buffer, this is not properly supported.\n" 782 "Please configure the application to use double buffering (1 back buffer) if possible.\n"); 783 } 784 785 if (device->wined3d->flags & WINED3D_NO3D) 786 swapchain->swapchain_ops = &swapchain_gdi_ops; 787 else 788 swapchain->swapchain_ops = &swapchain_gl_ops; 789 790 window = desc->device_window ? desc->device_window : device->create_parms.focus_window; 791 792 swapchain->device = device; 793 swapchain->parent = parent; 794 swapchain->parent_ops = parent_ops; 795 swapchain->ref = 1; 796 swapchain->win_handle = window; 797 swapchain->device_window = window; 798 799 if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d, 800 adapter->ordinal, &swapchain->original_mode, NULL))) 801 { 802 ERR("Failed to get current display mode, hr %#x.\n", hr); 803 goto err; 804 } 805 GetWindowRect(window, &swapchain->original_window_rect); 806 807 GetClientRect(window, &client_rect); 808 if (desc->windowed) 809 { 810 if (!desc->backbuffer_width) 811 { 812 desc->backbuffer_width = client_rect.right; 813 TRACE("Updating width to %u.\n", desc->backbuffer_width); 814 } 815 816 if (!desc->backbuffer_height) 817 { 818 desc->backbuffer_height = client_rect.bottom; 819 TRACE("Updating height to %u.\n", desc->backbuffer_height); 820 } 821 822 if (desc->backbuffer_format == WINED3DFMT_UNKNOWN) 823 { 824 desc->backbuffer_format = swapchain->original_mode.format_id; 825 TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->original_mode.format_id)); 826 } 827 } 828 swapchain->desc = *desc; 829 wined3d_swapchain_apply_sample_count_override(swapchain, swapchain->desc.backbuffer_format, 830 &swapchain->desc.multisample_type, &swapchain->desc.multisample_quality); 831 swapchain_update_render_to_fbo(swapchain); 832 833 TRACE("Creating front buffer.\n"); 834 835 texture_desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; 836 texture_desc.format = swapchain->desc.backbuffer_format; 837 texture_desc.multisample_type = swapchain->desc.multisample_type; 838 texture_desc.multisample_quality = swapchain->desc.multisample_quality; 839 texture_desc.usage = 0; 840 texture_desc.pool = WINED3D_POOL_DEFAULT; 841 texture_desc.width = swapchain->desc.backbuffer_width; 842 texture_desc.height = swapchain->desc.backbuffer_height; 843 texture_desc.depth = 1; 844 texture_desc.size = 0; 845 846 if (swapchain->desc.flags & WINED3D_SWAPCHAIN_GDI_COMPATIBLE) 847 texture_flags |= WINED3D_TEXTURE_CREATE_GET_DC; 848 849 if (FAILED(hr = device->device_parent->ops->create_swapchain_texture(device->device_parent, 850 parent, &texture_desc, texture_flags, &swapchain->front_buffer))) 851 { 852 WARN("Failed to create front buffer, hr %#x.\n", hr); 853 goto err; 854 } 855 856 wined3d_texture_set_swapchain(swapchain->front_buffer, swapchain); 857 if (!(device->wined3d->flags & WINED3D_NO3D)) 858 { 859 wined3d_texture_validate_location(swapchain->front_buffer, 0, WINED3D_LOCATION_DRAWABLE); 860 wined3d_texture_invalidate_location(swapchain->front_buffer, 0, ~WINED3D_LOCATION_DRAWABLE); 861 } 862 863 /* MSDN says we're only allowed a single fullscreen swapchain per device, 864 * so we should really check to see if there is a fullscreen swapchain 865 * already. Does a single head count as full screen? */ 866 if (!desc->windowed) 867 { 868 if (desc->flags & WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH) 869 { 870 /* Change the display settings */ 871 swapchain->d3d_mode.width = desc->backbuffer_width; 872 swapchain->d3d_mode.height = desc->backbuffer_height; 873 swapchain->d3d_mode.format_id = desc->backbuffer_format; 874 swapchain->d3d_mode.refresh_rate = desc->refresh_rate; 875 swapchain->d3d_mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN; 876 877 if (FAILED(hr = wined3d_set_adapter_display_mode(device->wined3d, 878 adapter->ordinal, &swapchain->d3d_mode))) 879 { 880 WARN("Failed to set display mode, hr %#x.\n", hr); 881 goto err; 882 } 883 displaymode_set = TRUE; 884 } 885 else 886 { 887 swapchain->d3d_mode = swapchain->original_mode; 888 } 889 } 890 891 if (!(device->wined3d->flags & WINED3D_NO3D)) 892 { 893 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context)); 894 if (!swapchain->context) 895 { 896 ERR("Failed to create the context array.\n"); 897 hr = E_OUTOFMEMORY; 898 goto err; 899 } 900 901 wined3d_cs_init_object(device->cs, wined3d_swapchain_cs_init, swapchain); 902 device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); 903 904 if (!swapchain->context[0]) 905 { 906 hr = WINED3DERR_NOTAVAILABLE; 907 goto err; 908 } 909 } 910 911 if (swapchain->desc.backbuffer_count > 0) 912 { 913 if (!(swapchain->back_buffers = wined3d_calloc(swapchain->desc.backbuffer_count, 914 sizeof(*swapchain->back_buffers)))) 915 { 916 ERR("Failed to allocate backbuffer array memory.\n"); 917 hr = E_OUTOFMEMORY; 918 goto err; 919 } 920 921 texture_desc.usage |= WINED3DUSAGE_RENDERTARGET; 922 for (i = 0; i < swapchain->desc.backbuffer_count; ++i) 923 { 924 TRACE("Creating back buffer %u.\n", i); 925 if (FAILED(hr = device->device_parent->ops->create_swapchain_texture(device->device_parent, 926 parent, &texture_desc, texture_flags, &swapchain->back_buffers[i]))) 927 { 928 WARN("Failed to create back buffer %u, hr %#x.\n", i, hr); 929 swapchain->desc.backbuffer_count = i; 930 goto err; 931 } 932 wined3d_texture_set_swapchain(swapchain->back_buffers[i], swapchain); 933 } 934 } 935 936 /* Swapchains share the depth/stencil buffer, so only create a single depthstencil surface. */ 937 if (desc->enable_auto_depth_stencil && !(device->wined3d->flags & WINED3D_NO3D)) 938 { 939 TRACE("Creating depth/stencil buffer.\n"); 940 if (!device->auto_depth_stencil_view) 941 { 942 struct wined3d_view_desc desc; 943 struct wined3d_texture *ds; 944 945 texture_desc.format = swapchain->desc.auto_depth_stencil_format; 946 texture_desc.usage = WINED3DUSAGE_DEPTHSTENCIL; 947 948 if (FAILED(hr = device->device_parent->ops->create_swapchain_texture(device->device_parent, 949 device->device_parent, &texture_desc, texture_flags, &ds))) 950 { 951 WARN("Failed to create the auto depth/stencil surface, hr %#x.\n", hr); 952 goto err; 953 } 954 955 desc.format_id = ds->resource.format->id; 956 desc.flags = 0; 957 desc.u.texture.level_idx = 0; 958 desc.u.texture.level_count = 1; 959 desc.u.texture.layer_idx = 0; 960 desc.u.texture.layer_count = 1; 961 hr = wined3d_rendertarget_view_create(&desc, &ds->resource, NULL, &wined3d_null_parent_ops, 962 &device->auto_depth_stencil_view); 963 wined3d_texture_decref(ds); 964 if (FAILED(hr)) 965 { 966 ERR("Failed to create rendertarget view, hr %#x.\n", hr); 967 goto err; 968 } 969 } 970 } 971 972 wined3d_swapchain_get_gamma_ramp(swapchain, &swapchain->orig_gamma); 973 974 return WINED3D_OK; 975 976 err: 977 if (displaymode_set) 978 { 979 if (FAILED(wined3d_set_adapter_display_mode(device->wined3d, 980 adapter->ordinal, &swapchain->original_mode))) 981 ERR("Failed to restore display mode.\n"); 982 ClipCursor(NULL); 983 } 984 985 if (swapchain->back_buffers) 986 { 987 for (i = 0; i < swapchain->desc.backbuffer_count; ++i) 988 { 989 if (swapchain->back_buffers[i]) 990 { 991 wined3d_texture_set_swapchain(swapchain->back_buffers[i], NULL); 992 wined3d_texture_decref(swapchain->back_buffers[i]); 993 } 994 } 995 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers); 996 } 997 998 wined3d_cs_destroy_object(swapchain->device->cs, wined3d_swapchain_destroy_object, swapchain); 999 swapchain->device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); 1000 1001 if (swapchain->front_buffer) 1002 { 1003 wined3d_texture_set_swapchain(swapchain->front_buffer, NULL); 1004 wined3d_texture_decref(swapchain->front_buffer); 1005 } 1006 1007 return hr; 1008 } 1009 1010 HRESULT CDECL wined3d_swapchain_create(struct wined3d_device *device, struct wined3d_swapchain_desc *desc, 1011 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_swapchain **swapchain) 1012 { 1013 struct wined3d_swapchain *object; 1014 HRESULT hr; 1015 1016 TRACE("device %p, desc %p, parent %p, parent_ops %p, swapchain %p.\n", 1017 device, desc, parent, parent_ops, swapchain); 1018 1019 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); 1020 if (!object) 1021 return E_OUTOFMEMORY; 1022 1023 hr = swapchain_init(object, device, desc, parent, parent_ops); 1024 if (FAILED(hr)) 1025 { 1026 WARN("Failed to initialize swapchain, hr %#x.\n", hr); 1027 HeapFree(GetProcessHeap(), 0, object); 1028 return hr; 1029 } 1030 1031 TRACE("Created swapchain %p.\n", object); 1032 *swapchain = object; 1033 1034 return WINED3D_OK; 1035 } 1036 1037 static struct wined3d_context *swapchain_create_context(struct wined3d_swapchain *swapchain) 1038 { 1039 struct wined3d_context **ctx_array; 1040 struct wined3d_context *ctx; 1041 1042 TRACE("Creating a new context for swapchain %p, thread %u.\n", swapchain, GetCurrentThreadId()); 1043 1044 if (!(ctx = context_create(swapchain, swapchain->front_buffer, swapchain->ds_format))) 1045 { 1046 ERR("Failed to create a new context for the swapchain\n"); 1047 return NULL; 1048 } 1049 context_release(ctx); 1050 1051 if (!(ctx_array = wined3d_calloc(swapchain->num_contexts + 1, sizeof(*ctx_array)))) 1052 { 1053 ERR("Out of memory when trying to allocate a new context array\n"); 1054 context_destroy(swapchain->device, ctx); 1055 return NULL; 1056 } 1057 memcpy(ctx_array, swapchain->context, sizeof(*ctx_array) * swapchain->num_contexts); 1058 HeapFree(GetProcessHeap(), 0, swapchain->context); 1059 ctx_array[swapchain->num_contexts] = ctx; 1060 swapchain->context = ctx_array; 1061 swapchain->num_contexts++; 1062 1063 TRACE("Returning context %p\n", ctx); 1064 return ctx; 1065 } 1066 1067 void swapchain_destroy_contexts(struct wined3d_swapchain *swapchain) 1068 { 1069 unsigned int i; 1070 1071 for (i = 0; i < swapchain->num_contexts; ++i) 1072 { 1073 context_destroy(swapchain->device, swapchain->context[i]); 1074 } 1075 HeapFree(GetProcessHeap(), 0, swapchain->context); 1076 swapchain->num_contexts = 0; 1077 swapchain->context = NULL; 1078 } 1079 1080 struct wined3d_context *swapchain_get_context(struct wined3d_swapchain *swapchain) 1081 { 1082 DWORD tid = GetCurrentThreadId(); 1083 unsigned int i; 1084 1085 for (i = 0; i < swapchain->num_contexts; ++i) 1086 { 1087 if (swapchain->context[i]->tid == tid) 1088 return swapchain->context[i]; 1089 } 1090 1091 /* Create a new context for the thread */ 1092 return swapchain_create_context(swapchain); 1093 } 1094 1095 HDC swapchain_get_backup_dc(struct wined3d_swapchain *swapchain) 1096 { 1097 if (!swapchain->backup_dc) 1098 { 1099 TRACE("Creating the backup window for swapchain %p.\n", swapchain); 1100 1101 if (!(swapchain->backup_wnd = CreateWindowA(WINED3D_OPENGL_WINDOW_CLASS_NAME, "WineD3D fake window", 1102 WS_OVERLAPPEDWINDOW, 10, 10, 10, 10, NULL, NULL, NULL, NULL))) 1103 { 1104 ERR("Failed to create a window.\n"); 1105 return NULL; 1106 } 1107 1108 if (!(swapchain->backup_dc = GetDC(swapchain->backup_wnd))) 1109 { 1110 ERR("Failed to get a DC.\n"); 1111 DestroyWindow(swapchain->backup_wnd); 1112 swapchain->backup_wnd = NULL; 1113 return NULL; 1114 } 1115 } 1116 1117 return swapchain->backup_dc; 1118 } 1119 1120 void swapchain_update_draw_bindings(struct wined3d_swapchain *swapchain) 1121 { 1122 UINT i; 1123 1124 wined3d_resource_update_draw_binding(&swapchain->front_buffer->resource); 1125 1126 for (i = 0; i < swapchain->desc.backbuffer_count; ++i) 1127 { 1128 wined3d_resource_update_draw_binding(&swapchain->back_buffers[i]->resource); 1129 } 1130 } 1131 1132 void swapchain_update_swap_interval(struct wined3d_swapchain *swapchain) 1133 { 1134 wined3d_cs_init_object(swapchain->device->cs, wined3d_swapchain_update_swap_interval_cs, swapchain); 1135 } 1136 1137 void wined3d_swapchain_activate(struct wined3d_swapchain *swapchain, BOOL activate) 1138 { 1139 struct wined3d_device *device = swapchain->device; 1140 BOOL filter_messages = device->filter_messages; 1141 1142 /* This code is not protected by the wined3d mutex, so it may run while 1143 * wined3d_device_reset is active. Testing on Windows shows that changing 1144 * focus during resets and resetting during focus change events causes 1145 * the application to crash with an invalid memory access. */ 1146 1147 device->filter_messages = !(device->wined3d->flags & WINED3D_FOCUS_MESSAGES); 1148 1149 if (activate) 1150 { 1151 if (!(device->create_parms.flags & WINED3DCREATE_NOWINDOWCHANGES)) 1152 { 1153 /* The d3d versions do not agree on the exact messages here. D3d8 restores 1154 * the window but leaves the size untouched, d3d9 sets the size on an 1155 * invisible window, generates messages but doesn't change the window 1156 * properties. The implementation follows d3d9. 1157 * 1158 * Guild Wars 1 wants a WINDOWPOSCHANGED message on the device window to 1159 * resume drawing after a focus loss. */ 1160 SetWindowPos(swapchain->device_window, NULL, 0, 0, 1161 swapchain->desc.backbuffer_width, swapchain->desc.backbuffer_height, 1162 SWP_NOACTIVATE | SWP_NOZORDER); 1163 } 1164 1165 if (device->wined3d->flags & WINED3D_RESTORE_MODE_ON_ACTIVATE) 1166 { 1167 if (FAILED(wined3d_set_adapter_display_mode(device->wined3d, 1168 device->adapter->ordinal, &swapchain->d3d_mode))) 1169 ERR("Failed to set display mode.\n"); 1170 } 1171 } 1172 else 1173 { 1174 if (FAILED(wined3d_set_adapter_display_mode(device->wined3d, 1175 device->adapter->ordinal, NULL))) 1176 ERR("Failed to set display mode.\n"); 1177 1178 swapchain->reapply_mode = TRUE; 1179 1180 if (!(device->create_parms.flags & WINED3DCREATE_NOWINDOWCHANGES) 1181 && IsWindowVisible(swapchain->device_window)) 1182 ShowWindow(swapchain->device_window, SW_MINIMIZE); 1183 } 1184 1185 device->filter_messages = filter_messages; 1186 } 1187 1188 HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapchain, unsigned int buffer_count, 1189 unsigned int width, unsigned int height, enum wined3d_format_id format_id, 1190 enum wined3d_multisample_type multisample_type, unsigned int multisample_quality) 1191 { 1192 struct wined3d_device *device = swapchain->device; 1193 BOOL update_desc = FALSE; 1194 1195 TRACE("swapchain %p, buffer_count %u, width %u, height %u, format %s, " 1196 "multisample_type %#x, multisample_quality %#x.\n", 1197 swapchain, buffer_count, width, height, debug_d3dformat(format_id), 1198 multisample_type, multisample_quality); 1199 1200 wined3d_swapchain_apply_sample_count_override(swapchain, format_id, &multisample_type, &multisample_quality); 1201 1202 if (buffer_count && buffer_count != swapchain->desc.backbuffer_count) 1203 FIXME("Cannot change the back buffer count yet.\n"); 1204 1205 device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); 1206 1207 if (!width || !height) 1208 { 1209 /* The application is requesting that either the swapchain width or 1210 * height be set to the corresponding dimension in the window's 1211 * client rect. */ 1212 1213 RECT client_rect; 1214 1215 if (!swapchain->desc.windowed) 1216 return WINED3DERR_INVALIDCALL; 1217 1218 if (!GetClientRect(swapchain->device_window, &client_rect)) 1219 { 1220 ERR("Failed to get client rect, last error %#x.\n", GetLastError()); 1221 return WINED3DERR_INVALIDCALL; 1222 } 1223 1224 if (!width) 1225 width = client_rect.right; 1226 1227 if (!height) 1228 height = client_rect.bottom; 1229 } 1230 1231 if (width != swapchain->desc.backbuffer_width 1232 || height != swapchain->desc.backbuffer_height) 1233 { 1234 swapchain->desc.backbuffer_width = width; 1235 swapchain->desc.backbuffer_height = height; 1236 update_desc = TRUE; 1237 } 1238 1239 if (format_id == WINED3DFMT_UNKNOWN) 1240 { 1241 if (!swapchain->desc.windowed) 1242 return WINED3DERR_INVALIDCALL; 1243 format_id = swapchain->original_mode.format_id; 1244 } 1245 1246 if (format_id != swapchain->desc.backbuffer_format) 1247 { 1248 swapchain->desc.backbuffer_format = format_id; 1249 update_desc = TRUE; 1250 } 1251 1252 if (multisample_type != swapchain->desc.multisample_type 1253 || multisample_quality != swapchain->desc.multisample_quality) 1254 { 1255 swapchain->desc.multisample_type = multisample_type; 1256 swapchain->desc.multisample_quality = multisample_quality; 1257 update_desc = TRUE; 1258 } 1259 1260 if (update_desc) 1261 { 1262 HRESULT hr; 1263 UINT i; 1264 1265 if (FAILED(hr = wined3d_texture_update_desc(swapchain->front_buffer, swapchain->desc.backbuffer_width, 1266 swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format, 1267 swapchain->desc.multisample_type, swapchain->desc.multisample_quality, NULL, 0))) 1268 return hr; 1269 1270 for (i = 0; i < swapchain->desc.backbuffer_count; ++i) 1271 { 1272 if (FAILED(hr = wined3d_texture_update_desc(swapchain->back_buffers[i], swapchain->desc.backbuffer_width, 1273 swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format, 1274 swapchain->desc.multisample_type, swapchain->desc.multisample_quality, NULL, 0))) 1275 return hr; 1276 } 1277 } 1278 1279 swapchain_update_render_to_fbo(swapchain); 1280 swapchain_update_draw_bindings(swapchain); 1281 1282 return WINED3D_OK; 1283 } 1284 1285 static HRESULT wined3d_swapchain_set_display_mode(struct wined3d_swapchain *swapchain, 1286 struct wined3d_display_mode *mode) 1287 { 1288 struct wined3d_device *device = swapchain->device; 1289 HRESULT hr; 1290 1291 if (swapchain->desc.flags & WINED3D_SWAPCHAIN_USE_CLOSEST_MATCHING_MODE) 1292 { 1293 if (FAILED(hr = wined3d_find_closest_matching_adapter_mode(device->wined3d, 1294 device->adapter->ordinal, mode))) 1295 { 1296 WARN("Failed to find closest matching mode, hr %#x.\n", hr); 1297 } 1298 } 1299 1300 if (FAILED(hr = wined3d_set_adapter_display_mode(device->wined3d, 1301 device->adapter->ordinal, mode))) 1302 { 1303 WARN("Failed to set display mode, hr %#x.\n", hr); 1304 return WINED3DERR_INVALIDCALL; 1305 } 1306 1307 return WINED3D_OK; 1308 } 1309 1310 HRESULT CDECL wined3d_swapchain_resize_target(struct wined3d_swapchain *swapchain, 1311 const struct wined3d_display_mode *mode) 1312 { 1313 struct wined3d_device *device = swapchain->device; 1314 struct wined3d_display_mode actual_mode; 1315 RECT original_window_rect, window_rect; 1316 HRESULT hr; 1317 1318 TRACE("swapchain %p, mode %p.\n", swapchain, mode); 1319 1320 if (swapchain->desc.windowed) 1321 { 1322 SetRect(&window_rect, 0, 0, mode->width, mode->height); 1323 AdjustWindowRectEx(&window_rect, 1324 GetWindowLongW(swapchain->device_window, GWL_STYLE), FALSE, 1325 GetWindowLongW(swapchain->device_window, GWL_EXSTYLE)); 1326 SetRect(&window_rect, 0, 0, 1327 window_rect.right - window_rect.left, window_rect.bottom - window_rect.top); 1328 GetWindowRect(swapchain->device_window, &original_window_rect); 1329 OffsetRect(&window_rect, original_window_rect.left, original_window_rect.top); 1330 } 1331 else if (swapchain->desc.flags & WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH) 1332 { 1333 actual_mode = *mode; 1334 if (FAILED(hr = wined3d_swapchain_set_display_mode(swapchain, &actual_mode))) 1335 return hr; 1336 SetRect(&window_rect, 0, 0, actual_mode.width, actual_mode.height); 1337 } 1338 else 1339 { 1340 if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d, device->adapter->ordinal, 1341 &actual_mode, NULL))) 1342 { 1343 ERR("Failed to get display mode, hr %#x.\n", hr); 1344 return WINED3DERR_INVALIDCALL; 1345 } 1346 1347 SetRect(&window_rect, 0, 0, actual_mode.width, actual_mode.height); 1348 } 1349 1350 MoveWindow(swapchain->device_window, window_rect.left, window_rect.top, 1351 window_rect.right - window_rect.left, 1352 window_rect.bottom - window_rect.top, TRUE); 1353 1354 return WINED3D_OK; 1355 } 1356 1357 HRESULT CDECL wined3d_swapchain_set_fullscreen(struct wined3d_swapchain *swapchain, 1358 const struct wined3d_swapchain_desc *swapchain_desc, const struct wined3d_display_mode *mode) 1359 { 1360 struct wined3d_device *device = swapchain->device; 1361 struct wined3d_display_mode actual_mode; 1362 HRESULT hr; 1363 1364 TRACE("swapchain %p, desc %p, mode %p.\n", swapchain, swapchain_desc, mode); 1365 1366 if (swapchain->desc.flags & WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH) 1367 { 1368 if (mode) 1369 { 1370 actual_mode = *mode; 1371 } 1372 else 1373 { 1374 if (!swapchain_desc->windowed) 1375 { 1376 actual_mode.width = swapchain_desc->backbuffer_width; 1377 actual_mode.height = swapchain_desc->backbuffer_height; 1378 actual_mode.refresh_rate = swapchain_desc->refresh_rate; 1379 actual_mode.format_id = swapchain_desc->backbuffer_format; 1380 actual_mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN; 1381 } 1382 else 1383 { 1384 actual_mode = swapchain->original_mode; 1385 } 1386 } 1387 1388 if (FAILED(hr = wined3d_swapchain_set_display_mode(swapchain, &actual_mode))) 1389 return hr; 1390 } 1391 else 1392 { 1393 if (mode) 1394 WARN("WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH is not set, ignoring mode.\n"); 1395 1396 if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d, device->adapter->ordinal, 1397 &actual_mode, NULL))) 1398 { 1399 ERR("Failed to get display mode, hr %#x.\n", hr); 1400 return WINED3DERR_INVALIDCALL; 1401 } 1402 } 1403 1404 if (!swapchain_desc->windowed) 1405 { 1406 unsigned int width = actual_mode.width; 1407 unsigned int height = actual_mode.height; 1408 1409 if (swapchain->desc.windowed) 1410 { 1411 /* Switch from windowed to fullscreen */ 1412 HWND focus_window = device->create_parms.focus_window; 1413 if (!focus_window) 1414 focus_window = swapchain->device_window; 1415 if (FAILED(hr = wined3d_device_acquire_focus_window(device, focus_window))) 1416 { 1417 ERR("Failed to acquire focus window, hr %#x.\n", hr); 1418 return hr; 1419 } 1420 1421 wined3d_device_setup_fullscreen_window(device, swapchain->device_window, width, height); 1422 } 1423 else 1424 { 1425 /* Fullscreen -> fullscreen mode change */ 1426 BOOL filter_messages = device->filter_messages; 1427 device->filter_messages = TRUE; 1428 1429 MoveWindow(swapchain->device_window, 0, 0, width, height, TRUE); 1430 ShowWindow(swapchain->device_window, SW_SHOW); 1431 1432 device->filter_messages = filter_messages; 1433 } 1434 swapchain->d3d_mode = actual_mode; 1435 } 1436 else if (!swapchain->desc.windowed) 1437 { 1438 /* Fullscreen -> windowed switch */ 1439 RECT *window_rect = NULL; 1440 if (swapchain->desc.flags & WINED3D_SWAPCHAIN_RESTORE_WINDOW_RECT) 1441 window_rect = &swapchain->original_window_rect; 1442 wined3d_device_restore_fullscreen_window(device, swapchain->device_window, window_rect); 1443 wined3d_device_release_focus_window(device); 1444 } 1445 1446 swapchain->desc.windowed = swapchain_desc->windowed; 1447 1448 return WINED3D_OK; 1449 } 1450