f3773edd6abbe587185b068fd3265fccad47c738
[mesa.git] / src / gallium / state_trackers / wgl / stw_context.c
1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include <windows.h>
29
30 #define WGL_WGLEXT_PROTOTYPES
31
32 #include <GL/gl.h>
33 #include <GL/wglext.h>
34
35 #include "pipe/p_compiler.h"
36 #include "pipe/p_context.h"
37 #include "pipe/p_state.h"
38 #include "util/u_memory.h"
39 #include "util/u_atomic.h"
40 #include "state_tracker/st_api.h"
41 #include "hud/hud_context.h"
42
43 #include "stw_icd.h"
44 #include "stw_device.h"
45 #include "stw_winsys.h"
46 #include "stw_framebuffer.h"
47 #include "stw_pixelformat.h"
48 #include "stw_context.h"
49 #include "stw_tls.h"
50
51
52 struct stw_context *
53 stw_current_context(void)
54 {
55 struct st_context_iface *st;
56
57 st = (stw_dev) ? stw_dev->stapi->get_current(stw_dev->stapi) : NULL;
58
59 return (struct stw_context *) ((st) ? st->st_manager_private : NULL);
60 }
61
62 BOOL APIENTRY
63 DrvCopyContext(
64 DHGLRC dhrcSource,
65 DHGLRC dhrcDest,
66 UINT fuMask )
67 {
68 struct stw_context *src;
69 struct stw_context *dst;
70 BOOL ret = FALSE;
71
72 if (!stw_dev)
73 return FALSE;
74
75 pipe_mutex_lock( stw_dev->ctx_mutex );
76
77 src = stw_lookup_context_locked( dhrcSource );
78 dst = stw_lookup_context_locked( dhrcDest );
79
80 if (src && dst) {
81 /* FIXME */
82 assert(0);
83 (void) src;
84 (void) dst;
85 (void) fuMask;
86 }
87
88 pipe_mutex_unlock( stw_dev->ctx_mutex );
89
90 return ret;
91 }
92
93 BOOL APIENTRY
94 DrvShareLists(
95 DHGLRC dhglrc1,
96 DHGLRC dhglrc2 )
97 {
98 struct stw_context *ctx1;
99 struct stw_context *ctx2;
100 BOOL ret = FALSE;
101
102 if (!stw_dev)
103 return FALSE;
104
105 pipe_mutex_lock( stw_dev->ctx_mutex );
106
107 ctx1 = stw_lookup_context_locked( dhglrc1 );
108 ctx2 = stw_lookup_context_locked( dhglrc2 );
109
110 if (ctx1 && ctx2 && ctx2->st->share)
111 ret = ctx2->st->share(ctx2->st, ctx1->st);
112
113 pipe_mutex_unlock( stw_dev->ctx_mutex );
114
115 return ret;
116 }
117
118 DHGLRC APIENTRY
119 DrvCreateContext(
120 HDC hdc )
121 {
122 return DrvCreateLayerContext( hdc, 0 );
123 }
124
125 DHGLRC APIENTRY
126 DrvCreateLayerContext(
127 HDC hdc,
128 INT iLayerPlane )
129 {
130 return stw_create_context_attribs(hdc, iLayerPlane, 0, 1, 0, 0,
131 WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
132 }
133
134 DHGLRC
135 stw_create_context_attribs(
136 HDC hdc,
137 INT iLayerPlane,
138 DHGLRC hShareContext,
139 int majorVersion, int minorVersion,
140 int contextFlags, int profileMask)
141 {
142 int iPixelFormat;
143 struct stw_framebuffer *fb;
144 const struct stw_pixelformat_info *pfi;
145 struct st_context_attribs attribs;
146 struct stw_context *ctx = NULL;
147 struct stw_context *shareCtx = NULL;
148 enum st_context_error ctx_err = 0;
149
150 if (!stw_dev)
151 return 0;
152
153 if (iLayerPlane != 0)
154 return 0;
155
156 iPixelFormat = GetPixelFormat(hdc);
157 if(!iPixelFormat)
158 return 0;
159
160 /*
161 * GDI only knows about displayable pixel formats, so determine the pixel
162 * format from the framebuffer.
163 *
164 * TODO: Remove the GetPixelFormat() above, and stop relying on GDI.
165 */
166 fb = stw_framebuffer_from_hdc( hdc );
167 if (fb) {
168 assert(iPixelFormat == fb->iDisplayablePixelFormat);
169 iPixelFormat = fb->iPixelFormat;
170 stw_framebuffer_release(fb);
171 }
172
173 pfi = stw_pixelformat_get_info( iPixelFormat );
174
175 if (hShareContext != 0) {
176 pipe_mutex_lock( stw_dev->ctx_mutex );
177 shareCtx = stw_lookup_context_locked( hShareContext );
178 pipe_mutex_unlock( stw_dev->ctx_mutex );
179 }
180
181 ctx = CALLOC_STRUCT( stw_context );
182 if (ctx == NULL)
183 goto no_ctx;
184
185 ctx->hdc = hdc;
186 ctx->iPixelFormat = iPixelFormat;
187
188 memset(&attribs, 0, sizeof(attribs));
189 attribs.visual = pfi->stvis;
190 attribs.major = majorVersion;
191 attribs.minor = minorVersion;
192 if (contextFlags & WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB)
193 attribs.flags |= ST_CONTEXT_FLAG_FORWARD_COMPATIBLE;
194 if (contextFlags & WGL_CONTEXT_DEBUG_BIT_ARB)
195 attribs.flags |= ST_CONTEXT_FLAG_DEBUG;
196
197 /* There are no profiles before OpenGL 3.2. The
198 * WGL_ARB_create_context_profile spec says:
199 *
200 * "If the requested OpenGL version is less than 3.2,
201 * WGL_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality of the
202 * context is determined solely by the requested version."
203 *
204 * The spec also says:
205 *
206 * "The default value for WGL_CONTEXT_PROFILE_MASK_ARB is
207 * WGL_CONTEXT_CORE_PROFILE_BIT_ARB."
208 */
209 attribs.profile = ST_PROFILE_DEFAULT;
210 if ((majorVersion > 3 || (majorVersion == 3 && minorVersion >= 2))
211 && ((profileMask & WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB) == 0))
212 attribs.profile = ST_PROFILE_OPENGL_CORE;
213
214 ctx->st = stw_dev->stapi->create_context(stw_dev->stapi,
215 stw_dev->smapi, &attribs, &ctx_err, shareCtx ? shareCtx->st : NULL);
216 if (ctx->st == NULL)
217 goto no_st_ctx;
218
219 ctx->st->st_manager_private = (void *) ctx;
220
221 if (ctx->st->cso_context) {
222 ctx->hud = hud_create(ctx->st->pipe, ctx->st->cso_context);
223 }
224
225 pipe_mutex_lock( stw_dev->ctx_mutex );
226 ctx->dhglrc = handle_table_add(stw_dev->ctx_table, ctx);
227 pipe_mutex_unlock( stw_dev->ctx_mutex );
228 if (!ctx->dhglrc)
229 goto no_hglrc;
230
231 return ctx->dhglrc;
232
233 no_hglrc:
234 if (ctx->hud) {
235 hud_destroy(ctx->hud);
236 }
237 ctx->st->destroy(ctx->st);
238 no_st_ctx:
239 FREE(ctx);
240 no_ctx:
241 return 0;
242 }
243
244 BOOL APIENTRY
245 DrvDeleteContext(
246 DHGLRC dhglrc )
247 {
248 struct stw_context *ctx ;
249 BOOL ret = FALSE;
250
251 if (!stw_dev)
252 return FALSE;
253
254 pipe_mutex_lock( stw_dev->ctx_mutex );
255 ctx = stw_lookup_context_locked(dhglrc);
256 handle_table_remove(stw_dev->ctx_table, dhglrc);
257 pipe_mutex_unlock( stw_dev->ctx_mutex );
258
259 if (ctx) {
260 struct stw_context *curctx = stw_current_context();
261
262 /* Unbind current if deleting current context. */
263 if (curctx == ctx)
264 stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
265
266 if (ctx->hud) {
267 hud_destroy(ctx->hud);
268 }
269
270 ctx->st->destroy(ctx->st);
271 FREE(ctx);
272
273 ret = TRUE;
274 }
275
276 return ret;
277 }
278
279 BOOL APIENTRY
280 DrvReleaseContext(
281 DHGLRC dhglrc )
282 {
283 struct stw_context *ctx;
284
285 if (!stw_dev)
286 return FALSE;
287
288 pipe_mutex_lock( stw_dev->ctx_mutex );
289 ctx = stw_lookup_context_locked( dhglrc );
290 pipe_mutex_unlock( stw_dev->ctx_mutex );
291
292 if (!ctx)
293 return FALSE;
294
295 /* The expectation is that ctx is the same context which is
296 * current for this thread. We should check that and return False
297 * if not the case.
298 */
299 if (ctx != stw_current_context())
300 return FALSE;
301
302 if (stw_make_current( NULL, 0 ) == FALSE)
303 return FALSE;
304
305 return TRUE;
306 }
307
308
309 DHGLRC
310 stw_get_current_context( void )
311 {
312 struct stw_context *ctx;
313
314 ctx = stw_current_context();
315 if(!ctx)
316 return 0;
317
318 return ctx->dhglrc;
319 }
320
321 HDC
322 stw_get_current_dc( void )
323 {
324 struct stw_context *ctx;
325
326 ctx = stw_current_context();
327 if(!ctx)
328 return NULL;
329
330 return ctx->hdc;
331 }
332
333 BOOL
334 stw_make_current(
335 HDC hdc,
336 DHGLRC dhglrc )
337 {
338 struct stw_context *curctx = NULL;
339 struct stw_context *ctx = NULL;
340 struct stw_framebuffer *fb = NULL;
341 BOOL ret = FALSE;
342
343 if (!stw_dev)
344 return FALSE;
345
346 curctx = stw_current_context();
347 if (curctx != NULL) {
348 if (curctx->dhglrc == dhglrc) {
349 if (curctx->hdc == hdc) {
350 /* Return if already current. */
351 return TRUE;
352 }
353 } else {
354 curctx->st->flush(curctx->st, ST_FLUSH_FRONT, NULL);
355 }
356 }
357
358 if (dhglrc) {
359 pipe_mutex_lock( stw_dev->ctx_mutex );
360 ctx = stw_lookup_context_locked( dhglrc );
361 pipe_mutex_unlock( stw_dev->ctx_mutex );
362 if (!ctx) {
363 goto fail;
364 }
365
366 fb = stw_framebuffer_from_hdc( hdc );
367 if (fb) {
368 stw_framebuffer_update(fb);
369 }
370 else {
371 /* Applications should call SetPixelFormat before creating a context,
372 * but not all do, and the opengl32 runtime seems to use a default pixel
373 * format in some cases, so we must create a framebuffer for those here
374 */
375 int iPixelFormat = GetPixelFormat(hdc);
376 if (iPixelFormat)
377 fb = stw_framebuffer_create( hdc, iPixelFormat );
378 if (!fb)
379 goto fail;
380 }
381
382 if (fb->iPixelFormat != ctx->iPixelFormat) {
383 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
384 goto fail;
385 }
386
387 /* Bind the new framebuffer */
388 ctx->hdc = hdc;
389
390 ret = stw_dev->stapi->make_current(stw_dev->stapi, ctx->st,
391 fb->stfb, fb->stfb);
392 stw_framebuffer_reference(&ctx->current_framebuffer, fb);
393 } else {
394 ret = stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
395 }
396
397 fail:
398
399 if (fb) {
400 stw_framebuffer_release(fb);
401 }
402
403 /* On failure, make the thread's current rendering context not current
404 * before returning */
405 if (!ret) {
406 stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
407 ctx = NULL;
408 }
409
410 /* Unreference the previous framebuffer if any. It must be done after
411 * make_current, as it can be referenced inside.
412 */
413 if (curctx && curctx != ctx) {
414 stw_framebuffer_reference(&curctx->current_framebuffer, NULL);
415 }
416
417 return ret;
418 }
419
420 /**
421 * Flush the current context if it is bound to the framebuffer.
422 */
423 void
424 stw_flush_current_locked( struct stw_framebuffer *fb )
425 {
426 struct stw_context *ctx = stw_current_context();
427
428 if (ctx && ctx->current_framebuffer == fb) {
429 ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL);
430 }
431 }
432
433 /**
434 * Notify the current context that the framebuffer has become invalid.
435 */
436 void
437 stw_notify_current_locked( struct stw_framebuffer *fb )
438 {
439 p_atomic_inc(&fb->stfb->stamp);
440 }
441
442 /**
443 * Although WGL allows different dispatch entrypoints per context
444 */
445 static const GLCLTPROCTABLE cpt =
446 {
447 OPENGL_VERSION_110_ENTRIES,
448 {
449 &glNewList,
450 &glEndList,
451 &glCallList,
452 &glCallLists,
453 &glDeleteLists,
454 &glGenLists,
455 &glListBase,
456 &glBegin,
457 &glBitmap,
458 &glColor3b,
459 &glColor3bv,
460 &glColor3d,
461 &glColor3dv,
462 &glColor3f,
463 &glColor3fv,
464 &glColor3i,
465 &glColor3iv,
466 &glColor3s,
467 &glColor3sv,
468 &glColor3ub,
469 &glColor3ubv,
470 &glColor3ui,
471 &glColor3uiv,
472 &glColor3us,
473 &glColor3usv,
474 &glColor4b,
475 &glColor4bv,
476 &glColor4d,
477 &glColor4dv,
478 &glColor4f,
479 &glColor4fv,
480 &glColor4i,
481 &glColor4iv,
482 &glColor4s,
483 &glColor4sv,
484 &glColor4ub,
485 &glColor4ubv,
486 &glColor4ui,
487 &glColor4uiv,
488 &glColor4us,
489 &glColor4usv,
490 &glEdgeFlag,
491 &glEdgeFlagv,
492 &glEnd,
493 &glIndexd,
494 &glIndexdv,
495 &glIndexf,
496 &glIndexfv,
497 &glIndexi,
498 &glIndexiv,
499 &glIndexs,
500 &glIndexsv,
501 &glNormal3b,
502 &glNormal3bv,
503 &glNormal3d,
504 &glNormal3dv,
505 &glNormal3f,
506 &glNormal3fv,
507 &glNormal3i,
508 &glNormal3iv,
509 &glNormal3s,
510 &glNormal3sv,
511 &glRasterPos2d,
512 &glRasterPos2dv,
513 &glRasterPos2f,
514 &glRasterPos2fv,
515 &glRasterPos2i,
516 &glRasterPos2iv,
517 &glRasterPos2s,
518 &glRasterPos2sv,
519 &glRasterPos3d,
520 &glRasterPos3dv,
521 &glRasterPos3f,
522 &glRasterPos3fv,
523 &glRasterPos3i,
524 &glRasterPos3iv,
525 &glRasterPos3s,
526 &glRasterPos3sv,
527 &glRasterPos4d,
528 &glRasterPos4dv,
529 &glRasterPos4f,
530 &glRasterPos4fv,
531 &glRasterPos4i,
532 &glRasterPos4iv,
533 &glRasterPos4s,
534 &glRasterPos4sv,
535 &glRectd,
536 &glRectdv,
537 &glRectf,
538 &glRectfv,
539 &glRecti,
540 &glRectiv,
541 &glRects,
542 &glRectsv,
543 &glTexCoord1d,
544 &glTexCoord1dv,
545 &glTexCoord1f,
546 &glTexCoord1fv,
547 &glTexCoord1i,
548 &glTexCoord1iv,
549 &glTexCoord1s,
550 &glTexCoord1sv,
551 &glTexCoord2d,
552 &glTexCoord2dv,
553 &glTexCoord2f,
554 &glTexCoord2fv,
555 &glTexCoord2i,
556 &glTexCoord2iv,
557 &glTexCoord2s,
558 &glTexCoord2sv,
559 &glTexCoord3d,
560 &glTexCoord3dv,
561 &glTexCoord3f,
562 &glTexCoord3fv,
563 &glTexCoord3i,
564 &glTexCoord3iv,
565 &glTexCoord3s,
566 &glTexCoord3sv,
567 &glTexCoord4d,
568 &glTexCoord4dv,
569 &glTexCoord4f,
570 &glTexCoord4fv,
571 &glTexCoord4i,
572 &glTexCoord4iv,
573 &glTexCoord4s,
574 &glTexCoord4sv,
575 &glVertex2d,
576 &glVertex2dv,
577 &glVertex2f,
578 &glVertex2fv,
579 &glVertex2i,
580 &glVertex2iv,
581 &glVertex2s,
582 &glVertex2sv,
583 &glVertex3d,
584 &glVertex3dv,
585 &glVertex3f,
586 &glVertex3fv,
587 &glVertex3i,
588 &glVertex3iv,
589 &glVertex3s,
590 &glVertex3sv,
591 &glVertex4d,
592 &glVertex4dv,
593 &glVertex4f,
594 &glVertex4fv,
595 &glVertex4i,
596 &glVertex4iv,
597 &glVertex4s,
598 &glVertex4sv,
599 &glClipPlane,
600 &glColorMaterial,
601 &glCullFace,
602 &glFogf,
603 &glFogfv,
604 &glFogi,
605 &glFogiv,
606 &glFrontFace,
607 &glHint,
608 &glLightf,
609 &glLightfv,
610 &glLighti,
611 &glLightiv,
612 &glLightModelf,
613 &glLightModelfv,
614 &glLightModeli,
615 &glLightModeliv,
616 &glLineStipple,
617 &glLineWidth,
618 &glMaterialf,
619 &glMaterialfv,
620 &glMateriali,
621 &glMaterialiv,
622 &glPointSize,
623 &glPolygonMode,
624 &glPolygonStipple,
625 &glScissor,
626 &glShadeModel,
627 &glTexParameterf,
628 &glTexParameterfv,
629 &glTexParameteri,
630 &glTexParameteriv,
631 &glTexImage1D,
632 &glTexImage2D,
633 &glTexEnvf,
634 &glTexEnvfv,
635 &glTexEnvi,
636 &glTexEnviv,
637 &glTexGend,
638 &glTexGendv,
639 &glTexGenf,
640 &glTexGenfv,
641 &glTexGeni,
642 &glTexGeniv,
643 &glFeedbackBuffer,
644 &glSelectBuffer,
645 &glRenderMode,
646 &glInitNames,
647 &glLoadName,
648 &glPassThrough,
649 &glPopName,
650 &glPushName,
651 &glDrawBuffer,
652 &glClear,
653 &glClearAccum,
654 &glClearIndex,
655 &glClearColor,
656 &glClearStencil,
657 &glClearDepth,
658 &glStencilMask,
659 &glColorMask,
660 &glDepthMask,
661 &glIndexMask,
662 &glAccum,
663 &glDisable,
664 &glEnable,
665 &glFinish,
666 &glFlush,
667 &glPopAttrib,
668 &glPushAttrib,
669 &glMap1d,
670 &glMap1f,
671 &glMap2d,
672 &glMap2f,
673 &glMapGrid1d,
674 &glMapGrid1f,
675 &glMapGrid2d,
676 &glMapGrid2f,
677 &glEvalCoord1d,
678 &glEvalCoord1dv,
679 &glEvalCoord1f,
680 &glEvalCoord1fv,
681 &glEvalCoord2d,
682 &glEvalCoord2dv,
683 &glEvalCoord2f,
684 &glEvalCoord2fv,
685 &glEvalMesh1,
686 &glEvalPoint1,
687 &glEvalMesh2,
688 &glEvalPoint2,
689 &glAlphaFunc,
690 &glBlendFunc,
691 &glLogicOp,
692 &glStencilFunc,
693 &glStencilOp,
694 &glDepthFunc,
695 &glPixelZoom,
696 &glPixelTransferf,
697 &glPixelTransferi,
698 &glPixelStoref,
699 &glPixelStorei,
700 &glPixelMapfv,
701 &glPixelMapuiv,
702 &glPixelMapusv,
703 &glReadBuffer,
704 &glCopyPixels,
705 &glReadPixels,
706 &glDrawPixels,
707 &glGetBooleanv,
708 &glGetClipPlane,
709 &glGetDoublev,
710 &glGetError,
711 &glGetFloatv,
712 &glGetIntegerv,
713 &glGetLightfv,
714 &glGetLightiv,
715 &glGetMapdv,
716 &glGetMapfv,
717 &glGetMapiv,
718 &glGetMaterialfv,
719 &glGetMaterialiv,
720 &glGetPixelMapfv,
721 &glGetPixelMapuiv,
722 &glGetPixelMapusv,
723 &glGetPolygonStipple,
724 &glGetString,
725 &glGetTexEnvfv,
726 &glGetTexEnviv,
727 &glGetTexGendv,
728 &glGetTexGenfv,
729 &glGetTexGeniv,
730 &glGetTexImage,
731 &glGetTexParameterfv,
732 &glGetTexParameteriv,
733 &glGetTexLevelParameterfv,
734 &glGetTexLevelParameteriv,
735 &glIsEnabled,
736 &glIsList,
737 &glDepthRange,
738 &glFrustum,
739 &glLoadIdentity,
740 &glLoadMatrixf,
741 &glLoadMatrixd,
742 &glMatrixMode,
743 &glMultMatrixf,
744 &glMultMatrixd,
745 &glOrtho,
746 &glPopMatrix,
747 &glPushMatrix,
748 &glRotated,
749 &glRotatef,
750 &glScaled,
751 &glScalef,
752 &glTranslated,
753 &glTranslatef,
754 &glViewport,
755 &glArrayElement,
756 &glBindTexture,
757 &glColorPointer,
758 &glDisableClientState,
759 &glDrawArrays,
760 &glDrawElements,
761 &glEdgeFlagPointer,
762 &glEnableClientState,
763 &glIndexPointer,
764 &glIndexub,
765 &glIndexubv,
766 &glInterleavedArrays,
767 &glNormalPointer,
768 &glPolygonOffset,
769 &glTexCoordPointer,
770 &glVertexPointer,
771 &glAreTexturesResident,
772 &glCopyTexImage1D,
773 &glCopyTexImage2D,
774 &glCopyTexSubImage1D,
775 &glCopyTexSubImage2D,
776 &glDeleteTextures,
777 &glGenTextures,
778 &glGetPointerv,
779 &glIsTexture,
780 &glPrioritizeTextures,
781 &glTexSubImage1D,
782 &glTexSubImage2D,
783 &glPopClientAttrib,
784 &glPushClientAttrib
785 }
786 };
787
788 PGLCLTPROCTABLE APIENTRY
789 DrvSetContext(
790 HDC hdc,
791 DHGLRC dhglrc,
792 PFN_SETPROCTABLE pfnSetProcTable )
793 {
794 PGLCLTPROCTABLE r = (PGLCLTPROCTABLE)&cpt;
795
796 if (!stw_make_current( hdc, dhglrc ))
797 r = NULL;
798
799 return r;
800 }