Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * Copyright © 2011 Intel Corporation | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice (including the next | |
12 | * paragraph) shall be included in all copies or substantial portions of the | |
13 | * Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
21 | * DEALINGS IN THE SOFTWARE. | |
22 | */ | |
23 | #ifdef HAVE_DIX_CONFIG_H | |
24 | #include <dix-config.h> | |
25 | #endif | |
26 | ||
27 | #include <GL/glxtokens.h> | |
28 | #include "glxserver.h" | |
29 | #include "glxext.h" | |
30 | #include "indirect_dispatch.h" | |
31 | ||
32 | #define ALL_VALID_FLAGS \ | |
33 | (GLX_CONTEXT_DEBUG_BIT_ARB | GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB \ | |
34 | | GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB) | |
35 | ||
36 | static Bool | |
37 | validate_GL_version(int major_version, int minor_version) | |
38 | { | |
39 | if (major_version <= 0 || minor_version < 0) | |
40 | return False; | |
41 | ||
42 | switch (major_version) { | |
43 | case 1: | |
44 | if (minor_version > 5) | |
45 | return False; | |
46 | break; | |
47 | ||
48 | case 2: | |
49 | if (minor_version > 1) | |
50 | return False; | |
51 | break; | |
52 | ||
53 | case 3: | |
54 | if (minor_version > 3) | |
55 | return False; | |
56 | break; | |
57 | ||
58 | default: | |
59 | break; | |
60 | } | |
61 | ||
62 | return True; | |
63 | } | |
64 | ||
65 | static Bool | |
66 | validate_render_type(uint32_t render_type) | |
67 | { | |
68 | switch (render_type) { | |
69 | case GLX_RGBA_TYPE: | |
70 | case GLX_COLOR_INDEX_TYPE: | |
71 | case GLX_RGBA_FLOAT_TYPE_ARB: | |
72 | case GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT: | |
73 | return True; | |
74 | default: | |
75 | return False; | |
76 | } | |
77 | } | |
78 | ||
79 | int | |
80 | __glXDisp_CreateContextAttribsARB(__GLXclientState * cl, GLbyte * pc) | |
81 | { | |
82 | ClientPtr client = cl->client; | |
83 | xGLXCreateContextAttribsARBReq *req = (xGLXCreateContextAttribsARBReq *) pc; | |
84 | int32_t *attribs = (req->numAttribs != 0) ? (int32_t *) (req + 1) : NULL; | |
85 | unsigned i; | |
86 | int major_version = 1; | |
87 | int minor_version = 0; | |
88 | uint32_t flags = 0; | |
89 | uint32_t render_type = GLX_RGBA_TYPE; | |
90 | __GLXcontext *ctx = NULL; | |
91 | __GLXcontext *shareCtx = NULL; | |
92 | __GLXscreen *glxScreen; | |
93 | __GLXconfig *config; | |
94 | int err; | |
95 | ||
96 | /* The GLX_ARB_create_context_robustness spec says: | |
97 | * | |
98 | * "The default value for GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB | |
99 | * is GLX_NO_RESET_NOTIFICATION_ARB." | |
100 | */ | |
101 | int reset = GLX_NO_RESET_NOTIFICATION_ARB; | |
102 | ||
103 | /* The GLX_ARB_create_context_profile spec says: | |
104 | * | |
105 | * "The default value for GLX_CONTEXT_PROFILE_MASK_ARB is | |
106 | * GLX_CONTEXT_CORE_PROFILE_BIT_ARB." | |
107 | * | |
108 | * The core profile only makes sense for OpenGL versions 3.2 and later. | |
109 | * If the version ultimately specified is less than 3.2, the core profile | |
110 | * bit is cleared (see below). | |
111 | */ | |
112 | int profile = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; | |
113 | ||
114 | /* Verify that the size of the packet matches the size inferred from the | |
115 | * sizes specified for the various fields. | |
116 | */ | |
117 | const unsigned expected_size = (sz_xGLXCreateContextAttribsARBReq | |
118 | + (req->numAttribs * 8)) / 4; | |
119 | ||
120 | if (req->length != expected_size) | |
121 | return BadLength; | |
122 | ||
123 | LEGAL_NEW_RESOURCE(req->context, client); | |
124 | ||
125 | /* The GLX_ARB_create_context spec says: | |
126 | * | |
127 | * "* If <config> is not a valid GLXFBConfig, GLXBadFBConfig is | |
128 | * generated." | |
129 | * | |
130 | * On the client, the screen comes from the FBConfig, so GLXBadFBConfig | |
131 | * should be issued if the screen is nonsense. | |
132 | */ | |
133 | if (!validGlxScreen(client, req->screen, &glxScreen, &err)) | |
134 | return __glXError(GLXBadFBConfig); | |
135 | ||
136 | if (!validGlxFBConfig(client, glxScreen, req->fbconfig, &config, &err)) | |
137 | return __glXError(GLXBadFBConfig); | |
138 | ||
139 | /* Validate the context with which the new context should share resources. | |
140 | */ | |
141 | if (req->shareList != None) { | |
142 | if (!validGlxContext(client, req->shareList, DixReadAccess, | |
143 | &shareCtx, &err)) | |
144 | return err; | |
145 | ||
146 | /* The crazy condition is because C doesn't have a logical XOR | |
147 | * operator. Comparing directly for equality may fail if one is 1 and | |
148 | * the other is 2 even though both are logically true. | |
149 | */ | |
150 | if (!!req->isDirect != !!shareCtx->isDirect) { | |
151 | client->errorValue = req->shareList; | |
152 | return BadMatch; | |
153 | } | |
154 | ||
155 | /* The GLX_ARB_create_context spec says: | |
156 | * | |
157 | * "* If the server context state for <share_context>...was | |
158 | * created on a different screen than the one referenced by | |
159 | * <config>...BadMatch is generated." | |
160 | */ | |
161 | if (glxScreen != shareCtx->pGlxScreen) { | |
162 | client->errorValue = shareCtx->pGlxScreen->pScreen->myNum; | |
163 | return BadMatch; | |
164 | } | |
165 | } | |
166 | ||
167 | for (i = 0; i < req->numAttribs; i++) { | |
168 | switch (attribs[i * 2]) { | |
169 | case GLX_CONTEXT_MAJOR_VERSION_ARB: | |
170 | major_version = attribs[2 * i + 1]; | |
171 | break; | |
172 | ||
173 | case GLX_CONTEXT_MINOR_VERSION_ARB: | |
174 | minor_version = attribs[2 * i + 1]; | |
175 | break; | |
176 | ||
177 | case GLX_CONTEXT_FLAGS_ARB: | |
178 | flags = attribs[2 * i + 1]; | |
179 | break; | |
180 | ||
181 | case GLX_RENDER_TYPE: | |
182 | render_type = attribs[2 * i + 1]; | |
183 | break; | |
184 | ||
185 | case GLX_CONTEXT_PROFILE_MASK_ARB: | |
186 | profile = attribs[2 * i + 1]; | |
187 | break; | |
188 | ||
189 | case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB: | |
190 | reset = attribs[2 * i + 1]; | |
191 | if (reset != GLX_NO_RESET_NOTIFICATION_ARB | |
192 | && reset != GLX_LOSE_CONTEXT_ON_RESET_ARB) | |
193 | return BadValue; | |
194 | ||
195 | break; | |
196 | ||
197 | default: | |
198 | return BadValue; | |
199 | } | |
200 | } | |
201 | ||
202 | /* The GLX_ARB_create_context spec says: | |
203 | * | |
204 | * "If attributes GLX_CONTEXT_MAJOR_VERSION_ARB and | |
205 | * GLX_CONTEXT_MINOR_VERSION_ARB, when considered together | |
206 | * with attributes GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB and | |
207 | * GLX_RENDER_TYPE, specify an OpenGL version and feature set | |
208 | * that are not defined, BadMatch is generated. | |
209 | * | |
210 | * ...Feature deprecation was introduced with OpenGL 3.0, so | |
211 | * forward-compatible contexts may only be requested for | |
212 | * OpenGL 3.0 and above. Thus, examples of invalid | |
213 | * combinations of attributes include: | |
214 | * | |
215 | * - Major version < 1 or > 3 | |
216 | * - Major version == 1 and minor version < 0 or > 5 | |
217 | * - Major version == 2 and minor version < 0 or > 1 | |
218 | * - Major version == 3 and minor version > 2 | |
219 | * - Forward-compatible flag set and major version < 3 | |
220 | * - Color index rendering and major version >= 3" | |
221 | */ | |
222 | if (!validate_GL_version(major_version, minor_version)) | |
223 | return BadMatch; | |
224 | ||
225 | if (major_version < 3 | |
226 | && ((flags & GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB) != 0)) | |
227 | return BadMatch; | |
228 | ||
229 | if (major_version >= 3 && render_type == GLX_COLOR_INDEX_TYPE) | |
230 | return BadMatch; | |
231 | ||
232 | if (!validate_render_type(render_type)) | |
233 | return BadValue; | |
234 | ||
235 | if ((flags & ~ALL_VALID_FLAGS) != 0) | |
236 | return BadValue; | |
237 | ||
238 | /* The GLX_ARB_create_context_profile spec says: | |
239 | * | |
240 | * "* If attribute GLX_CONTEXT_PROFILE_MASK_ARB has no bits set; has | |
241 | * any bits set other than GLX_CONTEXT_CORE_PROFILE_BIT_ARB and | |
242 | * GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; has more than one of | |
243 | * these bits set; or if the implementation does not support the | |
244 | * requested profile, then GLXBadProfileARB is generated." | |
245 | */ | |
246 | switch (profile) { | |
247 | case GLX_CONTEXT_CORE_PROFILE_BIT_ARB: | |
248 | case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: | |
249 | break; | |
250 | case GLX_CONTEXT_ES2_PROFILE_BIT_EXT: | |
251 | /* The GLX_EXT_create_context_es2_profile spec says: | |
252 | * | |
253 | * "... If the version requested is 2.0, and the | |
254 | * GLX_CONTEXT_ES2_PROFILE_BIT_EXT bit is set in the | |
255 | * GLX_CONTEXT_PROFILE_MASK_ARB attribute (see below), then the | |
256 | * context returned will implement OpenGL ES 2.0." | |
257 | * | |
258 | * It also says: | |
259 | * | |
260 | * "* If attribute GLX_CONTEXT_PROFILE_MASK_ARB has no bits set; | |
261 | * has any bits set other than | |
262 | * GLX_CONTEXT_CORE_PROFILE_BIT_ARB, | |
263 | * GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, or | |
264 | * GLX_CONTEXT_ES2_PROFILE_BIT_EXT; has more than one of these | |
265 | * bits set; or if the implementation does not supported the | |
266 | * requested profile, then GLXBadProfileARB is generated." | |
267 | * | |
268 | * It does not specifically say what is supposed to happen if | |
269 | * GLX_CONTEXT_ES2_PROFILE_BIT_EXT is set but the version requested is | |
270 | * not 2.0. We choose to generate GLXBadProfileARB as this matches | |
271 | * NVIDIA's behavior. | |
272 | */ | |
273 | if (major_version != 2 || minor_version != 0) | |
274 | return __glXError(GLXBadProfileARB); | |
275 | break; | |
276 | default: | |
277 | return __glXError(GLXBadProfileARB); | |
278 | } | |
279 | ||
280 | /* The GLX_ARB_create_context_robustness spec says: | |
281 | * | |
282 | * "* If the reset notification behavior of <share_context> and the | |
283 | * newly created context are different, BadMatch is generated." | |
284 | */ | |
285 | if (shareCtx != NULL && shareCtx->resetNotificationStrategy != reset) | |
286 | return BadMatch; | |
287 | ||
288 | /* There is no GLX protocol for desktop OpenGL versions after 1.4. There | |
289 | * is no GLX protocol for any version of OpenGL ES. If the application is | |
290 | * requested an indirect rendering context for a version that cannot be | |
291 | * satisfied, reject it. | |
292 | * | |
293 | * The GLX_ARB_create_context spec says: | |
294 | * | |
295 | * "* If <config> does not support compatible OpenGL contexts | |
296 | * providing the requested API major and minor version, | |
297 | * forward-compatible flag, and debug context flag, GLXBadFBConfig | |
298 | * is generated." | |
299 | */ | |
300 | if (!req->isDirect && (major_version > 1 || minor_version > 4 | |
301 | || profile == GLX_CONTEXT_ES2_PROFILE_BIT_EXT)) { | |
302 | return __glXError(GLXBadFBConfig); | |
303 | } | |
304 | ||
305 | /* Allocate memory for the new context | |
306 | */ | |
307 | if (req->isDirect) { | |
308 | ctx = __glXdirectContextCreate(glxScreen, config, shareCtx); | |
309 | err = BadAlloc; | |
310 | } | |
311 | else { | |
312 | ctx = glxScreen->createContext(glxScreen, config, shareCtx, | |
313 | req->numAttribs, (uint32_t *) attribs, | |
314 | &err); | |
315 | } | |
316 | ||
317 | if (ctx == NULL) | |
318 | return err; | |
319 | ||
320 | ctx->pGlxScreen = glxScreen; | |
321 | ctx->config = config; | |
322 | ctx->id = req->context; | |
323 | ctx->share_id = req->shareList; | |
324 | ctx->idExists = True; | |
325 | ctx->currentClient = False; | |
326 | ctx->isDirect = req->isDirect; | |
327 | ctx->hasUnflushedCommands = False; | |
328 | ctx->renderMode = GL_RENDER; | |
329 | ctx->feedbackBuf = NULL; | |
330 | ctx->feedbackBufSize = 0; | |
331 | ctx->selectBuf = NULL; | |
332 | ctx->selectBufSize = 0; | |
333 | ctx->drawPriv = NULL; | |
334 | ctx->readPriv = NULL; | |
335 | ctx->resetNotificationStrategy = reset; | |
336 | ||
337 | /* Add the new context to the various global tables of GLX contexts. | |
338 | */ | |
339 | if (!__glXAddContext(ctx)) { | |
340 | (*ctx->destroy) (ctx); | |
341 | client->errorValue = req->context; | |
342 | return BadAlloc; | |
343 | } | |
344 | ||
345 | return Success; | |
346 | } | |
347 | ||
348 | int | |
349 | __glXDispSwap_CreateContextAttribsARB(__GLXclientState * cl, GLbyte * pc) | |
350 | { | |
351 | return BadRequest; | |
352 | } |