swapchain.c revision 058c0c53c37f5cb271aeb3c385c10766f84f4aef
/*
* Copyright 2002-2003 Jason Edmeades
* Copyright 2002-2003 Raphael Junqueira
* Copyright 2005 Oliver Stieber
* Copyright 2007-2008 Stefan Dösinger for CodeWeavers
* Copyright 2011 Henri Verbeet for CodeWeavers
*
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wined3d_private.h"
static VOID swapchain_cleanup_rt_refs(struct wined3d_swapchain *swapchain, struct wined3d_surface * rt, int iBb)
{
struct wined3d_context *context;
UINT i;
for (i = 0; i < device->context_count; ++i)
{
{
}
}
if (device->swapchain_count)
{
{
{
struct wined3d_surface *new_rt;
if (i)
else
new_rt = default_swapchain->back_buffers ? default_swapchain->back_buffers[0] : default_swapchain->front_buffer;
}
}
}
}
{
/* first make sure the swapchain is not used by anyone */
struct wined3d_context *context;
UINT i;
/* Release the swapchain's draw buffers. Make sure swapchain->back_buffers[0]
* is the last buffer to be destroyed, FindContext() depends on that. */
if (swapchain->front_buffer)
{
}
if (swapchain->back_buffers)
{
while (i--)
{
}
}
for (i = 0; i < device->context_count; ++i)
{
/* pretty hacky, @todo: check if the context is acquired and re-acquire it with a new swapchain */
{
}
}
//
// if (swapchain->front_buffer)
// swapchain_cleanup_rt_refs(swapchain, swapchain->front_buffer, -1);
//
// if (swapchain->back_buffers)
// {
// for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
// {
// swapchain_cleanup_rt_refs(swapchain, swapchain->back_buffers[i], i);
// }
// }
}
#endif
#ifdef VBOX_WITH_WDDM
{
UINT i;
for (i = 0; i < device->swapchain_count; ++i)
{
{
return swapchain;
}
}
return NULL;
}
{
}
#endif
/* Do not call while under the GL lock. */
{
#ifndef VBOX_WITH_WDDM
struct wined3d_display_mode mode;
#endif
UINT i;
#ifndef VBOX_WITH_WDDM
#endif
/* Release the swapchain's draw buffers. Make sure swapchain->back_buffers[0]
* is the last buffer to be destroyed, FindContext() depends on that. */
if (swapchain->front_buffer)
{
}
if (swapchain->back_buffers)
{
while (i--)
{
}
}
#endif
#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
for (i = 0; i < swapchain->num_contexts; ++i)
{
}
#endif
#ifndef VBOX_WITH_WDDM
/* Restore the screen resolution if we rendered in fullscreen.
* This will restore the screen resolution to what it was before creating
* the swapchain. In case of d3d8 and d3d9 this will be the original
* desktop resolution. In case of d3d7 this will be a NOP because ddraw
* sets the resolution before starting up Direct3D, thus orig_width and
* orig_height will be equal to the modes in the presentation params. */
{
mode.refresh_rate = 0;
}
{
TRACE("Destroying backup wined3d window %p, dc %p.\n", swapchain->backup_wnd, swapchain->backup_dc);
}
#endif
# ifdef VBOX_WITH_WDDM
if(swapchain->win_handle) {
}
# endif
#endif
}
{
return refcount;
}
/* Do not call while under the GL lock. */
{
if (!refcount)
{
}
return refcount;
}
{
}
{
#ifdef VBOX_WITH_WDDM
if (window)
ERR("not expected!");
#else
if (!window)
return;
TRACE("Setting swapchain %p window from %p to %p.\n",
#endif
}
{
TRACE("swapchain %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p, flags %#x.\n",
if (flags)
if (!swapchain->back_buffers)
{
WARN("Swapchain doesn't have a backbuffer, returning WINED3DERR_INVALIDCALL\n");
return WINED3DERR_INVALIDCALL;
}
return WINED3D_OK;
}
struct wined3d_surface *dst_surface)
{
struct wined3d_surface *src_surface;
#ifndef VBOX_WITH_WINE_FIXES
{
FIXME("Using destination rect %s in windowed mode, this is likely wrong.\n",
}
#endif
return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, &src_rect, 0, NULL, WINED3D_TEXF_POINT);
}
struct wined3d_surface * CDECL wined3d_swapchain_get_back_buffer(const struct wined3d_swapchain *swapchain,
{
TRACE("swapchain %p, back_buffer_idx %u, type %#x.\n",
#ifdef VBOX_WITH_WDDM
if (back_buffer_idx == ~0UL)
{
return swapchain->front_buffer;
}
#endif
/* Return invalid if there is no backbuffer array, otherwise it will
* crash when ddraw is used (there swapchain->back_buffers is always
* NULL). We need this because this function is called from
* stateblock_init_default_state() to get the default scissorrect
* dimensions. */
{
WARN("Invalid back buffer index.\n");
/* Native d3d9 doesn't set NULL here, just as wine's d3d9. But set it
* here in wined3d to avoid problems in other libs. */
return NULL;
}
}
struct wined3d_raster_status *raster_status)
{
}
{
TRACE("Returning w %u, h %u, refresh rate %u, format %s.\n",
return hr;
}
struct wined3d_device * CDECL wined3d_swapchain_get_device(const struct wined3d_swapchain *swapchain)
{
}
struct wined3d_swapchain_desc *desc)
{
}
{
if (flags)
#ifdef VBOX_WITH_WDDM
#else
#endif
#ifdef VBOX_WITH_WDDM
#else
#endif
return WINED3D_OK;
}
struct wined3d_gamma_ramp *ramp)
{
#ifdef VBOX_WITH_WDDM
#else
#endif
#ifdef VBOX_WITH_WDDM
#else
#endif
return WINED3D_OK;
}
/* A GL context is provided by the caller */
{
TRACE("swapchain %p, context %p, src_rect %s, dst_rect %s.\n",
else
if (gl_info->fbo_ops.glBlitFramebuffer && is_identity_fixup(backbuffer->resource.format->color_fixup))
{
{
}
context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
/* Note that the texture is upside down */
gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
checkGLcall("Swapchain present blit(EXT_framebuffer_blit)\n");
}
else
{
struct wined3d_context *context2;
{
tex_bottom /= src_h;
}
context_apply_fbo_state_blit(context2, GL_FRAMEBUFFER, swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
/* Set up the texture. The surface is not in a wined3d_texture
* container, so there are no D3D texture settings to dirtify. */
/* Set the viewport to the destination rectandle, disable any projection
* transformation set up by context_apply_blit_state(), and draw a
* (-1,-1)-(1,1) quad.
*
* Back up viewport and matrix to avoid breaking last_was_blit
*
* Note that context_apply_blit_state() set up viewport and ortho to
* match the surface size - we want the GL drawable(=window) size. */
/* bottom left */
/* top left */
/* top right */
/* bottom right */
checkGLcall("Swapchain present blit(manual)\n");
}
}
{
const struct wined3d_gl_info *gl_info;
struct wined3d_context *context;
{
WARN("Invalid context, skipping present.\n");
return;
}
/* Render the cursor onto the back buffer, using our nifty directdraw blitting code :-) */
{
struct wined3d_surface cursor;
{
};
/* Build a fake surface to call the Blitting code. It is not possible to use the interface passed by
* the application because we are only supposed to copy the information out. Using a fake surface
* allows us to use the Blitting engine and avoid copying the whole texture -> render target blitting code.
*/
cursor.texture_level = 0;
/* The cursor must have pow2 sizes */
/* The surface is in the texture */
/* DDBLT_KEYSRC will cause BltOverride to enable the alpha test with GL_NOTEQUAL, 0.0,
* which is exactly what we want :-)
*/
#ifndef VBOX_WITH_WINE_FIXES
#endif
}
{
/* Blit the logo into the upper left corner of the drawable. */
}
#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
#else
#endif
if (src_rect_in)
{
src_rect = *src_rect_in;
{
}
}
else
{
}
if (dst_rect_in)
dst_rect = *dst_rect_in;
else
/* 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)
{
}
else
{
}
if (swapchain->render_to_fbo)
{
/* This codepath should only be hit with the COPY swapeffect. Otherwise a backbuffer-
* window size mismatch is impossible(fullscreen) and src and dst rectangles are
* not allowed(they need the COPY swapeffect)
*
* The DISCARD swap effect is ok as well since any backbuffer content is allowed after
* the swap. */
FIXME("Render-to-fbo with WINED3D_SWAP_EFFECT_FLIP\n");
}
#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
#endif
# ifdef DEBUG
{
}
# endif
/* call wglSwapBuffers through the gl table to avoid confusing the Steam overlay */
gl_info->gl_ops.wgl.p_wglSwapBuffers(context->swapchain->hDC); /* TODO: cycle through the swapchain buffers */
#else
/* call wglSwapBuffers through the gl table to avoid confusing the Steam overlay */
#endif
TRACE("SwapBuffers called, Starting new frame\n");
/* FPS support */
{
/* every 1.5 seconds */
{
}
}
/* This is disabled, but the code left in for debug purposes.
*
* Since we're allowed to modify the new back buffer on a D3DSWAPEFFECT_DISCARD flip,
* we can clear it with some ugly color to make bad drawing visible and ease debugging.
* The Debug runtime does the same on Windows. However, a few games do not redraw the
* screen properly, like Max Payne 2, which leaves a few pixels undefined.
*
* Tests show that the content of the back buffer after a discard flip is indeed not
* reliable, so no game can depend on the exact content. However, it resembles the
* old contents in some way, for example by showing fragments at other locations. In
* general, the color theme is still intact. So Max payne, which draws rather dark scenes
* gets a dark background image. If we clear it with a bright ugly color, the game's
* bug shows up much more than it does on Windows, and the players see single pixels
* with wrong colors.
* (The Max Payne bug has been confirmed on Windows with the debug runtime) */
{
TRACE("Clearing the color buffer with cyan color\n");
}
{
/* Both memory copies of the surfaces are ok, flip them around too instead of dirtifying
* Doesn't work with render_to_fbo because we're not flipping
*/
{
/* Tell the front buffer surface that is has been modified. However,
* the other locations were preserved during that, so keep the flags.
* This serves to update the emulated overlay, if any. */
}
else
{
}
}
else
{
/* If the swapeffect is DISCARD, the back buffer is undefined. That means the SYSMEM
* and INTEXTURE copies can keep their old content if they have any defined content.
* If the swapeffect is COPY, the content remains the same. If it is FLIP however,
* the texture / sysmem copy needs to be reloaded from the drawable
*/
}
if (fb->depth_stencil)
{
{
{
}
}
}
}
static const struct wined3d_swapchain_ops swapchain_gl_ops =
{
};
/* Helper function that blits the front buffer contents to the target window. */
{
const struct wined3d_surface *front;
return;
ERR("Trying to blit a mapped surface.\n");
/* Front buffer coordinates are screen coordinates. Map them to the
* destination window if not fullscreened. */
{
#ifndef VBOX_WITH_WINE_FIXES
#else
ERR("should not be here!");
#endif
}
if (rect)
}
{
/* Flip the DC. */
{
}
/* Flip the DIBsection. */
{
}
/* Flip the surface data. */
{
void *tmp;
}
/* FPS support */
{
++frames;
/* every 1.5 seconds */
{
frames = 0;
}
}
}
static const struct wined3d_swapchain_ops swapchain_gdi_ops =
{
};
{
return;
{
TRACE("Single buffered rendering.\n");
return;
}
TRACE("Backbuffer %ux%u, window %ux%u.\n",
TRACE("Multisample type %#x, quality %#x.\n",
{
TRACE("Backbuffer dimensions match window dimensions, rendering onscreen.\n");
return;
}
TRACE("Rendering to FBO.\n");
}
/* Do not call while under the GL lock. */
{
struct wined3d_resource_desc surface_desc;
const struct wined3d_format *format;
struct wined3d_display_mode mode;
#ifndef VBOX_WITH_WDDM
#endif
UINT i;
#ifdef VBOX_WITH_WDDM
#endif
{
FIXME("The application requested %u back buffers, this is not supported.\n",
return WINED3DERR_INVALIDCALL;
}
{
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");
}
else
#ifndef VBOX_WITH_WDDM
#else
if (desc->device_window)
{
if (!overriden_swapchain)
{
ERR("invalid window handle supplied");
return E_FAIL;
}
}
else
{
{
return hr;
}
}
#endif
#ifndef VBOX_WITH_WDDM
# ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
{
ERR("failed to get window DC");
return E_FAIL;
}
# endif
#else
#endif
#ifndef VBOX_WITH_WDDM
#endif
{
if (!desc->backbuffer_width)
{
}
if (!desc->backbuffer_height)
{
}
#ifndef VBOX_WITH_WDDM
{
}
#endif
}
TRACE("Creating front buffer.\n");
surface_desc.size = 0;
{
goto err;
}
/* 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? */
#ifndef VBOX_WITH_WDDM
{
struct wined3d_display_mode mode;
/* Change the display settings */
if (FAILED(hr = wined3d_set_adapter_display_mode(device->wined3d, device->adapter->ordinal, &mode)))
{
goto err;
}
}
#endif
{
#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
static const enum wined3d_format_id formats[] =
{
};
{
ERR("Failed to create the context array.\n");
hr = E_OUTOFMEMORY;
goto err;
}
/* 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. */
{
TRACE("Depth stencil format %s is not supported, trying next format\n",
debug_d3dformat(formats[i]));
}
#else
struct wined3d_context * swapchain_context;
if (!swapchain_context)
#endif
{
WARN("Failed to create context.\n");
goto err;
}
{
FIXME("Add OpenGL context recreation support to context_validate_onscreen_formats\n");
}
#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
#else
#endif
}
{
if (!swapchain->back_buffers)
{
ERR("Failed to allocate backbuffer array memory.\n");
hr = E_OUTOFMEMORY;
goto err;
}
{
TRACE("Creating back buffer %u.\n", i);
{
goto err;
}
}
}
{
if (!device->auto_depth_stencil)
{
{
goto err;
}
}
}
#ifndef VBOX_WITH_WDDM
#else
if (overriden_swapchain)
{
}
#endif
return WINED3D_OK;
err:
#ifndef VBOX_WITH_WDDM
if (displaymode_set)
{
/* Change the display settings */
}
#endif
if (swapchain->back_buffers)
{
{
if (swapchain->back_buffers[i])
{
}
}
#ifdef VBOX_WITH_WINE_FIX_INITCLEAR
#endif
}
#ifdef VBOX_WITH_WINE_FIX_INITCLEAR
#endif
#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
{
{
swapchain->num_contexts = 0;
}
}
#else
if (!device->swapchain_count)
{
while (device->context_count)
{
}
}
#endif
if (swapchain->front_buffer)
{
}
#ifdef VBOX_WITH_WDDM
{
}
#endif
return hr;
}
/* Do not call while under the GL lock. */
HRESULT CDECL wined3d_swapchain_create(struct wined3d_device *device, struct wined3d_swapchain_desc *desc,
{
struct wined3d_swapchain *object;
TRACE("device %p, desc %p, parent %p, parent_ops %p, swapchain %p.\n",
if (!object)
return E_OUTOFMEMORY;
{
return hr;
}
return WINED3D_OK;
}
#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
/* Do not call while under the GL lock. */
{
struct wined3d_context **newArray;
struct wined3d_context *ctx;
{
ERR("Failed to create a new context for the swapchain\n");
return NULL;
}
if(!newArray) {
ERR("Out of memory when trying to allocate a new context array\n");
return NULL;
}
return ctx;
}
{
unsigned int i;
for (i = 0; i < swapchain->num_contexts; ++i)
{
}
swapchain->num_contexts = 0;
}
{
unsigned int i;
for (i = 0; i < swapchain->num_contexts; ++i)
{
# else
#endif
}
/* Create a new context for the thread */
return swapchain_create_context(swapchain);
}
#else /* if defined VBOX_WINE_WITH_SINGLE_CONTEXT */
{
return context;
}
#endif
{
/* The drawable size of an onscreen drawable is the surface size.
* (Actually: The window size, but the surface is created in window size) */
}
#ifndef VBOX_WITH_WDDM
{
{
if (!(swapchain->backup_wnd = CreateWindowA(WINED3D_OPENGL_WINDOW_CLASS_NAME, "WineD3D fake window",
{
ERR("Failed to create a window.\n");
return NULL;
}
{
ERR("Failed to get a DC.\n");
return NULL;
}
}
}
#endif
{
UINT i;
{
}
}
#ifdef VBOX_WITH_WDDM
HRESULT CDECL wined3d_swapchain_present_rt(struct wined3d_swapchain *swapchain, struct wined3d_surface *rt)
{
{
return hr;
}
{
return hr;
}
return S_OK;
}
#endif