static bool parse_context_forward_compatible(struct wcore_config_attrs *attrs, const int32_t attrib_list[]) { if (!parse_bool(attrib_list, WAFFLE_CONTEXT_FORWARD_COMPATIBLE, &attrs->context_forward_compatible, false)) { return false; } if (!attrs->context_forward_compatible) { /* It's always valid to request a non-forward-compatible context. */ return true; } if (attrs->context_api != WAFFLE_CONTEXT_OPENGL) { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "To request a forward-compatible context, the context " "API must be WAFFLE_CONTEXT_OPENGL"); return false; } if (attrs->context_full_version < 30) { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "To request a forward-compatible context, the context " "version must be at least 3.0"); return false; } return true; }
extern "C" bool nacl_container_window_resize(struct nacl_container *nc, int32_t width, int32_t height) { waffle::nacl_container *cpp_nc = reinterpret_cast<waffle::nacl_container*>(nc); int32_t error = cpp_nc->ctx->ResizeBuffers(width, height); if (error == PP_OK) return true; switch (error) { case PP_ERROR_BADRESOURCE: wcore_errorf(WAFFLE_ERROR_FATAL, "Invalid NaCl 3D context."); break; case PP_ERROR_BADARGUMENT: wcore_errorf(WAFFLE_ERROR_BAD_PARAMETER, "Invalid values given for resize (w %d h %d)", width, height); break; default: wcore_errorf(WAFFLE_ERROR_UNKNOWN, "NaCl resize failed."); } return false; }
static bool parse_context_api(struct wcore_config_attrs *attrs, const int32_t attrib_list[]) { bool found; found = wcore_attrib_list_get(attrib_list, WAFFLE_CONTEXT_API, &attrs->context_api); if (!found) { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "required attribute WAFFLE_CONTEXT_API is missing"); return false; } switch (attrs->context_api) { case WAFFLE_CONTEXT_OPENGL: case WAFFLE_CONTEXT_OPENGL_ES1: case WAFFLE_CONTEXT_OPENGL_ES2: case WAFFLE_CONTEXT_OPENGL_ES3: break; default: wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "WAFFLE_CONTEXT_API has bad value %#x", attrs->context_api); return false; } return true; }
static bool nacl_container_context_init(waffle::nacl_container *nc, struct nacl_config *cfg) { // There is no way currently to pass a pp::Instance for Waffle, so // we fetch a map of all instances and if there's only one we select // that one, otherwise we fail. const pp::Module::InstanceMap instances = pp::Module::Get()->current_instances(); if (instances.size() != 1) { wcore_errorf(WAFFLE_ERROR_FATAL, "Could not find a pp::Instance for Waffle to use."); return false; } pp::Instance *pp_instance = instances.begin()->second; nc->ctx = new pp::Graphics3D(pp_instance, pp::Graphics3D(), cfg->attribs); if (nc->ctx->is_null()) { wcore_errorf(WAFFLE_ERROR_FATAL, "Unable to create NaCl 3D context."); return false; } // We need to fetch NaCl specific init, makecurrent and terminate // functions that communicate with the browser interface. As nacl_config // currently supports only ES2, this is hardcoded for ES2. nc->glapi = dlopen(NACL_GLES2_LIBRARY, RTLD_LAZY); if (!nc->glapi) { wcore_errorf(WAFFLE_ERROR_FATAL, "dlopen failed: %s", dlerror()); return false; } #define RESOLVE(func) \ nc->func = (typeof(nc->func)) dlsym(nc->glapi, (#func)); \ if (!nc->func) { \ wcore_errorf(WAFFLE_ERROR_FATAL, "failed to resolve %s", #func); \ return false; \ } RESOLVE(glInitializePPAPI); RESOLVE(glSetCurrentContextPPAPI); RESOLVE(glTerminatePPAPI); #undef RESOLVE if (!nc->glInitializePPAPI(pp::Module::Get()->get_browser_interface())) { wcore_errorf(WAFFLE_ERROR_FATAL, "Unable to initialize GL PPAPI!"); return false; } if (!pp_instance->BindGraphics(*nc->ctx)) { wcore_errorf(WAFFLE_ERROR_FATAL, "Unable to bind NaCl 3D context."); return false; } nc->swapper = new NaclSwapThread(pp_instance, nc->ctx); return true; }
static void test_wcore_error_first_call_with_message_wins(void **state) { wcore_error_reset(); wcore_errorf(WAFFLE_ERROR_UNKNOWN, "cookies"); wcore_errorf(WAFFLE_NO_ERROR, "all is well"); assert_int_equal(wcore_error_get_code(), WAFFLE_ERROR_UNKNOWN); assert_string_equal(wcore_error_get_info()->message, "cookies"); }
struct wcore_window* wgbm_window_create(struct wcore_platform *wc_plat, struct wcore_config *wc_config, int32_t width, int32_t height, const intptr_t attrib_list[]) { struct wgbm_display *dpy = wgbm_display(wc_config->display); struct wgbm_platform *plat = wgbm_platform(wegl_platform(wc_plat)); struct wgbm_window *self; uint32_t gbm_format; bool ok = true; if (width == -1 && height == -1) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "fullscreen window not supported"); return NULL; } if (wcore_attrib_list_length(attrib_list) > 0) { wcore_error_bad_attribute(attrib_list[0]); return NULL; } self = wcore_calloc(sizeof(*self)); if (self == NULL) return NULL; gbm_format = wgbm_config_get_gbm_format(wc_plat, wc_config->display, wc_config); assert(gbm_format != 0); self->gbm_surface = plat->gbm_surface_create(dpy->gbm_device, width, height, gbm_format, GBM_BO_USE_RENDERING); if (!self->gbm_surface) { wcore_errorf(WAFFLE_ERROR_UNKNOWN, "gbm_surface_create failed"); goto error; } ok = wegl_window_init(&self->wegl, wc_config, (intptr_t) self->gbm_surface); if (!ok) goto error; return &self->wegl.wcore; error: wgbm_window_destroy(&self->wegl.wcore); return NULL; }
static bool glx_platform_destroy(struct wcore_platform *wc_self) { struct glx_platform *self = glx_platform(wc_self); bool ok = true; int error = 0; if (!self) return true; if (self->linux) ok &= linux_platform_destroy(self->linux); if (self->glxHandle) { error = dlclose(self->glxHandle); if (error) { ok &= false; wcore_errorf(WAFFLE_ERROR_UNKNOWN, "dlclose(\"%s\") failed: %s", libGL_filename, dlerror()); } } ok &= wcore_platform_teardown(wc_self); free(self); return ok; }
struct wcore_window* sl_window_create(struct wcore_platform *wc_plat, struct wcore_config *wc_config, int32_t width, int32_t height, const intptr_t attrib_list[]) { struct sl_window *self; bool ok = true; if (width == -1 && height == -1) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "fullscreen window not supported"); return NULL; } if (wcore_attrib_list_length(attrib_list) > 0) { wcore_error_bad_attribute(attrib_list[0]); return NULL; } self = wcore_calloc(sizeof(*self)); if (self == NULL) return NULL; ok = wegl_pbuffer_init(&self->wegl, wc_config, width, height); if (!ok) goto error; return &self->wegl.wcore; error: sl_window_destroy(&self->wegl.wcore); return NULL; }
static void test_wcore_error_with_message(void **state) { wcore_error_reset(); wcore_errorf(WAFFLE_ERROR_BAD_PARAMETER, "bad %s (0x%x)", "gl_api", 0x17); assert_int_equal(wcore_error_get_code(), WAFFLE_ERROR_BAD_PARAMETER); assert_string_equal(wcore_error_get_info()->message, "bad gl_api (0x17)"); }
static bool wayland_platform_destroy(struct wcore_platform *wc_self) { struct wayland_platform *self = wayland_platform(wegl_platform(wc_self)); bool ok = true; int error; if (!self) return true; if (self->linux) ok &= linux_platform_destroy(self->linux); if (self->dl_wl_egl) { error = dlclose(self->dl_wl_egl); if (error) { ok &= false; wcore_errorf(WAFFLE_ERROR_UNKNOWN, "dlclose(\"%s\") failed: %s", libwl_egl_filename, dlerror()); } } ok &= wayland_wrapper_teardown(); ok &= wegl_platform_teardown(&self->wegl); free(self); return ok; }
static bool parse_bool(const int32_t attrib_list[], int32_t attrib_name, bool *value, bool default_value) { int32_t raw_value; wcore_attrib_list_get_with_default(attrib_list, attrib_name, &raw_value, default_value); if (raw_value == WAFFLE_DONT_CARE) { *value = default_value; } else if (raw_value == true || raw_value == false) { *value = raw_value; } else { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "%s has bad value 0x%x. " "Must be true(1), false(0), or WAFFLE_DONT_CARE(-1)", wcore_enum_to_string(attrib_name), raw_value); return false; } return true; }
WAFFLE_API bool waffle_display_supports_context_api( struct waffle_display *self, int32_t context_api) { struct wcore_display *wc_self = wcore_display(self); const struct api_object *obj_list[] = { wc_self ? &wc_self->api : NULL, }; if (!api_check_entry(obj_list, 1)) return false; switch (context_api) { case WAFFLE_CONTEXT_OPENGL: case WAFFLE_CONTEXT_OPENGL_ES1: case WAFFLE_CONTEXT_OPENGL_ES2: case WAFFLE_CONTEXT_OPENGL_ES3: break; default: wcore_errorf(WAFFLE_ERROR_BAD_PARAMETER, "context_api has bad value %#x", context_api); return false; } return api_platform->vtbl->display.supports_context_api(wc_self, context_api); }
static void test_wcore_error_first_call_without_message_wins(void **state) { wcore_error_reset(); wcore_errorf(WAFFLE_ERROR_UNKNOWN, "cookies"); wcore_error(WAFFLE_ERROR_BAD_ATTRIBUTE); assert_int_equal(wcore_error_get_code(), WAFFLE_ERROR_UNKNOWN); assert_string_equal(wcore_error_get_info()->message, "cookies"); }
static bool parse_context_profile(struct wcore_config_attrs *attrs, const int32_t attrib_list[]) { wcore_attrib_list_get_with_default(attrib_list, WAFFLE_CONTEXT_PROFILE, &attrs->context_profile, attrs->context_profile); switch (attrs->context_api) { case WAFFLE_CONTEXT_OPENGL: if (attrs->context_full_version >= 32 && attrs->context_profile != WAFFLE_CONTEXT_CORE_PROFILE && attrs->context_profile != WAFFLE_CONTEXT_COMPATIBILITY_PROFILE) { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "for OpenGL >= 3.2," "WAFFLE_CONTEXT_PROFILE must be either " "WAFFLE_CONTEXT_CORE_PROFILE or " "WAFFLE_CONTEXT_COMPATIBILITY_PROFILE"); return false; } else if (attrs->context_full_version < 32 && attrs->context_profile != WAFFLE_NONE) { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "for OpenGL < 3.2, WAFFLE_CONTEXT_PROFILE must be " "WAFFLE_NONE"); return false; } break; case WAFFLE_CONTEXT_OPENGL_ES1: case WAFFLE_CONTEXT_OPENGL_ES2: case WAFFLE_CONTEXT_OPENGL_ES3: if (attrs->context_profile != WAFFLE_NONE) { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "for OpenGL ES, WAFFLE_CONTEXT_PROFILE must be " "WAFFLE_NONE"); return false; } break; default: assert(false); return false; } return true; }
struct wcore_platform* glx_platform_create(void) { struct glx_platform *self; bool ok = true; self = wcore_calloc(sizeof(*self)); if (self == NULL) return NULL; ok = wcore_platform_init(&self->wcore); if (!ok) goto error; self->glxHandle = dlopen(libGL_filename, RTLD_LAZY | RTLD_LOCAL); if (!self->glxHandle) { wcore_errorf(WAFFLE_ERROR_FATAL, "dlopen(\"%s\") failed: %s", libGL_filename, dlerror()); goto error; } #define RETRIEVE_GLX_SYMBOL(function) \ self->function = dlsym(self->glxHandle, #function); \ if (!self->function) { \ wcore_errorf(WAFFLE_ERROR_FATAL, \ "dlsym(\"%s\", \"" #function "\") failed: %s", \ libGL_filename, dlerror()); \ goto error; \ } RETRIEVE_GLX_SYMBOL(glXCreateNewContext); RETRIEVE_GLX_SYMBOL(glXDestroyContext); RETRIEVE_GLX_SYMBOL(glXMakeCurrent); RETRIEVE_GLX_SYMBOL(glXQueryExtensionsString); RETRIEVE_GLX_SYMBOL(glXGetProcAddress); RETRIEVE_GLX_SYMBOL(glXGetVisualFromFBConfig); RETRIEVE_GLX_SYMBOL(glXGetFBConfigAttrib); RETRIEVE_GLX_SYMBOL(glXChooseFBConfig); RETRIEVE_GLX_SYMBOL(glXSwapBuffers); #undef RETRIEVE_GLX_SYMBOL self->linux = linux_platform_create(); if (!self->linux) goto error; self->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) self->glXGetProcAddress((const uint8_t*) "glXCreateContextAttribsARB"); self->wcore.vtbl = &glx_platform_vtbl; return &self->wcore; error: glx_platform_destroy(&self->wcore); return NULL; }
struct wcore_platform* wayland_platform_create(void) { struct wayland_platform *self; bool ok = true; self = wcore_calloc(sizeof(*self)); if (self == NULL) return NULL; ok = wegl_platform_init(&self->wegl, EGL_PLATFORM_WAYLAND_KHR); if (!ok) goto error; ok = wayland_wrapper_init(); if (!ok) goto error; self->dl_wl_egl = dlopen(libwl_egl_filename, RTLD_LAZY | RTLD_LOCAL); if (!self->dl_wl_egl) { wcore_errorf(WAFFLE_ERROR_FATAL, "dlopen(\"%s\") failed: %s", libwl_egl_filename, dlerror()); goto error; } #define RETRIEVE_WL_EGL_SYMBOL(function) \ self->function = dlsym(self->dl_wl_egl, #function); \ if (!self->function) { \ wcore_errorf(WAFFLE_ERROR_FATAL, \ "dlsym(\"%s\", \"" #function "\") failed: %s", \ libwl_egl_filename, dlerror()); \ goto error; \ } RETRIEVE_WL_EGL_SYMBOL(wl_egl_window_create); RETRIEVE_WL_EGL_SYMBOL(wl_egl_window_destroy); RETRIEVE_WL_EGL_SYMBOL(wl_egl_window_resize); #undef RETRIEVE_WL_EGL_SYMBOL self->linux = linux_platform_create(); if (!self->linux) goto error; self->wegl.wcore.vtbl = &wayland_platform_vtbl; return &self->wegl.wcore; error: wayland_platform_destroy(&self->wegl.wcore); return NULL; }
static bool check_final(struct wcore_config_attrs *attrs) { if (attrs->context_api == WAFFLE_CONTEXT_OPENGL && attrs->context_profile == WAFFLE_CONTEXT_CORE_PROFILE && attrs->context_full_version >= 32 && attrs->accum_buffer) { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "%s", "WAFFLE_ACCUM_BUFFER must be false for" "OpenGL Core profile"); return false; } return true; }
static bool wgl_dl_open(struct wgl_platform *plat) { plat->dl_gl = LoadLibraryA(wgl_gl_path); if (plat->dl_gl) return true; int error = GetLastError(); if (error) { wcore_errorf(WAFFLE_ERROR_UNKNOWN, "LoadLibraryA(\"%s\") failed: %d", wgl_gl_path, error); } return false; }
void* linux_dl_sym(struct linux_dl *self, const char *symbol) { // Clear any previous error. dlerror(); void *sym = dlsym(self->dl, symbol); const char *error = dlerror(); if (error) { wcore_errorf(WAFFLE_ERROR_UNKNOWN, "dlsym(libname=\"%s\", \"%s\") failed: %s", self->name, symbol, error); return NULL; } return sym; }
static bool glx_platform_make_current(struct wcore_platform *wc_self, struct wcore_display *wc_dpy, struct wcore_window *wc_window, struct wcore_context *wc_ctx) { struct glx_platform *self = glx_platform(wc_self); Display *dpy = glx_display(wc_dpy)->x11.xlib; GLXDrawable win = wc_window ? glx_window(wc_window)->x11.xcb : 0; GLXContext ctx = wc_ctx ? glx_context(wc_ctx)->glx : NULL; bool ok; ok = wrapped_glXMakeCurrent(self, dpy, win, ctx); if (!ok) { wcore_errorf(WAFFLE_ERROR_UNKNOWN, "glXMakeCurrent failed"); } return ok; }
bool linux_dl_close(struct linux_dl *self) { int error = 0; if (!self) return true; if (self->dl) { error = dlclose(self->dl); if (error) { wcore_errorf(WAFFLE_ERROR_UNKNOWN, "dlclose(libname=\"%s\") failed: %s", self->name, dlerror()); } } free(self); return error == 0; }
static bool check_keys(const int32_t attrib_list[]) { if (attrib_list == NULL) return true; for (int32_t i = 0; attrib_list[i]; i += 2) { int32_t key = attrib_list[i]; switch (key) { case WAFFLE_CONTEXT_API: case WAFFLE_CONTEXT_MAJOR_VERSION: case WAFFLE_CONTEXT_MINOR_VERSION: case WAFFLE_CONTEXT_PROFILE: case WAFFLE_CONTEXT_FORWARD_COMPATIBLE: case WAFFLE_CONTEXT_DEBUG: case WAFFLE_RED_SIZE: case WAFFLE_GREEN_SIZE: case WAFFLE_BLUE_SIZE: case WAFFLE_ALPHA_SIZE: case WAFFLE_DEPTH_SIZE: case WAFFLE_STENCIL_SIZE: case WAFFLE_SAMPLES: case WAFFLE_SAMPLE_BUFFERS: case WAFFLE_DOUBLE_BUFFERED: case WAFFLE_ACCUM_BUFFER: break; default: wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "unrecognized attribute 0x%x at attrib_list[%d]", key, i); return false; } } return true; }
bool api_check_entry(const struct api_object *obj_list[], int length) { wcore_error_reset(); if (!api_platform) { wcore_error(WAFFLE_ERROR_NOT_INITIALIZED); return false; } for (int i = 0; i < length; ++i) { if (obj_list[i] == NULL) { wcore_errorf(WAFFLE_ERROR_BAD_PARAMETER, "null pointer"); return false; } if (obj_list[i]->display_id != obj_list[0]->display_id) { wcore_error(WAFFLE_ERROR_BAD_DISPLAY_MATCH); return false; } } return true; }
void wegl_emit_error(struct wegl_platform *plat, const char *egl_func_call) { EGLint egl_error_code = plat->eglGetError(); const char *egl_error_name; switch (egl_error_code) { #define CASE(x) case x: egl_error_name = #x; break CASE(EGL_FALSE); CASE(EGL_TRUE); CASE(EGL_DONT_CARE); CASE(EGL_SUCCESS); CASE(EGL_NOT_INITIALIZED); CASE(EGL_BAD_ACCESS); CASE(EGL_BAD_ALLOC); CASE(EGL_BAD_ATTRIBUTE); CASE(EGL_BAD_CONFIG); CASE(EGL_BAD_CONTEXT); CASE(EGL_BAD_CURRENT_SURFACE); CASE(EGL_BAD_DISPLAY); CASE(EGL_BAD_MATCH); CASE(EGL_BAD_NATIVE_PIXMAP); CASE(EGL_BAD_NATIVE_WINDOW); CASE(EGL_BAD_PARAMETER); CASE(EGL_BAD_SURFACE); CASE(EGL_CONTEXT_LOST); default: egl_error_name = ""; break; #undef CASE } wcore_errorf(WAFFLE_ERROR_UNKNOWN, "%s failed with error %s(0x%x)", egl_func_call, egl_error_name, egl_error_code); }
struct linux_dl* linux_dl_open(int32_t waffle_dl) { struct linux_dl *self = wcore_calloc(sizeof(*self)); if (self == NULL) return NULL; self->name = linux_dl_get_name(waffle_dl); if (!self->name) goto error; self->dl = dlopen(self->name, RTLD_LAZY); if (!self->dl) { wcore_errorf(WAFFLE_ERROR_UNKNOWN, "dlopen(\"%s\") failed: %s", self->name, dlerror()); goto error; } return self; error: free(self); return NULL; }
/// @brief Check the values of `attrs->context_*`. static bool glx_config_check_context_attrs(struct glx_display *dpy, const struct wcore_config_attrs *attrs) { struct glx_platform *plat = glx_platform(dpy->wcore.platform); if (attrs->context_forward_compatible) { assert(attrs->context_api == WAFFLE_CONTEXT_OPENGL); assert(wcore_config_attrs_version_ge(attrs, 30)); } if (attrs->context_debug && !dpy->ARB_create_context) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_ARB_create_context is required in order to " "request a debug context"); return false; } if (attrs->context_robust && !dpy->ARB_create_context_robustness) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_ARB_create_context_robustness is required in order to " "request a robust access context"); return false; } switch (attrs->context_api) { case WAFFLE_CONTEXT_OPENGL: if (!wcore_config_attrs_version_eq(attrs, 10) && !dpy->ARB_create_context) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_ARB_create_context is required in order to " "request an OpenGL version not equal to the default " "value 1.0"); return false; } else if (wcore_config_attrs_version_ge(attrs, 32) && !dpy->ARB_create_context_profile) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_ARB_create_context_profile is required " "to create a context with version >= 3.2"); return false; } else if (wcore_config_attrs_version_ge(attrs, 32)) { assert(attrs->context_profile == WAFFLE_CONTEXT_CORE_PROFILE || attrs->context_profile == WAFFLE_CONTEXT_COMPATIBILITY_PROFILE); } if (attrs->context_forward_compatible && !dpy->ARB_create_context) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_ARB_create_context is required in order to " "request a forward-compatible context"); return false; } return true; case WAFFLE_CONTEXT_OPENGL_ES1: assert(wcore_config_attrs_version_eq(attrs, 10) || wcore_config_attrs_version_eq(attrs, 11)); assert(!attrs->context_forward_compatible); if (!dpy->EXT_create_context_es_profile) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_EXT_create_context_es_profile is required " "to create an OpenGL ES1 context"); return false; } else if (!linux_platform_dl_can_open(plat->linux, WAFFLE_DL_OPENGL_ES1)) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "failed to open the OpenGL ES1 library"); return false; } return true; case WAFFLE_CONTEXT_OPENGL_ES2: assert(attrs->context_major_version == 2); assert(!attrs->context_forward_compatible); if (!dpy->EXT_create_context_es_profile && !dpy->EXT_create_context_es2_profile) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_EXT_create_context_es_profile or " "GLX_EXT_create_context_es2_profile is required " "to create an OpenGL ES2 context"); return false; } if (!linux_platform_dl_can_open(plat->linux, WAFFLE_DL_OPENGL_ES2)) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "failed to open the OpenGL ES2 library"); return false; } return true; case WAFFLE_CONTEXT_OPENGL_ES3: assert(attrs->context_major_version == 3); if (!dpy->EXT_create_context_es_profile) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_EXT_create_context_es_profile is required " "to create an OpenGL ES3 context"); return false; } if (!linux_platform_dl_can_open(plat->linux, WAFFLE_DL_OPENGL_ES3)) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "failed to open the OpenGL ES3 library"); return false; } return true; default: wcore_error_internal("context_api has bad value %#x", attrs->context_api); return false; } }
struct wcore_config* glx_config_choose(struct wcore_platform *wc_plat, struct wcore_display *wc_dpy, const struct wcore_config_attrs *attrs) { struct glx_config *self; struct glx_display *dpy = glx_display(wc_dpy); struct glx_platform *plat = glx_platform(wc_plat); GLXFBConfig *configs = NULL; int num_configs = 0; XVisualInfo *vi = NULL; bool ok = true; if (!glx_config_check_context_attrs(dpy, attrs)) return NULL; self = wcore_calloc(sizeof(*self)); if (self == NULL) return NULL; ok = wcore_config_init(&self->wcore, wc_dpy, attrs); if (!ok) goto error; int attrib_list[] = { // From page 12 (18 of pdf) of the GLX 1.4 spec: // // For GLXFBConfigs that correspond to a TrueColor or DirectColor // visual, GLX BUFFER SIZE is the sum of GLX RED SIZE, GLX GREEN // SIZE, GLX BLUE SIZE, and GLX ALPHA SIZE. GLX_BUFFER_SIZE, attrs->rgba_size, GLX_RED_SIZE, attrs->red_size, GLX_GREEN_SIZE, attrs->green_size, GLX_BLUE_SIZE, attrs->blue_size, GLX_ALPHA_SIZE, attrs->alpha_size, GLX_DEPTH_SIZE, attrs->depth_size, GLX_STENCIL_SIZE, attrs->stencil_size, GLX_SAMPLE_BUFFERS, attrs->sample_buffers, GLX_SAMPLES, attrs->samples, GLX_DOUBLEBUFFER, attrs->double_buffered, GLX_ACCUM_RED_SIZE, attrs->accum_buffer, GLX_ACCUM_GREEN_SIZE, attrs->accum_buffer, GLX_ACCUM_BLUE_SIZE, attrs->accum_buffer, GLX_ACCUM_ALPHA_SIZE, attrs->accum_buffer, // According to the GLX 1.4 spec Table 3.4, the default value of // GLX_DRAWABLE_TYPE is GLX_WINDOW_BIT. Explicitly set the default // here for the sake of self-documentation. GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, 0, }; // Set glx_fbconfig. configs = wrapped_glXChooseFBConfig(plat, dpy->x11.xlib, dpy->x11.screen, attrib_list, &num_configs); if (!configs || num_configs == 0) { wcore_errorf(WAFFLE_ERROR_UNKNOWN, "glXChooseFBConfig returned no matching configs"); goto error; } // Simply take the first. self->glx_fbconfig = configs[0]; // Set glx_fbconfig_id. ok = !wrapped_glXGetFBConfigAttrib(plat, dpy->x11.xlib, self->glx_fbconfig, GLX_FBCONFIG_ID, &self->glx_fbconfig_id); if (!ok) { wcore_errorf(WAFFLE_ERROR_UNKNOWN, "glxGetFBConfigAttrib failed"); goto error; } // Set xcb_visual_id. vi = wrapped_glXGetVisualFromFBConfig(plat, dpy->x11.xlib, self->glx_fbconfig); if (!vi) { wcore_errorf(WAFFLE_ERROR_UNKNOWN, "glXGetVisualInfoFromFBConfig failed with " "GLXFBConfigID=0x%x\n", self->glx_fbconfig_id); goto error; } self->xcb_visual_id = vi->visualid; goto cleanup; error: glx_config_destroy(&self->wcore); self = NULL; cleanup: if (configs) XFree(configs); if (vi) XFree(vi); return &self->wcore; }
static bool parse_context_version(struct wcore_config_attrs *attrs, const int32_t attrib_list[]) { wcore_attrib_list_get_with_default(attrib_list, WAFFLE_CONTEXT_MAJOR_VERSION, &attrs->context_major_version, attrs->context_major_version); wcore_attrib_list_get_with_default(attrib_list, WAFFLE_CONTEXT_MINOR_VERSION, &attrs->context_minor_version, attrs->context_minor_version); if (attrs->context_major_version < 1) { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "WAFFLE_CONTEXT_MAJOR_VERSION must be >= 1"); return false; } if (attrs->context_minor_version < 0) { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "WAFFLE_CONTEXT_MINOR_VERSION must be >= 0"); return false; } attrs->context_full_version = 10 * attrs->context_major_version + attrs->context_minor_version; switch (attrs->context_api) { case WAFFLE_CONTEXT_OPENGL: if (attrs->context_full_version < 10) { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "for OpenGL, the requested context version " "must be >= 1.0"); return false; } break; case WAFFLE_CONTEXT_OPENGL_ES1: if (attrs->context_full_version != 10 && attrs->context_full_version != 11) { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "for OpenGL ES1, the requested context version " "must be 1.0 or 1.1"); return false; } break; case WAFFLE_CONTEXT_OPENGL_ES2: if (attrs->context_major_version != 2) { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "for OpenGL ES2, the requested major context " "version must be 2"); return false; } break; case WAFFLE_CONTEXT_OPENGL_ES3: if (attrs->context_major_version != 3) { wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE, "for OpenGL ES3, the requested major context " "version must be 3"); return false; } break; default: wcore_error_internal("attrs->context_api has bad value 0x%x", attrs->context_api); return false; } return true; }
struct wcore_config* nacl_config_choose(struct wcore_platform *wc_plat, struct wcore_display *wc_dpy, const struct wcore_config_attrs *attrs) { struct nacl_config *self; bool ok = true; self = wcore_calloc(sizeof(*self)); if (self == NULL) return NULL; // Currently only OpenGL ES 2.0 is supported. if (attrs->context_api != WAFFLE_CONTEXT_OPENGL_ES2) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "NaCl does no support context type %s.", wcore_enum_to_string(attrs->context_api)); goto error; } if (attrs->context_robust) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "NaCl does not support robust contexts."); goto error; } unsigned attr = 0; // Max amount of attribs is hardcoded in nacl_config.h (64) #define PUSH_ATTRIB(a, val) \ if (val != WAFFLE_DONT_CARE) {\ self->attribs[attr++] = a; \ self->attribs[attr++] = val;\ } PUSH_ATTRIB(PP_GRAPHICS3DATTRIB_ALPHA_SIZE, attrs->alpha_size); PUSH_ATTRIB(PP_GRAPHICS3DATTRIB_BLUE_SIZE, attrs->blue_size); PUSH_ATTRIB(PP_GRAPHICS3DATTRIB_GREEN_SIZE, attrs->green_size); PUSH_ATTRIB(PP_GRAPHICS3DATTRIB_RED_SIZE, attrs->red_size); PUSH_ATTRIB(PP_GRAPHICS3DATTRIB_DEPTH_SIZE, attrs->depth_size); PUSH_ATTRIB(PP_GRAPHICS3DATTRIB_STENCIL_SIZE, attrs->stencil_size); PUSH_ATTRIB(PP_GRAPHICS3DATTRIB_SAMPLES, attrs->samples); PUSH_ATTRIB(PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, attrs->sample_buffers); // Note, we have to have at least 1x1 size so that initial context // backing surface creation will succeed without errors. Later on // it is resized by window creation/resize. PUSH_ATTRIB(PP_GRAPHICS3DATTRIB_WIDTH, 1); PUSH_ATTRIB(PP_GRAPHICS3DATTRIB_HEIGHT, 1); PUSH_ATTRIB(PP_GRAPHICS3DATTRIB_NONE, 0); #undef PUSH_ATTRIB ok = wcore_config_init(&self->wcore, wc_dpy, attrs); if (!ok) goto error; return &self->wcore; error: nacl_config_destroy(&self->wcore); self = NULL; return NULL; }
/// @brief Check the values of `attrs->context_*`. static bool glx_config_check_context_attrs(struct glx_display *dpy, const struct wcore_config_attrs *attrs) { if (attrs->context_forward_compatible) { assert(attrs->context_api == WAFFLE_CONTEXT_OPENGL); assert(wcore_config_attrs_version_ge(attrs, 30)); } if (attrs->context_debug && !dpy->ARB_create_context) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_ARB_create_context is required in order to " "request a debug context"); return false; } if (attrs->context_robust && !dpy->ARB_create_context_robustness) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_ARB_create_context_robustness is required in order to " "request a robust access context"); return false; } switch (attrs->context_api) { case WAFFLE_CONTEXT_OPENGL: if (glx_context_needs_arb_create_context(attrs) && !dpy->ARB_create_context) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_ARB_create_context is required in order to " "request an OpenGL version greater or equal than 3.2"); return false; } else if (wcore_config_attrs_version_ge(attrs, 32) && !dpy->ARB_create_context_profile) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_ARB_create_context_profile is required " "to create a context with version >= 3.2"); return false; } else if (wcore_config_attrs_version_ge(attrs, 32)) { assert(attrs->context_profile == WAFFLE_CONTEXT_CORE_PROFILE || attrs->context_profile == WAFFLE_CONTEXT_COMPATIBILITY_PROFILE); } if (attrs->context_forward_compatible && !dpy->ARB_create_context) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_ARB_create_context is required in order to " "request a forward-compatible context"); return false; } return true; case WAFFLE_CONTEXT_OPENGL_ES1: if (!dpy->EXT_create_context_es_profile) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_EXT_create_context_es_profile is required " "to create an OpenGL ES1 context"); return false; } return true; case WAFFLE_CONTEXT_OPENGL_ES2: if (!dpy->EXT_create_context_es_profile && !dpy->EXT_create_context_es2_profile) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_EXT_create_context_es_profile or " "GLX_EXT_create_context_es2_profile is required " "to create an OpenGL ES2 context"); return false; } return true; case WAFFLE_CONTEXT_OPENGL_ES3: if (!dpy->EXT_create_context_es_profile) { wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM, "GLX_EXT_create_context_es_profile is required " "to create an OpenGL ES3 context"); return false; } return true; default: assert(false); return false; } }