#include "scissor.h"
#include "shared.h"
#include "shaderobj.h"
-#include "simple_list.h"
+#include "shaderimage.h"
+#include "util/simple_list.h"
#include "state.h"
#include "stencil.h"
#include "texcompress_s3tc.h"
#include "program/prog_print.h"
#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"
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 );
}
*/
consts->VertexID_is_zero_based = false;
- /* CheckArrayBounds is overriden by drivers/x11 for X server */
- consts->CheckArrayBounds = GL_FALSE;
-
/* GL_ARB_draw_buffers */
consts->MaxDrawBuffers = MAX_DRAW_BUFFERS;
consts->MaxGeometryTotalOutputComponents = MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS;
/* Shading language version */
- if (api == API_OPENGL_COMPAT || api == API_OPENGL_CORE) {
- consts->GLSLVersion = 120;
- _mesa_override_glsl_version(consts);
- }
- else if (api == API_OPENGLES2) {
- consts->GLSLVersion = 100;
- }
- else if (api == API_OPENGLES) {
- consts->GLSLVersion = 0; /* GLSL not supported */
- }
+ consts->GLSLVersion = 120;
+ _mesa_override_glsl_version(consts);
+
+#ifdef DEBUG
+ consts->GenerateTemporaryNames = true;
+#else
+ consts->GenerateTemporaryNames = false;
+#endif
/* GL_ARB_framebuffer_object */
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;
/* GL_ARB_robustness */
consts->ResetStrategy = GL_NO_RESET_NOTIFICATION_ARB;
- /* PrimitiveRestart */
- consts->PrimitiveRestartInSoftware = GL_FALSE;
-
/* ES 3.0 or ARB_ES3_compatibility */
consts->MaxElementIndex = 0xffffffffu;
/** GL_ARB_gpu_shader5 */
consts->MinFragmentInterpolationOffset = MIN_FRAGMENT_INTERPOLATION_OFFSET;
consts->MaxFragmentInterpolationOffset = MAX_FRAGMENT_INTERPOLATION_OFFSET;
+
+ /** GL_KHR_context_flush_control */
+ consts->ContextReleaseBehavior = GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH;
}
static void
check_context_limits(struct gl_context *ctx)
{
+ (void) ctx;
+
/* check that we don't exceed the size of various bitfields */
assert(VARYING_SLOT_MAX <=
(8 * sizeof(ctx->VertexProgram._Current->Base.OutputsWritten)));
_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 );
}
+/* 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 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
+ */
+#if USE_GLAPI_NOP_FEATURES
+static void
+nop_handler(const char *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ 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
+
+
/**
- * 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.
+ * Special no-op glFlush, see below.
*/
-int
-_mesa_generic_nop(void)
+#if defined(_WIN32)
+static void GLAPIENTRY
+nop_glFlush(void)
+{
+ /* don't record an error like we do in nop_handler() */
+}
+#endif
+
+
+#if !USE_GLAPI_NOP_FEATURES
+static int
+generic_nop(void)
{
GET_CURRENT_CONTEXT(ctx);
_mesa_error(ctx, GL_INVALID_OPERATION,
"(unsupported extension or deprecated function?)");
return 0;
}
+#endif
/**
- * Allocate and initialize a new dispatch table.
+ * 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()
+_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++) {
- entry[i] = (_glapi_proc) _mesa_generic_nop;
+ entry[i] = (_glapi_proc) generic_nop;
}
}
+#else
+ 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().
+ *
+ * The MS opengl32.dll library apparently calls glFlush from
+ * wglGetProcAddress(). If we're inside glBegin/End(), glFlush
+ * will dispatch to _mesa_generic_nop() and we'll generate a
+ * GL_INVALID_OPERATION error.
+ *
+ * The specific case which hits this is piglit's primitive-restart
+ * test which calls glPrimitiveRestartNV() inside glBegin/End. The
+ * first time we call glPrimitiveRestartNV() Piglit's API dispatch
+ * code will try to resolve the function by calling wglGetProcAddress.
+ * This raises GL_INVALID_OPERATION and an assert(glGetError()==0)
+ * will fail causing the test to fail. By suppressing the error, the
+ * assertion passes and the test continues.
+ */
+ SET_Flush(table, nop_glFlush);
+ }
+#endif
+
+#if USE_GLAPI_NOP_FEATURES
+ _glapi_set_nop_handler(nop_handler);
+#endif
+
return table;
}
{
struct _glapi_table *table;
- table = _mesa_alloc_dispatch_table();
+ table = alloc_dispatch_table();
if (!table)
return NULL;
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;
ctx->CurrentDispatch = ctx->OutsideBeginEnd;
ctx->FragmentProgram._MaintainTexEnvProgram
- = (_mesa_getenv("MESA_TEX_PROG") != NULL);
+ = (getenv("MESA_TEX_PROG") != NULL);
ctx->VertexProgram._MaintainTnlProgram
- = (_mesa_getenv("MESA_TNL_PROG") != NULL);
+ = (getenv("MESA_TNL_PROG") != NULL);
if (ctx->VertexProgram._MaintainTnlProgram) {
/* this is required... */
ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
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;
_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);
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];
}
}
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()) {
bufferIndex = BUFFER_FRONT_LEFT;
}
- _mesa_readbuffer(ctx, buffer, bufferIndex);
+ _mesa_readbuffer(ctx, ctx->ReadBuffer, buffer, bufferIndex);
}
}
* first time each context is made current we'll print some useful
* information.
*/
- if (_mesa_getenv("MESA_INFO")) {
+ if (getenv("MESA_INFO")) {
_mesa_print_info(ctx);
}
}
}
if (curCtx &&
- (curCtx->WinSysDrawBuffer || curCtx->WinSysReadBuffer) &&
+ (curCtx->WinSysDrawBuffer || curCtx->WinSysReadBuffer) &&
/* make sure this context is valid for flushing */
- curCtx != newCtx)
+ curCtx != newCtx &&
+ curCtx->Const.ContextReleaseBehavior ==
+ GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH)
_mesa_flush(curCtx);
/* 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 */
_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);
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 a program is active and SSO not in use, check if validation of
+ * samplers succeeded for the active program. */
+ if (ctx->_Shader->ActiveProgram && ctx->_Shader != ctx->Pipeline.Current) {
+ char errMsg[100];
+ if (!_mesa_sampler_uniforms_are_valid(ctx->_Shader->ActiveProgram,
+ errMsg, 100)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", errMsg);
+ return GL_FALSE;
+ }
+ }
+
if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
_mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
"%s(incomplete framebuffer)", where);