*
* Implementation of GLSL-related API functions.
* The glUniform* functions are in uniforms.c
- *
- *
- * XXX things to do:
- * 1. Check that the right error code is generated for all _mesa_error() calls.
- * 2. Insert FLUSH_VERTICES calls in various places
*/
+#include <errno.h>
#include <stdbool.h>
#include <c99_alloca.h>
#include "main/glheader.h"
#include "main/state.h"
#include "main/transformfeedback.h"
#include "main/uniforms.h"
+#include "compiler/glsl/builtin_functions.h"
#include "compiler/glsl/glsl_parser_extras.h"
#include "compiler/glsl/ir.h"
#include "compiler/glsl/ir_uniform.h"
#include "util/hash_table.h"
#include "util/mesa-sha1.h"
#include "util/crc32.h"
+#include "util/os_file.h"
/**
* Return mask of GLSL_x flags by examining the MESA_GLSL env var.
{
for (int i = 0; i < MESA_SHADER_STAGES; i++) {
_mesa_reference_program(ctx, &ctx->Shader.CurrentProgram[i], NULL);
+ _mesa_reference_shader_program(ctx,
+ &ctx->Shader.ReferencedPrograms[i],
+ NULL);
+ free(ctx->SubroutineIndex[i].IndexPtr);
+ ctx->SubroutineIndex[i].IndexPtr = NULL;
}
_mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
shProg->Shaders = newList;
shProg->NumShaders = n - 1;
-#ifdef DEBUG
+#ifndef NDEBUG
/* sanity check - make sure the new list's entries are sensible */
for (j = 0; j < shProg->NumShaders; j++) {
assert(shProg->Shaders[j]->Stage == MESA_SHADER_VERTEX ||
return false;
}
+/**
+ * Return the length of a string, or 0 if the pointer passed in is NULL
+ */
+static size_t strlen_or_zero(const char *s)
+{
+ return s ? strlen(s) : 0;
+}
/**
* glGetProgramiv() - get shader program state.
case GL_DELETE_STATUS:
*params = shProg->DeletePending;
return;
+ case GL_COMPLETION_STATUS_ARB:
+ if (ctx->Driver.GetShaderProgramCompletionStatus)
+ *params = ctx->Driver.GetShaderProgramCompletionStatus(ctx, shProg);
+ else
+ *params = GL_TRUE;
+ return;
case GL_LINK_STATUS:
*params = shProg->data->LinkStatus ? GL_TRUE : GL_FALSE;
return;
if (shProg->data->UniformStorage[i].is_shader_storage)
continue;
+ /* From ARB_gl_spirv spec:
+ *
+ * "If pname is ACTIVE_UNIFORM_MAX_LENGTH, the length of the
+ * longest active uniform name, including a null terminator, is
+ * returned. If no active uniforms exist, zero is returned. If no
+ * name reflection information is available, one is returned."
+ *
+ * We are setting 0 here, as below it will add 1 for the NUL character.
+ */
+ const GLint base_len =
+ strlen_or_zero(shProg->data->UniformStorage[i].name);
+
/* Add one for the terminating NUL character for a non-array, and
* 4 for the "[0]" and the NUL for an array.
*/
- const GLint len = strlen(shProg->data->UniformStorage[i].name) + 1 +
- ((shProg->data->UniformStorage[i].array_elements != 0) ? 3 : 0);
+ const GLint len = base_len + 1 +
+ ((shProg->data->UniformStorage[i].array_elements != 0) ? 3 : 0);
if (len > max_len)
max_len = len;
case GL_TRANSFORM_FEEDBACK_VARYINGS:
if (!has_xfb)
break;
- *params = shProg->TransformFeedback.NumVarying;
+
+ /* Check first if there are transform feedback varyings specified in the
+ * shader (ARB_enhanced_layouts). If there isn't any, return the number of
+ * varyings specified using the API.
+ */
+ if (shProg->last_vert_prog &&
+ shProg->last_vert_prog->sh.LinkedTransformFeedback->NumVarying > 0)
+ *params =
+ shProg->last_vert_prog->sh.LinkedTransformFeedback->NumVarying;
+ else
+ *params = shProg->TransformFeedback.NumVarying;
return;
case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: {
unsigned i;
GLint max_len = 0;
+ bool in_shader_varyings;
+ int num_varying;
+
if (!has_xfb)
break;
- for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
- /* Add one for the terminating NUL character.
+ /* Check first if there are transform feedback varyings specified in the
+ * shader (ARB_enhanced_layouts). If there isn't any, use the ones
+ * specified using the API.
+ */
+ in_shader_varyings = shProg->last_vert_prog &&
+ shProg->last_vert_prog->sh.LinkedTransformFeedback->NumVarying > 0;
+
+ num_varying = in_shader_varyings ?
+ shProg->last_vert_prog->sh.LinkedTransformFeedback->NumVarying :
+ shProg->TransformFeedback.NumVarying;
+
+ for (i = 0; i < num_varying; i++) {
+ const char *name = in_shader_varyings ?
+ shProg->last_vert_prog->sh.LinkedTransformFeedback->Varyings[i].Name
+ : shProg->TransformFeedback.VaryingNames[i];
+
+ /* Add one for the terminating NUL character. We have to use
+ * strlen_or_zero, as for shaders constructed from SPIR-V binaries,
+ * it is possible that no name reflection information is available.
*/
- const GLint len =
- strlen(shProg->TransformFeedback.VaryingNames[i]) + 1;
+ const GLint len = strlen_or_zero(name) + 1;
if (len > max_len)
max_len = len;
}
return;
case GL_GEOMETRY_SHADER_INVOCATIONS:
- if (!has_gs || !ctx->Extensions.ARB_gpu_shader5)
+ if (!has_gs ||
+ (_mesa_is_desktop_gl(ctx) && !ctx->Extensions.ARB_gpu_shader5)) {
break;
+ }
if (check_gs_query(ctx, shProg)) {
*params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->
Program->info.gs.invocations;
break;
for (i = 0; i < shProg->data->NumUniformBlocks; i++) {
- /* Add one for the terminating NUL character.
+ /* Add one for the terminating NUL character. Name can be NULL, in
+ * that case, from ARB_gl_spirv:
+ * "If pname is ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, the length of
+ * the longest active uniform block name, including the null
+ * terminator, is returned. If no active uniform blocks exist,
+ * zero is returned. If no name reflection information is
+ * available, one is returned."
*/
- const GLint len = strlen(shProg->data->UniformBlocks[i].Name) + 1;
+ const GLint len =
+ strlen_or_zero(shProg->data->UniformBlocks[i].Name) + 1;
if (len > max_len)
max_len = len;
if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
break;
- *params = shProg->BinaryRetreivableHint;
+ *params = shProg->BinaryRetrievableHint;
return;
case GL_PROGRAM_BINARY_LENGTH:
- if (ctx->Const.NumProgramBinaryFormats == 0) {
+ if (ctx->Const.NumProgramBinaryFormats == 0 || !shProg->data->LinkStatus) {
*params = 0;
} else {
_mesa_get_program_binary_length(ctx, shProg, params);
case GL_DELETE_STATUS:
*params = shader->DeletePending;
break;
+ case GL_COMPLETION_STATUS_ARB:
+ /* _mesa_glsl_compile_shader is not offloaded to other threads. */
+ *params = GL_TRUE;
+ return;
case GL_COMPILE_STATUS:
*params = shader->CompileStatus ? GL_TRUE : GL_FALSE;
break;
#endif
}
+static void
+ensure_builtin_types(struct gl_context *ctx)
+{
+ if (!ctx->shader_builtin_ref) {
+ _mesa_glsl_builtin_functions_init_or_ref();
+ ctx->shader_builtin_ref = true;
+ }
+}
/**
* Compile a shader.
_mesa_log("%s\n", sh->Source);
}
+ ensure_builtin_types(ctx);
+
/* this call will set the shader->CompileStatus field to indicate if
* compilation was successful.
*/
}
}
+ ensure_builtin_types(ctx);
+
FLUSH_VERTICES(ctx, 0);
_mesa_glsl_link_shader(ctx, shProg);
/* Capture .shader_test files. */
const char *capture_path = _mesa_get_shader_capture_path();
if (shProg->Name != 0 && shProg->Name != ~0 && capture_path != NULL) {
- FILE *file;
- char *filename = ralloc_asprintf(NULL, "%s/%u.shader_test",
+ /* Find an unused filename. */
+ FILE *file = NULL;
+ char *filename = NULL;
+ for (unsigned i = 0;; i++) {
+ if (i) {
+ filename = ralloc_asprintf(NULL, "%s/%u-%u.shader_test",
+ capture_path, shProg->Name, i);
+ } else {
+ filename = ralloc_asprintf(NULL, "%s/%u.shader_test",
capture_path, shProg->Name);
- file = fopen(filename, "w");
+ }
+ file = os_file_create_unique(filename, 0644);
+ if (file)
+ break;
+ /* If we are failing for another reason than "this filename already
+ * exists", we are likely to fail again with another filename, so
+ * let's just give up */
+ if (errno != EEXIST)
+ break;
+ ralloc_free(filename);
+ }
if (file) {
fprintf(file, "[require]\nGLSL%s >= %u.%02u\n",
shProg->IsES ? " ES" : "",
_mesa_update_vertex_processing_mode(ctx);
+ shProg->BinaryRetrievableHint = shProg->BinaryRetrievableHintPending;
+
/* debug code */
if (0) {
GLuint i;
* following format:
*
* <path>/<stage prefix>_<CHECKSUM>.glsl
+ * <path>/<stage prefix>_<CHECKSUM>.arb
*/
static char *
construct_name(const gl_shader_stage stage, const char *source,
"VS", "TC", "TE", "GS", "FS", "CS",
};
+ const char *format = strncmp(source, "!!ARB", 5) ? "glsl" : "arb";
+
generate_sha1(source, sha);
- return ralloc_asprintf(NULL, "%s/%s_%s.glsl", path, types[stage], sha);
+ return ralloc_asprintf(NULL, "%s/%s_%s.%s", path, types[stage], sha, format);
}
/**
* Write given shader source to a file in MESA_SHADER_DUMP_PATH.
*/
-static void
-dump_shader(const gl_shader_stage stage, const char *source)
+void
+_mesa_dump_shader_source(const gl_shader_stage stage, const char *source)
{
static bool path_exists = true;
char *dump_path;
* Read shader source code from a file.
* Useful for debugging to override an app's shader.
*/
-static GLcharARB *
-read_shader(const gl_shader_stage stage, const char *source)
+GLcharARB *
+_mesa_read_shader_source(const gl_shader_stage stage, const char *source)
{
char *read_path;
static bool path_exists = true;
/* Dump original shader source to MESA_SHADER_DUMP_PATH and replace
* if corresponding entry found from MESA_SHADER_READ_PATH.
*/
- dump_shader(sh->Stage, source);
+ _mesa_dump_shader_source(sh->Stage, source);
- replacement = read_shader(sh->Stage, source);
+ replacement = _mesa_read_shader_source(sh->Stage, source);
if (replacement) {
free(source);
source = replacement;
void GLAPIENTRY
_mesa_ReleaseShaderCompiler(void)
{
- _mesa_destroy_shader_compiler_caches();
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (ctx->shader_builtin_ref) {
+ _mesa_glsl_builtin_functions_decref();
+ ctx->shader_builtin_ref = false;
+ }
}
* will not be in effect until the next time LinkProgram or
* ProgramBinary has been called successfully."
*
- * The resloution of issue 9 in the extension spec also says:
+ * The resolution of issue 9 in the extension spec also says:
*
* "The application may use the PROGRAM_BINARY_RETRIEVABLE_HINT hint
* to indicate to the GL implementation that this program will
* changes made to the program before being saved such that when it
* is loaded again a recompile can be avoided."
*/
- shProg->BinaryRetreivableHint = value;
+ shProg->BinaryRetrievableHintPending = value;
return;
case GL_PROGRAM_SEPARABLE: