eglcontext.c revision adbff7e977c7c768e752a24fb643d68bdf961bfe
1#include <assert.h>
2#include <stdlib.h>
3#include <string.h>
4#include "eglconfig.h"
5#include "eglcontext.h"
6#include "egldriver.h"
7#include "eglglobals.h"
8#include "eglhash.h"
9#include "eglsurface.h"
10
11
12/**
13 * Initialize the given _EGLContext object to defaults.
14 */
15void
16_eglInitContext(_EGLContext *ctx)
17{
18   /* just init to zer for now */
19   memset(ctx, 0, sizeof(_EGLContext));
20}
21
22
23/*
24 * Assign an EGLContext handle to the _EGLContext object then put it into
25 * the hash table.
26 */
27void
28_eglSaveContext(_EGLContext *ctx)
29{
30   assert(ctx);
31   ctx->Handle = _eglHashGenKey(_eglGlobal.Contexts);
32   _eglHashInsert(_eglGlobal.Contexts, ctx->Handle, ctx);
33}
34
35
36/**
37 * Remove the given _EGLContext object from the hash table.
38 */
39void
40_eglRemoveContext(_EGLContext *ctx)
41{
42   _eglHashRemove(_eglGlobal.Contexts, ctx->Handle);
43}
44
45
46/**
47 * Return the _EGLContext object that corresponds to the given
48 * EGLContext handle.
49 */
50_EGLContext *
51_eglLookupContext(EGLContext ctx)
52{
53   _EGLContext *c = (_EGLContext *) _eglHashLookup(_eglGlobal.Contexts, ctx);
54   return c;
55}
56
57
58/**
59 * Return the currently bound _EGLContext object, or NULL.
60 */
61_EGLContext *
62_eglGetCurrentContext(void)
63{
64   /* XXX this should be per-thread someday */
65   return _eglGlobal.CurrentContext;
66}
67
68
69/**
70 * Just a placeholder/demo function.  Real driver will never use this!
71 */
72EGLContext
73_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list)
74{
75   _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
76   if (!conf) {
77      _eglError(EGL_BAD_CONFIG, "eglCreateContext");
78      return EGL_NO_CONTEXT;
79   }
80
81   if (share_list != EGL_NO_CONTEXT) {
82      _EGLContext *shareCtx = _eglLookupContext(share_list);
83      if (!shareCtx) {
84         _eglError(EGL_BAD_CONTEXT, "eglCreateContext(share_list)");
85         return EGL_NO_CONTEXT;
86      }
87   }
88
89   return EGL_NO_CONTEXT;
90}
91
92
93/**
94 * Default fallback routine - drivers should usually override this.
95 */
96EGLBoolean
97_eglDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx)
98{
99   _EGLContext *context = _eglLookupContext(ctx);
100   if (context) {
101      _eglHashRemove(_eglGlobal.Contexts, ctx);
102      if (context->IsBound) {
103         context->DeletePending = EGL_TRUE;
104      }
105      else {
106         free(context);
107      }
108      return EGL_TRUE;
109   }
110   else {
111      _eglError(EGL_BAD_CONTEXT, "eglDestroyContext");
112      return EGL_TRUE;
113   }
114}
115
116
117EGLBoolean
118_eglQueryContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
119{
120   _EGLContext *c = _eglLookupContext(ctx);
121
122   (void) drv;
123   (void) dpy;
124
125   if (!c) {
126      _eglError(EGL_BAD_CONTEXT, "eglQueryContext");
127      return EGL_FALSE;
128   }
129
130   switch (attribute) {
131   case EGL_CONFIG_ID:
132      *value = GET_CONFIG_ATTRIB(c->Config, EGL_CONFIG_ID);
133      return EGL_TRUE;
134   default:
135      _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
136      return EGL_FALSE;
137   }
138}
139
140
141/**
142 * Drivers will typically call this to do the error checking and
143 * update the various IsBound and DeletePending flags.
144 * Then, the driver will do its device-dependent Make-Current stuff.
145 */
146EGLBoolean
147_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d, EGLSurface r, EGLContext context)
148{
149   _EGLContext *ctx = _eglLookupContext(context);
150   _EGLSurface *draw = _eglLookupSurface(d);
151   _EGLSurface *read = _eglLookupSurface(r);
152
153   _EGLContext *oldContext = _eglGetCurrentContext();
154   _EGLSurface *oldDrawSurface = _eglGetCurrentSurface(EGL_DRAW);
155   _EGLSurface *oldReadSurface = _eglGetCurrentSurface(EGL_READ);
156
157   /* error checking */
158   if (ctx) {
159      if (draw == NULL || read == NULL) {
160         _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
161         return EGL_FALSE;
162      }
163      if (draw->Config != ctx->Config) {
164         _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
165         return EGL_FALSE;
166      }
167      if (read->Config != ctx->Config) {
168         _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
169         return EGL_FALSE;
170      }
171   }
172
173   /*
174    * check if the old context or surfaces need to be deleted
175    */
176   if (oldDrawSurface != NULL) {
177      oldDrawSurface->IsBound = EGL_FALSE;
178      if (oldDrawSurface->DeletePending) {
179         /* make sure we don't try to rebind a deleted surface */
180         if (draw == oldDrawSurface || draw == oldReadSurface) {
181            draw = NULL;
182         }
183         /* really delete surface now */
184         drv->DestroySurface(drv, dpy, oldDrawSurface->Handle);
185      }
186   }
187   if (oldReadSurface != NULL && oldReadSurface != oldDrawSurface) {
188      oldReadSurface->IsBound = EGL_FALSE;
189      if (oldReadSurface->DeletePending) {
190         /* make sure we don't try to rebind a deleted surface */
191         if (read == oldDrawSurface || read == oldReadSurface) {
192            read = NULL;
193         }
194         /* really delete surface now */
195         drv->DestroySurface(drv, dpy, oldReadSurface->Handle);
196      }
197   }
198   if (oldContext != NULL) {
199      oldContext->IsBound = EGL_FALSE;
200      if (oldContext->DeletePending) {
201         /* make sure we don't try to rebind a deleted context */
202         if (ctx == oldContext) {
203            ctx = NULL;
204         }
205         /* really delete context now */
206         drv->DestroyContext(drv, dpy, oldContext->Handle);
207      }
208   }
209
210   if (ctx) {
211      /* check read/draw again, in case we deleted them above */
212      if (draw == NULL || read == NULL) {
213         _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
214         return EGL_FALSE;
215      }
216      ctx->DrawSurface = draw;
217      ctx->ReadSurface = read;
218      ctx->IsBound = EGL_TRUE;
219      draw->IsBound = EGL_TRUE;
220      read->IsBound = EGL_TRUE;
221   }
222
223   _eglGlobal.CurrentContext = ctx;
224
225   return EGL_TRUE;
226}
227