Re: [Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls (v3)
On Fri, 2016-09-16 at 18:33 +0100, Emil Velikov wrote: > But regardless, this and v2 14/14 look a lot better and are > > Reviewed-by: Emil VelikovMerged, thanks. - ajax ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls (v3)
On 14 September 2016 at 14:59, Adam Jacksonwrote: > From: Kyle Brenneman > > This decorates every EGL entrypoint with _EGL_FUNC_START, which records > the function name and primary dispatch object label in the current > thread state. It also adds debug report functions and calls them when > appropriate. > > This would be useful enough for debugging on its own, if the user set a > breakpoint when the report function was called. We will also need this > state tracked in order to expose EGL_KHR_debug. > > v2: > - Clear the object label in more cases in _eglSetFuncName > - Pass draw surface (if any) to _EGL_FUNC_START in eglSwapInterval > > v3: > - Set dummy thread's CurrentAPI to EGL_OPENGL_ES_API not zero Maybe (only maybe) we want this as a one-line fix for stable. But regardless, this and v2 14/14 look a lot better and are Reviewed-by: Emil Velikov Thanks for addressing all the comment Adam ! Emil ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls (v3)
This looks right to me. -Kyle On 09/14/2016 07:59 AM, Adam Jackson wrote: From: Kyle BrennemanThis decorates every EGL entrypoint with _EGL_FUNC_START, which records the function name and primary dispatch object label in the current thread state. It also adds debug report functions and calls them when appropriate. This would be useful enough for debugging on its own, if the user set a breakpoint when the report function was called. We will also need this state tracked in order to expose EGL_KHR_debug. v2: - Clear the object label in more cases in _eglSetFuncName - Pass draw surface (if any) to _EGL_FUNC_START in eglSwapInterval v3: - Set dummy thread's CurrentAPI to EGL_OPENGL_ES_API not zero - Less ?: in _eglSetFuncName --- src/egl/main/eglapi.c | 153 +++--- src/egl/main/eglcurrent.c | 91 ++- src/egl/main/eglcurrent.h | 22 +++ src/egl/main/eglglobals.h | 5 ++ 4 files changed, 258 insertions(+), 13 deletions(-) diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index 1c62a80..cbc3841 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -250,6 +250,37 @@ _eglUnlockDisplay(_EGLDisplay *dpy) mtx_unlock(>Mutex); } +static EGLBoolean +_eglSetFuncName(const char *funcName, _EGLDisplay *disp, EGLenum objectType, _EGLResource *object) +{ + _EGLThreadInfo *thr = _eglGetCurrentThread(); + if (!_eglIsCurrentThreadDummy()) { + thr->CurrentFuncName = funcName; + thr->CurrentObjectLabel = NULL; + + if (objectType == EGL_OBJECT_THREAD_KHR) + thr->CurrentObjectLabel = thr->Label; + else if (objectType == EGL_OBJECT_DISPLAY_KHR && disp) + thr->CurrentObjectLabel = disp->Label; + else if (object) + thr->CurrentObjectLabel = object->Label; + + return EGL_TRUE; + } + + _eglDebugReportFull(EGL_BAD_ALLOC, funcName, funcName, + EGL_DEBUG_MSG_CRITICAL_KHR, NULL, NULL); + return EGL_FALSE; +} + +#define _EGL_FUNC_START(disp, objectType, object, ret) \ + do { \ + if (!_eglSetFuncName(__func__, disp, objectType, (_EGLResource *) object)) { \ + if (disp) \ +_eglUnlockDisplay(disp); \ + return ret; \ + } \ + } while(0) static EGLint * _eglConvertAttribsToInt(const EGLAttrib *attr_list) @@ -287,6 +318,8 @@ eglGetDisplay(EGLNativeDisplayType nativeDisplay) _EGLDisplay *dpy; void *native_display_ptr; + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); + STATIC_ASSERT(sizeof(void*) == sizeof(nativeDisplay)); native_display_ptr = (void*) nativeDisplay; @@ -330,6 +363,7 @@ static EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list) { + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); return _eglGetPlatformDisplayCommon(platform, native_display, attrib_list); } @@ -340,6 +374,8 @@ eglGetPlatformDisplay(EGLenum platform, void *native_display, EGLDisplay display; EGLint *int_attribs; + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); + int_attribs = _eglConvertAttribsToInt(attrib_list); if (attrib_list && !int_attribs) RETURN_EGL_ERROR(NULL, EGL_BAD_ALLOC, NULL); @@ -483,6 +519,8 @@ eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + if (!disp) RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE); @@ -533,6 +571,8 @@ eglTerminate(EGLDisplay dpy) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + if (!disp) RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE); @@ -560,6 +600,7 @@ eglQueryString(EGLDisplay dpy, EGLint name) } disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, NULL); _EGL_CHECK_DISPLAY(disp, NULL, drv); switch (name) { @@ -585,6 +626,8 @@ eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); ret = drv->API.GetConfigs(drv, disp, configs, config_size, num_config); @@ -600,6 +643,8 @@ eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); ret = drv->API.ChooseConfig(drv, disp, attrib_list, configs, config_size, num_config); @@ -617,6 +662,8 @@ eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
Re: [Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls
Note that the primary object can still be meaningful even on a function that's defined to never throw an error. Those functions could still send a WARN or INFO level message if they had reason to, just not a CRITICAL or ERROR level. Until any of those are added to Mesa, though, it's an academic distinction. -Kyle On 09/14/2016 08:00 AM, Adam Jackson wrote: On Wed, 2016-09-14 at 12:08 +0100, Emil Velikov wrote: Thanks for reminding me - eglQueryAPI should never throw an error, indeed. Since EGL_KHR_debug is applicable for functions_do_ throw an error, one should leave the API out of the spec text shouldn't they ? I mean, sure, but this patch is against Mesa, not the spec. This is precisely what I'm talking about - one cannot relate the error label to a {surface,context,display} object that is yet to be found. As such the object label (and friends) should be related to the current thread. I see your point, I'm just not sure what you want done about it. My reading of the spec is that there are two ways an implementation can handle this: a) "The primary object should be the object the function operates on, see table 13.2 which provides the recommended mapping between functions and their primary object." Note "recommended", which suggests the primary object could be something else. b) " will contain the label attached to the primary object of the message; Labels will be NULL if not set by the application. [...] This may be NULL even though the application labeled the object. This is because it is possible an error was raised while executing the command before the primary object was validated, therefore its label can not be included in the callback." This suggests that if the primary object can't be validated, then a NULL label will be used. Now to me, option b seems more conservative. Debug callbacks need to be prepared for null object labels due to mandatory spec language. They need to be prepared for unexpected primary objects only due to optional spec language. And option b is the approach this patch takes, entrypoints that error before the primary object is validated will invoke the callback with a null object label. If we want to amend the spec language, great, that's a fine idea, and Khronos bugzilla is → that way. But even if we did, I think the implementation in this patch (well, v3 of it) can be said to conform to the spec as it currently exists, and that such amendment should not invalidate existing implementations. - ajax ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls
On 14 September 2016 at 15:00, Adam Jacksonwrote: > On Wed, 2016-09-14 at 12:08 +0100, Emil Velikov wrote: > >> Thanks for reminding me - eglQueryAPI should never throw an error, >> indeed. Since EGL_KHR_debug is applicable for functions_do_ throw an >> error, one should leave the API out of the spec text shouldn't they ? > > I mean, sure, but this patch is against Mesa, not the spec. > Fully agree - this is not something we need to address in mesa. >> This is precisely what I'm talking about - one cannot relate the error >> label to a {surface,context,display} object that is yet to be found. >> As such the object label (and friends) should be related to the >> current thread. > > I see your point, I'm just not sure what you want done about it. My > reading of the spec is that there are two ways an implementation can > handle this: > > a) "The primary object should be the object the function operates on, > see table 13.2 which provides the recommended mapping between functions > and their primary object." > > Note "recommended", which suggests the primary object could be > something else. > > b) " will contain the label attached to the primary object > of the message; Labels will be NULL if not set by the application. > [...] This may be NULL even though the application > labeled the object. This is because it is possible an error was raised > while executing the command before the primary object was validated, > therefore its label can not be included in the callback." > > This suggests that if the primary object can't be validated, then a > NULL label will be used. > > Now to me, option b seems more conservative. Debug callbacks need to be > prepared for null object labels due to mandatory spec language. They > need to be prepared for unexpected primary objects only due to optional > spec language. And option b is the approach this patch takes, > entrypoints that error before the primary object is validated will > invoke the callback with a null object label. > > If we want to amend the spec language, great, that's a fine idea, and > Khronos bugzilla is → that way. But even if we did, I think the > implementation in this patch (well, v3 of it) can be said to conform to > the spec as it currently exists, and that such amendment should not > invalidate existing implementations. > Again, fully agree - it's not something we should address in mesa. Just checking that our understanding of the spec aligns and it [the spec] leaves an open question. Then again... seems like I've missed "recommended" which effectively gives implementations flexibility to answer do things in a way they seem fit. Thanks ! Emil ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls
On Wed, 2016-09-14 at 12:08 +0100, Emil Velikov wrote: > Thanks for reminding me - eglQueryAPI should never throw an error, > indeed. Since EGL_KHR_debug is applicable for functions_do_ throw an > error, one should leave the API out of the spec text shouldn't they ? I mean, sure, but this patch is against Mesa, not the spec. > This is precisely what I'm talking about - one cannot relate the error > label to a {surface,context,display} object that is yet to be found. > As such the object label (and friends) should be related to the > current thread. I see your point, I'm just not sure what you want done about it. My reading of the spec is that there are two ways an implementation can handle this: a) "The primary object should be the object the function operates on, see table 13.2 which provides the recommended mapping between functions and their primary object." Note "recommended", which suggests the primary object could be something else. b) " will contain the label attached to the primary object of the message; Labels will be NULL if not set by the application. [...] This may be NULL even though the application labeled the object. This is because it is possible an error was raised while executing the command before the primary object was validated, therefore its label can not be included in the callback." This suggests that if the primary object can't be validated, then a NULL label will be used. Now to me, option b seems more conservative. Debug callbacks need to be prepared for null object labels due to mandatory spec language. They need to be prepared for unexpected primary objects only due to optional spec language. And option b is the approach this patch takes, entrypoints that error before the primary object is validated will invoke the callback with a null object label. If we want to amend the spec language, great, that's a fine idea, and Khronos bugzilla is → that way. But even if we did, I think the implementation in this patch (well, v3 of it) can be said to conform to the spec as it currently exists, and that such amendment should not invalidate existing implementations. - ajax ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
[Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls (v3)
From: Kyle BrennemanThis decorates every EGL entrypoint with _EGL_FUNC_START, which records the function name and primary dispatch object label in the current thread state. It also adds debug report functions and calls them when appropriate. This would be useful enough for debugging on its own, if the user set a breakpoint when the report function was called. We will also need this state tracked in order to expose EGL_KHR_debug. v2: - Clear the object label in more cases in _eglSetFuncName - Pass draw surface (if any) to _EGL_FUNC_START in eglSwapInterval v3: - Set dummy thread's CurrentAPI to EGL_OPENGL_ES_API not zero - Less ?: in _eglSetFuncName --- src/egl/main/eglapi.c | 153 +++--- src/egl/main/eglcurrent.c | 91 ++- src/egl/main/eglcurrent.h | 22 +++ src/egl/main/eglglobals.h | 5 ++ 4 files changed, 258 insertions(+), 13 deletions(-) diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index 1c62a80..cbc3841 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -250,6 +250,37 @@ _eglUnlockDisplay(_EGLDisplay *dpy) mtx_unlock(>Mutex); } +static EGLBoolean +_eglSetFuncName(const char *funcName, _EGLDisplay *disp, EGLenum objectType, _EGLResource *object) +{ + _EGLThreadInfo *thr = _eglGetCurrentThread(); + if (!_eglIsCurrentThreadDummy()) { + thr->CurrentFuncName = funcName; + thr->CurrentObjectLabel = NULL; + + if (objectType == EGL_OBJECT_THREAD_KHR) + thr->CurrentObjectLabel = thr->Label; + else if (objectType == EGL_OBJECT_DISPLAY_KHR && disp) + thr->CurrentObjectLabel = disp->Label; + else if (object) + thr->CurrentObjectLabel = object->Label; + + return EGL_TRUE; + } + + _eglDebugReportFull(EGL_BAD_ALLOC, funcName, funcName, + EGL_DEBUG_MSG_CRITICAL_KHR, NULL, NULL); + return EGL_FALSE; +} + +#define _EGL_FUNC_START(disp, objectType, object, ret) \ + do { \ + if (!_eglSetFuncName(__func__, disp, objectType, (_EGLResource *) object)) { \ + if (disp) \ +_eglUnlockDisplay(disp); \ + return ret; \ + } \ + } while(0) static EGLint * _eglConvertAttribsToInt(const EGLAttrib *attr_list) @@ -287,6 +318,8 @@ eglGetDisplay(EGLNativeDisplayType nativeDisplay) _EGLDisplay *dpy; void *native_display_ptr; + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); + STATIC_ASSERT(sizeof(void*) == sizeof(nativeDisplay)); native_display_ptr = (void*) nativeDisplay; @@ -330,6 +363,7 @@ static EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list) { + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); return _eglGetPlatformDisplayCommon(platform, native_display, attrib_list); } @@ -340,6 +374,8 @@ eglGetPlatformDisplay(EGLenum platform, void *native_display, EGLDisplay display; EGLint *int_attribs; + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); + int_attribs = _eglConvertAttribsToInt(attrib_list); if (attrib_list && !int_attribs) RETURN_EGL_ERROR(NULL, EGL_BAD_ALLOC, NULL); @@ -483,6 +519,8 @@ eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + if (!disp) RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE); @@ -533,6 +571,8 @@ eglTerminate(EGLDisplay dpy) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + if (!disp) RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE); @@ -560,6 +600,7 @@ eglQueryString(EGLDisplay dpy, EGLint name) } disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, NULL); _EGL_CHECK_DISPLAY(disp, NULL, drv); switch (name) { @@ -585,6 +626,8 @@ eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); ret = drv->API.GetConfigs(drv, disp, configs, config_size, num_config); @@ -600,6 +643,8 @@ eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); ret = drv->API.ChooseConfig(drv, disp, attrib_list, configs, config_size, num_config); @@ -617,6 +662,8 @@ eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_CONFIG(disp, conf,
Re: [Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls
On 13 September 2016 at 17:46, Adam Jacksonwrote: > On Tue, 2016-09-13 at 16:54 +0100, Emil Velikov wrote: >> Going through table 13.2 and the below there are some discrepancies. >> >> AFAICT some of those can be seen as spec bugs (B), while others seem >> to be missing (M) >> - thread - eglBindAPI (M) > > Not really missing, but tricky. _EGL_FUNC_START calls _eglSetFuncName > which initializes thr->CurrentObjectLabel, so if there _is_ a non-dummy > thread then the callback will get the correct label for the thread > object. > > However, if we're on the dummy thread, then we'll hit the call > to _eglDebugReportFull(objectLabel=NULL), which will correctly call the > callback with both labels NULL. Arguably _eglSetFuncName should also > clear ->CurrentObjectLabel in this case. > Staring at the list for a while and yet I've missed the _EGL_FUNC_START line in eglBindAPI. >> - display - eglGetCurrentDisplay (B) > > It's somewhat irrelevant since our implementation never throws an error > on this path (and it's not clear that any implementation ever would), > but: what do you mean by "spec bug" here? > From the spec will contain the label attached to the primary object of the message; Labels will be NULL if not set by the application. The primary object should be the object the function operates on, see table 13.2 which provides the recommended mapping between functions and their primary object. It tells us the relation between the label and the (primary) object which we implement by attaching the label to the corresponding primitive object in _eglSetFuncName. In this particular case if one cannot derive the current display, how can they cannot attach the label to the display object ? In a similar way we have the eglCreate entry points, which relate to the dpy since one cannot relate (attach in our case) the label to the non-existent primitive that one is trying to create. NB: The fact that mesa/foo does not throw an error is implementation detail, which should not be relied upon. >> - context - eglQueryAPI (M), > > eglQueryAPI is _defined_ as never throwing an error, so I'm not sure > this is really "missing". However, the dummy thread's ->CurrentAPI is > initialized to 0, but "no API" is EGL_NONE which is not zero but > 0x3038, so that really is a bug; I'll fix that up. > Thanks for reminding me - eglQueryAPI should never throw an error, indeed. Since EGL_KHR_debug is applicable for functions_do_ throw an error, one should leave the API out of the spec text shouldn't they ? The only text that would be applicable i one that reminds us about that. Something vaguely like "Since eglQueryAPI never throws an error, calling the function should not have any effect on the object label, (others) already associated with the context/thread/..." >> eglGetCurrentContext (B) > > Again, this is defined as not throwing an error, so as long as we never > trigger the debug callback there's no problem here. > The above description for dpy still applies here. Just replace s/display/context/. >> - surface - eglSwapInterval (B) > > Again, not sure what you mean by "spec bug" here. But there is an > implementation bug, we should pass ctx->DrawSurface as the active > object to _EGL_FUNC_START since we're already locked; if it's NULL and > we have a live thread then _eglSetFuncName will clear the current > object label correctly. I'll fix that up. > Yes there is the implementation bug that you've mentioned. But there's more to it imho. The validation between current context (and thus draw surface) and user provided dpy sounds a bit iffy. I'm also leaning that the function operate/relates closer to the (current) thread than the actual drawable, no ? >> eglGetCurrentSurface(B) > > The weird part about this one is that we might need to throw an error > before we've found a valid surface to operate with. This is precisely what I'm talking about - one cannot relate the error label to a {surface,context,display} object that is yet to be found. As such the object label (and friends) should be related to the current thread. Regards, Emil ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls (v2)
On 09/13/2016 02:42 PM, Adam Jackson wrote: On Tue, 2016-09-13 at 14:14 -0600, Kyle Brenneman wrote: On 09/13/2016 11:57 AM, Adam Jackson wrote: @@ -37,7 +39,7 @@ /* This should be kept in sync with _eglInitThreadInfo() */ #define _EGL_THREAD_INFO_INITIALIZER \ - { EGL_SUCCESS, NULL, 0, NULL, NULL, NULL } + { EGL_SUCCESS, NULL, EGL_NONE, NULL, NULL, NULL } The API here should be EGL_OPENGL_ES_API, not EGL_NONE. Otherwise, the current API would effectively change when the _EGLThreadInfo struct is allocated. Or I guess more generally, _EGL_THREAD_INFO_INITIALIZER should produce the same data as _eglInitThreadInfo. Mmm, okay. That's a very close reading of the spec. QueryAPI allows the result to be EGL_NONE, which does make sense for the dummy thread since you sure won't be doing much with it. But BindAPI says the default is EGL_OPENGL_ES_API, so presumably that should apply even to the dummy context. One does wonder then how you could ever get EGL_NONE out of QueryAPI. - ajax eglQueryAPI allows the result to be EGL_NONE only if it doesn't support GLES. From the spec (EGL 1.5, section 3.7): "The initial value of the current rendering API is EGL_OPENGL_ES_API , unless OpenGL ES is not supported by an implementation, in which case the initial value is EGL_NONE." ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls (v2)
On Tue, 2016-09-13 at 14:14 -0600, Kyle Brenneman wrote: > On 09/13/2016 11:57 AM, Adam Jackson wrote: > > @@ -37,7 +39,7 @@ > > > > /* This should be kept in sync with _eglInitThreadInfo() */ > > #define _EGL_THREAD_INFO_INITIALIZER \ > > - { EGL_SUCCESS, NULL, 0, NULL, NULL, NULL } > > + { EGL_SUCCESS, NULL, EGL_NONE, NULL, NULL, NULL } > > The API here should be EGL_OPENGL_ES_API, not EGL_NONE. Otherwise, the > current API would effectively change when the _EGLThreadInfo struct is > allocated. Or I guess more generally, _EGL_THREAD_INFO_INITIALIZER > should produce the same data as _eglInitThreadInfo. Mmm, okay. That's a very close reading of the spec. QueryAPI allows the result to be EGL_NONE, which does make sense for the dummy thread since you sure won't be doing much with it. But BindAPI says the default is EGL_OPENGL_ES_API, so presumably that should apply even to the dummy context. One does wonder then how you could ever get EGL_NONE out of QueryAPI. - ajax ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls (v2)
On 09/13/2016 11:57 AM, Adam Jackson wrote: From: Kyle BrennemanThis decorates every EGL entrypoint with _EGL_FUNC_START, which records the function name and primary dispatch object label in the current thread state. It also adds debug report functions and calls them when appropriate. This would be useful enough for debugging on its own, if the user set a breakpoint when the report function was called. We will also need this state tracked in order to expose EGL_KHR_debug. v2: - Clear the object label in more cases in _eglSetFuncName - Set dummy thread's CurrentAPI to EGL_NONE not zero - Pass draw surface (if any) to _EGL_FUNC_START in eglSwapInterval --- src/egl/main/eglapi.c | 155 ++ src/egl/main/eglcurrent.c | 91 ++- src/egl/main/eglcurrent.h | 22 +++ src/egl/main/eglglobals.h | 5 ++ 4 files changed, 259 insertions(+), 14 deletions(-) diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index 0477ad9..216b289 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -250,6 +250,37 @@ _eglUnlockDisplay(_EGLDisplay *dpy) mtx_unlock(>Mutex); } +static EGLBoolean +_eglSetFuncName(const char *funcName, _EGLDisplay *disp, EGLenum objectType, _EGLResource *object) +{ + _EGLThreadInfo *thr = _eglGetCurrentThread(); + if (!_eglIsCurrentThreadDummy()) { + thr->CurrentFuncName = funcName; + thr->CurrentObjectLabel = NULL; + + if (objectType == EGL_OBJECT_THREAD_KHR) + thr->CurrentObjectLabel = thr->Label; + else if (objectType == EGL_OBJECT_DISPLAY_KHR) + thr->CurrentObjectLabel = disp ? disp->Label : NULL; + else + thr->CurrentObjectLabel = object ? object->Label : NULL; + + return EGL_TRUE; + } + + _eglDebugReportFull(EGL_BAD_ALLOC, funcName, funcName, + EGL_DEBUG_MSG_CRITICAL_KHR, NULL, NULL); + return EGL_FALSE; +} _eglSetFuncName starts with "thr->CurrentObjectLabel = NULL", so if it didn't set the label to something else later, it would have been cleared. + +#define _EGL_FUNC_START(disp, objectType, object, ret) \ + do { \ + if (!_eglSetFuncName(__func__, disp, objectType, (_EGLResource *) object)) { \ + if (disp) \ +_eglUnlockDisplay(disp); \ + return ret; \ + } \ + } while(0) static EGLint * _eglConvertAttribsToInt(const EGLAttrib *attr_list) @@ -287,6 +318,8 @@ eglGetDisplay(EGLNativeDisplayType nativeDisplay) _EGLDisplay *dpy; void *native_display_ptr; + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); + STATIC_ASSERT(sizeof(void*) == sizeof(nativeDisplay)); native_display_ptr = (void*) nativeDisplay; @@ -330,6 +363,7 @@ static EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list) { + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); return _eglGetPlatformDisplayCommon(platform, native_display, attrib_list); } @@ -340,6 +374,8 @@ eglGetPlatformDisplay(EGLenum platform, void *native_display, EGLDisplay display; EGLint *int_attribs; + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); + int_attribs = _eglConvertAttribsToInt(attrib_list); if (attrib_list && !int_attribs) RETURN_EGL_ERROR(NULL, EGL_BAD_ALLOC, NULL); @@ -483,6 +519,8 @@ eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + if (!disp) RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE); @@ -533,6 +571,8 @@ eglTerminate(EGLDisplay dpy) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + if (!disp) RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE); @@ -560,6 +600,7 @@ eglQueryString(EGLDisplay dpy, EGLint name) } disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, NULL); _EGL_CHECK_DISPLAY(disp, NULL, drv); switch (name) { @@ -585,6 +626,8 @@ eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); ret = drv->API.GetConfigs(drv, disp, configs, config_size, num_config); @@ -600,6 +643,8 @@ eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); ret = drv->API.ChooseConfig(drv, disp, attrib_list, configs, config_size,
[Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls (v2)
From: Kyle BrennemanThis decorates every EGL entrypoint with _EGL_FUNC_START, which records the function name and primary dispatch object label in the current thread state. It also adds debug report functions and calls them when appropriate. This would be useful enough for debugging on its own, if the user set a breakpoint when the report function was called. We will also need this state tracked in order to expose EGL_KHR_debug. v2: - Clear the object label in more cases in _eglSetFuncName - Set dummy thread's CurrentAPI to EGL_NONE not zero - Pass draw surface (if any) to _EGL_FUNC_START in eglSwapInterval --- src/egl/main/eglapi.c | 155 ++ src/egl/main/eglcurrent.c | 91 ++- src/egl/main/eglcurrent.h | 22 +++ src/egl/main/eglglobals.h | 5 ++ 4 files changed, 259 insertions(+), 14 deletions(-) diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index 0477ad9..216b289 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -250,6 +250,37 @@ _eglUnlockDisplay(_EGLDisplay *dpy) mtx_unlock(>Mutex); } +static EGLBoolean +_eglSetFuncName(const char *funcName, _EGLDisplay *disp, EGLenum objectType, _EGLResource *object) +{ + _EGLThreadInfo *thr = _eglGetCurrentThread(); + if (!_eglIsCurrentThreadDummy()) { + thr->CurrentFuncName = funcName; + thr->CurrentObjectLabel = NULL; + + if (objectType == EGL_OBJECT_THREAD_KHR) + thr->CurrentObjectLabel = thr->Label; + else if (objectType == EGL_OBJECT_DISPLAY_KHR) + thr->CurrentObjectLabel = disp ? disp->Label : NULL; + else + thr->CurrentObjectLabel = object ? object->Label : NULL; + + return EGL_TRUE; + } + + _eglDebugReportFull(EGL_BAD_ALLOC, funcName, funcName, + EGL_DEBUG_MSG_CRITICAL_KHR, NULL, NULL); + return EGL_FALSE; +} + +#define _EGL_FUNC_START(disp, objectType, object, ret) \ + do { \ + if (!_eglSetFuncName(__func__, disp, objectType, (_EGLResource *) object)) { \ + if (disp) \ +_eglUnlockDisplay(disp); \ + return ret; \ + } \ + } while(0) static EGLint * _eglConvertAttribsToInt(const EGLAttrib *attr_list) @@ -287,6 +318,8 @@ eglGetDisplay(EGLNativeDisplayType nativeDisplay) _EGLDisplay *dpy; void *native_display_ptr; + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); + STATIC_ASSERT(sizeof(void*) == sizeof(nativeDisplay)); native_display_ptr = (void*) nativeDisplay; @@ -330,6 +363,7 @@ static EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list) { + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); return _eglGetPlatformDisplayCommon(platform, native_display, attrib_list); } @@ -340,6 +374,8 @@ eglGetPlatformDisplay(EGLenum platform, void *native_display, EGLDisplay display; EGLint *int_attribs; + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); + int_attribs = _eglConvertAttribsToInt(attrib_list); if (attrib_list && !int_attribs) RETURN_EGL_ERROR(NULL, EGL_BAD_ALLOC, NULL); @@ -483,6 +519,8 @@ eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + if (!disp) RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE); @@ -533,6 +571,8 @@ eglTerminate(EGLDisplay dpy) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + if (!disp) RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE); @@ -560,6 +600,7 @@ eglQueryString(EGLDisplay dpy, EGLint name) } disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, NULL); _EGL_CHECK_DISPLAY(disp, NULL, drv); switch (name) { @@ -585,6 +626,8 @@ eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); ret = drv->API.GetConfigs(drv, disp, configs, config_size, num_config); @@ -600,6 +643,8 @@ eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); ret = drv->API.ChooseConfig(drv, disp, attrib_list, configs, config_size, num_config); @@ -617,6 +662,8 @@ eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_CONFIG(disp, conf, EGL_FALSE, drv); ret =
Re: [Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls
On Tue, 2016-09-13 at 16:54 +0100, Emil Velikov wrote: > Going through table 13.2 and the below there are some discrepancies. > > AFAICT some of those can be seen as spec bugs (B), while others seem > to be missing (M) > - thread - eglBindAPI (M) Not really missing, but tricky. _EGL_FUNC_START calls _eglSetFuncName which initializes thr->CurrentObjectLabel, so if there _is_ a non-dummy thread then the callback will get the correct label for the thread object. However, if we're on the dummy thread, then we'll hit the call to _eglDebugReportFull(objectLabel=NULL), which will correctly call the callback with both labels NULL. Arguably _eglSetFuncName should also clear ->CurrentObjectLabel in this case. > - display - eglGetCurrentDisplay (B) It's somewhat irrelevant since our implementation never throws an error on this path (and it's not clear that any implementation ever would), but: what do you mean by "spec bug" here? > - context - eglQueryAPI (M), eglQueryAPI is _defined_ as never throwing an error, so I'm not sure this is really "missing". However, the dummy thread's ->CurrentAPI is initialized to 0, but "no API" is EGL_NONE which is not zero but 0x3038, so that really is a bug; I'll fix that up. > eglGetCurrentContext (B) Again, this is defined as not throwing an error, so as long as we never trigger the debug callback there's no problem here. > - surface - eglSwapInterval (B) Again, not sure what you mean by "spec bug" here. But there is an implementation bug, we should pass ctx->DrawSurface as the active object to _EGL_FUNC_START since we're already locked; if it's NULL and we have a live thread then _eglSetFuncName will clear the current object label correctly. I'll fix that up. > eglGetCurrentSurface(B) The weird part about this one is that we might need to throw an error before we've found a valid surface to operate with. The spec allows the object label to be NULL in this case, but _eglSetFuncName isn't clearing the current object label when initialized with a NULL object. I'll fix that too. - ajax ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls
On 12 September 2016 at 23:19, Adam Jacksonwrote: > +static EGLBoolean > +_eglSetFuncName(const char *funcName, _EGLDisplay *disp, EGLenum objectType, > _EGLResource *object) > +{ > + if (disp != NULL) { > +thr->CurrentObjectLabel = disp->Label; > + } > + } else { > + /* > + * Everything else will either be NULL or a valid _EGLResource > + * pointer. > + */ > + if (object != NULL) { First thought was object/disp can never be NULL, only to remember that input validation happens at a later stage. Oh well :-] Going through table 13.2 and the below there are some discrepancies. AFAICT some of those can be seen as spec bugs (B), while others seem to be missing (M) - thread - eglBindAPI (M) - display - eglGetCurrentDisplay (B) - context - eglQueryAPI (M), eglGetCurrentContext (B) - surface - eglSwapInterval (B), eglGetCurrentSurface(B) - image - ok - sync - ok -Emil ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
[Mesa-dev] [PATCH 13/14] egl: Track EGL_KHR_debug state when going through EGL API calls
From: Kyle BrennemanThis decorates every EGL entrypoint with _EGL_FUNC_START, which records the function name and primary dispatch object label in the current thread state. It also adds debug report functions and calls them when appropriate. This would be useful enough for debugging on its own, if the user set a breakpoint when the report function was called. We will also need this state tracked in order to expose EGL_KHR_debug. --- src/egl/main/eglapi.c | 161 +++--- src/egl/main/eglcurrent.c | 89 - src/egl/main/eglcurrent.h | 22 +++ src/egl/main/eglglobals.h | 5 ++ 4 files changed, 266 insertions(+), 11 deletions(-) diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index 0477ad9..0a6ebe7 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -250,6 +250,46 @@ _eglUnlockDisplay(_EGLDisplay *dpy) mtx_unlock(>Mutex); } +static EGLBoolean +_eglSetFuncName(const char *funcName, _EGLDisplay *disp, EGLenum objectType, _EGLResource *object) +{ + _EGLThreadInfo *thr = _eglGetCurrentThread(); + if (!_eglIsCurrentThreadDummy()) { + thr->CurrentFuncName = funcName; + thr->CurrentObjectLabel = NULL; + + if (objectType == EGL_OBJECT_THREAD_KHR) { + thr->CurrentObjectLabel = thr->Label; + } else if (objectType == EGL_OBJECT_DISPLAY_KHR) { + if (disp != NULL) { +thr->CurrentObjectLabel = disp->Label; + } + } else { + /* + * Everything else will either be NULL or a valid _EGLResource + * pointer. + */ + if (object != NULL) { +thr->CurrentObjectLabel = object->Label; + } + } + + return EGL_TRUE; + } + + _eglDebugReportFull(EGL_BAD_ALLOC, funcName, funcName, + EGL_DEBUG_MSG_CRITICAL_KHR, NULL, NULL); + return EGL_FALSE; +} + +#define _EGL_FUNC_START(disp, objectType, object, ret) \ + do { \ + if (!_eglSetFuncName(__func__, disp, objectType, (_EGLResource *) object)) { \ + if (disp) \ +_eglUnlockDisplay(disp); \ + return ret; \ + } \ + } while(0) static EGLint * _eglConvertAttribsToInt(const EGLAttrib *attr_list) @@ -287,6 +327,8 @@ eglGetDisplay(EGLNativeDisplayType nativeDisplay) _EGLDisplay *dpy; void *native_display_ptr; + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); + STATIC_ASSERT(sizeof(void*) == sizeof(nativeDisplay)); native_display_ptr = (void*) nativeDisplay; @@ -330,6 +372,7 @@ static EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list) { + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); return _eglGetPlatformDisplayCommon(platform, native_display, attrib_list); } @@ -340,6 +383,8 @@ eglGetPlatformDisplay(EGLenum platform, void *native_display, EGLDisplay display; EGLint *int_attribs; + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); + int_attribs = _eglConvertAttribsToInt(attrib_list); if (attrib_list && !int_attribs) RETURN_EGL_ERROR(NULL, EGL_BAD_ALLOC, NULL); @@ -483,6 +528,8 @@ eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + if (!disp) RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE); @@ -533,6 +580,8 @@ eglTerminate(EGLDisplay dpy) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + if (!disp) RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE); @@ -560,6 +609,7 @@ eglQueryString(EGLDisplay dpy, EGLint name) } disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, NULL); _EGL_CHECK_DISPLAY(disp, NULL, drv); switch (name) { @@ -585,6 +635,8 @@ eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); ret = drv->API.GetConfigs(drv, disp, configs, config_size, num_config); @@ -600,6 +652,8 @@ eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); ret = drv->API.ChooseConfig(drv, disp, attrib_list, configs, config_size, num_config); @@ -617,6 +671,8 @@ eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_CONFIG(disp, conf, EGL_FALSE, drv);