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-03-09 19:30:08 +01:00
Context_MarkStateDirty ( This - > contexts [ This - > numContexts ] , state , This - > shader_backend - > 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 ] ;
}
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-25 00:18:54 +02:00
# define PUSH1(att) attribs[nAttribs++] = (att);
# define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
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 ;
2007-08-28 22:40:26 +02:00
short redBits , greenBits , blueBits , alphaBits , colorBits ;
2007-08-09 14:12:42 +02:00
short depthBits , stencilBits ;
IWineD3DSurface * StencilSurface = This - > stencilBufferTarget ;
WINED3DFORMAT StencilBufferFormat = ( NULL ! = StencilSurface ) ? ( ( IWineD3DSurfaceImpl * ) StencilSurface ) - > resource . format : 0 ;
int attribs [ 256 ] ;
int nAttribs = 0 ;
unsigned int nFormats ;
/* Retrieve the specifications for the pixelformat from the backbuffer / stencilbuffer */
2007-08-28 22:40:26 +02:00
getColorBits ( target - > resource . format , & redBits , & greenBits , & blueBits , & alphaBits , & colorBits ) ;
2007-08-09 14:12:42 +02:00
getDepthStencilBits ( StencilBufferFormat , & depthBits , & stencilBits ) ;
PUSH2 ( WGL_DRAW_TO_PBUFFER_ARB , 1 ) ; /* We need pbuffer support; doublebuffering isn't needed */
PUSH2 ( WGL_PIXEL_TYPE_ARB , WGL_TYPE_RGBA_ARB ) ; /* Make sure we don't get a float or color index format */
PUSH2 ( WGL_COLOR_BITS_ARB , colorBits ) ;
2007-08-28 22:40:26 +02:00
PUSH2 ( WGL_RED_BITS_ARB , redBits ) ;
PUSH2 ( WGL_GREEN_BITS_ARB , greenBits ) ;
PUSH2 ( WGL_BLUE_BITS_ARB , blueBits ) ;
2007-08-09 14:12:42 +02:00
PUSH2 ( WGL_ALPHA_BITS_ARB , alphaBits ) ;
PUSH2 ( WGL_DEPTH_BITS_ARB , depthBits ) ;
PUSH2 ( WGL_STENCIL_BITS_ARB , stencilBits ) ;
PUSH1 ( 0 ) ; /* end the list */
/* Try to find a pixelformat that matches exactly. If that fails let ChoosePixelFormat try to find a close match */
if ( ! GL_EXTCALL ( wglChoosePixelFormatARB ( hdc_parent , ( const int * ) & attribs , NULL , 1 , & iPixelFormat , & nFormats ) ) )
{
PIXELFORMATDESCRIPTOR pfd ;
TRACE ( " Falling back to ChoosePixelFormat as wglChoosePixelFormatARB failed \n " ) ;
ZeroMemory ( & pfd , sizeof ( pfd ) ) ;
pfd . nSize = sizeof ( pfd ) ;
pfd . nVersion = 1 ;
pfd . dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER_DONTCARE | PFD_DRAW_TO_WINDOW ;
pfd . iPixelType = PFD_TYPE_RGBA ;
pfd . cColorBits = colorBits ;
pfd . cDepthBits = depthBits ;
pfd . cStencilBits = stencilBits ;
pfd . iLayerType = PFD_MAIN_PLANE ;
iPixelFormat = ChoosePixelFormat ( hdc_parent , & pfd ) ;
if ( ! iPixelFormat ) {
/* If this happens something is very wrong as ChoosePixelFormat barely fails */
ERR ( " Can't find a suitable iPixelFormat for the pbuffer \n " ) ;
}
}
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-25 00:18:54 +02:00
short redBits , greenBits , blueBits , alphaBits , colorBits ;
short depthBits = 0 , stencilBits = 0 ;
2007-08-11 17:04:26 +02:00
int res ;
2007-08-25 00:18:54 +02:00
int attribs [ 256 ] ;
int nAttribs = 0 ;
unsigned int nFormats ;
2008-02-23 00:27:38 +01:00
WINED3DFORMAT fmt = target - > resource . format ;
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
/* PixelFormat selection */
2007-08-25 00:18:54 +02:00
PUSH2 ( WGL_DRAW_TO_WINDOW_ARB , GL_TRUE ) ; /* We want to draw to a window */
PUSH2 ( WGL_DOUBLE_BUFFER_ARB , GL_TRUE ) ;
PUSH2 ( WGL_PIXEL_TYPE_ARB , WGL_TYPE_RGBA_ARB ) ; /* Make sure we don't get a float or color index format */
2007-10-05 20:02:50 +02:00
PUSH2 ( WGL_SUPPORT_OPENGL_ARB , GL_TRUE ) ;
PUSH2 ( WGL_ACCELERATION_ARB , WGL_FULL_ACCELERATION_ARB ) ; /* Make sure we receive an accelerated format. On windows (at least on ATI) this is not always the case */
2007-08-25 00:18:54 +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 ) {
if ( target - > resource . format = = WINED3DFMT_X4R4G4B4 )
fmt = WINED3DFMT_A4R4G4B4 ;
else if ( target - > resource . format = = WINED3DFMT_X8R8G8B8 )
fmt = WINED3DFMT_A8R8G8B8 ;
2008-02-23 16:15:11 +01:00
/* We like to have two aux buffers in backbuffer mode */
PUSH2 ( WGL_AUX_BUFFERS_ARB , 2 ) ;
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 . */
if ( fmt = = WINED3DFMT_P8 )
fmt = WINED3DFMT_A8R8G8B8 ;
2008-02-23 00:27:38 +01:00
if ( ! getColorBits ( fmt , & redBits , & greenBits , & blueBits , & alphaBits , & colorBits ) ) {
2007-08-25 00:18:54 +02:00
ERR ( " Unable to get color bits for format %#x! \n " , target - > resource . format ) ;
return FALSE ;
}
PUSH2 ( WGL_COLOR_BITS_ARB , colorBits ) ;
PUSH2 ( WGL_RED_BITS_ARB , redBits ) ;
PUSH2 ( WGL_GREEN_BITS_ARB , greenBits ) ;
PUSH2 ( WGL_BLUE_BITS_ARB , blueBits ) ;
PUSH2 ( WGL_ALPHA_BITS_ARB , alphaBits ) ;
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 ) ) ;
2007-08-25 00:18:54 +02:00
if ( ! getDepthStencilBits ( pPresentParms - > AutoDepthStencilFormat , & depthBits , & stencilBits ) ) {
ERR ( " Unable to get depth / stencil bits for AutoDepthStencilFormat %#x! \n " , pPresentParms - > AutoDepthStencilFormat ) ;
return FALSE ;
2007-08-11 12:17:56 +02:00
}
2007-08-25 00:18:54 +02:00
PUSH2 ( WGL_DEPTH_BITS_ARB , depthBits ) ;
PUSH2 ( WGL_STENCIL_BITS_ARB , stencilBits ) ;
2007-08-09 01:04:30 +02:00
}
2007-08-25 00:18:54 +02:00
PUSH1 ( 0 ) ; /* end the list */
2008-01-09 20:37:05 +01:00
/* In case of failure hope that standard ChoosePixelFormat will find something suitable */
2007-08-25 00:18:54 +02:00
if ( ! GL_EXTCALL ( wglChoosePixelFormatARB ( hdc , ( const int * ) & attribs , NULL , 1 , & iPixelFormat , & nFormats ) ) )
{
/* 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 " ) ;
}
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 ) ;
if ( oldPixelFormat ) {
/* 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 ) ;
}
else {
ERR ( " SetPixelFormat failed on HDC=%p for iPixelFormat=%d \n " , hdc , iPixelFormat ) ;
return FALSE ;
}
}
2007-02-12 19:21:10 +01:00
}
2007-08-25 00:18:54 +02:00
# undef PUSH1
# undef PUSH2
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-03-30 14:52:18 +02:00
if ( oldCtx & & oldDrawable & & GL_SUPPORT ( ATI_FRAGMENT_SHADER ) ) {
/* See comment in ActivateContext context switching */
glDisable ( GL_FRAGMENT_SHADER_ATI ) ;
checkGLcall ( " glEnable(GL_FRAGMENT_SHADER_ATI) " ) ;
}
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 ( ) ;
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-03-30 14:52:18 +02:00
if ( GL_SUPPORT ( ATI_FRAGMENT_SHADER ) ) {
glEnable ( GL_FRAGMENT_SHADER_ATI ) ;
checkGLcall ( " glEnable(GL_FRAGMENT_SHADER_ATI) " ) ;
}
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 ;
for ( s = 0 ; s < This - > numContexts ; s + + ) {
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
}
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-03-09 19:30:08 +01:00
const struct StateEntry * StateTable = This - > shader_backend - > StateTable ;
2007-02-12 19:18:41 +01:00
TRACE ( " Setting up context %p for blitting \n " , context ) ;
if ( context - > last_was_blit ) {
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
glMatrixMode ( GL_PROJECTION ) ;
checkGLcall ( " glMatrixMode(GL_PROJECTION) " ) ;
glLoadIdentity ( ) ;
checkGLcall ( " glLoadIdentity() " ) ;
glOrtho ( 0 , width , height , 0 , 0.0 , - 1.0 ) ;
checkGLcall ( " glOrtho " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_TRANSFORM ( WINED3DTS_PROJECTION ) , 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
glViewport ( 0 , 0 , width , height ) ;
checkGLcall ( " glViewport " ) ;
2008-03-09 19:30:08 +01:00
Context_MarkStateDirty ( context , STATE_VIEWPORT , StateTable ) ;
2007-05-07 21:08:14 +02:00
if ( GL_SUPPORT ( NV_TEXTURE_SHADER2 ) ) {
glDisable ( GL_TEXTURE_SHADER_NV ) ;
checkGLcall ( " glDisable(GL_TEXTURE_SHADER_NV) " ) ;
2008-03-22 14:31:52 +01:00
} else if ( GL_SUPPORT ( ATI_FRAGMENT_SHADER ) ) {
glDisable ( GL_FRAGMENT_SHADER_ATI ) ;
checkGLcall ( " glDisable(GL_FRAGMENT_SHADER_ATI) " ) ;
2007-05-07 21:08:14 +02:00
}
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-03-09 19:30:08 +01:00
const struct StateEntry * StateTable = This - > shader_backend - > 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 ( wined3d_settings . offscreen_rendering_mode ! = ORM_FBO ) {
/* Make sure we have a OpenGL texture name so the PreLoad() used to read the buffer
* back when we are done won ' t mark us dirty .
*/
IWineD3DSurface_PreLoad ( target ) ;
}
2007-06-02 22:20:17 +02: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
}
}
if ( readTexture ) {
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
if ( oldRenderOffscreen ! = This - > render_offscreen & & This - > depth_copy_state ! = WINED3D_DCS_NO_COPY ) {
This - > depth_copy_state = WINED3D_DCS_COPY ;
}
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-03-09 19:30:08 +01:00
const struct StateEntry * StateTable = This - > shader_backend - > 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
if ( GL_SUPPORT ( ATI_FRAGMENT_SHADER ) ) {
/* Mesa crashes when enabling a context with GL_FRAGMENT_SHADER_ATI enabled.
* Thus we disable it before deactivating any context , and re - enable it afterwards .
*
* This bug is filed as bug # 15269 on bugs . freedesktop . org
*/
glDisable ( GL_FRAGMENT_SHADER_ATI ) ;
checkGLcall ( " glEnable(GL_FRAGMENT_SHADER_ATI) " ) ;
}
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-03-30 14:52:18 +02:00
} else if ( GL_SUPPORT ( ATI_FRAGMENT_SHADER ) & & ! context - > last_was_blit ) {
glEnable ( GL_FRAGMENT_SHADER_ATI ) ;
checkGLcall ( " glEnable(GL_FRAGMENT_SHADER_ATI) " ) ;
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 ) {
if ( GL_SUPPORT ( NV_TEXTURE_SHADER2 ) ) {
glEnable ( GL_TEXTURE_SHADER_NV ) ;
checkGLcall ( " glEnable(GL_TEXTURE_SHADER_NV) " ) ;
} else if ( GL_SUPPORT ( ATI_FRAGMENT_SHADER ) ) {
glEnable ( GL_FRAGMENT_SHADER_ATI ) ;
checkGLcall ( " glEnable(GL_FRAGMENT_SHADER_ATI) " ) ;
}
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 ) {
if ( GL_SUPPORT ( NV_TEXTURE_SHADER2 ) ) {
glEnable ( GL_TEXTURE_SHADER_NV ) ;
checkGLcall ( " glEnable(GL_TEXTURE_SHADER_NV) " ) ;
} else if ( GL_SUPPORT ( ATI_FRAGMENT_SHADER ) ) {
glEnable ( GL_FRAGMENT_SHADER_ATI ) ;
checkGLcall ( " glEnable(GL_FRAGMENT_SHADER_ATI) " ) ;
}
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
}