mesa/src/egl/main/eglcontext.c

863 lines
28 KiB
C
Raw Normal View History

/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
* Copyright 2010-2011 LunarG, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
2005-04-22 22:09:39 +01:00
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "eglconfig.h"
#include "eglcontext.h"
#include "egldisplay.h"
#include "eglcurrent.h"
2005-04-22 22:09:39 +01:00
#include "eglsurface.h"
#include "egllog.h"
#include "util/macros.h"
/**
* Return the API bit (one of EGL_xxx_BIT) of the context.
*/
static EGLint
_eglGetContextAPIBit(_EGLContext *ctx)
{
EGLint bit = 0;
switch (ctx->ClientAPI) {
case EGL_OPENGL_ES_API:
switch (ctx->ClientMajorVersion) {
case 1:
bit = EGL_OPENGL_ES_BIT;
break;
case 2:
bit = EGL_OPENGL_ES2_BIT;
break;
case 3:
bit = EGL_OPENGL_ES3_BIT_KHR;
break;
default:
break;
}
break;
case EGL_OPENVG_API:
bit = EGL_OPENVG_BIT;
break;
case EGL_OPENGL_API:
bit = EGL_OPENGL_BIT;
break;
default:
break;
}
return bit;
}
/**
* Parse the list of context attributes and return the proper error code.
*/
static EGLint
_eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *disp,
const EGLint *attrib_list)
{
EGLenum api = ctx->ClientAPI;
EGLint i, err = EGL_SUCCESS;
if (!attrib_list)
return EGL_SUCCESS;
if (api == EGL_OPENVG_API && attrib_list[0] != EGL_NONE) {
_eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attrib_list[0]);
return EGL_BAD_ATTRIBUTE;
}
for (i = 0; attrib_list[i] != EGL_NONE; i++) {
EGLint attr = attrib_list[i++];
EGLint val = attrib_list[i];
switch (attr) {
case EGL_CONTEXT_CLIENT_VERSION:
/* The EGL 1.4 spec says:
*
* "attribute EGL_CONTEXT_CLIENT_VERSION is only valid when the
* current rendering API is EGL_OPENGL_ES_API"
*
* The EGL_KHR_create_context spec says:
*
* "EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
* (this token is an alias for EGL_CONTEXT_CLIENT_VERSION)"
*
* "The values for attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
* EGL_CONTEXT_MINOR_VERSION_KHR specify the requested client API
* version. They are only meaningful for OpenGL and OpenGL ES
* contexts, and specifying them for other types of contexts will
* generate an error."
*/
if ((api != EGL_OPENGL_ES_API &&
(!disp->Extensions.KHR_create_context || api != EGL_OPENGL_API))) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->ClientMajorVersion = val;
break;
case EGL_CONTEXT_MINOR_VERSION_KHR:
/* The EGL_KHR_create_context spec says:
*
* "The values for attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
* EGL_CONTEXT_MINOR_VERSION_KHR specify the requested client API
* version. They are only meaningful for OpenGL and OpenGL ES
* contexts, and specifying them for other types of contexts will
* generate an error."
*/
if (!disp->Extensions.KHR_create_context ||
(api != EGL_OPENGL_ES_API && api != EGL_OPENGL_API)) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->ClientMinorVersion = val;
break;
case EGL_CONTEXT_FLAGS_KHR:
if (!disp->Extensions.KHR_create_context) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL_KHR_create_context spec says:
*
* "If the EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR flag bit is set in
* EGL_CONTEXT_FLAGS_KHR, then a <debug context> will be created.
* [...]
* In some cases a debug context may be identical to a non-debug
* context. This bit is supported for OpenGL and OpenGL ES
* contexts."
*/
if ((val & EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR) &&
(api != EGL_OPENGL_API && api != EGL_OPENGL_ES_API)) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL_KHR_create_context spec says:
*
* "If the EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR flag bit
* is set in EGL_CONTEXT_FLAGS_KHR, then a <forward-compatible>
* context will be created. Forward-compatible contexts are
* defined only for OpenGL versions 3.0 and later. They must not
* support functionality marked as <deprecated> by that version of
* the API, while a non-forward-compatible context must support
* all functionality in that version, deprecated or not. This bit
* is supported for OpenGL contexts, and requesting a
* forward-compatible context for OpenGL versions less than 3.0
* will generate an error."
*
* Note: since the forward-compatible flag can be set more than one way,
* the OpenGL version check is performed once, below.
*/
if ((val & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) &&
api != EGL_OPENGL_API) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if ((val & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) &&
api != EGL_OPENGL_API) {
/* The EGL_KHR_create_context spec says:
*
* 10) Which error should be generated if robust buffer access
* or reset notifications are requested under OpenGL ES?
*
* As per Issue 6, this extension does not support creating
* robust contexts for OpenGL ES. This is only supported via
* the EGL_EXT_create_context_robustness extension.
*
* Attempting to use this extension to create robust OpenGL
* ES context will generate an EGL_BAD_ATTRIBUTE error. This
* specific error is generated because this extension does
* not define the EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR
* and EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR
* bits for OpenGL ES contexts. Thus, use of these bits fall
* under condition described by: "If an attribute is
* specified that is not meaningful for the client API
* type.." in the above specification.
*
* The spec requires that we emit the error even if the display
* supports EGL_EXT_create_context_robustness. To create a robust
* GLES context, the *attribute*
* EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT must be used, not the
* *flag* EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR.
*/
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->Flags |= val;
break;
case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
if (!disp->Extensions.KHR_create_context) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL_KHR_create_context spec says:
*
* "[EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR] is only meaningful for
* OpenGL contexts, and specifying it for other types of
* contexts, including OpenGL ES contexts, will generate an
* error."
*/
if (api != EGL_OPENGL_API) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->Profile = val;
break;
case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
/* The EGL_KHR_create_context spec says:
*
* "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR] is only
* meaningful for OpenGL contexts, and specifying it for other
* types of contexts, including OpenGL ES contexts, will generate
* an error."
*
* EGL 1.5 defines EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY
* (without a suffix) which has the same value as the KHR token,
* and specifies that it now works with both GL and ES contexts:
*
* "This attribute is supported only for OpenGL and OpenGL ES
* contexts."
*/
if (!(disp->Extensions.KHR_create_context && api == EGL_OPENGL_API)
&& !(disp->Version >= 15 && (api == EGL_OPENGL_API ||
api == EGL_OPENGL_ES_API))) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->ResetNotificationStrategy = val;
break;
case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
/* The EGL_EXT_create_context_robustness spec says:
*
* "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT] is only
* meaningful for OpenGL ES contexts, and specifying it for other
* types of contexts will generate an EGL_BAD_ATTRIBUTE error."
*/
if (!disp->Extensions.EXT_create_context_robustness
|| api != EGL_OPENGL_ES_API) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->ResetNotificationStrategy = val;
break;
case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
if (!disp->Extensions.EXT_create_context_robustness) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val == EGL_TRUE)
ctx->Flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
break;
case EGL_CONTEXT_OPENGL_ROBUST_ACCESS:
if (disp->Version < 15) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val == EGL_TRUE)
ctx->Flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
break;
case EGL_CONTEXT_OPENGL_DEBUG:
if (disp->Version < 15) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val == EGL_TRUE)
ctx->Flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
break;
case EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE:
if (disp->Version < 15) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val == EGL_TRUE)
ctx->Flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
break;
case EGL_CONTEXT_OPENGL_NO_ERROR_KHR:
if (disp->Version < 14 ||
!disp->Extensions.KHR_create_context_no_error) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The KHR_no_error spec only applies against OpenGL 2.0+ and
* OpenGL ES 2.0+
*/
if (((api != EGL_OPENGL_API && api != EGL_OPENGL_ES_API) ||
ctx->ClientMajorVersion < 2) && val == EGL_TRUE) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* Canonicalize value to EGL_TRUE/EGL_FALSE definitions */
ctx->NoError = !!val;
break;
egl: Support IMG_context_priority IMG_context_priority https://www.khronos.org/registry/egl/extensions/IMG/EGL_IMG_context_priority.txt "This extension allows an EGLContext to be created with a priority hint. It is possible that an implementation will not honour the hint, especially if there are constraints on the number of high priority contexts available in the system, or system policy limits access to high priority contexts to appropriate system privilege level. A query is provided to find the real priority level assigned to the context after creation." The extension adds a new eglCreateContext attribute for choosing a priority hint. This stub parses the attribute and copies into the base struct _egl_context, and hooks up the query similarly. Since the attribute is purely a hint, I have no qualms about the lack of implementation before reporting back the value the user gave! v2: Remember to set the default ContextPriority value to medium. v3: Use the driRendererQuery interface to probe the backend for supported priority values and use those to mask the EGL interface. v4: Treat the priority attrib as a hint and gracefully mask any requests not supported by the driver, the EGLContext will remain at medium priority. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Rob Clark <robdclark@gmail.com> Reviewed-by: Ben Widawsky <ben@bwidawsk.net> Reviewed-by: Emil Velikov <emli.velikov@collabora.com> Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2016-10-27 19:34:46 +01:00
case EGL_CONTEXT_PRIORITY_LEVEL_IMG:
/* The EGL_IMG_context_priority spec says:
*
* "EGL_CONTEXT_PRIORITY_LEVEL_IMG determines the priority level of
* the context to be created. This attribute is a hint, as an
* implementation may not support multiple contexts at some
* priority levels and system policy may limit access to high
* priority contexts to appropriate system privilege level. The
* default value for EGL_CONTEXT_PRIORITY_LEVEL_IMG is
* EGL_CONTEXT_PRIORITY_MEDIUM_IMG."
*/
{
int bit;
switch (val) {
case EGL_CONTEXT_PRIORITY_HIGH_IMG:
bit = __EGL_CONTEXT_PRIORITY_HIGH_BIT;
break;
case EGL_CONTEXT_PRIORITY_MEDIUM_IMG:
bit = __EGL_CONTEXT_PRIORITY_MEDIUM_BIT;
break;
case EGL_CONTEXT_PRIORITY_LOW_IMG:
bit = __EGL_CONTEXT_PRIORITY_LOW_BIT;
break;
default:
bit = -1;
break;
}
if (bit < 0) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* "This extension allows an EGLContext to be created with a
* priority hint. It is possible that an implementation will not
* honour the hint, especially if there are constraints on the
* number of high priority contexts available in the system, or
* system policy limits access to high priority contexts to
* appropriate system privilege level. A query is provided to find
* the real priority level assigned to the context after creation."
*
* We currently assume that the driver applies the priority hint
* and filters out any it cannot handle during the screen setup,
* e.g. dri2_setup_screen(). As such we can mask any change that
* the driver would fail, and ctx->ContextPriority matches the
* hint applied to the driver/hardware backend.
*/
if (disp->Extensions.IMG_context_priority & (1 << bit))
egl: Support IMG_context_priority IMG_context_priority https://www.khronos.org/registry/egl/extensions/IMG/EGL_IMG_context_priority.txt "This extension allows an EGLContext to be created with a priority hint. It is possible that an implementation will not honour the hint, especially if there are constraints on the number of high priority contexts available in the system, or system policy limits access to high priority contexts to appropriate system privilege level. A query is provided to find the real priority level assigned to the context after creation." The extension adds a new eglCreateContext attribute for choosing a priority hint. This stub parses the attribute and copies into the base struct _egl_context, and hooks up the query similarly. Since the attribute is purely a hint, I have no qualms about the lack of implementation before reporting back the value the user gave! v2: Remember to set the default ContextPriority value to medium. v3: Use the driRendererQuery interface to probe the backend for supported priority values and use those to mask the EGL interface. v4: Treat the priority attrib as a hint and gracefully mask any requests not supported by the driver, the EGLContext will remain at medium priority. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Rob Clark <robdclark@gmail.com> Reviewed-by: Ben Widawsky <ben@bwidawsk.net> Reviewed-by: Emil Velikov <emli.velikov@collabora.com> Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2016-10-27 19:34:46 +01:00
ctx->ContextPriority = val;
break;
}
case EGL_CONTEXT_RELEASE_BEHAVIOR_KHR:
if (val == EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR ||
val == EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR) {
ctx->ReleaseBehavior = val;
} else {
err = EGL_BAD_ATTRIBUTE;
}
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS) {
_eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr);
break;
}
}
if (api == EGL_OPENGL_API) {
/* The EGL_KHR_create_context spec says:
*
* "If the requested OpenGL version is less than 3.2,
* EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR is ignored and the
* functionality of the context is determined solely by the
* requested version."
*
* Since the value is ignored, only validate the setting if the version
* is >= 3.2.
*/
if (ctx->ClientMajorVersion >= 4
|| (ctx->ClientMajorVersion == 3 && ctx->ClientMinorVersion >= 2)) {
switch (ctx->Profile) {
case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR:
case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR:
break;
default:
/* The EGL_KHR_create_context spec says:
*
* "* If an OpenGL context is requested, the requested version
* is greater than 3.2, and the value for attribute
* EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR has no bits set; has
* any bits set other than EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
* and EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; has
* more than one of these bits set; or if the implementation does
* not support the requested profile, then an EGL_BAD_MATCH error
* is generated."
*/
err = EGL_BAD_MATCH;
break;
}
}
/* The EGL_KHR_create_context spec says:
*
* "* If an OpenGL context is requested and the values for
* attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
* EGL_CONTEXT_MINOR_VERSION_KHR, when considered together with
* the value for attribute
* EGL_CONTEXT_FORWARD_COMPATIBLE_BIT_KHR, specify an OpenGL
* version and feature set that are not defined, than an
* EGL_BAD_MATCH error is generated.
*
* ... Thus, examples of invalid combinations of attributes
* include:
*
* - Major version < 1 or > 4
* - Major version == 1 and minor version < 0 or > 5
* - Major version == 2 and minor version < 0 or > 1
* - Major version == 3 and minor version < 0 or > 2
* - Major version == 4 and minor version < 0 or > 2
* - Forward-compatible flag set and major version < 3"
*/
if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
err = EGL_BAD_MATCH;
switch (ctx->ClientMajorVersion) {
case 1:
if (ctx->ClientMinorVersion > 5
|| (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
err = EGL_BAD_MATCH;
break;
case 2:
if (ctx->ClientMinorVersion > 1
|| (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
err = EGL_BAD_MATCH;
break;
case 3:
/* Note: The text above is incorrect. There *is* an OpenGL 3.3!
*/
if (ctx->ClientMinorVersion > 3)
err = EGL_BAD_MATCH;
break;
case 4:
default:
/* Don't put additional version checks here. We don't know that
* there won't be versions > 4.2.
*/
break;
}
} else if (api == EGL_OPENGL_ES_API) {
/* The EGL_KHR_create_context spec says:
*
* "* If an OpenGL ES context is requested and the values for
* attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
* EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that
* is not defined, than an EGL_BAD_MATCH error is generated.
*
* ... Examples of invalid combinations of attributes include:
*
* - Major version < 1 or > 2
* - Major version == 1 and minor version < 0 or > 1
* - Major version == 2 and minor version != 0
*/
if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
err = EGL_BAD_MATCH;
switch (ctx->ClientMajorVersion) {
case 1:
if (ctx->ClientMinorVersion > 1)
err = EGL_BAD_MATCH;
break;
case 2:
if (ctx->ClientMinorVersion > 0)
err = EGL_BAD_MATCH;
break;
case 3:
/* Don't put additional version checks here. We don't know that
* there won't be versions > 3.0.
*/
break;
default:
err = EGL_BAD_MATCH;
break;
}
}
switch (ctx->ResetNotificationStrategy) {
case EGL_NO_RESET_NOTIFICATION_KHR:
case EGL_LOSE_CONTEXT_ON_RESET_KHR:
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL_KHR_create_context_no_error spec says:
*
* "BAD_MATCH is generated if the EGL_CONTEXT_OPENGL_NO_ERROR_KHR is TRUE at
* the same time as a debug or robustness context is specified."
*/
if (ctx->NoError && (ctx->Flags & EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR ||
ctx->Flags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) {
err = EGL_BAD_MATCH;
}
if ((ctx->Flags & ~(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
| EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
| EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) != 0) {
err = EGL_BAD_ATTRIBUTE;
}
return err;
}
2005-04-22 22:09:39 +01:00
/**
* Initialize the given _EGLContext object to defaults and/or the values
* in the attrib_list.
*
* According to EGL 1.5 Section 3.7:
*
* "EGL_OPENGL_API and EGL_OPENGL_ES_API are interchangeable for all
* purposes except eglCreateContext."
*
* And since we only support GL and GLES, this is the only place where the
* bound API matters at all. We look up the current API from the current
* thread, and stash that in the context we're initializing. Our caller is
* responsible for determining whether that's an API it supports.
2005-04-22 22:09:39 +01:00
*/
EGLBoolean
_eglInitContext(_EGLContext *ctx, _EGLDisplay *disp, _EGLConfig *conf,
const EGLint *attrib_list)
2005-04-22 22:09:39 +01:00
{
const EGLenum api = eglQueryAPI();
EGLint err;
if (api == EGL_NONE)
return _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
_eglInitResource(&ctx->Resource, sizeof(*ctx), disp);
ctx->ClientAPI = api;
ctx->Config = conf;
ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
ctx->ClientMajorVersion = 1; /* the default, per EGL spec */
ctx->ClientMinorVersion = 0;
ctx->Flags = 0;
ctx->ResetNotificationStrategy = EGL_NO_RESET_NOTIFICATION_KHR;
egl: Support IMG_context_priority IMG_context_priority https://www.khronos.org/registry/egl/extensions/IMG/EGL_IMG_context_priority.txt "This extension allows an EGLContext to be created with a priority hint. It is possible that an implementation will not honour the hint, especially if there are constraints on the number of high priority contexts available in the system, or system policy limits access to high priority contexts to appropriate system privilege level. A query is provided to find the real priority level assigned to the context after creation." The extension adds a new eglCreateContext attribute for choosing a priority hint. This stub parses the attribute and copies into the base struct _egl_context, and hooks up the query similarly. Since the attribute is purely a hint, I have no qualms about the lack of implementation before reporting back the value the user gave! v2: Remember to set the default ContextPriority value to medium. v3: Use the driRendererQuery interface to probe the backend for supported priority values and use those to mask the EGL interface. v4: Treat the priority attrib as a hint and gracefully mask any requests not supported by the driver, the EGLContext will remain at medium priority. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Rob Clark <robdclark@gmail.com> Reviewed-by: Ben Widawsky <ben@bwidawsk.net> Reviewed-by: Emil Velikov <emli.velikov@collabora.com> Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2016-10-27 19:34:46 +01:00
ctx->ContextPriority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG;
ctx->ReleaseBehavior = EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR;
err = _eglParseContextAttribList(ctx, disp, attrib_list);
if (err == EGL_SUCCESS && ctx->Config) {
EGLint api_bit;
api_bit = _eglGetContextAPIBit(ctx);
if (!(ctx->Config->RenderableType & api_bit)) {
_eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
api_bit, ctx->Config->RenderableType);
err = EGL_BAD_CONFIG;
}
}
if (err != EGL_SUCCESS)
return _eglError(err, "eglCreateContext");
return EGL_TRUE;
2005-04-22 22:09:39 +01:00
}
static EGLint
_eglQueryContextRenderBuffer(_EGLContext *ctx)
{
_EGLSurface *surf = ctx->DrawSurface;
egl: Simplify queries for EGL_RENDER_BUFFER There exist *two* queryable EGL_RENDER_BUFFER states in EGL: eglQuerySurface(EGL_RENDER_BUFFER) and eglQueryContext(EGL_RENDER_BUFFER). These changes eliminate potentially very fragile code in the upcoming EGL_KHR_mutable_render_buffer implementation. * eglQuerySurface(EGL_RENDER_BUFFER) The implementation of eglQuerySurface(EGL_RENDER_BUFFER) contained abstruse logic which required comprehending the specification complexities of how the two EGL_RENDER_BUFFER states interact. The function sometimes returned _EGLContext::WindowRenderBuffer, sometimes _EGLSurface::RenderBuffer. Why? The function tried to encode the actual logic from the EGL spec. When did the function return which variable? Go study the EGL spec, hope you understand it, then hope Mesa mutated the EGL_RENDER_BUFFER state in all the correct places. Have fun. To simplify eglQuerySurface(EGL_RENDER_BUFFER), and to improve confidence in its correctness, flatten its indirect logic. For pixmap and pbuffer surfaces, simply return a hard-coded literal value, as the spec suggests. For window surfaces, simply return _EGLSurface::RequestedRenderBuffer. Nothing difficult here. * eglQueryContext(EGL_RENDER_BUFFER) The implementation of this suffered from the same issues as eglQuerySurface, and the solution is the same. confidence in its correctness, flatten its indirect logic. For pixmap and pbuffer surfaces, simply return a hard-coded literal value, as the spec suggests. For window surfaces, simply return _EGLSurface::ActiveRenderBuffer. Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
2018-04-07 22:23:48 +01:00
/* From the EGL 1.5 spec:
*
* - If the context is not bound to a surface, then EGL_NONE will be
* returned.
*/
if (!surf)
return EGL_NONE;
egl: Simplify queries for EGL_RENDER_BUFFER There exist *two* queryable EGL_RENDER_BUFFER states in EGL: eglQuerySurface(EGL_RENDER_BUFFER) and eglQueryContext(EGL_RENDER_BUFFER). These changes eliminate potentially very fragile code in the upcoming EGL_KHR_mutable_render_buffer implementation. * eglQuerySurface(EGL_RENDER_BUFFER) The implementation of eglQuerySurface(EGL_RENDER_BUFFER) contained abstruse logic which required comprehending the specification complexities of how the two EGL_RENDER_BUFFER states interact. The function sometimes returned _EGLContext::WindowRenderBuffer, sometimes _EGLSurface::RenderBuffer. Why? The function tried to encode the actual logic from the EGL spec. When did the function return which variable? Go study the EGL spec, hope you understand it, then hope Mesa mutated the EGL_RENDER_BUFFER state in all the correct places. Have fun. To simplify eglQuerySurface(EGL_RENDER_BUFFER), and to improve confidence in its correctness, flatten its indirect logic. For pixmap and pbuffer surfaces, simply return a hard-coded literal value, as the spec suggests. For window surfaces, simply return _EGLSurface::RequestedRenderBuffer. Nothing difficult here. * eglQueryContext(EGL_RENDER_BUFFER) The implementation of this suffered from the same issues as eglQuerySurface, and the solution is the same. confidence in its correctness, flatten its indirect logic. For pixmap and pbuffer surfaces, simply return a hard-coded literal value, as the spec suggests. For window surfaces, simply return _EGLSurface::ActiveRenderBuffer. Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
2018-04-07 22:23:48 +01:00
switch (surf->Type) {
default:
unreachable("bad EGLSurface type");
case EGL_PIXMAP_BIT:
/* - If the context is bound to a pixmap surface, then EGL_SINGLE_BUFFER
* will be returned.
*/
return EGL_SINGLE_BUFFER;
case EGL_PBUFFER_BIT:
/* - If the context is bound to a pbuffer surface, then EGL_BACK_BUFFER
* will be returned.
*/
return EGL_BACK_BUFFER;
case EGL_WINDOW_BIT:
/* - If the context is bound to a window surface, then either
* EGL_BACK_BUFFER or EGL_SINGLE_BUFFER may be returned. The value
* returned depends on both the buffer requested by the setting of the
* EGL_RENDER_BUFFER property of the surface [...], and on the client
* API (not all client APIs support single-buffer Rendering to window
* surfaces). Some client APIs allow control of whether rendering goes
* to the front or back buffer. This client API-specific choice is not
* reflected in the returned value, which only describes the buffer
* that will be rendered to by default if not overridden by the client
* API.
*/
return surf->ActiveRenderBuffer;
}
}
2005-04-22 22:09:39 +01:00
EGLBoolean
_eglQueryContext(_EGLContext *c, EGLint attribute, EGLint *value)
2005-04-22 22:09:39 +01:00
{
if (!value)
return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
2005-04-22 22:09:39 +01:00
switch (attribute) {
case EGL_CONFIG_ID:
/*
* From EGL_KHR_no_config_context:
*
* "Querying EGL_CONFIG_ID returns the ID of the EGLConfig with
* respect to which the context was created, or zero if created
* without respect to an EGLConfig."
*/
*value = c->Config ? c->Config->ConfigID : 0;
break;
case EGL_CONTEXT_CLIENT_VERSION:
*value = c->ClientMajorVersion;
break;
2006-01-30 00:10:55 +00:00
case EGL_CONTEXT_CLIENT_TYPE:
*value = c->ClientAPI;
break;
case EGL_RENDER_BUFFER:
*value = _eglQueryContextRenderBuffer(c);
break;
egl: Support IMG_context_priority IMG_context_priority https://www.khronos.org/registry/egl/extensions/IMG/EGL_IMG_context_priority.txt "This extension allows an EGLContext to be created with a priority hint. It is possible that an implementation will not honour the hint, especially if there are constraints on the number of high priority contexts available in the system, or system policy limits access to high priority contexts to appropriate system privilege level. A query is provided to find the real priority level assigned to the context after creation." The extension adds a new eglCreateContext attribute for choosing a priority hint. This stub parses the attribute and copies into the base struct _egl_context, and hooks up the query similarly. Since the attribute is purely a hint, I have no qualms about the lack of implementation before reporting back the value the user gave! v2: Remember to set the default ContextPriority value to medium. v3: Use the driRendererQuery interface to probe the backend for supported priority values and use those to mask the EGL interface. v4: Treat the priority attrib as a hint and gracefully mask any requests not supported by the driver, the EGLContext will remain at medium priority. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Rob Clark <robdclark@gmail.com> Reviewed-by: Ben Widawsky <ben@bwidawsk.net> Reviewed-by: Emil Velikov <emli.velikov@collabora.com> Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2016-10-27 19:34:46 +01:00
case EGL_CONTEXT_PRIORITY_LEVEL_IMG:
*value = c->ContextPriority;
break;
2005-04-22 22:09:39 +01:00
default:
return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
2005-04-22 22:09:39 +01:00
}
return EGL_TRUE;
2005-04-22 22:09:39 +01:00
}
/**
* Bind the context to the thread and return the previous context.
*
* Note that the context may be NULL.
*/
_EGLContext *
_eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t)
2005-04-22 22:09:39 +01:00
{
_EGLContext *oldCtx;
oldCtx = t->CurrentContext;
if (ctx != oldCtx) {
if (oldCtx)
oldCtx->Binding = NULL;
if (ctx)
ctx->Binding = t;
t->CurrentContext = ctx;
}
return oldCtx;
}
/**
* Return true if the given context and surfaces can be made current.
*/
static EGLBoolean
_eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
{
_EGLThreadInfo *t = _eglGetCurrentThread();
_EGLDisplay *disp;
2005-04-22 22:09:39 +01:00
/* this is easy */
if (!ctx) {
if (draw || read)
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
return EGL_TRUE;
}
disp = ctx->Resource.Display;
if (!disp->Extensions.KHR_surfaceless_context
&& (draw == NULL || read == NULL))
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
/*
* The spec says
*
* "If ctx is current to some other thread, or if either draw or read are
* bound to contexts in another thread, an EGL_BAD_ACCESS error is
* generated."
*
* and
*
* "at most one context may be bound to a particular surface at a given
* time"
*/
if (ctx->Binding && ctx->Binding != t)
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
if (draw && draw->CurrentContext && draw->CurrentContext != ctx) {
if (draw->CurrentContext->Binding != t)
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
}
if (read && read->CurrentContext && read->CurrentContext != ctx) {
if (read->CurrentContext->Binding != t)
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
}
/* If the context has a config then it must match that of the two
* surfaces */
if (ctx->Config) {
if ((draw && draw->Config != ctx->Config) ||
(read && read->Config != ctx->Config))
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
} else {
/* Otherwise we must be using the EGL_KHR_no_config_context
* extension */
assert(disp->Extensions.KHR_no_config_context);
/* The extension doesn't permit binding draw and read buffers with
* differing contexts */
if (draw && read && draw->Config != read->Config)
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
}
return EGL_TRUE;
}
/**
* Bind the context to the current thread and given surfaces. Return the
* previous bound context and surfaces. The caller should unreference the
* returned context and surfaces.
*
* Making a second call with the resources returned by the first call
* unsurprisingly undoes the first call, except for the resouce reference
* counts.
*/
EGLBoolean
_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
_EGLContext **old_ctx,
_EGLSurface **old_draw, _EGLSurface **old_read)
{
_EGLThreadInfo *t = _eglGetCurrentThread();
_EGLContext *prev_ctx;
_EGLSurface *prev_draw, *prev_read;
if (!_eglCheckMakeCurrent(ctx, draw, read))
return EGL_FALSE;
/* increment refcounts before binding */
_eglGetContext(ctx);
_eglGetSurface(draw);
_eglGetSurface(read);
/* bind the new context */
prev_ctx = _eglBindContextToThread(ctx, t);
/* break previous bindings */
if (prev_ctx) {
prev_draw = prev_ctx->DrawSurface;
prev_read = prev_ctx->ReadSurface;
if (prev_draw)
prev_draw->CurrentContext = NULL;
if (prev_read)
prev_read->CurrentContext = NULL;
prev_ctx->DrawSurface = NULL;
prev_ctx->ReadSurface = NULL;
}
else {
prev_draw = prev_read = NULL;
}
/* establish new bindings */
if (ctx) {
if (draw)
draw->CurrentContext = ctx;
if (read)
read->CurrentContext = ctx;
ctx->DrawSurface = draw;
ctx->ReadSurface = read;
}
assert(old_ctx && old_draw && old_read);
*old_ctx = prev_ctx;
*old_draw = prev_draw;
*old_read = prev_read;
return EGL_TRUE;
}