Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/sun/java2d/opengl/GLXGraphicsConfig.c
32288 views
/*1* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <stdlib.h>26#include <string.h>2728#include "sun_java2d_opengl_GLXGraphicsConfig.h"2930#include "jni.h"31#include "jlong.h"32#include "GLXGraphicsConfig.h"33#include "GLXSurfaceData.h"34#include "awt_GraphicsEnv.h"35#include "awt_util.h"3637#ifndef HEADLESS3839extern Bool usingXinerama;4041/**42* This is a globally shared context used when creating textures. When any43* new contexts are created, they specify this context as the "share list"44* context, which means any texture objects created when this shared context45* is current will be available to any other context.46*/47static GLXContext sharedContext = 0;4849/**50* Attempts to initialize GLX and the core OpenGL library. For this method51* to return JNI_TRUE, the following must be true:52* - libGL must be loaded successfully (via dlopen)53* - all function symbols from libGL must be available and loaded properly54* - the GLX extension must be available through X1155* - client GLX version must be >= 1.356* If any of these requirements are not met, this method will return57* JNI_FALSE, indicating there is no hope of using GLX/OpenGL for any58* GraphicsConfig in the environment.59*/60static jboolean61GLXGC_InitGLX()62{63int errorbase, eventbase;64const char *version;6566J2dRlsTraceLn(J2D_TRACE_INFO, "GLXGC_InitGLX");6768if (!OGLFuncs_OpenLibrary()) {69return JNI_FALSE;70}7172if (!OGLFuncs_InitPlatformFuncs() ||73!OGLFuncs_InitBaseFuncs() ||74!OGLFuncs_InitExtFuncs())75{76OGLFuncs_CloseLibrary();77return JNI_FALSE;78}7980if (!j2d_glXQueryExtension(awt_display, &errorbase, &eventbase)) {81J2dRlsTraceLn(J2D_TRACE_ERROR,82"GLXGC_InitGLX: GLX extension is not present");83OGLFuncs_CloseLibrary();84return JNI_FALSE;85}8687version = j2d_glXGetClientString(awt_display, GLX_VERSION);88if (version == NULL) {89J2dRlsTraceLn(J2D_TRACE_ERROR,90"GLXGC_InitGLX: could not query GLX version");91OGLFuncs_CloseLibrary();92return JNI_FALSE;93}9495// we now only verify that the client GLX version is >= 1.3 (if the96// server does not support GLX 1.3, then we will find that out later97// when we attempt to create a GLXFBConfig)98J2dRlsTraceLn1(J2D_TRACE_INFO,99"GLXGC_InitGLX: client GLX version=%s", version);100if (!((version[0] == '1' && version[2] >= '3') || (version[0] > '1'))) {101J2dRlsTraceLn(J2D_TRACE_ERROR,102"GLXGC_InitGLX: invalid GLX version; 1.3 is required");103OGLFuncs_CloseLibrary();104return JNI_FALSE;105}106107return JNI_TRUE;108}109110/**111* Returns JNI_TRUE if GLX is available for the current display. Note that112* this method will attempt to initialize GLX (and all the necessary function113* symbols) if it has not been already. The AWT_LOCK must be acquired before114* calling this method.115*/116jboolean117GLXGC_IsGLXAvailable()118{119static jboolean glxAvailable = JNI_FALSE;120static jboolean firstTime = JNI_TRUE;121122J2dTraceLn(J2D_TRACE_INFO, "GLXGC_IsGLXAvailable");123124if (firstTime) {125glxAvailable = GLXGC_InitGLX();126firstTime = JNI_FALSE;127}128129return glxAvailable;130}131132/**133* Disposes all memory and resources allocated for the given OGLContext.134*/135static void136GLXGC_DestroyOGLContext(OGLContext *oglc)137{138GLXCtxInfo *ctxinfo;139140J2dTraceLn(J2D_TRACE_INFO, "GLXGC_DestroyOGLContext");141142if (oglc == NULL) {143J2dRlsTraceLn(J2D_TRACE_ERROR,144"GLXGC_DestroyOGLContext: context is null");145return;146}147148// at this point, this context will be current to its scratch surface149// so the following GL/GLX operations should be safe...150151OGLContext_DestroyContextResources(oglc);152153ctxinfo = (GLXCtxInfo *)oglc->ctxInfo;154if (ctxinfo != NULL) {155// release the current context before we continue156j2d_glXMakeContextCurrent(awt_display, None, None, NULL);157158if (ctxinfo->context != 0) {159j2d_glXDestroyContext(awt_display, ctxinfo->context);160}161if (ctxinfo->scratchSurface != 0) {162j2d_glXDestroyPbuffer(awt_display, ctxinfo->scratchSurface);163}164165free(ctxinfo);166}167168free(oglc);169}170171/**172* Disposes all memory and resources associated with the given173* GLXGraphicsConfigInfo (including its native OGLContext data).174*/175void176OGLGC_DestroyOGLGraphicsConfig(jlong pConfigInfo)177{178GLXGraphicsConfigInfo *glxinfo =179(GLXGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);180181J2dTraceLn(J2D_TRACE_INFO, "OGLGC_DestroyOGLGraphicsConfig");182183if (glxinfo == NULL) {184J2dRlsTraceLn(J2D_TRACE_ERROR,185"OGLGC_DestroyOGLGraphicsConfig: info is null");186return;187}188189if (glxinfo->context != NULL) {190GLXGC_DestroyOGLContext(glxinfo->context);191}192193free(glxinfo);194}195196/**197* Attempts to create a new GLXFBConfig for the requested screen and visual.198* If visualid is 0, this method will iterate through all GLXFBConfigs (if199* any) that match the requested attributes and will attempt to find an200* fbconfig with a minimal combined depth+stencil buffer. Note that we201* currently only need depth capabilities (for shape clipping purposes), but202* glXChooseFBConfig() will often return a list of fbconfigs with the largest203* depth buffer (and stencil) sizes at the top of the list. Therefore, we204* scan through the whole list to find the most VRAM-efficient fbconfig.205* If visualid is non-zero, the GLXFBConfig associated with the given visual206* is chosen (assuming it meets the requested attributes). If there are no207* valid GLXFBConfigs available, this method returns 0.208*/209static GLXFBConfig210GLXGC_InitFBConfig(JNIEnv *env, jint screennum, VisualID visualid)211{212GLXFBConfig *fbconfigs;213GLXFBConfig chosenConfig = 0;214int nconfs, i;215int attrlist[] = {GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PBUFFER_BIT,216GLX_RENDER_TYPE, GLX_RGBA_BIT,217GLX_CONFIG_CAVEAT, GLX_NONE, // avoid "slow" configs218GLX_DEPTH_SIZE, 16, // anything >= 16 will work for us2190};220221// this is the initial minimum value for the combined depth+stencil size222// (we initialize it to some absurdly high value; realistic values will223// be much less than this number)224int minDepthPlusStencil = 512;225226J2dRlsTraceLn2(J2D_TRACE_INFO, "GLXGC_InitFBConfig: scn=%d vis=0x%x",227screennum, visualid);228229// find all fbconfigs for this screen with the provided attributes230fbconfigs = j2d_glXChooseFBConfig(awt_display, screennum,231attrlist, &nconfs);232233if ((fbconfigs == NULL) || (nconfs <= 0)) {234J2dRlsTraceLn(J2D_TRACE_ERROR,235"GLXGC_InitFBConfig: could not find any valid fbconfigs");236return 0;237}238239J2dRlsTraceLn(J2D_TRACE_VERBOSE, " candidate fbconfigs:");240241// iterate through the list of fbconfigs, looking for the one that matches242// the requested VisualID and supports RGBA rendering as well as the243// creation of windows and pbuffers244for (i = 0; i < nconfs; i++) {245XVisualInfo *xvi;246VisualID fbvisualid;247GLXFBConfig fbc = fbconfigs[i];248249// get VisualID from GLXFBConfig250xvi = j2d_glXGetVisualFromFBConfig(awt_display, fbc);251if (xvi == NULL) {252continue;253}254fbvisualid = xvi->visualid;255XFree(xvi);256257if (visualid == 0 || visualid == fbvisualid) {258int dtype, rtype, depth, stencil, db, alpha, gamma;259260// get GLX-specific attributes from GLXFBConfig261j2d_glXGetFBConfigAttrib(awt_display, fbc,262GLX_DRAWABLE_TYPE, &dtype);263j2d_glXGetFBConfigAttrib(awt_display, fbc,264GLX_RENDER_TYPE, &rtype);265j2d_glXGetFBConfigAttrib(awt_display, fbc,266GLX_DEPTH_SIZE, &depth);267j2d_glXGetFBConfigAttrib(awt_display, fbc,268GLX_STENCIL_SIZE, &stencil);269270// these attributes don't affect our decision, but they are271// interesting for trace logs, so we will query them anyway272j2d_glXGetFBConfigAttrib(awt_display, fbc,273GLX_DOUBLEBUFFER, &db);274j2d_glXGetFBConfigAttrib(awt_display, fbc,275GLX_ALPHA_SIZE, &alpha);276277J2dRlsTrace5(J2D_TRACE_VERBOSE,278"[V] id=0x%x db=%d alpha=%d depth=%d stencil=%d valid=",279fbvisualid, db, alpha, depth, stencil);280281#ifdef __sparc282/*283* Sun's OpenGL implementation will always284* return at least two GLXFBConfigs (visuals) from285* glXChooseFBConfig(). The first will be a linear (gamma286* corrected) visual; the second will have the same capabilities287* as the first, except it will be a non-linear (non-gamma288* corrected) visual, which is the one we want, otherwise289* everything will look "washed out". So we will reject any290* visuals that have gamma values other than 1.0 (the value291* returned by glXGetFBConfigAttrib() will be scaled292* by 100, so 100 corresponds to a gamma value of 1.0, 220293* corresponds to 2.2, and so on).294*/295j2d_glXGetFBConfigAttrib(awt_display, fbc,296GLX_GAMMA_VALUE_SUN, &gamma);297if (gamma != 100) {298J2dRlsTrace(J2D_TRACE_VERBOSE, "false (linear visual)\n");299continue;300}301#endif /* __sparc */302303if ((dtype & GLX_WINDOW_BIT) &&304(dtype & GLX_PBUFFER_BIT) &&305(rtype & GLX_RGBA_BIT) &&306(depth >= 16))307{308if (visualid == 0) {309// when visualid == 0, we loop through all configs310// looking for an fbconfig that has the smallest combined311// depth+stencil size (this keeps VRAM usage to a minimum)312if ((depth + stencil) < minDepthPlusStencil) {313J2dRlsTrace(J2D_TRACE_VERBOSE, "true\n");314minDepthPlusStencil = depth + stencil;315chosenConfig = fbc;316} else {317J2dRlsTrace(J2D_TRACE_VERBOSE,318"false (large depth)\n");319}320continue;321} else {322// in this case, visualid == fbvisualid, which means323// we've found a valid fbconfig corresponding to the324// requested VisualID, so break out of the loop325J2dRlsTrace(J2D_TRACE_VERBOSE, "true\n");326chosenConfig = fbc;327break;328}329} else {330J2dRlsTrace(J2D_TRACE_VERBOSE, "false (bad match)\n");331}332}333}334335// free the list of fbconfigs336XFree(fbconfigs);337338if (chosenConfig == 0) {339J2dRlsTraceLn(J2D_TRACE_ERROR,340"GLXGC_InitFBConfig: could not find an appropriate fbconfig");341return 0;342}343344return chosenConfig;345}346347/**348* Returns the X11 VisualID that corresponds to the best GLXFBConfig for the349* given screen. If no valid visual could be found, this method returns zero.350* Note that this method will attempt to initialize GLX (and all the351* necessary function symbols) if it has not been already. The AWT_LOCK352* must be acquired before calling this method.353*/354VisualID355GLXGC_FindBestVisual(JNIEnv *env, jint screen)356{357GLXFBConfig fbc;358XVisualInfo *xvi;359VisualID visualid;360361J2dRlsTraceLn1(J2D_TRACE_INFO, "GLXGC_FindBestVisual: scn=%d", screen);362363if (!GLXGC_IsGLXAvailable()) {364J2dRlsTraceLn(J2D_TRACE_ERROR,365"GLXGC_FindBestVisual: could not initialize GLX");366return 0;367}368369fbc = GLXGC_InitFBConfig(env, screen, 0);370if (fbc == 0) {371J2dRlsTraceLn(J2D_TRACE_ERROR,372"GLXGC_FindBestVisual: could not find best visual");373return 0;374}375376xvi = j2d_glXGetVisualFromFBConfig(awt_display, fbc);377if (xvi == NULL) {378J2dRlsTraceLn(J2D_TRACE_ERROR,379"GLXGC_FindBestVisual: could not get visual for fbconfig");380return 0;381}382383visualid = xvi->visualid;384XFree(xvi);385386J2dRlsTraceLn2(J2D_TRACE_INFO,387"GLXGC_FindBestVisual: chose 0x%x as the best visual for screen %d",388visualid, screen);389390return visualid;391}392393/**394* Creates a scratch pbuffer, which can be used to make a context current395* for extension queries, etc.396*/397static GLXPbuffer398GLXGC_InitScratchPbuffer(GLXFBConfig fbconfig)399{400int pbattrlist[] = {GLX_PBUFFER_WIDTH, 1,401GLX_PBUFFER_HEIGHT, 1,402GLX_PRESERVED_CONTENTS, GL_FALSE,4030};404405J2dTraceLn(J2D_TRACE_INFO, "GLXGC_InitScratchPbuffer");406407return j2d_glXCreatePbuffer(awt_display, fbconfig, pbattrlist);408}409410/**411* Initializes a new OGLContext, which includes the native GLXContext handle412* and some other important information such as the associated GLXFBConfig.413*/414static OGLContext *415GLXGC_InitOGLContext(GLXFBConfig fbconfig, GLXContext context,416GLXPbuffer scratch, jint caps)417{418OGLContext *oglc;419GLXCtxInfo *ctxinfo;420421J2dTraceLn(J2D_TRACE_INFO, "GLXGC_InitOGLContext");422423oglc = (OGLContext *)malloc(sizeof(OGLContext));424if (oglc == NULL) {425J2dRlsTraceLn(J2D_TRACE_ERROR,426"GLXGC_InitOGLContext: could not allocate memory for oglc");427return NULL;428}429430memset(oglc, 0, sizeof(OGLContext));431432ctxinfo = (GLXCtxInfo *)malloc(sizeof(GLXCtxInfo));433if (ctxinfo == NULL) {434J2dRlsTraceLn(J2D_TRACE_ERROR,435"GLXGC_InitOGLContext: could not allocate memory for ctxinfo");436free(oglc);437return NULL;438}439440ctxinfo->fbconfig = fbconfig;441ctxinfo->context = context;442ctxinfo->scratchSurface = scratch;443oglc->ctxInfo = ctxinfo;444oglc->caps = caps;445446return oglc;447}448449#endif /* !HEADLESS */450451/**452* Determines whether the GLX pipeline can be used for a given GraphicsConfig453* provided its screen number and visual ID. If the minimum requirements are454* met, the native GLXGraphicsConfigInfo structure is initialized for this455* GraphicsConfig with the necessary information (GLXFBConfig, etc.)456* and a pointer to this structure is returned as a jlong. If457* initialization fails at any point, zero is returned, indicating that GLX458* cannot be used for this GraphicsConfig (we should fallback on the existing459* X11 pipeline).460*/461JNIEXPORT jlong JNICALL462Java_sun_java2d_opengl_GLXGraphicsConfig_getGLXConfigInfo(JNIEnv *env,463jclass glxgc,464jint screennum,465jint visnum)466{467#ifndef HEADLESS468OGLContext *oglc;469GLXFBConfig fbconfig;470GLXContext context;471GLXPbuffer scratch;472GLXGraphicsConfigInfo *glxinfo;473jint caps = CAPS_EMPTY;474int db, alpha;475const unsigned char *versionstr;476477J2dRlsTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_getGLXConfigInfo");478479if (usingXinerama) {480// when Xinerama is enabled, the screen ID needs to be 0481screennum = 0;482}483484fbconfig = GLXGC_InitFBConfig(env, screennum, (VisualID)visnum);485if (fbconfig == 0) {486J2dRlsTraceLn(J2D_TRACE_ERROR,487"GLXGraphicsConfig_getGLXConfigInfo: could not create fbconfig");488return 0L;489}490491if (sharedContext == 0) {492// create the one shared context493sharedContext = j2d_glXCreateNewContext(awt_display, fbconfig,494GLX_RGBA_TYPE, 0, GL_TRUE);495if (sharedContext == 0) {496J2dRlsTraceLn(J2D_TRACE_ERROR,497"GLXGraphicsConfig_getGLXConfigInfo: could not create shared context");498return 0L;499}500}501502// create the GLXContext for this GLXGraphicsConfig503context = j2d_glXCreateNewContext(awt_display, fbconfig,504GLX_RGBA_TYPE, sharedContext,505GL_TRUE);506if (context == 0) {507J2dRlsTraceLn(J2D_TRACE_ERROR,508"GLXGraphicsConfig_getGLXConfigInfo: could not create GLX context");509return 0L;510}511512// this is pretty sketchy, but it seems to be the easiest way to create513// some form of GLXDrawable using only the display and a GLXFBConfig514// (in order to make the context current for checking the version,515// extensions, etc)...516scratch = GLXGC_InitScratchPbuffer(fbconfig);517if (scratch == 0) {518J2dRlsTraceLn(J2D_TRACE_ERROR,519"GLXGraphicsConfig_getGLXConfigInfo: could not create scratch pbuffer");520j2d_glXDestroyContext(awt_display, context);521return 0L;522}523524// the context must be made current before we can query the525// version and extension strings526j2d_glXMakeContextCurrent(awt_display, scratch, scratch, context);527528#ifdef __sparc529/*530* 6438225: The software rasterizer used by Sun's OpenGL libraries531* for certain boards has quality issues, and besides, performance532* of these boards is not high enough to justify the use of the533* OpenGL-based Java 2D pipeline. If we detect one of the following534* boards via the GL_RENDERER string, just give up:535* - FFB[2[+]] ("Creator[3D]")536* - PGX-series ("m64")537* - AFB ("Elite3D")538*/539{540const char *renderer = (const char *)j2d_glGetString(GL_RENDERER);541542J2dRlsTraceLn1(J2D_TRACE_VERBOSE,543"GLXGraphicsConfig_getGLXConfigInfo: detected renderer (%s)",544(renderer == NULL) ? "null" : renderer);545546if (renderer == NULL ||547strncmp(renderer, "Creator", 7) == 0 ||548strncmp(renderer, "SUNWm64", 7) == 0 ||549strncmp(renderer, "Elite", 5) == 0)550{551J2dRlsTraceLn1(J2D_TRACE_ERROR,552"GLXGraphicsConfig_getGLXConfigInfo: unsupported board (%s)",553(renderer == NULL) ? "null" : renderer);554j2d_glXMakeContextCurrent(awt_display, None, None, NULL);555j2d_glXDestroyPbuffer(awt_display, scratch);556j2d_glXDestroyContext(awt_display, context);557return 0L;558}559}560#endif /* __sparc */561562versionstr = j2d_glGetString(GL_VERSION);563OGLContext_GetExtensionInfo(env, &caps);564565// destroy the temporary resources566j2d_glXMakeContextCurrent(awt_display, None, None, NULL);567568J2dRlsTraceLn1(J2D_TRACE_INFO,569"GLXGraphicsConfig_getGLXConfigInfo: OpenGL version=%s",570(versionstr == NULL) ? "null" : (char *)versionstr);571572if (!OGLContext_IsVersionSupported(versionstr)) {573J2dRlsTraceLn(J2D_TRACE_ERROR,574"GLXGraphicsConfig_getGLXConfigInfo: OpenGL 1.2 is required");575j2d_glXDestroyPbuffer(awt_display, scratch);576j2d_glXDestroyContext(awt_display, context);577return 0L;578}579580// get config-specific capabilities581j2d_glXGetFBConfigAttrib(awt_display, fbconfig, GLX_DOUBLEBUFFER, &db);582if (db) {583caps |= CAPS_DOUBLEBUFFERED;584}585j2d_glXGetFBConfigAttrib(awt_display, fbconfig, GLX_ALPHA_SIZE, &alpha);586if (alpha > 0) {587caps |= CAPS_STORED_ALPHA;588}589590// initialize the OGLContext, which wraps the GLXFBConfig and GLXContext591oglc = GLXGC_InitOGLContext(fbconfig, context, scratch, caps);592if (oglc == NULL) {593J2dRlsTraceLn(J2D_TRACE_ERROR,594"GLXGraphicsConfig_getGLXConfigInfo: could not create oglc");595j2d_glXDestroyPbuffer(awt_display, scratch);596j2d_glXDestroyContext(awt_display, context);597return 0L;598}599600J2dTraceLn(J2D_TRACE_VERBOSE,601"GLXGraphicsConfig_getGLXConfigInfo: finished checking dependencies");602603// create the GLXGraphicsConfigInfo record for this config604glxinfo = (GLXGraphicsConfigInfo *)malloc(sizeof(GLXGraphicsConfigInfo));605if (glxinfo == NULL) {606J2dRlsTraceLn(J2D_TRACE_ERROR,607"GLXGraphicsConfig_getGLXConfigInfo: could not allocate memory for glxinfo");608GLXGC_DestroyOGLContext(oglc);609return 0L;610}611612glxinfo->screen = screennum;613glxinfo->visual = visnum;614glxinfo->context = oglc;615glxinfo->fbconfig = fbconfig;616617return ptr_to_jlong(glxinfo);618#else619return 0L;620#endif /* !HEADLESS */621}622623JNIEXPORT void JNICALL624Java_sun_java2d_opengl_GLXGraphicsConfig_initConfig(JNIEnv *env,625jobject glxgc,626jlong aData,627jlong configInfo)628{629#ifndef HEADLESS630GLXGraphicsConfigInfo *glxinfo;631AwtGraphicsConfigDataPtr configData =632(AwtGraphicsConfigDataPtr)jlong_to_ptr(aData);633634J2dTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_initConfig");635636if (configData == NULL) {637JNU_ThrowNullPointerException(env, "Native GraphicsConfig missing");638return;639}640641glxinfo = (GLXGraphicsConfigInfo *)jlong_to_ptr(configInfo);642if (glxinfo == NULL) {643JNU_ThrowNullPointerException(env,644"GLXGraphicsConfigInfo data missing");645return;646}647648configData->glxInfo = glxinfo;649#endif /* !HEADLESS */650}651652JNIEXPORT jint JNICALL653Java_sun_java2d_opengl_GLXGraphicsConfig_getOGLCapabilities(JNIEnv *env,654jclass glxgc,655jlong configInfo)656{657#ifndef HEADLESS658GLXGraphicsConfigInfo *glxinfo =659(GLXGraphicsConfigInfo *)jlong_to_ptr(configInfo);660661J2dTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_getOGLCapabilities");662663if (glxinfo == NULL || glxinfo->context == NULL) {664return CAPS_EMPTY;665}666667return glxinfo->context->caps;668#else669return CAPS_EMPTY;670#endif /* !HEADLESS */671}672673674