static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3d_device *device, struct wined3d_swapchain_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_adapter *adapter = device->adapter; const struct wined3d_gl_info *gl_info = &adapter->gl_info; struct wined3d_resource_desc surface_desc; BOOL displaymode_set = FALSE; RECT client_rect; HWND window; HRESULT hr; UINT i; if (desc->backbuffer_count > WINED3DPRESENT_BACK_BUFFER_MAX) { FIXME("The application requested %u back buffers, this is not supported.\n", desc->backbuffer_count); return WINED3DERR_INVALIDCALL; } if (desc->backbuffer_count > 1) { FIXME("The application requested more than one back buffer, this is not properly supported.\n" "Please configure the application to use double buffering (1 back buffer) if possible.\n"); } if (device->wined3d->flags & WINED3D_NO3D) swapchain->swapchain_ops = &swapchain_gdi_ops; else swapchain->swapchain_ops = &swapchain_gl_ops; window = desc->device_window ? desc->device_window : device->create_parms.focus_window; swapchain->device = device; swapchain->parent = parent; swapchain->parent_ops = parent_ops; swapchain->ref = 1; swapchain->win_handle = window; swapchain->device_window = window; if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d, adapter->ordinal, &swapchain->original_mode, NULL))) { ERR("Failed to get current display mode, hr %#x.\n", hr); goto err; } GetClientRect(window, &client_rect); if (desc->windowed && (!desc->backbuffer_width || !desc->backbuffer_height || desc->backbuffer_format == WINED3DFMT_UNKNOWN)) { if (!desc->backbuffer_width) { desc->backbuffer_width = client_rect.right; TRACE("Updating width to %u.\n", desc->backbuffer_width); } if (!desc->backbuffer_height) { desc->backbuffer_height = client_rect.bottom; TRACE("Updating height to %u.\n", desc->backbuffer_height); } if (desc->backbuffer_format == WINED3DFMT_UNKNOWN) { desc->backbuffer_format = swapchain->original_mode.format_id; TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->original_mode.format_id)); } } swapchain->desc = *desc; swapchain_update_render_to_fbo(swapchain); swapchain_update_surface(swapchain); TRACE("Creating front buffer.\n"); surface_desc.resource_type = WINED3D_RTYPE_SURFACE; surface_desc.format = swapchain->desc.backbuffer_format; surface_desc.multisample_type = swapchain->desc.multisample_type; surface_desc.multisample_quality = swapchain->desc.multisample_quality; surface_desc.usage = 0; surface_desc.pool = WINED3D_POOL_DEFAULT; surface_desc.width = swapchain->desc.backbuffer_width; surface_desc.height = swapchain->desc.backbuffer_height; surface_desc.depth = 1; surface_desc.size = 0; if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent, parent, &surface_desc, &swapchain->front_buffer))) { WARN("Failed to create front buffer, hr %#x.\n", hr); goto err; } surface_set_swapchain(swapchain->front_buffer, swapchain); if (!(device->wined3d->flags & WINED3D_NO3D)) { surface_validate_location(swapchain->front_buffer, WINED3D_LOCATION_DRAWABLE); surface_invalidate_location(swapchain->front_buffer, ~WINED3D_LOCATION_DRAWABLE); } /* MSDN says we're only allowed a single fullscreen swapchain per device, * so we should really check to see if there is a fullscreen swapchain * already. Does a single head count as full screen? */ if (!desc->windowed) { struct wined3d_display_mode mode; /* Change the display settings */ mode.width = desc->backbuffer_width; mode.height = desc->backbuffer_height; mode.format_id = desc->backbuffer_format; mode.refresh_rate = desc->refresh_rate; mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN; if (FAILED(hr = wined3d_set_adapter_display_mode(device->wined3d, adapter->ordinal, &mode))) { WARN("Failed to set display mode, hr %#x.\n", hr); goto err; } displaymode_set = TRUE; } if (!(device->wined3d->flags & WINED3D_NO3D)) { static const enum wined3d_format_id formats[] = { WINED3DFMT_D24_UNORM_S8_UINT, WINED3DFMT_D32_UNORM, WINED3DFMT_R24_UNORM_X8_TYPELESS, WINED3DFMT_D16_UNORM, WINED3DFMT_S1_UINT_D15_UNORM }; swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context)); if (!swapchain->context) { ERR("Failed to create the context array.\n"); hr = E_OUTOFMEMORY; goto err; } swapchain->num_contexts = 1; /* In WGL both color, depth and stencil are features of a pixel format. In case of D3D they are separate. * You are able to add a depth + stencil surface at a later stage when you need it. * In order to support this properly in WineD3D we need the ability to recreate the opengl context and * drawable when this is required. This is very tricky as we need to reapply ALL opengl states for the new * context, need torecreate shaders, textures and other resources. * * The context manager already takes care of the state problem and for the other tasks code from Reset * can be used. These changes are way to risky during the 1.0 code freeze which is taking place right now. * Likely a lot of other new bugs will be exposed. For that reason request a depth stencil surface all the * time. It can cause a slight performance hit but fixes a lot of regressions. A fixme reminds of that this * issue needs to be fixed. */ for (i = 0; i < (sizeof(formats) / sizeof(*formats)); i++) { swapchain->ds_format = wined3d_get_format(gl_info, formats[i]); swapchain->context[0] = context_create(swapchain, swapchain->front_buffer, swapchain->ds_format); if (swapchain->context[0]) break; TRACE("Depth stencil format %s is not supported, trying next format\n", debug_d3dformat(formats[i])); } if (!swapchain->context[0]) { WARN("Failed to create context.\n"); hr = WINED3DERR_NOTAVAILABLE; goto err; } if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && (!desc->enable_auto_depth_stencil || swapchain->desc.auto_depth_stencil_format != swapchain->ds_format->id)) { FIXME("Add OpenGL context recreation support to context_validate_onscreen_formats\n"); } context_release(swapchain->context[0]); } if (swapchain->desc.backbuffer_count > 0) { swapchain->back_buffers = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->back_buffers) * swapchain->desc.backbuffer_count); if (!swapchain->back_buffers) { ERR("Failed to allocate backbuffer array memory.\n"); hr = E_OUTOFMEMORY; goto err; } surface_desc.usage |= WINED3DUSAGE_RENDERTARGET; for (i = 0; i < swapchain->desc.backbuffer_count; ++i) { TRACE("Creating back buffer %u.\n", i); if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent, parent, &surface_desc, &swapchain->back_buffers[i]))) { WARN("Failed to create back buffer %u, hr %#x.\n", i, hr); swapchain->desc.backbuffer_count = i; goto err; } surface_set_swapchain(swapchain->back_buffers[i], swapchain); } } /* Swapchains share the depth/stencil buffer, so only create a single depthstencil surface. */ if (desc->enable_auto_depth_stencil && !(device->wined3d->flags & WINED3D_NO3D)) { TRACE("Creating depth/stencil buffer.\n"); if (!device->auto_depth_stencil) { surface_desc.format = swapchain->desc.auto_depth_stencil_format; surface_desc.usage = WINED3DUSAGE_DEPTHSTENCIL; if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent, device->device_parent, &surface_desc, &device->auto_depth_stencil))) { WARN("Failed to create the auto depth stencil, hr %#x.\n", hr); goto err; } } } wined3d_swapchain_get_gamma_ramp(swapchain, &swapchain->orig_gamma); return WINED3D_OK; err: if (displaymode_set) { if (FAILED(wined3d_set_adapter_display_mode(device->wined3d, adapter->ordinal, &swapchain->original_mode))) ERR("Failed to restore display mode.\n"); ClipCursor(NULL); } if (swapchain->back_buffers) { for (i = 0; i < swapchain->desc.backbuffer_count; ++i) { if (swapchain->back_buffers[i]) { surface_set_swapchain(swapchain->back_buffers[i], NULL); wined3d_surface_decref(swapchain->back_buffers[i]); } } HeapFree(GetProcessHeap(), 0, swapchain->back_buffers); } if (swapchain->context) { if (swapchain->context[0]) { context_release(swapchain->context[0]); context_destroy(device, swapchain->context[0]); swapchain->num_contexts = 0; } HeapFree(GetProcessHeap(), 0, swapchain->context); } if (swapchain->front_buffer) { surface_set_swapchain(swapchain->front_buffer, NULL); wined3d_surface_decref(swapchain->front_buffer); } if (swapchain->surface && !GL_EXTCALL(wglDestroySurfaceWINE(swapchain->surface))) ERR("wglDestroySurfaceWINE failed to destroy surface %p\n", swapchain->surface); return hr; }
/* Do not call while under the GL lock. */ static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, enum wined3d_surface_type surface_type, struct wined3d_device *device, struct wined3d_swapchain_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_adapter *adapter = device->adapter; const struct wined3d_format *format; struct wined3d_display_mode mode; BOOL displaymode_set = FALSE; RECT client_rect; HWND window; HRESULT hr; UINT i; if (desc->backbuffer_count > WINED3DPRESENT_BACK_BUFFER_MAX) { FIXME("The application requested %u back buffers, this is not supported.\n", desc->backbuffer_count); return WINED3DERR_INVALIDCALL; } if (desc->backbuffer_count > 1) { FIXME("The application requested more than one back buffer, this is not properly supported.\n" "Please configure the application to use double buffering (1 back buffer) if possible.\n"); } switch (surface_type) { case WINED3D_SURFACE_TYPE_GDI: swapchain->swapchain_ops = &swapchain_gdi_ops; break; case WINED3D_SURFACE_TYPE_OPENGL: swapchain->swapchain_ops = &swapchain_gl_ops; break; default: ERR("Invalid surface type %#x.\n", surface_type); return WINED3DERR_INVALIDCALL; } window = desc->device_window ? desc->device_window : device->create_parms.focus_window; swapchain->device = device; swapchain->parent = parent; swapchain->parent_ops = parent_ops; swapchain->ref = 1; swapchain->win_handle = window; swapchain->device_window = window; wined3d_get_adapter_display_mode(device->wined3d, adapter->ordinal, &mode); swapchain->orig_width = mode.width; swapchain->orig_height = mode.height; swapchain->orig_fmt = mode.format_id; format = wined3d_get_format(&adapter->gl_info, mode.format_id); GetClientRect(window, &client_rect); if (desc->windowed && (!desc->backbuffer_width || !desc->backbuffer_height || desc->backbuffer_format == WINED3DFMT_UNKNOWN)) { if (!desc->backbuffer_width) { desc->backbuffer_width = client_rect.right; TRACE("Updating width to %u.\n", desc->backbuffer_width); } if (!desc->backbuffer_height) { desc->backbuffer_height = client_rect.bottom; TRACE("Updating height to %u.\n", desc->backbuffer_height); } if (desc->backbuffer_format == WINED3DFMT_UNKNOWN) { desc->backbuffer_format = swapchain->orig_fmt; TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->orig_fmt)); } } swapchain->desc = *desc; swapchain_update_render_to_fbo(swapchain); TRACE("Creating front buffer.\n"); hr = device->device_parent->ops->create_rendertarget(device->device_parent, parent, swapchain->desc.backbuffer_width, swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format, swapchain->desc.multisample_type, swapchain->desc.multisample_quality, TRUE /* Lockable */, &swapchain->front_buffer); if (FAILED(hr)) { WARN("Failed to create front buffer, hr %#x.\n", hr); goto err; } surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_SWAPCHAIN, swapchain); if (surface_type == WINED3D_SURFACE_TYPE_OPENGL) surface_modify_location(swapchain->front_buffer, SFLAG_INDRAWABLE, TRUE); /* MSDN says we're only allowed a single fullscreen swapchain per device, * so we should really check to see if there is a fullscreen swapchain * already. Does a single head count as full screen? */ if (!desc->windowed) { struct wined3d_display_mode mode; /* Change the display settings */ mode.width = desc->backbuffer_width; mode.height = desc->backbuffer_height; mode.format_id = desc->backbuffer_format; mode.refresh_rate = desc->refresh_rate; hr = wined3d_device_set_display_mode(device, 0, &mode); if (FAILED(hr)) { WARN("Failed to set display mode, hr %#x.\n", hr); goto err; } displaymode_set = TRUE; } if (surface_type == WINED3D_SURFACE_TYPE_OPENGL) { static const enum wined3d_format_id formats[] = { WINED3DFMT_D24_UNORM_S8_UINT, WINED3DFMT_D32_UNORM, WINED3DFMT_R24_UNORM_X8_TYPELESS, WINED3DFMT_D16_UNORM, WINED3DFMT_S1_UINT_D15_UNORM }; const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context)); if (!swapchain->context) { ERR("Failed to create the context array.\n"); hr = E_OUTOFMEMORY; goto err; } swapchain->num_contexts = 1; /* In WGL both color, depth and stencil are features of a pixel format. In case of D3D they are separate. * You are able to add a depth + stencil surface at a later stage when you need it. * In order to support this properly in WineD3D we need the ability to recreate the opengl context and * drawable when this is required. This is very tricky as we need to reapply ALL opengl states for the new * context, need torecreate shaders, textures and other resources. * * The context manager already takes care of the state problem and for the other tasks code from Reset * can be used. These changes are way to risky during the 1.0 code freeze which is taking place right now. * Likely a lot of other new bugs will be exposed. For that reason request a depth stencil surface all the * time. It can cause a slight performance hit but fixes a lot of regressions. A fixme reminds of that this * issue needs to be fixed. */ for (i = 0; i < (sizeof(formats) / sizeof(*formats)); i++) { swapchain->ds_format = wined3d_get_format(gl_info, formats[i]); swapchain->context[0] = context_create(swapchain, swapchain->front_buffer, swapchain->ds_format); if (swapchain->context[0]) break; TRACE("Depth stencil format %s is not supported, trying next format\n", debug_d3dformat(formats[i])); } if (!swapchain->context[0]) { WARN("Failed to create context.\n"); hr = WINED3DERR_NOTAVAILABLE; goto err; } if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && (!desc->enable_auto_depth_stencil || swapchain->desc.auto_depth_stencil_format != swapchain->ds_format->id)) { FIXME("Add OpenGL context recreation support to context_validate_onscreen_formats\n"); } context_release(swapchain->context[0]); } if (swapchain->desc.backbuffer_count > 0) { swapchain->back_buffers = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->back_buffers) * swapchain->desc.backbuffer_count); if (!swapchain->back_buffers) { ERR("Failed to allocate backbuffer array memory.\n"); hr = E_OUTOFMEMORY; goto err; } for (i = 0; i < swapchain->desc.backbuffer_count; ++i) { TRACE("Creating back buffer %u.\n", i); hr = device->device_parent->ops->create_rendertarget(device->device_parent, parent, swapchain->desc.backbuffer_width, swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format, swapchain->desc.multisample_type, swapchain->desc.multisample_quality, TRUE /* Lockable */, &swapchain->back_buffers[i]); if (FAILED(hr)) { WARN("Failed to create back buffer %u, hr %#x.\n", i, hr); goto err; } surface_set_container(swapchain->back_buffers[i], WINED3D_CONTAINER_SWAPCHAIN, swapchain); } } /* Swapchains share the depth/stencil buffer, so only create a single depthstencil surface. */ if (desc->enable_auto_depth_stencil && surface_type == WINED3D_SURFACE_TYPE_OPENGL) { TRACE("Creating depth/stencil buffer.\n"); if (!device->auto_depth_stencil) { hr = device->device_parent->ops->create_depth_stencil(device->device_parent, swapchain->desc.backbuffer_width, swapchain->desc.backbuffer_height, swapchain->desc.auto_depth_stencil_format, swapchain->desc.multisample_type, swapchain->desc.multisample_quality, FALSE /* FIXME: Discard */, &device->auto_depth_stencil); if (FAILED(hr)) { WARN("Failed to create the auto depth stencil, hr %#x.\n", hr); goto err; } surface_set_container(device->auto_depth_stencil, WINED3D_CONTAINER_NONE, NULL); } } wined3d_swapchain_get_gamma_ramp(swapchain, &swapchain->orig_gamma); return WINED3D_OK; err: if (displaymode_set) { DEVMODEW devmode; ClipCursor(NULL); /* Change the display settings */ memset(&devmode, 0, sizeof(devmode)); devmode.dmSize = sizeof(devmode); devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; devmode.dmBitsPerPel = format->byte_count * CHAR_BIT; devmode.dmPelsWidth = swapchain->orig_width; devmode.dmPelsHeight = swapchain->orig_height; ChangeDisplaySettingsExW(adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL); } if (swapchain->back_buffers) { for (i = 0; i < swapchain->desc.backbuffer_count; ++i) { if (swapchain->back_buffers[i]) { surface_set_container(swapchain->back_buffers[i], WINED3D_CONTAINER_NONE, NULL); wined3d_surface_decref(swapchain->back_buffers[i]); } } HeapFree(GetProcessHeap(), 0, swapchain->back_buffers); } if (swapchain->context) { if (swapchain->context[0]) { context_release(swapchain->context[0]); context_destroy(device, swapchain->context[0]); swapchain->num_contexts = 0; } HeapFree(GetProcessHeap(), 0, swapchain->context); } if (swapchain->front_buffer) { surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL); wined3d_surface_decref(swapchain->front_buffer); } return hr; }
static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3d_device *device, struct wined3d_swapchain_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_adapter *adapter = device->adapter; struct wined3d_resource_desc surface_desc; BOOL displaymode_set = FALSE; RECT client_rect; HWND window; HRESULT hr; UINT i; if (desc->backbuffer_count > WINED3DPRESENT_BACK_BUFFER_MAX) { FIXME("The application requested %u back buffers, this is not supported.\n", desc->backbuffer_count); return WINED3DERR_INVALIDCALL; } if (desc->backbuffer_count > 1) { FIXME("The application requested more than one back buffer, this is not properly supported.\n" "Please configure the application to use double buffering (1 back buffer) if possible.\n"); } if (device->wined3d->flags & WINED3D_NO3D) swapchain->swapchain_ops = &swapchain_gdi_ops; else swapchain->swapchain_ops = &swapchain_gl_ops; window = desc->device_window ? desc->device_window : device->create_parms.focus_window; swapchain->device = device; swapchain->parent = parent; swapchain->parent_ops = parent_ops; swapchain->ref = 1; swapchain->win_handle = window; swapchain->device_window = window; if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d, adapter->ordinal, &swapchain->original_mode, NULL))) { ERR("Failed to get current display mode, hr %#x.\n", hr); goto err; } GetClientRect(window, &client_rect); if (desc->windowed && (!desc->backbuffer_width || !desc->backbuffer_height || desc->backbuffer_format == WINED3DFMT_UNKNOWN)) { if (!desc->backbuffer_width) { desc->backbuffer_width = client_rect.right; TRACE("Updating width to %u.\n", desc->backbuffer_width); } if (!desc->backbuffer_height) { desc->backbuffer_height = client_rect.bottom; TRACE("Updating height to %u.\n", desc->backbuffer_height); } if (desc->backbuffer_format == WINED3DFMT_UNKNOWN) { desc->backbuffer_format = swapchain->original_mode.format_id; TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->original_mode.format_id)); } } swapchain->desc = *desc; swapchain_update_render_to_fbo(swapchain); TRACE("Creating front buffer.\n"); surface_desc.resource_type = WINED3D_RTYPE_SURFACE; surface_desc.format = swapchain->desc.backbuffer_format; surface_desc.multisample_type = swapchain->desc.multisample_type; surface_desc.multisample_quality = swapchain->desc.multisample_quality; surface_desc.usage = 0; surface_desc.pool = WINED3D_POOL_DEFAULT; surface_desc.width = swapchain->desc.backbuffer_width; surface_desc.height = swapchain->desc.backbuffer_height; surface_desc.depth = 1; surface_desc.size = 0; if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent, parent, &surface_desc, &swapchain->front_buffer))) { WARN("Failed to create front buffer, hr %#x.\n", hr); goto err; } surface_set_swapchain(swapchain->front_buffer, swapchain); if (!(device->wined3d->flags & WINED3D_NO3D)) { wined3d_resource_validate_location(&swapchain->front_buffer->resource, WINED3D_LOCATION_DRAWABLE); wined3d_resource_invalidate_location(&swapchain->front_buffer->resource, ~WINED3D_LOCATION_DRAWABLE); } /* MSDN says we're only allowed a single fullscreen swapchain per device, * so we should really check to see if there is a fullscreen swapchain * already. Does a single head count as full screen? */ if (!desc->windowed) { struct wined3d_display_mode mode; /* Change the display settings */ mode.width = desc->backbuffer_width; mode.height = desc->backbuffer_height; mode.format_id = desc->backbuffer_format; mode.refresh_rate = desc->refresh_rate; mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN; if (FAILED(hr = wined3d_set_adapter_display_mode(device->wined3d, adapter->ordinal, &mode))) { WARN("Failed to set display mode, hr %#x.\n", hr); goto err; } displaymode_set = TRUE; } if (!(device->wined3d->flags & WINED3D_NO3D)) { hr = wined3d_cs_emit_create_swapchain_context(device->cs, swapchain); if (FAILED(hr)) goto err; } if (swapchain->desc.backbuffer_count > 0) { swapchain->back_buffers = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->back_buffers) * swapchain->desc.backbuffer_count); if (!swapchain->back_buffers) { ERR("Failed to allocate backbuffer array memory.\n"); hr = E_OUTOFMEMORY; goto err; } surface_desc.usage |= WINED3DUSAGE_RENDERTARGET; for (i = 0; i < swapchain->desc.backbuffer_count; ++i) { TRACE("Creating back buffer %u.\n", i); if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent, parent, &surface_desc, &swapchain->back_buffers[i]))) { WARN("Failed to create back buffer %u, hr %#x.\n", i, hr); swapchain->desc.backbuffer_count = i; goto err; } surface_set_swapchain(swapchain->back_buffers[i], swapchain); } } /* Swapchains share the depth/stencil buffer, so only create a single depthstencil surface. */ if (desc->enable_auto_depth_stencil && !(device->wined3d->flags & WINED3D_NO3D)) { TRACE("Creating depth/stencil buffer.\n"); if (!device->auto_depth_stencil) { surface_desc.format = swapchain->desc.auto_depth_stencil_format; surface_desc.usage = WINED3DUSAGE_DEPTHSTENCIL; if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent, device->device_parent, &surface_desc, &device->auto_depth_stencil))) { WARN("Failed to create the auto depth stencil, hr %#x.\n", hr); goto err; } } } wined3d_swapchain_get_gamma_ramp(swapchain, &swapchain->orig_gamma); return WINED3D_OK; err: if (displaymode_set) { if (FAILED(wined3d_set_adapter_display_mode(device->wined3d, adapter->ordinal, &swapchain->original_mode))) ERR("Failed to restore display mode.\n"); ClipCursor(NULL); } if (swapchain->back_buffers) { for (i = 0; i < swapchain->desc.backbuffer_count; ++i) { if (swapchain->back_buffers[i]) { surface_set_swapchain(swapchain->back_buffers[i], NULL); wined3d_surface_decref(swapchain->back_buffers[i]); } } HeapFree(GetProcessHeap(), 0, swapchain->back_buffers); } if (swapchain->context) { if (swapchain->context[0]) { context_release(swapchain->context[0]); context_destroy(device, swapchain->context[0]); swapchain->num_contexts = 0; } HeapFree(GetProcessHeap(), 0, swapchain->context); } if (swapchain->front_buffer) { surface_set_swapchain(swapchain->front_buffer, NULL); wined3d_surface_decref(swapchain->front_buffer); } return hr; }