2007-02-12 19:18:36 +01:00
/*
* Context and render target management in wined3d
*
2008-03-29 02:36:13 +01:00
* Copyright 2007 - 2008 Stefan D <EFBFBD> singer for CodeWeavers
2007-02-12 19:18:36 +01:00
*
* This library is free software ; you can redistribute it and / or
* 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"
WINE_DEFAULT_DEBUG_CHANNEL ( d3d ) ;
2007-06-09 14:27:41 +02:00
# define GLINFO_LOCATION This->adapter->gl_info
2007-02-12 19:18:41 +01:00
2007-02-12 19:21:10 +01:00
/*****************************************************************************
* Context_MarkStateDirty
*
* Marks a state in a context dirty . Only one context , opposed to
* IWineD3DDeviceImpl_MarkStateDirty , which marks the state dirty in all
* contexts
*
* Params :
* context : Context to mark the state dirty in
* state : State to mark dirty
2008-03-09 19:30:08 +01:00
* StateTable : Pointer to the state table in use ( for state grouping )
2007-02-12 19:21:10 +01:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-03-09 19:30:08 +01:00
static void Context_MarkStateDirty ( WineD3DContext * context , DWORD state , const struct StateEntry * StateTable ) {
2007-02-12 19:21:10 +01:00
DWORD rep = StateTable [ state ] . representative ;
DWORD idx ;
BYTE shift ;
if ( ! rep | | isStateDirty ( context , rep ) ) return ;
context - > dirtyArray [ context - > numDirtyEntries + + ] = rep ;
idx = rep > > 5 ;
shift = rep & 0x1f ;
context - > isStateDirty [ idx ] | = ( 1 < < shift ) ;
}
2007-02-12 19:22:41 +01:00
/*****************************************************************************
* AddContextToArray
*
* Adds a context to the context array . Helper function for CreateContext
*
* This method is not called in performance - critical code paths , only when a
* new render target or swapchain is created . Thus performance is not an issue
* here .
*
* Params :
* This : Device to add the context for
2007-08-08 03:09:38 +02:00
* hdc : device context
* glCtx : WGL context to add
* pbuffer : optional pbuffer used with this context
2007-02-12 19:22:41 +01:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-08-08 03:09:38 +02:00
static WineD3DContext * AddContextToArray ( IWineD3DDeviceImpl * This , HWND win_handle , HDC hdc , HGLRC glCtx , HPBUFFERARB pbuffer ) {
2007-02-12 19:22:41 +01:00
WineD3DContext * * oldArray = This - > contexts ;
DWORD state ;
This - > contexts = HeapAlloc ( GetProcessHeap ( ) , 0 , sizeof ( * This - > contexts ) * ( This - > numContexts + 1 ) ) ;
if ( This - > contexts = = NULL ) {
ERR ( " Unable to grow the context array \n " ) ;
This - > contexts = oldArray ;
return NULL ;
}
if ( oldArray ) {
memcpy ( This - > contexts , oldArray , sizeof ( * This - > contexts ) * This - > numContexts ) ;
}
This - > contexts [ This - > numContexts ] = HeapAlloc ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY , sizeof ( WineD3DContext ) ) ;
if ( This - > contexts [ This - > numContexts ] = = NULL ) {
ERR ( " Unable to allocate a new context \n " ) ;
HeapFree ( GetProcessHeap ( ) , 0 , This - > contexts ) ;
This - > contexts = oldArray ;
return NULL ;
}
2007-08-08 03:09:38 +02:00
This - > contexts [ This - > numContexts ] - > hdc = hdc ;
2007-02-12 19:22:41 +01:00
This - > contexts [ This - > numContexts ] - > glCtx = glCtx ;
2007-08-08 03:09:38 +02:00
This - > contexts [ This - > numContexts ] - > pbuffer = pbuffer ;
This - > contexts [ This - > numContexts ] - > win_handle = win_handle ;
2007-02-12 19:22:41 +01:00
HeapFree ( GetProcessHeap ( ) , 0 , oldArray ) ;
/* Mark all states dirty to force a proper initialization of the states on the first use of the context
*/
for ( state = 0 ; state < = STATE_HIGHEST ; state + + ) {
2008-07-02 01:23:44 +02:00
Context_MarkStateDirty ( This - > contexts [ This - > numContexts ] , state , This - > StateTable ) ;
2007-02-12 19:22:41 +01:00
}
This - > numContexts + + ;
TRACE ( " Created context %p \n " , This - > contexts [ This - > numContexts - 1 ] ) ;
return This - > contexts [ This - > numContexts - 1 ] ;
}
2008-04-27 19:35:27 +02:00
/* This function takes care of WineD3D pixel format selection. */
2008-04-28 23:44:21 +02:00
static int WineD3D_ChoosePixelFormat ( IWineD3DDeviceImpl * This , HDC hdc , WINED3DFORMAT ColorFormat , WINED3DFORMAT DepthStencilFormat , BOOL auxBuffers , int numSamples , BOOL pbuffer , BOOL findCompatible )
2008-04-27 19:35:27 +02:00
{
2008-04-27 19:42:48 +02:00
int iPixelFormat = 0 ;
2008-04-27 19:35:27 +02:00
short redBits , greenBits , blueBits , alphaBits , colorBits ;
short depthBits = 0 , stencilBits = 0 ;
2008-04-27 19:42:48 +02:00
int i = 0 ;
int nCfgs = This - > adapter - > nCfgs ;
WineD3D_PixelFormat * cfgs = This - > adapter - > cfgs ;
2008-04-27 19:35:27 +02:00
2008-06-02 22:39:51 +02:00
TRACE ( " ColorFormat=%s, DepthStencilFormat=%s, auxBuffers=%d, numSamples=%d, pbuffer=%d, findCompatible=%d \n " ,
debug_d3dformat ( ColorFormat ) , debug_d3dformat ( DepthStencilFormat ) , auxBuffers , numSamples , pbuffer , findCompatible ) ;
2008-04-27 19:42:48 +02:00
if ( ! getColorBits ( ColorFormat , & redBits , & greenBits , & blueBits , & alphaBits , & colorBits ) ) {
2008-04-27 19:35:27 +02:00
ERR ( " Unable to get color bits for format %s (%#x)! \n " , debug_d3dformat ( ColorFormat ) , ColorFormat ) ;
return 0 ;
}
2008-05-18 19:41:56 +02:00
/* 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 . */
if ( DepthStencilFormat ! = WINED3DFMT_D24S8 )
FIXME ( " Add OpenGL context recreation support to SetDepthStencilSurface \n " ) ;
DepthStencilFormat = WINED3DFMT_D24S8 ;
2008-04-27 19:42:48 +02:00
if ( DepthStencilFormat ) {
getDepthStencilBits ( DepthStencilFormat , & depthBits , & stencilBits ) ;
2008-04-27 19:35:27 +02:00
}
2008-04-27 19:42:48 +02:00
/* Find a pixel format which EXACTLY matches our requirements (except for depth) */
for ( i = 0 ; i < nCfgs ; i + + ) {
BOOL exactDepthMatch = TRUE ;
2008-04-28 23:13:12 +02:00
cfgs = & This - > adapter - > cfgs [ i ] ;
2008-04-27 19:42:48 +02:00
/* For now only accept RGBA formats. Perhaps some day we will
* allow floating point formats for pbuffers . */
if ( cfgs - > iPixelType ! = WGL_TYPE_RGBA_ARB )
continue ;
2008-05-01 15:23:17 +02:00
/* In window mode (!pbuffer) we need a window drawable format and double buffering. */
if ( ! pbuffer & & ! ( cfgs - > windowDrawable & & cfgs - > doubleBuffer ) )
2008-04-27 19:42:48 +02:00
continue ;
/* We like to have aux buffers in backbuffer mode */
if ( auxBuffers & & ! cfgs - > auxBuffers )
continue ;
2008-05-01 15:26:02 +02:00
/* In pbuffer-mode we need a pbuffer-capable format but we don't want double buffering */
if ( pbuffer & & ( ! cfgs - > pbufferDrawable | | cfgs - > doubleBuffer ) )
2008-04-27 19:42:48 +02:00
continue ;
if ( cfgs - > redSize ! = redBits )
continue ;
if ( cfgs - > greenSize ! = greenBits )
continue ;
if ( cfgs - > blueSize ! = blueBits )
continue ;
if ( cfgs - > alphaSize ! = alphaBits )
continue ;
/* 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 . */
if ( cfgs - > depthSize < depthBits )
continue ;
else if ( cfgs - > depthSize > depthBits )
exactDepthMatch = FALSE ;
/* In all cases make sure the number of stencil bits matches our requirements
2008-05-03 16:37:09 +02:00
* even when we don ' t need stencil because it could affect performance EXCEPT
* on cards which don ' t offer depth formats without stencil like the i915 drivers
* on Linux . */
if ( stencilBits ! = cfgs - > stencilSize & & ! ( This - > adapter - > brokenStencil & & stencilBits < = cfgs - > stencilSize ) )
2008-04-27 19:42:48 +02:00
continue ;
2008-04-28 23:44:21 +02:00
/* Check multisampling support */
if ( cfgs - > numSamples ! = numSamples )
continue ;
2008-04-27 19:42:48 +02:00
/* When we have passed all the checks then we have found a format which matches our
* requirements . Note that we only check for a limit number of capabilities right now ,
* so there can easily be a dozen of pixel formats which appear to be the ' same ' but
* can still differ in things like multisampling , stereo , SRGB and other flags .
*/
/* Exit the loop as we have found a format :) */
if ( exactDepthMatch ) {
iPixelFormat = cfgs - > iPixelFormat ;
break ;
} else if ( ! iPixelFormat ) {
/* In the end we might end up with a format which doesn't exactly match our depth
* requirements . Accept the first format we found because formats with higher iPixelFormat
* values tend to have more extended capabilities ( e . g . multisampling ) which we don ' t need . */
iPixelFormat = cfgs - > iPixelFormat ;
}
2008-04-27 19:35:27 +02:00
}
2008-04-27 19:42:48 +02:00
/* When findCompatible is set and no suitable format was found, let ChoosePixelFormat choose a pixel format in order not to crash. */
if ( ! iPixelFormat & & ! findCompatible ) {
2008-04-27 19:35:27 +02:00
ERR ( " Can't find a suitable iPixelFormat \n " ) ;
return FALSE ;
2008-04-28 23:13:12 +02:00
} else if ( ! iPixelFormat ) {
2008-04-27 19:35:27 +02:00
PIXELFORMATDESCRIPTOR pfd ;
2008-04-27 19:42:48 +02:00
TRACE ( " Falling back to ChoosePixelFormat as we weren't able to find an exactly matching pixel format \n " ) ;
2008-04-27 19:35:27 +02:00
/* PixelFormat selection */
ZeroMemory ( & pfd , sizeof ( pfd ) ) ;
pfd . nSize = sizeof ( pfd ) ;
pfd . nVersion = 1 ;
pfd . dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW ; /*PFD_GENERIC_ACCELERATED*/
pfd . iPixelType = PFD_TYPE_RGBA ;
pfd . cAlphaBits = alphaBits ;
pfd . cColorBits = colorBits ;
pfd . cDepthBits = depthBits ;
pfd . cStencilBits = stencilBits ;
pfd . iLayerType = PFD_MAIN_PLANE ;
iPixelFormat = ChoosePixelFormat ( hdc , & pfd ) ;
if ( ! iPixelFormat ) {
/* If this happens something is very wrong as ChoosePixelFormat barely fails */
ERR ( " Can't find a suitable iPixelFormat \n " ) ;
return FALSE ;
}
}
2008-04-28 23:13:12 +02:00
TRACE ( " Found iPixelFormat=%d for ColorFormat=%s, DepthStencilFormat=%s \n " , iPixelFormat , debug_d3dformat ( ColorFormat ) , debug_d3dformat ( DepthStencilFormat ) ) ;
2008-04-27 19:35:27 +02:00
return iPixelFormat ;
}
2007-02-12 19:21:10 +01:00
/*****************************************************************************
* CreateContext
*
* Creates a new context for a window , or a pbuffer context .
*
2007-02-12 19:22:41 +01:00
* * Params :
2007-02-12 19:21:10 +01:00
* This : Device to activate the context for
* target : Surface this context will render to
2007-08-08 03:09:38 +02:00
* win_handle : handle to the window which we are drawing to
* create_pbuffer : tells whether to create a pbuffer or not
2007-08-11 12:17:56 +02:00
* pPresentParameters : contains the pixelformats to use for onscreen rendering
2007-02-12 19:21:10 +01:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-08-11 12:17:56 +02:00
WineD3DContext * CreateContext ( IWineD3DDeviceImpl * This , IWineD3DSurfaceImpl * target , HWND win_handle , BOOL create_pbuffer , const WINED3DPRESENT_PARAMETERS * pPresentParms ) {
2007-08-08 03:09:38 +02:00
HDC oldDrawable , hdc ;
HPBUFFERARB pbuffer = NULL ;
HGLRC ctx = NULL , oldCtx ;
2007-02-12 19:21:10 +01:00
WineD3DContext * ret = NULL ;
2007-06-17 00:26:17 +02:00
int s ;
2007-02-12 19:21:10 +01:00
2007-08-08 03:09:38 +02:00
TRACE ( " (%p): Creating a %s context for render target %p \n " , This , create_pbuffer ? " offscreen " : " onscreen " , target ) ;
2007-02-12 19:21:10 +01:00
2007-08-08 03:09:38 +02:00
if ( create_pbuffer ) {
HDC hdc_parent = GetDC ( win_handle ) ;
2007-08-09 14:12:42 +02:00
int iPixelFormat = 0 ;
IWineD3DSurface * StencilSurface = This - > stencilBufferTarget ;
WINED3DFORMAT StencilBufferFormat = ( NULL ! = StencilSurface ) ? ( ( IWineD3DSurfaceImpl * ) StencilSurface ) - > resource . format : 0 ;
2008-04-27 20:40:33 +02:00
/* Try to find a pixel format with pbuffer support. */
2008-04-28 23:44:21 +02:00
iPixelFormat = WineD3D_ChoosePixelFormat ( This , hdc_parent , target - > resource . format , StencilBufferFormat , FALSE /* auxBuffers */ , 0 /* numSamples */ , TRUE /* PBUFFER */ , FALSE /* findCompatible */ ) ;
2008-04-27 20:40:33 +02:00
if ( ! iPixelFormat ) {
TRACE ( " Trying to locate a compatible pixel format because an exact match failed. \n " ) ;
/* For some reason we weren't able to find a format, try to find something instead of crashing.
* A reason for failure could have been wglChoosePixelFormatARB strictness . */
2008-04-28 23:44:21 +02:00
iPixelFormat = WineD3D_ChoosePixelFormat ( This , hdc_parent , target - > resource . format , StencilBufferFormat , FALSE /* auxBuffer */ , 0 /* numSamples */ , TRUE /* PBUFFER */ , TRUE /* findCompatible */ ) ;
2008-04-27 20:40:33 +02:00
}
/* This shouldn't happen as ChoosePixelFormat always returns something */
if ( ! iPixelFormat ) {
ERR ( " Unable to locate a pixel format for a pbuffer \n " ) ;
ReleaseDC ( win_handle , hdc_parent ) ;
goto out ;
2007-08-09 14:12:42 +02:00
}
2007-02-12 19:21:10 +01:00
TRACE ( " Creating a pBuffer drawable for the new context \n " ) ;
2007-08-08 03:09:38 +02:00
pbuffer = GL_EXTCALL ( wglCreatePbufferARB ( hdc_parent , iPixelFormat , target - > currentDesc . Width , target - > currentDesc . Height , 0 ) ) ;
if ( ! pbuffer ) {
ERR ( " Cannot create a pbuffer \n " ) ;
ReleaseDC ( win_handle , hdc_parent ) ;
2007-08-06 20:53:20 +02:00
goto out ;
}
2007-08-08 03:09:38 +02:00
/* In WGL a pbuffer is 'wrapped' inside a HDC to 'fool' wglMakeCurrent */
hdc = GL_EXTCALL ( wglGetPbufferDCARB ( pbuffer ) ) ;
if ( ! hdc ) {
ERR ( " Cannot get a HDC for pbuffer (%p) \n " , pbuffer ) ;
GL_EXTCALL ( wglDestroyPbufferARB ( pbuffer ) ) ;
ReleaseDC ( win_handle , hdc_parent ) ;
2007-02-12 19:21:10 +01:00
goto out ;
}
2007-08-08 03:09:38 +02:00
ReleaseDC ( win_handle , hdc_parent ) ;
} else {
PIXELFORMATDESCRIPTOR pfd ;
int iPixelFormat ;
2007-08-11 17:04:26 +02:00
int res ;
2008-04-27 19:35:27 +02:00
WINED3DFORMAT ColorFormat = target - > resource . format ;
WINED3DFORMAT DepthStencilFormat = 0 ;
BOOL auxBuffers = FALSE ;
2008-04-28 23:44:21 +02:00
int numSamples = 0 ;
2007-02-12 19:21:10 +01:00
2007-08-08 03:09:38 +02:00
hdc = GetDC ( win_handle ) ;
if ( hdc = = NULL ) {
ERR ( " Cannot retrieve a device context! \n " ) ;
2007-02-12 19:21:10 +01:00
goto out ;
}
2007-08-08 03:09:38 +02:00
2008-02-23 00:27:38 +01:00
/* In case of ORM_BACKBUFFER, make sure to request an alpha component for X4R4G4B4/X8R8G8B8 as we might need it for the backbuffer. */
if ( wined3d_settings . offscreen_rendering_mode = = ORM_BACKBUFFER ) {
2008-04-27 19:35:27 +02:00
auxBuffers = TRUE ;
2008-02-23 00:27:38 +01:00
if ( target - > resource . format = = WINED3DFMT_X4R4G4B4 )
2008-04-27 19:35:27 +02:00
ColorFormat = WINED3DFMT_A4R4G4B4 ;
2008-02-23 00:27:38 +01:00
else if ( target - > resource . format = = WINED3DFMT_X8R8G8B8 )
2008-04-27 19:35:27 +02:00
ColorFormat = WINED3DFMT_A8R8G8B8 ;
2008-02-23 00:27:38 +01:00
}
2008-03-30 23:36:03 +02:00
/* DirectDraw supports 8bit paletted render targets and these are used by old games like Starcraft and C&C.
* Most modern hardware doesn ' t support 8 bit natively so we perform some form of 8 bit - > 32 bit conversion .
* The conversion ( ab ) uses the alpha component for storing the palette index . For this reason we require
* a format with 8 bit alpha , so request A8R8G8B8 . */
2008-04-27 19:35:27 +02:00
if ( ColorFormat = = WINED3DFMT_P8 )
ColorFormat = WINED3DFMT_A8R8G8B8 ;
2007-08-09 01:04:30 +02:00
2007-08-11 12:17:56 +02:00
/* Retrieve the depth stencil format from the present parameters.
* The choice of the proper format can give a nice performance boost
* in case of GPU limited programs . */
if ( pPresentParms - > EnableAutoDepthStencil ) {
TRACE ( " pPresentParms->EnableAutoDepthStencil=enabled; using AutoDepthStencilFormat=%s \n " , debug_d3dformat ( pPresentParms - > AutoDepthStencilFormat ) ) ;
2008-04-27 19:35:27 +02:00
DepthStencilFormat = pPresentParms - > AutoDepthStencilFormat ;
2007-08-09 01:04:30 +02:00
}
2008-04-28 23:44:21 +02:00
/* D3D only allows multisampling when SwapEffect is set to WINED3DSWAPEFFECT_DISCARD */
if ( pPresentParms - > MultiSampleType & & ( pPresentParms - > SwapEffect = = WINED3DSWAPEFFECT_DISCARD ) ) {
if ( ! GL_SUPPORT ( ARB_MULTISAMPLE ) )
ERR ( " The program is requesting multisampling without support! \n " ) ;
else {
ERR ( " Requesting MultiSampleType=%d \n " , pPresentParms - > MultiSampleType ) ;
numSamples = pPresentParms - > MultiSampleType ;
}
}
2008-04-27 19:35:27 +02:00
/* Try to find a pixel format which matches our requirements */
2008-04-28 23:44:21 +02:00
iPixelFormat = WineD3D_ChoosePixelFormat ( This , hdc , ColorFormat , DepthStencilFormat , auxBuffers , numSamples , FALSE /* PBUFFER */ , FALSE /* findCompatible */ ) ;
2007-08-25 00:18:54 +02:00
2008-04-27 19:35:27 +02:00
/* Try to locate a compatible format if we weren't able to find anything */
if ( ! iPixelFormat ) {
TRACE ( " Trying to locate a compatible pixel format because an exact match failed. \n " ) ;
2008-04-28 23:44:21 +02:00
iPixelFormat = WineD3D_ChoosePixelFormat ( This , hdc , ColorFormat , DepthStencilFormat , auxBuffers , 0 /* numSamples */ , FALSE /* PBUFFER */ , TRUE /* findCompatible */ ) ;
2008-04-27 19:35:27 +02:00
}
2007-08-25 00:18:54 +02:00
2008-04-27 19:35:27 +02:00
/* If we still don't have a pixel format, something is very wrong as ChoosePixelFormat barely fails */
if ( ! iPixelFormat ) {
ERR ( " Can't find a suitable iPixelFormat \n " ) ;
return FALSE ;
2007-02-12 19:22:41 +01:00
}
2007-08-08 03:09:38 +02:00
DescribePixelFormat ( hdc , iPixelFormat , sizeof ( pfd ) , & pfd ) ;
2007-08-11 17:04:26 +02:00
res = SetPixelFormat ( hdc , iPixelFormat , NULL ) ;
if ( ! res ) {
int oldPixelFormat = GetPixelFormat ( hdc ) ;
2008-04-23 00:15:15 +02:00
/* By default WGL doesn't allow pixel format adjustments but we need it here.
* For this reason there is a WINE - specific wglSetPixelFormat which allows you to
* set the pixel format multiple times . Only use it when it is really needed . */
if ( oldPixelFormat = = iPixelFormat ) {
/* We don't have to do anything as the formats are the same :) */
} else if ( oldPixelFormat & & GL_SUPPORT ( WGL_WINE_PIXEL_FORMAT_PASSTHROUGH ) ) {
res = GL_EXTCALL ( wglSetPixelFormatWINE ( hdc , iPixelFormat , NULL ) ) ;
if ( ! res ) {
ERR ( " wglSetPixelFormatWINE failed on HDC=%p for iPixelFormat=%d \n " , hdc , iPixelFormat ) ;
return FALSE ;
}
} else if ( oldPixelFormat ) {
2007-08-11 17:04:26 +02:00
/* 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 ( " HDC=%p is already set to iPixelFormat=%d and OpenGL doesn't allow changes! \n " , hdc , oldPixelFormat ) ;
2008-04-23 00:15:15 +02:00
} else {
2007-08-11 17:04:26 +02:00
ERR ( " SetPixelFormat failed on HDC=%p for iPixelFormat=%d \n " , hdc , iPixelFormat ) ;
return FALSE ;
}
}
2007-02-12 19:21:10 +01:00
}
2007-08-16 15:04:47 +02:00
ctx = pwglCreateContext ( hdc ) ;
if ( This - > numContexts ) pwglShareLists ( This - > contexts [ 0 ] - > glCtx , ctx ) ;
2007-08-08 03:09:38 +02:00
2007-02-12 19:21:10 +01:00
if ( ! ctx ) {
2007-08-08 03:09:38 +02:00
ERR ( " Failed to create a WGL context \n " ) ;
if ( create_pbuffer ) {
GL_EXTCALL ( wglReleasePbufferDCARB ( pbuffer , hdc ) ) ;
GL_EXTCALL ( wglDestroyPbufferARB ( pbuffer ) ) ;
}
2007-02-12 19:21:10 +01:00
goto out ;
}
2007-08-08 03:09:38 +02:00
ret = AddContextToArray ( This , win_handle , hdc , ctx , pbuffer ) ;
2007-02-12 19:21:10 +01:00
if ( ! ret ) {
ERR ( " Failed to add the newly created context to the context list \n " ) ;
2007-08-16 15:04:47 +02:00
pwglDeleteContext ( ctx ) ;
2007-08-08 03:09:38 +02:00
if ( create_pbuffer ) {
GL_EXTCALL ( wglReleasePbufferDCARB ( pbuffer , hdc ) ) ;
GL_EXTCALL ( wglDestroyPbufferARB ( pbuffer ) ) ;
}
2007-02-12 19:21:10 +01:00
goto out ;
}
ret - > surface = ( IWineD3DSurface * ) target ;
2007-08-08 03:09:38 +02:00
ret - > isPBuffer = create_pbuffer ;
2007-06-02 22:20:17 +02:00
ret - > tid = GetCurrentThreadId ( ) ;
2008-03-04 02:30:23 +01:00
if ( This - > shader_backend - > shader_dirtifyable_constants ( ( IWineD3DDevice * ) This ) ) {
/* Create the dirty constants array and initialize them to dirty */
ret - > vshader_const_dirty = HeapAlloc ( GetProcessHeap ( ) , 0 ,
sizeof ( * ret - > vshader_const_dirty ) * GL_LIMITS ( vshader_constantsF ) ) ;
ret - > pshader_const_dirty = HeapAlloc ( GetProcessHeap ( ) , 0 ,
sizeof ( * ret - > pshader_const_dirty ) * GL_LIMITS ( pshader_constantsF ) ) ;
memset ( ret - > vshader_const_dirty , 1 ,
sizeof ( * ret - > vshader_const_dirty ) * GL_LIMITS ( vshader_constantsF ) ) ;
memset ( ret - > pshader_const_dirty , 1 ,
sizeof ( * ret - > pshader_const_dirty ) * GL_LIMITS ( pshader_constantsF ) ) ;
}
2007-02-12 19:21:10 +01:00
TRACE ( " Successfully created new context %p \n " , ret ) ;
/* Set up the context defaults */
2007-08-16 15:04:47 +02:00
oldCtx = pwglGetCurrentContext ( ) ;
oldDrawable = pwglGetCurrentDC ( ) ;
2008-04-11 08:19:04 +02:00
if ( oldCtx & & oldDrawable ) {
2008-03-30 14:52:18 +02:00
/* See comment in ActivateContext context switching */
2008-04-11 08:19:04 +02:00
This - > shader_backend - > shader_fragment_enable ( ( IWineD3DDevice * ) This , FALSE ) ;
2008-03-30 14:52:18 +02:00
}
2007-08-16 15:04:47 +02:00
if ( pwglMakeCurrent ( hdc , ctx ) = = FALSE ) {
2007-02-12 19:21:10 +01:00
ERR ( " Cannot activate context to set up defaults \n " ) ;
goto out ;
}
2007-09-29 16:58:44 +02:00
ENTER_GL ( ) ;
2008-04-08 14:20:27 +02:00
glGetIntegerv ( GL_AUX_BUFFERS , & ret - > aux_buffers ) ;
2007-02-12 19:21:10 +01:00
TRACE ( " Setting up the screen \n " ) ;
/* Clear the screen */
glClearColor ( 1.0 , 0.0 , 0.0 , 0.0 ) ;
checkGLcall ( " glClearColor " ) ;
glClearIndex ( 0 ) ;
glClearDepth ( 1 ) ;
glClearStencil ( 0xffff ) ;
checkGLcall ( " glClear " ) ;
glColor3f ( 1.0 , 1.0 , 1.0 ) ;
checkGLcall ( " glColor3f " ) ;
glEnable ( GL_LIGHTING ) ;
checkGLcall ( " glEnable " ) ;
glLightModeli ( GL_LIGHT_MODEL_LOCAL_VIEWER , GL_TRUE ) ;
checkGLcall ( " glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); " ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_COMBINE_EXT ) ;
checkGLcall ( " glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); " ) ;
glLightModeli ( GL_LIGHT_MODEL_COLOR_CONTROL , GL_SEPARATE_SPECULAR_COLOR ) ;
checkGLcall ( " glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); " ) ;
2007-06-08 22:28:04 +02:00
glPixelStorei ( GL_PACK_ALIGNMENT , This - > surface_alignment ) ;
checkGLcall ( " glPixelStorei(GL_PACK_ALIGNMENT, This->surface_alignment); " ) ;
glPixelStorei ( GL_UNPACK_ALIGNMENT , This - > surface_alignment ) ;
checkGLcall ( " glPixelStorei(GL_UNPACK_ALIGNMENT, This->surface_alignment); " ) ;
2007-02-12 19:21:10 +01:00
2007-03-31 23:02:37 +02:00
if ( GL_SUPPORT ( APPLE_CLIENT_STORAGE ) ) {
/* Most textures will use client storage if supported. Exceptions are non-native power of 2 textures
* and textures in DIB sections ( due to the memory protection ) .
*/
glPixelStorei ( GL_UNPACK_CLIENT_STORAGE_APPLE , GL_TRUE ) ;
checkGLcall ( " glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE) " ) ;
}
2007-04-27 00:43:15 +02:00
if ( GL_SUPPORT ( ARB_VERTEX_BLEND ) ) {
/* 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 too
*/
glEnable ( GL_WEIGHT_SUM_UNITY_ARB ) ;
checkGLcall ( " glEnable(GL_WEIGHT_SUM_UNITY_ARB) " ) ;
}
2007-05-07 21:08:14 +02:00
if ( GL_SUPPORT ( NV_TEXTURE_SHADER2 ) ) {
glEnable ( GL_TEXTURE_SHADER_NV ) ;
checkGLcall ( " glEnable(GL_TEXTURE_SHADER_NV) " ) ;
/* 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.
*/
for ( s = 1 ; s < GL_LIMITS ( textures ) ; s + + ) {
GL_EXTCALL ( glActiveTextureARB ( GL_TEXTURE0_ARB + s ) ) ;
glTexEnvi ( GL_TEXTURE_SHADER_NV , GL_PREVIOUS_TEXTURE_INPUT_NV , GL_TEXTURE0_ARB + s - 1 ) ;
checkGLcall ( " glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ... \n " ) ;
}
}
2008-03-22 14:31:52 +01:00
2007-06-17 00:26:17 +02:00
if ( GL_SUPPORT ( ARB_POINT_SPRITE ) ) {
for ( s = 0 ; s < GL_LIMITS ( textures ) ; s + + ) {
GL_EXTCALL ( glActiveTextureARB ( GL_TEXTURE0_ARB + s ) ) ;
glTexEnvi ( GL_POINT_SPRITE_ARB , GL_COORD_REPLACE_ARB , GL_TRUE ) ;
checkGLcall ( " glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE) \n " ) ;
}
}
2007-09-29 16:58:44 +02:00
LEAVE_GL ( ) ;
2007-03-31 23:02:37 +02:00
2008-03-30 14:52:18 +02:00
/* Never keep GL_FRAGMENT_SHADER_ATI enabled on a context that we switch away from,
* but enable it for the first context we create , and reenable it on the old context
*/
2007-02-12 19:22:41 +01:00
if ( oldDrawable & & oldCtx ) {
2007-08-16 15:04:47 +02:00
pwglMakeCurrent ( oldDrawable , oldCtx ) ;
2007-02-12 19:22:41 +01:00
}
2008-04-11 08:19:04 +02:00
This - > shader_backend - > shader_fragment_enable ( ( IWineD3DDevice * ) This , TRUE ) ;
2007-02-12 19:21:10 +01:00
out :
return ret ;
}
2007-02-12 19:22:41 +01:00
/*****************************************************************************
* RemoveContextFromArray
*
* Removes a context from the context manager . The opengl context is not
* destroyed or unset . context is not a valid pointer after that call .
*
2007-02-20 15:57:10 +01:00
* Similar to the former call this isn ' t a performance critical function . A
2007-02-12 19:22:41 +01:00
* helper function for DestroyContext .
*
* Params :
* This : Device to activate the context for
* context : Context to remove
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void RemoveContextFromArray ( IWineD3DDeviceImpl * This , WineD3DContext * context ) {
UINT t , s ;
WineD3DContext * * oldArray = This - > contexts ;
TRACE ( " Removing ctx %p \n " , context ) ;
This - > numContexts - - ;
if ( This - > numContexts ) {
This - > contexts = HeapAlloc ( GetProcessHeap ( ) , 0 , sizeof ( * This - > contexts ) * This - > numContexts ) ;
if ( ! This - > contexts ) {
ERR ( " Cannot allocate a new context array, PANIC!!! \n " ) ;
}
t = 0 ;
2008-05-03 22:15:58 +02:00
/* Note that we decreased numContexts a few lines up, so use '<=' instead of '<' */
for ( s = 0 ; s < = This - > numContexts ; s + + ) {
2007-02-12 19:22:41 +01:00
if ( oldArray [ s ] = = context ) continue ;
This - > contexts [ t ] = oldArray [ s ] ;
t + + ;
}
} else {
This - > contexts = NULL ;
}
HeapFree ( GetProcessHeap ( ) , 0 , context ) ;
HeapFree ( GetProcessHeap ( ) , 0 , oldArray ) ;
}
2007-02-12 19:21:10 +01:00
/*****************************************************************************
* DestroyContext
*
* Destroys a wineD3DContext
*
* Params :
* This : Device to activate the context for
* context : Context to destroy
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DestroyContext ( IWineD3DDeviceImpl * This , WineD3DContext * context ) {
2007-02-12 19:22:41 +01:00
/* check that we are the current context first */
TRACE ( " Destroying ctx %p \n " , context ) ;
2007-08-16 15:04:47 +02:00
if ( pwglGetCurrentContext ( ) = = context - > glCtx ) {
pwglMakeCurrent ( NULL , NULL ) ;
2007-02-12 19:22:41 +01:00
}
if ( context - > isPBuffer ) {
2007-08-08 03:09:38 +02:00
GL_EXTCALL ( wglReleasePbufferDCARB ( context - > pbuffer , context - > hdc ) ) ;
GL_EXTCALL ( wglDestroyPbufferARB ( context - > pbuffer ) ) ;
} else ReleaseDC ( context - > win_handle , context - > hdc ) ;
2007-08-16 15:04:47 +02:00
pwglDeleteContext ( context - > glCtx ) ;
2007-08-08 03:09:38 +02:00
2008-03-04 02:30:23 +01:00
HeapFree ( GetProcessHeap ( ) , 0 , context - > vshader_const_dirty ) ;
HeapFree ( GetProcessHeap ( ) , 0 , context - > pshader_const_dirty ) ;
2007-02-12 19:22:41 +01:00
RemoveContextFromArray ( This , context ) ;
2007-02-12 19:21:10 +01:00
}
2008-06-17 01:41:49 +02:00
static inline void set_blit_dimension ( UINT width , UINT height ) {
glMatrixMode ( GL_PROJECTION ) ;
checkGLcall ( " glMatrixMode(GL_PROJECTION) " ) ;
glLoadIdentity ( ) ;
checkGLcall ( " glLoadIdentity() " ) ;
glOrtho ( 0 , width , height , 0 , 0.0 , - 1.0 ) ;
checkGLcall ( " glOrtho " ) ;
glViewport ( 0 , 0 , width , height ) ;
checkGLcall ( " glViewport " ) ;
}
2007-02-12 19:18:41 +01:00
/*****************************************************************************
* SetupForBlit
*
* Sets up a context for DirectDraw blitting .
2007-11-26 21:43:08 +01:00
* All texture units are disabled , texture unit 0 is set as current unit
2008-01-09 20:37:05 +01:00
* fog , lighting , blending , alpha test , z test , scissor test , culling disabled
2007-02-12 19:18:41 +01:00
* color writing enabled for all channels
* register combiners disabled , shaders disabled
2008-01-09 20:37:05 +01:00
* world matrix is set to identity , texture matrix 0 too
2007-02-12 19:18:41 +01:00
* projection matrix is setup for drawing screen coordinates
*
* Params :
* This : Device to activate the context for
* context : Context to setup
* width : render target width
* height : render target height
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static inline void SetupForBlit ( IWineD3DDeviceImpl * This , WineD3DContext * context , UINT width , UINT height ) {
int i ;
2008-07-02 01:23:44 +02:00
const struct StateEntry * StateTable = This - > StateTable ;
2007-02-12 19:18:41 +01:00
TRACE ( " Setting up context %p for blitting \n " , context ) ;
if ( context - > last_was_blit ) {
2008-06-17 01:41:49 +02:00
if ( context - > blit_w ! = width | | context - > blit_h ! = height ) {
set_blit_dimension ( width , height ) ;
context - > blit_w = width ; context - > blit_h = height ;
/* No need to dirtify here, the states are still dirtified because they weren't
* applied since the last SetupForBlit call . Otherwise last_was_blit would not
* be set
*/
}
2007-02-12 19:18:41 +01:00
TRACE ( " Context is already set up for blitting, nothing to do \n " ) ;
return ;
}
context - > last_was_blit = TRUE ;
2007-02-12 19:21:10 +01:00
/* TODO: Use a display list */
2007-02-12 19:18:41 +01:00
/* Disable shaders */
This - > shader_backend - > shader_cleanup ( ( IWineD3DDevice * ) This ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_VSHADER , StateTable ) ;
Context_MarkStateDirty ( context , STATE_PIXELSHADER , StateTable ) ;
2007-02-12 19:18:41 +01:00
/* Disable all textures. The caller can then bind a texture it wants to blit
* from
*/
if ( GL_SUPPORT ( NV_REGISTER_COMBINERS ) ) {
glDisable ( GL_REGISTER_COMBINERS_NV ) ;
checkGLcall ( " glDisable(GL_REGISTER_COMBINERS_NV) " ) ;
}
if ( GL_SUPPORT ( ARB_MULTITEXTURE ) ) {
2007-03-01 01:21:47 +01:00
/* 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
*/
for ( i = GL_LIMITS ( textures ) - 1 ; i > 0 ; i - - ) {
GL_EXTCALL ( glActiveTextureARB ( GL_TEXTURE0_ARB + i ) ) ;
checkGLcall ( " glActiveTextureARB " ) ;
2007-03-28 19:17:51 +02:00
if ( GL_SUPPORT ( ARB_TEXTURE_CUBE_MAP ) ) {
glDisable ( GL_TEXTURE_CUBE_MAP_ARB ) ;
checkGLcall ( " glDisable GL_TEXTURE_CUBE_MAP_ARB " ) ;
}
2007-02-12 19:18:41 +01:00
glDisable ( GL_TEXTURE_3D ) ;
checkGLcall ( " glDisable GL_TEXTURE_3D " ) ;
glDisable ( GL_TEXTURE_2D ) ;
checkGLcall ( " glDisable GL_TEXTURE_2D " ) ;
2007-03-01 01:21:47 +01:00
glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_REPLACE ) ;
checkGLcall ( " glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_TEXTURESTAGE ( i , WINED3DTSS_COLOROP ) , StateTable ) ;
Context_MarkStateDirty ( context , STATE_SAMPLER ( i ) , StateTable ) ;
2007-02-12 19:18:41 +01:00
}
GL_EXTCALL ( glActiveTextureARB ( GL_TEXTURE0_ARB ) ) ;
checkGLcall ( " glActiveTextureARB " ) ;
}
2007-03-28 19:17:51 +02:00
if ( GL_SUPPORT ( ARB_TEXTURE_CUBE_MAP ) ) {
glDisable ( GL_TEXTURE_CUBE_MAP_ARB ) ;
checkGLcall ( " glDisable GL_TEXTURE_CUBE_MAP_ARB " ) ;
}
2007-02-12 19:18:41 +01:00
glDisable ( GL_TEXTURE_3D ) ;
checkGLcall ( " glDisable GL_TEXTURE_3D " ) ;
2007-11-26 21:43:08 +01:00
glDisable ( GL_TEXTURE_2D ) ;
checkGLcall ( " glDisable GL_TEXTURE_2D " ) ;
2007-02-12 19:18:41 +01:00
glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_REPLACE ) ;
glMatrixMode ( GL_TEXTURE ) ;
checkGLcall ( " glMatrixMode(GL_TEXTURE) " ) ;
glLoadIdentity ( ) ;
checkGLcall ( " glLoadIdentity() " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_TRANSFORM ( WINED3DTS_TEXTURE0 ) , StateTable ) ;
2007-02-12 19:18:41 +01:00
if ( GL_SUPPORT ( EXT_TEXTURE_LOD_BIAS ) ) {
glTexEnvf ( GL_TEXTURE_FILTER_CONTROL_EXT ,
GL_TEXTURE_LOD_BIAS_EXT ,
0.0 ) ;
checkGLcall ( " glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ... " ) ;
}
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_SAMPLER ( 0 ) , StateTable ) ;
Context_MarkStateDirty ( context , STATE_TEXTURESTAGE ( 0 , WINED3DTSS_COLOROP ) , StateTable ) ;
2007-02-12 19:18:41 +01:00
/* Other misc states */
glDisable ( GL_ALPHA_TEST ) ;
checkGLcall ( " glDisable(GL_ALPHA_TEST) " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_ALPHATESTENABLE ) , StateTable ) ;
2007-02-12 19:18:41 +01:00
glDisable ( GL_LIGHTING ) ;
checkGLcall ( " glDisable GL_LIGHTING " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_LIGHTING ) , StateTable ) ;
2007-02-12 19:18:41 +01:00
glDisable ( GL_DEPTH_TEST ) ;
checkGLcall ( " glDisable GL_DEPTH_TEST " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_ZENABLE ) , StateTable ) ;
2007-02-12 19:18:41 +01:00
glDisable ( GL_FOG ) ;
checkGLcall ( " glDisable GL_FOG " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_FOGENABLE ) , StateTable ) ;
2007-02-12 19:18:41 +01:00
glDisable ( GL_BLEND ) ;
checkGLcall ( " glDisable GL_BLEND " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_ALPHABLENDENABLE ) , StateTable ) ;
2007-02-12 19:18:41 +01:00
glDisable ( GL_CULL_FACE ) ;
checkGLcall ( " glDisable GL_CULL_FACE " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_CULLMODE ) , StateTable ) ;
2007-02-12 19:18:41 +01:00
glDisable ( GL_STENCIL_TEST ) ;
checkGLcall ( " glDisable GL_STENCIL_TEST " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_STENCILENABLE ) , StateTable ) ;
2007-12-01 01:10:37 +01:00
glDisable ( GL_SCISSOR_TEST ) ;
checkGLcall ( " glDisable GL_SCISSOR_TEST " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_SCISSORTESTENABLE ) , StateTable ) ;
2007-02-12 19:18:41 +01:00
if ( GL_SUPPORT ( ARB_POINT_SPRITE ) ) {
glDisable ( GL_POINT_SPRITE_ARB ) ;
checkGLcall ( " glDisable GL_POINT_SPRITE_ARB " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_POINTSPRITEENABLE ) , StateTable ) ;
2007-02-12 19:18:41 +01:00
}
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
checkGLcall ( " glColorMask " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_CLIPPING ) , StateTable ) ;
2007-08-14 16:32:35 +02:00
if ( GL_SUPPORT ( EXT_SECONDARY_COLOR ) ) {
glDisable ( GL_COLOR_SUM_EXT ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_SPECULARENABLE ) , StateTable ) ;
2007-08-14 16:32:35 +02:00
checkGLcall ( " glDisable(GL_COLOR_SUM_EXT) " ) ;
}
if ( GL_SUPPORT ( NV_REGISTER_COMBINERS ) ) {
GL_EXTCALL ( glFinalCombinerInputNV ( GL_VARIABLE_B_NV , GL_SPARE0_NV , GL_UNSIGNED_IDENTITY_NV , GL_RGB ) ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_SPECULARENABLE ) , StateTable ) ;
2007-08-14 16:32:35 +02:00
checkGLcall ( " glFinalCombinerInputNV " ) ;
}
2007-02-12 19:18:41 +01:00
/* Setup transforms */
glMatrixMode ( GL_MODELVIEW ) ;
checkGLcall ( " glMatrixMode(GL_MODELVIEW) " ) ;
glLoadIdentity ( ) ;
checkGLcall ( " glLoadIdentity() " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_TRANSFORM ( WINED3DTS_WORLDMATRIX ( 0 ) ) , StateTable ) ;
2007-02-12 19:18:41 +01:00
context - > last_was_rhw = TRUE ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_VDECL , StateTable ) ; /* because of last_was_rhw = TRUE */
2007-02-12 19:18:41 +01:00
glDisable ( GL_CLIP_PLANE0 ) ; checkGLcall ( " glDisable(clip plane 0) " ) ;
glDisable ( GL_CLIP_PLANE1 ) ; checkGLcall ( " glDisable(clip plane 1) " ) ;
glDisable ( GL_CLIP_PLANE2 ) ; checkGLcall ( " glDisable(clip plane 2) " ) ;
glDisable ( GL_CLIP_PLANE3 ) ; checkGLcall ( " glDisable(clip plane 3) " ) ;
glDisable ( GL_CLIP_PLANE4 ) ; checkGLcall ( " glDisable(clip plane 4) " ) ;
glDisable ( GL_CLIP_PLANE5 ) ; checkGLcall ( " glDisable(clip plane 5) " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_CLIPPING ) , StateTable ) ;
2007-02-12 19:18:41 +01:00
2008-06-17 01:41:49 +02:00
set_blit_dimension ( width , height ) ;
context - > blit_w = width ; context - > blit_h = height ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_VIEWPORT , StateTable ) ;
2008-06-17 01:41:49 +02:00
Context_MarkStateDirty ( context , STATE_TRANSFORM ( WINED3DTS_PROJECTION ) , StateTable ) ;
2007-05-07 21:08:14 +02:00
2008-04-11 08:19:04 +02:00
This - > shader_backend - > shader_fragment_enable ( ( IWineD3DDevice * ) This , FALSE ) ;
2007-02-12 19:18:41 +01:00
}
2007-07-04 16:47:22 +02:00
/*****************************************************************************
* findThreadContextForSwapChain
*
* Searches a swapchain for all contexts and picks one for the thread tid .
* If none can be found the swapchain is requested to create a new context
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static WineD3DContext * findThreadContextForSwapChain ( IWineD3DSwapChain * swapchain , DWORD tid ) {
int i ;
for ( i = 0 ; i < ( ( IWineD3DSwapChainImpl * ) swapchain ) - > num_contexts ; i + + ) {
if ( ( ( IWineD3DSwapChainImpl * ) swapchain ) - > context [ i ] - > tid = = tid ) {
return ( ( IWineD3DSwapChainImpl * ) swapchain ) - > context [ i ] ;
}
}
/* Create a new context for the thread */
return IWineD3DSwapChainImpl_CreateContextForThread ( swapchain ) ;
}
2007-02-12 19:18:36 +01:00
/*****************************************************************************
2007-07-09 00:48:53 +02:00
* FindContext
2007-02-12 19:18:36 +01:00
*
2007-07-09 00:48:53 +02:00
* Finds a context for the current render target and thread
2007-02-12 19:18:36 +01:00
*
2007-07-09 00:48:53 +02:00
* Parameters :
* target : Render target to find the context for
* tid : Thread to activate the context for
*
* Returns : The needed context
2007-02-12 19:18:36 +01:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-06 01:11:35 +01:00
static inline WineD3DContext * FindContext ( IWineD3DDeviceImpl * This , IWineD3DSurface * target , DWORD tid , GLint * buffer ) {
2007-07-09 00:48:53 +02:00
IWineD3DSwapChain * swapchain = NULL ;
HRESULT hr ;
BOOL readTexture = wined3d_settings . offscreen_rendering_mode ! = ORM_FBO & & This - > render_offscreen ;
WineD3DContext * context = This - > activeContext ;
BOOL oldRenderOffscreen = This - > render_offscreen ;
2007-12-06 22:33:26 +01:00
const WINED3DFORMAT oldFmt = ( ( IWineD3DSurfaceImpl * ) This - > lastActiveRenderTarget ) - > resource . format ;
const WINED3DFORMAT newFmt = ( ( IWineD3DSurfaceImpl * ) target ) - > resource . format ;
2008-07-02 01:23:44 +02:00
const struct StateEntry * StateTable = This - > StateTable ;
2007-12-06 22:33:26 +01:00
/* 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 ( oldFmt ! = newFmt ) {
2008-03-28 10:02:39 +01:00
const GlPixelFormatDesc * glDesc ;
2007-12-06 22:33:26 +01:00
const StaticPixelFormatDesc * old = getFormatDescEntry ( oldFmt , NULL , NULL ) ;
2008-03-28 10:02:39 +01:00
const StaticPixelFormatDesc * new = getFormatDescEntry ( newFmt , & GLINFO_LOCATION , & glDesc ) ;
2007-12-06 22:33:26 +01:00
2008-03-28 10:02:39 +01:00
/* Disable blending when the alphaMask has changed and when a format doesn't support blending */
if ( ( old - > alphaMask & & ! new - > alphaMask ) | | ( ! old - > alphaMask & & new - > alphaMask ) | | ! ( glDesc - > Flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING ) ) {
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_ALPHABLENDENABLE ) , StateTable ) ;
2007-12-06 22:33:26 +01:00
}
}
2007-07-09 00:48:53 +02:00
hr = IWineD3DSurface_GetContainer ( target , & IID_IWineD3DSwapChain , ( void * * ) & swapchain ) ;
if ( hr = = WINED3D_OK & & swapchain ) {
TRACE ( " Rendering onscreen \n " ) ;
context = findThreadContextForSwapChain ( swapchain , tid ) ;
This - > render_offscreen = FALSE ;
/* The context != This->activeContext will catch a NOP context change. This can occur
* if we are switching back to swapchain rendering in case of FBO or Back Buffer offscreen
* rendering . No context change is needed in that case
*/
2007-02-12 19:18:36 +01:00
2007-11-06 01:11:35 +01:00
if ( ( ( IWineD3DSwapChainImpl * ) swapchain ) - > frontBuffer = = target ) {
* buffer = GL_FRONT ;
} else {
* buffer = GL_BACK ;
}
if ( wined3d_settings . offscreen_rendering_mode = = ORM_PBUFFER ) {
2007-07-09 00:48:53 +02:00
if ( This - > pbufferContext & & tid = = This - > pbufferContext - > tid ) {
This - > pbufferContext - > tid = 0 ;
}
}
IWineD3DSwapChain_Release ( swapchain ) ;
2007-02-12 19:21:10 +01:00
2007-07-09 00:48:53 +02:00
if ( oldRenderOffscreen ) {
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , WINED3DTS_PROJECTION , StateTable ) ;
Context_MarkStateDirty ( context , STATE_VDECL , StateTable ) ;
Context_MarkStateDirty ( context , STATE_VIEWPORT , StateTable ) ;
Context_MarkStateDirty ( context , STATE_SCISSORRECT , StateTable ) ;
Context_MarkStateDirty ( context , STATE_FRONTFACE , StateTable ) ;
2007-07-09 00:48:53 +02:00
}
2007-06-02 22:20:17 +02:00
2007-07-09 00:48:53 +02:00
} else {
TRACE ( " Rendering offscreen \n " ) ;
This - > render_offscreen = TRUE ;
2007-11-06 01:11:35 +01:00
* buffer = This - > offscreenBuffer ;
2007-07-09 00:48:53 +02:00
switch ( wined3d_settings . offscreen_rendering_mode ) {
case ORM_FBO :
/* FBOs do not need a different context. Stay with whatever context is active at the moment */
if ( This - > activeContext & & tid = = This - > lastThread ) {
context = This - > activeContext ;
} else {
2008-01-09 20:37:05 +01:00
/* This may happen if the app jumps straight into offscreen rendering
2007-07-09 00:48:53 +02:00
* Start using the context of the primary swapchain . tid = = 0 is no problem
* for findThreadContextForSwapChain .
*
* Can also happen on thread switches - in that case findThreadContextForSwapChain
* is perfect to call .
*/
context = findThreadContextForSwapChain ( This - > swapchains [ 0 ] , tid ) ;
}
break ;
case ORM_PBUFFER :
{
IWineD3DSurfaceImpl * targetimpl = ( IWineD3DSurfaceImpl * ) target ;
if ( This - > pbufferContext = = NULL | |
This - > pbufferWidth < targetimpl - > currentDesc . Width | |
This - > pbufferHeight < targetimpl - > currentDesc . Height ) {
if ( This - > pbufferContext ) {
DestroyContext ( This , This - > pbufferContext ) ;
}
2007-06-02 22:20:17 +02:00
2007-07-09 00:48:53 +02:00
/* The display is irrelevant here, the window is 0. But CreateContext needs a valid X connection.
* Create the context on the same server as the primary swapchain . The primary swapchain is exists at this point .
*/
This - > pbufferContext = CreateContext ( This , targetimpl ,
2007-08-08 03:09:38 +02:00
( ( IWineD3DSwapChainImpl * ) This - > swapchains [ 0 ] ) - > context [ 0 ] - > win_handle ,
2007-08-11 12:17:56 +02:00
TRUE /* pbuffer */ , & ( ( IWineD3DSwapChainImpl * ) This - > swapchains [ 0 ] ) - > presentParms ) ;
2007-07-09 00:48:53 +02:00
This - > pbufferWidth = targetimpl - > currentDesc . Width ;
This - > pbufferHeight = targetimpl - > currentDesc . Height ;
}
if ( This - > pbufferContext ) {
if ( This - > pbufferContext - > tid ! = 0 & & This - > pbufferContext - > tid ! = tid ) {
FIXME ( " The PBuffr context is only supported for one thread for now! \n " ) ;
}
This - > pbufferContext - > tid = tid ;
context = This - > pbufferContext ;
break ;
} else {
ERR ( " Failed to create a buffer context and drawable, falling back to back buffer offscreen rendering \n " ) ;
wined3d_settings . offscreen_rendering_mode = ORM_BACKBUFFER ;
}
}
2007-02-12 19:21:10 +01:00
2007-07-09 00:48:53 +02:00
case ORM_BACKBUFFER :
/* Stay with the currently active context for back buffer rendering */
if ( This - > activeContext & & tid = = This - > lastThread ) {
context = This - > activeContext ;
2007-02-27 21:32:15 +01:00
} else {
2008-01-23 15:16:30 +01:00
/* This may happen if the app jumps straight into offscreen rendering
2007-07-09 00:48:53 +02:00
* Start using the context of the primary swapchain . tid = = 0 is no problem
* for findThreadContextForSwapChain .
*
* Can also happen on thread switches - in that case findThreadContextForSwapChain
* is perfect to call .
*/
context = findThreadContextForSwapChain ( This - > swapchains [ 0 ] , tid ) ;
2007-07-04 16:47:22 +02:00
}
2007-07-09 00:48:53 +02:00
break ;
}
2007-02-12 19:21:10 +01:00
2007-07-09 00:48:53 +02:00
if ( ! oldRenderOffscreen ) {
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , WINED3DTS_PROJECTION , StateTable ) ;
Context_MarkStateDirty ( context , STATE_VDECL , StateTable ) ;
Context_MarkStateDirty ( context , STATE_VIEWPORT , StateTable ) ;
Context_MarkStateDirty ( context , STATE_SCISSORRECT , StateTable ) ;
Context_MarkStateDirty ( context , STATE_FRONTFACE , StateTable ) ;
2007-07-09 00:48:53 +02:00
}
}
2008-06-12 21:18:46 +02:00
/* 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 . This leads to these possible situations :
*
* 0 ) lastActiveRenderTarget = = target & & oldTid = = newTid :
* Nothing to do , we don ' t even reach this code in this case . . .
*
* 1 ) lastActiveRenderTarget ! = target & & oldTid = = newTid :
* The currently active context is OK for readback . Call PreLoad , and it
* performs the read
*
* 2 ) lastActiveRenderTarget = = target & & oldTid ! = newTid :
* Nothing to do - the drawable is unchanged
*
* 3 ) lastActiveRenderTarget ! = target & & oldTid ! = newTid :
* This is tricky . We have to get a context with the old drawable from somewhere
* before we can switch to the new context . In this case , PreLoad calls
* ActivateContext ( lastActiveRenderTarget ) from the new ( current ) thread . This
* is case ( 2 ) then . The old drawable is activated for the new thread , and the
* readback can be done . The recursed ActivateContext does * not * call PreLoad again .
* After that , the outer ActivateContext ( which calls PreLoad ) can activate the new
* target for the new thread
*/
if ( readTexture & & This - > lastActiveRenderTarget ! = target ) {
2007-07-09 00:48:53 +02:00
BOOL oldInDraw = This - > isInDraw ;
2007-02-12 19:21:10 +01:00
2007-07-09 00:48:53 +02:00
/* PreLoad requires a context to load the texture, thus it will call ActivateContext.
* Set the isInDraw to true to signal PreLoad that it has a context . Will be tricky
* when using offscreen rendering with multithreading
*/
This - > isInDraw = TRUE ;
2007-02-12 19:21:10 +01:00
2007-07-09 00:48:53 +02:00
/* Do that before switching the context:
* Read the back buffer of the old drawable into the destination texture
*/
IWineD3DSurface_PreLoad ( This - > lastActiveRenderTarget ) ;
2007-02-12 19:21:10 +01:00
2007-07-09 00:48:53 +02:00
/* Assume that the drawable will be modified by some other things now */
2007-10-09 22:17:59 +02:00
IWineD3DSurface_ModifyLocation ( This - > lastActiveRenderTarget , SFLAG_INDRAWABLE , FALSE ) ;
2007-04-08 02:46:40 +02:00
2007-07-09 00:48:53 +02:00
This - > isInDraw = oldInDraw ;
}
2007-03-17 23:00:39 +01:00
2007-07-09 00:48:53 +02:00
return context ;
}
2007-03-17 23:00:39 +01:00
2007-07-09 00:48:53 +02:00
/*****************************************************************************
* ActivateContext
*
* Finds a rendering context and drawable matching the device and render
* target for the current thread , activates them and puts them into the
* requested state .
*
* Params :
* This : Device to activate the context for
* target : Requested render target
* usage : Prepares the context for blitting , drawing or other actions
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void ActivateContext ( IWineD3DDeviceImpl * This , IWineD3DSurface * target , ContextUsage usage ) {
DWORD tid = GetCurrentThreadId ( ) ;
int i ;
DWORD dirtyState , idx ;
BYTE shift ;
WineD3DContext * context ;
2007-11-06 01:11:35 +01:00
GLint drawBuffer = 0 ;
2008-07-02 01:23:44 +02:00
const struct StateEntry * StateTable = This - > StateTable ;
2007-03-10 00:55:08 +01:00
2007-07-09 00:48:53 +02:00
TRACE ( " (%p): Selecting context for render target %p, thread %d \n " , This , target , tid ) ;
if ( This - > lastActiveRenderTarget ! = target | | tid ! = This - > lastThread ) {
2007-11-06 01:11:35 +01:00
context = FindContext ( This , target , tid , & drawBuffer ) ;
2007-02-12 19:21:10 +01:00
This - > lastActiveRenderTarget = target ;
2007-07-09 17:27:39 +02:00
This - > lastThread = tid ;
2007-02-12 19:21:10 +01:00
} else {
/* Stick to the old context */
context = This - > activeContext ;
}
/* Activate the opengl context */
if ( context ! = This - > activeContext ) {
2007-08-08 03:09:38 +02:00
BOOL ret ;
2007-11-09 16:38:50 +01:00
/* Prevent an unneeded context switch as those are expensive */
if ( context - > glCtx & & ( context - > glCtx = = pwglGetCurrentContext ( ) ) ) {
TRACE ( " Already using gl context %p \n " , context - > glCtx ) ;
}
else {
TRACE ( " Switching gl ctx to %p, hdc=%p ctx=%p \n " , context , context - > hdc , context - > glCtx ) ;
2008-03-30 14:52:18 +02:00
2008-04-11 08:19:04 +02:00
This - > shader_backend - > shader_fragment_enable ( ( IWineD3DDevice * ) This , FALSE ) ;
2007-11-09 16:38:50 +01:00
ret = pwglMakeCurrent ( context - > hdc , context - > glCtx ) ;
if ( ret = = FALSE ) {
ERR ( " Failed to activate the new context \n " ) ;
2008-04-11 08:19:04 +02:00
} else if ( ! context - > last_was_blit ) {
This - > shader_backend - > shader_fragment_enable ( ( IWineD3DDevice * ) This , TRUE ) ;
2007-11-09 16:38:50 +01:00
}
2007-02-12 19:21:10 +01:00
}
2008-03-04 02:30:23 +01:00
if ( This - > activeContext - > vshader_const_dirty ) {
memset ( This - > activeContext - > vshader_const_dirty , 1 ,
2008-03-05 02:40:16 +01:00
sizeof ( * This - > activeContext - > vshader_const_dirty ) * GL_LIMITS ( vshader_constantsF ) ) ;
2008-03-04 02:30:23 +01:00
}
if ( This - > activeContext - > pshader_const_dirty ) {
memset ( This - > activeContext - > pshader_const_dirty , 1 ,
2008-03-05 02:40:16 +01:00
sizeof ( * This - > activeContext - > pshader_const_dirty ) * GL_LIMITS ( pshader_constantsF ) ) ;
2008-03-04 02:30:23 +01:00
}
2007-02-12 19:21:10 +01:00
This - > activeContext = context ;
}
2007-02-12 19:18:36 +01:00
2007-09-29 17:12:35 +02:00
/* We only need ENTER_GL for the gl calls made below and for the helper functions which make GL calls */
ENTER_GL ( ) ;
2007-11-06 01:11:35 +01:00
/* Select the right draw buffer. It is selected in FindContext. */
if ( drawBuffer & & context - > last_draw_buffer ! = drawBuffer ) {
TRACE ( " Drawing to buffer: %#x \n " , drawBuffer ) ;
context - > last_draw_buffer = drawBuffer ;
glDrawBuffer ( drawBuffer ) ;
checkGLcall ( " glDrawBuffer " ) ;
}
2007-02-12 19:18:36 +01:00
switch ( usage ) {
case CTXUSAGE_RESOURCELOAD :
/* This does not require any special states to be set up */
break ;
2007-07-09 16:57:58 +02:00
case CTXUSAGE_CLEAR :
2008-03-22 14:31:52 +01:00
if ( context - > last_was_blit ) {
2008-04-11 08:19:04 +02:00
This - > shader_backend - > shader_fragment_enable ( ( IWineD3DDevice * ) This , TRUE ) ;
2007-07-09 16:57:58 +02:00
}
2008-04-06 00:49:00 +02:00
/* Blending and clearing should be orthogonal, but tests on the nvidia driver show that disabling
2008-04-22 08:18:14 +02:00
* blending when clearing improves the clearing performance incredibly .
2008-04-06 00:49:00 +02:00
*/
glDisable ( GL_BLEND ) ;
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_ALPHABLENDENABLE ) , StateTable ) ;
2007-07-09 16:57:58 +02:00
glEnable ( GL_SCISSOR_TEST ) ;
checkGLcall ( " glEnable GL_SCISSOR_TEST " ) ;
context - > last_was_blit = FALSE ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_RENDER ( WINED3DRS_SCISSORTESTENABLE ) , StateTable ) ;
Context_MarkStateDirty ( context , STATE_SCISSORRECT , StateTable ) ;
2007-07-09 16:57:58 +02:00
break ;
2007-02-12 19:18:36 +01:00
case CTXUSAGE_DRAWPRIM :
/* This needs all dirty states applied */
2008-03-22 14:31:52 +01:00
if ( context - > last_was_blit ) {
2008-04-11 08:19:04 +02:00
This - > shader_backend - > shader_fragment_enable ( ( IWineD3DDevice * ) This , TRUE ) ;
2007-05-07 21:08:14 +02:00
}
2007-07-01 23:40:57 +02:00
IWineD3DDeviceImpl_FindTexUnitMap ( This ) ;
2007-02-12 19:18:36 +01:00
for ( i = 0 ; i < context - > numDirtyEntries ; i + + ) {
dirtyState = context - > dirtyArray [ i ] ;
idx = dirtyState > > 5 ;
shift = dirtyState & 0x1f ;
context - > isStateDirty [ idx ] & = ~ ( 1 < < shift ) ;
StateTable [ dirtyState ] . apply ( dirtyState , This - > stateBlock , context ) ;
}
context - > numDirtyEntries = 0 ; /* This makes the whole list clean */
2007-02-12 19:18:41 +01:00
context - > last_was_blit = FALSE ;
2007-02-12 19:18:36 +01:00
break ;
case CTXUSAGE_BLIT :
2007-02-12 19:18:41 +01:00
SetupForBlit ( This , context ,
( ( IWineD3DSurfaceImpl * ) target ) - > currentDesc . Width ,
( ( IWineD3DSurfaceImpl * ) target ) - > currentDesc . Height ) ;
2007-02-12 19:18:36 +01:00
break ;
default :
FIXME ( " Unexpected context usage requested \n " ) ;
}
2007-08-06 16:27:08 +02:00
LEAVE_GL ( ) ;
2007-02-12 19:18:36 +01:00
}