void *wined3d_resource_map_internal(struct wined3d_resource *resource, DWORD flags) { struct wined3d_device *device = resource->device; struct wined3d_context *context = NULL; void *mem; if (device->d3d_initialized) context = context_acquire(device, NULL); if (!wined3d_resource_prepare_map_memory(resource, context)) { WARN("Out of memory.\n"); context_release(context); return NULL; } if (flags & WINED3D_MAP_DISCARD) { switch (resource->map_binding) { case WINED3D_LOCATION_BUFFER: resource->map_buffer = wined3d_device_get_bo(device, resource->size, GL_STREAM_DRAW_ARB, GL_PIXEL_UNPACK_BUFFER_ARB, context); break; case WINED3D_LOCATION_SYSMEM: wined3d_resource_allocate_sysmem(resource); break; default: if (resource->access_fence) ERR("Location %s does not support DISCARD maps.\n", wined3d_debug_location(resource->map_binding)); if (resource->pool != WINED3D_POOL_DEFAULT) FIXME("Discard used on %s pool resource.\n", debug_d3dpool(resource->pool)); } wined3d_resource_validate_location(resource, resource->map_binding); } else { wined3d_resource_load_location(resource, context, resource->map_binding); } mem = wined3d_resource_get_map_ptr(resource, context, flags); if (context) context_release(context); return mem; }
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; }
static void swapchain_gl_present(struct wined3d_swapchain *swapchain, const RECT *src_rect_in, const RECT *dst_rect_in, const RGNDATA *dirty_region, DWORD flags, struct wined3d_surface *depth_stencil) { struct wined3d_surface *back_buffer = swapchain->back_buffers[0]; const struct wined3d_gl_info *gl_info; struct wined3d_context *context; RECT src_rect, dst_rect; BOOL render_to_fbo; context = context_acquire(swapchain->device, back_buffer); if (!context->valid) { context_release(context); WARN("Invalid context, skipping present.\n"); return; } gl_info = context->gl_info; if (swapchain->device->logo_texture) { struct wined3d_surface *src_surface = surface_from_resource( wined3d_texture_get_sub_resource(swapchain->device->logo_texture, 0)); RECT rect = {0, 0, src_surface->resource.width, src_surface->resource.height}; /* Blit the logo into the upper left corner of the drawable. */ wined3d_surface_blt(back_buffer, &rect, src_surface, &rect, WINEDDBLT_ALPHATEST, NULL, WINED3D_TEXF_POINT); } TRACE("Presenting HDC %p.\n", context->hdc); render_to_fbo = swapchain->render_to_fbo; if (src_rect_in) { src_rect = *src_rect_in; if (!render_to_fbo && (src_rect.left || src_rect.top || src_rect.right != swapchain->desc.backbuffer_width || src_rect.bottom != swapchain->desc.backbuffer_height)) { render_to_fbo = TRUE; } } else { src_rect.left = 0; src_rect.top = 0; src_rect.right = swapchain->desc.backbuffer_width; src_rect.bottom = swapchain->desc.backbuffer_height; } if (dst_rect_in) dst_rect = *dst_rect_in; else GetClientRect(swapchain->win_handle, &dst_rect); if (!render_to_fbo && (dst_rect.left || dst_rect.top || dst_rect.right != swapchain->desc.backbuffer_width || dst_rect.bottom != swapchain->desc.backbuffer_height)) render_to_fbo = TRUE; /* Rendering to a window of different size, presenting partial rectangles, * or rendering to a different window needs help from FBO_blit or a textured * draw. Render the swapchain to a FBO in the future. * * Note that FBO_blit from the backbuffer to the frontbuffer cannot solve * all these issues - this fails if the window is smaller than the backbuffer. */ if (!swapchain->render_to_fbo && render_to_fbo && wined3d_settings.offscreen_rendering_mode == ORM_FBO) { wined3d_resource_load_location(&back_buffer->resource, context, WINED3D_LOCATION_TEXTURE_RGB); wined3d_resource_invalidate_location(&back_buffer->resource, WINED3D_LOCATION_DRAWABLE); swapchain->render_to_fbo = TRUE; swapchain_update_draw_bindings(swapchain); } else { wined3d_resource_load_location(&back_buffer->resource, context, back_buffer->draw_binding); } if (swapchain->render_to_fbo) { static unsigned int once; if (swapchain->desc.swap_effect == WINED3D_SWAP_EFFECT_FLIP && !once++) FIXME("WINED3D_SWAP_EFFECT_FLIP not implemented.\n"); swapchain_blit(swapchain, context, &src_rect, &dst_rect); } if (swapchain->num_contexts > 1 && !wined3d_settings.cs_multithreaded) gl_info->gl_ops.gl.p_glFlush(); /* call wglSwapBuffers through the gl table to avoid confusing the Steam overlay */ gl_info->gl_ops.wgl.p_wglSwapBuffers(context->hdc); /* TODO: cycle through the swapchain buffers */ TRACE("SwapBuffers called, Starting new frame\n"); /* FPS support */ if (TRACE_ON(fps)) { DWORD time = GetTickCount(); ++swapchain->frames; /* every 1.5 seconds */ if (time - swapchain->prev_time > 1500) { TRACE_(fps)("%p @ approx %.2ffps\n", swapchain, 1000.0 * swapchain->frames / (time - swapchain->prev_time)); swapchain->prev_time = time; swapchain->frames = 0; } } wined3d_resource_validate_location(&swapchain->front_buffer->resource, WINED3D_LOCATION_DRAWABLE); wined3d_resource_invalidate_location(&swapchain->front_buffer->resource, ~WINED3D_LOCATION_DRAWABLE); switch (swapchain->desc.swap_effect) { case WINED3D_SWAP_EFFECT_DISCARD: wined3d_resource_validate_location(&back_buffer->resource, WINED3D_LOCATION_DISCARDED); break; case WINED3D_SWAP_EFFECT_FLIP: wined3d_resource_validate_location(&back_buffer->resource, back_buffer->draw_binding); wined3d_resource_invalidate_location(&back_buffer->resource, ~back_buffer->draw_binding); break; default: break; } if (depth_stencil) { if (swapchain->desc.flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL || depth_stencil->flags & SFLAG_DISCARD) { surface_modify_ds_location(depth_stencil, WINED3D_LOCATION_DISCARDED, depth_stencil->resource.width, depth_stencil->resource.height); if (depth_stencil == swapchain->device->cs->onscreen_depth_stencil) { wined3d_surface_decref(swapchain->device->cs->onscreen_depth_stencil); swapchain->device->cs->onscreen_depth_stencil = NULL; } } } context_release(context); }