advapi32: Create MachineGuid value if it doesn't exist.
[wine] / dlls / wined3d / context.c
1 /*
2  * Context and render target management in wined3d
3  *
4  * Copyright 2007 Stefan Dösinger for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include <stdio.h>
23 #ifdef HAVE_FLOAT_H
24 # include <float.h>
25 #endif
26 #include "wined3d_private.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
29
30 #define GLINFO_LOCATION This->adapter->gl_info
31
32 /*****************************************************************************
33  * Context_MarkStateDirty
34  *
35  * Marks a state in a context dirty. Only one context, opposed to
36  * IWineD3DDeviceImpl_MarkStateDirty, which marks the state dirty in all
37  * contexts
38  *
39  * Params:
40  *  context: Context to mark the state dirty in
41  *  state: State to mark dirty
42  *  StateTable: Pointer to the state table in use(for state grouping)
43  *
44  *****************************************************************************/
45 static void Context_MarkStateDirty(WineD3DContext *context, DWORD state, const struct StateEntry *StateTable) {
46     DWORD rep = StateTable[state].representative;
47     DWORD idx;
48     BYTE shift;
49
50     if(!rep || isStateDirty(context, rep)) return;
51
52     context->dirtyArray[context->numDirtyEntries++] = rep;
53     idx = rep >> 5;
54     shift = rep & 0x1f;
55     context->isStateDirty[idx] |= (1 << shift);
56 }
57
58 /*****************************************************************************
59  * AddContextToArray
60  *
61  * Adds a context to the context array. Helper function for CreateContext
62  *
63  * This method is not called in performance-critical code paths, only when a
64  * new render target or swapchain is created. Thus performance is not an issue
65  * here.
66  *
67  * Params:
68  *  This: Device to add the context for
69  *  hdc: device context
70  *  glCtx: WGL context to add
71  *  pbuffer: optional pbuffer used with this context
72  *
73  *****************************************************************************/
74 static WineD3DContext *AddContextToArray(IWineD3DDeviceImpl *This, HWND win_handle, HDC hdc, HGLRC glCtx, HPBUFFERARB pbuffer) {
75     WineD3DContext **oldArray = This->contexts;
76     DWORD state;
77
78     This->contexts = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->contexts) * (This->numContexts + 1));
79     if(This->contexts == NULL) {
80         ERR("Unable to grow the context array\n");
81         This->contexts = oldArray;
82         return NULL;
83     }
84     if(oldArray) {
85         memcpy(This->contexts, oldArray, sizeof(*This->contexts) * This->numContexts);
86     }
87
88     This->contexts[This->numContexts] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineD3DContext));
89     if(This->contexts[This->numContexts] == NULL) {
90         ERR("Unable to allocate a new context\n");
91         HeapFree(GetProcessHeap(), 0, This->contexts);
92         This->contexts = oldArray;
93         return NULL;
94     }
95
96     This->contexts[This->numContexts]->hdc = hdc;
97     This->contexts[This->numContexts]->glCtx = glCtx;
98     This->contexts[This->numContexts]->pbuffer = pbuffer;
99     This->contexts[This->numContexts]->win_handle = win_handle;
100     HeapFree(GetProcessHeap(), 0, oldArray);
101
102     /* Mark all states dirty to force a proper initialization of the states on the first use of the context
103      */
104     for(state = 0; state <= STATE_HIGHEST; state++) {
105         Context_MarkStateDirty(This->contexts[This->numContexts], state, This->shader_backend->StateTable);
106     }
107
108     This->numContexts++;
109     TRACE("Created context %p\n", This->contexts[This->numContexts - 1]);
110     return This->contexts[This->numContexts - 1];
111 }
112
113 /*****************************************************************************
114  * CreateContext
115  *
116  * Creates a new context for a window, or a pbuffer context.
117  *
118  * * Params:
119  *  This: Device to activate the context for
120  *  target: Surface this context will render to
121  *  win_handle: handle to the window which we are drawing to
122  *  create_pbuffer: tells whether to create a pbuffer or not
123  *  pPresentParameters: contains the pixelformats to use for onscreen rendering
124  *
125  *****************************************************************************/
126 WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, HWND win_handle, BOOL create_pbuffer, const WINED3DPRESENT_PARAMETERS *pPresentParms) {
127     HDC oldDrawable, hdc;
128     HPBUFFERARB pbuffer = NULL;
129     HGLRC ctx = NULL, oldCtx;
130     WineD3DContext *ret = NULL;
131     int s;
132
133     TRACE("(%p): Creating a %s context for render target %p\n", This, create_pbuffer ? "offscreen" : "onscreen", target);
134
135 #define PUSH1(att)        attribs[nAttribs++] = (att);
136 #define PUSH2(att,value)  attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
137     if(create_pbuffer) {
138         HDC hdc_parent = GetDC(win_handle);
139         int iPixelFormat = 0;
140         short redBits, greenBits, blueBits, alphaBits, colorBits;
141         short depthBits, stencilBits;
142
143         IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
144         WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
145
146         int attribs[256];
147         int nAttribs = 0;
148         unsigned int nFormats;
149
150         /* Retrieve the specifications for the pixelformat from the backbuffer / stencilbuffer */
151         getColorBits(target->resource.format, &redBits, &greenBits, &blueBits, &alphaBits, &colorBits);
152         getDepthStencilBits(StencilBufferFormat, &depthBits, &stencilBits);
153         PUSH2(WGL_DRAW_TO_PBUFFER_ARB, 1); /* We need pbuffer support; doublebuffering isn't needed */
154         PUSH2(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB); /* Make sure we don't get a float or color index format */
155         PUSH2(WGL_COLOR_BITS_ARB, colorBits);
156         PUSH2(WGL_RED_BITS_ARB, redBits);
157         PUSH2(WGL_GREEN_BITS_ARB, greenBits);
158         PUSH2(WGL_BLUE_BITS_ARB, blueBits);
159         PUSH2(WGL_ALPHA_BITS_ARB, alphaBits);
160         PUSH2(WGL_DEPTH_BITS_ARB, depthBits);
161         PUSH2(WGL_STENCIL_BITS_ARB, stencilBits);
162         PUSH1(0); /* end the list */
163
164         /* Try to find a pixelformat that matches exactly. If that fails let ChoosePixelFormat try to find a close match */
165         if(!GL_EXTCALL(wglChoosePixelFormatARB(hdc_parent, (const int*)&attribs, NULL, 1, &iPixelFormat, &nFormats)))
166         {
167             PIXELFORMATDESCRIPTOR pfd;
168
169             TRACE("Falling back to ChoosePixelFormat as wglChoosePixelFormatARB failed\n");
170
171             ZeroMemory(&pfd, sizeof(pfd));
172             pfd.nSize      = sizeof(pfd);
173             pfd.nVersion   = 1;
174             pfd.dwFlags    = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER_DONTCARE | PFD_DRAW_TO_WINDOW;
175             pfd.iPixelType = PFD_TYPE_RGBA;
176             pfd.cColorBits = colorBits;
177             pfd.cDepthBits = depthBits;
178             pfd.cStencilBits = stencilBits;
179             pfd.iLayerType = PFD_MAIN_PLANE;
180
181             iPixelFormat = ChoosePixelFormat(hdc_parent, &pfd);
182             if(!iPixelFormat) {
183                 /* If this happens something is very wrong as ChoosePixelFormat barely fails */
184                 ERR("Can't find a suitable iPixelFormat for the pbuffer\n");
185             }
186         }
187
188         TRACE("Creating a pBuffer drawable for the new context\n");
189         pbuffer = GL_EXTCALL(wglCreatePbufferARB(hdc_parent, iPixelFormat, target->currentDesc.Width, target->currentDesc.Height, 0));
190         if(!pbuffer) {
191             ERR("Cannot create a pbuffer\n");
192             ReleaseDC(win_handle, hdc_parent);
193             goto out;
194         }
195
196         /* In WGL a pbuffer is 'wrapped' inside a HDC to 'fool' wglMakeCurrent */
197         hdc = GL_EXTCALL(wglGetPbufferDCARB(pbuffer));
198         if(!hdc) {
199             ERR("Cannot get a HDC for pbuffer (%p)\n", pbuffer);
200             GL_EXTCALL(wglDestroyPbufferARB(pbuffer));
201             ReleaseDC(win_handle, hdc_parent);
202             goto out;
203         }
204         ReleaseDC(win_handle, hdc_parent);
205     } else {
206         PIXELFORMATDESCRIPTOR pfd;
207         int iPixelFormat;
208         short redBits, greenBits, blueBits, alphaBits, colorBits;
209         short depthBits=0, stencilBits=0;
210         int res;
211         int attribs[256];
212         int nAttribs = 0;
213         unsigned int nFormats;
214         WINED3DFORMAT fmt = target->resource.format;
215
216         hdc = GetDC(win_handle);
217         if(hdc == NULL) {
218             ERR("Cannot retrieve a device context!\n");
219             goto out;
220         }
221
222         /* PixelFormat selection */
223         PUSH2(WGL_DRAW_TO_WINDOW_ARB, GL_TRUE); /* We want to draw to a window */
224         PUSH2(WGL_DOUBLE_BUFFER_ARB, GL_TRUE);
225         PUSH2(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB); /* Make sure we don't get a float or color index format */
226         PUSH2(WGL_SUPPORT_OPENGL_ARB, GL_TRUE);
227         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 */
228
229         /* In case of ORM_BACKBUFFER, make sure to request an alpha component for X4R4G4B4/X8R8G8B8 as we might need it for the backbuffer. */
230         if(wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER) {
231             if(target->resource.format == WINED3DFMT_X4R4G4B4)
232                 fmt = WINED3DFMT_A4R4G4B4;
233             else if(target->resource.format == WINED3DFMT_X8R8G8B8)
234                 fmt = WINED3DFMT_A8R8G8B8;
235
236             /* We like to have two aux buffers in backbuffer mode */
237             PUSH2(WGL_AUX_BUFFERS_ARB, 2);
238         }
239
240         if(!getColorBits(fmt, &redBits, &greenBits, &blueBits, &alphaBits, &colorBits)) {
241             ERR("Unable to get color bits for format %#x!\n", target->resource.format);
242             return FALSE;
243         }
244         PUSH2(WGL_COLOR_BITS_ARB, colorBits);
245         PUSH2(WGL_RED_BITS_ARB, redBits);
246         PUSH2(WGL_GREEN_BITS_ARB, greenBits);
247         PUSH2(WGL_BLUE_BITS_ARB, blueBits);
248         PUSH2(WGL_ALPHA_BITS_ARB, alphaBits);
249
250         /* Retrieve the depth stencil format from the present parameters.
251          * The choice of the proper format can give a nice performance boost
252          * in case of GPU limited programs. */
253         if(pPresentParms->EnableAutoDepthStencil) {
254             TRACE("pPresentParms->EnableAutoDepthStencil=enabled; using AutoDepthStencilFormat=%s\n", debug_d3dformat(pPresentParms->AutoDepthStencilFormat));
255             if(!getDepthStencilBits(pPresentParms->AutoDepthStencilFormat, &depthBits, &stencilBits)) {
256                 ERR("Unable to get depth / stencil bits for AutoDepthStencilFormat %#x!\n", pPresentParms->AutoDepthStencilFormat);
257                 return FALSE;
258             }
259             PUSH2(WGL_DEPTH_BITS_ARB, depthBits);
260             PUSH2(WGL_STENCIL_BITS_ARB, stencilBits);
261         }
262
263         PUSH1(0); /* end the list */
264
265         /* In case of failure hope that standard ChoosePixelFormat will find something suitable */
266         if(!GL_EXTCALL(wglChoosePixelFormatARB(hdc, (const int*)&attribs, NULL, 1, &iPixelFormat, &nFormats)))
267         {
268             /* PixelFormat selection */
269             ZeroMemory(&pfd, sizeof(pfd));
270             pfd.nSize      = sizeof(pfd);
271             pfd.nVersion   = 1;
272             pfd.dwFlags    = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/
273             pfd.iPixelType = PFD_TYPE_RGBA;
274             pfd.cAlphaBits = alphaBits;
275             pfd.cColorBits = colorBits;
276             pfd.cDepthBits = depthBits;
277             pfd.cStencilBits = stencilBits;
278             pfd.iLayerType = PFD_MAIN_PLANE;
279
280             iPixelFormat = ChoosePixelFormat(hdc, &pfd);
281             if(!iPixelFormat) {
282                 /* If this happens something is very wrong as ChoosePixelFormat barely fails */
283                 ERR("Can't find a suitable iPixelFormat\n");
284             }
285         }
286
287         DescribePixelFormat(hdc, iPixelFormat, sizeof(pfd), &pfd);
288         res = SetPixelFormat(hdc, iPixelFormat, NULL);
289         if(!res) {
290             int oldPixelFormat = GetPixelFormat(hdc);
291
292             if(oldPixelFormat) {
293                 /* OpenGL doesn't allow pixel format adjustments. Print an error and continue using the old format.
294                  * There's a big chance that the old format works although with a performance hit and perhaps rendering errors. */
295                 ERR("HDC=%p is already set to iPixelFormat=%d and OpenGL doesn't allow changes!\n", hdc, oldPixelFormat);
296             }
297             else {
298                 ERR("SetPixelFormat failed on HDC=%p for iPixelFormat=%d\n", hdc, iPixelFormat);
299                 return FALSE;
300             }
301         }
302     }
303 #undef PUSH1
304 #undef PUSH2
305
306     ctx = pwglCreateContext(hdc);
307     if(This->numContexts) pwglShareLists(This->contexts[0]->glCtx, ctx);
308
309     if(!ctx) {
310         ERR("Failed to create a WGL context\n");
311         if(create_pbuffer) {
312             GL_EXTCALL(wglReleasePbufferDCARB(pbuffer, hdc));
313             GL_EXTCALL(wglDestroyPbufferARB(pbuffer));
314         }
315         goto out;
316     }
317     ret = AddContextToArray(This, win_handle, hdc, ctx, pbuffer);
318     if(!ret) {
319         ERR("Failed to add the newly created context to the context list\n");
320         pwglDeleteContext(ctx);
321         if(create_pbuffer) {
322             GL_EXTCALL(wglReleasePbufferDCARB(pbuffer, hdc));
323             GL_EXTCALL(wglDestroyPbufferARB(pbuffer));
324         }
325         goto out;
326     }
327     ret->surface = (IWineD3DSurface *) target;
328     ret->isPBuffer = create_pbuffer;
329     ret->tid = GetCurrentThreadId();
330     if(This->shader_backend->shader_dirtifyable_constants((IWineD3DDevice *) This)) {
331         /* Create the dirty constants array and initialize them to dirty */
332         ret->vshader_const_dirty = HeapAlloc(GetProcessHeap(), 0,
333                 sizeof(*ret->vshader_const_dirty) * GL_LIMITS(vshader_constantsF));
334         ret->pshader_const_dirty = HeapAlloc(GetProcessHeap(), 0,
335                 sizeof(*ret->pshader_const_dirty) * GL_LIMITS(pshader_constantsF));
336         memset(ret->vshader_const_dirty, 1,
337                sizeof(*ret->vshader_const_dirty) * GL_LIMITS(vshader_constantsF));
338         memset(ret->pshader_const_dirty, 1,
339                 sizeof(*ret->pshader_const_dirty) * GL_LIMITS(pshader_constantsF));
340     }
341
342     TRACE("Successfully created new context %p\n", ret);
343
344     /* Set up the context defaults */
345     oldCtx  = pwglGetCurrentContext();
346     oldDrawable = pwglGetCurrentDC();
347     if(pwglMakeCurrent(hdc, ctx) == FALSE) {
348         ERR("Cannot activate context to set up defaults\n");
349         goto out;
350     }
351
352     ENTER_GL();
353     TRACE("Setting up the screen\n");
354     /* Clear the screen */
355     glClearColor(1.0, 0.0, 0.0, 0.0);
356     checkGLcall("glClearColor");
357     glClearIndex(0);
358     glClearDepth(1);
359     glClearStencil(0xffff);
360
361     checkGLcall("glClear");
362
363     glColor3f(1.0, 1.0, 1.0);
364     checkGLcall("glColor3f");
365
366     glEnable(GL_LIGHTING);
367     checkGLcall("glEnable");
368
369     glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
370     checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
371
372     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
373     checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
374
375     glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
376     checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
377
378     glPixelStorei(GL_PACK_ALIGNMENT, This->surface_alignment);
379     checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, This->surface_alignment);");
380     glPixelStorei(GL_UNPACK_ALIGNMENT, This->surface_alignment);
381     checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, This->surface_alignment);");
382
383     if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
384         /* Most textures will use client storage if supported. Exceptions are non-native power of 2 textures
385          * and textures in DIB sections(due to the memory protection).
386          */
387         glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
388         checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
389     }
390     if(GL_SUPPORT(ARB_VERTEX_BLEND)) {
391         /* Direct3D always uses n-1 weights for n world matrices and uses 1 - sum for the last one
392          * this is equal to GL_WEIGHT_SUM_UNITY_ARB. Enabling it doesn't do anything unless
393          * GL_VERTEX_BLEND_ARB isn't enabled too
394          */
395         glEnable(GL_WEIGHT_SUM_UNITY_ARB);
396         checkGLcall("glEnable(GL_WEIGHT_SUM_UNITY_ARB)");
397     }
398     if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
399         glEnable(GL_TEXTURE_SHADER_NV);
400         checkGLcall("glEnable(GL_TEXTURE_SHADER_NV)");
401
402         /* Set up the previous texture input for all shader units. This applies to bump mapping, and in d3d
403          * the previous texture where to source the offset from is always unit - 1.
404          */
405         for(s = 1; s < GL_LIMITS(textures); s++) {
406             GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + s));
407             glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB + s - 1);
408             checkGLcall("glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ...\n");
409         }
410     } else if(GL_SUPPORT(ATI_FRAGMENT_SHADER)) {
411         glEnable(GL_FRAGMENT_SHADER_ATI);
412         checkGLcall("glEnable(GL_FRAGMENT_SHADER_ATI)");
413     }
414
415     if(GL_SUPPORT(ARB_POINT_SPRITE)) {
416         for(s = 0; s < GL_LIMITS(textures); s++) {
417             GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + s));
418             glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
419             checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n");
420         }
421     }
422     LEAVE_GL();
423
424     if(oldDrawable && oldCtx) {
425         pwglMakeCurrent(oldDrawable, oldCtx);
426     }
427
428 out:
429     return ret;
430 }
431
432 /*****************************************************************************
433  * RemoveContextFromArray
434  *
435  * Removes a context from the context manager. The opengl context is not
436  * destroyed or unset. context is not a valid pointer after that call.
437  *
438  * Similar to the former call this isn't a performance critical function. A
439  * helper function for DestroyContext.
440  *
441  * Params:
442  *  This: Device to activate the context for
443  *  context: Context to remove
444  *
445  *****************************************************************************/
446 static void RemoveContextFromArray(IWineD3DDeviceImpl *This, WineD3DContext *context) {
447     UINT t, s;
448     WineD3DContext **oldArray = This->contexts;
449
450     TRACE("Removing ctx %p\n", context);
451
452     This->numContexts--;
453
454     if(This->numContexts) {
455         This->contexts = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->contexts) * This->numContexts);
456         if(!This->contexts) {
457             ERR("Cannot allocate a new context array, PANIC!!!\n");
458         }
459         t = 0;
460         for(s = 0; s < This->numContexts; s++) {
461             if(oldArray[s] == context) continue;
462             This->contexts[t] = oldArray[s];
463             t++;
464         }
465     } else {
466         This->contexts = NULL;
467     }
468
469     HeapFree(GetProcessHeap(), 0, context);
470     HeapFree(GetProcessHeap(), 0, oldArray);
471 }
472
473 /*****************************************************************************
474  * DestroyContext
475  *
476  * Destroys a wineD3DContext
477  *
478  * Params:
479  *  This: Device to activate the context for
480  *  context: Context to destroy
481  *
482  *****************************************************************************/
483 void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context) {
484
485     /* check that we are the current context first */
486     TRACE("Destroying ctx %p\n", context);
487     if(pwglGetCurrentContext() == context->glCtx){
488         pwglMakeCurrent(NULL, NULL);
489     }
490
491     if(context->isPBuffer) {
492         GL_EXTCALL(wglReleasePbufferDCARB(context->pbuffer, context->hdc));
493         GL_EXTCALL(wglDestroyPbufferARB(context->pbuffer));
494     } else ReleaseDC(context->win_handle, context->hdc);
495     pwglDeleteContext(context->glCtx);
496
497     HeapFree(GetProcessHeap(), 0, context->vshader_const_dirty);
498     HeapFree(GetProcessHeap(), 0, context->pshader_const_dirty);
499     RemoveContextFromArray(This, context);
500 }
501
502 /*****************************************************************************
503  * SetupForBlit
504  *
505  * Sets up a context for DirectDraw blitting.
506  * All texture units are disabled, texture unit 0 is set as current unit
507  * fog, lighting, blending, alpha test, z test, scissor test, culling disabled
508  * color writing enabled for all channels
509  * register combiners disabled, shaders disabled
510  * world matrix is set to identity, texture matrix 0 too
511  * projection matrix is setup for drawing screen coordinates
512  *
513  * Params:
514  *  This: Device to activate the context for
515  *  context: Context to setup
516  *  width: render target width
517  *  height: render target height
518  *
519  *****************************************************************************/
520 static inline void SetupForBlit(IWineD3DDeviceImpl *This, WineD3DContext *context, UINT width, UINT height) {
521     int i;
522     const struct StateEntry *StateTable = This->shader_backend->StateTable;
523
524     TRACE("Setting up context %p for blitting\n", context);
525     if(context->last_was_blit) {
526         TRACE("Context is already set up for blitting, nothing to do\n");
527         return;
528     }
529     context->last_was_blit = TRUE;
530
531     /* TODO: Use a display list */
532
533     /* Disable shaders */
534     This->shader_backend->shader_cleanup((IWineD3DDevice *) This);
535     Context_MarkStateDirty(context, STATE_VSHADER, StateTable);
536     Context_MarkStateDirty(context, STATE_PIXELSHADER, StateTable);
537
538     /* Disable all textures. The caller can then bind a texture it wants to blit
539      * from
540      */
541     if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
542         glDisable(GL_REGISTER_COMBINERS_NV);
543         checkGLcall("glDisable(GL_REGISTER_COMBINERS_NV)");
544     }
545     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
546         /* The blitting code uses (for now) the fixed function pipeline, so make sure to reset all fixed
547          * function texture unit. No need to care for higher samplers
548          */
549         for(i = GL_LIMITS(textures) - 1; i > 0 ; i--) {
550             GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
551             checkGLcall("glActiveTextureARB");
552
553             if(GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) {
554                 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
555                 checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
556             }
557             glDisable(GL_TEXTURE_3D);
558             checkGLcall("glDisable GL_TEXTURE_3D");
559             glDisable(GL_TEXTURE_2D);
560             checkGLcall("glDisable GL_TEXTURE_2D");
561
562             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
563             checkGLcall("glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);");
564
565             Context_MarkStateDirty(context, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP), StateTable);
566             Context_MarkStateDirty(context, STATE_SAMPLER(i), StateTable);
567         }
568         GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
569         checkGLcall("glActiveTextureARB");
570     }
571     if(GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) {
572         glDisable(GL_TEXTURE_CUBE_MAP_ARB);
573         checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
574     }
575     glDisable(GL_TEXTURE_3D);
576     checkGLcall("glDisable GL_TEXTURE_3D");
577     glDisable(GL_TEXTURE_2D);
578     checkGLcall("glDisable GL_TEXTURE_2D");
579
580     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
581
582     glMatrixMode(GL_TEXTURE);
583     checkGLcall("glMatrixMode(GL_TEXTURE)");
584     glLoadIdentity();
585     checkGLcall("glLoadIdentity()");
586     Context_MarkStateDirty(context, STATE_TRANSFORM(WINED3DTS_TEXTURE0), StateTable);
587
588     if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
589         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
590                   GL_TEXTURE_LOD_BIAS_EXT,
591                   0.0);
592         checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
593     }
594     Context_MarkStateDirty(context, STATE_SAMPLER(0), StateTable);
595     Context_MarkStateDirty(context, STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP), StateTable);
596
597     /* Other misc states */
598     glDisable(GL_ALPHA_TEST);
599     checkGLcall("glDisable(GL_ALPHA_TEST)");
600     Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_ALPHATESTENABLE), StateTable);
601     glDisable(GL_LIGHTING);
602     checkGLcall("glDisable GL_LIGHTING");
603     Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_LIGHTING), StateTable);
604     glDisable(GL_DEPTH_TEST);
605     checkGLcall("glDisable GL_DEPTH_TEST");
606     Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_ZENABLE), StateTable);
607     glDisable(GL_FOG);
608     checkGLcall("glDisable GL_FOG");
609     Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_FOGENABLE), StateTable);
610     glDisable(GL_BLEND);
611     checkGLcall("glDisable GL_BLEND");
612     Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), StateTable);
613     glDisable(GL_CULL_FACE);
614     checkGLcall("glDisable GL_CULL_FACE");
615     Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_CULLMODE), StateTable);
616     glDisable(GL_STENCIL_TEST);
617     checkGLcall("glDisable GL_STENCIL_TEST");
618     Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_STENCILENABLE), StateTable);
619     glDisable(GL_SCISSOR_TEST);
620     checkGLcall("glDisable GL_SCISSOR_TEST");
621     Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE), StateTable);
622     if(GL_SUPPORT(ARB_POINT_SPRITE)) {
623         glDisable(GL_POINT_SPRITE_ARB);
624         checkGLcall("glDisable GL_POINT_SPRITE_ARB");
625         Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_POINTSPRITEENABLE), StateTable);
626     }
627     glColorMask(GL_TRUE, GL_TRUE,GL_TRUE,GL_TRUE);
628     checkGLcall("glColorMask");
629     Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_CLIPPING), StateTable);
630     if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
631         glDisable(GL_COLOR_SUM_EXT);
632         Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_SPECULARENABLE), StateTable);
633         checkGLcall("glDisable(GL_COLOR_SUM_EXT)");
634     }
635     if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
636         GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
637         Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_SPECULARENABLE), StateTable);
638         checkGLcall("glFinalCombinerInputNV");
639     }
640
641     /* Setup transforms */
642     glMatrixMode(GL_MODELVIEW);
643     checkGLcall("glMatrixMode(GL_MODELVIEW)");
644     glLoadIdentity();
645     checkGLcall("glLoadIdentity()");
646     Context_MarkStateDirty(context, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), StateTable);
647
648     glMatrixMode(GL_PROJECTION);
649     checkGLcall("glMatrixMode(GL_PROJECTION)");
650     glLoadIdentity();
651     checkGLcall("glLoadIdentity()");
652     glOrtho(0, width, height, 0, 0.0, -1.0);
653     checkGLcall("glOrtho");
654     Context_MarkStateDirty(context, STATE_TRANSFORM(WINED3DTS_PROJECTION), StateTable);
655
656     context->last_was_rhw = TRUE;
657     Context_MarkStateDirty(context, STATE_VDECL, StateTable); /* because of last_was_rhw = TRUE */
658
659     glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)");
660     glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)");
661     glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)");
662     glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)");
663     glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)");
664     glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)");
665     Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_CLIPPING), StateTable);
666
667     glViewport(0, 0, width, height);
668     checkGLcall("glViewport");
669     Context_MarkStateDirty(context, STATE_VIEWPORT, StateTable);
670
671     if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
672         glDisable(GL_TEXTURE_SHADER_NV);
673         checkGLcall("glDisable(GL_TEXTURE_SHADER_NV)");
674     } else if(GL_SUPPORT(ATI_FRAGMENT_SHADER)) {
675         glDisable(GL_FRAGMENT_SHADER_ATI);
676         checkGLcall("glDisable(GL_FRAGMENT_SHADER_ATI)");
677     }
678 }
679
680 /*****************************************************************************
681  * findThreadContextForSwapChain
682  *
683  * Searches a swapchain for all contexts and picks one for the thread tid.
684  * If none can be found the swapchain is requested to create a new context
685  *
686  *****************************************************************************/
687 static WineD3DContext *findThreadContextForSwapChain(IWineD3DSwapChain *swapchain, DWORD tid) {
688     int i;
689
690     for(i = 0; i < ((IWineD3DSwapChainImpl *) swapchain)->num_contexts; i++) {
691         if(((IWineD3DSwapChainImpl *) swapchain)->context[i]->tid == tid) {
692             return ((IWineD3DSwapChainImpl *) swapchain)->context[i];
693         }
694
695     }
696
697     /* Create a new context for the thread */
698     return IWineD3DSwapChainImpl_CreateContextForThread(swapchain);
699 }
700
701 /*****************************************************************************
702  * FindContext
703  *
704  * Finds a context for the current render target and thread
705  *
706  * Parameters:
707  *  target: Render target to find the context for
708  *  tid: Thread to activate the context for
709  *
710  * Returns: The needed context
711  *
712  *****************************************************************************/
713 static inline WineD3DContext *FindContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, DWORD tid, GLint *buffer) {
714     IWineD3DSwapChain *swapchain = NULL;
715     HRESULT hr;
716     BOOL readTexture = wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->render_offscreen;
717     WineD3DContext *context = This->activeContext;
718     BOOL oldRenderOffscreen = This->render_offscreen;
719     const WINED3DFORMAT oldFmt = ((IWineD3DSurfaceImpl *) This->lastActiveRenderTarget)->resource.format;
720     const WINED3DFORMAT newFmt = ((IWineD3DSurfaceImpl *) target)->resource.format;
721     const struct StateEntry *StateTable = This->shader_backend->StateTable;
722
723     /* To compensate the lack of format switching with some offscreen rendering methods and on onscreen buffers
724      * the alpha blend state changes with different render target formats
725      */
726     if(oldFmt != newFmt) {
727         const StaticPixelFormatDesc *old = getFormatDescEntry(oldFmt, NULL, NULL);
728         const StaticPixelFormatDesc *new = getFormatDescEntry(newFmt, NULL, NULL);
729
730         if((old->alphaMask && !new->alphaMask) || (!old->alphaMask && new->alphaMask)) {
731             Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), StateTable);
732         }
733     }
734
735     hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **) &swapchain);
736     if(hr == WINED3D_OK && swapchain) {
737         TRACE("Rendering onscreen\n");
738
739         context = findThreadContextForSwapChain(swapchain, tid);
740
741         This->render_offscreen = FALSE;
742         /* The context != This->activeContext will catch a NOP context change. This can occur
743          * if we are switching back to swapchain rendering in case of FBO or Back Buffer offscreen
744          * rendering. No context change is needed in that case
745          */
746
747         if(((IWineD3DSwapChainImpl *) swapchain)->frontBuffer == target) {
748             *buffer = GL_FRONT;
749         } else {
750             *buffer = GL_BACK;
751         }
752         if(wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER) {
753             if(This->pbufferContext && tid == This->pbufferContext->tid) {
754                 This->pbufferContext->tid = 0;
755             }
756         }
757         IWineD3DSwapChain_Release(swapchain);
758
759         if(oldRenderOffscreen) {
760             Context_MarkStateDirty(context, WINED3DTS_PROJECTION, StateTable);
761             Context_MarkStateDirty(context, STATE_VDECL, StateTable);
762             Context_MarkStateDirty(context, STATE_VIEWPORT, StateTable);
763             Context_MarkStateDirty(context, STATE_SCISSORRECT, StateTable);
764             Context_MarkStateDirty(context, STATE_FRONTFACE, StateTable);
765         }
766
767     } else {
768         TRACE("Rendering offscreen\n");
769         This->render_offscreen = TRUE;
770         *buffer = This->offscreenBuffer;
771
772         switch(wined3d_settings.offscreen_rendering_mode) {
773             case ORM_FBO:
774                 /* FBOs do not need a different context. Stay with whatever context is active at the moment */
775                 if(This->activeContext && tid == This->lastThread) {
776                     context = This->activeContext;
777                 } else {
778                     /* This may happen if the app jumps straight into offscreen rendering
779                      * Start using the context of the primary swapchain. tid == 0 is no problem
780                      * for findThreadContextForSwapChain.
781                      *
782                      * Can also happen on thread switches - in that case findThreadContextForSwapChain
783                      * is perfect to call.
784                      */
785                     context = findThreadContextForSwapChain(This->swapchains[0], tid);
786                 }
787                 break;
788
789             case ORM_PBUFFER:
790             {
791                 IWineD3DSurfaceImpl *targetimpl = (IWineD3DSurfaceImpl *) target;
792                 if(This->pbufferContext == NULL ||
793                    This->pbufferWidth < targetimpl->currentDesc.Width ||
794                    This->pbufferHeight < targetimpl->currentDesc.Height) {
795                     if(This->pbufferContext) {
796                         DestroyContext(This, This->pbufferContext);
797                     }
798
799                     /* The display is irrelevant here, the window is 0. But CreateContext needs a valid X connection.
800                      * Create the context on the same server as the primary swapchain. The primary swapchain is exists at this point.
801                      */
802                     This->pbufferContext = CreateContext(This, targetimpl,
803                             ((IWineD3DSwapChainImpl *) This->swapchains[0])->context[0]->win_handle,
804                             TRUE /* pbuffer */, &((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms);
805                     This->pbufferWidth = targetimpl->currentDesc.Width;
806                     This->pbufferHeight = targetimpl->currentDesc.Height;
807                    }
808
809                    if(This->pbufferContext) {
810                        if(This->pbufferContext->tid != 0 && This->pbufferContext->tid != tid) {
811                            FIXME("The PBuffr context is only supported for one thread for now!\n");
812                        }
813                        This->pbufferContext->tid = tid;
814                        context = This->pbufferContext;
815                        break;
816                    } else {
817                        ERR("Failed to create a buffer context and drawable, falling back to back buffer offscreen rendering\n");
818                        wined3d_settings.offscreen_rendering_mode = ORM_BACKBUFFER;
819                    }
820             }
821
822             case ORM_BACKBUFFER:
823                 /* Stay with the currently active context for back buffer rendering */
824                 if(This->activeContext && tid == This->lastThread) {
825                     context = This->activeContext;
826                 } else {
827                     /* This may happen if the app jumps straight into offscreen rendering
828                      * Start using the context of the primary swapchain. tid == 0 is no problem
829                      * for findThreadContextForSwapChain.
830                      *
831                      * Can also happen on thread switches - in that case findThreadContextForSwapChain
832                      * is perfect to call.
833                      */
834                     context = findThreadContextForSwapChain(This->swapchains[0], tid);
835                 }
836                 break;
837         }
838
839         if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) {
840             /* Make sure we have a OpenGL texture name so the PreLoad() used to read the buffer
841              * back when we are done won't mark us dirty.
842              */
843             IWineD3DSurface_PreLoad(target);
844         }
845
846         if(!oldRenderOffscreen) {
847             Context_MarkStateDirty(context, WINED3DTS_PROJECTION, StateTable);
848             Context_MarkStateDirty(context, STATE_VDECL, StateTable);
849             Context_MarkStateDirty(context, STATE_VIEWPORT, StateTable);
850             Context_MarkStateDirty(context, STATE_SCISSORRECT, StateTable);
851             Context_MarkStateDirty(context, STATE_FRONTFACE, StateTable);
852         }
853     }
854     if (readTexture) {
855         BOOL oldInDraw = This->isInDraw;
856
857         /* PreLoad requires a context to load the texture, thus it will call ActivateContext.
858          * Set the isInDraw to true to signal PreLoad that it has a context. Will be tricky
859          * when using offscreen rendering with multithreading
860          */
861         This->isInDraw = TRUE;
862
863         /* Do that before switching the context:
864          * Read the back buffer of the old drawable into the destination texture
865          */
866         IWineD3DSurface_PreLoad(This->lastActiveRenderTarget);
867
868         /* Assume that the drawable will be modified by some other things now */
869         IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, FALSE);
870
871         This->isInDraw = oldInDraw;
872     }
873
874     if(oldRenderOffscreen != This->render_offscreen && This->depth_copy_state != WINED3D_DCS_NO_COPY) {
875         This->depth_copy_state = WINED3D_DCS_COPY;
876     }
877     return context;
878 }
879
880 /*****************************************************************************
881  * ActivateContext
882  *
883  * Finds a rendering context and drawable matching the device and render
884  * target for the current thread, activates them and puts them into the
885  * requested state.
886  *
887  * Params:
888  *  This: Device to activate the context for
889  *  target: Requested render target
890  *  usage: Prepares the context for blitting, drawing or other actions
891  *
892  *****************************************************************************/
893 void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextUsage usage) {
894     DWORD                         tid = GetCurrentThreadId();
895     int                           i;
896     DWORD                         dirtyState, idx;
897     BYTE                          shift;
898     WineD3DContext                *context;
899     GLint                         drawBuffer=0;
900     const struct StateEntry       *StateTable = This->shader_backend->StateTable;
901
902     TRACE("(%p): Selecting context for render target %p, thread %d\n", This, target, tid);
903     if(This->lastActiveRenderTarget != target || tid != This->lastThread) {
904         context = FindContext(This, target, tid, &drawBuffer);
905         This->lastActiveRenderTarget = target;
906         This->lastThread = tid;
907     } else {
908         /* Stick to the old context */
909         context = This->activeContext;
910     }
911
912     /* Activate the opengl context */
913     if(context != This->activeContext) {
914         BOOL ret;
915
916         /* Prevent an unneeded context switch as those are expensive */
917         if(context->glCtx && (context->glCtx == pwglGetCurrentContext())) {
918             TRACE("Already using gl context %p\n", context->glCtx);
919         }
920         else {
921             TRACE("Switching gl ctx to %p, hdc=%p ctx=%p\n", context, context->hdc, context->glCtx);
922             ret = pwglMakeCurrent(context->hdc, context->glCtx);
923             if(ret == FALSE) {
924                 ERR("Failed to activate the new context\n");
925             }
926         }
927         if(This->activeContext->vshader_const_dirty) {
928             memset(This->activeContext->vshader_const_dirty, 1,
929                    sizeof(*This->activeContext->vshader_const_dirty) * GL_LIMITS(vshader_constantsF));
930         }
931         if(This->activeContext->pshader_const_dirty) {
932             memset(This->activeContext->pshader_const_dirty, 1,
933                    sizeof(*This->activeContext->pshader_const_dirty) * GL_LIMITS(pshader_constantsF));
934         }
935         This->activeContext = context;
936     }
937
938     /* We only need ENTER_GL for the gl calls made below and for the helper functions which make GL calls */
939     ENTER_GL();
940     /* Select the right draw buffer. It is selected in FindContext. */
941     if(drawBuffer && context->last_draw_buffer != drawBuffer) {
942         TRACE("Drawing to buffer: %#x\n", drawBuffer);
943         context->last_draw_buffer = drawBuffer;
944
945         glDrawBuffer(drawBuffer);
946         checkGLcall("glDrawBuffer");
947     }
948
949     switch(usage) {
950         case CTXUSAGE_RESOURCELOAD:
951             /* This does not require any special states to be set up */
952             break;
953
954         case CTXUSAGE_CLEAR:
955             if(context->last_was_blit) {
956                 if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
957                     glEnable(GL_TEXTURE_SHADER_NV);
958                     checkGLcall("glEnable(GL_TEXTURE_SHADER_NV)");
959                 } else if(GL_SUPPORT(ATI_FRAGMENT_SHADER)) {
960                     glEnable(GL_FRAGMENT_SHADER_ATI);
961                     checkGLcall("glEnable(GL_FRAGMENT_SHADER_ATI)");
962                 }
963             }
964
965             glEnable(GL_SCISSOR_TEST);
966             checkGLcall("glEnable GL_SCISSOR_TEST");
967             context->last_was_blit = FALSE;
968             Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE), StateTable);
969             Context_MarkStateDirty(context, STATE_SCISSORRECT, StateTable);
970             break;
971
972         case CTXUSAGE_DRAWPRIM:
973             /* This needs all dirty states applied */
974             if(context->last_was_blit) {
975                 if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
976                     glEnable(GL_TEXTURE_SHADER_NV);
977                     checkGLcall("glEnable(GL_TEXTURE_SHADER_NV)");
978                 } else if(GL_SUPPORT(ATI_FRAGMENT_SHADER)) {
979                     glEnable(GL_FRAGMENT_SHADER_ATI);
980                     checkGLcall("glEnable(GL_FRAGMENT_SHADER_ATI)");
981                 }
982             }
983
984             IWineD3DDeviceImpl_FindTexUnitMap(This);
985
986             for(i=0; i < context->numDirtyEntries; i++) {
987                 dirtyState = context->dirtyArray[i];
988                 idx = dirtyState >> 5;
989                 shift = dirtyState & 0x1f;
990                 context->isStateDirty[idx] &= ~(1 << shift);
991                 StateTable[dirtyState].apply(dirtyState, This->stateBlock, context);
992             }
993             context->numDirtyEntries = 0; /* This makes the whole list clean */
994             context->last_was_blit = FALSE;
995             break;
996
997         case CTXUSAGE_BLIT:
998             SetupForBlit(This, context,
999                          ((IWineD3DSurfaceImpl *)target)->currentDesc.Width,
1000                          ((IWineD3DSurfaceImpl *)target)->currentDesc.Height);
1001             break;
1002
1003         default:
1004             FIXME("Unexpected context usage requested\n");
1005     }
1006     LEAVE_GL();
1007 }