X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fcontext.c;h=be983d4c86ab5b32b4afd9aa653827197bc62edd;hb=555f67c3d717a52464b517cd6d9874468ab3bd92;hp=4b5b694a7fb21c60574d882f399278d4159d50de;hpb=2b7fd5b11df95869249a1bdc6e1b222747aaa075;p=mesa.git diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index 4b5b694a7fb..be983d4c86a 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -118,7 +118,9 @@ #include "scissor.h" #include "shared.h" #include "shaderobj.h" -#include "simple_list.h" +#include "shaderimage.h" +#include "util/simple_list.h" +#include "util/strtod.h" #include "state.h" #include "stencil.h" #include "texcompress_s3tc.h" @@ -134,6 +136,7 @@ #include "math/m_matrix.h" #include "main/dispatch.h" /* for _gloffset_COUNT */ #include "uniforms.h" +#include "macros.h" #ifdef USE_SPARC_ASM #include "sparc/sparc.h" @@ -335,31 +338,6 @@ _mesa_destroy_visual( struct gl_config *vis ) /*@{*/ -/** - * This is lame. gdb only seems to recognize enum types that are - * actually used somewhere. We want to be able to print/use enum - * values such as TEXTURE_2D_INDEX in gdb. But we don't actually use - * the gl_texture_index type anywhere. Thus, this lame function. - */ -static void -dummy_enum_func(void) -{ - gl_buffer_index bi = BUFFER_FRONT_LEFT; - gl_face_index fi = FACE_POS_X; - gl_frag_result fr = FRAG_RESULT_DEPTH; - gl_texture_index ti = TEXTURE_2D_ARRAY_INDEX; - gl_vert_attrib va = VERT_ATTRIB_POS; - gl_varying_slot vs = VARYING_SLOT_POS; - - (void) bi; - (void) fi; - (void) fr; - (void) ti; - (void) va; - (void) vs; -} - - /** * One-time initialization mutex lock. * @@ -368,6 +346,16 @@ dummy_enum_func(void) mtx_t OneTimeLock = _MTX_INITIALIZER_NP; +/** + * Calls all the various one-time-fini functions in Mesa + */ + +static void +one_time_fini(void) +{ + _mesa_destroy_shader_compiler(); + _mesa_locale_fini(); +} /** * Calls all the various one-time-init functions in Mesa. @@ -389,13 +377,14 @@ one_time_init( struct gl_context *ctx ) if (!api_init_mask) { GLuint i; - /* do some implementation tests */ - assert( sizeof(GLbyte) == 1 ); - assert( sizeof(GLubyte) == 1 ); - assert( sizeof(GLshort) == 2 ); - assert( sizeof(GLushort) == 2 ); - assert( sizeof(GLint) == 4 ); - assert( sizeof(GLuint) == 4 ); + STATIC_ASSERT(sizeof(GLbyte) == 1); + STATIC_ASSERT(sizeof(GLubyte) == 1); + STATIC_ASSERT(sizeof(GLshort) == 2); + STATIC_ASSERT(sizeof(GLushort) == 2); + STATIC_ASSERT(sizeof(GLint) == 4); + STATIC_ASSERT(sizeof(GLuint) == 4); + + _mesa_locale_init(); _mesa_one_time_init_extension_overrides(); @@ -405,16 +394,14 @@ one_time_init( struct gl_context *ctx ) _mesa_ubyte_to_float_color_tab[i] = (float) i / 255.0F; } + atexit(one_time_fini); + #if defined(DEBUG) && defined(__DATE__) && defined(__TIME__) if (MESA_VERBOSE != 0) { _mesa_debug(ctx, "Mesa %s DEBUG build %s %s\n", PACKAGE_VERSION, __DATE__, __TIME__); } #endif - -#ifdef DEBUG - _mesa_test_formats(); -#endif } /* per-API one-time init */ @@ -427,13 +414,6 @@ one_time_init( struct gl_context *ctx ) api_init_mask |= 1 << ctx->API; mtx_unlock(&OneTimeLock); - - /* Hopefully atexit() is widely available. If not, we may need some - * #ifdef tests here. - */ - atexit(_mesa_destroy_shader_compiler); - - dummy_enum_func(); } @@ -446,7 +426,7 @@ _mesa_init_current(struct gl_context *ctx) GLuint i; /* Init all to (0,0,0,1) */ - for (i = 0; i < Elements(ctx->Current.Attrib); i++) { + for (i = 0; i < ARRAY_SIZE(ctx->Current.Attrib); i++) { ASSIGN_4V( ctx->Current.Attrib[i], 0.0, 0.0, 0.0, 1.0 ); } @@ -487,13 +467,15 @@ init_program_limits(struct gl_constants *consts, gl_shader_stage stage, prog->MaxOutputComponents = 16 * 4; /* old limit not to break tnl and swrast */ break; case MESA_SHADER_FRAGMENT: - prog->MaxParameters = MAX_NV_FRAGMENT_PROGRAM_PARAMS; - prog->MaxAttribs = MAX_NV_FRAGMENT_PROGRAM_INPUTS; + prog->MaxParameters = MAX_FRAGMENT_PROGRAM_PARAMS; + prog->MaxAttribs = MAX_FRAGMENT_PROGRAM_INPUTS; prog->MaxAddressRegs = MAX_FRAGMENT_PROGRAM_ADDRESS_REGS; prog->MaxUniformComponents = 4 * MAX_UNIFORMS; prog->MaxInputComponents = 16 * 4; /* old limit not to break tnl and swrast */ prog->MaxOutputComponents = 0; /* value not used */ break; + case MESA_SHADER_TESS_CTRL: + case MESA_SHADER_TESS_EVAL: case MESA_SHADER_GEOMETRY: prog->MaxParameters = MAX_VERTEX_PROGRAM_PARAMS; prog->MaxAttribs = MAX_VERTEX_GENERIC_ATTRIBS; @@ -552,6 +534,8 @@ init_program_limits(struct gl_constants *consts, gl_shader_stage stage, prog->MaxAtomicBuffers = 0; prog->MaxAtomicCounters = 0; + + prog->MaxShaderStorageBlocks = 8; } @@ -613,6 +597,12 @@ _mesa_init_constants(struct gl_constants *consts, gl_api api) consts->MaxUniformBlockSize = 16384; consts->UniformBufferOffsetAlignment = 1; + /** GL_ARB_shader_storage_buffer_object */ + consts->MaxCombinedShaderStorageBlocks = 8; + consts->MaxShaderStorageBufferBindings = 8; + consts->MaxShaderStorageBlockSize = 128 * 1024 * 1024; /* 2^27 */ + consts->ShaderStorageBufferOffsetAlignment = 256; + /* GL_ARB_explicit_uniform_location, GL_MAX_UNIFORM_LOCATIONS */ consts->MaxUserAssignableUniformLocations = 4 * MESA_SHADER_STAGES * MAX_UNIFORMS; @@ -656,7 +646,7 @@ _mesa_init_constants(struct gl_constants *consts, gl_api api) consts->MaxSamples = 0; /* GLSL default if NativeIntegers == FALSE */ - consts->UniformBooleanTrue = FLT_AS_UINT(1.0f); + consts->UniformBooleanTrue = FLOAT_AS_UNION(1.0f).u; /* GL_ARB_sync */ consts->MaxServerWaitTimeout = 0x1fff7fffffffULL; @@ -664,6 +654,9 @@ _mesa_init_constants(struct gl_constants *consts, gl_api api) /* GL_EXT_provoking_vertex */ consts->QuadsFollowProvokingVertexConvention = GL_TRUE; + /** GL_ARB_viewport_array */ + consts->LayerAndVPIndexProvokingVertex = GL_UNDEFINED_VERTEX; + /* GL_EXT_transform_feedback */ consts->MaxTransformFeedbackBuffers = MAX_FEEDBACK_BUFFERS; consts->MaxTransformFeedbackSeparateComponents = 4 * MAX_FEEDBACK_ATTRIBS; @@ -722,6 +715,14 @@ _mesa_init_constants(struct gl_constants *consts, gl_api api) /** GL_KHR_context_flush_control */ consts->ContextReleaseBehavior = GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH; + + /** GL_ARB_tessellation_shader */ + consts->MaxTessGenLevel = MAX_TESS_GEN_LEVEL; + consts->MaxPatchVertices = MAX_PATCH_VERTICES; + consts->Program[MESA_SHADER_TESS_CTRL].MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS; + consts->Program[MESA_SHADER_TESS_EVAL].MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS; + consts->MaxTessPatchComponents = MAX_TESS_PATCH_COMPONENTS; + consts->MaxTessControlTotalOutputComponents = MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS; } @@ -820,6 +821,7 @@ init_attrib_groups(struct gl_context *ctx) _mesa_init_feedback( ctx ); _mesa_init_fog( ctx ); _mesa_init_hint( ctx ); + _mesa_init_image_units( ctx ); _mesa_init_line( ctx ); _mesa_init_lighting( ctx ); _mesa_init_matrix( ctx ); @@ -880,20 +882,52 @@ update_default_objects(struct gl_context *ctx) } +/* XXX this is temporary and should be removed at some point in the + * future when there's a reasonable expectation that the libGL library + * contains the _glapi_new_nop_table() and _glapi_set_nop_handler() + * functions which were added in Mesa 10.6. + */ +#if !defined(_WIN32) +/* Avoid libGL / driver ABI break */ +#define USE_GLAPI_NOP_FEATURES 0 +#else +#define USE_GLAPI_NOP_FEATURES 1 +#endif + + /** - * This is the default function we plug into all dispatch table slots - * This helps prevents a segfault when someone calls a GL function without - * first checking if the extension's supported. + * This function is called by the glapi no-op functions. For each OpenGL + * function/entrypoint there's a simple no-op function. These "no-op" + * functions call this function. + * + * If there's a current OpenGL context for the calling thread, we record a + * GL_INVALID_OPERATION error. This can happen either because the app's + * calling an unsupported extension function, or calling an illegal function + * (such as glClear between glBegin/glEnd). + * + * If there's no current OpenGL context for the calling thread, we can + * print a message to stderr. + * + * \param name the name of the OpenGL function */ -int -_mesa_generic_nop(void) +#if USE_GLAPI_NOP_FEATURES +static void +nop_handler(const char *name) { GET_CURRENT_CONTEXT(ctx); - _mesa_error(ctx, GL_INVALID_OPERATION, - "unsupported function called " - "(unsupported extension or deprecated function?)"); - return 0; + if (ctx) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid call)", name); + } +#if defined(DEBUG) + else if (getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG")) { + fprintf(stderr, + "GL User Error: gl%s called without a rendering context\n", + name); + fflush(stderr); + } +#endif } +#endif /** @@ -903,45 +937,70 @@ _mesa_generic_nop(void) static void GLAPIENTRY nop_glFlush(void) { - /* don't record an error like we do in _mesa_generic_nop() */ + /* don't record an error like we do in nop_handler() */ } #endif -extern void (*__glapi_noop_table[])(void); +#if !USE_GLAPI_NOP_FEATURES +static int +generic_nop(void) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_INVALID_OPERATION, + "unsupported function called " + "(unsupported extension or deprecated function?)"); + return 0; +} +#endif /** - * Allocate and initialize a new dispatch table. All the dispatch - * function pointers will point at the _mesa_generic_nop() function - * which raises GL_INVALID_OPERATION. + * Create a new API dispatch table in which all entries point to the + * generic_nop() function. This will not work on Windows because of + * the __stdcall convention which requires the callee to clean up the + * call stack. That's impossible with one generic no-op function. */ struct _glapi_table * -_mesa_alloc_dispatch_table(void) +_mesa_new_nop_table(unsigned numEntries) { - /* Find the larger of Mesa's dispatch table and libGL's dispatch table. - * In practice, this'll be the same for stand-alone Mesa. But for DRI - * Mesa we do this to accomodate different versions of libGL and various - * DRI drivers. - */ - GLint numEntries = MAX2(_glapi_get_dispatch_table_size(), _gloffset_COUNT); struct _glapi_table *table; +#if !USE_GLAPI_NOP_FEATURES table = malloc(numEntries * sizeof(_glapi_proc)); if (table) { _glapi_proc *entry = (_glapi_proc *) table; - GLint i; + unsigned i; for (i = 0; i < numEntries; i++) { -#if defined(_WIN32) - /* FIXME: This will not generate an error, but at least it won't - * corrupt the stack like _mesa_generic_nop does. */ - entry[i] = __glapi_noop_table[i]; + entry[i] = (_glapi_proc) generic_nop; + } + } #else - entry[i] = (_glapi_proc) _mesa_generic_nop; + table = _glapi_new_nop_table(numEntries); #endif - } + return table; +} + + +/** + * Allocate and initialize a new dispatch table. The table will be + * populated with pointers to "no-op" functions. In turn, the no-op + * functions will call nop_handler() above. + */ +static struct _glapi_table * +alloc_dispatch_table(void) +{ + /* Find the larger of Mesa's dispatch table and libGL's dispatch table. + * In practice, this'll be the same for stand-alone Mesa. But for DRI + * Mesa we do this to accommodate different versions of libGL and various + * DRI drivers. + */ + int numEntries = MAX2(_glapi_get_dispatch_table_size(), _gloffset_COUNT); + + struct _glapi_table *table = _mesa_new_nop_table(numEntries); #if defined(_WIN32) + if (table) { /* This is a special case for Windows in the event that * wglGetProcAddress is called between glBegin/End(). * @@ -959,8 +1018,13 @@ _mesa_alloc_dispatch_table(void) * assertion passes and the test continues. */ SET_Flush(table, nop_glFlush); -#endif } +#endif + +#if USE_GLAPI_NOP_FEATURES + _glapi_set_nop_handler(nop_handler); +#endif + return table; } @@ -996,7 +1060,7 @@ create_beginend_table(const struct gl_context *ctx) { struct _glapi_table *table; - table = _mesa_alloc_dispatch_table(); + table = alloc_dispatch_table(); if (!table) return NULL; @@ -1104,9 +1168,7 @@ _mesa_initialize_context(struct gl_context *ctx, ctx->HasConfig = GL_FALSE; } - if (_mesa_is_desktop_gl(ctx)) { - _mesa_override_gl_version(ctx); - } + _mesa_override_gl_version(ctx); /* misc one-time initializations */ one_time_init(ctx); @@ -1135,7 +1197,7 @@ _mesa_initialize_context(struct gl_context *ctx, goto fail; /* setup the API dispatch tables with all nop functions */ - ctx->OutsideBeginEnd = _mesa_alloc_dispatch_table(); + ctx->OutsideBeginEnd = alloc_dispatch_table(); if (!ctx->OutsideBeginEnd) goto fail; ctx->Exec = ctx->OutsideBeginEnd; @@ -1162,7 +1224,7 @@ _mesa_initialize_context(struct gl_context *ctx, switch (ctx->API) { case API_OPENGL_COMPAT: ctx->BeginEnd = create_beginend_table(ctx); - ctx->Save = _mesa_alloc_dispatch_table(); + ctx->Save = alloc_dispatch_table(); if (!ctx->BeginEnd || !ctx->Save) goto fail; @@ -1268,7 +1330,8 @@ _mesa_free_context_data( struct gl_context *ctx ) _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, NULL); _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram, NULL); - _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL); + _mesa_reference_tesscprog(ctx, &ctx->TessCtrlProgram._Current, NULL); + _mesa_reference_tesseprog(ctx, &ctx->TessEvalProgram._Current, NULL); _mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current, NULL); _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL); @@ -1280,11 +1343,9 @@ _mesa_free_context_data( struct gl_context *ctx ) _mesa_free_attrib_data(ctx); _mesa_free_buffer_objects(ctx); - _mesa_free_lighting_data( ctx ); _mesa_free_eval_data( ctx ); _mesa_free_texture_data( ctx ); _mesa_free_matrix_data( ctx ); - _mesa_free_viewport_data( ctx ); _mesa_free_pipeline_data(ctx); _mesa_free_program_data(ctx); _mesa_free_shader_state(ctx); @@ -1445,17 +1506,10 @@ _mesa_copy_context( const struct gl_context *src, struct gl_context *dst, dst->Transform = src->Transform; } if (mask & GL_VIEWPORT_BIT) { - /* Cannot use memcpy, because of pointers in GLmatrix _WindowMap */ unsigned i; for (i = 0; i < src->Const.MaxViewports; i++) { - dst->ViewportArray[i].X = src->ViewportArray[i].X; - dst->ViewportArray[i].Y = src->ViewportArray[i].Y; - dst->ViewportArray[i].Width = src->ViewportArray[i].Width; - dst->ViewportArray[i].Height = src->ViewportArray[i].Height; - dst->ViewportArray[i].Near = src->ViewportArray[i].Near; - dst->ViewportArray[i].Far = src->ViewportArray[i].Far; - _math_matrix_copy(&dst->ViewportArray[i]._WindowMap, - &src->ViewportArray[i]._WindowMap); + /* OK to memcpy */ + dst->ViewportArray[i] = src->ViewportArray[i]; } } @@ -1567,7 +1621,8 @@ handle_first_current(struct gl_context *ctx) else buffer = GL_FRONT; - _mesa_drawbuffers(ctx, 1, &buffer, NULL /* destMask */); + _mesa_drawbuffers(ctx, ctx->DrawBuffer, 1, &buffer, + NULL /* destMask */); } if (ctx->ReadBuffer != _mesa_get_incomplete_framebuffer()) { @@ -1580,7 +1635,7 @@ handle_first_current(struct gl_context *ctx) bufferIndex = BUFFER_FRONT_LEFT; } - _mesa_readbuffer(ctx, buffer, bufferIndex); + _mesa_readbuffer(ctx, ctx->ReadBuffer, buffer, bufferIndex); } } @@ -1645,7 +1700,7 @@ _mesa_make_current( struct gl_context *newCtx, /* We used to call _glapi_check_multithread() here. Now do it in drivers */ _glapi_set_context((void *) newCtx); - ASSERT(_mesa_get_current_context() == newCtx); + assert(_mesa_get_current_context() == newCtx); if (!newCtx) { _glapi_set_dispatch(NULL); /* none current */ @@ -1654,8 +1709,8 @@ _mesa_make_current( struct gl_context *newCtx, _glapi_set_dispatch(newCtx->CurrentDispatch); if (drawBuffer && readBuffer) { - ASSERT(_mesa_is_winsys_fbo(drawBuffer)); - ASSERT(_mesa_is_winsys_fbo(readBuffer)); + assert(_mesa_is_winsys_fbo(drawBuffer)); + assert(_mesa_is_winsys_fbo(readBuffer)); _mesa_reference_framebuffer(&newCtx->WinSysDrawBuffer, drawBuffer); _mesa_reference_framebuffer(&newCtx->WinSysReadBuffer, readBuffer); @@ -1912,56 +1967,77 @@ shader_linked_or_absent(struct gl_context *ctx, GLboolean _mesa_valid_to_render(struct gl_context *ctx, const char *where) { - bool from_glsl_shader[MESA_SHADER_COMPUTE] = { false }; unsigned i; /* This depends on having up to date derived state (shaders) */ if (ctx->NewState) _mesa_update_state(ctx); - for (i = 0; i < MESA_SHADER_COMPUTE; i++) { - if (!shader_linked_or_absent(ctx, ctx->_Shader->CurrentProgram[i], - &from_glsl_shader[i], where)) - return GL_FALSE; - } + if (ctx->API == API_OPENGL_CORE || ctx->API == API_OPENGLES2) { + bool from_glsl_shader[MESA_SHADER_COMPUTE] = { false }; - /* Any shader stages that are not supplied by the GLSL shader and have - * assembly shaders enabled must now be validated. - */ - if (!from_glsl_shader[MESA_SHADER_VERTEX] - && ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(vertex program not valid)", where); - return GL_FALSE; - } + for (i = 0; i < MESA_SHADER_COMPUTE; i++) { + if (!shader_linked_or_absent(ctx, ctx->_Shader->CurrentProgram[i], + &from_glsl_shader[i], where)) + return GL_FALSE; + } - /* FINISHME: If GL_NV_geometry_program4 is ever supported, the current - * FINISHME: geometry program should validated here. - */ - (void) from_glsl_shader[MESA_SHADER_GEOMETRY]; + /* In OpenGL Core Profile and OpenGL ES 2.0 / 3.0, there are no assembly + * shaders. Don't check state related to those. + */ + } else { + bool has_vertex_shader = false; + bool has_fragment_shader = false; + + /* In OpenGL Compatibility Profile, there is only vertex shader and + * fragment shader. We take this path also for API_OPENGLES because + * optimizing that path would make the other (more common) paths + * slightly slower. + */ + if (!shader_linked_or_absent(ctx, + ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX], + &has_vertex_shader, where)) + return GL_FALSE; - if (!from_glsl_shader[MESA_SHADER_FRAGMENT]) { - if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(fragment program not valid)", where); - return GL_FALSE; - } + if (!shader_linked_or_absent(ctx, + ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT], + &has_fragment_shader, where)) + return GL_FALSE; - /* If drawing to integer-valued color buffers, there must be an - * active fragment shader (GL_EXT_texture_integer). + /* Any shader stages that are not supplied by the GLSL shader and have + * assembly shaders enabled must now be validated. */ - if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) { + if (!has_vertex_shader + && ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) { _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(integer format but no fragment shader)", where); + "%s(vertex program not valid)", where); return GL_FALSE; } + + if (!has_fragment_shader) { + if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(fragment program not valid)", where); + return GL_FALSE; + } + + /* If drawing to integer-valued color buffers, there must be an + * active fragment shader (GL_EXT_texture_integer). + */ + if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(integer format but no fragment shader)", where); + return GL_FALSE; + } + } } /* A pipeline object is bound */ if (ctx->_Shader->Name && !ctx->_Shader->Validated) { - /* Error message will be printed inside _mesa_validate_program_pipeline. - */ - if (!_mesa_validate_program_pipeline(ctx, ctx->_Shader, GL_TRUE)) { + if (!_mesa_validate_program_pipeline(ctx, ctx->_Shader)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glValidateProgramPipeline failed to validate the " + "pipeline"); return GL_FALSE; } }