"Fossies" - the Fresh Open Source Software Archive

Member "wine-6.0.1/dlls/wined3d/swapchain.c" (7 Jun 2021, 89106 Bytes) of package /linux/misc/wine-6.0.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "swapchain.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.0_vs_6.0.1.

    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 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
   28 
   29 void wined3d_swapchain_cleanup(struct wined3d_swapchain *swapchain)
   30 {
   31     HRESULT hr;
   32     UINT i;
   33 
   34     TRACE("Destroying swapchain %p.\n", swapchain);
   35 
   36     wined3d_swapchain_state_cleanup(&swapchain->state);
   37     wined3d_swapchain_set_gamma_ramp(swapchain, 0, &swapchain->orig_gamma);
   38 
   39     /* Release the swapchain's draw buffers. Make sure swapchain->back_buffers[0]
   40      * is the last buffer to be destroyed, FindContext() depends on that. */
   41     if (swapchain->front_buffer)
   42     {
   43         wined3d_texture_set_swapchain(swapchain->front_buffer, NULL);
   44         if (wined3d_texture_decref(swapchain->front_buffer))
   45             WARN("Something's still holding the front buffer (%p).\n", swapchain->front_buffer);
   46         swapchain->front_buffer = NULL;
   47     }
   48 
   49     if (swapchain->back_buffers)
   50     {
   51         i = swapchain->state.desc.backbuffer_count;
   52 
   53         while (i--)
   54         {
   55             wined3d_texture_set_swapchain(swapchain->back_buffers[i], NULL);
   56             if (wined3d_texture_decref(swapchain->back_buffers[i]))
   57                 WARN("Something's still holding back buffer %u (%p).\n", i, swapchain->back_buffers[i]);
   58         }
   59         heap_free(swapchain->back_buffers);
   60         swapchain->back_buffers = NULL;
   61     }
   62 
   63     /* Restore the screen resolution if we rendered in fullscreen.
   64      * This will restore the screen resolution to what it was before creating
   65      * the swapchain. In case of d3d8 and d3d9 this will be the original
   66      * desktop resolution. In case of d3d7 this will be a NOP because ddraw
   67      * sets the resolution before starting up Direct3D, thus orig_width and
   68      * orig_height will be equal to the modes in the presentation params. */
   69     if (!swapchain->state.desc.windowed)
   70     {
   71         if (swapchain->state.desc.auto_restore_display_mode)
   72         {
   73             if (FAILED(hr = wined3d_restore_display_modes(swapchain->device->wined3d)))
   74                 ERR("Failed to restore display mode, hr %#x.\n", hr);
   75 
   76             if (swapchain->state.desc.flags & WINED3D_SWAPCHAIN_RESTORE_WINDOW_RECT)
   77             {
   78                 wined3d_swapchain_state_restore_from_fullscreen(&swapchain->state,
   79                         swapchain->state.device_window, &swapchain->state.original_window_rect);
   80                 wined3d_device_release_focus_window(swapchain->device);
   81             }
   82         }
   83         else
   84         {
   85             wined3d_swapchain_state_restore_from_fullscreen(&swapchain->state, swapchain->state.device_window, NULL);
   86         }
   87     }
   88 }
   89 
   90 static void wined3d_swapchain_gl_destroy_object(void *object)
   91 {
   92     wined3d_swapchain_gl_destroy_contexts(object);
   93 }
   94 
   95 void wined3d_swapchain_gl_cleanup(struct wined3d_swapchain_gl *swapchain_gl)
   96 {
   97     struct wined3d_cs *cs = swapchain_gl->s.device->cs;
   98 
   99     wined3d_swapchain_cleanup(&swapchain_gl->s);
  100 
  101     wined3d_cs_destroy_object(cs, wined3d_swapchain_gl_destroy_object, swapchain_gl);
  102     wined3d_cs_finish(cs, WINED3D_CS_QUEUE_DEFAULT);
  103 
  104     if (swapchain_gl->backup_dc)
  105     {
  106         TRACE("Destroying backup wined3d window %p, dc %p.\n", swapchain_gl->backup_wnd, swapchain_gl->backup_dc);
  107 
  108         wined3d_release_dc(swapchain_gl->backup_wnd, swapchain_gl->backup_dc);
  109         DestroyWindow(swapchain_gl->backup_wnd);
  110     }
  111 }
  112 
  113 static void wined3d_swapchain_vk_destroy_vulkan_swapchain(struct wined3d_swapchain_vk *swapchain_vk)
  114 {
  115     struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device);
  116     const struct wined3d_vk_info *vk_info;
  117     unsigned int i;
  118     VkResult vr;
  119 
  120     TRACE("swapchain_vk %p.\n", swapchain_vk);
  121 
  122     vk_info = &wined3d_adapter_vk(device_vk->d.adapter)->vk_info;
  123 
  124     if ((vr = VK_CALL(vkQueueWaitIdle(device_vk->vk_queue))) < 0)
  125         ERR("Failed to wait on queue, vr %s.\n", wined3d_debug_vkresult(vr));
  126     heap_free(swapchain_vk->vk_images);
  127     for (i = 0; i < swapchain_vk->image_count; ++i)
  128     {
  129         VK_CALL(vkDestroySemaphore(device_vk->vk_device, swapchain_vk->vk_semaphores[i].available, NULL));
  130         VK_CALL(vkDestroySemaphore(device_vk->vk_device, swapchain_vk->vk_semaphores[i].presentable, NULL));
  131     }
  132     heap_free(swapchain_vk->vk_semaphores);
  133     VK_CALL(vkDestroySwapchainKHR(device_vk->vk_device, swapchain_vk->vk_swapchain, NULL));
  134     VK_CALL(vkDestroySurfaceKHR(vk_info->instance, swapchain_vk->vk_surface, NULL));
  135 }
  136 
  137 static void wined3d_swapchain_vk_destroy_object(void *object)
  138 {
  139     wined3d_swapchain_vk_destroy_vulkan_swapchain(object);
  140 }
  141 
  142 void wined3d_swapchain_vk_cleanup(struct wined3d_swapchain_vk *swapchain_vk)
  143 {
  144     struct wined3d_cs *cs = swapchain_vk->s.device->cs;
  145 
  146     wined3d_cs_destroy_object(cs, wined3d_swapchain_vk_destroy_object, swapchain_vk);
  147     wined3d_cs_finish(cs, WINED3D_CS_QUEUE_DEFAULT);
  148 
  149     wined3d_swapchain_cleanup(&swapchain_vk->s);
  150 }
  151 
  152 ULONG CDECL wined3d_swapchain_incref(struct wined3d_swapchain *swapchain)
  153 {
  154     ULONG refcount = InterlockedIncrement(&swapchain->ref);
  155 
  156     TRACE("%p increasing refcount to %u.\n", swapchain, refcount);
  157 
  158     return refcount;
  159 }
  160 
  161 ULONG CDECL wined3d_swapchain_decref(struct wined3d_swapchain *swapchain)
  162 {
  163     ULONG refcount = InterlockedDecrement(&swapchain->ref);
  164 
  165     TRACE("%p decreasing refcount to %u.\n", swapchain, refcount);
  166 
  167     if (!refcount)
  168     {
  169         struct wined3d_device *device;
  170 
  171         wined3d_mutex_lock();
  172 
  173         device = swapchain->device;
  174         if (device->swapchain_count && device->swapchains[0] == swapchain)
  175             wined3d_device_uninit_3d(device);
  176         wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
  177 
  178         swapchain->parent_ops->wined3d_object_destroyed(swapchain->parent);
  179         swapchain->device->adapter->adapter_ops->adapter_destroy_swapchain(swapchain);
  180 
  181         wined3d_mutex_unlock();
  182     }
  183 
  184     return refcount;
  185 }
  186 
  187 void * CDECL wined3d_swapchain_get_parent(const struct wined3d_swapchain *swapchain)
  188 {
  189     TRACE("swapchain %p.\n", swapchain);
  190 
  191     return swapchain->parent;
  192 }
  193 
  194 void CDECL wined3d_swapchain_set_window(struct wined3d_swapchain *swapchain, HWND window)
  195 {
  196     if (!window)
  197         window = swapchain->state.device_window;
  198     if (window == swapchain->win_handle)
  199         return;
  200 
  201     TRACE("Setting swapchain %p window from %p to %p.\n",
  202             swapchain, swapchain->win_handle, window);
  203 
  204     wined3d_cs_finish(swapchain->device->cs, WINED3D_CS_QUEUE_DEFAULT);
  205 
  206     swapchain->win_handle = window;
  207 }
  208 
  209 HRESULT CDECL wined3d_swapchain_present(struct wined3d_swapchain *swapchain,
  210         const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override,
  211         unsigned int swap_interval, DWORD flags)
  212 {
  213     RECT s, d;
  214 
  215     TRACE("swapchain %p, src_rect %s, dst_rect %s, dst_window_override %p, swap_interval %u, flags %#x.\n",
  216             swapchain, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
  217             dst_window_override, swap_interval, flags);
  218 
  219     if (flags)
  220         FIXME("Ignoring flags %#x.\n", flags);
  221 
  222     wined3d_mutex_lock();
  223 
  224     if (!swapchain->back_buffers)
  225     {
  226         WARN("Swapchain doesn't have a backbuffer, returning WINED3DERR_INVALIDCALL.\n");
  227         wined3d_mutex_unlock();
  228         return WINED3DERR_INVALIDCALL;
  229     }
  230 
  231     if (!src_rect)
  232     {
  233         SetRect(&s, 0, 0, swapchain->state.desc.backbuffer_width,
  234                 swapchain->state.desc.backbuffer_height);
  235         src_rect = &s;
  236     }
  237 
  238     if (!dst_rect)
  239     {
  240         GetClientRect(swapchain->win_handle, &d);
  241         dst_rect = &d;
  242     }
  243 
  244     wined3d_cs_emit_present(swapchain->device->cs, swapchain, src_rect,
  245             dst_rect, dst_window_override, swap_interval, flags);
  246 
  247     wined3d_mutex_unlock();
  248 
  249     return WINED3D_OK;
  250 }
  251 
  252 HRESULT CDECL wined3d_swapchain_get_front_buffer_data(const struct wined3d_swapchain *swapchain,
  253         struct wined3d_texture *dst_texture, unsigned int sub_resource_idx)
  254 {
  255     RECT src_rect, dst_rect;
  256 
  257     TRACE("swapchain %p, dst_texture %p, sub_resource_idx %u.\n", swapchain, dst_texture, sub_resource_idx);
  258 
  259     SetRect(&src_rect, 0, 0, swapchain->front_buffer->resource.width, swapchain->front_buffer->resource.height);
  260     dst_rect = src_rect;
  261 
  262     if (swapchain->state.desc.windowed)
  263     {
  264         MapWindowPoints(swapchain->win_handle, NULL, (POINT *)&dst_rect, 2);
  265         FIXME("Using destination rect %s in windowed mode, this is likely wrong.\n",
  266                 wine_dbgstr_rect(&dst_rect));
  267     }
  268 
  269     return wined3d_texture_blt(dst_texture, sub_resource_idx, &dst_rect,
  270             swapchain->front_buffer, 0, &src_rect, 0, NULL, WINED3D_TEXF_POINT);
  271 }
  272 
  273 struct wined3d_texture * CDECL wined3d_swapchain_get_back_buffer(const struct wined3d_swapchain *swapchain,
  274         UINT back_buffer_idx)
  275 {
  276     TRACE("swapchain %p, back_buffer_idx %u.\n",
  277             swapchain, back_buffer_idx);
  278 
  279     /* Return invalid if there is no backbuffer array, otherwise it will
  280      * crash when ddraw is used (there swapchain->back_buffers is always
  281      * NULL). We need this because this function is called from
  282      * stateblock_init_default_state() to get the default scissorrect
  283      * dimensions. */
  284     if (!swapchain->back_buffers || back_buffer_idx >= swapchain->state.desc.backbuffer_count)
  285     {
  286         WARN("Invalid back buffer index.\n");
  287         /* Native d3d9 doesn't set NULL here, just as wine's d3d9. But set it
  288          * here in wined3d to avoid problems in other libs. */
  289         return NULL;
  290     }
  291 
  292     TRACE("Returning back buffer %p.\n", swapchain->back_buffers[back_buffer_idx]);
  293 
  294     return swapchain->back_buffers[back_buffer_idx];
  295 }
  296 
  297 struct wined3d_output * wined3d_swapchain_get_output(const struct wined3d_swapchain *swapchain)
  298 {
  299     TRACE("swapchain %p.\n", swapchain);
  300 
  301     return swapchain->state.desc.output;
  302 }
  303 
  304 HRESULT CDECL wined3d_swapchain_get_raster_status(const struct wined3d_swapchain *swapchain,
  305         struct wined3d_raster_status *raster_status)
  306 {
  307     struct wined3d_output *output;
  308 
  309     TRACE("swapchain %p, raster_status %p.\n", swapchain, raster_status);
  310 
  311     output = wined3d_swapchain_get_output(swapchain);
  312     if (!output)
  313     {
  314         ERR("Failed to get output from swapchain %p.\n", swapchain);
  315         return E_FAIL;
  316     }
  317 
  318     return wined3d_output_get_raster_status(output, raster_status);
  319 }
  320 
  321 struct wined3d_swapchain_state * CDECL wined3d_swapchain_get_state(struct wined3d_swapchain *swapchain)
  322 {
  323     return &swapchain->state;
  324 }
  325 
  326 HRESULT CDECL wined3d_swapchain_get_display_mode(const struct wined3d_swapchain *swapchain,
  327         struct wined3d_display_mode *mode, enum wined3d_display_rotation *rotation)
  328 {
  329     struct wined3d_output *output;
  330     HRESULT hr;
  331 
  332     TRACE("swapchain %p, mode %p, rotation %p.\n", swapchain, mode, rotation);
  333 
  334     if (!(output = wined3d_swapchain_get_output(swapchain)))
  335     {
  336         ERR("Failed to get output from swapchain %p.\n", swapchain);
  337         return E_FAIL;
  338     }
  339 
  340     hr = wined3d_output_get_display_mode(output, mode, rotation);
  341 
  342     TRACE("Returning w %u, h %u, refresh rate %u, format %s.\n",
  343             mode->width, mode->height, mode->refresh_rate, debug_d3dformat(mode->format_id));
  344 
  345     return hr;
  346 }
  347 
  348 struct wined3d_device * CDECL wined3d_swapchain_get_device(const struct wined3d_swapchain *swapchain)
  349 {
  350     TRACE("swapchain %p.\n", swapchain);
  351 
  352     return swapchain->device;
  353 }
  354 
  355 void CDECL wined3d_swapchain_get_desc(const struct wined3d_swapchain *swapchain,
  356         struct wined3d_swapchain_desc *desc)
  357 {
  358     TRACE("swapchain %p, desc %p.\n", swapchain, desc);
  359 
  360     *desc = swapchain->state.desc;
  361 }
  362 
  363 HRESULT CDECL wined3d_swapchain_set_gamma_ramp(const struct wined3d_swapchain *swapchain,
  364         DWORD flags, const struct wined3d_gamma_ramp *ramp)
  365 {
  366     HDC dc;
  367 
  368     TRACE("swapchain %p, flags %#x, ramp %p.\n", swapchain, flags, ramp);
  369 
  370     if (flags)
  371         FIXME("Ignoring flags %#x.\n", flags);
  372 
  373     dc = GetDCEx(swapchain->state.device_window, 0, DCX_USESTYLE | DCX_CACHE);
  374     SetDeviceGammaRamp(dc, (void *)ramp);
  375     ReleaseDC(swapchain->state.device_window, dc);
  376 
  377     return WINED3D_OK;
  378 }
  379 
  380 void CDECL wined3d_swapchain_set_palette(struct wined3d_swapchain *swapchain, struct wined3d_palette *palette)
  381 {
  382     TRACE("swapchain %p, palette %p.\n", swapchain, palette);
  383 
  384     wined3d_cs_finish(swapchain->device->cs, WINED3D_CS_QUEUE_DEFAULT);
  385 
  386     swapchain->palette = palette;
  387 }
  388 
  389 HRESULT CDECL wined3d_swapchain_get_gamma_ramp(const struct wined3d_swapchain *swapchain,
  390         struct wined3d_gamma_ramp *ramp)
  391 {
  392     HDC dc;
  393 
  394     TRACE("swapchain %p, ramp %p.\n", swapchain, ramp);
  395 
  396     dc = GetDCEx(swapchain->state.device_window, 0, DCX_USESTYLE | DCX_CACHE);
  397     GetDeviceGammaRamp(dc, ramp);
  398     ReleaseDC(swapchain->state.device_window, dc);
  399 
  400     return WINED3D_OK;
  401 }
  402 
  403 /* The is a fallback for cases where we e.g. can't create a GL context or
  404  * Vulkan swapchain for the swapchain window. */
  405 static void swapchain_blit_gdi(struct wined3d_swapchain *swapchain,
  406         struct wined3d_context *context, const RECT *src_rect, const RECT *dst_rect)
  407 {
  408     struct wined3d_texture *back_buffer = swapchain->back_buffers[0];
  409     D3DKMT_DESTROYDCFROMMEMORY destroy_desc;
  410     D3DKMT_CREATEDCFROMMEMORY create_desc;
  411     const struct wined3d_format *format;
  412     unsigned int row_pitch, slice_pitch;
  413     HDC src_dc, dst_dc;
  414     NTSTATUS status;
  415     HBITMAP bitmap;
  416 
  417     static unsigned int once;
  418 
  419     TRACE("swapchain %p, context %p, src_rect %s, dst_rect %s.\n",
  420             swapchain, context, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect));
  421 
  422     if (!once++)
  423         FIXME("Using GDI present.\n");
  424 
  425     format = back_buffer->resource.format;
  426     if (!format->ddi_format)
  427     {
  428         WARN("Cannot create a DC for format %s.\n", debug_d3dformat(format->id));
  429         return;
  430     }
  431 
  432     wined3d_texture_load_location(back_buffer, 0, context, WINED3D_LOCATION_SYSMEM);
  433     wined3d_texture_get_pitch(back_buffer, 0, &row_pitch, &slice_pitch);
  434 
  435     create_desc.pMemory = back_buffer->resource.heap_memory;
  436     create_desc.Format = format->ddi_format;
  437     create_desc.Width = wined3d_texture_get_level_width(back_buffer, 0);
  438     create_desc.Height = wined3d_texture_get_level_height(back_buffer, 0);
  439     create_desc.Pitch = row_pitch;
  440     create_desc.hDeviceDc = CreateCompatibleDC(NULL);
  441     create_desc.pColorTable = NULL;
  442 
  443     status = D3DKMTCreateDCFromMemory(&create_desc);
  444     DeleteDC(create_desc.hDeviceDc);
  445     if (status)
  446     {
  447         WARN("Failed to create DC, status %#x.\n", status);
  448         return;
  449     }
  450 
  451     src_dc = create_desc.hDc;
  452     bitmap = create_desc.hBitmap;
  453 
  454     TRACE("Created source DC %p, bitmap %p for backbuffer %p.\n", src_dc, bitmap, back_buffer);
  455 
  456     if (!(dst_dc = GetDCEx(swapchain->win_handle, 0, DCX_USESTYLE | DCX_CACHE)))
  457         ERR("Failed to get destination DC.\n");
  458 
  459     if (!BitBlt(dst_dc, dst_rect->left, dst_rect->top, dst_rect->right - dst_rect->left,
  460             dst_rect->bottom - dst_rect->top, src_dc, src_rect->left, src_rect->top, SRCCOPY))
  461         ERR("Failed to blit.\n");
  462 
  463     ReleaseDC(swapchain->win_handle, dst_dc);
  464     destroy_desc.hDc = src_dc;
  465     destroy_desc.hBitmap = bitmap;
  466     if ((status = D3DKMTDestroyDCFromMemory(&destroy_desc)))
  467         ERR("Failed to destroy src dc, status %#x.\n", status);
  468 }
  469 
  470 /* A GL context is provided by the caller */
  471 static void swapchain_blit(const struct wined3d_swapchain *swapchain,
  472         struct wined3d_context *context, const RECT *src_rect, const RECT *dst_rect)
  473 {
  474     struct wined3d_texture *texture = swapchain->back_buffers[0];
  475     struct wined3d_device *device = swapchain->device;
  476     enum wined3d_texture_filter_type filter;
  477     DWORD location;
  478 
  479     TRACE("swapchain %p, context %p, src_rect %s, dst_rect %s.\n",
  480             swapchain, context, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect));
  481 
  482     if ((src_rect->right - src_rect->left == dst_rect->right - dst_rect->left
  483             && src_rect->bottom - src_rect->top == dst_rect->bottom - dst_rect->top)
  484             || is_complex_fixup(texture->resource.format->color_fixup))
  485         filter = WINED3D_TEXF_NONE;
  486     else
  487         filter = WINED3D_TEXF_LINEAR;
  488 
  489     location = WINED3D_LOCATION_TEXTURE_RGB;
  490     if (texture->resource.multisample_type)
  491         location = WINED3D_LOCATION_RB_RESOLVED;
  492 
  493     wined3d_texture_validate_location(texture, 0, WINED3D_LOCATION_DRAWABLE);
  494     device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_COLOR_BLIT, context, texture, 0,
  495             location, src_rect, texture, 0, WINED3D_LOCATION_DRAWABLE, dst_rect, NULL, filter);
  496     wined3d_texture_invalidate_location(texture, 0, WINED3D_LOCATION_DRAWABLE);
  497 }
  498 
  499 static void swapchain_gl_set_swap_interval(struct wined3d_swapchain *swapchain,
  500         struct wined3d_context_gl *context_gl, unsigned int swap_interval)
  501 {
  502     const struct wined3d_gl_info *gl_info = context_gl->gl_info;
  503 
  504     swap_interval = swap_interval <= 4 ? swap_interval : 1;
  505     if (swapchain->swap_interval == swap_interval)
  506         return;
  507 
  508     swapchain->swap_interval = swap_interval;
  509 
  510     if (!gl_info->supported[WGL_EXT_SWAP_CONTROL])
  511         return;
  512 
  513     if (!GL_EXTCALL(wglSwapIntervalEXT(swap_interval)))
  514     {
  515         ERR("Failed to set swap interval %u for context %p, last error %#x.\n",
  516                 swap_interval, context_gl, GetLastError());
  517     }
  518 }
  519 
  520 /* Context activation is done by the caller. */
  521 static void wined3d_swapchain_gl_rotate(struct wined3d_swapchain *swapchain, struct wined3d_context *context)
  522 {
  523     struct wined3d_texture_sub_resource *sub_resource;
  524     struct wined3d_texture_gl *texture, *texture_prev;
  525     struct gl_texture tex0;
  526     GLuint rb0;
  527     DWORD locations0;
  528     unsigned int i;
  529     static const DWORD supported_locations = WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_RB_MULTISAMPLE;
  530 
  531     if (swapchain->state.desc.backbuffer_count < 2 || !swapchain->render_to_fbo)
  532         return;
  533 
  534     texture_prev = wined3d_texture_gl(swapchain->back_buffers[0]);
  535 
  536     /* Back buffer 0 is already in the draw binding. */
  537     tex0 = texture_prev->texture_rgb;
  538     rb0 = texture_prev->rb_multisample;
  539     locations0 = texture_prev->t.sub_resources[0].locations;
  540 
  541     for (i = 1; i < swapchain->state.desc.backbuffer_count; ++i)
  542     {
  543         texture = wined3d_texture_gl(swapchain->back_buffers[i]);
  544         sub_resource = &texture->t.sub_resources[0];
  545 
  546         if (!(sub_resource->locations & supported_locations))
  547             wined3d_texture_load_location(&texture->t, 0, context, texture->t.resource.draw_binding);
  548 
  549         texture_prev->texture_rgb = texture->texture_rgb;
  550         texture_prev->rb_multisample = texture->rb_multisample;
  551 
  552         wined3d_texture_validate_location(&texture_prev->t, 0, sub_resource->locations & supported_locations);
  553         wined3d_texture_invalidate_location(&texture_prev->t, 0, ~(sub_resource->locations & supported_locations));
  554 
  555         texture_prev = texture;
  556     }
  557 
  558     texture_prev->texture_rgb = tex0;
  559     texture_prev->rb_multisample = rb0;
  560 
  561     wined3d_texture_validate_location(&texture_prev->t, 0, locations0 & supported_locations);
  562     wined3d_texture_invalidate_location(&texture_prev->t, 0, ~(locations0 & supported_locations));
  563 
  564     device_invalidate_state(swapchain->device, STATE_FRAMEBUFFER);
  565 }
  566 
  567 static void swapchain_gl_present(struct wined3d_swapchain *swapchain,
  568         const RECT *src_rect, const RECT *dst_rect, unsigned int swap_interval, DWORD flags)
  569 {
  570     struct wined3d_swapchain_gl *swapchain_gl = wined3d_swapchain_gl(swapchain);
  571     const struct wined3d_swapchain_desc *desc = &swapchain->state.desc;
  572     struct wined3d_texture *back_buffer = swapchain->back_buffers[0];
  573     const struct wined3d_gl_info *gl_info;
  574     struct wined3d_context_gl *context_gl;
  575     struct wined3d_context *context;
  576     BOOL render_to_fbo;
  577 
  578     context = context_acquire(swapchain->device, swapchain->front_buffer, 0);
  579     context_gl = wined3d_context_gl(context);
  580     if (!context_gl->valid)
  581     {
  582         context_release(context);
  583         WARN("Invalid context, skipping present.\n");
  584         return;
  585     }
  586 
  587     gl_info = context_gl->gl_info;
  588 
  589     swapchain_gl_set_swap_interval(swapchain, context_gl, swap_interval);
  590 
  591     TRACE("Presenting DC %p.\n", context_gl->dc);
  592 
  593     if (context_gl->dc == swapchain_gl->backup_dc)
  594         swapchain_blit_gdi(swapchain, context, src_rect, dst_rect);
  595 
  596     if (!(render_to_fbo = swapchain->render_to_fbo)
  597             && (src_rect->left || src_rect->top
  598             || src_rect->right != desc->backbuffer_width
  599             || src_rect->bottom != desc->backbuffer_height
  600             || dst_rect->left || dst_rect->top
  601             || dst_rect->right != desc->backbuffer_width
  602             || dst_rect->bottom != desc->backbuffer_height))
  603         render_to_fbo = TRUE;
  604 
  605     /* Rendering to a window of different size, presenting partial rectangles,
  606      * or rendering to a different window needs help from FBO_blit or a textured
  607      * draw. Render the swapchain to a FBO in the future.
  608      *
  609      * Note that FBO_blit from the backbuffer to the frontbuffer cannot solve
  610      * all these issues - this fails if the window is smaller than the backbuffer.
  611      */
  612     if (!swapchain->render_to_fbo && render_to_fbo && wined3d_settings.offscreen_rendering_mode == ORM_FBO)
  613     {
  614         wined3d_texture_load_location(back_buffer, 0, context, WINED3D_LOCATION_TEXTURE_RGB);
  615         wined3d_texture_invalidate_location(back_buffer, 0, WINED3D_LOCATION_DRAWABLE);
  616         swapchain->render_to_fbo = TRUE;
  617         swapchain_update_draw_bindings(swapchain);
  618     }
  619     else
  620     {
  621         wined3d_texture_load_location(back_buffer, 0, context, back_buffer->resource.draw_binding);
  622     }
  623 
  624     if (swapchain->render_to_fbo)
  625         swapchain_blit(swapchain, context, src_rect, dst_rect);
  626 
  627     if (swapchain_gl->context_count > 1)
  628         gl_info->gl_ops.gl.p_glFinish();
  629 
  630     /* call wglSwapBuffers through the gl table to avoid confusing the Steam overlay */
  631     gl_info->gl_ops.wgl.p_wglSwapBuffers(context_gl->dc);
  632     wined3d_context_gl_submit_command_fence(context_gl);
  633 
  634     wined3d_swapchain_gl_rotate(swapchain, context);
  635 
  636     TRACE("SwapBuffers called, Starting new frame\n");
  637 
  638     wined3d_texture_validate_location(swapchain->front_buffer, 0, WINED3D_LOCATION_DRAWABLE);
  639     wined3d_texture_invalidate_location(swapchain->front_buffer, 0, ~WINED3D_LOCATION_DRAWABLE);
  640 
  641     context_release(context);
  642 }
  643 
  644 static void swapchain_frontbuffer_updated(struct wined3d_swapchain *swapchain)
  645 {
  646     struct wined3d_texture *front_buffer = swapchain->front_buffer;
  647     struct wined3d_context *context;
  648 
  649     context = context_acquire(swapchain->device, front_buffer, 0);
  650     wined3d_texture_load_location(front_buffer, 0, context, front_buffer->resource.draw_binding);
  651     context_release(context);
  652     SetRectEmpty(&swapchain->front_buffer_update);
  653 }
  654 
  655 static const struct wined3d_swapchain_ops swapchain_gl_ops =
  656 {
  657     swapchain_gl_present,
  658     swapchain_frontbuffer_updated,
  659 };
  660 
  661 static bool wined3d_swapchain_vk_present_mode_supported(struct wined3d_swapchain_vk *swapchain_vk,
  662         VkPresentModeKHR vk_present_mode)
  663 {
  664     struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device);
  665     const struct wined3d_vk_info *vk_info;
  666     struct wined3d_adapter_vk *adapter_vk;
  667     VkPhysicalDevice vk_physical_device;
  668     VkPresentModeKHR *vk_modes;
  669     bool supported = false;
  670     uint32_t count, i;
  671     VkResult vr;
  672 
  673     adapter_vk = wined3d_adapter_vk(device_vk->d.adapter);
  674     vk_physical_device = adapter_vk->physical_device;
  675     vk_info = &adapter_vk->vk_info;
  676 
  677     if ((vr = VK_CALL(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical_device,
  678             swapchain_vk->vk_surface, &count, NULL))) < 0)
  679     {
  680         ERR("Failed to get supported present mode count, vr %s.\n", wined3d_debug_vkresult(vr));
  681         return false;
  682     }
  683 
  684     if (!(vk_modes = heap_calloc(count, sizeof(*vk_modes))))
  685         return false;
  686 
  687     if ((vr = VK_CALL(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical_device,
  688             swapchain_vk->vk_surface, &count, vk_modes))) < 0)
  689     {
  690         ERR("Failed to get supported present modes, vr %s.\n", wined3d_debug_vkresult(vr));
  691         goto done;
  692     }
  693 
  694     for (i = 0; i < count; ++i)
  695     {
  696         if (vk_modes[i] == vk_present_mode)
  697         {
  698             supported = true;
  699             goto done;
  700         }
  701     }
  702 
  703 done:
  704     heap_free(vk_modes);
  705     return supported;
  706 }
  707 
  708 static VkFormat get_swapchain_fallback_format(VkFormat vk_format)
  709 {
  710     switch (vk_format)
  711     {
  712         case VK_FORMAT_R8G8B8A8_SRGB:
  713             return VK_FORMAT_B8G8R8A8_SRGB;
  714         case VK_FORMAT_R8G8B8A8_UNORM:
  715         case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
  716         case VK_FORMAT_R16G16B16A16_SFLOAT:
  717             return VK_FORMAT_B8G8R8A8_UNORM;
  718         default:
  719             WARN("Unhandled format %#x.\n", vk_format);
  720             return VK_FORMAT_UNDEFINED;
  721     }
  722 }
  723 
  724 static VkFormat wined3d_swapchain_vk_select_vk_format(struct wined3d_swapchain_vk *swapchain_vk,
  725         VkSurfaceKHR vk_surface)
  726 {
  727     struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device);
  728     const struct wined3d_swapchain_desc *desc = &swapchain_vk->s.state.desc;
  729     const struct wined3d_vk_info *vk_info;
  730     struct wined3d_adapter_vk *adapter_vk;
  731     const struct wined3d_format *format;
  732     VkPhysicalDevice vk_physical_device;
  733     VkSurfaceFormatKHR *vk_formats;
  734     uint32_t format_count, i;
  735     VkFormat vk_format;
  736     VkResult vr;
  737 
  738     adapter_vk = wined3d_adapter_vk(device_vk->d.adapter);
  739     vk_physical_device = adapter_vk->physical_device;
  740     vk_info = &adapter_vk->vk_info;
  741 
  742     if ((format = wined3d_get_format(&adapter_vk->a, desc->backbuffer_format, WINED3D_BIND_RENDER_TARGET)))
  743         vk_format = wined3d_format_vk(format)->vk_format;
  744     else
  745         vk_format = VK_FORMAT_B8G8R8A8_UNORM;
  746 
  747     vr = VK_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, NULL));
  748     if (vr < 0 || !format_count)
  749     {
  750         WARN("Failed to get supported surface format count, vr %s.\n", wined3d_debug_vkresult(vr));
  751         return VK_FORMAT_UNDEFINED;
  752     }
  753 
  754     if (!(vk_formats = heap_calloc(format_count, sizeof(*vk_formats))))
  755         return VK_FORMAT_UNDEFINED;
  756 
  757     if ((vr = VK_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device,
  758             vk_surface, &format_count, vk_formats))) < 0)
  759     {
  760         WARN("Failed to get supported surface formats, vr %s.\n", wined3d_debug_vkresult(vr));
  761         heap_free(vk_formats);
  762         return VK_FORMAT_UNDEFINED;
  763     }
  764 
  765     for (i = 0; i < format_count; ++i)
  766     {
  767         if (vk_formats[i].format == vk_format && vk_formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
  768             break;
  769     }
  770     if (i == format_count)
  771     {
  772         /* Try to create a swapchain with format conversion. */
  773         vk_format = get_swapchain_fallback_format(vk_format);
  774         WARN("Failed to find Vulkan swapchain format for %s.\n", debug_d3dformat(desc->backbuffer_format));
  775         for (i = 0; i < format_count; ++i)
  776         {
  777             if (vk_formats[i].format == vk_format && vk_formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
  778                 break;
  779         }
  780     }
  781     heap_free(vk_formats);
  782     if (i == format_count)
  783     {
  784         FIXME("Failed to find Vulkan swapchain format for %s.\n", debug_d3dformat(desc->backbuffer_format));
  785         return VK_FORMAT_UNDEFINED;
  786     }
  787 
  788     TRACE("Using Vulkan swapchain format %#x.\n", vk_format);
  789 
  790     return vk_format;
  791 }
  792 
  793 static bool wined3d_swapchain_vk_create_vulkan_swapchain_images(struct wined3d_swapchain_vk *swapchain_vk,
  794         VkSwapchainKHR vk_swapchain)
  795 {
  796     struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device);
  797     const struct wined3d_vk_info *vk_info;
  798     VkSemaphoreCreateInfo semaphore_info;
  799     uint32_t image_count, i;
  800     VkResult vr;
  801 
  802     vk_info = &wined3d_adapter_vk(device_vk->d.adapter)->vk_info;
  803 
  804     if ((vr = VK_CALL(vkGetSwapchainImagesKHR(device_vk->vk_device, vk_swapchain, &image_count, NULL))) < 0)
  805     {
  806         ERR("Failed to get image count, vr %s\n", wined3d_debug_vkresult(vr));
  807         return false;
  808     }
  809 
  810     if (!(swapchain_vk->vk_images = heap_calloc(image_count, sizeof(*swapchain_vk->vk_images))))
  811     {
  812         ERR("Failed to allocate images array.\n");
  813         return false;
  814     }
  815 
  816     if ((vr = VK_CALL(vkGetSwapchainImagesKHR(device_vk->vk_device,
  817             vk_swapchain, &image_count, swapchain_vk->vk_images))) < 0)
  818     {
  819         ERR("Failed to get swapchain images, vr %s.\n", wined3d_debug_vkresult(vr));
  820         heap_free(swapchain_vk->vk_images);
  821         return false;
  822     }
  823 
  824     if (!(swapchain_vk->vk_semaphores = heap_calloc(image_count, sizeof(*swapchain_vk->vk_semaphores))))
  825     {
  826         ERR("Failed to allocate semaphores array.\n");
  827         heap_free(swapchain_vk->vk_images);
  828         return false;
  829     }
  830 
  831     semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
  832     semaphore_info.pNext = NULL;
  833     semaphore_info.flags = 0;
  834     for (i = 0; i < image_count; ++i)
  835     {
  836         if ((vr = VK_CALL(vkCreateSemaphore(device_vk->vk_device,
  837                 &semaphore_info, NULL, &swapchain_vk->vk_semaphores[i].available))) < 0)
  838         {
  839             ERR("Failed to create semaphore, vr %s.\n", wined3d_debug_vkresult(vr));
  840             goto fail;
  841         }
  842 
  843         if ((vr = VK_CALL(vkCreateSemaphore(device_vk->vk_device,
  844                 &semaphore_info, NULL, &swapchain_vk->vk_semaphores[i].presentable))) < 0)
  845         {
  846             ERR("Failed to create semaphore, vr %s.\n", wined3d_debug_vkresult(vr));
  847             goto fail;
  848         }
  849     }
  850     swapchain_vk->image_count = image_count;
  851 
  852     return true;
  853 
  854 fail:
  855     for (i = 0; i < image_count; ++i)
  856     {
  857         if (swapchain_vk->vk_semaphores[i].available)
  858             VK_CALL(vkDestroySemaphore(device_vk->vk_device, swapchain_vk->vk_semaphores[i].available, NULL));
  859         if (swapchain_vk->vk_semaphores[i].presentable)
  860             VK_CALL(vkDestroySemaphore(device_vk->vk_device, swapchain_vk->vk_semaphores[i].presentable, NULL));
  861     }
  862     heap_free(swapchain_vk->vk_semaphores);
  863     heap_free(swapchain_vk->vk_images);
  864     return false;
  865 }
  866 
  867 static HRESULT wined3d_swapchain_vk_create_vulkan_swapchain(struct wined3d_swapchain_vk *swapchain_vk)
  868 {
  869     struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device);
  870     const struct wined3d_swapchain_desc *desc = &swapchain_vk->s.state.desc;
  871     VkSwapchainCreateInfoKHR vk_swapchain_desc;
  872     VkWin32SurfaceCreateInfoKHR surface_desc;
  873     unsigned int width, height, image_count;
  874     const struct wined3d_vk_info *vk_info;
  875     VkSurfaceCapabilitiesKHR surface_caps;
  876     struct wined3d_adapter_vk *adapter_vk;
  877     VkPresentModeKHR vk_present_mode;
  878     VkSwapchainKHR vk_swapchain;
  879     VkImageUsageFlags usage;
  880     VkSurfaceKHR vk_surface;
  881     VkBool32 supported;
  882     VkFormat vk_format;
  883     VkResult vr;
  884 
  885     adapter_vk = wined3d_adapter_vk(device_vk->d.adapter);
  886     vk_info = &adapter_vk->vk_info;
  887 
  888     surface_desc.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
  889     surface_desc.pNext = NULL;
  890     surface_desc.flags = 0;
  891     surface_desc.hinstance = (HINSTANCE)GetWindowLongPtrW(swapchain_vk->s.win_handle, GWLP_HINSTANCE);
  892     surface_desc.hwnd = swapchain_vk->s.win_handle;
  893     if ((vr = VK_CALL(vkCreateWin32SurfaceKHR(vk_info->instance, &surface_desc, NULL, &vk_surface))) < 0)
  894     {
  895         ERR("Failed to create Vulkan surface, vr %s.\n", wined3d_debug_vkresult(vr));
  896         return E_FAIL;
  897     }
  898     swapchain_vk->vk_surface = vk_surface;
  899 
  900     if ((vr = VK_CALL(vkGetPhysicalDeviceSurfaceSupportKHR(adapter_vk->physical_device,
  901             device_vk->vk_queue_family_index, vk_surface, &supported))) < 0 || !supported)
  902     {
  903         ERR("Queue family does not support presentation on this surface, vr %s.\n", wined3d_debug_vkresult(vr));
  904         goto fail;
  905     }
  906 
  907     if ((vk_format = wined3d_swapchain_vk_select_vk_format(swapchain_vk, vk_surface)) == VK_FORMAT_UNDEFINED)
  908     {
  909         ERR("Failed to select swapchain format.\n");
  910         goto fail;
  911     }
  912 
  913     if ((vr = VK_CALL(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(adapter_vk->physical_device,
  914             swapchain_vk->vk_surface, &surface_caps))) < 0)
  915     {
  916         ERR("Failed to get surface capabilities, vr %s.\n", wined3d_debug_vkresult(vr));
  917         goto fail;
  918     }
  919 
  920     image_count = desc->backbuffer_count;
  921     if (image_count < surface_caps.minImageCount)
  922         image_count = surface_caps.minImageCount;
  923     else if (surface_caps.maxImageCount && image_count > surface_caps.maxImageCount)
  924         image_count = surface_caps.maxImageCount;
  925 
  926     if (image_count != desc->backbuffer_count)
  927         WARN("Image count %u is not supported (%u-%u).\n", desc->backbuffer_count,
  928                 surface_caps.minImageCount, surface_caps.maxImageCount);
  929 
  930     width = desc->backbuffer_width;
  931     if (width < surface_caps.minImageExtent.width)
  932         width = surface_caps.minImageExtent.width;
  933     else if (width > surface_caps.maxImageExtent.width)
  934         width = surface_caps.maxImageExtent.width;
  935 
  936     height = desc->backbuffer_height;
  937     if (height < surface_caps.minImageExtent.height)
  938         height = surface_caps.minImageExtent.height;
  939     else if (height > surface_caps.maxImageExtent.height)
  940         height = surface_caps.maxImageExtent.height;
  941 
  942     if (width != desc->backbuffer_width || height != desc->backbuffer_height)
  943         WARN("Swapchain dimensions %ux%u are not supported (%u-%u x %u-%u).\n",
  944                 desc->backbuffer_width, desc->backbuffer_height,
  945                 surface_caps.minImageExtent.width, surface_caps.maxImageExtent.width,
  946                 surface_caps.minImageExtent.height, surface_caps.maxImageExtent.height);
  947 
  948     usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  949     usage |= surface_caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
  950     usage |= surface_caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT;
  951     if (!(usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) || !(usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
  952         WARN("Transfer not supported for swapchain images.\n");
  953 
  954     if (!(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR))
  955     {
  956         FIXME("Unsupported alpha mode, %#x.\n", surface_caps.supportedCompositeAlpha);
  957         goto fail;
  958     }
  959 
  960     vk_present_mode = VK_PRESENT_MODE_FIFO_KHR;
  961     if (!swapchain_vk->s.swap_interval)
  962     {
  963         if (wined3d_swapchain_vk_present_mode_supported(swapchain_vk, VK_PRESENT_MODE_IMMEDIATE_KHR))
  964             vk_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
  965         else
  966             FIXME("Unsupported swap interval %u.\n", swapchain_vk->s.swap_interval);
  967     }
  968 
  969     vk_swapchain_desc.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
  970     vk_swapchain_desc.pNext = NULL;
  971     vk_swapchain_desc.flags = 0;
  972     vk_swapchain_desc.surface = vk_surface;
  973     vk_swapchain_desc.minImageCount = image_count;
  974     vk_swapchain_desc.imageFormat = vk_format;
  975     vk_swapchain_desc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
  976     vk_swapchain_desc.imageExtent.width = width;
  977     vk_swapchain_desc.imageExtent.height = height;
  978     vk_swapchain_desc.imageArrayLayers = 1;
  979     vk_swapchain_desc.imageUsage = usage;
  980     vk_swapchain_desc.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
  981     vk_swapchain_desc.queueFamilyIndexCount = 0;
  982     vk_swapchain_desc.pQueueFamilyIndices = NULL;
  983     vk_swapchain_desc.preTransform = surface_caps.currentTransform;
  984     vk_swapchain_desc.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  985     vk_swapchain_desc.presentMode = vk_present_mode;
  986     vk_swapchain_desc.clipped = VK_TRUE;
  987     vk_swapchain_desc.oldSwapchain = VK_NULL_HANDLE;
  988     if ((vr = VK_CALL(vkCreateSwapchainKHR(device_vk->vk_device, &vk_swapchain_desc, NULL, &vk_swapchain))) < 0)
  989     {
  990         ERR("Failed to create Vulkan swapchain, vr %s.\n", wined3d_debug_vkresult(vr));
  991         goto fail;
  992     }
  993     swapchain_vk->vk_swapchain = vk_swapchain;
  994 
  995     if (!wined3d_swapchain_vk_create_vulkan_swapchain_images(swapchain_vk, vk_swapchain))
  996     {
  997         VK_CALL(vkDestroySwapchainKHR(device_vk->vk_device, vk_swapchain, NULL));
  998         goto fail;
  999     }
 1000 
 1001     return WINED3D_OK;
 1002 
 1003 fail:
 1004     VK_CALL(vkDestroySurfaceKHR(vk_info->instance, vk_surface, NULL));
 1005     return E_FAIL;
 1006 }
 1007 
 1008 static HRESULT wined3d_swapchain_vk_recreate(struct wined3d_swapchain_vk *swapchain_vk)
 1009 {
 1010     TRACE("swapchain_vk %p.\n", swapchain_vk);
 1011 
 1012     wined3d_swapchain_vk_destroy_vulkan_swapchain(swapchain_vk);
 1013 
 1014     return wined3d_swapchain_vk_create_vulkan_swapchain(swapchain_vk);
 1015 }
 1016 
 1017 static void wined3d_swapchain_vk_set_swap_interval(struct wined3d_swapchain_vk *swapchain_vk,
 1018         unsigned int swap_interval)
 1019 {
 1020     if (swap_interval > 1)
 1021     {
 1022         if (swap_interval <= 4)
 1023             FIXME("Unsupported swap interval %u.\n", swap_interval);
 1024         swap_interval = 1;
 1025     }
 1026 
 1027     if (swapchain_vk->s.swap_interval == swap_interval)
 1028         return;
 1029 
 1030     swapchain_vk->s.swap_interval = swap_interval;
 1031     wined3d_swapchain_vk_recreate(swapchain_vk);
 1032 }
 1033 
 1034 static void wined3d_swapchain_vk_blit(struct wined3d_swapchain_vk *swapchain_vk,
 1035         struct wined3d_context_vk *context_vk, const RECT *src_rect, const RECT *dst_rect, unsigned int swap_interval)
 1036 {
 1037     struct wined3d_texture_vk *back_buffer_vk = wined3d_texture_vk(swapchain_vk->s.back_buffers[0]);
 1038     struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device);
 1039     const struct wined3d_swapchain_desc *desc = &swapchain_vk->s.state.desc;
 1040     const struct wined3d_vk_info *vk_info = context_vk->vk_info;
 1041     VkCommandBuffer vk_command_buffer;
 1042     VkPresentInfoKHR present_desc;
 1043     unsigned int present_idx;
 1044     VkImageLayout vk_layout;
 1045     uint32_t image_idx;
 1046     VkImageBlit blit;
 1047     VkResult vr;
 1048     HRESULT hr;
 1049 
 1050     static const VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
 1051 
 1052     wined3d_swapchain_vk_set_swap_interval(swapchain_vk, swap_interval);
 1053 
 1054     present_idx = swapchain_vk->current++ % swapchain_vk->image_count;
 1055     wined3d_context_vk_wait_command_buffer(context_vk, swapchain_vk->vk_semaphores[present_idx].command_buffer_id);
 1056     vr = VK_CALL(vkAcquireNextImageKHR(device_vk->vk_device, swapchain_vk->vk_swapchain, UINT64_MAX,
 1057             swapchain_vk->vk_semaphores[present_idx].available, VK_NULL_HANDLE, &image_idx));
 1058     if (vr == VK_ERROR_OUT_OF_DATE_KHR)
 1059     {
 1060         if (FAILED(hr = wined3d_swapchain_vk_recreate(swapchain_vk)))
 1061         {
 1062             ERR("Failed to recreate swapchain, hr %#x.\n", hr);
 1063             return;
 1064         }
 1065         vr = VK_CALL(vkAcquireNextImageKHR(device_vk->vk_device, swapchain_vk->vk_swapchain, UINT64_MAX,
 1066                 swapchain_vk->vk_semaphores[present_idx].available, VK_NULL_HANDLE, &image_idx));
 1067     }
 1068     if (vr < 0)
 1069     {
 1070         ERR("Failed to acquire next Vulkan image, vr %s.\n", wined3d_debug_vkresult(vr));
 1071         return;
 1072     }
 1073 
 1074     vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
 1075 
 1076     wined3d_context_vk_end_current_render_pass(context_vk);
 1077 
 1078     wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
 1079             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
 1080             vk_access_mask_from_bind_flags(back_buffer_vk->t.resource.bind_flags),
 1081             VK_ACCESS_TRANSFER_READ_BIT,
 1082             back_buffer_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
 1083             back_buffer_vk->vk_image, VK_IMAGE_ASPECT_COLOR_BIT);
 1084 
 1085     wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
 1086             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
 1087             0, VK_ACCESS_TRANSFER_WRITE_BIT,
 1088             VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
 1089             swapchain_vk->vk_images[image_idx], VK_IMAGE_ASPECT_COLOR_BIT);
 1090 
 1091     blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 1092     blit.srcSubresource.mipLevel = 0;
 1093     blit.srcSubresource.baseArrayLayer = 0;
 1094     blit.srcSubresource.layerCount = 1;
 1095     blit.srcOffsets[0].x = src_rect->left;
 1096     blit.srcOffsets[0].y = src_rect->top;
 1097     blit.srcOffsets[0].z = 0;
 1098     blit.srcOffsets[1].x = src_rect->right;
 1099     blit.srcOffsets[1].y = src_rect->bottom;
 1100     blit.srcOffsets[1].z = 1;
 1101     blit.dstSubresource = blit.srcSubresource;
 1102     blit.dstOffsets[0].x = dst_rect->left;
 1103     blit.dstOffsets[0].y = dst_rect->top;
 1104     blit.dstOffsets[0].z = 0;
 1105     blit.dstOffsets[1].x = dst_rect->right;
 1106     blit.dstOffsets[1].y = dst_rect->bottom;
 1107     blit.dstOffsets[1].z = 1;
 1108     VK_CALL(vkCmdBlitImage(vk_command_buffer,
 1109             back_buffer_vk->vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
 1110             swapchain_vk->vk_images[image_idx], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
 1111             1, &blit, VK_FILTER_NEAREST));
 1112 
 1113     wined3d_context_vk_reference_texture(context_vk, back_buffer_vk);
 1114     wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
 1115             VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
 1116             VK_ACCESS_TRANSFER_WRITE_BIT, 0,
 1117             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
 1118             swapchain_vk->vk_images[image_idx], VK_IMAGE_ASPECT_COLOR_BIT);
 1119 
 1120     if (desc->swap_effect == WINED3D_SWAP_EFFECT_DISCARD || desc->swap_effect == WINED3D_SWAP_EFFECT_FLIP_DISCARD)
 1121         vk_layout = VK_IMAGE_LAYOUT_UNDEFINED;
 1122     else
 1123         vk_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
 1124     wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
 1125             VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
 1126             VK_ACCESS_TRANSFER_READ_BIT,
 1127             vk_access_mask_from_bind_flags(back_buffer_vk->t.resource.bind_flags),
 1128             vk_layout, back_buffer_vk->layout,
 1129             back_buffer_vk->vk_image, VK_IMAGE_ASPECT_COLOR_BIT);
 1130     back_buffer_vk->bind_mask = 0;
 1131 
 1132     swapchain_vk->vk_semaphores[present_idx].command_buffer_id = context_vk->current_command_buffer.id;
 1133     wined3d_context_vk_submit_command_buffer(context_vk,
 1134             1, &swapchain_vk->vk_semaphores[present_idx].available, &wait_stage,
 1135             1, &swapchain_vk->vk_semaphores[present_idx].presentable);
 1136 
 1137     present_desc.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
 1138     present_desc.pNext = NULL;
 1139     present_desc.waitSemaphoreCount = 1;
 1140     present_desc.pWaitSemaphores = &swapchain_vk->vk_semaphores[present_idx].presentable;
 1141     present_desc.swapchainCount = 1;
 1142     present_desc.pSwapchains = &swapchain_vk->vk_swapchain;
 1143     present_desc.pImageIndices = &image_idx;
 1144     present_desc.pResults = NULL;
 1145     if ((vr = VK_CALL(vkQueuePresentKHR(device_vk->vk_queue, &present_desc))))
 1146         ERR("Present returned vr %s.\n", wined3d_debug_vkresult(vr));
 1147 }
 1148 
 1149 static void wined3d_swapchain_vk_rotate(struct wined3d_swapchain *swapchain, struct wined3d_context_vk *context_vk)
 1150 {
 1151     struct wined3d_texture_sub_resource *sub_resource;
 1152     struct wined3d_texture_vk *texture, *texture_prev;
 1153     struct wined3d_allocator_block *memory0;
 1154     VkDescriptorImageInfo vk_info0;
 1155     VkDeviceMemory vk_memory0;
 1156     VkImageLayout vk_layout0;
 1157     VkImage vk_image0;
 1158     DWORD locations0;
 1159     unsigned int i;
 1160     uint64_t id0;
 1161 
 1162     static const DWORD supported_locations = WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_RB_MULTISAMPLE;
 1163 
 1164     if (swapchain->state.desc.backbuffer_count < 2)
 1165         return;
 1166 
 1167     texture_prev = wined3d_texture_vk(swapchain->back_buffers[0]);
 1168 
 1169     /* Back buffer 0 is already in the draw binding. */
 1170     vk_image0 = texture_prev->vk_image;
 1171     memory0 = texture_prev->memory;
 1172     vk_memory0 = texture_prev->vk_memory;
 1173     vk_layout0 = texture_prev->layout;
 1174     id0 = texture_prev->command_buffer_id;
 1175     vk_info0 = texture_prev->default_image_info;
 1176     locations0 = texture_prev->t.sub_resources[0].locations;
 1177 
 1178     for (i = 1; i < swapchain->state.desc.backbuffer_count; ++i)
 1179     {
 1180         texture = wined3d_texture_vk(swapchain->back_buffers[i]);
 1181         sub_resource = &texture->t.sub_resources[0];
 1182 
 1183         if (!(sub_resource->locations & supported_locations))
 1184             wined3d_texture_load_location(&texture->t, 0, &context_vk->c, texture->t.resource.draw_binding);
 1185 
 1186         texture_prev->vk_image = texture->vk_image;
 1187         texture_prev->memory = texture->memory;
 1188         texture_prev->vk_memory = texture->vk_memory;
 1189         texture_prev->layout = texture->layout;
 1190         texture_prev->command_buffer_id = texture->command_buffer_id;
 1191         texture_prev->default_image_info = texture->default_image_info;
 1192 
 1193         wined3d_texture_validate_location(&texture_prev->t, 0, sub_resource->locations & supported_locations);
 1194         wined3d_texture_invalidate_location(&texture_prev->t, 0, ~(sub_resource->locations & supported_locations));
 1195 
 1196         texture_prev = texture;
 1197     }
 1198 
 1199     texture_prev->vk_image = vk_image0;
 1200     texture_prev->memory = memory0;
 1201     texture_prev->vk_memory = vk_memory0;
 1202     texture_prev->layout = vk_layout0;
 1203     texture_prev->command_buffer_id = id0;
 1204     texture_prev->default_image_info = vk_info0;
 1205 
 1206     wined3d_texture_validate_location(&texture_prev->t, 0, locations0 & supported_locations);
 1207     wined3d_texture_invalidate_location(&texture_prev->t, 0, ~(locations0 & supported_locations));
 1208 
 1209     device_invalidate_state(swapchain->device, STATE_FRAMEBUFFER);
 1210 }
 1211 
 1212 static void swapchain_vk_present(struct wined3d_swapchain *swapchain, const RECT *src_rect,
 1213         const RECT *dst_rect, unsigned int swap_interval, uint32_t flags)
 1214 {
 1215     struct wined3d_swapchain_vk *swapchain_vk = wined3d_swapchain_vk(swapchain);
 1216     struct wined3d_texture *back_buffer = swapchain->back_buffers[0];
 1217     struct wined3d_context_vk *context_vk;
 1218 
 1219     context_vk = wined3d_context_vk(context_acquire(swapchain->device, back_buffer, 0));
 1220 
 1221     wined3d_texture_load_location(back_buffer, 0, &context_vk->c, back_buffer->resource.draw_binding);
 1222 
 1223     if (swapchain_vk->vk_swapchain)
 1224         wined3d_swapchain_vk_blit(swapchain_vk, context_vk, src_rect, dst_rect, swap_interval);
 1225     else
 1226         swapchain_blit_gdi(swapchain, &context_vk->c, src_rect, dst_rect);
 1227 
 1228     wined3d_swapchain_vk_rotate(swapchain, context_vk);
 1229 
 1230     wined3d_texture_validate_location(swapchain->front_buffer, 0, WINED3D_LOCATION_DRAWABLE);
 1231     wined3d_texture_invalidate_location(swapchain->front_buffer, 0, ~WINED3D_LOCATION_DRAWABLE);
 1232 
 1233     TRACE("Starting new frame.\n");
 1234 
 1235     context_release(&context_vk->c);
 1236 }
 1237 
 1238 static const struct wined3d_swapchain_ops swapchain_vk_ops =
 1239 {
 1240     swapchain_vk_present,
 1241     swapchain_frontbuffer_updated,
 1242 };
 1243 
 1244 static void swapchain_gdi_frontbuffer_updated(struct wined3d_swapchain *swapchain)
 1245 {
 1246     struct wined3d_dc_info *front;
 1247     POINT offset = {0, 0};
 1248     HDC src_dc, dst_dc;
 1249     RECT draw_rect;
 1250     HWND window;
 1251 
 1252     TRACE("swapchain %p.\n", swapchain);
 1253 
 1254     front = &swapchain->front_buffer->dc_info[0];
 1255     if (swapchain->palette)
 1256         wined3d_palette_apply_to_dc(swapchain->palette, front->dc);
 1257 
 1258     if (swapchain->front_buffer->resource.map_count)
 1259         ERR("Trying to blit a mapped surface.\n");
 1260 
 1261     TRACE("Copying surface %p to screen.\n", front);
 1262 
 1263     src_dc = front->dc;
 1264     window = swapchain->win_handle;
 1265     dst_dc = GetDCEx(window, 0, DCX_CLIPSIBLINGS | DCX_CACHE);
 1266 
 1267     /* Front buffer coordinates are screen coordinates. Map them to the
 1268      * destination window if not fullscreened. */
 1269     if (swapchain->state.desc.windowed)
 1270         ClientToScreen(window, &offset);
 1271 
 1272     TRACE("offset %s.\n", wine_dbgstr_point(&offset));
 1273 
 1274     SetRect(&draw_rect, 0, 0, swapchain->front_buffer->resource.width,
 1275             swapchain->front_buffer->resource.height);
 1276     IntersectRect(&draw_rect, &draw_rect, &swapchain->front_buffer_update);
 1277 
 1278     BitBlt(dst_dc, draw_rect.left - offset.x, draw_rect.top - offset.y,
 1279             draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top,
 1280             src_dc, draw_rect.left, draw_rect.top, SRCCOPY);
 1281     ReleaseDC(window, dst_dc);
 1282 
 1283     SetRectEmpty(&swapchain->front_buffer_update);
 1284 }
 1285 
 1286 static void swapchain_gdi_present(struct wined3d_swapchain *swapchain,
 1287         const RECT *src_rect, const RECT *dst_rect, unsigned int swap_interval, DWORD flags)
 1288 {
 1289     struct wined3d_dc_info *front, *back;
 1290     HBITMAP bitmap;
 1291     void *data;
 1292     HDC dc;
 1293 
 1294     front = &swapchain->front_buffer->dc_info[0];
 1295     back = &swapchain->back_buffers[0]->dc_info[0];
 1296 
 1297     /* Flip the surface data. */
 1298     dc = front->dc;
 1299     bitmap = front->bitmap;
 1300     data = swapchain->front_buffer->resource.heap_memory;
 1301 
 1302     front->dc = back->dc;
 1303     front->bitmap = back->bitmap;
 1304     swapchain->front_buffer->resource.heap_memory = swapchain->back_buffers[0]->resource.heap_memory;
 1305 
 1306     back->dc = dc;
 1307     back->bitmap = bitmap;
 1308     swapchain->back_buffers[0]->resource.heap_memory = data;
 1309 
 1310     SetRect(&swapchain->front_buffer_update, 0, 0,
 1311             swapchain->front_buffer->resource.width,
 1312             swapchain->front_buffer->resource.height);
 1313     swapchain_gdi_frontbuffer_updated(swapchain);
 1314 }
 1315 
 1316 static const struct wined3d_swapchain_ops swapchain_no3d_ops =
 1317 {
 1318     swapchain_gdi_present,
 1319     swapchain_gdi_frontbuffer_updated,
 1320 };
 1321 
 1322 static void swapchain_update_render_to_fbo(struct wined3d_swapchain *swapchain)
 1323 {
 1324     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO)
 1325         return;
 1326 
 1327     if (!swapchain->state.desc.backbuffer_count)
 1328     {
 1329         TRACE("Single buffered rendering.\n");
 1330         swapchain->render_to_fbo = FALSE;
 1331         return;
 1332     }
 1333 
 1334     TRACE("Rendering to FBO.\n");
 1335     swapchain->render_to_fbo = TRUE;
 1336 }
 1337 
 1338 static void wined3d_swapchain_apply_sample_count_override(const struct wined3d_swapchain *swapchain,
 1339         enum wined3d_format_id format_id, enum wined3d_multisample_type *type, DWORD *quality)
 1340 {
 1341     const struct wined3d_adapter *adapter;
 1342     const struct wined3d_gl_info *gl_info;
 1343     const struct wined3d_format *format;
 1344     enum wined3d_multisample_type t;
 1345 
 1346     if (wined3d_settings.sample_count == ~0u)
 1347         return;
 1348 
 1349     adapter = swapchain->device->adapter;
 1350     gl_info = &adapter->gl_info;
 1351     if (!(format = wined3d_get_format(adapter, format_id, WINED3D_BIND_RENDER_TARGET)))
 1352         return;
 1353 
 1354     if ((t = min(wined3d_settings.sample_count, gl_info->limits.samples)))
 1355         while (!(format->multisample_types & 1u << (t - 1)))
 1356             ++t;
 1357     TRACE("Using sample count %u.\n", t);
 1358     *type = t;
 1359     *quality = 0;
 1360 }
 1361 
 1362 void swapchain_set_max_frame_latency(struct wined3d_swapchain *swapchain, const struct wined3d_device *device)
 1363 {
 1364     /* Subtract 1 for the implicit OpenGL latency. */
 1365     swapchain->max_frame_latency = device->max_frame_latency >= 2 ? device->max_frame_latency - 1 : 1;
 1366 }
 1367 
 1368 static enum wined3d_format_id adapter_format_from_backbuffer_format(const struct wined3d_adapter *adapter,
 1369         enum wined3d_format_id format_id)
 1370 {
 1371     const struct wined3d_format *backbuffer_format;
 1372 
 1373     backbuffer_format = wined3d_get_format(adapter, format_id, WINED3D_BIND_RENDER_TARGET);
 1374     return pixelformat_for_depth(backbuffer_format->byte_count * CHAR_BIT);
 1375 }
 1376 
 1377 static HRESULT wined3d_swapchain_state_init(struct wined3d_swapchain_state *state,
 1378         const struct wined3d_swapchain_desc *desc, HWND window, struct wined3d *wined3d,
 1379         struct wined3d_swapchain_state_parent *parent)
 1380 {
 1381     HRESULT hr;
 1382 
 1383     state->desc = *desc;
 1384 
 1385     if (FAILED(hr = wined3d_output_get_display_mode(desc->output, &state->original_mode, NULL)))
 1386     {
 1387         ERR("Failed to get current display mode, hr %#x.\n", hr);
 1388         return hr;
 1389     }
 1390 
 1391     if (!desc->windowed)
 1392     {
 1393         if (desc->flags & WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH)
 1394         {
 1395             state->d3d_mode.width = desc->backbuffer_width;
 1396             state->d3d_mode.height = desc->backbuffer_height;
 1397             state->d3d_mode.format_id = adapter_format_from_backbuffer_format(desc->output->adapter,
 1398                     desc->backbuffer_format);
 1399             state->d3d_mode.refresh_rate = desc->refresh_rate;
 1400             state->d3d_mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN;
 1401         }
 1402         else
 1403         {
 1404             state->d3d_mode = state->original_mode;
 1405         }
 1406     }
 1407 
 1408     GetWindowRect(window, &state->original_window_rect);
 1409     state->wined3d = wined3d;
 1410     state->device_window = window;
 1411     state->parent = parent;
 1412 
 1413     if (desc->flags & WINED3D_SWAPCHAIN_REGISTER_STATE)
 1414         wined3d_swapchain_state_register(state);
 1415 
 1416     return hr;
 1417 }
 1418 
 1419 static HRESULT wined3d_swapchain_init(struct wined3d_swapchain *swapchain, struct wined3d_device *device,
 1420         struct wined3d_swapchain_desc *desc, struct wined3d_swapchain_state_parent *state_parent,
 1421         void *parent, const struct wined3d_parent_ops *parent_ops,
 1422         const struct wined3d_swapchain_ops *swapchain_ops)
 1423 {
 1424     struct wined3d_resource_desc texture_desc;
 1425     struct wined3d_output_desc output_desc;
 1426     BOOL displaymode_set = FALSE;
 1427     DWORD texture_flags = 0;
 1428     HRESULT hr = E_FAIL;
 1429     RECT client_rect;
 1430     unsigned int i;
 1431     HWND window;
 1432 
 1433     wined3d_mutex_lock();
 1434 
 1435     if (desc->backbuffer_count > 1)
 1436     {
 1437         FIXME("The application requested more than one back buffer, this is not properly supported.\n"
 1438                 "Please configure the application to use double buffering (1 back buffer) if possible.\n");
 1439     }
 1440 
 1441     if (desc->swap_effect != WINED3D_SWAP_EFFECT_DISCARD
 1442             && desc->swap_effect != WINED3D_SWAP_EFFECT_SEQUENTIAL
 1443             && desc->swap_effect != WINED3D_SWAP_EFFECT_COPY)
 1444         FIXME("Unimplemented swap effect %#x.\n", desc->swap_effect);
 1445 
 1446     window = desc->device_window ? desc->device_window : device->create_parms.focus_window;
 1447     if (FAILED(hr = wined3d_swapchain_state_init(&swapchain->state, desc, window, device->wined3d, state_parent)))
 1448     {
 1449         ERR("Failed to initialise swapchain state, hr %#x.\n", hr);
 1450         wined3d_mutex_unlock();
 1451         return hr;
 1452     }
 1453 
 1454     swapchain->swapchain_ops = swapchain_ops;
 1455     swapchain->device = device;
 1456     swapchain->parent = parent;
 1457     swapchain->parent_ops = parent_ops;
 1458     swapchain->ref = 1;
 1459     swapchain->win_handle = window;
 1460     swapchain->swap_interval = WINED3D_SWAP_INTERVAL_DEFAULT;
 1461     swapchain_set_max_frame_latency(swapchain, device);
 1462 
 1463     GetClientRect(window, &client_rect);
 1464     if (desc->windowed)
 1465     {
 1466         TRACE("Client rect %s.\n", wine_dbgstr_rect(&client_rect));
 1467 
 1468         if (!desc->backbuffer_width)
 1469         {
 1470             desc->backbuffer_width = client_rect.right ? client_rect.right : 8;
 1471             TRACE("Updating width to %u.\n", desc->backbuffer_width);
 1472         }
 1473         if (!desc->backbuffer_height)
 1474         {
 1475             desc->backbuffer_height = client_rect.bottom ? client_rect.bottom : 8;
 1476             TRACE("Updating height to %u.\n", desc->backbuffer_height);
 1477         }
 1478 
 1479         if (desc->backbuffer_format == WINED3DFMT_UNKNOWN)
 1480         {
 1481             desc->backbuffer_format = swapchain->state.original_mode.format_id;
 1482             TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->state.original_mode.format_id));
 1483         }
 1484     }
 1485     else
 1486     {
 1487         if (FAILED(hr = wined3d_output_get_desc(desc->output, &output_desc)))
 1488         {
 1489             ERR("Failed to get output description, hr %#x.\n", hr);
 1490             goto err;
 1491         }
 1492 
 1493         wined3d_swapchain_state_setup_fullscreen(&swapchain->state, window,
 1494                 output_desc.desktop_rect.left, output_desc.desktop_rect.top, desc->backbuffer_width,
 1495                 desc->backbuffer_height);
 1496     }
 1497     swapchain->state.desc = *desc;
 1498     wined3d_swapchain_apply_sample_count_override(swapchain, swapchain->state.desc.backbuffer_format,
 1499             &swapchain->state.desc.multisample_type, &swapchain->state.desc.multisample_quality);
 1500     swapchain_update_render_to_fbo(swapchain);
 1501 
 1502     TRACE("Creating front buffer.\n");
 1503 
 1504     texture_desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
 1505     texture_desc.format = swapchain->state.desc.backbuffer_format;
 1506     texture_desc.multisample_type = swapchain->state.desc.multisample_type;
 1507     texture_desc.multisample_quality = swapchain->state.desc.multisample_quality;
 1508     texture_desc.usage = 0;
 1509     if (device->wined3d->flags & WINED3D_NO3D)
 1510         texture_desc.usage |= WINED3DUSAGE_OWNDC;
 1511     texture_desc.bind_flags = 0;
 1512     if (device->wined3d->flags & WINED3D_NO3D)
 1513         texture_desc.access = WINED3D_RESOURCE_ACCESS_CPU;
 1514     else
 1515         texture_desc.access = WINED3D_RESOURCE_ACCESS_GPU;
 1516     if (swapchain->state.desc.flags & WINED3D_SWAPCHAIN_LOCKABLE_BACKBUFFER)
 1517         texture_desc.access |= WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
 1518     texture_desc.width = swapchain->state.desc.backbuffer_width;
 1519     texture_desc.height = swapchain->state.desc.backbuffer_height;
 1520     texture_desc.depth = 1;
 1521     texture_desc.size = 0;
 1522 
 1523     if (swapchain->state.desc.flags & WINED3D_SWAPCHAIN_GDI_COMPATIBLE)
 1524         texture_flags |= WINED3D_TEXTURE_CREATE_GET_DC;
 1525 
 1526     if (FAILED(hr = device->device_parent->ops->create_swapchain_texture(device->device_parent,
 1527             parent, &texture_desc, texture_flags, &swapchain->front_buffer)))
 1528     {
 1529         WARN("Failed to create front buffer, hr %#x.\n", hr);
 1530         goto err;
 1531     }
 1532 
 1533     wined3d_texture_set_swapchain(swapchain->front_buffer, swapchain);
 1534     if (!(device->wined3d->flags & WINED3D_NO3D))
 1535     {
 1536         wined3d_texture_validate_location(swapchain->front_buffer, 0, WINED3D_LOCATION_DRAWABLE);
 1537         wined3d_texture_invalidate_location(swapchain->front_buffer, 0, ~WINED3D_LOCATION_DRAWABLE);
 1538     }
 1539 
 1540     /* MSDN says we're only allowed a single fullscreen swapchain per device,
 1541      * so we should really check to see if there is a fullscreen swapchain
 1542      * already. Does a single head count as full screen? */
 1543     if (!desc->windowed && desc->flags & WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH)
 1544     {
 1545         /* Change the display settings */
 1546         if (FAILED(hr = wined3d_output_set_display_mode(desc->output,
 1547                 &swapchain->state.d3d_mode)))
 1548         {
 1549             WARN("Failed to set display mode, hr %#x.\n", hr);
 1550             goto err;
 1551         }
 1552         displaymode_set = TRUE;
 1553     }
 1554 
 1555     if (swapchain->state.desc.backbuffer_count > 0)
 1556     {
 1557         if (!(swapchain->back_buffers = heap_calloc(swapchain->state.desc.backbuffer_count,
 1558                 sizeof(*swapchain->back_buffers))))
 1559         {
 1560             ERR("Failed to allocate backbuffer array memory.\n");
 1561             hr = E_OUTOFMEMORY;
 1562             goto err;
 1563         }
 1564 
 1565         texture_desc.bind_flags = swapchain->state.desc.backbuffer_bind_flags;
 1566         texture_desc.usage = 0;
 1567         if (device->wined3d->flags & WINED3D_NO3D)
 1568             texture_desc.usage |= WINED3DUSAGE_OWNDC;
 1569         for (i = 0; i < swapchain->state.desc.backbuffer_count; ++i)
 1570         {
 1571             TRACE("Creating back buffer %u.\n", i);
 1572             if (FAILED(hr = device->device_parent->ops->create_swapchain_texture(device->device_parent,
 1573                     parent, &texture_desc, texture_flags, &swapchain->back_buffers[i])))
 1574             {
 1575                 WARN("Failed to create back buffer %u, hr %#x.\n", i, hr);
 1576                 swapchain->state.desc.backbuffer_count = i;
 1577                 goto err;
 1578             }
 1579             wined3d_texture_set_swapchain(swapchain->back_buffers[i], swapchain);
 1580         }
 1581     }
 1582 
 1583     /* Swapchains share the depth/stencil buffer, so only create a single depthstencil surface. */
 1584     if (desc->enable_auto_depth_stencil)
 1585     {
 1586         TRACE("Creating depth/stencil buffer.\n");
 1587         if (!device->auto_depth_stencil_view)
 1588         {
 1589             struct wined3d_view_desc desc;
 1590             struct wined3d_texture *ds;
 1591 
 1592             texture_desc.format = swapchain->state.desc.auto_depth_stencil_format;
 1593             texture_desc.usage = 0;
 1594             texture_desc.bind_flags = WINED3D_BIND_DEPTH_STENCIL;
 1595             if (device->wined3d->flags & WINED3D_NO3D)
 1596                 texture_desc.access = WINED3D_RESOURCE_ACCESS_CPU;
 1597             else
 1598                 texture_desc.access = WINED3D_RESOURCE_ACCESS_GPU;
 1599 
 1600             if (FAILED(hr = device->device_parent->ops->create_swapchain_texture(device->device_parent,
 1601                     device->device_parent, &texture_desc, 0, &ds)))
 1602             {
 1603                 WARN("Failed to create the auto depth/stencil surface, hr %#x.\n", hr);
 1604                 goto err;
 1605             }
 1606 
 1607             desc.format_id = ds->resource.format->id;
 1608             desc.flags = 0;
 1609             desc.u.texture.level_idx = 0;
 1610             desc.u.texture.level_count = 1;
 1611             desc.u.texture.layer_idx = 0;
 1612             desc.u.texture.layer_count = 1;
 1613             hr = wined3d_rendertarget_view_create(&desc, &ds->resource, NULL, &wined3d_null_parent_ops,
 1614                     &device->auto_depth_stencil_view);
 1615             wined3d_texture_decref(ds);
 1616             if (FAILED(hr))
 1617             {
 1618                 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
 1619                 goto err;
 1620             }
 1621         }
 1622     }
 1623 
 1624     wined3d_swapchain_get_gamma_ramp(swapchain, &swapchain->orig_gamma);
 1625 
 1626     wined3d_mutex_unlock();
 1627 
 1628     return WINED3D_OK;
 1629 
 1630 err:
 1631     if (displaymode_set)
 1632     {
 1633         if (FAILED(wined3d_restore_display_modes(device->wined3d)))
 1634             ERR("Failed to restore display mode.\n");
 1635     }
 1636 
 1637     if (swapchain->back_buffers)
 1638     {
 1639         for (i = 0; i < swapchain->state.desc.backbuffer_count; ++i)
 1640         {
 1641             if (swapchain->back_buffers[i])
 1642             {
 1643                 wined3d_texture_set_swapchain(swapchain->back_buffers[i], NULL);
 1644                 wined3d_texture_decref(swapchain->back_buffers[i]);
 1645             }
 1646         }
 1647         heap_free(swapchain->back_buffers);
 1648     }
 1649 
 1650     if (swapchain->front_buffer)
 1651     {
 1652         wined3d_texture_set_swapchain(swapchain->front_buffer, NULL);
 1653         wined3d_texture_decref(swapchain->front_buffer);
 1654     }
 1655 
 1656     wined3d_swapchain_state_cleanup(&swapchain->state);
 1657     wined3d_mutex_unlock();
 1658 
 1659     return hr;
 1660 }
 1661 
 1662 HRESULT wined3d_swapchain_no3d_init(struct wined3d_swapchain *swapchain_no3d, struct wined3d_device *device,
 1663         struct wined3d_swapchain_desc *desc, struct wined3d_swapchain_state_parent *state_parent,
 1664         void *parent, const struct wined3d_parent_ops *parent_ops)
 1665 {
 1666     TRACE("swapchain_no3d %p, device %p, desc %p, state_parent %p, parent %p, parent_ops %p.\n",
 1667             swapchain_no3d, device, desc, state_parent, parent, parent_ops);
 1668 
 1669     return wined3d_swapchain_init(swapchain_no3d, device, desc, state_parent, parent, parent_ops,
 1670             &swapchain_no3d_ops);
 1671 }
 1672 
 1673 HRESULT wined3d_swapchain_gl_init(struct wined3d_swapchain_gl *swapchain_gl, struct wined3d_device *device,
 1674         struct wined3d_swapchain_desc *desc, struct wined3d_swapchain_state_parent *state_parent,
 1675         void *parent, const struct wined3d_parent_ops *parent_ops)
 1676 {
 1677     HRESULT hr;
 1678 
 1679     TRACE("swapchain_gl %p, device %p, desc %p, state_parent %p, parent %p, parent_ops %p.\n",
 1680             swapchain_gl, device, desc, state_parent, parent, parent_ops);
 1681 
 1682     if (FAILED(hr = wined3d_swapchain_init(&swapchain_gl->s, device, desc, state_parent, parent,
 1683             parent_ops, &swapchain_gl_ops)))
 1684     {
 1685         /* Cleanup any context that may have been created for the swapchain. */
 1686         wined3d_cs_destroy_object(device->cs, wined3d_swapchain_gl_destroy_object, swapchain_gl);
 1687         wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
 1688     }
 1689 
 1690     return hr;
 1691 }
 1692 
 1693 HRESULT wined3d_swapchain_vk_init(struct wined3d_swapchain_vk *swapchain_vk, struct wined3d_device *device,
 1694         struct wined3d_swapchain_desc *desc, struct wined3d_swapchain_state_parent *state_parent,
 1695         void *parent, const struct wined3d_parent_ops *parent_ops)
 1696 {
 1697     HRESULT hr;
 1698 
 1699     TRACE("swapchain_vk %p, device %p, desc %p, parent %p, parent_ops %p.\n",
 1700             swapchain_vk, device, desc, parent, parent_ops);
 1701 
 1702     if (FAILED(hr = wined3d_swapchain_init(&swapchain_vk->s, device, desc, state_parent, parent,
 1703             parent_ops, &swapchain_vk_ops)))
 1704         return hr;
 1705 
 1706     if (swapchain_vk->s.win_handle == GetDesktopWindow())
 1707     {
 1708         WARN("Creating a desktop window swapchain.\n");
 1709         return hr;
 1710     }
 1711 
 1712     if (FAILED(hr = wined3d_swapchain_vk_create_vulkan_swapchain(swapchain_vk)))
 1713     {
 1714         wined3d_swapchain_cleanup(&swapchain_vk->s);
 1715         return hr;
 1716     }
 1717 
 1718     return hr;
 1719 }
 1720 
 1721 HRESULT CDECL wined3d_swapchain_create(struct wined3d_device *device,
 1722         struct wined3d_swapchain_desc *desc, struct wined3d_swapchain_state_parent *state_parent,
 1723         void *parent, const struct wined3d_parent_ops *parent_ops,
 1724         struct wined3d_swapchain **swapchain)
 1725 {
 1726     struct wined3d_swapchain *object;
 1727     HRESULT hr;
 1728 
 1729     if (FAILED(hr = device->adapter->adapter_ops->adapter_create_swapchain(device,
 1730             desc, state_parent, parent, parent_ops, &object)))
 1731         return hr;
 1732 
 1733     if (desc->flags & WINED3D_SWAPCHAIN_IMPLICIT)
 1734     {
 1735         wined3d_mutex_lock();
 1736         if (FAILED(hr = wined3d_device_set_implicit_swapchain(device, object)))
 1737         {
 1738             wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
 1739             device->adapter->adapter_ops->adapter_destroy_swapchain(object);
 1740             wined3d_mutex_unlock();
 1741             return hr;
 1742         }
 1743         wined3d_mutex_unlock();
 1744     }
 1745 
 1746     *swapchain = object;
 1747 
 1748     return hr;
 1749 }
 1750 
 1751 static struct wined3d_context_gl *wined3d_swapchain_gl_create_context(struct wined3d_swapchain_gl *swapchain_gl)
 1752 {
 1753     struct wined3d_device *device = swapchain_gl->s.device;
 1754     struct wined3d_context_gl *context_gl;
 1755 
 1756     TRACE("Creating a new context for swapchain %p, thread %u.\n", swapchain_gl, GetCurrentThreadId());
 1757 
 1758     wined3d_from_cs(device->cs);
 1759 
 1760     if (!(context_gl = heap_alloc_zero(sizeof(*context_gl))))
 1761     {
 1762         ERR("Failed to allocate context memory.\n");
 1763         return NULL;
 1764     }
 1765 
 1766     if (FAILED(wined3d_context_gl_init(context_gl, swapchain_gl)))
 1767     {
 1768         WARN("Failed to initialise context.\n");
 1769         heap_free(context_gl);
 1770         return NULL;
 1771     }
 1772 
 1773     if (!device_context_add(device, &context_gl->c))
 1774     {
 1775         ERR("Failed to add the newly created context to the context list.\n");
 1776         wined3d_context_gl_destroy(context_gl);
 1777         return NULL;
 1778     }
 1779 
 1780     TRACE("Created context %p.\n", context_gl);
 1781 
 1782     context_release(&context_gl->c);
 1783 
 1784     if (!wined3d_array_reserve((void **)&swapchain_gl->contexts, &swapchain_gl->contexts_size,
 1785             swapchain_gl->context_count + 1, sizeof(*swapchain_gl->contexts)))
 1786     {
 1787         ERR("Failed to allocate new context array memory.\n");
 1788         wined3d_context_gl_destroy(context_gl);
 1789         return NULL;
 1790     }
 1791     swapchain_gl->contexts[swapchain_gl->context_count++] = context_gl;
 1792 
 1793     return context_gl;
 1794 }
 1795 
 1796 void wined3d_swapchain_gl_destroy_contexts(struct wined3d_swapchain_gl *swapchain_gl)
 1797 {
 1798     unsigned int i;
 1799 
 1800     for (i = 0; i < swapchain_gl->context_count; ++i)
 1801     {
 1802         wined3d_context_gl_destroy(swapchain_gl->contexts[i]);
 1803     }
 1804     heap_free(swapchain_gl->contexts);
 1805     swapchain_gl->contexts_size = 0;
 1806     swapchain_gl->context_count = 0;
 1807     swapchain_gl->contexts = NULL;
 1808 }
 1809 
 1810 struct wined3d_context_gl *wined3d_swapchain_gl_get_context(struct wined3d_swapchain_gl *swapchain_gl)
 1811 {
 1812     DWORD tid = GetCurrentThreadId();
 1813     unsigned int i;
 1814 
 1815     for (i = 0; i < swapchain_gl->context_count; ++i)
 1816     {
 1817         if (swapchain_gl->contexts[i]->tid == tid)
 1818             return swapchain_gl->contexts[i];
 1819     }
 1820 
 1821     /* Create a new context for the thread. */
 1822     return wined3d_swapchain_gl_create_context(swapchain_gl);
 1823 }
 1824 
 1825 HDC wined3d_swapchain_gl_get_backup_dc(struct wined3d_swapchain_gl *swapchain_gl)
 1826 {
 1827     if (!swapchain_gl->backup_dc)
 1828     {
 1829         TRACE("Creating the backup window for swapchain %p.\n", swapchain_gl);
 1830 
 1831         if (!(swapchain_gl->backup_wnd = CreateWindowA(WINED3D_OPENGL_WINDOW_CLASS_NAME, "WineD3D fake window",
 1832                 WS_OVERLAPPEDWINDOW, 10, 10, 10, 10, NULL, NULL, NULL, NULL)))
 1833         {
 1834             ERR("Failed to create a window.\n");
 1835             return NULL;
 1836         }
 1837 
 1838         if (!(swapchain_gl->backup_dc = GetDC(swapchain_gl->backup_wnd)))
 1839         {
 1840             ERR("Failed to get a DC.\n");
 1841             DestroyWindow(swapchain_gl->backup_wnd);
 1842             swapchain_gl->backup_wnd = NULL;
 1843             return NULL;
 1844         }
 1845     }
 1846 
 1847     return swapchain_gl->backup_dc;
 1848 }
 1849 
 1850 void swapchain_update_draw_bindings(struct wined3d_swapchain *swapchain)
 1851 {
 1852     UINT i;
 1853 
 1854     wined3d_resource_update_draw_binding(&swapchain->front_buffer->resource);
 1855 
 1856     for (i = 0; i < swapchain->state.desc.backbuffer_count; ++i)
 1857     {
 1858         wined3d_resource_update_draw_binding(&swapchain->back_buffers[i]->resource);
 1859     }
 1860 }
 1861 
 1862 void wined3d_swapchain_activate(struct wined3d_swapchain *swapchain, BOOL activate)
 1863 {
 1864     struct wined3d_device *device = swapchain->device;
 1865     HWND window = swapchain->state.device_window;
 1866     struct wined3d_output_desc output_desc;
 1867     unsigned int screensaver_active;
 1868     struct wined3d_output *output;
 1869     BOOL focus_messages, filter;
 1870     HRESULT hr;
 1871 
 1872     /* This code is not protected by the wined3d mutex, so it may run while
 1873      * wined3d_device_reset is active. Testing on Windows shows that changing
 1874      * focus during resets and resetting during focus change events causes
 1875      * the application to crash with an invalid memory access. */
 1876 
 1877     if (!(focus_messages = device->wined3d->flags & WINED3D_FOCUS_MESSAGES))
 1878         filter = wined3d_filter_messages(window, TRUE);
 1879 
 1880     if (activate)
 1881     {
 1882         SystemParametersInfoW(SPI_GETSCREENSAVEACTIVE, 0, &screensaver_active, 0);
 1883         if ((device->restore_screensaver = !!screensaver_active))
 1884             SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0);
 1885 
 1886         if (!(device->create_parms.flags & WINED3DCREATE_NOWINDOWCHANGES))
 1887         {
 1888             /* The d3d versions do not agree on the exact messages here. D3d8 restores
 1889              * the window but leaves the size untouched, d3d9 sets the size on an
 1890              * invisible window, generates messages but doesn't change the window
 1891              * properties. The implementation follows d3d9.
 1892              *
 1893              * Guild Wars 1 wants a WINDOWPOSCHANGED message on the device window to
 1894              * resume drawing after a focus loss. */
 1895             output = wined3d_swapchain_get_output(swapchain);
 1896             if (!output)
 1897             {
 1898                 ERR("Failed to get output from swapchain %p.\n", swapchain);
 1899                 return;
 1900             }
 1901 
 1902             if (SUCCEEDED(hr = wined3d_output_get_desc(output, &output_desc)))
 1903                 SetWindowPos(window, NULL, output_desc.desktop_rect.left,
 1904                         output_desc.desktop_rect.top, swapchain->state.desc.backbuffer_width,
 1905                         swapchain->state.desc.backbuffer_height, SWP_NOACTIVATE | SWP_NOZORDER);
 1906             else
 1907                 ERR("Failed to get output description, hr %#x.\n", hr);
 1908         }
 1909 
 1910         if (device->wined3d->flags & WINED3D_RESTORE_MODE_ON_ACTIVATE)
 1911         {
 1912             output = wined3d_swapchain_get_output(swapchain);
 1913             if (!output)
 1914             {
 1915                 ERR("Failed to get output from swapchain %p.\n", swapchain);
 1916                 return;
 1917             }
 1918 
 1919             if (FAILED(hr = wined3d_output_set_display_mode(output,
 1920                     &swapchain->state.d3d_mode)))
 1921                 ERR("Failed to set display mode, hr %#x.\n", hr);
 1922         }
 1923 
 1924         if (swapchain == device->swapchains[0])
 1925             device->device_parent->ops->activate(device->device_parent, TRUE);
 1926     }
 1927     else
 1928     {
 1929         if (device->restore_screensaver)
 1930         {
 1931             SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, TRUE, NULL, 0);
 1932             device->restore_screensaver = FALSE;
 1933         }
 1934 
 1935         if (FAILED(hr = wined3d_restore_display_modes(device->wined3d)))
 1936             ERR("Failed to restore display modes, hr %#x.\n", hr);
 1937 
 1938         swapchain->reapply_mode = TRUE;
 1939 
 1940         /* Some DDraw apps (Deus Ex: GOTY, and presumably all UT 1 based games) destroy the device
 1941          * during window minimization. Do our housekeeping now, as the device may not exist after
 1942          * the ShowWindow call.
 1943          *
 1944          * In d3d9, the device is marked lost after the window is minimized. If we find an app
 1945          * that needs this behavior (e.g. because it calls TestCooperativeLevel in the window proc)
 1946          * we'll have to control this via a create flag. Note that the device and swapchain are not
 1947          * safe to access after the ShowWindow call. */
 1948         if (swapchain == device->swapchains[0])
 1949             device->device_parent->ops->activate(device->device_parent, FALSE);
 1950 
 1951         if (!(device->create_parms.flags & WINED3DCREATE_NOWINDOWCHANGES) && IsWindowVisible(window))
 1952             ShowWindow(window, SW_MINIMIZE);
 1953     }
 1954 
 1955     if (!focus_messages)
 1956         wined3d_filter_messages(window, filter);
 1957 }
 1958 
 1959 HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapchain, unsigned int buffer_count,
 1960         unsigned int width, unsigned int height, enum wined3d_format_id format_id,
 1961         enum wined3d_multisample_type multisample_type, unsigned int multisample_quality)
 1962 {
 1963     struct wined3d_swapchain_desc *desc = &swapchain->state.desc;
 1964     BOOL update_desc = FALSE;
 1965 
 1966     TRACE("swapchain %p, buffer_count %u, width %u, height %u, format %s, "
 1967             "multisample_type %#x, multisample_quality %#x.\n",
 1968             swapchain, buffer_count, width, height, debug_d3dformat(format_id),
 1969             multisample_type, multisample_quality);
 1970 
 1971     wined3d_swapchain_apply_sample_count_override(swapchain, format_id, &multisample_type, &multisample_quality);
 1972 
 1973     if (buffer_count && buffer_count != desc->backbuffer_count)
 1974         FIXME("Cannot change the back buffer count yet.\n");
 1975 
 1976     wined3d_cs_finish(swapchain->device->cs, WINED3D_CS_QUEUE_DEFAULT);
 1977 
 1978     if (!width || !height)
 1979     {
 1980         /* The application is requesting that either the swapchain width or
 1981          * height be set to the corresponding dimension in the window's
 1982          * client rect. */
 1983 
 1984         RECT client_rect;
 1985 
 1986         if (!desc->windowed)
 1987             return WINED3DERR_INVALIDCALL;
 1988 
 1989         if (!GetClientRect(swapchain->state.device_window, &client_rect))
 1990         {
 1991             ERR("Failed to get client rect, last error %#x.\n", GetLastError());
 1992             return WINED3DERR_INVALIDCALL;
 1993         }
 1994 
 1995         if (!width)
 1996             width = client_rect.right;
 1997 
 1998         if (!height)
 1999             height = client_rect.bottom;
 2000     }
 2001 
 2002     if (width != desc->backbuffer_width || height != desc->backbuffer_height)
 2003     {
 2004         desc->backbuffer_width = width;
 2005         desc->backbuffer_height = height;
 2006         update_desc = TRUE;
 2007     }
 2008 
 2009     if (format_id == WINED3DFMT_UNKNOWN)
 2010     {
 2011         if (!desc->windowed)
 2012             return WINED3DERR_INVALIDCALL;
 2013         format_id = swapchain->state.original_mode.format_id;
 2014     }
 2015 
 2016     if (format_id != desc->backbuffer_format)
 2017     {
 2018         desc->backbuffer_format = format_id;
 2019         update_desc = TRUE;
 2020     }
 2021 
 2022     if (multisample_type != desc->multisample_type
 2023             || multisample_quality != desc->multisample_quality)
 2024     {
 2025         desc->multisample_type = multisample_type;
 2026         desc->multisample_quality = multisample_quality;
 2027         update_desc = TRUE;
 2028     }
 2029 
 2030     if (update_desc)
 2031     {
 2032         HRESULT hr;
 2033         UINT i;
 2034 
 2035         if (FAILED(hr = wined3d_texture_update_desc(swapchain->front_buffer, 0, desc->backbuffer_width,
 2036                 desc->backbuffer_height, desc->backbuffer_format,
 2037                 desc->multisample_type, desc->multisample_quality, NULL, 0)))
 2038             return hr;
 2039 
 2040         for (i = 0; i < desc->backbuffer_count; ++i)
 2041         {
 2042             if (FAILED(hr = wined3d_texture_update_desc(swapchain->back_buffers[i], 0, desc->backbuffer_width,
 2043                     desc->backbuffer_height, desc->backbuffer_format,
 2044                     desc->multisample_type, desc->multisample_quality, NULL, 0)))
 2045                 return hr;
 2046         }
 2047     }
 2048 
 2049     swapchain_update_render_to_fbo(swapchain);
 2050     swapchain_update_draw_bindings(swapchain);
 2051 
 2052     return WINED3D_OK;
 2053 }
 2054 
 2055 static HRESULT wined3d_swapchain_state_set_display_mode(struct wined3d_swapchain_state *state,
 2056         struct wined3d_output *output, struct wined3d_display_mode *mode)
 2057 {
 2058     HRESULT hr;
 2059 
 2060     if (state->desc.flags & WINED3D_SWAPCHAIN_USE_CLOSEST_MATCHING_MODE)
 2061     {
 2062         if (FAILED(hr = wined3d_output_find_closest_matching_mode(output, mode)))
 2063         {
 2064             WARN("Failed to find closest matching mode, hr %#x.\n", hr);
 2065         }
 2066     }
 2067 
 2068     if (output != state->desc.output)
 2069     {
 2070         if (FAILED(hr = wined3d_restore_display_modes(state->wined3d)))
 2071         {
 2072             WARN("Failed to restore display modes, hr %#x.\n", hr);
 2073             return hr;
 2074         }
 2075 
 2076         if (FAILED(hr = wined3d_output_get_display_mode(output, &state->original_mode, NULL)))
 2077         {
 2078             WARN("Failed to get current display mode, hr %#x.\n", hr);
 2079             return hr;
 2080         }
 2081     }
 2082 
 2083     if (FAILED(hr = wined3d_output_set_display_mode(output, mode)))
 2084     {
 2085         WARN("Failed to set display mode, hr %#x.\n", hr);
 2086         return WINED3DERR_INVALIDCALL;
 2087     }
 2088 
 2089     return WINED3D_OK;
 2090 }
 2091 
 2092 HRESULT CDECL wined3d_swapchain_state_resize_target(struct wined3d_swapchain_state *state,
 2093         const struct wined3d_display_mode *mode)
 2094 {
 2095     struct wined3d_display_mode actual_mode;
 2096     struct wined3d_output_desc output_desc;
 2097     RECT original_window_rect, window_rect;
 2098     int x, y, width, height;
 2099     HWND window;
 2100     HRESULT hr;
 2101 
 2102     TRACE("state %p, mode %p.\n", state, mode);
 2103 
 2104     wined3d_mutex_lock();
 2105 
 2106     window = state->device_window;
 2107 
 2108     if (state->desc.windowed)
 2109     {
 2110         SetRect(&window_rect, 0, 0, mode->width, mode->height);
 2111         AdjustWindowRectEx(&window_rect,
 2112                 GetWindowLongW(window, GWL_STYLE), FALSE,
 2113                 GetWindowLongW(window, GWL_EXSTYLE));
 2114         GetWindowRect(window, &original_window_rect);
 2115 
 2116         x = original_window_rect.left;
 2117         y = original_window_rect.top;
 2118         width = window_rect.right - window_rect.left;
 2119         height = window_rect.bottom - window_rect.top;
 2120     }
 2121     else
 2122     {
 2123         if (state->desc.flags & WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH)
 2124         {
 2125             actual_mode = *mode;
 2126             if (FAILED(hr = wined3d_swapchain_state_set_display_mode(state, state->desc.output,
 2127                     &actual_mode)))
 2128             {
 2129                 ERR("Failed to set display mode, hr %#x.\n", hr);
 2130                 wined3d_mutex_unlock();
 2131                 return hr;
 2132             }
 2133         }
 2134 
 2135         if (FAILED(hr = wined3d_output_get_desc(state->desc.output, &output_desc)))
 2136         {
 2137             ERR("Failed to get output description, hr %#x.\n", hr);
 2138             wined3d_mutex_unlock();
 2139             return hr;
 2140         }
 2141 
 2142         x = output_desc.desktop_rect.left;
 2143         y = output_desc.desktop_rect.top;
 2144         width = output_desc.desktop_rect.right - output_desc.desktop_rect.left;
 2145         height = output_desc.desktop_rect.bottom - output_desc.desktop_rect.top;
 2146     }
 2147 
 2148     wined3d_mutex_unlock();
 2149 
 2150     MoveWindow(window, x, y, width, height, TRUE);
 2151 
 2152     return WINED3D_OK;
 2153 }
 2154 
 2155 static LONG fullscreen_style(LONG style)
 2156 {
 2157     /* Make sure the window is managed, otherwise we won't get keyboard input. */
 2158     style |= WS_POPUP | WS_SYSMENU;
 2159     style &= ~(WS_CAPTION | WS_THICKFRAME);
 2160 
 2161     return style;
 2162 }
 2163 
 2164 static LONG fullscreen_exstyle(LONG exstyle)
 2165 {
 2166     /* Filter out window decorations. */
 2167     exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
 2168 
 2169     return exstyle;
 2170 }
 2171 
 2172 HRESULT wined3d_swapchain_state_setup_fullscreen(struct wined3d_swapchain_state *state,
 2173         HWND window, int x, int y, int width, int height)
 2174 {
 2175     unsigned int window_pos_flags = SWP_FRAMECHANGED | SWP_NOACTIVATE;
 2176     LONG style, exstyle;
 2177     BOOL filter;
 2178 
 2179     TRACE("Setting up window %p for fullscreen mode.\n", window);
 2180 
 2181     if (!IsWindow(window))
 2182     {
 2183         WARN("%p is not a valid window.\n", window);
 2184         return WINED3DERR_NOTAVAILABLE;
 2185     }
 2186 
 2187     if (state->style || state->exstyle)
 2188     {
 2189         ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
 2190                 window, state->style, state->exstyle);
 2191     }
 2192 
 2193     if (state->desc.flags & WINED3D_SWAPCHAIN_NO_WINDOW_CHANGES)
 2194         window_pos_flags |= SWP_NOZORDER;
 2195     else
 2196         window_pos_flags |= SWP_SHOWWINDOW;
 2197 
 2198     state->style = GetWindowLongW(window, GWL_STYLE);
 2199     state->exstyle = GetWindowLongW(window, GWL_EXSTYLE);
 2200 
 2201     style = fullscreen_style(state->style);
 2202     exstyle = fullscreen_exstyle(state->exstyle);
 2203 
 2204     TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
 2205             state->style, state->exstyle, style, exstyle);
 2206 
 2207     filter = wined3d_filter_messages(window, TRUE);
 2208 
 2209     SetWindowLongW(window, GWL_STYLE, style);
 2210     SetWindowLongW(window, GWL_EXSTYLE, exstyle);
 2211     SetWindowPos(window, HWND_TOPMOST, x, y, width, height, window_pos_flags);
 2212 
 2213     wined3d_filter_messages(window, filter);
 2214 
 2215     return WINED3D_OK;
 2216 }
 2217 
 2218 void wined3d_swapchain_state_restore_from_fullscreen(struct wined3d_swapchain_state *state,
 2219         HWND window, const RECT *window_rect)
 2220 {
 2221     unsigned int window_pos_flags = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE;
 2222     HWND window_pos_after = NULL;
 2223     LONG style, exstyle;
 2224     RECT rect = {0};
 2225     BOOL filter;
 2226 
 2227     if (!state->style && !state->exstyle)
 2228         return;
 2229 
 2230     if ((state->desc.flags & WINED3D_SWAPCHAIN_RESTORE_WINDOW_STATE)
 2231             && !(state->desc.flags & WINED3D_SWAPCHAIN_NO_WINDOW_CHANGES))
 2232     {
 2233         window_pos_after = (state->exstyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_NOTOPMOST;
 2234         window_pos_flags |= (state->style & WS_VISIBLE) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
 2235         window_pos_flags &= ~SWP_NOZORDER;
 2236     }
 2237 
 2238     style = GetWindowLongW(window, GWL_STYLE);
 2239     exstyle = GetWindowLongW(window, GWL_EXSTYLE);
 2240 
 2241     /* These flags are set by wined3d_device_setup_fullscreen_window, not the
 2242      * application, and we want to ignore them in the test below, since it's
 2243      * not the application's fault that they changed. Additionally, we want to
 2244      * preserve the current status of these flags (i.e. don't restore them) to
 2245      * more closely emulate the behavior of Direct3D, which leaves these flags
 2246      * alone when returning to windowed mode. */
 2247     state->style ^= (state->style ^ style) & WS_VISIBLE;
 2248     state->exstyle ^= (state->exstyle ^ exstyle) & WS_EX_TOPMOST;
 2249 
 2250     TRACE("Restoring window style of window %p to %08x, %08x.\n",
 2251             window, state->style, state->exstyle);
 2252 
 2253     filter = wined3d_filter_messages(window, TRUE);
 2254 
 2255     /* Only restore the style if the application didn't modify it during the
 2256      * fullscreen phase. Some applications change it before calling Reset()
 2257      * when switching between windowed and fullscreen modes (HL2), some
 2258      * depend on the original style (Eve Online). */
 2259     if (style == fullscreen_style(state->style) && exstyle == fullscreen_exstyle(state->exstyle))
 2260     {
 2261         SetWindowLongW(window, GWL_STYLE, state->style);
 2262         SetWindowLongW(window, GWL_EXSTYLE, state->exstyle);
 2263     }
 2264 
 2265     if (window_rect)
 2266         rect = *window_rect;
 2267     else
 2268         window_pos_flags |= (SWP_NOMOVE | SWP_NOSIZE);
 2269     SetWindowPos(window, window_pos_after, rect.left, rect.top,
 2270             rect.right - rect.left, rect.bottom - rect.top, window_pos_flags);
 2271 
 2272     wined3d_filter_messages(window, filter);
 2273 
 2274     /* Delete the old values. */
 2275     state->style = 0;
 2276     state->exstyle = 0;
 2277 }
 2278 
 2279 HRESULT CDECL wined3d_swapchain_state_set_fullscreen(struct wined3d_swapchain_state *state,
 2280         const struct wined3d_swapchain_desc *swapchain_desc,
 2281         const struct wined3d_display_mode *mode)
 2282 {
 2283     struct wined3d_display_mode actual_mode;
 2284     struct wined3d_output_desc output_desc;
 2285     BOOL windowed = state->desc.windowed;
 2286     HRESULT hr;
 2287 
 2288     TRACE("state %p, swapchain_desc %p, mode %p.\n", state, swapchain_desc, mode);
 2289 
 2290     if (state->desc.flags & WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH)
 2291     {
 2292         if (mode)
 2293         {
 2294             actual_mode = *mode;
 2295             if (FAILED(hr = wined3d_swapchain_state_set_display_mode(state, swapchain_desc->output,
 2296                     &actual_mode)))
 2297                 return hr;
 2298         }
 2299         else
 2300         {
 2301             if (!swapchain_desc->windowed)
 2302             {
 2303                 actual_mode.width = swapchain_desc->backbuffer_width;
 2304                 actual_mode.height = swapchain_desc->backbuffer_height;
 2305                 actual_mode.refresh_rate = swapchain_desc->refresh_rate;
 2306                 actual_mode.format_id = adapter_format_from_backbuffer_format(swapchain_desc->output->adapter,
 2307                         swapchain_desc->backbuffer_format);
 2308                 actual_mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN;
 2309                 if (FAILED(hr = wined3d_swapchain_state_set_display_mode(state, swapchain_desc->output,
 2310                         &actual_mode)))
 2311                     return hr;
 2312             }
 2313             else
 2314             {
 2315                 if (FAILED(hr = wined3d_restore_display_modes(state->wined3d)))
 2316                 {
 2317                     WARN("Failed to restore display modes for all outputs, hr %#x.\n", hr);
 2318                     return hr;
 2319                 }
 2320             }
 2321         }
 2322     }
 2323     else
 2324     {
 2325         if (mode)
 2326             WARN("WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH is not set, ignoring mode.\n");
 2327 
 2328         if (FAILED(hr = wined3d_output_get_display_mode(swapchain_desc->output, &actual_mode,
 2329                 NULL)))
 2330         {
 2331             ERR("Failed to get display mode, hr %#x.\n", hr);
 2332             return WINED3DERR_INVALIDCALL;
 2333         }
 2334     }
 2335 
 2336     if (!swapchain_desc->windowed)
 2337     {
 2338         unsigned int width = actual_mode.width;
 2339         unsigned int height = actual_mode.height;
 2340 
 2341         if (FAILED(hr = wined3d_output_get_desc(swapchain_desc->output, &output_desc)))
 2342         {
 2343             ERR("Failed to get output description, hr %#x.\n", hr);
 2344             return hr;
 2345         }
 2346 
 2347         if (state->desc.windowed)
 2348         {
 2349             /* Switch from windowed to fullscreen */
 2350             if (FAILED(hr = wined3d_swapchain_state_setup_fullscreen(state, state->device_window,
 2351                     output_desc.desktop_rect.left, output_desc.desktop_rect.top, width, height)))
 2352                 return hr;
 2353         }
 2354         else
 2355         {
 2356             HWND window = state->device_window;
 2357             BOOL filter;
 2358 
 2359             /* Fullscreen -> fullscreen mode change */
 2360             filter = wined3d_filter_messages(window, TRUE);
 2361             MoveWindow(window, output_desc.desktop_rect.left, output_desc.desktop_rect.top, width,
 2362                     height, TRUE);
 2363             ShowWindow(window, SW_SHOW);
 2364             wined3d_filter_messages(window, filter);
 2365         }
 2366         state->d3d_mode = actual_mode;
 2367     }
 2368     else if (!state->desc.windowed)
 2369     {
 2370         /* Fullscreen -> windowed switch */
 2371         RECT *window_rect = NULL;
 2372         if (state->desc.flags & WINED3D_SWAPCHAIN_RESTORE_WINDOW_RECT)
 2373             window_rect = &state->original_window_rect;
 2374         wined3d_swapchain_state_restore_from_fullscreen(state, state->device_window, window_rect);
 2375     }
 2376 
 2377     state->desc.output = swapchain_desc->output;
 2378     state->desc.windowed = swapchain_desc->windowed;
 2379 
 2380     if (windowed != state->desc.windowed)
 2381         state->parent->ops->windowed_state_changed(state->parent, state->desc.windowed);
 2382 
 2383     return WINED3D_OK;
 2384 }
 2385 
 2386 BOOL CDECL wined3d_swapchain_state_is_windowed(const struct wined3d_swapchain_state *state)
 2387 {
 2388     TRACE("state %p.\n", state);
 2389 
 2390     return state->desc.windowed;
 2391 }
 2392 
 2393 void CDECL wined3d_swapchain_state_destroy(struct wined3d_swapchain_state *state)
 2394 {
 2395     wined3d_swapchain_state_cleanup(state);
 2396     heap_free(state);
 2397 }
 2398 
 2399 HRESULT CDECL wined3d_swapchain_state_create(const struct wined3d_swapchain_desc *desc,
 2400         HWND window, struct wined3d *wined3d, struct wined3d_swapchain_state_parent *state_parent,
 2401         struct wined3d_swapchain_state **state)
 2402 {
 2403     struct wined3d_swapchain_state *s;
 2404     HRESULT hr;
 2405 
 2406     TRACE("desc %p, window %p, wined3d %p, state %p.\n", desc, window, wined3d, state);
 2407 
 2408     if (!(s = heap_alloc_zero(sizeof(*s))))
 2409         return E_OUTOFMEMORY;
 2410 
 2411     if (FAILED(hr = wined3d_swapchain_state_init(s, desc, window, wined3d, state_parent)))
 2412     {
 2413         heap_free(s);
 2414         return hr;
 2415     }
 2416 
 2417     *state = s;
 2418 
 2419     return hr;
 2420 }