context.c revision a7ba3d5f31ca70d04a3933e570374e5ec5eff84a
/*
* Context and render target management in wined3d
*
* Copyright 2007-2011, 2013 Stefan Dösinger for CodeWeavers
* Copyright 2009-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 <stdio.h>
#ifdef HAVE_FLOAT_H
# include <float.h>
#endif
#include "wined3d_private.h"
static DWORD wined3d_context_tls_idx;
#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
# define vboxGetCurrentContext() VBoxTlsRefGetCurrent(struct wined3d_context, wined3d_context_tls_idx)
# define vboxSetCurrentContext(_ctx) VBoxTlsRefSetCurrent(struct wined3d_context, wined3d_context_tls_idx, (_ctx))
#endif
/* FBO helper functions */
/* Context activation is done by the caller. */
{
switch (target)
{
case GL_READ_FRAMEBUFFER:
break;
case GL_DRAW_FRAMEBUFFER:
break;
case GL_FRAMEBUFFER:
break;
default:
break;
}
checkGLcall("glBindFramebuffer()");
}
/* Context activation is done by the caller. */
{
unsigned int i;
{
checkGLcall("glFramebufferTexture2D()");
}
checkGLcall("glFramebufferTexture2D()");
checkGLcall("glFramebufferTexture2D()");
}
/* Context activation is done by the caller. */
{
checkGLcall("glDeleteFramebuffers()");
}
{
{
checkGLcall("glFramebufferRenderbuffer()");
}
{
checkGLcall("glFramebufferRenderbuffer()");
}
}
/* Context activation is done by the caller. */
{
if (depth_stencil)
{
{
}
else
{
switch (location)
{
case SFLAG_INTEXTURE:
case SFLAG_INSRGBTEX:
{
checkGLcall("glFramebufferTexture2D()");
}
{
checkGLcall("glFramebufferTexture2D()");
}
break;
case SFLAG_INRB_MULTISAMPLE:
break;
case SFLAG_INRB_RESOLVED:
break;
default:
break;
}
}
if (!(format_flags & WINED3DFMT_FLAG_DEPTH))
{
checkGLcall("glFramebufferTexture2D()");
}
if (!(format_flags & WINED3DFMT_FLAG_STENCIL))
{
checkGLcall("glFramebufferTexture2D()");
}
}
else
{
checkGLcall("glFramebufferTexture2D()");
checkGLcall("glFramebufferTexture2D()");
}
}
/* Context activation is done by the caller. */
{
{
switch (location)
{
case SFLAG_INTEXTURE:
case SFLAG_INSRGBTEX:
checkGLcall("glFramebufferTexture2D()");
break;
case SFLAG_INRB_MULTISAMPLE:
checkGLcall("glFramebufferRenderbuffer()");
break;
case SFLAG_INRB_RESOLVED:
checkGLcall("glFramebufferRenderbuffer()");
break;
default:
break;
}
}
else
{
gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx, GL_TEXTURE_2D, 0, 0);
checkGLcall("glFramebufferTexture2D()");
}
}
/* Context activation is done by the caller. */
{
if (status == GL_FRAMEBUFFER_COMPLETE)
{
TRACE("FBO complete\n");
}
else
{
const struct wined3d_surface *attachment;
unsigned int i;
if (!context->current_fbo)
{
ERR("FBO 0 is incomplete, driver bug?\n");
return;
}
/* Dump the FBO attachments */
{
if (attachment)
{
FIXME("\tColor attachment %d: (%p) %s %ux%u %u samples.\n",
}
}
if (attachment)
{
FIXME("\tDepth attachment: (%p) %s %ux%u %u samples.\n",
}
}
}
{
}
{
}
{
entry->render_targets = HeapAlloc(GetProcessHeap(), 0, gl_info->limits.buffers * sizeof(*entry->render_targets));
memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
checkGLcall("glGenFramebuffers()");
return entry;
}
/* Context activation is done by the caller. */
{
memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
}
/* Context activation is done by the caller. */
{
{
}
}
/* Context activation is done by the caller. */
{
{
{
WARN("Depth stencil is smaller than the primary color buffer, disabling\n");
}
}
{
{
return entry;
}
}
{
}
else
{
}
return entry;
}
/* Context activation is done by the caller. */
static void context_apply_fbo_entry(struct wined3d_context *context, GLenum target, struct fbo_entry *entry)
{
unsigned int i;
{
return;
}
/* Apply render targets */
{
}
/* Apply depth targets */
if (entry->depth_stencil)
/* Set valid read and draw buffer bindings to satisfy pedantic pre-ES2_compatibility
* GL contexts requirements. */
if (target != GL_FRAMEBUFFER)
{
if (target == GL_READ_FRAMEBUFFER)
else
}
}
/* Context activation is done by the caller. */
{
{
}
if (context->rebind_fbo)
{
}
if (location == SFLAG_INDRAWABLE)
{
}
else
{
context->current_fbo = context_find_fbo_entry(context, target, render_targets, depth_stencil, location);
}
}
/* Context activation is done by the caller. */
{
if (clear_size)
}
/* Context activation is done by the caller. */
void context_alloc_occlusion_query(struct wined3d_context *context, struct wined3d_occlusion_query *query)
{
{
}
else
{
{
checkGLcall("glGenQueriesARB");
}
else
{
WARN("Occlusion queries not supported, not allocating query id.\n");
}
}
}
{
{
if (!new_data)
{
return;
}
}
}
/* Context activation is done by the caller. */
{
{
}
else
{
{
/* Using ARB_sync, not much to do here. */
}
{
checkGLcall("glGenFencesAPPLE");
}
{
checkGLcall("glGenFencesNV");
}
else
{
WARN("Event queries not supported, not allocating query id.\n");
}
}
}
{
{
union wined3d_gl_query_object *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_event_queries,
if (!new_data)
{
return;
}
}
}
{
UINT i;
for (i = 0; i < device->context_count; ++i)
{
{
UINT j;
{
continue;
}
{
{
break;
}
}
}
}
}
static void context_queue_fbo_entry_destruction(struct wined3d_context *context, struct fbo_entry *entry)
{
}
{
if (!device->d3d_initialized) return;
switch (type)
{
case WINED3D_RTYPE_SURFACE:
break;
default:
break;
}
}
{
}
{
switch (type)
{
case WINED3D_RTYPE_SURFACE:
break;
default:
break;
}
}
{
unsigned int i;
{
{
return;
}
}
{
}
}
#ifndef VBOX
{
if (!current)
{
{
/* This may also happen if the dc belongs to a destroyed window. */
WARN("Failed to set pixel format %d on device context %p, last error %#x.\n",
return FALSE;
}
return TRUE;
}
/* By default WGL doesn't allow pixel format adjustments but we need it
* here. For this reason there's a Wine specific wglSetPixelFormat()
* which allows us to set the pixel format multiple times. Only use it
* when really needed. */
{
{
ERR("wglSetPixelFormatWINE failed to set pixel format %d on device context %p.\n",
return FALSE;
}
return TRUE;
}
/* OpenGL doesn't allow pixel format adjustments. Print an error and
* continue using the old format. There's a big chance that the old
* format works although with a performance hit and perhaps rendering
* errors. */
ERR("Unable to set pixel format %d on device context %p. Already using format %d.\n",
return TRUE;
}
#endif
{
#ifndef VBOX
{
WARN("Failed to set pixel format %d on device context %p.\n",
}
#else
#endif
{
#ifndef VBOX_WITH_WDDM
#endif
#ifndef VBOX
WARN("Failed to make GL context %p current on device context %p, last error %#x.\n",
#else
WARN("Failed to make GL context %p current on device context %p, last error %#x.\n",
#endif
WARN("Trying fallback to the backup window.\n");
#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
/* FIXME: If the context is destroyed it's no longer associated with
* a swapchain, so we can't use the swapchain to get a backup dc. To
* make this work windowless contexts would need to be handled by the
* device. */
{
return FALSE;
}
#endif
#ifndef VBOX_WITH_WDDM
{
return FALSE;
}
#ifndef VBOX
{
ERR("Failed to set pixel format %d on device context %p.\n",
return FALSE;
}
#endif
{
ERR("Fallback to backup window (dc %p) failed too, last error %#x.\n",
dc, GetLastError());
return FALSE;
}
#else
return FALSE;
#endif
}
return TRUE;
}
static void context_restore_gl_context(const struct wined3d_gl_info *gl_info, HDC dc, HGLRC gl_ctx, int pf)
{
#ifndef VBOX
{
return;
}
#endif
{
ERR("Failed to restore GL context %p on device context %p, last error %#x.\n",
}
#ifdef VBOX
else
{
/* success branch */
/* sync back our tls with gl settings */
{
UINT i = 0;
for (; i < device->context_count; ++i)
{
{
break;
}
}
if (i == device->context_count)
{
}
}
}
#endif
}
{
{
ERR("NULL hDC");
return FALSE;
}
#if defined(DEBUG) || !defined(VBOX_WITH_WDDM)
{
{
# if defined(VBOX_WITH_WDDM)
ERR("Unexpected swapchain for dc %p window expected %p, but was %p.\n", swapchain->hDC, swapchain->win_handle, hWnd);
# else
ERR("Swapchain for dc %p window expected %p, but was %p.\n", swapchain->hDC, swapchain->win_handle, hWnd);
return FALSE;
# endif
}
}
#endif
return TRUE;
}
{
int i;
if (context)
{
{
return swapchain;
}
}
{
{
return device->swapchains[i];
}
}
return NULL;
}
{
if (swapchain)
return swapchain;
ERR("no valid swapchain found!");
return swapchain;
}
struct wined3d_swapchain *swapchain,
const struct wined3d_format *ds_format)
{
struct wined3d_context *context;
struct wined3d_surface *target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
if (!device->context_count)
{
#ifdef VBOX_WITH_WDDM
#endif
);
if(!context)
{
ERR("Failed to create the context.\n");
}
else
{
}
}
else
{
if(!context)
{
ERR("Failed to acquire the context.\n");
}
else
{
}
}
return context;
}
#endif
, struct wined3d_swapchain *swapchain
#endif
)
{
TRACE("Updating context %p swapchain from %p to %p.\n",
return;
if (!swapchain_validate(swapchain))
{
goto err;
}
#else
return;
TRACE("Updating context %p window from %p to %p.\n",
{
/* You'd figure ReleaseDC() would fail if the DC doesn't match the
* window. However, that's not what actually happens, and there are
* user32 tests that confirm ReleaseDC() with the wrong window is
* supposed to succeed. So explicitly check that the DC belongs to
* the window, since we want to avoid releasing a DC that belongs to
* some other window if the original window was already destroyed. */
{
WARN("DC %p does not belong to window %p.\n",
}
#ifndef VBOX
#else
#endif
{
ERR("Failed to release device context %p, last error %#x.\n",
}
}
#ifndef VBOX
#else
#endif
{
goto err;
}
#ifndef VBOX
{
ERR("Failed to set pixel format %d on device context %p.\n",
goto err;
}
#endif
#endif
return;
err:
}
{
return;
if (!swapchain)
{
ERR("no valid swapchain found");
return;
}
}
#endif
/* Do not call while under the GL lock. */
{
struct wined3d_occlusion_query *occlusion_query;
struct wined3d_event_query *event_query;
unsigned int i;
int restore_pf;
#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
#else
#endif
else
restore_ctx = NULL;
LIST_FOR_EACH_ENTRY(occlusion_query, &context->occlusion_queries, struct wined3d_occlusion_query, entry)
{
}
{
{
{
}
else if (gl_info->supported[APPLE_FENCE]) GL_EXTCALL(glDeleteFencesAPPLE(1, &event_query->object.id));
}
}
{
}
{
}
{
if (context->dummy_arbfp_prog)
{
}
GL_EXTCALL(glDeleteQueriesARB(context->free_occlusion_query_count, context->free_occlusion_queries));
{
for (i = 0; i < context->free_event_query_count; ++i)
{
}
}
{
for (i = 0; i < context->free_event_query_count; ++i)
{
}
}
{
for (i = 0; i < context->free_event_query_count; ++i)
{
}
}
checkGLcall("context cleanup");
}
if (restore_ctx)
{
}
{
ERR("Failed to disable GL context.\n");
}
#ifndef VBOX_WITH_WDDM
# ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
# ifndef VBOX
# else
# endif
# endif
#endif
{
}
}
DWORD context_get_tls_idx(void)
{
return wined3d_context_tls_idx;
}
{
}
#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
{
{
/* this is a destroyed context left in the tls of the current thread */
/* 1. this releases the context and clears the tls */
/* return there is no context current */
return NULL;
}
if (!adjustTid)
return ctx;
return ctx;
/* the context may have cleared swapchain (if swapchain was destroyed), ensure it has some valid swapchain set */
if (context_set_current(ctx))
{
return ctx;
}
ERR("context_set_current failed\n");
return NULL;
}
#endif
struct wined3d_context *context_get_current(void)
{
#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
return TlsGetValue(wined3d_context_tls_idx);
#else
return context_get_current_ex(tid);
#endif
}
/* Do not call while under the GL lock. */
{
#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
#else
#endif
{
#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
{
}
else
#endif
{
return TRUE;
}
}
if (old)
{
#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
#else
{
}
else
{
}
#endif
}
if (ctx)
{
{
return FALSE;
}
#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
TRACE("Switching to D3D context %p, GL context %p, device context %p.\n", ctx, ctx->glCtx, ctx->hdc);
#else
TRACE("Switching to D3D context %p, GL context %p, device context %p.\n", ctx, ctx->glCtx, ctx->swapchain->hDC);
#endif
if (!context_set_gl_context(ctx))
return FALSE;
}
else if(wglGetCurrentContext())
{
TRACE("Clearing current D3D context.\n");
{
#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
#else
#endif
return FALSE;
}
}
#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
if (ctx)
return TRUE;
#else
#endif
}
#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
{
/* In theory, we should do context_set_current(NULL) here,
* but since it may result in calling a context dtor, it should be done under wined3d lock.
* We can not acquire a wined3d lock here since this routine is called in a DllMain context
* and this would result in a lock order violation, which may result in a deadlock.
* In other words, wined3d may internally call Win32 API functions which result in
* a DLL lock acquisition while holding wined3d lock.
* So lock order should always be "wined3d lock" -> "dll lock".
*
* This is why we do the following:
* */
/* 1. get the current context w/o adjusting its thread id, etc. */
if (!old)
return;
// /* there is a currently assigned context,
// * 2. now increase its ref count to ensure its dtor routine is not called while making set_current(NULL).
// * This is needed since dtor can only be run with a wined3d lock held */
// VBoxTlsRefAddRef(old);
/* context_tls_dtor now does only memfree, so just call it right away */
/* 3. now we can call context_set_current(NULL) */
// /* 4. to avoid possible deadlocks we make an asynchronous call to a worker thread to make
// * wined3d lock - context release - wined3d unlock from there. */
// VBoxExtReleaseContextAsync(old);
}
#endif
{
{
else if (context != context_get_current())
}
{
TRACE("Restoring GL context %p on device context %p.\n", context->restore_ctx, context->restore_dc);
context_restore_gl_context(context->gl_info, context->restore_dc, context->restore_ctx, context->restore_pf);
}
}
{
{
{
TRACE("Another GL context (%p on device context %p) is already current.\n",
}
}
}
{
}
/* This function takes care of wined3d pixel format selection. */
{
int iPixelFormat=0;
unsigned int current_value;
unsigned int i;
TRACE("device %p, dc %p, color_format %s, ds_format %s, aux_buffers %#x, find_compatible %#x.\n",
{
ERR("Unable to get color bits for format %s (%#x)!\n",
return 0;
}
current_value = 0;
for (i = 0; i < cfg_count; ++i)
{
unsigned int value;
/* For now only accept RGBA formats. Perhaps some day we will
* allow floating point formats for pbuffers. */
continue;
/* In window mode we need a window drawable format and double buffering. */
continue;
continue;
continue;
continue;
continue;
continue;
continue;
/* Check multisampling support. */
if (cfg->numSamples)
continue;
value = 1;
/* We try to locate a format which matches our requirements exactly. In case of
* depth it is no problem to emulate 16-bit using e.g. 24-bit, so accept that. */
value += 1;
value += 2;
value += 4;
/* We like to have aux buffers in backbuffer mode */
value += 8;
value += 16;
if (value > current_value)
{
}
}
/* When findCompatible is set and no suitable format was found, let ChoosePixelFormat choose a pixel format in order not to crash. */
if(!iPixelFormat && !findCompatible) {
ERR("Can't find a suitable iPixelFormat\n");
return FALSE;
} else if(!iPixelFormat) {
TRACE("Falling back to ChoosePixelFormat as we weren't able to find an exactly matching pixel format\n");
/* PixelFormat selection */
pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/
if(!iPixelFormat) {
/* If this happens something is very wrong as ChoosePixelFormat barely fails */
ERR("Can't find a suitable iPixelFormat\n");
return FALSE;
}
}
TRACE("Found iPixelFormat=%d for ColorFormat=%s, DepthStencilFormat=%s\n",
return iPixelFormat;
}
/* Context activation is done by the caller. */
static void bind_dummy_textures(const struct wined3d_device *device, const struct wined3d_context *context)
{
for (i = 0; i < count; ++i)
{
checkGLcall("glActiveTextureARB");
checkGLcall("glBindTexture");
{
checkGLcall("glBindTexture");
}
{
checkGLcall("glBindTexture");
}
{
checkGLcall("glBindTexture");
}
}
}
#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
{
}
#endif
{
}
{
switch (type)
{
case GL_DEBUG_TYPE_ERROR_ARB:
break;
break;
break;
default:
break;
}
}
/* Do not call while under the GL lock. */
#ifdef VBOX_WITH_WDDM
, struct VBOXUHGSMI *pHgsmi
#endif
)
{
const struct wined3d_format *color_format;
struct wined3d_context *ret;
int pixel_format;
unsigned int s;
int swap_interval;
#ifdef VBOX_WITH_WDDM
if (!pHgsmi)
{
ERR("HGSMI should be specified!");
return NULL;
}
#endif
if (!ret)
return NULL;
if (!ret->blit_targets)
goto out;
if (!ret->draw_buffers)
goto out;
if (!ret->free_occlusion_queries)
goto out;
if (!ret->free_event_queries)
goto out;
#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
#endif
{
ERR("Swapchain hDC is null");
goto out;
}
#else
{
WARN("Failed to retireve device context, trying swapchain backup.\n");
{
ERR("Failed to retrieve a device context.\n");
goto out;
}
}
#endif
/* In case of ORM_BACKBUFFER, make sure to request an alpha component for
{
auxBuffers = TRUE;
}
/* DirectDraw supports 8bit paletted render targets and these are used by
* old games like StarCraft and C&C. Most modern hardware doesn't support
* 8bit natively so we perform some form of 8bit -> 32bit conversion. The
* conversion (ab)uses the alpha component for storing the palette index.
* For this reason we require a format with 8bit alpha, so request
* A8R8G8B8. */
/* Try to find a pixel format which matches our requirements. */
pixel_format = context_choose_pixel_format(device, hdc, color_format, ds_format, auxBuffers, FALSE);
/* Try to locate a compatible format if we weren't able to find anything. */
if (!pixel_format)
{
TRACE("Trying to locate a compatible pixel format because an exact match failed.\n");
}
/* If we still don't have a pixel format, something is very wrong as ChoosePixelFormat barely fails */
if (!pixel_format)
{
ERR("Can't find a suitable pixel format.\n");
goto out;
}
#ifndef VBOX
{
goto out;
}
{
unsigned int ctx_attrib_idx = 0;
{
}
ctx_attribs[ctx_attrib_idx] = 0;
{
ERR("Failed to create a WGL context.\n");
goto out;
}
}
else
{
#else
#ifdef VBOX_WITH_WDDM
, pHgsmi
#else
, NULL
#endif
);
if (!ctx)
#endif
{
ERR("Failed to create a WGL context.\n");
goto out;
}
#ifndef VBOX
{
if (!wglDeleteContext(ctx))
goto out;
}
}
#endif
{
ERR("Failed to add the newly created context to the context list\n");
if (!wglDeleteContext(ctx))
goto out;
}
/* Mark all states dirty to force a proper initialization of the states
* on the first use of the context. */
{
}
#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
#else
#endif
#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
#endif
/* Set up the context defaults */
if (!context_set_current(ret))
{
ERR("Cannot activate context to set up defaults.\n");
if (!wglDeleteContext(ctx))
goto out;
}
{
if (TRACE_ON(d3d_synchronous))
{
}
{
}
{
}
}
{
swap_interval = 0;
break;
swap_interval = 1;
break;
swap_interval = 2;
break;
swap_interval = 3;
break;
swap_interval = 4;
break;
default:
swap_interval = 1;
}
{
ERR("wglSwapIntervalEXT failed to set swap interval %d for context %p, last error %#x\n",
}
#ifdef VBOX
/* for WDDM case this is used for shared resource handling
*
* for XPDM this is needed to at least support texture sharing between device contexts.
* this is a kinda hack, but it is needed since our ogl driver currently does not support ShareLists */
# if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
# endif
# if defined(VBOX_WITH_WDDM)
# endif
#endif
TRACE("Setting up the screen\n");
checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);");
checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, device->surface_alignment);");
{
/* Most textures will use client storage if supported. Exceptions are
* non-native power of 2 textures and textures in DIB sections. */
checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
}
{
/* Direct3D always uses n-1 weights for n world matrices and uses
* 1 - sum for the last one this is equal to GL_WEIGHT_SUM_UNITY_ARB.
* Enabling it doesn't do anything unless GL_VERTEX_BLEND_ARB isn't
* enabled as well. */
checkGLcall("glEnable(GL_WEIGHT_SUM_UNITY_ARB)");
}
{
/* Set up the previous texture input for all shader units. This applies to bump mapping, and in d3d
* the previous texture where to source the offset from is always unit - 1.
*/
{
checkGLcall("glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ...");
}
}
{
/* MacOS(radeon X1600 at least, but most likely others too) refuses to draw if GLSL and ARBFP are
* enabled, but the currently bound arbfp program is 0. Enabling ARBFP with prog 0 is invalid, but
* GLSL should bypass this. This causes problems in programs that never use the fixed function pipeline,
* because the ARBFP extension is enabled by the ARBFP pipeline at context creation, but no program
* is ever assigned.
*
* So make sure a program is assigned to each context. The first real ARBFP use will set a different
* program and the dummy program is destroyed when the context is destroyed.
*/
const char *dummy_program =
"!!ARBfp1.0\n"
"MOV result.color, fragment.color.primary;\n"
"END\n";
GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(dummy_program), dummy_program));
}
{
{
checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)");
}
}
{
}
{
}
/* If this happens to be the first context for the device, dummy textures
* are not created yet. In that case, they will be created (and bound) by
* create_dummy_textures right after this context is initialized. */
if (device->dummy_texture_2d[0])
return ret;
out:
return NULL;
}
/* Do not call while under the GL lock. */
{
#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
#endif
#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
{
}
else
{
/* Make a copy of gl_info for context_destroy_gl_resources use, the one
in wined3d_adapter may go away in the meantime */
}
#else
#endif
#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
#else
#endif
}
/* Context activation is done by the caller. */
{
const GLdouble projection[] =
{
0.0, 0.0, 2.0, 0.0,
-1.0, -1.0, -1.0, 1.0,
};
checkGLcall("glMatrixMode(GL_PROJECTION)");
checkGLcall("glLoadMatrixd");
checkGLcall("glViewport");
}
{
{
ERR("not tested!");
#else
#endif
#ifdef DEBUG_misha
#endif
return;
}
}
/*****************************************************************************
* SetupForBlit
*
* Sets up a context for DirectDraw blitting.
* All texture units are disabled, texture unit 0 is set as current unit
* fog, lighting, blending, alpha test, z test, scissor test, culling disabled
* color writing enabled for all channels
* register combiners disabled, shaders disabled
* world matrix is set to identity, texture matrix 0 too
* projection matrix is setup for drawing screen coordinates
*
* Params:
* This: Device to activate the context for
* context: Context to setup
*
*****************************************************************************/
/* Context activation is done by the caller. */
{
int i;
if (context->last_was_blit)
{
{
/* No need to dirtify here, the states are still dirtified because
* they weren't applied since the last SetupForBlit() call. */
}
TRACE("Context is already set up for blitting, nothing to do\n");
return;
}
/* Disable all textures. The caller can then bind a texture it wants to blit
* from
*
* The blitting code uses (for now) the fixed function pipeline, so make sure to reset all fixed
* function texture unit. No need to care for higher samplers
*/
{
{
checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
}
checkGLcall("glDisable GL_TEXTURE_3D");
{
checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
}
checkGLcall("glDisable GL_TEXTURE_2D");
checkGLcall("glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);");
if (sampler != WINED3D_UNMAPPED_STAGE)
{
if (sampler < MAX_TEXTURES)
}
}
{
checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
}
checkGLcall("glDisable GL_TEXTURE_3D");
{
checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
}
checkGLcall("glDisable GL_TEXTURE_2D");
checkGLcall("glMatrixMode(GL_TEXTURE)");
checkGLcall("glLoadIdentity()");
{
GL_TEXTURE_LOD_BIAS_EXT, 0.0f);
checkGLcall("glTexEnvf GL_TEXTURE_LOD_BIAS_EXT ...");
}
if (sampler != WINED3D_UNMAPPED_STAGE)
{
if (sampler < MAX_TEXTURES)
{
}
}
/* Other misc states */
checkGLcall("glDisable(GL_ALPHA_TEST)");
checkGLcall("glDisable GL_LIGHTING");
checkGLcall("glDisable GL_DEPTH_TEST");
checkGLcall("glDisable GL_FOG");
checkGLcall("glDisable GL_BLEND");
checkGLcall("glDisable GL_CULL_FACE");
checkGLcall("glDisable GL_STENCIL_TEST");
checkGLcall("glDisable GL_SCISSOR_TEST");
{
checkGLcall("glDisable GL_POINT_SPRITE_ARB");
}
checkGLcall("glColorMask");
{
checkGLcall("glDisable(GL_COLOR_SUM_EXT)");
}
/* Setup transforms */
checkGLcall("glMatrixMode(GL_MODELVIEW)");
checkGLcall("glLoadIdentity()");
/* Disable shaders */
}
{
}
{
}
/* Context activation is done by the caller. */
{
if (!rt_mask)
{
checkGLcall("glDrawBuffer()");
}
else if (is_rt_mask_onscreen(rt_mask))
{
checkGLcall("glDrawBuffer()");
}
else
{
{
unsigned int i = 0;
while (rt_mask)
{
if (rt_mask & 1)
else
rt_mask >>= 1;
++i;
}
{
checkGLcall("glDrawBuffers()");
}
else
{
checkGLcall("glDrawBuffer()");
}
}
else
{
ERR("Unexpected draw buffers mask with backbuffer ORM.\n");
}
}
}
/* Context activation is done by the caller. */
{
DWORD *current_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
if (new_mask == *current_mask)
return;
checkGLcall("glDrawBuffer()");
*current_mask = new_mask;
}
/* Context activation is done by the caller. */
void context_active_texture(struct wined3d_context *context, const struct wined3d_gl_info *gl_info, unsigned int unit)
{
checkGLcall("glActiveTextureARB");
}
{
if (name)
{
checkGLcall("glBindTexture");
}
else
{
}
if (old_texture_type != target)
{
switch (old_texture_type)
{
case GL_NONE:
/* nothing to do */
break;
case GL_TEXTURE_2D:
checkGLcall("glBindTexture");
break;
case GL_TEXTURE_RECTANGLE_ARB:
checkGLcall("glBindTexture");
break;
case GL_TEXTURE_CUBE_MAP:
checkGLcall("glBindTexture");
break;
case GL_TEXTURE_3D:
checkGLcall("glBindTexture");
break;
default:
}
}
}
{
}
const struct wined3d_format *required)
{
if ((existing->flags & WINED3DFMT_FLAG_FLOAT) != (required->flags & WINED3DFMT_FLAG_FLOAT)) return FALSE;
/* If stencil bits are used the exact amount is required - otherwise wrapping
* won't work correctly */
return TRUE;
}
/* The caller provides a context */
const struct wined3d_surface *depth_stencil)
{
/* Onscreen surfaces are always in a swapchain */
/* TODO: If the requested format would satisfy the needs of the existing one(reverse match),
* or no onscreen depth buffer was created, the OpenGL drawable could be changed to the new
* format. */
WARN("Depth stencil format is not supported by WGL, rendering the backbuffer in an FBO\n");
/* The currently active context is the necessary context to access the swapchain's onscreen buffers */
}
static DWORD context_generate_rt_mask_no_fbo(const struct wined3d_device *device, const struct wined3d_surface *rt)
{
return 0;
return context_generate_rt_mask_from_surface(rt);
else
}
/* Context activation is done by the caller. */
{
{
if (context->render_offscreen)
{
rt_mask = 1;
else
rt_mask = 0;
}
else
{
}
}
else
{
}
{
}
{
}
}
{
unsigned int i;
for (i = 0; i < rt_count; ++i)
{
return TRUE;
}
WARN("Invalid render target config, need at least one attachment.\n");
return FALSE;
}
/* Context activation is done by the caller. */
BOOL context_apply_clear_state(struct wined3d_context *context, const struct wined3d_device *device,
{
UINT i;
{
return FALSE;
{
{
for (i = 0; i < rt_count; ++i)
{
rt_mask |= (1 << i);
}
{
++i;
}
}
else
{
}
/* If the framebuffer is not the device's fb the device's fb has to be reapplied
* next draw. Otherwise we could mark the framebuffer state clean here, once the
* state management allows this */
}
else
{
}
}
{
for (i = 0; i < rt_count; ++i)
{
}
}
else
{
}
{
}
{
}
if (context->last_was_blit)
/* Blending and clearing should be orthogonal, but tests on the nvidia
* driver show that disabling blending when clearing improves the clearing
* performance incredibly. */
checkGLcall("glEnable GL_SCISSOR_TEST");
return TRUE;
}
static DWORD find_draw_buffers_mask(const struct wined3d_context *context, const struct wined3d_device *device)
{
unsigned int i;
if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return context_generate_rt_mask_no_fbo(device, rts[0]);
i = 0;
while (rt_mask_bits)
{
rt_mask_bits &= ~(1 << i);
rt_mask &= ~(1 << i);
i++;
}
return rt_mask;
}
/* Context activation is done by the caller. */
void context_state_fb(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
{
{
if (!context->render_offscreen)
{
}
else
{
}
}
{
}
}
/* Context activation is done by the caller. */
void context_state_drawbuf(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
{
{
}
}
/* Context activation is done by the caller. */
{
unsigned int i;
return FALSE;
if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && isStateDirty(context, STATE_FRAMEBUFFER))
{
}
/* Preload resources before FBO setup. Texture preload in particular may
* result in changes to the current FBO, due to using e.g. FBO blits for
* updating a resource location. */
if (state->index_buffer)
{
else
}
for (i = 0; i < context->numDirtyEntries; ++i)
{
}
if (context->select_shader)
{
context->select_shader = 0;
}
if (context->load_constants)
{
context->load_constants = 0;
}
{
}
return TRUE;
}
{
/* To compensate the lack of format switching with some offscreen rendering methods and on onscreen buffers
* the alpha blend state changes with different render target formats. */
if (!context->current_rt)
{
}
else
{
{
/* Disable blending when the alpha mask has changed and when a format doesn't support blending. */
}
/* When switching away from an offscreen render target, and we're not
* using FBOs, we have to read the drawable into the texture. This is
* done via PreLoad (and SFLAG_INDRAWABLE set on the surface). There
* are some things that need care though. PreLoad needs a GL context,
* and FindContext is called before the context is activated. It also
* has to be called with the old rendertarget active, otherwise a
* wrong drawable is read. */
{
/* Read the back buffer of the old drawable into the destination texture. */
}
}
}
/* Do not call while under the GL lock. */
struct wined3d_context *context_acquire(const struct wined3d_device *device, struct wined3d_surface *target)
{
struct wined3d_context *context;
#endif
#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
#endif
if (!target)
{
if (current_context
#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
#else
#endif
)
{
}
else
{
#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
#else
if (!swapchain)
{
ERR("no valid swapchain found!");
}
#endif
if (swapchain->back_buffers)
else
}
}
#ifdef VBOX_WITH_WINE_DBG
#endif
{
}
{
TRACE("Rendering onscreen.\n");
#endif
}
else
{
TRACE("Rendering offscreen.\n");
#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
/* Stay with the current context if possible. Otherwise use the
* context for the primary swapchain. */
else
#endif
}
#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
#else
if (!swapchain)
#endif
if (context != current_context)
{
if (!context_set_current(context))
ERR("Failed to activate the new context.\n");
}
else if (context->restore_ctx)
{
}
return context;
}