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