From f1c5043f94261fecd8a6e54fe37d786554affcdd Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 10 Jun 2010 22:48:16 -0600 Subject: mesa: move shader/slang/* sources to main/slang/* Reduce the source tree depth a bit. --- src/mesa/slang/descrip.mms | 67 + src/mesa/slang/library/.gitignore | 1 + src/mesa/slang/library/Makefile | 51 + src/mesa/slang/library/SConscript | 52 + src/mesa/slang/library/slang_120_core.gc | 1978 ++++++++ src/mesa/slang/library/slang_builtin_120_common.gc | 200 + .../slang/library/slang_builtin_120_fragment.gc | 30 + src/mesa/slang/library/slang_common_builtin.gc | 1887 +++++++ src/mesa/slang/library/slang_core.gc | 2619 ++++++++++ src/mesa/slang/library/slang_fragment_builtin.gc | 299 ++ src/mesa/slang/library/slang_vertex_builtin.gc | 210 + src/mesa/slang/slang_builtin.c | 937 ++++ src/mesa/slang/slang_builtin.h | 64 + src/mesa/slang/slang_codegen.c | 5357 ++++++++++++++++++++ src/mesa/slang/slang_codegen.h | 73 + src/mesa/slang/slang_compile.c | 3044 +++++++++++ src/mesa/slang/slang_compile.h | 100 + src/mesa/slang/slang_compile_function.c | 262 + src/mesa/slang/slang_compile_function.h | 92 + src/mesa/slang/slang_compile_operation.c | 334 ++ src/mesa/slang/slang_compile_operation.h | 225 + src/mesa/slang/slang_compile_struct.c | 174 + src/mesa/slang/slang_compile_struct.h | 66 + src/mesa/slang/slang_compile_variable.c | 247 + src/mesa/slang/slang_compile_variable.h | 90 + src/mesa/slang/slang_emit.c | 2666 ++++++++++ src/mesa/slang/slang_emit.h | 51 + src/mesa/slang/slang_ir.c | 498 ++ src/mesa/slang/slang_ir.h | 280 + src/mesa/slang/slang_label.c | 104 + src/mesa/slang/slang_label.h | 45 + src/mesa/slang/slang_link.c | 1124 ++++ src/mesa/slang/slang_link.h | 37 + src/mesa/slang/slang_log.c | 133 + src/mesa/slang/slang_log.h | 57 + src/mesa/slang/slang_mem.c | 243 + src/mesa/slang/slang_mem.h | 55 + src/mesa/slang/slang_print.c | 883 ++++ src/mesa/slang/slang_print.h | 29 + src/mesa/slang/slang_simplify.c | 527 ++ src/mesa/slang/slang_simplify.h | 50 + src/mesa/slang/slang_storage.c | 321 ++ src/mesa/slang/slang_storage.h | 139 + src/mesa/slang/slang_typeinfo.c | 1177 +++++ src/mesa/slang/slang_typeinfo.h | 259 + src/mesa/slang/slang_utility.c | 228 + src/mesa/slang/slang_utility.h | 100 + src/mesa/slang/slang_vartable.c | 362 ++ src/mesa/slang/slang_vartable.h | 42 + 49 files changed, 27869 insertions(+) create mode 100644 src/mesa/slang/descrip.mms create mode 100644 src/mesa/slang/library/.gitignore create mode 100644 src/mesa/slang/library/Makefile create mode 100644 src/mesa/slang/library/SConscript create mode 100644 src/mesa/slang/library/slang_120_core.gc create mode 100644 src/mesa/slang/library/slang_builtin_120_common.gc create mode 100644 src/mesa/slang/library/slang_builtin_120_fragment.gc create mode 100644 src/mesa/slang/library/slang_common_builtin.gc create mode 100644 src/mesa/slang/library/slang_core.gc create mode 100644 src/mesa/slang/library/slang_fragment_builtin.gc create mode 100644 src/mesa/slang/library/slang_vertex_builtin.gc create mode 100644 src/mesa/slang/slang_builtin.c create mode 100644 src/mesa/slang/slang_builtin.h create mode 100644 src/mesa/slang/slang_codegen.c create mode 100644 src/mesa/slang/slang_codegen.h create mode 100644 src/mesa/slang/slang_compile.c create mode 100644 src/mesa/slang/slang_compile.h create mode 100644 src/mesa/slang/slang_compile_function.c create mode 100644 src/mesa/slang/slang_compile_function.h create mode 100644 src/mesa/slang/slang_compile_operation.c create mode 100644 src/mesa/slang/slang_compile_operation.h create mode 100644 src/mesa/slang/slang_compile_struct.c create mode 100644 src/mesa/slang/slang_compile_struct.h create mode 100644 src/mesa/slang/slang_compile_variable.c create mode 100644 src/mesa/slang/slang_compile_variable.h create mode 100644 src/mesa/slang/slang_emit.c create mode 100644 src/mesa/slang/slang_emit.h create mode 100644 src/mesa/slang/slang_ir.c create mode 100644 src/mesa/slang/slang_ir.h create mode 100644 src/mesa/slang/slang_label.c create mode 100644 src/mesa/slang/slang_label.h create mode 100644 src/mesa/slang/slang_link.c create mode 100644 src/mesa/slang/slang_link.h create mode 100644 src/mesa/slang/slang_log.c create mode 100644 src/mesa/slang/slang_log.h create mode 100644 src/mesa/slang/slang_mem.c create mode 100644 src/mesa/slang/slang_mem.h create mode 100644 src/mesa/slang/slang_print.c create mode 100644 src/mesa/slang/slang_print.h create mode 100644 src/mesa/slang/slang_simplify.c create mode 100644 src/mesa/slang/slang_simplify.h create mode 100644 src/mesa/slang/slang_storage.c create mode 100644 src/mesa/slang/slang_storage.h create mode 100644 src/mesa/slang/slang_typeinfo.c create mode 100644 src/mesa/slang/slang_typeinfo.h create mode 100644 src/mesa/slang/slang_utility.c create mode 100644 src/mesa/slang/slang_utility.h create mode 100644 src/mesa/slang/slang_vartable.c create mode 100644 src/mesa/slang/slang_vartable.h (limited to 'src/mesa/slang') diff --git a/src/mesa/slang/descrip.mms b/src/mesa/slang/descrip.mms new file mode 100644 index 0000000000..674b786ac0 --- /dev/null +++ b/src/mesa/slang/descrip.mms @@ -0,0 +1,67 @@ +# Makefile for core library for VMS +# contributed by Jouk Jansen joukj@hrem.nano.tudelft.nl +# Last revision : 3 October 2007 + +.first + define gl [----.include.gl] + define math [--.math] + define swrast [--.swrast] + define array_cache [--.array_cache] + define main [--.main] + define glapi [--.glapi] + define shader [--.shader] + +.include [----]mms-config. + +##### MACROS ##### + +VPATH = RCS + +INCDIR = [----.include],[--.main],[--.glapi],[-.slang],[-] +LIBDIR = [----.lib] +CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1)/name=(as_is,short)/float=ieee/ieee=denorm + +SOURCES = \ + slang_compile.c + +OBJECTS = slang_builtin.obj,slang_codegen.obj,slang_compile.obj,\ + slang_compile_function.obj,slang_compile_operation.obj,\ + slang_compile_struct.obj,slang_compile_variable.obj,slang_emit.obj,\ + slang_ir.obj,slang_label.obj,slang_library_noise.obj,slang_link.obj,\ + slang_log.obj,slang_mem.obj,slang_preprocess.obj,slang_print.obj,\ + slang_simplify.obj,slang_storage.obj,slang_typeinfo.obj,\ + slang_utility.obj,slang_vartable.obj + +##### RULES ##### + +VERSION=Mesa V3.4 + +##### TARGETS ##### +# Make the library +$(LIBDIR)$(GL_LIB) : $(OBJECTS) + @ library $(LIBDIR)$(GL_LIB) $(OBJECTS) + +clean : + purge + delete *.obj;* + +slang_builtin.obj : slang_builtin.c +slang_codegen.obj : slang_codegen.c +slang_compile.obj : slang_compile.c +slang_compile_function.obj : slang_compile_function.c +slang_compile_operation.obj : slang_compile_operation.c +slang_compile_struct.obj : slang_compile_struct.c +slang_compile_variable.obj : slang_compile_variable.c +slang_emit.obj : slang_emit.c +slang_ir.obj : slang_ir.c +slang_label.obj : slang_label.c +slang_library_noise.obj : slang_library_noise.c +slang_link.obj : slang_link.c +slang_log.obj : slang_log.c +slang_mem.obj : slang_mem.c +slang_print.obj : slang_print.c +slang_simplify.obj : slang_simplify.c +slang_storage.obj : slang_storage.c +slang_typeinfo.obj : slang_typeinfo.c +slang_utility.obj : slang_utility.c +slang_vartable.obj : slang_vartable.c diff --git a/src/mesa/slang/library/.gitignore b/src/mesa/slang/library/.gitignore new file mode 100644 index 0000000000..02a89fc7df --- /dev/null +++ b/src/mesa/slang/library/.gitignore @@ -0,0 +1 @@ +*_gc.h diff --git a/src/mesa/slang/library/Makefile b/src/mesa/slang/library/Makefile new file mode 100644 index 0000000000..75c91e7db7 --- /dev/null +++ b/src/mesa/slang/library/Makefile @@ -0,0 +1,51 @@ +# src/mesa/shader/slang/library/Makefile + +TOP = ../../../.. + +include $(TOP)/configs/current + +GLSL_CL = $(TOP)/src/glsl/apps/compile + +# +# targets +# + +.PHONY: default clean + +default: builtin + +clean: + -rm -f *_gc.h + +builtin: builtin_110 builtin_120 + +# +# builtin library sources +# + +builtin_110: slang_common_builtin_gc.h slang_core_gc.h slang_fragment_builtin_gc.h slang_vertex_builtin_gc.h + +builtin_120: slang_120_core_gc.h slang_builtin_120_common_gc.h slang_builtin_120_fragment_gc.h + + +slang_120_core_gc.h: slang_120_core.gc + $(GLSL_CL) fragment slang_120_core.gc slang_120_core_gc.h + +slang_builtin_120_common_gc.h: slang_builtin_120_common.gc + $(GLSL_CL) fragment slang_builtin_120_common.gc slang_builtin_120_common_gc.h + +slang_builtin_120_fragment_gc.h: slang_builtin_120_fragment.gc + $(GLSL_CL) fragment slang_builtin_120_fragment.gc slang_builtin_120_fragment_gc.h + +slang_common_builtin_gc.h: slang_common_builtin.gc + $(GLSL_CL) fragment slang_common_builtin.gc slang_common_builtin_gc.h + +slang_core_gc.h: slang_core.gc + $(GLSL_CL) fragment slang_core.gc slang_core_gc.h + +slang_fragment_builtin_gc.h: slang_fragment_builtin.gc + $(GLSL_CL) fragment slang_fragment_builtin.gc slang_fragment_builtin_gc.h + +slang_vertex_builtin_gc.h: slang_vertex_builtin.gc + $(GLSL_CL) vertex slang_vertex_builtin.gc slang_vertex_builtin_gc.h + diff --git a/src/mesa/slang/library/SConscript b/src/mesa/slang/library/SConscript new file mode 100644 index 0000000000..0b25467a4e --- /dev/null +++ b/src/mesa/slang/library/SConscript @@ -0,0 +1,52 @@ +####################################################################### +# SConscript for GLSL builtin library + +Import('*') + +env = env.Clone() + +# See also http://www.scons.org/wiki/UsingCodeGenerators + +def glsl_compile_emitter(target, source, env): + env.Depends(target, glsl_compile) + return (target, source) + +bld_frag = Builder( + action = Action(glsl_compile[0].abspath + ' fragment $SOURCE $TARGET', '$CODEGENCODESTR'), + emitter = glsl_compile_emitter, + suffix = '.gc', + src_suffix = '_gc.h') + +bld_vert = Builder( + action = Action(glsl_compile[0].abspath + ' vertex $SOURCE $TARGET', '$CODEGENCODESTR'), + emitter = glsl_compile_emitter, + suffix = '.gc', + src_suffix = '_gc.h') + +env['BUILDERS']['bld_frag'] = bld_frag +env['BUILDERS']['bld_vert'] = bld_vert + +# Generate GLSL builtin library binaries +env.bld_frag( + '#src/mesa/shader/slang/library/slang_core_gc.h', + '#src/mesa/shader/slang/library/slang_core.gc') +env.bld_frag( + '#src/mesa/shader/slang/library/slang_common_builtin_gc.h', + '#src/mesa/shader/slang/library/slang_common_builtin.gc') +env.bld_frag( + '#src/mesa/shader/slang/library/slang_fragment_builtin_gc.h', + '#src/mesa/shader/slang/library/slang_fragment_builtin.gc') +env.bld_vert( + '#src/mesa/shader/slang/library/slang_vertex_builtin_gc.h', + '#src/mesa/shader/slang/library/slang_vertex_builtin.gc') + +# Generate GLSL 1.20 builtin library binaries +env.bld_frag( + '#src/mesa/shader/slang/library/slang_120_core_gc.h', + '#src/mesa/shader/slang/library/slang_120_core.gc') +env.bld_frag( + '#src/mesa/shader/slang/library/slang_builtin_120_common_gc.h', + '#src/mesa/shader/slang/library/slang_builtin_120_common.gc') +env.bld_frag( + '#src/mesa/shader/slang/library/slang_builtin_120_fragment_gc.h', + '#src/mesa/shader/slang/library/slang_builtin_120_fragment.gc') diff --git a/src/mesa/slang/library/slang_120_core.gc b/src/mesa/slang/library/slang_120_core.gc new file mode 100644 index 0000000000..04c5ec2ec5 --- /dev/null +++ b/src/mesa/slang/library/slang_120_core.gc @@ -0,0 +1,1978 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// Constructors and operators introduced in GLSL 1.20 - mostly on new +// (non-square) types of matrices. +// +// One important change in the language is that when a matrix is used +// as an argument to a matrix constructor, it must be the only argument +// for the constructor. The compiler takes care of it by itself and +// here we only care to re-introduce constructors for old (square) +// types of matrices. +// + +// +// From Shader Spec, ver. 1.20, rev. 6 +// + +//// mat2x3: 2 columns of vec3 + +mat2x3 __constructor(const float f00, const float f10, const float f20, + const float f01, const float f11, const float f21) +{ + __retVal[0].x = f00; + __retVal[0].y = f10; + __retVal[0].z = f20; + __retVal[1].x = f01; + __retVal[1].y = f11; + __retVal[1].z = f21; +} + +mat2x3 __constructor(const float f) +{ + __retVal = mat2x3( f, 0.0, 0.0, + 0.0, f, 0.0); +} + +mat2x3 __constructor(const int i) +{ + const float f = float(i); + __retVal = mat2x3(f); +} + +mat2x3 __constructor(const bool b) +{ + const float f = float(b); + __retVal = mat2x3(f); +} + +mat2x3 __constructor(const vec3 c0, const vec3 c1) +{ + __retVal[0] = c0; + __retVal[1] = c1; +} + + + +//// mat2x4: 2 columns of vec4 + +mat2x4 __constructor(const float f00, const float f10, const float f20, const float f30, + const float f01, const float f11, const float f21, const float f31) +{ + __retVal[0].x = f00; + __retVal[0].y = f10; + __retVal[0].z = f20; + __retVal[0].w = f30; + __retVal[1].x = f01; + __retVal[1].y = f11; + __retVal[1].z = f21; + __retVal[1].w = f31; +} + +mat2x4 __constructor(const float f) +{ + __retVal = mat2x4( f, 0.0, 0.0, 0.0, + 0.0, f, 0.0, 0.0); +} + +mat2x4 __constructor(const int i) +{ + const float f = float(i); + __retVal = mat2x4(f); +} + +mat2x4 __constructor(const bool b) +{ + const float f = float(b); + __retVal = mat2x4(f); +} + +mat2x4 __constructor(const vec4 c0, const vec4 c1) +{ + __retVal[0] = c0; + __retVal[1] = c1; +} + + + +//// mat3x2: 3 columns of vec2 + +mat3x2 __constructor(const float f00, const float f10, + const float f01, const float f11, + const float f02, const float f12) +{ + __retVal[0].x = f00; + __retVal[0].y = f10; + __retVal[1].x = f01; + __retVal[1].y = f11; + __retVal[2].x = f02; + __retVal[2].y = f12; +} + +mat3x2 __constructor(const float f) +{ + __retVal = mat3x2( f, 0.0, + 0.0, f, + 0.0, 0.0); +} + +mat3x2 __constructor(const int i) +{ + const float f = float(i); + __retVal = mat3x2(f); +} + +mat3x2 __constructor(const bool b) +{ + const float f = float(b); + __retVal = mat3x2(f); +} + +mat3x2 __constructor(const vec2 c0, const vec2 c1, const vec2 c2) +{ + __retVal[0] = c0; + __retVal[1] = c1; + __retVal[2] = c2; +} + + + +//// mat3x4: 3 columns of vec4 + +mat3x4 __constructor(const float f00, const float f10, const float f20, const float f30, + const float f01, const float f11, const float f21, const float f31, + const float f02, const float f12, const float f22, const float f32) +{ + __retVal[0].x = f00; + __retVal[0].y = f10; + __retVal[0].z = f20; + __retVal[0].w = f30; + __retVal[1].x = f01; + __retVal[1].y = f11; + __retVal[1].z = f21; + __retVal[1].w = f31; + __retVal[2].x = f02; + __retVal[2].y = f12; + __retVal[2].z = f22; + __retVal[2].w = f32; +} + +mat3x4 __constructor(const float f) +{ + __retVal = mat3x4( f, 0.0, 0.0, 0.0, + 0.0, f, 0.0, 0.0, + 0.0, 0.0, f, 0.0); +} + +mat3x4 __constructor(const int i) +{ + const float f = float(i); + __retVal = mat3x4(f); +} + +mat3x4 __constructor(const bool b) +{ + const float f = float(b); + __retVal = mat3x4(f); +} + +mat3x4 __constructor(const vec4 c0, const vec4 c1, const vec4 c2) +{ + __retVal[0] = c0; + __retVal[1] = c1; + __retVal[2] = c2; +} + + + +//// mat4x2: 4 columns of vec2 + +mat4x2 __constructor(const float f00, const float f10, + const float f01, const float f11, + const float f02, const float f12, + const float f03, const float f13) +{ + __retVal[0].x = f00; + __retVal[0].y = f10; + __retVal[1].x = f01; + __retVal[1].y = f11; + __retVal[2].x = f02; + __retVal[2].y = f12; + __retVal[3].x = f03; + __retVal[3].y = f13; +} + +mat4x2 __constructor(const float f) +{ + __retVal = mat4x2( f, 0.0, + 0.0, 4, + 0.0, 0.0, + 0.0, 0.0); +} + +mat4x2 __constructor(const int i) +{ + const float f = float(i); + __retVal = mat4x2(f); +} + +mat4x2 __constructor(const bool b) +{ + const float f = float(b); + __retVal = mat4x2(f); +} + +mat4x2 __constructor(const vec2 c0, const vec2 c1, const vec2 c2, const vec2 c3) +{ + __retVal[0] = c0; + __retVal[1] = c1; + __retVal[2] = c2; + __retVal[3] = c3; +} + + + +//// mat4x3: 4 columns of vec3 + +mat4x3 __constructor(const float f00, const float f10, const float f20, + const float f01, const float f11, const float f21, + const float f02, const float f12, const float f22, + const float f03, const float f13, const float f23) +{ + __retVal[0].x = f00; + __retVal[0].y = f10; + __retVal[0].z = f20; + __retVal[1].x = f01; + __retVal[1].y = f11; + __retVal[1].z = f21; + __retVal[2].x = f02; + __retVal[2].y = f12; + __retVal[2].z = f22; + __retVal[3].x = f03; + __retVal[3].y = f13; + __retVal[3].z = f23; +} + +mat4x3 __constructor(const float f) +{ + __retVal = mat4x3( f, 0.0, 0.0, + 0.0, f, 0.0, + 0.0, 0.0, f, + 0.0, 0.0, 0.0); +} + +mat4x3 __constructor(const int i) +{ + const float f = float(i); + __retVal = mat4x3(f); +} + +mat4x3 __constructor(const bool b) +{ + const float f = float(b); + __retVal = mat4x3(f); +} + +mat4x3 __constructor(const vec3 c0, const vec3 c1, const vec3 c2, const vec3 c3) +{ + __retVal[0] = c0; + __retVal[1] = c1; + __retVal[2] = c2; + __retVal[3] = c3; +} + + + +//// misc assorted matrix constructors + +mat2 __constructor(const mat2 m) +{ + __retVal = m; +} + +mat2 __constructor(const mat3x2 m) +{ + __retVal = mat2(m[0], m[1]); +} + +mat2 __constructor(const mat4x2 m) +{ + __retVal = mat2(m[0], m[1]); +} + +mat2 __constructor(const mat2x3 m) +{ + __retVal = mat2(m[0].xy, m[1].xy); +} + +mat2 __constructor(const mat2x4 m) +{ + __retVal = mat2(m[0].xy, m[1].xy); +} + +mat2 __constructor(const mat3 m) +{ + __retVal = mat2(m[0].xy, m[1].xy); +} + +mat2 __constructor(const mat3x4 m) +{ + __retVal = mat2(m[0].xy, m[1].xy); +} + +mat2 __constructor(const mat4x3 m) +{ + __retVal = mat2(m[0].xy, m[1].xy); +} + +mat2 __constructor(const mat4 m) +{ + __retVal = mat2(m[0].xy, m[1].xy); +} + + + +mat2x3 __constructor(const mat2x3 m) +{ + __retVal = m; +} + +mat2x3 __constructor(const mat3 m) +{ + __retVal = mat2x3(m[0], m[1]); +} + +mat2x3 __constructor(const mat4x3 m) +{ + __retVal = mat2x3(m[0], m[1]); +} + +mat2x3 __constructor(const mat2x4 m) +{ + __retVal = mat2x3(m[0].xyz, m[1].xyz); +} + +mat2x3 __constructor(const mat3x4 m) +{ + __retVal = mat2x3(m[0].xyz, m[1].xyz); +} + +mat2x3 __constructor(const mat4 m) +{ + __retVal = mat2x3(m[0].xyz, m[1].xyz); +} + +mat2x3 __constructor(const mat2 m) +{ + __retVal = mat2x3(m[0].x, m[0].y, 0.0, + m[1].x, m[1].y, 0.0); +} + +mat2x3 __constructor(const mat3x2 m) +{ + __retVal = mat2x3(m[0].x, m[0].y, 0.0, + m[1].x, m[1].y, 0.0); +} + +mat2x3 __constructor(const mat4x2 m) +{ + __retVal = mat2x3(m[0].x, m[0].y, 0.0, + m[1].x, m[1].y, 0.0); +} + + + +mat2x4 __constructor(const mat2x4 m) +{ + __retVal = m; +} + +mat2x4 __constructor(const mat3x4 m) +{ + __retVal = mat2x4(m[0], m[1]); +} + +mat2x4 __constructor(const mat4 m) +{ + __retVal = mat2x4(m[0], m[1]); +} + +mat2x4 __constructor(const mat2x3 m) +{ + __retVal = mat2x4(m[0].x, m[0].y, m[0].z, 0.0, + m[1].x, m[1].y, m[1].z, 0.0); +} + +mat2x4 __constructor(const mat3 m) +{ + __retVal = mat2x4(m[0].x, m[0].y, m[0].z, 0.0, + m[1].x, m[1].y, m[1].z, 0.0); +} + +mat2x4 __constructor(const mat4x3 m) +{ + __retVal = mat2x4(m[0].x, m[0].y, m[0].z, 0.0, + m[1].x, m[1].y, m[1].z, 0.0); +} + +mat2x4 __constructor(const mat2 m) +{ + __retVal = mat2x4(m[0].x, m[1].y, 0.0, 0.0, + m[1].x, m[1].y, 0.0, 0.0); +} + +mat2x4 __constructor(const mat3x2 m) +{ + __retVal = mat2x4(m[0].x, m[0].y, 0.0, 0.0, + m[1].x, m[1].y, 0.0, 0.0); +} + +mat2x4 __constructor(const mat4x2 m) +{ + __retVal = mat2x4(m[0].x, m[0].y, 0.0, 0.0, + m[1].x, m[1].y, 0.0, 0.0); +} + + + +mat3x2 __constructor(const mat3x2 m) +{ + __retVal = m; +} + +mat3x2 __constructor(const mat4x2 m) +{ + __retVal = mat3x2(m[0], m[1], m[2]); +} + +mat3x2 __constructor(const mat3 m) +{ + __retVal = mat3x2(m[0], m[1], m[2]); +} + +mat3x2 __constructor(const mat3x4 m) +{ + __retVal = mat3x2(m[0].x, m[0].y, + m[1].x, m[1].y, + m[2].x, m[2].y); +} + +mat3x2 __constructor(const mat4x3 m) +{ + __retVal = mat3x2(m[0].x, m[0].y, + m[1].x, m[1].y, + m[2].x, m[2].y); +} + +mat3x2 __constructor(const mat4 m) +{ + __retVal = mat3x2(m[0].x, m[0].y, + m[1].x, m[1].y, + 0.0, 0.0); +} + +mat3x2 __constructor(const mat2 m) +{ + __retVal = mat3x2(m[0], m[1], vec2(0.0)); +} + +mat3x2 __constructor(const mat2x3 m) +{ + __retVal = mat3x2(m[0].x, m[0].y, + m[1].x, m[1].y, + 0.0, 0.0); +} + +mat3x2 __constructor(const mat2x4 m) +{ + __retVal = mat3x2(m[0].x, m[0].y, + m[1].x, m[1].y, + 0.0, 0.0); +} + + + + +mat3 __constructor(const mat3 m) +{ + __retVal = m; +} + +mat3 __constructor(const mat4x3 m) +{ + __retVal = mat3 ( + m[0], + m[1], + m[2] + ); +} + +mat3 __constructor(const mat3x4 m) +{ + __retVal = mat3 ( + m[0].xyz, + m[1].xyz, + m[2].xyz + ); +} + +mat3 __constructor(const mat4 m) +{ + __retVal = mat3 ( + m[0].xyz, + m[1].xyz, + m[2].xyz + ); +} + +mat3 __constructor(const mat2x3 m) +{ + __retVal = mat3 ( + m[0], + m[1], + 0., 0., 1. + ); +} + +mat3 __constructor(const mat2x4 m) +{ + __retVal = mat3 ( + m[0].xyz, + m[1].xyz, + 0., 0., 1. + ); +} + +mat3 __constructor(const mat3x2 m) +{ + __retVal = mat3 ( + m[0], 0., + m[1], 0., + m[2], 1. + ); +} + +mat3 __constructor(const mat4x2 m) +{ + __retVal = mat3 ( + m[0], 0., + m[1], 0., + m[2], 1. + ); +} + +mat3 __constructor(const mat2 m) +{ + __retVal = mat3 ( + m[0], 0., + m[1], 0., + 0., 0., 1. + ); +} + + +mat3x4 __constructor(const mat3x4 m) +{ + __retVal = m; +} + +mat3x4 __constructor(const mat4 m) +{ + __retVal = mat3x4 ( + m[0], + m[1], + m[2] + ); +} + +mat3x4 __constructor(const mat3 m) +{ + __retVal = mat3x4 ( + m[0], 0., + m[1], 0., + m[2], 0. + ); +} + +mat3x4 __constructor(const mat4x3 m) +{ + __retVal = mat3x4 ( + m[0], 0., + m[1], 0., + m[2], 0. + ); +} + +mat3x4 __constructor(const mat2x4 m) +{ + __retVal = mat3x4 ( + m[0], + m[1], + 0., 0., 1., 0. + ); +} + +mat3x4 __constructor(const mat2x3 m) +{ + __retVal = mat3x4 ( + m[0], 0., + m[1], 0., + 0., 0., 1., 0. + ); +} + +mat3x4 __constructor(const mat3x2 m) +{ + __retVal = mat3x4 ( + m[0], 0., 0., + m[1], 0., 0., + m[2], 1., 0. + ); +} + +mat3x4 __constructor(const mat4x2 m) +{ + __retVal = mat3x4 ( + m[0], 0., 0., + m[1], 0., 0., + m[2], 1., 0. + ); +} + +mat3x4 __constructor(const mat2 m) +{ + __retVal = mat3x4 ( + m[0], 0., 0., + m[1], 0., 0., + 0., 0., 1., 0. + ); +} + + +mat4x2 __constructor(const mat4x2 m) +{ + __retVal = m; +} + +mat4x2 __constructor(const mat4x3 m) +{ + __retVal = mat4x2 ( + m[0].xy, + m[1].xy, + m[2].xy, + m[3].xy + ); +} + +mat4x2 __constructor(const mat4 m) +{ + __retVal = mat4x2 ( + m[0].xy, + m[1].xy, + m[2].xy, + m[3].xy + ); +} + +mat4x2 __constructor(const mat3x2 m) +{ + __retVal = mat4x2 ( + m[0], + m[1], + 0., 0. + ); +} + +mat4x2 __constructor(const mat3 m) +{ + __retVal = mat4x2 ( + m[0].xy, + m[1].xy, + m[2].xy, + 0., 0. + ); +} + +mat4x2 __constructor(const mat3x4 m) +{ + __retVal = mat4x2 ( + m[0].xy, + m[1].xy, + m[2].xy, + 0., 0. + ); +} + +mat4x2 __constructor(const mat2 m) +{ + __retVal = mat4x2 ( + m[0], + m[1], + 0., 0., + 0., 0. + ); +} + +mat4x2 __constructor(const mat2x3 m) +{ + __retVal = mat4x2 ( + m[0].xy, + m[1].xy, + 0., 0., + 0., 0. + ); +} + +mat4x2 __constructor(const mat2x4 m) +{ + __retVal = mat4x2 ( + m[0].xy, + m[1].xy, + 0., 0., + 0., 0. + ); +} + + +mat4x3 __constructor(const mat4x3 m) +{ + __retVal = m; +} + +mat4x3 __constructor(const mat4 m) +{ + __retVal = mat4x3 ( + m[0].xyz, + m[1].xyz, + m[2].xyz, + m[3].xyz + ); +} + +mat4x3 __constructor(const mat3 m) +{ + __retVal = mat4x3 ( + m[0], + m[1], + m[2], + 0., 0., 0. + ); +} + +mat4x3 __constructor(const mat3x4 m) +{ + __retVal = mat4x3 ( + m[0].xyz, + m[1].xyz, + m[2].xyz, + 0., 0., 0. + ); +} + +mat4x3 __constructor(const mat4x2 m) +{ + __retVal = mat4x3 ( + m[0], 0., + m[1], 0., + m[2], 1., + m[3], 0. + ); +} + +mat4x3 __constructor(const mat2x3 m) +{ + __retVal = mat4x3 ( + m[0], + m[1], + 0., 0., 1., + 0., 0., 0. + ); +} + +mat4x3 __constructor(const mat3x2 m) +{ + __retVal = mat4x3 ( + m[0], 0., + m[1], 0., + m[2], 1., + 0., 0., 0. + ); +} + +mat4x3 __constructor(const mat2x4 m) +{ + __retVal = mat4x3 ( + m[0].xyz, + m[1].xyz, + 0., 0., 1., + 0., 0., 0. + ); +} + +mat4x3 __constructor(const mat2 m) +{ + __retVal = mat4x3 ( + m[0], 0., + m[1], 0., + 0., 0., 1., + 0., 0., 0. + ); +} + + +mat4 __constructor(const mat4 m) +{ + __retVal = m; +} + +mat4 __constructor(const mat3x4 m) +{ + __retVal = mat4 ( + m[0], + m[1], + m[2], + 0., 0., 0., 1. + ); +} + +mat4 __constructor(const mat4x3 m) +{ + __retVal = mat4 ( + m[0], 0., + m[1], 0., + m[2], 0., + m[3], 1. + ); +} + +mat4 __constructor(const mat2x4 m) +{ + __retVal = mat4 ( + m[0], + m[1], + 0., 0., 1., 0., + 0., 0., 0., 1. + ); +} + +mat4 __constructor(const mat4x2 m) +{ + __retVal = mat4 ( + m[0], 0., 0., + m[1], 0., 0., + m[2], 1., 0., + m[3], 0., 1. + ); +} + +mat4 __constructor(const mat3 m) +{ + __retVal = mat4 ( + m[0], 0., + m[1], 0., + m[2], 0., + 0., 0., 0., 1. + ); +} + +mat4 __constructor(const mat2x3 m) +{ + __retVal = mat4 ( + m[0], 0., + m[1], 0., + 0., 0., 1., 0., + 0., 0., 0., 1. + ); +} + +mat4 __constructor(const mat3x2 m) +{ + __retVal = mat4 ( + m[0], 0., 0., + m[1], 0., 0., + m[2], 1., 0., + 0., 0., 0., 1. + ); +} + +mat4 __constructor(const mat2 m) +{ + __retVal = mat4 ( + m[0], 0., 0., + m[1], 0., 0., + 0., 0., 1., 0., + 0., 0., 0., 1. + ); +} + + +void __operator += (inout mat2x3 m, const mat2x3 n) { + m[0] += n[0]; + m[1] += n[1]; +} + +void __operator += (inout mat2x4 m, const mat2x4 n) { + m[0] += n[0]; + m[1] += n[1]; +} + +void __operator += (inout mat3x2 m, const mat3x2 n) { + m[0] += n[0]; + m[1] += n[1]; + m[2] += n[2]; +} + +void __operator += (inout mat3x4 m, const mat3x4 n) { + m[0] += n[0]; + m[1] += n[1]; + m[2] += n[2]; +} + +void __operator += (inout mat4x2 m, const mat4x2 n) { + m[0] += n[0]; + m[1] += n[1]; + m[2] += n[2]; + m[3] += n[3]; +} + +void __operator += (inout mat4x3 m, const mat4x3 n) { + m[0] += n[0]; + m[1] += n[1]; + m[2] += n[2]; + m[3] += n[3]; +} + + +void __operator -= (inout mat2x3 m, const mat2x3 n) { + m[0] -= n[0]; + m[1] -= n[1]; +} + +void __operator -= (inout mat2x4 m, const mat2x4 n) { + m[0] -= n[0]; + m[1] -= n[1]; +} + +void __operator -= (inout mat3x2 m, const mat3x2 n) { + m[0] -= n[0]; + m[1] -= n[1]; + m[2] -= n[2]; +} + +void __operator -= (inout mat3x4 m, const mat3x4 n) { + m[0] -= n[0]; + m[1] -= n[1]; + m[2] -= n[2]; +} + +void __operator -= (inout mat4x2 m, const mat4x2 n) { + m[0] -= n[0]; + m[1] -= n[1]; + m[2] -= n[2]; + m[3] -= n[3]; +} + +void __operator -= (inout mat4x3 m, const mat4x3 n) { + m[0] -= n[0]; + m[1] -= n[1]; + m[2] -= n[2]; + m[3] -= n[3]; +} + + +void __operator /= (inout mat2x3 m, const mat2x3 n) { + m[0] /= n[0]; + m[1] /= n[1]; +} + +void __operator /= (inout mat2x4 m, const mat2x4 n) { + m[0] /= n[0]; + m[1] /= n[1]; +} + +void __operator /= (inout mat3x2 m, const mat3x2 n) { + m[0] /= n[0]; + m[1] /= n[1]; + m[2] /= n[2]; +} + +void __operator /= (inout mat3x4 m, const mat3x4 n) { + m[0] /= n[0]; + m[1] /= n[1]; + m[2] /= n[2]; +} + +void __operator /= (inout mat4x2 m, const mat4x2 n) { + m[0] /= n[0]; + m[1] /= n[1]; + m[2] /= n[2]; + m[3] /= n[3]; +} + +void __operator /= (inout mat4x3 m, const mat4x3 n) { + m[0] /= n[0]; + m[1] /= n[1]; + m[2] /= n[2]; + m[3] /= n[3]; +} + + +vec3 __operator * (const mat2x3 m, const vec2 v) +{ + __retVal.x = v.x * m[0].x + v.y * m[1].x; + __retVal.y = v.x * m[0].y + v.y * m[1].y; + __retVal.z = v.x * m[0].z + v.y * m[1].z; +} + +vec4 __operator * (const mat2x4 m, const vec2 v) +{ + __retVal.x = v.x * m[0].x + v.y * m[1].x; + __retVal.y = v.x * m[0].y + v.y * m[1].y; + __retVal.z = v.x * m[0].z + v.y * m[1].z; + __retVal.w = v.x * m[0].w + v.y * m[1].w; +} + +vec2 __operator * (const mat3x2 m, const vec3 v) +{ + __retVal.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x; + __retVal.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y; +} + +vec4 __operator * (const mat3x4 m, const vec3 v) +{ + __retVal.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x; + __retVal.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y; + __retVal.z = v.x * m[0].z + v.y * m[1].z + v.z * m[2].z; + __retVal.w = v.x * m[0].w + v.y * m[1].w + v.z * m[2].w; +} + +vec2 __operator * (const mat4x2 m, const vec4 v) +{ + __retVal.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x + v.w * m[3].x; + __retVal.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y + v.w * m[3].y; +} + +vec3 __operator * (const mat4x3 m, const vec4 v) +{ + __retVal.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x + v.w * m[3].x; + __retVal.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y + v.w * m[3].y; + __retVal.z = v.x * m[0].z + v.y * m[1].z + v.z * m[2].z + v.w * m[3].z; +} + + +mat3x2 __operator * (const mat2 m, const mat3x2 n) +{ + //return mat3x2 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4x2 __operator * (const mat2 m, const mat4x2 n) +{ + //return mat4x2 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2x3 __operator * (const mat2x3 m, const mat2 n) +{ + //return mat2x3 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3 __operator * (const mat2x3 m, const mat3x2 n) +{ + //return mat3 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4x3 __operator * (const mat2x3 m, const mat4x2 n) +{ + //return mat4x3 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2x4 __operator * (const mat2x4 m, const mat2 n) +{ + //return mat2x4 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3x4 __operator * (const mat2x4 m, const mat3x2 n) +{ + //return mat3x4 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4 __operator * (const mat2x4 m, const mat4x2 n) +{ + //return mat4 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2 __operator * (const mat3x2 m, const mat2x3 n) +{ + //return mat2 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3x2 __operator * (const mat3x2 m, const mat3 n) +{ + //return mat3x2 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4x2 __operator * (const mat3x2 m, const mat4x3 n) +{ + //return mat4x2 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2x3 __operator * (const mat3 m, const mat2x3 n) +{ + //return mat2x3 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat4x3 __operator * (const mat3 m, const mat4x3 n) +{ + //return mat4x3 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2x4 __operator * (const mat3x4 m, const mat2x3 n) +{ + //return mat2x4 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3x4 __operator * (const mat3x4 m, const mat3 n) +{ + //return mat3x4 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4 __operator * (const mat3x4 m, const mat4x3 n) +{ + //return mat4 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2 __operator * (const mat4x2 m, const mat2x4 n) +{ + //return = mat2 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3x2 __operator * (const mat4x2 m, const mat3x4 n) +{ + //return mat3x2 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4x2 __operator * (const mat4x2 m, const mat4 n) +{ + //return mat4x2 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2x3 __operator * (const mat4x3 m, const mat2x4 n) +{ + //return mat2x3 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3 __operator * (const mat4x3 m, const mat3x4 n) +{ + //return mat3 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4x3 __operator * (const mat4x3 m, const mat4 n) +{ + //return mat4x3 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2x4 __operator * (const mat4 m, const mat2x4 n) +{ + //return mat2x4 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3x4 __operator * (const mat4 m, const mat3x4 n) +{ + //return mat3x4 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + + +void __operator *= (inout mat2x3 m, const mat2 n) { + m = m * n; +} + +void __operator *= (inout mat2x4 m, const mat2 n) { + m = m * n; +} + +void __operator *= (inout mat3x2 m, const mat3 n) { + m = m * n; +} + +void __operator *= (inout mat3x4 m, const mat3 n) { + m = m * n; +} + +void __operator *= (inout mat4x2 m, const mat4 n) { + m = m * n; +} + +void __operator *= (inout mat4x3 m, const mat4 n) { + m = m * n; +} + + +vec3 __operator * (const vec2 v, const mat3x2 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); + __retVal.z = dot(v, m[2]); +} + +vec4 __operator * (const vec2 v, const mat4x2 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); + __retVal.z = dot(v, m[2]); + __retVal.w = dot(v, m[3]); +} + +vec2 __operator * (const vec3 v, const mat2x3 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); +} + +vec4 __operator * (const vec3 v, const mat4x3 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); + __retVal.z = dot(v, m[2]); + __retVal.w = dot(v, m[3]); +} + +vec2 __operator * (const vec4 v, const mat2x4 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); +} + +vec3 __operator * (const vec4 v, const mat3x4 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); + __retVal.z = dot(v, m[2]); +} + + +void __operator += (inout mat2x3 m, const float a) { + m[0] += a; + m[1] += a; +} + +void __operator += (inout mat2x4 m, const float a) { + m[0] += a; + m[1] += a; +} + +void __operator += (inout mat3x2 m, const float a) { + m[0] += a; + m[1] += a; + m[2] += a; +} + +void __operator += (inout mat3x4 m, const float a) { + m[0] += a; + m[1] += a; + m[2] += a; +} + +void __operator += (inout mat4x2 m, const float a) { + m[0] += a; + m[1] += a; + m[2] += a; + m[3] += a; +} + +void __operator += (inout mat4x3 m, const float a) { + m[0] += a; + m[1] += a; + m[2] += a; + m[3] += a; +} + + +void __operator -= (inout mat2x3 m, const float a) { + m[0] -= a; + m[1] -= a; +} + +void __operator -= (inout mat2x4 m, const float a) { + m[0] -= a; + m[1] -= a; +} + +void __operator -= (inout mat3x2 m, const float a) { + m[0] -= a; + m[1] -= a; + m[2] -= a; +} + +void __operator -= (inout mat3x4 m, const float a) { + m[0] -= a; + m[1] -= a; + m[2] -= a; +} + +void __operator -= (inout mat4x2 m, const float a) { + m[0] -= a; + m[1] -= a; + m[2] -= a; + m[3] -= a; +} + +void __operator -= (inout mat4x3 m, const float a) { + m[0] -= a; + m[1] -= a; + m[2] -= a; + m[3] -= a; +} + + +void __operator *= (inout mat2x3 m, const float a) { + m[0] *= a; + m[1] *= a; +} + +void __operator *= (inout mat2x4 m, const float a) { + m[0] *= a; + m[1] *= a; +} + +void __operator *= (inout mat3x2 m, const float a) { + m[0] *= a; + m[1] *= a; + m[2] *= a; +} + +void __operator *= (inout mat3x4 m, const float a) { + m[0] *= a; + m[1] *= a; + m[2] *= a; +} + +void __operator *= (inout mat4x2 m, const float a) { + m[0] *= a; + m[1] *= a; + m[2] *= a; + m[3] *= a; +} + +void __operator *= (inout mat4x3 m, const float a) { + m[0] *= a; + m[1] *= a; + m[2] *= a; + m[3] *= a; +} + + +void __operator /= (inout mat2x3 m, const float a) { + m[0] /= a; + m[1] /= a; +} + +void __operator /= (inout mat2x4 m, const float a) { + m[0] /= a; + m[1] /= a; +} + +void __operator /= (inout mat3x2 m, const float a) { + m[0] /= a; + m[1] /= a; + m[2] /= a; +} + +void __operator /= (inout mat3x4 m, const float a) { + m[0] /= a; + m[1] /= a; + m[2] /= a; +} + +void __operator /= (inout mat4x2 m, const float a) { + m[0] /= a; + m[1] /= a; + m[2] /= a; + m[3] /= a; +} + +void __operator /= (inout mat4x3 m, const float a) { + m[0] /= a; + m[1] /= a; + m[2] /= a; + m[3] /= a; +} + + +mat2x3 __operator + (const mat2x3 m, const mat2x3 n) { + return mat2x3 (m[0] + n[0], m[1] + n[1]); +} + +mat2x4 __operator + (const mat2x4 m, const mat2x4 n) { + return mat2x4 (m[0] + n[0], m[1] + n[1]); +} + +mat3x2 __operator + (const mat3x2 m, const mat3x2 n) { + return mat3x2 (m[0] + n[0], m[1] + n[1], m[2] + n[2]); +} + +mat3x4 __operator + (const mat3x4 m, const mat3x4 n) { + return mat3x4 (m[0] + n[0], m[1] + n[1], m[2] + n[2]); +} + +mat4x2 __operator + (const mat4x2 m, const mat4x2 n) { + return mat4x2 (m[0] + n[0], m[1] + n[1], m[2] + n[2], m[3] + n[3]); +} + +mat4x3 __operator + (const mat4x3 m, const mat4x3 n) { + return mat4x3 (m[0] + n[0], m[1] + n[1], m[2] + n[2], m[3] + n[3]); +} + + +mat2x3 __operator - (const mat2x3 m, const mat2x3 n) { + return mat2x3 (m[0] - n[0], m[1] - n[1]); +} + +mat2x4 __operator - (const mat2x4 m, const mat2x4 n) { + return mat2x4 (m[0] - n[0], m[1] - n[1]); +} + +mat3x2 __operator - (const mat3x2 m, const mat3x2 n) { + return mat3x2 (m[0] - n[0], m[1] - n[1], m[2] - n[2]); +} + +mat3x4 __operator - (const mat3x4 m, const mat3x4 n) { + return mat3x4 (m[0] - n[0], m[1] - n[1], m[2] - n[2]); +} + +mat4x2 __operator - (const mat4x2 m, const mat4x2 n) { + return mat4x2 (m[0] - n[0], m[1] - n[1], m[2] - n[2], m[3] - n[3]); +} + +mat4x3 __operator - (const mat4x3 m, const mat4x3 n) { + return mat4x3 (m[0] - n[0], m[1] - n[1], m[2] - n[2], m[3] - n[3]); +} + + +mat2x3 __operator / (const mat2x3 m, const mat2x3 n) { + return mat2x3 (m[0] / n[0], m[1] / n[1]); +} + +mat2x4 __operator / (const mat2x4 m, const mat2x4 n) { + return mat2x4 (m[0] / n[0], m[1] / n[1]); +} + +mat3x2 __operator / (const mat3x2 m, const mat3x2 n) { + return mat3x2 (m[0] / n[0], m[1] / n[1], m[2] / n[2]); +} + +mat3x4 __operator / (const mat3x4 m, const mat3x4 n) { + return mat3x4 (m[0] / n[0], m[1] / n[1], m[2] / n[2]); +} + +mat4x2 __operator / (const mat4x2 m, const mat4x2 n) { + return mat4x2 (m[0] / n[0], m[1] / n[1], m[2] / n[2], m[3] / n[3]); +} + +mat4x3 __operator / (const mat4x3 m, const mat4x3 n) { + return mat4x3 (m[0] / n[0], m[1] / n[1], m[2] / n[2], m[3] / n[3]); +} + + +mat2x3 __operator + (const float a, const mat2x3 n) { + return mat2x3 (a + n[0], a + n[1]); +} + +mat2x3 __operator + (const mat2x3 m, const float b) { + return mat2x3 (m[0] + b, m[1] + b); +} + +mat2x4 __operator + (const float a, const mat2x4 n) { + return mat2x4 (a + n[0], a + n[1]); +} + +mat2x4 __operator + (const mat2x4 m, const float b) { + return mat2x4 (m[0] + b, m[1] + b); +} + +mat3x2 __operator + (const float a, const mat3x2 n) { + return mat3x2 (a + n[0], a + n[1], a + n[2]); +} + +mat3x2 __operator + (const mat3x2 m, const float b) { + return mat3x2 (m[0] + b, m[1] + b, m[2] + b); +} + +mat3x4 __operator + (const float a, const mat3x4 n) { + return mat3x4 (a + n[0], a + n[1], a + n[2]); +} + +mat3x4 __operator + (const mat3x4 m, const float b) { + return mat3x4 (m[0] + b, m[1] + b, m[2] + b); +} + +mat4x2 __operator + (const mat4x2 m, const float b) { + return mat4x2 (m[0] + b, m[1] + b, m[2] + b, m[3] + b); +} + +mat4x2 __operator + (const float a, const mat4x2 n) { + return mat4x2 (a + n[0], a + n[1], a + n[2], a + n[3]); +} + +mat4x3 __operator + (const mat4x3 m, const float b) { + return mat4x3 (m[0] + b, m[1] + b, m[2] + b, m[3] + b); +} + +mat4x3 __operator + (const float a, const mat4x3 n) { + return mat4x3 (a + n[0], a + n[1], a + n[2], a + n[3]); +} + + +mat2x3 __operator - (const float a, const mat2x3 n) { + return mat2x3 (a - n[0], a - n[1]); +} + +mat2x3 __operator - (const mat2x3 m, const float b) { + return mat2x3 (m[0] - b, m[1] - b); +} + +mat2x4 __operator - (const float a, const mat2x4 n) { + return mat2x4 (a - n[0], a - n[1]); +} + +mat2x4 __operator - (const mat2x4 m, const float b) { + return mat2x4 (m[0] - b, m[1] - b); +} + +mat3x2 __operator - (const float a, const mat3x2 n) { + return mat3x2 (a - n[0], a - n[1], a - n[2]); +} + +mat3x2 __operator - (const mat3x2 m, const float b) { + return mat3x2 (m[0] - b, m[1] - b, m[2] - b); +} + +mat3x4 __operator - (const float a, const mat3x4 n) { + return mat3x4 (a - n[0], a - n[1], a - n[2]); +} + +mat3x4 __operator - (const mat3x4 m, const float b) { + return mat3x4 (m[0] - b, m[1] - b, m[2] - b); +} + +mat4x2 __operator - (const mat4x2 m, const float b) { + return mat4x2 (m[0] - b, m[1] - b, m[2] - b, m[3] - b); +} + +mat4x2 __operator - (const float a, const mat4x2 n) { + return mat4x2 (a - n[0], a - n[1], a - n[2], a - n[3]); +} + +mat4x3 __operator - (const mat4x3 m, const float b) { + return mat4x3 (m[0] - b, m[1] - b, m[2] - b, m[3] - b); +} + +mat4x3 __operator - (const float a, const mat4x3 n) { + return mat4x3 (a - n[0], a - n[1], a - n[2], a - n[3]); +} + + +mat2x3 __operator * (const float a, const mat2x3 n) +{ + //return mat2x3 (a * n[0], a * n[1]); + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; +} + +mat2x3 __operator * (const mat2x3 m, const float b) +{ + //return mat2x3 (m[0] * b, m[1] * b); + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; +} + +mat2x4 __operator * (const float a, const mat2x4 n) +{ + //return mat2x4 (a * n[0], a * n[1]); + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; +} + +mat2x4 __operator * (const mat2x4 m, const float b) +{ + //return mat2x4 (m[0] * b, m[1] * b); + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; +} + +mat3x2 __operator * (const float a, const mat3x2 n) +{ + //return mat3x2 (a * n[0], a * n[1], a * n[2]); + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; + __retVal[2] = a * n[2]; +} + +mat3x2 __operator * (const mat3x2 m, const float b) +{ + //return mat3x2 (m[0] * b, m[1] * b, m[2] * b); + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; + __retVal[2] = m[2] * b; +} + +mat3x4 __operator * (const float a, const mat3x4 n) +{ + //return mat3x4 (a * n[0], a * n[1], a * n[2]); + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; + __retVal[2] = a * n[2]; +} + +mat3x4 __operator * (const mat3x4 m, const float b) +{ + //return mat3x4 (m[0] * b, m[1] * b, m[2] * b); + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; + __retVal[2] = m[2] * b; +} + +mat4x2 __operator * (const mat4x2 m, const float b) +{ + //return mat4x2 (m[0] * b, m[1] * b, m[2] * b, m[3] * b); + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; + __retVal[2] = m[2] * b; + __retVal[3] = m[3] * b; +} + +mat4x2 __operator * (const float a, const mat4x2 n) +{ + //return mat4x2 (a * n[0], a * n[1], a * n[2], a * n[3]); + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; + __retVal[2] = a * n[2]; + __retVal[3] = a * n[3]; +} + +mat4x3 __operator * (const mat4x3 m, const float b) +{ + //return mat4x3 (m[0] * b, m[1] * b, m[2] * b, m[3] * b); + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; + __retVal[2] = m[2] * b; + __retVal[3] = m[3] * b; +} + +mat4x3 __operator * (const float a, const mat4x3 n) +{ + //return mat4x3 (a * n[0], a * n[1], a * n[2], a * n[3]); + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; + __retVal[2] = a * n[2]; + __retVal[3] = a * n[3]; +} + + +mat2x3 __operator / (const float a, const mat2x3 n) +{ + //return mat2x3 (a / n[0], a / n[1]); + const float inv = 1.0 / a; + __retVal[0] = inv * n[0]; + __retVal[1] = inv * n[1]; +} + +mat2x3 __operator / (const mat2x3 m, const float b) +{ + //return mat2x3 (m[0] / b, m[1] / b); + const float inv = 1.0 / b; + __retVal[0] = m[0] * inv; + __retVal[1] = m[1] * inv; +} + +mat2x4 __operator / (const float a, const mat2x4 n) +{ + //return mat2x4 (a / n[0], a / n[1]); + const float inv = 1.0 / a; + __retVal[0] = inv * n[0]; + __retVal[1] = inv * n[1]; +} + +mat2x4 __operator / (const mat2x4 m, const float b) +{ + //return mat2x4 (m[0] / b, m[1] / b); + const float inv = 1.0 / b; + __retVal[0] = m[0] * inv; + __retVal[1] = m[1] * inv; +} + +mat3x2 __operator / (const float a, const mat3x2 n) +{ + //return mat3x2 (a / n[0], a / n[1], a / n[2]); + const float inv = 1.0 / a; + __retVal[0] = inv * n[0]; + __retVal[1] = inv * n[1]; + __retVal[2] = inv * n[2]; +} + +mat3x2 __operator / (const mat3x2 m, const float b) +{ + //return mat3x2 (m[0] / b, m[1] / b, m[2] / b); + const float inv = 1.0 / b; + __retVal[0] = m[0] * inv; + __retVal[1] = m[1] * inv; + __retVal[2] = m[2] * inv; +} + +mat3x4 __operator / (const float a, const mat3x4 n) +{ + //return mat3x4 (a / n[0], a / n[1], a / n[2]); + const float inv = 1.0 / a; + __retVal[0] = inv * n[0]; + __retVal[1] = inv * n[1]; + __retVal[2] = inv * n[2]; +} + +mat3x4 __operator / (const mat3x4 m, const float b) +{ + //return mat3x4 (m[0] / b, m[1] / b, m[2] / b); + const float inv = 1.0 / b; + __retVal[0] = m[0] * inv; + __retVal[1] = m[1] * inv; + __retVal[2] = m[2] * inv; +} + +mat4x2 __operator / (const mat4x2 m, const float b) +{ + //return mat4x2 (m[0] / b, m[1] / b, m[2] / b, m[3] / b); + const float inv = 1.0 / b; + __retVal[0] = m[0] * inv; + __retVal[1] = m[1] * inv; + __retVal[2] = m[2] * inv; + __retVal[3] = m[3] * inv; +} + +mat4x2 __operator / (const float a, const mat4x2 n) +{ + //return mat4x2 (a / n[0], a / n[1], a / n[2], a / n[3]); + const float inv = 1.0 / a; + __retVal[0] = inv * n[0]; + __retVal[1] = inv * n[1]; + __retVal[2] = inv * n[2]; + __retVal[3] = inv * n[3]; +} + +mat4x3 __operator / (const mat4x3 m, const float b) +{ + //return mat4x3 (m[0] / b, m[1] / b, m[2] / b, m[3] / b); + const float inv = 1.0 / b; + __retVal[0] = m[0] * inv; + __retVal[1] = m[1] * inv; + __retVal[2] = m[2] * inv; + __retVal[3] = m[3] * inv; +} + +mat4x3 __operator / (const float a, const mat4x3 n) +{ + //return mat4x3 (a / n[0], a / n[1], a / n[2], a / n[3]); + const float inv = 1.0 / a; + __retVal[0] = inv * n[0]; + __retVal[1] = inv * n[1]; + __retVal[2] = inv * n[2]; + __retVal[3] = inv * n[3]; +} + + +mat2x3 __operator - (const mat2x3 m) { + return mat2x3 (-m[0], -m[1]); +} + +mat2x4 __operator - (const mat2x4 m) { + return mat2x4 (-m[0], -m[1]); +} + +mat3x2 __operator - (const mat3x2 m) { + return mat3x2 (-m[0], -m[1], -m[2]); +} + +mat3x4 __operator - (const mat3x4 m) { + return mat3x4 (-m[0], -m[1], -m[2]); +} + +mat4x2 __operator - (const mat4x2 m) { + return mat4x2 (-m[0], -m[1], -m[2], -m[3]); +} + +mat4x3 __operator - (const mat4x3 m) { + return mat4x3 (-m[0], -m[1], -m[2], -m[3]); +} + + +void __operator -- (inout mat2x3 m) { + --m[0]; + --m[1]; +} + +void __operator -- (inout mat2x4 m) { + --m[0]; + --m[1]; +} + +void __operator -- (inout mat3x2 m) { + --m[0]; + --m[1]; + --m[2]; +} + +void __operator -- (inout mat3x4 m) { + --m[0]; + --m[1]; + --m[2]; +} + +void __operator -- (inout mat4x2 m) { + --m[0]; + --m[1]; + --m[2]; + --m[3]; +} + +void __operator -- (inout mat4x3 m) { + --m[0]; + --m[1]; + --m[2]; + --m[3]; +} + + +void __operator ++ (inout mat2x3 m) { + ++m[0]; + ++m[1]; +} + +void __operator ++ (inout mat2x4 m) { + ++m[0]; + ++m[1]; +} + +void __operator ++ (inout mat3x2 m) { + ++m[0]; + ++m[1]; + ++m[2]; +} + +void __operator ++ (inout mat3x4 m) { + ++m[0]; + ++m[1]; + ++m[2]; +} + +void __operator ++ (inout mat4x2 m) { + ++m[0]; + ++m[1]; + ++m[2]; + ++m[3]; +} + +void __operator ++ (inout mat4x3 m) { + ++m[0]; + ++m[1]; + ++m[2]; + ++m[3]; +} + diff --git a/src/mesa/slang/library/slang_builtin_120_common.gc b/src/mesa/slang/library/slang_builtin_120_common.gc new file mode 100644 index 0000000000..c6264c3b47 --- /dev/null +++ b/src/mesa/slang/library/slang_builtin_120_common.gc @@ -0,0 +1,200 @@ +/* + * Mesa 3-D graphics library + * Version: 6.6 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// From Shader Spec, ver. 1.20, rev. 6 +// + +// +// 8.5 Matrix Functions +// + +mat2x3 matrixCompMult (mat2x3 m, mat2x3 n) { + return mat2x3 (m[0] * n[0], m[1] * n[1]); +} + +mat2x4 matrixCompMult (mat2x4 m, mat2x4 n) { + return mat2x4 (m[0] * n[0], m[1] * n[1]); +} + +mat3x2 matrixCompMult (mat3x2 m, mat3x2 n) { + return mat3x2 (m[0] * n[0], m[1] * n[1], m[2] * n[2]); +} + +mat3x4 matrixCompMult (mat3x4 m, mat3x4 n) { + return mat3x4 (m[0] * n[0], m[1] * n[1], m[2] * n[2]); +} + +mat4x2 matrixCompMult (mat4x2 m, mat4x2 n) { + return mat4x2 (m[0] * n[0], m[1] * n[1], m[2] * n[2], m[3] * n[3]); +} + +mat4x3 matrixCompMult (mat4x3 m, mat4x3 n) { + return mat4x3 (m[0] * n[0], m[1] * n[1], m[2] * n[2], m[3] * n[3]); +} + +mat2 outerProduct (vec2 c, vec2 r) { + return mat2 ( + c.x * r.x, c.y * r.x, + c.x * r.y, c.y * r.y + ); +} + +mat3 outerProduct (vec3 c, vec3 r) { + return mat3 ( + c.x * r.x, c.y * r.x, c.z * r.x, + c.x * r.y, c.y * r.y, c.z * r.y, + c.x * r.z, c.y * r.z, c.z * r.z + ); +} + +mat4 outerProduct (vec4 c, vec4 r) { + return mat4 ( + c.x * r.x, c.y * r.x, c.z * r.x, c.w * r.x, + c.x * r.y, c.y * r.y, c.z * r.y, c.w * r.y, + c.x * r.z, c.y * r.z, c.z * r.z, c.w * r.z, + c.x * r.w, c.y * r.w, c.z * r.w, c.w * r.w + ); +} + +mat2x3 outerProduct (vec3 c, vec2 r) { + return mat2x3 ( + c.x * r.x, c.y * r.x, c.z * r.x, + c.x * r.y, c.y * r.y, c.z * r.y + ); +} + +mat3x2 outerProduct (vec2 c, vec3 r) { + return mat3x2 ( + c.x * r.x, c.y * r.x, + c.x * r.y, c.y * r.y, + c.x * r.z, c.y * r.z + ); +} + +mat2x4 outerProduct (vec4 c, vec2 r) { + return mat2x4 ( + c.x * r.x, c.y * r.x, c.z * r.x, c.w * r.x, + c.x * r.y, c.y * r.y, c.z * r.y, c.w * r.y + ); +} + +mat4x2 outerProduct (vec2 c, vec4 r) { + return mat4x2 ( + c.x * r.x, c.y * r.x, + c.x * r.y, c.y * r.y, + c.x * r.z, c.y * r.z, + c.x * r.w, c.y * r.w + ); +} + +mat3x4 outerProduct (vec4 c, vec3 r) { + return mat3x4 ( + c.x * r.x, c.y * r.x, c.z * r.x, c.w * r.x, + c.x * r.y, c.y * r.y, c.z * r.y, c.w * r.y, + c.x * r.z, c.y * r.z, c.z * r.z, c.w * r.z + ); +} + +mat4x3 outerProduct (vec3 c, vec4 r) { + return mat4x3 ( + c.x * r.x, c.y * r.x, c.z * r.x, + c.x * r.y, c.y * r.y, c.z * r.y, + c.x * r.z, c.y * r.z, c.z * r.z, + c.x * r.w, c.y * r.w, c.z * r.w + ); +} + +mat2 transpose (mat2 m) { + return mat2 ( + m[0].x, m[1].x, + m[0].y, m[1].y + ); +} + +mat3 transpose (mat3 m) { + return mat3 ( + m[0].x, m[1].x, m[2].x, + m[0].y, m[1].y, m[2].y, + m[0].z, m[1].z, m[2].z + ); +} + +mat4 transpose (mat4 m) { + return mat4 ( + m[0].x, m[1].x, m[2].x, m[3].x, + m[0].y, m[1].y, m[2].y, m[3].y, + m[0].z, m[1].z, m[2].z, m[3].z, + m[0].w, m[1].w, m[2].w, m[3].w + ); +} + +mat2x3 transpose (mat3x2 m) { + return mat2x3 ( + m[0].x, m[1].x, m[2].x, + m[0].y, m[1].y, m[2].y + ); +} + +mat3x2 transpose (mat2x3 m) { + return mat3x2 ( + m[0].x, m[1].x, + m[0].y, m[1].y, + m[0].z, m[1].z + ); +} + +mat2x4 transpose (mat4x2 m) { + return mat2x4 ( + m[0].x, m[1].x, m[2].x, m[3].x, + m[0].y, m[1].y, m[2].y, m[3].y + ); +} + +mat4x2 transpose (mat2x4 m) { + return mat4x2 ( + m[0].x, m[1].x, + m[0].y, m[1].y, + m[0].z, m[1].z, + m[0].w, m[1].w + ); +} + +mat3x4 transpose (mat4x3 m) { + return mat3x4 ( + m[0].x, m[1].x, m[2].x, m[3].x, + m[0].y, m[1].y, m[2].y, m[3].y, + m[0].z, m[1].z, m[2].z, m[3].z + ); +} + +mat4x3 transpose (mat3x4 m) { + return mat4x3 ( + m[0].x, m[1].x, m[2].x, + m[0].y, m[1].y, m[2].y, + m[0].z, m[1].z, m[2].z, + m[0].w, m[1].w, m[2].w + ); +} + diff --git a/src/mesa/slang/library/slang_builtin_120_fragment.gc b/src/mesa/slang/library/slang_builtin_120_fragment.gc new file mode 100644 index 0000000000..7d516046a1 --- /dev/null +++ b/src/mesa/slang/library/slang_builtin_120_fragment.gc @@ -0,0 +1,30 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// From Shader Spec, ver. 1.20, rev. 6 +// + +varying vec2 gl_PointCoord; + diff --git a/src/mesa/slang/library/slang_common_builtin.gc b/src/mesa/slang/library/slang_common_builtin.gc new file mode 100644 index 0000000000..d75354deff --- /dev/null +++ b/src/mesa/slang/library/slang_common_builtin.gc @@ -0,0 +1,1887 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * Copyright (C) 2008 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// From Shader Spec, ver. 1.10, rev. 59 +// + +// Note: the values assigned to these constants here aren't actually used. +// They're set by the compiler according to the GL context limits. +// See slang_simplify.c +const int gl_MaxLights = 8; +const int gl_MaxClipPlanes = 6; +const int gl_MaxTextureUnits = 8; +const int gl_MaxTextureCoords = 8; +const int gl_MaxVertexAttribs = 16; +const int gl_MaxVertexUniformComponents = 512; +const int gl_MaxVaryingFloats = 32; +const int gl_MaxVertexTextureImageUnits = 0; +const int gl_MaxCombinedTextureImageUnits = 2; +const int gl_MaxTextureImageUnits = 2; +const int gl_MaxFragmentUniformComponents = 64; +const int gl_MaxDrawBuffers = 1; + +uniform mat4 gl_ModelViewMatrix; +uniform mat4 gl_ProjectionMatrix; +uniform mat4 gl_ModelViewProjectionMatrix; +uniform mat4 gl_TextureMatrix[gl_MaxTextureCoords]; + +uniform mat3 gl_NormalMatrix; + +uniform mat4 gl_ModelViewMatrixInverse; +uniform mat4 gl_ProjectionMatrixInverse; +uniform mat4 gl_ModelViewProjectionMatrixInverse; +uniform mat4 gl_TextureMatrixInverse[gl_MaxTextureCoords]; + +uniform mat4 gl_ModelViewMatrixTranspose; +uniform mat4 gl_ProjectionMatrixTranspose; +uniform mat4 gl_ModelViewProjectionMatrixTranspose; +uniform mat4 gl_TextureMatrixTranspose[gl_MaxTextureCoords]; + +uniform mat4 gl_ModelViewMatrixInverseTranspose; +uniform mat4 gl_ProjectionMatrixInverseTranspose; +uniform mat4 gl_ModelViewProjectionMatrixInverseTranspose; +uniform mat4 gl_TextureMatrixInverseTranspose[gl_MaxTextureCoords]; + +uniform float gl_NormalScale; + +struct gl_DepthRangeParameters { + float near; + float far; + float diff; +}; + +uniform gl_DepthRangeParameters gl_DepthRange; + +uniform vec4 gl_ClipPlane[gl_MaxClipPlanes]; + +struct gl_PointParameters { + float size; + float sizeMin; + float sizeMax; + float fadeThresholdSize; + float distanceConstantAttenuation; + float distanceLinearAttenuation; + float distanceQuadraticAttenuation; +}; + +uniform gl_PointParameters gl_Point; + +struct gl_MaterialParameters { + vec4 emission; + vec4 ambient; + vec4 diffuse; + vec4 specular; + float shininess; +}; + +uniform gl_MaterialParameters gl_FrontMaterial; +uniform gl_MaterialParameters gl_BackMaterial; + +/* NOTE: the order of these fields is significant! + * See the definition of the lighting state vars such as STATE_SPOT_DIRECTION. + */ +struct gl_LightSourceParameters { + vec4 ambient; + vec4 diffuse; + vec4 specular; + vec4 position; + vec4 halfVector; + vec3 spotDirection; + float spotCosCutoff; + + float constantAttenuation; + float linearAttenuation; + float quadraticAttenuation; + float spotExponent; + + float spotCutoff; +}; + +uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights]; + +struct gl_LightModelParameters { + vec4 ambient; +}; + +uniform gl_LightModelParameters gl_LightModel; + +struct gl_LightModelProducts { + vec4 sceneColor; +}; + +uniform gl_LightModelProducts gl_FrontLightModelProduct; +uniform gl_LightModelProducts gl_BackLightModelProduct; + +struct gl_LightProducts { + vec4 ambient; + vec4 diffuse; + vec4 specular; +}; + +uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights]; +uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights]; + +uniform vec4 gl_TextureEnvColor[gl_MaxTextureImageUnits]; +uniform vec4 gl_EyePlaneS[gl_MaxTextureCoords]; +uniform vec4 gl_EyePlaneT[gl_MaxTextureCoords]; +uniform vec4 gl_EyePlaneR[gl_MaxTextureCoords]; +uniform vec4 gl_EyePlaneQ[gl_MaxTextureCoords]; +uniform vec4 gl_ObjectPlaneS[gl_MaxTextureCoords]; +uniform vec4 gl_ObjectPlaneT[gl_MaxTextureCoords]; +uniform vec4 gl_ObjectPlaneR[gl_MaxTextureCoords]; +uniform vec4 gl_ObjectPlaneQ[gl_MaxTextureCoords]; + +struct gl_FogParameters { + vec4 color; + float density; + float start; + float end; + float scale; +}; + +uniform gl_FogParameters gl_Fog; + + + + + +// +// 8.1 Angle and Trigonometry Functions +// + +//// radians + +float radians(const float deg) +{ + const float c = 3.1415926 / 180.0; + __asm vec4_multiply __retVal, deg, c; +} + +vec2 radians(const vec2 deg) +{ + const float c = 3.1415926 / 180.0; + __asm vec4_multiply __retVal.xy, deg.xy, c.xx; +} + +vec3 radians(const vec3 deg) +{ + const float c = 3.1415926 / 180.0; + __asm vec4_multiply __retVal.xyz, deg.xyz, c.xxx; +} + +vec4 radians(const vec4 deg) +{ + const float c = 3.1415926 / 180.0; + __asm vec4_multiply __retVal, deg, c.xxxx; +} + + +//// degrees + +float degrees(const float rad) +{ + const float c = 180.0 / 3.1415926; + __asm vec4_multiply __retVal, rad, c; +} + +vec2 degrees(const vec2 rad) +{ + const float c = 180.0 / 3.1415926; + __asm vec4_multiply __retVal.xy, rad.xy, c.xx; +} + +vec3 degrees(const vec3 rad) +{ + const float c = 180.0 / 3.1415926; + __asm vec4_multiply __retVal.xyz, rad.xyz, c.xxx; +} + +vec4 degrees(const vec4 rad) +{ + const float c = 180.0 / 3.1415926; + __asm vec4_multiply __retVal, rad, c.xxxx; +} + + +//// sin + +float sin(const float radians) +{ + __asm float_sine __retVal, radians; +} + +vec2 sin(const vec2 radians) +{ + __asm float_sine __retVal.x, radians.x; + __asm float_sine __retVal.y, radians.y; +} + +vec3 sin(const vec3 radians) +{ + __asm float_sine __retVal.x, radians.x; + __asm float_sine __retVal.y, radians.y; + __asm float_sine __retVal.z, radians.z; +} + +vec4 sin(const vec4 radians) +{ + __asm float_sine __retVal.x, radians.x; + __asm float_sine __retVal.y, radians.y; + __asm float_sine __retVal.z, radians.z; + __asm float_sine __retVal.w, radians.w; +} + + +//// cos + +float cos(const float radians) +{ + __asm float_cosine __retVal, radians; +} + +vec2 cos(const vec2 radians) +{ + __asm float_cosine __retVal.x, radians.x; + __asm float_cosine __retVal.y, radians.y; +} + +vec3 cos(const vec3 radians) +{ + __asm float_cosine __retVal.x, radians.x; + __asm float_cosine __retVal.y, radians.y; + __asm float_cosine __retVal.z, radians.z; +} + +vec4 cos(const vec4 radians) +{ + __asm float_cosine __retVal.x, radians.x; + __asm float_cosine __retVal.y, radians.y; + __asm float_cosine __retVal.z, radians.z; + __asm float_cosine __retVal.w, radians.w; +} + + + +//// tan + +float tan(const float angle) +{ + const float s = sin(angle); + const float c = cos(angle); + return s / c; +} + +vec2 tan(const vec2 angle) +{ + const vec2 s = sin(angle); + const vec2 c = cos(angle); + return s / c; +} + +vec3 tan(const vec3 angle) +{ + const vec3 s = sin(angle); + const vec3 c = cos(angle); + return s / c; +} + +vec4 tan(const vec4 angle) +{ + const vec4 s = sin(angle); + const vec4 c = cos(angle); + return s / c; +} + + + +float asin(const float x) +{ + const float a0 = 1.5707288; // PI/2? + const float a1 = -0.2121144; + const float a2 = 0.0742610; + //const float a3 = -0.0187293; + const float halfPi = 3.1415926 * 0.5; + const float y = abs(x); + // three terms seem to be enough: + __retVal = (halfPi - sqrt(1.0 - y) * (a0 + y * (a1 + a2 * y))) * sign(x); + // otherwise, try four: + //__retVal = (halfPi - sqrt(1.0 - y) * (a0 + y * (a1 + y * (a2 + y * a3)))) * sign(x); +} + +vec2 asin(const vec2 v) +{ + __retVal.x = asin(v.x); + __retVal.y = asin(v.y); +} + +vec3 asin(const vec3 v) +{ + __retVal.x = asin(v.x); + __retVal.y = asin(v.y); + __retVal.z = asin(v.z); +} + +vec4 asin(const vec4 v) +{ + __retVal.x = asin(v.x); + __retVal.y = asin(v.y); + __retVal.z = asin(v.z); + __retVal.w = asin(v.w); +} + +float acos(const float x) +{ + const float halfPi = 3.1415926 * 0.5; + __retVal = halfPi - asin(x); +} + +vec2 acos(const vec2 v) +{ + __retVal.x = acos(v.x); + __retVal.y = acos(v.y); +} + +vec3 acos(const vec3 v) +{ + __retVal.x = acos(v.x); + __retVal.y = acos(v.y); + __retVal.z = acos(v.z); +} + +vec4 acos(const vec4 v) +{ + __retVal.x = acos(v.x); + __retVal.y = acos(v.y); + __retVal.z = acos(v.z); + __retVal.w = acos(v.w); +} + +float atan(const float x) +{ + __retVal = asin(x * inversesqrt(x * x + 1.0)); +} + +vec2 atan(const vec2 y_over_x) +{ + __retVal.x = atan(y_over_x.x); + __retVal.y = atan(y_over_x.y); +} + +vec3 atan(const vec3 y_over_x) +{ + __retVal.x = atan(y_over_x.x); + __retVal.y = atan(y_over_x.y); + __retVal.z = atan(y_over_x.z); +} + +vec4 atan(const vec4 y_over_x) +{ + __retVal.x = atan(y_over_x.x); + __retVal.y = atan(y_over_x.y); + __retVal.z = atan(y_over_x.z); + __retVal.w = atan(y_over_x.w); +} + +float atan(const float y, const float x) +{ + float r; + if (abs(x) > 1.0e-4) { + r = atan(y / x); + if (x < 0.0) { + r = r + sign(y) * 3.141593; + } + } + else { + r = sign(y) * 1.5707965; // pi/2 + } + return r; +} + +vec2 atan(const vec2 u, const vec2 v) +{ + __retVal.x = atan(u.x, v.x); + __retVal.y = atan(u.y, v.y); +} + +vec3 atan(const vec3 u, const vec3 v) +{ + __retVal.x = atan(u.x, v.x); + __retVal.y = atan(u.y, v.y); + __retVal.z = atan(u.z, v.z); +} + +vec4 atan(const vec4 u, const vec4 v) +{ + __retVal.x = atan(u.x, v.x); + __retVal.y = atan(u.y, v.y); + __retVal.z = atan(u.z, v.z); + __retVal.w = atan(u.w, v.w); +} + + +// +// 8.2 Exponential Functions +// + +//// pow + +float pow(const float a, const float b) +{ + __asm float_power __retVal, a, b; +} + +vec2 pow(const vec2 a, const vec2 b) +{ + __asm float_power __retVal.x, a.x, b.x; + __asm float_power __retVal.y, a.y, b.y; +} + +vec3 pow(const vec3 a, const vec3 b) +{ + __asm float_power __retVal.x, a.x, b.x; + __asm float_power __retVal.y, a.y, b.y; + __asm float_power __retVal.z, a.z, b.z; +} + +vec4 pow(const vec4 a, const vec4 b) +{ + __asm float_power __retVal.x, a.x, b.x; + __asm float_power __retVal.y, a.y, b.y; + __asm float_power __retVal.z, a.z, b.z; + __asm float_power __retVal.w, a.w, b.w; +} + + +//// exp + +float exp(const float a) +{ + // NOTE: log2(e) = 1.44269502 + float t = a * 1.44269502; + __asm float_exp2 __retVal, t; +} + +vec2 exp(const vec2 a) +{ + vec2 t = a * 1.44269502; + __asm float_exp2 __retVal.x, t.x; + __asm float_exp2 __retVal.y, t.y; +} + +vec3 exp(const vec3 a) +{ + vec3 t = a * 1.44269502; + __asm float_exp2 __retVal.x, t.x; + __asm float_exp2 __retVal.y, t.y; + __asm float_exp2 __retVal.z, t.z; +} + +vec4 exp(const vec4 a) +{ + vec4 t = a * 1.44269502; + __asm float_exp2 __retVal.x, t.x; + __asm float_exp2 __retVal.y, t.y; + __asm float_exp2 __retVal.z, t.z; + __asm float_exp2 __retVal.w, t.w; +} + + + +//// log2 + +float log2(const float x) +{ + __asm float_log2 __retVal, x; +} + +vec2 log2(const vec2 v) +{ + __asm float_log2 __retVal.x, v.x; + __asm float_log2 __retVal.y, v.y; +} + +vec3 log2(const vec3 v) +{ + __asm float_log2 __retVal.x, v.x; + __asm float_log2 __retVal.y, v.y; + __asm float_log2 __retVal.z, v.z; +} + +vec4 log2(const vec4 v) +{ + __asm float_log2 __retVal.x, v.x; + __asm float_log2 __retVal.y, v.y; + __asm float_log2 __retVal.z, v.z; + __asm float_log2 __retVal.w, v.w; +} + + +//// log (natural log) + +float log(const float x) +{ + // note: logBaseB(x) = logBaseN(x) / logBaseN(B) + // compute log(x) = log2(x) / log2(e) + // c = 1.0 / log2(e) = 0.693147181 + const float c = 0.693147181; + return log2(x) * c; +} + +vec2 log(const vec2 v) +{ + const float c = 0.693147181; + return log2(v) * c; +} + +vec3 log(const vec3 v) +{ + const float c = 0.693147181; + return log2(v) * c; +} + +vec4 log(const vec4 v) +{ + const float c = 0.693147181; + return log2(v) * c; +} + + +//// exp2 + +float exp2(const float a) +{ + __asm float_exp2 __retVal, a; +} + +vec2 exp2(const vec2 a) +{ + __asm float_exp2 __retVal.x, a.x; + __asm float_exp2 __retVal.y, a.y; +} + +vec3 exp2(const vec3 a) +{ + __asm float_exp2 __retVal.x, a.x; + __asm float_exp2 __retVal.y, a.y; + __asm float_exp2 __retVal.z, a.z; +} + +vec4 exp2(const vec4 a) +{ + __asm float_exp2 __retVal.x, a.x; + __asm float_exp2 __retVal.y, a.y; + __asm float_exp2 __retVal.z, a.z; + __asm float_exp2 __retVal.w, a.w; +} + + +//// sqrt + +float sqrt(const float x) +{ + const float nx = -x; + float r; + __asm float_rsq r, x; + r = r * x; + __asm vec4_cmp __retVal, nx, r, 0.0; +} + +vec2 sqrt(const vec2 x) +{ + const vec2 nx = -x, zero = vec2(0.0); + vec2 r; + __asm float_rsq r.x, x.x; + __asm float_rsq r.y, x.y; + r = r * x; + __asm vec4_cmp __retVal, nx, r, zero; +} + +vec3 sqrt(const vec3 x) +{ + const vec3 nx = -x, zero = vec3(0.0); + vec3 r; + __asm float_rsq r.x, x.x; + __asm float_rsq r.y, x.y; + __asm float_rsq r.z, x.z; + r = r * x; + __asm vec4_cmp __retVal, nx, r, zero; +} + +vec4 sqrt(const vec4 x) +{ + const vec4 nx = -x, zero = vec4(0.0); + vec4 r; + __asm float_rsq r.x, x.x; + __asm float_rsq r.y, x.y; + __asm float_rsq r.z, x.z; + __asm float_rsq r.w, x.w; + r = r * x; + __asm vec4_cmp __retVal, nx, r, zero; +} + + +//// inversesqrt + +float inversesqrt(const float x) +{ + __asm float_rsq __retVal.x, x; +} + +vec2 inversesqrt(const vec2 v) +{ + __asm float_rsq __retVal.x, v.x; + __asm float_rsq __retVal.y, v.y; +} + +vec3 inversesqrt(const vec3 v) +{ + __asm float_rsq __retVal.x, v.x; + __asm float_rsq __retVal.y, v.y; + __asm float_rsq __retVal.z, v.z; +} + +vec4 inversesqrt(const vec4 v) +{ + __asm float_rsq __retVal.x, v.x; + __asm float_rsq __retVal.y, v.y; + __asm float_rsq __retVal.z, v.z; + __asm float_rsq __retVal.w, v.w; +} + + +//// normalize + +float normalize(const float x) +{ + __retVal = 1.0; +} + +vec2 normalize(const vec2 v) +{ + const float s = inversesqrt(dot(v, v)); + __asm vec4_multiply __retVal.xy, v, s; +} + +vec3 normalize(const vec3 v) +{ +// const float s = inversesqrt(dot(v, v)); +// __retVal = v * s; +// XXX note, we _could_ use __retVal.w instead of tmp and save a +// register, but that's actually a compilation error because v is a vec3 +// and the .w suffix is illegal. Oh well. + float tmp; + __asm vec3_dot tmp, v, v; + __asm float_rsq tmp, tmp; + __asm vec4_multiply __retVal.xyz, v, tmp; +} + +vec4 normalize(const vec4 v) +{ + float tmp; + __asm vec4_dot tmp, v, v; + __asm float_rsq tmp, tmp; + __asm vec4_multiply __retVal.xyz, v, tmp; +} + + + +// +// 8.3 Common Functions +// + + +//// abs + +float abs(const float a) +{ + __asm vec4_abs __retVal, a; +} + +vec2 abs(const vec2 a) +{ + __asm vec4_abs __retVal.xy, a; +} + +vec3 abs(const vec3 a) +{ + __asm vec4_abs __retVal.xyz, a; +} + +vec4 abs(const vec4 a) +{ + __asm vec4_abs __retVal, a; +} + + +//// sign + +float sign(const float x) +{ + float p, n; + __asm vec4_sgt p, x, 0.0; // p = (x > 0) + __asm vec4_sgt n, 0.0, x; // n = (x < 0) + __asm vec4_subtract __retVal, p, n; // sign = p - n +} + +vec2 sign(const vec2 v) +{ + vec2 p, n; + __asm vec4_sgt p.xy, v, 0.0; + __asm vec4_sgt n.xy, 0.0, v; + __asm vec4_subtract __retVal.xy, p, n; +} + +vec3 sign(const vec3 v) +{ + vec3 p, n; + __asm vec4_sgt p.xyz, v, 0.0; + __asm vec4_sgt n.xyz, 0.0, v; + __asm vec4_subtract __retVal.xyz, p, n; +} + +vec4 sign(const vec4 v) +{ + vec4 p, n; + __asm vec4_sgt p, v, 0.0; + __asm vec4_sgt n, 0.0, v; + __asm vec4_subtract __retVal, p, n; +} + + +//// floor + +float floor(const float a) +{ + __asm vec4_floor __retVal, a; +} + +vec2 floor(const vec2 a) +{ + __asm vec4_floor __retVal.xy, a; +} + +vec3 floor(const vec3 a) +{ + __asm vec4_floor __retVal.xyz, a; +} + +vec4 floor(const vec4 a) +{ + __asm vec4_floor __retVal, a; +} + + +//// ceil + +float ceil(const float a) +{ + // XXX this could be improved + float b = -a; + __asm vec4_floor b, b; + __retVal = -b; +} + +vec2 ceil(const vec2 a) +{ + vec2 b = -a; + __asm vec4_floor b, b; + __retVal.xy = -b; +} + +vec3 ceil(const vec3 a) +{ + vec3 b = -a; + __asm vec4_floor b, b; + __retVal.xyz = -b; +} + +vec4 ceil(const vec4 a) +{ + vec4 b = -a; + __asm vec4_floor b, b; + __retVal = -b; +} + + +//// fract + +float fract(const float a) +{ + __asm vec4_frac __retVal, a; +} + +vec2 fract(const vec2 a) +{ + __asm vec4_frac __retVal.xy, a; +} + +vec3 fract(const vec3 a) +{ + __asm vec4_frac __retVal.xyz, a; +} + +vec4 fract(const vec4 a) +{ + __asm vec4_frac __retVal, a; +} + + +//// mod (very untested!) + +float mod(const float a, const float b) +{ + float oneOverB; + __asm float_rcp oneOverB, b; + __retVal = a - b * floor(a * oneOverB); +} + +vec2 mod(const vec2 a, const float b) +{ + float oneOverB; + __asm float_rcp oneOverB, b; + __retVal.xy = a - b * floor(a * oneOverB); +} + +vec3 mod(const vec3 a, const float b) +{ + float oneOverB; + __asm float_rcp oneOverB, b; + __retVal.xyz = a - b * floor(a * oneOverB); +} + +vec4 mod(const vec4 a, const float b) +{ + float oneOverB; + __asm float_rcp oneOverB, b; + __retVal = a - b * floor(a * oneOverB); +} + +vec2 mod(const vec2 a, const vec2 b) +{ + vec2 oneOverB; + __asm float_rcp oneOverB.x, b.x; + __asm float_rcp oneOverB.y, b.y; + __retVal = a - b * floor(a * oneOverB); +} + +vec3 mod(const vec3 a, const vec3 b) +{ + vec3 oneOverB; + __asm float_rcp oneOverB.x, b.x; + __asm float_rcp oneOverB.y, b.y; + __asm float_rcp oneOverB.z, b.z; + __retVal = a - b * floor(a * oneOverB); +} + +vec4 mod(const vec4 a, const vec4 b) +{ + vec4 oneOverB; + __asm float_rcp oneOverB.x, b.x; + __asm float_rcp oneOverB.y, b.y; + __asm float_rcp oneOverB.z, b.z; + __asm float_rcp oneOverB.w, b.w; + __retVal = a - b * floor(a * oneOverB); +} + + +//// min + +float min(const float a, const float b) +{ + __asm vec4_min __retVal, a, b; +} + +vec2 min(const vec2 a, const vec2 b) +{ + __asm vec4_min __retVal.xy, a.xy, b.xy; +} + +vec3 min(const vec3 a, const vec3 b) +{ + __asm vec4_min __retVal.xyz, a.xyz, b.xyz; +} + +vec4 min(const vec4 a, const vec4 b) +{ + __asm vec4_min __retVal, a, b; +} + +vec2 min(const vec2 a, const float b) +{ + __asm vec4_min __retVal, a.xy, b; +} + +vec3 min(const vec3 a, const float b) +{ + __asm vec4_min __retVal, a.xyz, b; +} + +vec4 min(const vec4 a, const float b) +{ + __asm vec4_min __retVal, a, b; +} + + +//// max + +float max(const float a, const float b) +{ + __asm vec4_max __retVal, a, b; +} + +vec2 max(const vec2 a, const vec2 b) +{ + __asm vec4_max __retVal.xy, a.xy, b.xy; +} + +vec3 max(const vec3 a, const vec3 b) +{ + __asm vec4_max __retVal.xyz, a.xyz, b.xyz; +} + +vec4 max(const vec4 a, const vec4 b) +{ + __asm vec4_max __retVal, a, b; +} + +vec2 max(const vec2 a, const float b) +{ + __asm vec4_max __retVal, a.xy, b; +} + +vec3 max(const vec3 a, const float b) +{ + __asm vec4_max __retVal, a.xyz, b; +} + +vec4 max(const vec4 a, const float b) +{ + __asm vec4_max __retVal, a, b; +} + + +//// clamp + +float clamp(const float val, const float minVal, const float maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + +vec2 clamp(const vec2 val, const float minVal, const float maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + +vec3 clamp(const vec3 val, const float minVal, const float maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + +vec4 clamp(const vec4 val, const float minVal, const float maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + +vec2 clamp(const vec2 val, const vec2 minVal, const vec2 maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + +vec3 clamp(const vec3 val, const vec3 minVal, const vec3 maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + +vec4 clamp(const vec4 val, const vec4 minVal, const vec4 maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + + +//// mix + +float mix(const float x, const float y, const float a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + +vec2 mix(const vec2 x, const vec2 y, const float a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + +vec3 mix(const vec3 x, const vec3 y, const float a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + +vec4 mix(const vec4 x, const vec4 y, const float a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + +vec2 mix(const vec2 x, const vec2 y, const vec2 a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + +vec3 mix(const vec3 x, const vec3 y, const vec3 a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + +vec4 mix(const vec4 x, const vec4 y, const vec4 a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + + +//// step + +float step(const float edge, const float x) +{ + __asm vec4_sge __retVal, x, edge; +} + +vec2 step(const vec2 edge, const vec2 x) +{ + __asm vec4_sge __retVal.xy, x, edge; +} + +vec3 step(const vec3 edge, const vec3 x) +{ + __asm vec4_sge __retVal.xyz, x, edge; +} + +vec4 step(const vec4 edge, const vec4 x) +{ + __asm vec4_sge __retVal, x, edge; +} + +vec2 step(const float edge, const vec2 v) +{ + __asm vec4_sge __retVal.xy, v, edge; +} + +vec3 step(const float edge, const vec3 v) +{ + __asm vec4_sge __retVal.xyz, v, edge; +} + +vec4 step(const float edge, const vec4 v) +{ + __asm vec4_sge __retVal, v, edge; +} + + +//// smoothstep + +float smoothstep(const float edge0, const float edge1, const float x) +{ + float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + +vec2 smoothstep(const vec2 edge0, const vec2 edge1, const vec2 v) +{ + vec2 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + +vec3 smoothstep(const vec3 edge0, const vec3 edge1, const vec3 v) +{ + vec3 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + +vec4 smoothstep(const vec4 edge0, const vec4 edge1, const vec4 v) +{ + vec4 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + +vec2 smoothstep(const float edge0, const float edge1, const vec2 v) +{ + vec2 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + +vec3 smoothstep(const float edge0, const float edge1, const vec3 v) +{ + vec3 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + +vec4 smoothstep(const float edge0, const float edge1, const vec4 v) +{ + vec4 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + + + +// +// 8.4 Geometric Functions +// + + +//// length + +float length(const float x) +{ + return abs(x); +} + +float length(const vec2 v) +{ + float r; + const float p = dot(v, v); // p = v.x * v.x + v.y * v.y + __asm float_rsq r, p; // r = 1 / sqrt(p) + __retVal = p * r; // p * r = sqrt(p); +} + +float length(const vec3 v) +{ + float r; + const float p = dot(v, v); // p = v.x * v.x + v.y * v.y + v.z * v.z + __asm float_rsq r, p; // r = 1 / sqrt(p) + __retVal = p * r; // p * r = sqrt(p); +} + +float length(const vec4 v) +{ + float r; + const float p = dot(v, v); // p = v.x * v.x + v.y * v.y + ... + __asm float_rsq r, p; // r = 1 / sqrt(p) + __retVal = p * r; // p * r = sqrt(p); +} + + +//// distance + +float distance(const float x, const float y) +{ + const float d = x - y; + __retVal = length(d); +} + +float distance(const vec2 v, const vec2 u) +{ + const vec2 d2 = v - u; + __retVal = length(d2); +} + +float distance(const vec3 v, const vec3 u) +{ + const vec3 d3 = v - u; + __retVal = length(d3); +} + +float distance(const vec4 v, const vec4 u) +{ + const vec4 d4 = v - u; + __retVal = length(d4); +} + + +//// cross + +vec3 cross(const vec3 v, const vec3 u) +{ + __asm vec3_cross __retVal.xyz, v, u; +} + + +//// faceforward + +float faceforward(const float N, const float I, const float Nref) +{ + // this could probably be done better + const float d = dot(Nref, I); + float s; + __asm vec4_sgt s, 0.0, d; // s = (0.0 > d) ? 1 : 0 + return mix(-N, N, s); +} + +vec2 faceforward(const vec2 N, const vec2 I, const vec2 Nref) +{ + // this could probably be done better + const float d = dot(Nref, I); + float s; + __asm vec4_sgt s, 0.0, d; // s = (0.0 > d) ? 1 : 0 + return mix(-N, N, s); +} + +vec3 faceforward(const vec3 N, const vec3 I, const vec3 Nref) +{ + // this could probably be done better + const float d = dot(Nref, I); + float s; + __asm vec4_sgt s, 0.0, d; // s = (0.0 > d) ? 1 : 0 + return mix(-N, N, s); +} + +vec4 faceforward(const vec4 N, const vec4 I, const vec4 Nref) +{ + // this could probably be done better + const float d = dot(Nref, I); + float s; + __asm vec4_sgt s, 0.0, d; // s = (0.0 > d) ? 1 : 0 + return mix(-N, N, s); +} + + +//// reflect + +float reflect(const float I, const float N) +{ + return I - 2.0 * dot(N, I) * N; +} + +vec2 reflect(const vec2 I, const vec2 N) +{ + return I - 2.0 * dot(N, I) * N; +} + +vec3 reflect(const vec3 I, const vec3 N) +{ + return I - 2.0 * dot(N, I) * N; +} + +vec4 reflect(const vec4 I, const vec4 N) +{ + return I - 2.0 * dot(N, I) * N; +} + +//// refract + +float refract(const float I, const float N, const float eta) +{ + float n_dot_i = dot(N, I); + float k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i); + float retval; + if (k < 0.0) + retval = 0.0; + else + retval = eta * I - (eta * n_dot_i + sqrt(k)) * N; + return retval; +} + +vec2 refract(const vec2 I, const vec2 N, const float eta) +{ + float n_dot_i = dot(N, I); + float k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i); + vec2 retval; + if (k < 0.0) + retval = vec2(0.0); + else + retval = eta * I - (eta * n_dot_i + sqrt(k)) * N; + return retval; +} + +vec3 refract(const vec3 I, const vec3 N, const float eta) +{ + float n_dot_i = dot(N, I); + float k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i); + vec3 retval; + if (k < 0.0) + retval = vec3(0.0); + else + retval = eta * I - (eta * n_dot_i + sqrt(k)) * N; + return retval; +} + +vec4 refract(const vec4 I, const vec4 N, const float eta) +{ + float n_dot_i = dot(N, I); + float k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i); + vec4 retval; + if (k < 0.0) + retval = vec4(0.0); + else + retval = eta * I - (eta * n_dot_i + sqrt(k)) * N; + return retval; +} + + + + +// +// 8.5 Matrix Functions +// + +mat2 matrixCompMult (mat2 m, mat2 n) { + return mat2 (m[0] * n[0], m[1] * n[1]); +} + +mat3 matrixCompMult (mat3 m, mat3 n) { + return mat3 (m[0] * n[0], m[1] * n[1], m[2] * n[2]); +} + +mat4 matrixCompMult (mat4 m, mat4 n) { + return mat4 (m[0] * n[0], m[1] * n[1], m[2] * n[2], m[3] * n[3]); +} + + + + +// +// 8.6 Vector Relational Functions +// + +//// lessThan + +bvec2 lessThan(const vec2 u, const vec2 v) +{ + __asm vec4_slt __retVal.xy, u, v; +} + +bvec3 lessThan(const vec3 u, const vec3 v) +{ + __asm vec4_slt __retVal.xyz, u, v; +} + +bvec4 lessThan(const vec4 u, const vec4 v) +{ + __asm vec4_slt __retVal, u, v; +} + +bvec2 lessThan(const ivec2 u, const ivec2 v) +{ + __asm vec4_slt __retVal.xy, u, v; +} + +bvec3 lessThan(const ivec3 u, const ivec3 v) +{ + __asm vec4_slt __retVal.xyz, u, v; +} + +bvec4 lessThan(const ivec4 u, const ivec4 v) +{ + __asm vec4_slt __retVal, u, v; +} + + +//// lessThanEqual + +bvec2 lessThanEqual(const vec2 u, const vec2 v) +{ + __asm vec4_sle __retVal.xy, u, v; +} + +bvec3 lessThanEqual(const vec3 u, const vec3 v) +{ + __asm vec4_sle __retVal.xyz, u, v; +} + +bvec4 lessThanEqual(const vec4 u, const vec4 v) +{ + __asm vec4_sle __retVal, u, v; +} + +bvec2 lessThanEqual(const ivec2 u, const ivec2 v) +{ + __asm vec4_sle __retVal.xy, u, v; +} + +bvec3 lessThanEqual(const ivec3 u, const ivec3 v) +{ + __asm vec4_sle __retVal.xyz, u, v; +} + +bvec4 lessThanEqual(const ivec4 u, const ivec4 v) +{ + __asm vec4_sle __retVal, u, v; +} + + +//// greaterThan + +bvec2 greaterThan(const vec2 u, const vec2 v) +{ + __asm vec4_sgt __retVal.xy, u, v; +} + +bvec3 greaterThan(const vec3 u, const vec3 v) +{ + __asm vec4_sgt __retVal.xyz, u, v; +} + +bvec4 greaterThan(const vec4 u, const vec4 v) +{ + __asm vec4_sgt __retVal, u, v; +} + +bvec2 greaterThan(const ivec2 u, const ivec2 v) +{ + __asm vec4_sgt __retVal.xy, u.xy, v.xy; +} + +bvec3 greaterThan(const ivec3 u, const ivec3 v) +{ + __asm vec4_sgt __retVal.xyz, u, v; +} + +bvec4 greaterThan(const ivec4 u, const ivec4 v) +{ + __asm vec4_sgt __retVal, u, v; +} + + +//// greaterThanEqual + +bvec2 greaterThanEqual(const vec2 u, const vec2 v) +{ + __asm vec4_sge __retVal.xy, u, v; +} + +bvec3 greaterThanEqual(const vec3 u, const vec3 v) +{ + __asm vec4_sge __retVal.xyz, u, v; +} + +bvec4 greaterThanEqual(const vec4 u, const vec4 v) +{ + __asm vec4_sge __retVal, u, v; +} + +bvec2 greaterThanEqual(const ivec2 u, const ivec2 v) +{ + __asm vec4_sge __retVal.xy, u, v; +} + +bvec3 greaterThanEqual(const ivec3 u, const ivec3 v) +{ + __asm vec4_sge __retVal.xyz, u, v; +} + +bvec4 greaterThanEqual(const ivec4 u, const ivec4 v) +{ + __asm vec4_sge __retVal, u, v; +} + + +//// equal + +bvec2 equal(const vec2 u, const vec2 v) +{ + __asm vec4_seq __retVal.xy, u, v; +} + +bvec3 equal(const vec3 u, const vec3 v) +{ + __asm vec4_seq __retVal.xyz, u, v; +} + +bvec4 equal(const vec4 u, const vec4 v) +{ + __asm vec4_seq __retVal, u, v; +} + +bvec2 equal(const ivec2 u, const ivec2 v) +{ + __asm vec4_seq __retVal.xy, u, v; +} + +bvec3 equal(const ivec3 u, const ivec3 v) +{ + __asm vec4_seq __retVal.xyz, u, v; +} + +bvec4 equal(const ivec4 u, const ivec4 v) +{ + __asm vec4_seq __retVal, u, v; +} + +bvec2 equal(const bvec2 u, const bvec2 v) +{ + __asm vec4_seq __retVal.xy, u, v; +} + +bvec3 equal(const bvec3 u, const bvec3 v) +{ + __asm vec4_seq __retVal.xyz, u, v; +} + +bvec4 equal(const bvec4 u, const bvec4 v) +{ + __asm vec4_seq __retVal, u, v; +} + + + + +//// notEqual + +bvec2 notEqual(const vec2 u, const vec2 v) +{ + __asm vec4_sne __retVal.xy, u, v; +} + +bvec3 notEqual(const vec3 u, const vec3 v) +{ + __asm vec4_sne __retVal.xyz, u, v; +} + +bvec4 notEqual(const vec4 u, const vec4 v) +{ + __asm vec4_sne __retVal, u, v; +} + +bvec2 notEqual(const ivec2 u, const ivec2 v) +{ + __asm vec4_sne __retVal.xy, u, v; +} + +bvec3 notEqual(const ivec3 u, const ivec3 v) +{ + __asm vec4_sne __retVal.xyz, u, v; +} + +bvec4 notEqual(const ivec4 u, const ivec4 v) +{ + __asm vec4_sne __retVal, u, v; +} + +bvec2 notEqual(const bvec2 u, const bvec2 v) +{ + __asm vec4_sne __retVal.xy, u, v; +} + +bvec3 notEqual(const bvec3 u, const bvec3 v) +{ + __asm vec4_sne __retVal.xyz, u, v; +} + +bvec4 notEqual(const bvec4 u, const bvec4 v) +{ + __asm vec4_sne __retVal, u, v; +} + + + +//// any + +bool any(const bvec2 v) +{ + float sum; + __asm vec4_add sum.x, v.x, v.y; + __asm vec4_sne __retVal.x, sum.x, 0.0; +} + +bool any(const bvec3 v) +{ + float sum; + __asm vec4_add sum.x, v.x, v.y; + __asm vec4_add sum.x, sum.x, v.z; + __asm vec4_sne __retVal.x, sum.x, 0.0; +} + +bool any(const bvec4 v) +{ + float sum; + __asm vec4_add sum.x, v.x, v.y; + __asm vec4_add sum.x, sum.x, v.z; + __asm vec4_add sum.x, sum.x, v.w; + __asm vec4_sne __retVal.x, sum.x, 0.0; +} + + +//// all + +bool all (const bvec2 v) +{ + float prod; + __asm vec4_multiply prod, v.x, v.y; + __asm vec4_sne __retVal, prod, 0.0; +} + +bool all (const bvec3 v) +{ + float prod; + __asm vec4_multiply prod, v.x, v.y; + __asm vec4_multiply prod, prod, v.z; + __asm vec4_sne __retVal, prod, 0.0; +} + +bool all (const bvec4 v) +{ + float prod; + __asm vec4_multiply prod, v.x, v.y; + __asm vec4_multiply prod, prod, v.z; + __asm vec4_multiply prod, prod, v.w; + __asm vec4_sne __retVal, prod, 0.0; +} + + + +//// not + +bvec2 not (const bvec2 v) +{ + __asm vec4_seq __retVal.xy, v, 0.0; +} + +bvec3 not (const bvec3 v) +{ + __asm vec4_seq __retVal.xyz, v, 0.0; +} + +bvec4 not (const bvec4 v) +{ + __asm vec4_seq __retVal, v, 0.0; +} + + + +//// Texture Lookup Functions (for both fragment and vertex shaders) + +vec4 texture1D(const sampler1D sampler, const float coord) +{ + __asm vec4_tex_1d __retVal, sampler, coord; +} + +vec4 texture1DProj(const sampler1D sampler, const vec2 coord) +{ + // need to swizzle .y into .w + __asm vec4_tex_1d_proj __retVal, sampler, coord.xyyy; +} + +vec4 texture1DProj(const sampler1D sampler, const vec4 coord) +{ + __asm vec4_tex_1d_proj __retVal, sampler, coord; +} + + +vec4 texture2D(const sampler2D sampler, const vec2 coord) +{ + __asm vec4_tex_2d __retVal, sampler, coord; +} + +vec4 texture2DProj(const sampler2D sampler, const vec3 coord) +{ + // need to swizzle 'z' into 'w'. + __asm vec4_tex_2d_proj __retVal, sampler, coord.xyzz; +} + +vec4 texture2DProj(const sampler2D sampler, const vec4 coord) +{ + __asm vec4_tex_2d_proj __retVal, sampler, coord; +} + + +vec4 texture3D(const sampler3D sampler, const vec3 coord) +{ + __asm vec4_tex_3d __retVal, sampler, coord; +} + +vec4 texture3DProj(const sampler3D sampler, const vec4 coord) +{ + __asm vec4_tex_3d_proj __retVal, sampler, coord; +} + + +vec4 textureCube(const samplerCube sampler, const vec3 coord) +{ + __asm vec4_tex_cube __retVal, sampler, coord; +} + + + +vec4 shadow1D(const sampler1DShadow sampler, const vec3 coord) +{ + __asm vec4_tex_1d_shadow __retVal, sampler, coord; +} + +vec4 shadow1DProj(const sampler1DShadow sampler, const vec4 coord) +{ + // .s and .p will be divided by .q + __asm vec4_tex_1d_proj_shadow __retVal, sampler, coord; +} + +vec4 shadow2D(const sampler2DShadow sampler, const vec3 coord) +{ + __asm vec4_tex_2d_shadow __retVal, sampler, coord; +} + +vec4 shadow2DProj(const sampler2DShadow sampler, const vec4 coord) +{ + // .s, .t and .p will be divided by .q + __asm vec4_tex_2d_proj_shadow __retVal, sampler, coord; +} + + +//// GL_ARB_texture_rectangle: +vec4 texture2DRect(const sampler2DRect sampler, const vec2 coord) +{ + __asm vec4_tex_rect __retVal, sampler, coord; +} + +vec4 texture2DRectProj(const sampler2DRect sampler, const vec3 coord) +{ + // need to swizzle .y into .w + __asm vec4_tex_rect_proj __retVal, sampler, coord.xyzz; +} + +vec4 texture2DRectProj(const sampler2DRect sampler, const vec4 coord) +{ + __asm vec4_tex_rect_proj __retVal, sampler, ccoord; +} + +vec4 shadow2DRect(const sampler2DRectShadow sampler, const vec3 coord) +{ + __asm vec4_tex_rect_shadow __retVal, sampler, coord; +} + +vec4 shadow2DRectProj(const sampler2DRectShadow sampler, const vec4 coord) +{ + __asm vec4_tex_rect_proj_shadow __retVal, sampler, coord; +} + + + +//// GL_EXT_texture_array +vec4 texture1DArray(const sampler1DArray sampler, const vec2 coord) +{ + __asm vec4_tex_1d_array __retVal, sampler, coord; +} + +vec4 texture2DArray(const sampler2DArray sampler, const vec3 coord) +{ + __asm vec4_tex_2d_array __retVal, sampler, coord; +} + + +// +// 8.9 Noise Functions +// +// AUTHOR: Stefan Gustavson (stegu@itn.liu.se), Nov 26, 2005 +// + +float noise1(const float x) +{ + __asm float_noise1 __retVal, x; +} + + +float noise1(const vec2 x) +{ + __asm float_noise2 __retVal, x; +} + +float noise1(const vec3 x) +{ + __asm float_noise3 __retVal, x; +} + +float noise1(const vec4 x) +{ + __asm float_noise4 __retVal, x; +} + +vec2 noise2(const float x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + 19.34); +} + +vec2 noise2(const vec2 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec2(19.34, 7.66)); +} + +vec2 noise2(const vec3 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec3(19.34, 7.66, 3.23)); +} + +vec2 noise2(const vec4 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec4(19.34, 7.66, 3.23, 2.77)); +} + +vec3 noise3(const float x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + 19.34); + __retVal.z = noise1(x + 5.47); +} + +vec3 noise3(const vec2 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec2(19.34, 7.66)); + __retVal.z = noise1(x + vec2(5.47, 17.85)); +} + +vec3 noise3(const vec3 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec3(19.34, 7.66, 3.23)); + __retVal.z = noise1(x + vec3(5.47, 17.85, 11.04)); +} + +vec3 noise3(const vec4 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec4(19.34, 7.66, 3.23, 2.77)); + __retVal.z = noise1(x + vec4(5.47, 17.85, 11.04, 13.19)); +} + +vec4 noise4(const float x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + 19.34); + __retVal.z = noise1(x + 5.47); + __retVal.w = noise1(x + 23.54); +} + +vec4 noise4(const vec2 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec2 (19.34, 7.66)); + __retVal.z = noise1(x + vec2 (5.47, 17.85)); + __retVal.w = noise1(x + vec2 (23.54, 29.11)); +} + +vec4 noise4(const vec3 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec3(19.34, 7.66, 3.23)); + __retVal.z = noise1(x + vec3(5.47, 17.85, 11.04)); + __retVal.w = noise1(x + vec3(23.54, 29.11, 31.91)); +} + +vec4 noise4(const vec4 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec4(19.34, 7.66, 3.23, 2.77)); + __retVal.z = noise1(x + vec4(5.47, 17.85, 11.04, 13.19)); + __retVal.w = noise1(x + vec4(23.54, 29.11, 31.91, 37.48)); +} diff --git a/src/mesa/slang/library/slang_core.gc b/src/mesa/slang/library/slang_core.gc new file mode 100644 index 0000000000..0a0d15903b --- /dev/null +++ b/src/mesa/slang/library/slang_core.gc @@ -0,0 +1,2619 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// This file defines nearly all constructors and operators for built-in data +// types, using extended language syntax. In general, compiler treats +// constructors and operators as ordinary functions with some exceptions. +// For example, the language does not allow functions to be called in +// constant expressions - here the exception is made to allow it. +// +// Each implementation provides its own version of this file. Each +// implementation can define the required set of operators and constructors +// in its own fashion. +// +// The extended language syntax is only present when compiling this file. +// It is implicitly included at the very beginning of the compiled shader, +// so no built-in functions can be used. +// +// To communicate with the implementation, a special extended "__asm" keyword +// is used, followed by an instruction name (any valid identifier), a +// destination variable identifier and a list of zero or more source +// variable identifiers. +// +// A variable identifier is a variable name declared earlier in the code +// (as a function parameter, local or global variable). +// +// An instruction name designates an instruction that must be exported +// by the implementation. Each instruction receives data from source +// variable identifiers and returns data in the destination variable +// identifier. +// +// It is up to the implementation how to define a particular operator +// or constructor. If it is expected to being used rarely, it can be +// defined in terms of other operators and constructors, +// for example: +// +// ivec2 __operator + (const ivec2 x, const ivec2 y) { +// return ivec2 (x[0] + y[0], x[1] + y[1]); +// } +// +// If a particular operator or constructor is expected to be used very +// often or is an atomic operation (that is, an operation that cannot be +// expressed in terms of other operations or would create a dependency +// cycle) it must be defined using one or more __asm constructs. +// +// Each implementation must define constructors for all scalar types +// (bool, float, int). There are 9 scalar-to-scalar constructors +// (including identity constructors). However, since the language +// introduces special constructors (like matrix constructor with a single +// scalar value), implementations must also implement these cases. +// The compiler provides the following algorithm when resolving a constructor: +// - try to find a constructor with a prototype matching ours, +// - if no constructor is found and this is a scalar-to-scalar constructor, +// raise an error, +// - if a constructor is found, execute it and return, +// - count the size of the constructor parameter list - if it is less than +// the size of our constructor's type, raise an error, +// - for each parameter in the list do a recursive constructor matching for +// appropriate scalar fields in the constructed variable, +// +// Each implementation must also define a set of operators that deal with +// built-in data types. +// There are four kinds of operators: +// 1) Operators that are implemented only by the compiler: "()" (function +// call), "," (sequence) and "?:" (selection). +// 2) Operators that are implemented by the compiler by expressing it in +// terms of other operators: +// - "." (field selection) - translated to subscript access, +// - "&&" (logical and) - translated to " ? : +// false", +// - "||" (logical or) - translated to " ? true : ", +// 3) Operators that can be defined by the implementation and if the required +// prototype is not found, standard behaviour is used: +// - "==", "!=", "=" (equality, assignment) - compare or assign +// matching fields one-by-one; +// note that at least operators for scalar data types must be defined +// by the implementation to get it work, +// 4) All other operators not mentioned above. If no required prototype is +// found, an error is raised. An implementation must follow the language +// specification to provide all valid operator prototypes. +// + + + +//// Basic, scalar constructors/casts + +int __constructor(const float f) +{ + __asm vec4_to_ivec4 __retVal, f; +} + +int __constructor(const bool b) +{ + __retVal = b; +} + +int __constructor(const int i) +{ + __retVal = i; +} + +bool __constructor(const int i) +{ + __asm vec4_sne __retVal, i, 0.0; +} + +bool __constructor(const float f) +{ + __asm vec4_sne __retVal, f, 0.0; +} + +bool __constructor(const bool b) +{ + __retVal = b; +} + +float __constructor(const int i) +{ + __asm ivec4_to_vec4 __retVal, i; +} + +float __constructor(const bool b) +{ + __asm ivec4_to_vec4 __retVal, b; +} + +float __constructor(const float f) +{ + __retVal = f; +} + + +//// vec2 constructors + +vec2 __constructor(const float x, const float y) +{ + __retVal.x = x; + __retVal.y = y; +} + +vec2 __constructor(const float f) +{ + __asm vec4_move __retVal.xy, f; +} + +vec2 __constructor(const int i) +{ + __asm ivec4_to_vec4 __retVal.xy, i; +} + +vec2 __constructor(const bool b) +{ + __asm ivec4_to_vec4 __retVal.xy, b; +} + +vec2 __constructor(const bvec2 b) +{ +// __retVal = b; + __asm ivec4_to_vec4 __retVal.xy, b; +} + +vec2 __constructor(const vec3 v) +{ + __asm vec4_move __retVal.xy, v.xy; +} + +vec2 __constructor(const vec4 v) +{ + __asm vec4_move __retVal.xy, v.xy; +} + + +//// vec3 constructors + +vec3 __constructor(const float x, const float y, const float z) +{ + __retVal.x = x; + __retVal.y = y; + __retVal.z = z; +} + +vec3 __constructor(const float f) +{ + // Note: this could be "__retVal.xyz = f" but that's an illegal assignment + __asm vec4_move __retVal.xyz, f; +} + +vec3 __constructor(const int i) +{ + __asm ivec4_to_vec4 __retVal.xyz, i; +} + +vec3 __constructor(const bool b) +{ + __asm ivec4_to_vec4 __retVal.xyz, b; +} + +vec3 __constructor(const bvec3 b) +{ + __asm ivec4_to_vec4 __retVal.xyz, b; +} + +vec3 __constructor(const vec4 v) +{ + __asm vec4_move __retVal.xyz, v; +} + + +//// vec4 constructors + +vec4 __constructor(const float x, const float y, const float z, const float w) +{ + __retVal.x = x; + __retVal.y = y; + __retVal.z = z; + __retVal.w = w; +} + +vec4 __constructor(const float f) +{ + // Note: this could be "__retVal = f" but that's an illegal assignment + __asm vec4_move __retVal, f; +} + +vec4 __constructor(const int i) +{ + __asm ivec4_to_vec4 __retVal, i; +} + +vec4 __constructor(const bool b) +{ + __asm ivec4_to_vec4 __retVal, b; +} + +vec4 __constructor(const bvec4 b) +{ + __asm ivec4_to_vec4 __retVal, b; +} + +vec4 __constructor(const ivec4 i) +{ + __asm ivec4_to_vec4 __retVal, i; +} + +vec4 __constructor(const vec3 v3, const float f) +{ + // XXX this constructor shouldn't be needed anymore + __retVal.xyz = v3; + __retVal.w = f; +} + +vec4 __constructor(const vec2 v2, const float f1, const float f2) +{ + // XXX this constructor shouldn't be needed anymore + __retVal.xy = v2; + __retVal.z = f1; + __retVal.w = f2; +} + + +//// ivec2 constructors + +ivec2 __constructor(const int i, const int j) +{ + __retVal.x = i; + __retVal.y = j; +} + +ivec2 __constructor(const int i) +{ + __asm vec4_move __retVal.xy, i; +} + +ivec2 __constructor(const float f) +{ + __asm vec4_to_ivec4 __retVal.xy, f; +} + +ivec2 __constructor(const bool b) +{ + __asm vec4_to_ivec4 __retVal.xy, b; +} + + +//// ivec3 constructors + +ivec3 __constructor(const int i, const int j, const int k) +{ + __retVal.x = i; + __retVal.y = j; + __retVal.z = k; +} + +ivec3 __constructor(const int i) +{ + __asm vec4_move __retVal.xyz, i; +} + +ivec3 __constructor(const float f) +{ + __asm vec4_to_ivec4 __retVal.xyz, f; +} + +ivec3 __constructor(const bool b) +{ + __asm vec4_move __retVal.xyz, b; +} + + +//// ivec4 constructors + +ivec4 __constructor(const int x, const int y, const int z, const int w) +{ + __retVal.x = x; + __retVal.y = y; + __retVal.z = z; + __retVal.w = w; +} + +ivec4 __constructor(const int i) +{ + __asm vec4_move __retVal, i; +} + +ivec4 __constructor(const float f) +{ + __asm vec4_to_ivec4 __retVal, f; +} + +ivec4 __constructor(const bool b) +{ + __asm vec4_to_ivec4 __retVal, b; +} + + +//// bvec2 constructors + +bvec2 __constructor(const bool b1, const bool b2) +{ + __retVal.x = b1; + __retVal.y = b2; +} + +bvec2 __constructor(const int i1, const int i2) +{ + __asm vec4_sne __retVal.x, i1, 0.0; + __asm vec4_sne __retVal.y, i2, 0.0; +} + + +bvec2 __constructor(const bool b) +{ + __asm vec4_move __retVal.xy, b; +} + +bvec2 __constructor(const float f) +{ + __asm vec4_sne __retVal.xy, f, 0.0; +} + +bvec2 __constructor(const int i) +{ + __asm vec4_sne __retVal.xy, i, 0.0; +} + +bvec2 __constructor(const vec2 v) +{ + __asm vec4_sne __retVal.xy, v, 0.0; +} + +bvec2 __constructor(const ivec2 v) +{ + __asm vec4_sne __retVal.xy, v, 0.0; +} + + + +//// bvec3 constructors + +bvec3 __constructor(const bool b1, const bool b2, const bool b3) +{ + __retVal.x = b1; + __retVal.y = b2; + __retVal.z = b3; +} + +bvec3 __constructor(const float f1, const float f2, const float f3) +{ + __asm vec4_sne __retVal.x, f1, 0.0; + __asm vec4_sne __retVal.y, f2, 0.0; + __asm vec4_sne __retVal.z, f3, 0.0; +} + +bvec3 __constructor(const bool b) +{ + __asm vec4_move __retVal.xyz, b; +} + +bvec3 __constructor(const float f) +{ + __asm vec4_sne __retVal.xyz, f, 0.0; +} + +bvec3 __constructor(const int i) +{ + __asm vec4_sne __retVal.xyz, i, 0.0; +} + +bvec3 __constructor(const vec3 v) +{ + __asm vec4_sne __retVal.xyz, v, 0.0; +} + +bvec3 __constructor(const ivec3 v) +{ + __asm vec4_sne __retVal.xyz, v, 0.0; +} + + + +//// bvec4 constructors + +bvec4 __constructor(const bool b1, const bool b2, const bool b3, const bool b4) +{ + __retVal.x = b1; + __retVal.y = b2; + __retVal.z = b3; + __retVal.w = b4; +} + +bvec4 __constructor(const float f1, const float f2, const float f3, const float f4) +{ + const float zero = 0.0; + __asm vec4_sne __retVal.x, f1, zero; + __asm vec4_sne __retVal.y, f2, zero; + __asm vec4_sne __retVal.z, f3, zero; + __asm vec4_sne __retVal.w, f4, zero; +} + +bvec4 __constructor(const bool b) +{ + __asm vec4_move __retVal.xyzw, b; +} + +bvec4 __constructor(const float f) +{ + __asm vec4_sne __retVal.xyzw, f, 0.0; +} + +bvec4 __constructor(const int i) +{ + __asm vec4_sne __retVal.xyzw, i, 0.0; +} + +bvec4 __constructor(const vec4 v) +{ + __asm vec4_sne __retVal.xyzw, v, 0.0; +} + +bvec4 __constructor(const ivec4 v) +{ + __asm vec4_sne __retVal.xyzw, v, 0.0; +} + + + +//// mat2 constructors + +mat2 __constructor(const float m00, const float m10, + const float m01, const float m11) +{ + __retVal[0].x = m00; + __retVal[0].y = m10; + __retVal[1].x = m01; + __retVal[1].y = m11; +} + +mat2 __constructor(const float f) +{ + __retVal[0].x = f; + __retVal[0].y = 0.0; + __retVal[1].x = 0.0; + __retVal[1].y = f; +} + +mat2 __constructor(const int i) +{ + return mat2(float(i)); +} + +mat2 __constructor(const bool b) +{ + return mat2(float(b)); +} + +mat2 __constructor(const vec2 c0, const vec2 c1) +{ + __retVal[0] = c0; + __retVal[1] = c1; +} + + +//// mat3 constructors + +mat3 __constructor(const float m00, const float m10, const float m20, + const float m01, const float m11, const float m21, + const float m02, const float m12, const float m22) +{ + __retVal[0].x = m00; + __retVal[0].y = m10; + __retVal[0].z = m20; + __retVal[1].x = m01; + __retVal[1].y = m11; + __retVal[1].z = m21; + __retVal[2].x = m02; + __retVal[2].y = m12; + __retVal[2].z = m22; +} + +mat3 __constructor(const float f) +{ + vec2 v = vec2(f, 0.0); + __retVal[0] = v.xyy; + __retVal[1] = v.yxy; + __retVal[2] = v.yyx; +} + +mat3 __constructor(const int i) +{ + return mat3(float(i)); +} + +mat3 __constructor(const bool b) +{ + return mat3(float(b)); +} + +mat3 __constructor(const vec3 c0, const vec3 c1, const vec3 c2) +{ + __retVal[0] = c0; + __retVal[1] = c1; + __retVal[2] = c2; +} + + +//// mat4 constructors + +mat4 __constructor(const float m00, const float m10, const float m20, const float m30, + const float m01, const float m11, const float m21, const float m31, + const float m02, const float m12, const float m22, const float m32, + const float m03, const float m13, const float m23, const float m33) +{ + __retVal[0].x = m00; + __retVal[0].y = m10; + __retVal[0].z = m20; + __retVal[0].w = m30; + __retVal[1].x = m01; + __retVal[1].y = m11; + __retVal[1].z = m21; + __retVal[1].w = m31; + __retVal[2].x = m02; + __retVal[2].y = m12; + __retVal[2].z = m22; + __retVal[2].w = m32; + __retVal[3].x = m03; + __retVal[3].y = m13; + __retVal[3].z = m23; + __retVal[3].w = m33; +} + + +mat4 __constructor(const float f) +{ + vec2 v = vec2(f, 0.0); + __retVal[0] = v.xyyy; + __retVal[1] = v.yxyy; + __retVal[2] = v.yyxy; + __retVal[3] = v.yyyx; +} + +mat4 __constructor(const int i) +{ + return mat4(float(i)); +} + +mat4 __constructor(const bool b) +{ + return mat4(float(b)); +} + +mat4 __constructor(const vec4 c0, const vec4 c1, const vec4 c2, const vec4 c3) +{ + __retVal[0] = c0; + __retVal[1] = c1; + __retVal[2] = c2; + __retVal[3] = c3; +} + + + +//// Basic int operators + +int __operator + (const int a, const int b) +{ + __asm vec4_add __retVal, a, b; +} + +int __operator - (const int a, const int b) +{ + __asm vec4_subtract __retVal, a, b; +} + +int __operator * (const int a, const int b) +{ + __asm vec4_multiply __retVal, a, b; +} + +int __operator / (const int a, const int b) +{ + float bInv, x; + __asm float_rcp bInv, b; + __asm vec4_multiply x, a, bInv; + __asm vec4_to_ivec4 __retVal, x; +} + + +//// Basic ivec2 operators + +ivec2 __operator + (const ivec2 a, const ivec2 b) +{ + __asm vec4_add __retVal, a, b; +} + +ivec2 __operator - (const ivec2 a, const ivec2 b) +{ + __asm vec4_subtract __retVal, a, b; +} + +ivec2 __operator * (const ivec2 a, const ivec2 b) +{ + __asm vec4_multiply __retVal, a, b; +} + +ivec2 __operator / (const ivec2 a, const ivec2 b) +{ + vec2 bInv, x; + __asm float_rcp bInv.x, b.x; + __asm float_rcp bInv.y, b.y; + __asm vec4_multiply x, a, bInv; + __asm vec4_to_ivec4 __retVal, x; +} + + +//// Basic ivec3 operators + +ivec3 __operator + (const ivec3 a, const ivec3 b) +{ + __asm vec4_add __retVal, a, b; +} + +ivec3 __operator - (const ivec3 a, const ivec3 b) +{ + __asm vec4_subtract __retVal, a, b; +} + +ivec3 __operator * (const ivec3 a, const ivec3 b) +{ + __asm vec4_multiply __retVal, a, b; +} + +ivec3 __operator / (const ivec3 a, const ivec3 b) +{ + vec3 bInv, x; + __asm float_rcp bInv.x, b.x; + __asm float_rcp bInv.y, b.y; + __asm float_rcp bInv.z, b.z; + __asm vec4_multiply x, a, bInv; + __asm vec4_to_ivec4 __retVal, x; +} + + +//// Basic ivec4 operators + +ivec4 __operator + (const ivec4 a, const ivec4 b) +{ + __asm vec4_add __retVal, a, b; +} + +ivec4 __operator - (const ivec4 a, const ivec4 b) +{ + __asm vec4_subtract __retVal, a, b; +} + +ivec4 __operator * (const ivec4 a, const ivec4 b) +{ + __asm vec4_multiply __retVal, a, b; +} + +ivec4 __operator / (const ivec4 a, const ivec4 b) +{ + vec4 bInv, x; + __asm float_rcp bInv.x, b.x; + __asm float_rcp bInv.y, b.y; + __asm float_rcp bInv.z, b.z; + __asm float_rcp bInv.w, b.w; + __asm vec4_multiply x, a, bInv; + __asm vec4_to_ivec4 __retVal, x; +} + + +//// Basic float operators + +float __operator + (const float a, const float b) +{ + __asm vec4_add __retVal, a, b; +} + +float __operator - (const float a, const float b) +{ + __asm vec4_subtract __retVal, a, b; +} + +float __operator * (const float a, const float b) +{ + __asm vec4_multiply __retVal, a, b; +} + +float __operator / (const float a, const float b) +{ + float bInv; + __asm float_rcp bInv.x, b; + __asm vec4_multiply __retVal, a, bInv; +} + + +//// Basic vec2 operators + +vec2 __operator + (const vec2 v, const vec2 u) +{ + __asm vec4_add __retVal.xy, v, u; +} + +vec2 __operator - (const vec2 v, const vec2 u) +{ + __asm vec4_subtract __retVal.xy, v, u; +} + +vec2 __operator * (const vec2 v, const vec2 u) +{ + __asm vec4_multiply __retVal.xy, v, u; +} + +vec2 __operator / (const vec2 v, const vec2 u) +{ + vec2 w; // = 1 / u + __asm float_rcp w.x, u.x; + __asm float_rcp w.y, u.y; + __asm vec4_multiply __retVal.xy, v, w; +} + + +//// Basic vec3 operators + +vec3 __operator + (const vec3 v, const vec3 u) +{ + __asm vec4_add __retVal.xyz, v, u; +} + +vec3 __operator - (const vec3 v, const vec3 u) +{ + __asm vec4_subtract __retVal.xyz, v, u; +} + +vec3 __operator * (const vec3 v, const vec3 u) +{ + __asm vec4_multiply __retVal.xyz, v, u; +} + +vec3 __operator / (const vec3 v, const vec3 u) +{ + vec3 w; // = 1 / u + __asm float_rcp w.x, u.x; + __asm float_rcp w.y, u.y; + __asm float_rcp w.z, u.z; + __asm vec4_multiply __retVal.xyz, v, w; +} + + +//// Basic vec4 operators + +vec4 __operator + (const vec4 v, const vec4 u) +{ + __asm vec4_add __retVal, v, u; +} + +vec4 __operator - (const vec4 v, const vec4 u) +{ + __asm vec4_subtract __retVal, v, u; +} + +vec4 __operator * (const vec4 v, const vec4 u) +{ + __asm vec4_multiply __retVal, v, u; +} + +vec4 __operator / (const vec4 v, const vec4 u) +{ + vec4 w; // = 1 / u + __asm float_rcp w.x, u.x; + __asm float_rcp w.y, u.y; + __asm float_rcp w.z, u.z; + __asm float_rcp w.w, u.w; + __asm vec4_multiply __retVal, v, w; +} + + + + +//// Basic vec2/float operators + +vec2 __operator + (const float a, const vec2 u) +{ + __asm vec4_add __retVal.xy, a, u.xy; +} + +vec2 __operator + (const vec2 v, const float b) +{ + __asm vec4_add __retVal.xy, v.xy, b; +} + +vec2 __operator - (const float a, const vec2 u) +{ + __asm vec4_subtract __retVal.xy, a, u.xy; +} + +vec2 __operator - (const vec2 v, const float b) +{ + __asm vec4_subtract __retVal.xy, v.xy, b; +} + +vec2 __operator * (const float a, const vec2 u) +{ + __asm vec4_multiply __retVal.xy, a, u.xy; +} + +vec2 __operator * (const vec2 v, const float b) +{ + __asm vec4_multiply __retVal.xy, v.xy, b; +} + +vec2 __operator / (const float a, const vec2 u) +{ + vec2 invU; + __asm float_rcp invU.x, u.x; + __asm float_rcp invU.y, u.y; + __asm vec4_multiply __retVal.xy, a, invU.xy; +} + +vec2 __operator / (const vec2 v, const float b) +{ + float invB; + __asm float_rcp invB, b; + __asm vec4_multiply __retVal.xy, v.xy, invB; +} + + +//// Basic vec3/float operators + +vec3 __operator + (const float a, const vec3 u) +{ + __asm vec4_add __retVal.xyz, a, u.xyz; +} + +vec3 __operator + (const vec3 v, const float b) +{ + __asm vec4_add __retVal.xyz, v.xyz, b; +} + +vec3 __operator - (const float a, const vec3 u) +{ + __asm vec4_subtract __retVal.xyz, a, u.xyz; +} + +vec3 __operator - (const vec3 v, const float b) +{ + __asm vec4_subtract __retVal.xyz, v.xyz, b; +} + +vec3 __operator * (const float a, const vec3 u) +{ + __asm vec4_multiply __retVal.xyz, a, u.xyz; +} + +vec3 __operator * (const vec3 v, const float b) +{ + __asm vec4_multiply __retVal.xyz, v.xyz, b; +} + +vec3 __operator / (const float a, const vec3 u) +{ + vec3 invU; + __asm float_rcp invU.x, u.x; + __asm float_rcp invU.y, u.y; + __asm float_rcp invU.z, u.z; + __asm vec4_multiply __retVal.xyz, a, invU.xyz; +} + +vec3 __operator / (const vec3 v, const float b) +{ + float invB; + __asm float_rcp invB, b; + __asm vec4_multiply __retVal.xyz, v.xyz, invB; +} + + +//// Basic vec4/float operators + +vec4 __operator + (const float a, const vec4 u) +{ + __asm vec4_add __retVal, a, u; +} + +vec4 __operator + (const vec4 v, const float b) +{ + __asm vec4_add __retVal, v, b; +} + +vec4 __operator - (const float a, const vec4 u) +{ + __asm vec4_subtract __retVal, a, u; +} + +vec4 __operator - (const vec4 v, const float b) +{ + __asm vec4_subtract __retVal, v, b; +} + +vec4 __operator * (const float a, const vec4 u) +{ + __asm vec4_multiply __retVal, a, u; +} + +vec4 __operator * (const vec4 v, const float b) +{ + __asm vec4_multiply __retVal, v, b; +} + +vec4 __operator / (const float a, const vec4 u) +{ + vec4 invU; + __asm float_rcp invU.x, u.x; + __asm float_rcp invU.y, u.y; + __asm float_rcp invU.z, u.z; + __asm float_rcp invU.w, u.w; + __asm vec4_multiply __retVal, a, invU; +} + +vec4 __operator / (const vec4 v, const float b) +{ + float invB; + __asm float_rcp invB, b; + __asm vec4_multiply __retVal, v, invB; +} + + + +//// Basic ivec2/int operators + +ivec2 __operator + (const int a, const ivec2 u) +{ + __retVal = ivec2(a) + u; +} + +ivec2 __operator + (const ivec2 v, const int b) +{ + __retVal = v + ivec2(b); +} + +ivec2 __operator - (const int a, const ivec2 u) +{ + __retVal = ivec2(a) - u; +} + +ivec2 __operator - (const ivec2 v, const int b) +{ + __retVal = v - ivec2(b); +} + +ivec2 __operator * (const int a, const ivec2 u) +{ + __retVal = ivec2(a) * u; +} + +ivec2 __operator * (const ivec2 v, const int b) +{ + __retVal = v * ivec2(b); +} + +ivec2 __operator / (const int a, const ivec2 u) +{ + __retVal = ivec2(a) / u; +} + +ivec2 __operator / (const ivec2 v, const int b) +{ + __retVal = v / ivec2(b); +} + + +//// Basic ivec3/int operators + +ivec3 __operator + (const int a, const ivec3 u) +{ + __retVal = ivec3(a) + u; +} + +ivec3 __operator + (const ivec3 v, const int b) +{ + __retVal = v + ivec3(b); +} + +ivec3 __operator - (const int a, const ivec3 u) +{ + __retVal = ivec3(a) - u; +} + +ivec3 __operator - (const ivec3 v, const int b) +{ + __retVal = v - ivec3(b); +} + +ivec3 __operator * (const int a, const ivec3 u) +{ + __retVal = ivec3(a) * u; +} + +ivec3 __operator * (const ivec3 v, const int b) +{ + __retVal = v * ivec3(b); +} + +ivec3 __operator / (const int a, const ivec3 u) +{ + __retVal = ivec3(a) / u; +} + +ivec3 __operator / (const ivec3 v, const int b) +{ + __retVal = v / ivec3(b); +} + + +//// Basic ivec4/int operators + +ivec4 __operator + (const int a, const ivec4 u) +{ + __retVal = ivec4(a) + u; +} + +ivec4 __operator + (const ivec4 v, const int b) +{ + __retVal = v + ivec4(b); +} + +ivec4 __operator - (const int a, const ivec4 u) +{ + __retVal = ivec4(a) - u; +} + +ivec4 __operator - (const ivec4 v, const int b) +{ + __retVal = v - ivec4(b); +} + +ivec4 __operator * (const int a, const ivec4 u) +{ + __retVal = ivec4(a) * u; +} + +ivec4 __operator * (const ivec4 v, const int b) +{ + __retVal = v * ivec4(b); +} + +ivec4 __operator / (const int a, const ivec4 u) +{ + __retVal = ivec4(a) / u; +} + +ivec4 __operator / (const ivec4 v, const int b) +{ + __retVal = v / ivec4(b); +} + + + + +//// Unary negation operator + +int __operator - (const int a) +{ + __asm vec4_negate __retVal.x, a; +} + +ivec2 __operator - (const ivec2 v) +{ + __asm vec4_negate __retVal, v; +} + +ivec3 __operator - (const ivec3 v) +{ + __asm vec4_negate __retVal, v; +} + +ivec4 __operator - (const ivec4 v) +{ + __asm vec4_negate __retVal, v; +} + +float __operator - (const float a) +{ + __asm vec4_negate __retVal.x, a; +} + +vec2 __operator - (const vec2 v) +{ + __asm vec4_negate __retVal.xy, v.xy; +} + +vec3 __operator - (const vec3 v) +{ + __asm vec4_negate __retVal.xyz, v.xyz; +} + +vec4 __operator - (const vec4 v) +{ + __asm vec4_negate __retVal, v; +} + +mat2 __operator - (const mat2 m) +{ + __retVal[0] = -m[0]; + __retVal[1] = -m[1]; +} + +mat3 __operator - (const mat3 m) +{ + __retVal[0] = -m[0]; + __retVal[1] = -m[1]; + __retVal[2] = -m[2]; +} + +mat4 __operator - (const mat4 m) +{ + __retVal[0] = -m[0]; + __retVal[1] = -m[1]; + __retVal[2] = -m[2]; + __retVal[3] = -m[3]; +} + + + +//// dot product + +float dot(const float a, const float b) +{ + __retVal = a * b; +} + +float dot(const vec2 a, const vec2 b) +{ + __retVal = a.x * b.x + a.y * b.y; +} + +float dot(const vec3 a, const vec3 b) +{ + __asm vec3_dot __retVal, a, b; +} + +float dot(const vec4 a, const vec4 b) +{ + __asm vec4_dot __retVal, a, b; +} + + + +//// int assignment operators + +int __operator += (inout int a, const int b) +{ + a = a + b; + return a; +} + +int __operator -= (inout int a, const int b) +{ + a = a - b; + return a; +} + +int __operator *= (inout int a, const int b) +{ + a = a * b; + return a; +} + +int __operator /= (inout int a, const int b) +{ + a = a / b; + return a; +} + + +//// ivec2 assignment operators + +ivec2 __operator += (inout ivec2 v, const ivec2 u) +{ + v = v + u; + return v; +} + +ivec2 __operator -= (inout ivec2 v, const ivec2 u) +{ + v = v - u; + return v; +} + +ivec2 __operator *= (inout ivec2 v, const ivec2 u) +{ + v = v * u; + return v; +} + +ivec2 __operator /= (inout ivec2 v, const ivec2 u) +{ + v = v / u; + return v; +} + + +//// ivec3 assignment operators + +ivec3 __operator += (inout ivec3 v, const ivec3 u) +{ + v = v + u; + return v; +} + +ivec3 __operator -= (inout ivec3 v, const ivec3 u) +{ + v = v - u; + return v; +} + +ivec3 __operator *= (inout ivec3 v, const ivec3 u) +{ + v = v * u; + return v; +} + +ivec3 __operator /= (inout ivec3 v, const ivec3 u) +{ + v = v / u; + return v; +} + + +//// ivec4 assignment operators + +ivec4 __operator += (inout ivec4 v, const ivec4 u) +{ + v = v + u; + return v; +} + +ivec4 __operator -= (inout ivec4 v, const ivec4 u) +{ + v = v - u; + return v; +} + +ivec4 __operator *= (inout ivec4 v, const ivec4 u) +{ + v = v * u; + return v; +} + +ivec4 __operator /= (inout ivec4 v, const ivec4 u) +{ + v = v / u; + return v; +} + + +//// float assignment operators + +float __operator += (inout float a, const float b) +{ + a = a + b; + return a; +} + +float __operator -= (inout float a, const float b) +{ + a = a - b; + return a; +} + +float __operator *= (inout float a, const float b) +{ + a = a * b; + return a; +} + +float __operator /= (inout float a, const float b) +{ + a = a / b; + return a; +} + + +//// vec2 assignment operators + +vec2 __operator += (inout vec2 v, const vec2 u) +{ + v = v + u; + return v; +} + +vec2 __operator -= (inout vec2 v, const vec2 u) +{ + v = v - u; + return v; +} + +vec2 __operator *= (inout vec2 v, const vec2 u) +{ + v = v * u; + return v; +} + +vec2 __operator /= (inout vec2 v, const vec2 u) +{ + v = v / u; + return v; +} + + +//// vec3 assignment operators + +vec3 __operator += (inout vec3 v, const vec3 u) +{ + v = v + u; + return v; +} + +vec3 __operator -= (inout vec3 v, const vec3 u) +{ + v = v - u; + return v; +} + +vec3 __operator *= (inout vec3 v, const vec3 u) +{ + v = v * u; + return v; +} + +vec3 __operator /= (inout vec3 v, const vec3 u) +{ + v = v / u; + return v; +} + + +//// vec4 assignment operators + +vec4 __operator += (inout vec4 v, const vec4 u) +{ + v = v + u; + return v; +} + +vec4 __operator -= (inout vec4 v, const vec4 u) +{ + v = v - u; + return v; +} + +vec4 __operator *= (inout vec4 v, const vec4 u) +{ + v = v * u; + return v; +} + +vec4 __operator /= (inout vec4 v, const vec4 u) +{ + v = v / u; + return v; +} + + + +//// ivec2/int assignment operators + +ivec2 __operator += (inout ivec2 v, const int a) +{ + v = v + ivec2(a); + return v; +} + +ivec2 __operator -= (inout ivec2 v, const int a) +{ + v = v - ivec2(a); + return v; +} + +ivec2 __operator *= (inout ivec2 v, const int a) +{ + v = v * ivec2(a); + return v; +} + +ivec2 __operator /= (inout ivec2 v, const int a) +{ + v = v / ivec2(a); + return v; +} + + +//// ivec3/int assignment operators + +ivec3 __operator += (inout ivec3 v, const int a) +{ + v = v + ivec3(a); + return v; +} + +ivec3 __operator -= (inout ivec3 v, const int a) +{ + v = v - ivec3(a); + return v; +} + +ivec3 __operator *= (inout ivec3 v, const int a) +{ + v = v * ivec3(a); + return v; +} + +ivec4 __operator /= (inout ivec3 v, const int a) +{ + v = v / ivec3(a); + return v; +} + + +//// ivec4/int assignment operators + +ivec4 __operator += (inout ivec4 v, const int a) +{ + v = v + ivec4(a); + return v; +} + +ivec4 __operator -= (inout ivec4 v, const int a) +{ + v = v - ivec4(a); + return v; +} + +ivec4 __operator *= (inout ivec4 v, const int a) +{ + v = v * ivec4(a); + return v; +} + +ivec4 __operator /= (inout ivec4 v, const int a) +{ + v = v / ivec4(a); + return v; +} + + + +//// vec2/float assignment operators + +vec2 __operator += (inout vec2 v, const float a) +{ + v = v + vec2(a); + return v; +} + +vec2 __operator -= (inout vec2 v, const float a) +{ + v = v - vec2(a); + return v; +} + +vec2 __operator *= (inout vec2 v, const float a) +{ + v = v * vec2(a); + return v; +} + +vec2 __operator /= (inout vec2 v, const float a) +{ + v = v / vec2(a); + return v; +} + + +//// vec3/float assignment operators + +vec3 __operator += (inout vec3 v, const float a) +{ + v = v + vec3(a); + return v; +} + +vec3 __operator -= (inout vec3 v, const float a) +{ + v = v - vec3(a); + return v; +} + +vec3 __operator *= (inout vec3 v, const float a) +{ + v = v * vec3(a); + return v; +} + +vec3 __operator /= (inout vec3 v, const float a) +{ + v = v / vec3(a); + return v; +} + + +//// vec4/float assignment operators + +vec4 __operator += (inout vec4 v, const float a) +{ + v = v + vec4(a); + return v; +} + +vec4 __operator -= (inout vec4 v, const float a) +{ + v = v - vec4(a); + return v; +} + +vec4 __operator *= (inout vec4 v, const float a) +{ + v = v * vec4(a); + return v; +} + +vec4 __operator /= (inout vec4 v, const float a) +{ + v = v / vec4(a); + return v; +} + + + + + +//// Basic mat2 operations + +mat2 __operator + (const mat2 m, const mat2 n) +{ + __retVal[0] = m[0] + n[0]; + __retVal[1] = m[1] + n[1]; +} + +mat2 __operator - (const mat2 m, const mat2 n) +{ + __retVal[0] = m[0] - n[0]; + __retVal[1] = m[1] - n[1]; +} + +mat2 __operator * (const mat2 m, const mat2 n) +{ + __retVal[0] = m[0] * n[0].xx + m[1] * n[0].yy; + __retVal[1] = m[0] * n[1].xx + m[1] * n[1].yy; +} + +mat2 __operator / (const mat2 m, const mat2 n) +{ + __retVal[0] = m[0] / n[0]; + __retVal[1] = m[1] / n[1]; +} + + +//// Basic mat3 operations + +mat3 __operator + (const mat3 m, const mat3 n) +{ + __retVal[0] = m[0] + n[0]; + __retVal[1] = m[1] + n[1]; + __retVal[2] = m[2] + n[2]; +} + +mat3 __operator - (const mat3 m, const mat3 n) +{ + __retVal[0] = m[0] - n[0]; + __retVal[1] = m[1] - n[1]; + __retVal[2] = m[2] - n[2]; +} + +mat3 __operator * (const mat3 m, const mat3 n) +{ + __retVal[0] = m[0] * n[0].xxx + m[1] * n[0].yyy + m[2] * n[0].zzz; + __retVal[1] = m[0] * n[1].xxx + m[1] * n[1].yyy + m[2] * n[1].zzz; + __retVal[2] = m[0] * n[2].xxx + m[1] * n[2].yyy + m[2] * n[2].zzz; +} + +mat3 __operator / (const mat3 m, const mat3 n) +{ + __retVal[0] = m[0] / n[0]; + __retVal[1] = m[1] / n[1]; + __retVal[2] = m[2] / n[2]; +} + + +//// Basic mat4 operations + +mat4 __operator + (const mat4 m, const mat4 n) +{ + __retVal[0] = m[0] + n[0]; + __retVal[1] = m[1] + n[1]; + __retVal[2] = m[2] + n[2]; + __retVal[3] = m[3] + n[3]; +} + +mat4 __operator - (const mat4 m, const mat4 n) +{ + __retVal[0] = m[0] - n[0]; + __retVal[1] = m[1] - n[1]; + __retVal[2] = m[2] - n[2]; + __retVal[3] = m[3] - n[3]; +} + +mat4 __operator * (const mat4 m, const mat4 n) +{ + __retVal[0] = m[0] * n[0].xxxx + m[1] * n[0].yyyy + m[2] * n[0].zzzz + m[3] * n[0].wwww; + __retVal[1] = m[0] * n[1].xxxx + m[1] * n[1].yyyy + m[2] * n[1].zzzz + m[3] * n[1].wwww; + __retVal[2] = m[0] * n[2].xxxx + m[1] * n[2].yyyy + m[2] * n[2].zzzz + m[3] * n[2].wwww; + __retVal[3] = m[0] * n[3].xxxx + m[1] * n[3].yyyy + m[2] * n[3].zzzz + m[3] * n[3].wwww; +} + +mat4 __operator / (const mat4 m, const mat4 n) +{ + __retVal[0] = m[0] / n[0]; + __retVal[1] = m[1] / n[1]; + __retVal[2] = m[2] / n[2]; + __retVal[3] = m[3] / n[3]; +} + + +//// mat2/float operations + +mat2 __operator + (const float a, const mat2 n) +{ + __retVal[0] = a + n[0]; + __retVal[1] = a + n[1]; +} + +mat2 __operator + (const mat2 m, const float b) +{ + __retVal[0] = m[0] + b; + __retVal[1] = m[1] + b; +} + +mat2 __operator - (const float a, const mat2 n) +{ + __retVal[0] = a - n[0]; + __retVal[1] = a - n[1]; +} + +mat2 __operator - (const mat2 m, const float b) +{ + __retVal[0] = m[0] - b; + __retVal[1] = m[1] - b; +} + +mat2 __operator * (const float a, const mat2 n) +{ + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; +} + +mat2 __operator * (const mat2 m, const float b) +{ + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; +} + +mat2 __operator / (const float a, const mat2 n) +{ + __retVal[0] = a / n[0]; + __retVal[1] = a / n[1]; +} + +mat2 __operator / (const mat2 m, const float b) +{ + __retVal[0] = m[0] / b; + __retVal[1] = m[1] / b; +} + + +//// mat3/float operations + +mat3 __operator + (const float a, const mat3 n) +{ + __retVal[0] = a + n[0]; + __retVal[1] = a + n[1]; + __retVal[2] = a + n[2]; +} + +mat3 __operator + (const mat3 m, const float b) +{ + __retVal[0] = m[0] + b; + __retVal[1] = m[1] + b; + __retVal[2] = m[2] + b; +} + +mat3 __operator - (const float a, const mat3 n) +{ + __retVal[0] = a - n[0]; + __retVal[1] = a - n[1]; + __retVal[2] = a - n[2]; +} + +mat3 __operator - (const mat3 m, const float b) +{ + __retVal[0] = m[0] - b; + __retVal[1] = m[1] - b; + __retVal[2] = m[2] - b; +} + +mat3 __operator * (const float a, const mat3 n) +{ + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; + __retVal[2] = a * n[2]; +} + +mat3 __operator * (const mat3 m, const float b) +{ + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; + __retVal[2] = m[2] * b; +} + +mat3 __operator / (const float a, const mat3 n) +{ + __retVal[0] = a / n[0]; + __retVal[1] = a / n[1]; + __retVal[2] = a / n[2]; +} + +mat3 __operator / (const mat3 m, const float b) +{ + __retVal[0] = m[0] / b; + __retVal[1] = m[1] / b; + __retVal[2] = m[2] / b; +} + + +//// mat4/float operations + +mat4 __operator + (const float a, const mat4 n) +{ + __retVal[0] = a + n[0]; + __retVal[1] = a + n[1]; + __retVal[2] = a + n[2]; + __retVal[3] = a + n[3]; +} + +mat4 __operator + (const mat4 m, const float b) +{ + __retVal[0] = m[0] + b; + __retVal[1] = m[1] + b; + __retVal[2] = m[2] + b; + __retVal[3] = m[3] + b; +} + +mat4 __operator - (const float a, const mat4 n) +{ + __retVal[0] = a - n[0]; + __retVal[1] = a - n[1]; + __retVal[2] = a - n[2]; + __retVal[3] = a - n[3]; +} + +mat4 __operator - (const mat4 m, const float b) +{ + __retVal[0] = m[0] - b; + __retVal[1] = m[1] - b; + __retVal[2] = m[2] - b; + __retVal[3] = m[3] - b; +} + +mat4 __operator * (const float a, const mat4 n) +{ + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; + __retVal[2] = a * n[2]; + __retVal[3] = a * n[3]; +} + +mat4 __operator * (const mat4 m, const float b) +{ + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; + __retVal[2] = m[2] * b; + __retVal[3] = m[3] * b; +} + +mat4 __operator / (const float a, const mat4 n) +{ + __retVal[0] = a / n[0]; + __retVal[1] = a / n[1]; + __retVal[2] = a / n[2]; + __retVal[3] = a / n[3]; +} + +mat4 __operator / (const mat4 m, const float b) +{ + __retVal[0] = m[0] / b; + __retVal[1] = m[1] / b; + __retVal[2] = m[2] / b; + __retVal[3] = m[3] / b; +} + + + +//// matrix / vector products + +vec2 __operator * (const mat2 m, const vec2 v) +{ + __retVal = m[0] * v.xx + + m[1] * v.yy; +} + +vec2 __operator * (const vec2 v, const mat2 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); +} + +vec3 __operator * (const mat3 m, const vec3 v) +{ + __retVal = m[0] * v.xxx + + m[1] * v.yyy + + m[2] * v.zzz; +} + +vec3 __operator * (const vec3 v, const mat3 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); + __retVal.z = dot(v, m[2]); +} + +vec4 __operator * (const mat4 m, const vec4 v) +{ + __retVal = m[0] * v.xxxx + + m[1] * v.yyyy + + m[2] * v.zzzz + + m[3] * v.wwww; +} + +vec4 __operator * (const vec4 v, const mat4 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); + __retVal.z = dot(v, m[2]); + __retVal.w = dot(v, m[3]); +} + + + +//// mat2 assignment operators + +mat2 __operator += (inout mat2 m, const mat2 n) +{ + m[0] = m[0] + n[0]; + m[1] = m[1] + n[1]; + return m; +} + +mat2 __operator -= (inout mat2 m, const mat2 n) +{ + m[0] = m[0] - n[0]; + m[1] = m[1] - n[1]; + return m; +} + +mat2 __operator *= (inout mat2 m, const mat2 n) +{ + m = m * n; + return m; +} + +mat2 __operator /= (inout mat2 m, const mat2 n) +{ + m[0] = m[0] / n[0]; + m[1] = m[1] / n[1]; + return m; +} + + +//// mat3 assignment operators + +mat3 __operator += (inout mat3 m, const mat3 n) +{ + m[0] = m[0] + n[0]; + m[1] = m[1] + n[1]; + m[2] = m[2] + n[2]; + return m; +} + +mat3 __operator -= (inout mat3 m, const mat3 n) +{ + m[0] = m[0] - n[0]; + m[1] = m[1] - n[1]; + m[2] = m[2] - n[2]; + return m; +} + +mat3 __operator *= (inout mat3 m, const mat3 n) +{ + m = m * n; + return m; +} + +mat3 __operator /= (inout mat3 m, const mat3 n) +{ + m[0] = m[0] / n[0]; + m[1] = m[1] / n[1]; + m[2] = m[2] / n[2]; + return m; +} + + +// mat4 assignment operators + +mat4 __operator += (inout mat4 m, const mat4 n) +{ + m[0] = m[0] + n[0]; + m[1] = m[1] + n[1]; + m[2] = m[2] + n[2]; + m[3] = m[3] + n[3]; + return m; +} + +mat4 __operator -= (inout mat4 m, const mat4 n) +{ + m[0] = m[0] - n[0]; + m[1] = m[1] - n[1]; + m[2] = m[2] - n[2]; + m[3] = m[3] - n[3]; + return m; +} + +mat4 __operator *= (inout mat4 m, const mat4 n) +{ + m = m * n; + return m; +} + +mat4 __operator /= (inout mat4 m, const mat4 n) +{ + m[0] = m[0] / n[0]; + m[1] = m[1] / n[1]; + m[2] = m[2] / n[2]; + m[3] = m[3] / n[3]; + return m; +} + + +//// mat2/float assignment operators + +mat2 __operator += (inout mat2 m, const float a) +{ + vec2 v = vec2(a); + m[0] = m[0] + v; + m[1] = m[1] + v; + return m; +} + +mat2 __operator -= (inout mat2 m, const float a) +{ + vec2 v = vec2(a); + m[0] = m[0] - v; + m[1] = m[1] - v; + return m; +} + +mat2 __operator *= (inout mat2 m, const float a) +{ + vec2 v = vec2(a); + m[0] = m[0] * v; + m[1] = m[1] * v; + return m; +} + +mat2 __operator /= (inout mat2 m, const float a) +{ + vec2 v = vec2(1.0 / a); + m[0] = m[0] * v; + m[1] = m[1] * v; + return m; +} + + +//// mat3/float assignment operators + +mat3 __operator += (inout mat3 m, const float a) +{ + vec3 v = vec3(a); + m[0] = m[0] + v; + m[1] = m[1] + v; + m[2] = m[2] + v; + return m; +} + +mat3 __operator -= (inout mat3 m, const float a) +{ + vec3 v = vec3(a); + m[0] = m[0] - v; + m[1] = m[1] - v; + m[2] = m[2] - v; + return m; +} + +mat3 __operator *= (inout mat3 m, const float a) +{ + vec3 v = vec3(a); + m[0] = m[0] * v; + m[1] = m[1] * v; + m[2] = m[2] * v; + return m; +} + +mat3 __operator /= (inout mat3 m, const float a) +{ + vec3 v = vec3(1.0 / a); + m[0] = m[0] * v; + m[1] = m[1] * v; + m[2] = m[2] * v; + return m; +} + + +//// mat4/float assignment operators + +mat4 __operator += (inout mat4 m, const float a) +{ + vec4 v = vec4(a); + m[0] = m[0] + v; + m[1] = m[1] + v; + m[2] = m[2] + v; + m[3] = m[3] + v; + return m; +} + +mat4 __operator -= (inout mat4 m, const float a) +{ + vec4 v = vec4(a); + m[0] = m[0] - v; + m[1] = m[1] - v; + m[2] = m[2] - v; + m[3] = m[3] - v; + return m; +} + +mat4 __operator *= (inout mat4 m, const float a) +{ + vec4 v = vec4(a); + m[0] = m[0] * v; + m[1] = m[1] * v; + m[2] = m[2] * v; + m[3] = m[3] * v; + return m; +} + +mat4 __operator /= (inout mat4 m, const float a) +{ + vec4 v = vec4(1.0 / a); + m[0] = m[0] * v; + m[1] = m[1] * v; + m[2] = m[2] * v; + m[3] = m[3] * v; + return m; +} + + + +//// vec/mat assignment operators + +vec2 __operator *= (inout vec2 v, const mat2 m) +{ + v = v * m; + return v; +} + +vec3 __operator *= (inout vec3 v, const mat3 m) +{ + v = v * m; + return v; +} + +vec4 __operator *= (inout vec4 v, const mat4 m) +{ + v = v * m; + return v; +} + + + +//// pre-decrement operators + +int __operator --(inout int a) +{ + a = a - 1; + __retVal = a; +} + +ivec2 __operator --(inout ivec2 v) +{ + v = v - ivec2(1); + __retVal = v; +} + +ivec3 __operator --(inout ivec3 v) +{ + v = v - ivec3(1); + __retVal = v; +} + +ivec4 __operator --(inout ivec4 v) +{ + v = v - ivec4(1); + __retVal = v; +} + + +float __operator --(inout float a) +{ + a = a - 1.0; + __retVal = a; +} + +vec2 __operator --(inout vec2 v) +{ + v = v - vec2(1.0); + __retVal = v; +} + +vec3 __operator --(inout vec3 v) +{ + v = v - vec3(1.0); + __retVal = v; +} + +vec4 __operator --(inout vec4 v) +{ + v = v - vec4(1.0); + __retVal = v; +} + + +mat2 __operator --(inout mat2 m) +{ + m[0] = m[0] - vec2(1.0); + m[1] = m[1] - vec2(1.0); + __retVal = m; +} + +mat3 __operator --(inout mat3 m) +{ + m[0] = m[0] - vec3(1.0); + m[1] = m[1] - vec3(1.0); + m[2] = m[2] - vec3(1.0); + __retVal = m; +} + +mat4 __operator --(inout mat4 m) +{ + m[0] = m[0] - vec4(1.0); + m[1] = m[1] - vec4(1.0); + m[2] = m[2] - vec4(1.0); + m[3] = m[3] - vec4(1.0); + __retVal = m; +} + + +//// pre-increment operators + +int __operator ++(inout int a) +{ + a = a + 1; + __retVal = a; +} + +ivec2 __operator ++(inout ivec2 v) +{ + v = v + ivec2(1); + __retVal = v; +} + +ivec3 __operator ++(inout ivec3 v) +{ + v = v + ivec3(1); + __retVal = v; +} + +ivec4 __operator ++(inout ivec4 v) +{ + v = v + ivec4(1); + __retVal = v; +} + + +float __operator ++(inout float a) +{ + a = a + 1.0; + __retVal = a; +} + +vec2 __operator ++(inout vec2 v) +{ + v = v + vec2(1.0); + __retVal = v; +} + +vec3 __operator ++(inout vec3 v) +{ + v = v + vec3(1.0); + __retVal = v; +} + +vec4 __operator ++(inout vec4 v) +{ + v = v + vec4(1.0); + __retVal = v; +} + + +mat2 __operator ++(inout mat2 m) +{ + m[0] = m[0] + vec2(1.0); + m[1] = m[1] + vec2(1.0); + __retVal = m; +} + +mat3 __operator ++(inout mat3 m) +{ + m[0] = m[0] + vec3(1.0); + m[1] = m[1] + vec3(1.0); + m[2] = m[2] + vec3(1.0); + __retVal = m; +} + +mat4 __operator ++(inout mat4 m) +{ + m[0] = m[0] + vec4(1.0); + m[1] = m[1] + vec4(1.0); + m[2] = m[2] + vec4(1.0); + m[3] = m[3] + vec4(1.0); + __retVal = m; +} + + + +//// post-decrement + +int __postDecr(inout int a) +{ + __retVal = a; + a = a - 1; +} + +ivec2 __postDecr(inout ivec2 v) +{ + __retVal = v; + v = v - ivec2(1); +} + +ivec3 __postDecr(inout ivec3 v) +{ + __retVal = v; + v = v - ivec3(1); +} + +ivec4 __postDecr(inout ivec4 v) +{ + __retVal = v; + v = v - ivec4(1); +} + + +float __postDecr(inout float a) +{ + __retVal = a; + a = a - 1.0; +} + +vec2 __postDecr(inout vec2 v) +{ + __retVal = v; + v = v - vec2(1.0); +} + +vec3 __postDecr(inout vec3 v) +{ + __retVal = v; + v = v - vec3(1.0); +} + +vec4 __postDecr(inout vec4 v) +{ + __retVal = v; + v = v - vec4(1.0); +} + + +mat2 __postDecr(inout mat2 m) +{ + __retVal = m; + m[0] = m[0] - vec2(1.0); + m[1] = m[1] - vec2(1.0); +} + +mat3 __postDecr(inout mat3 m) +{ + __retVal = m; + m[0] = m[0] - vec3(1.0); + m[1] = m[1] - vec3(1.0); + m[2] = m[2] - vec3(1.0); +} + +mat4 __postDecr(inout mat4 m) +{ + __retVal = m; + m[0] = m[0] - vec4(1.0); + m[1] = m[1] - vec4(1.0); + m[2] = m[2] - vec4(1.0); + m[3] = m[3] - vec4(1.0); +} + + +//// post-increment + +float __postIncr(inout float a) +{ + __retVal = a; + a = a + 1; +} + +vec2 __postIncr(inout vec2 v) +{ + __retVal = v; + v = v + vec2(1.0); +} + +vec3 __postIncr(inout vec3 v) +{ + __retVal = v; + v = v + vec3(1.0); +} + +vec4 __postIncr(inout vec4 v) +{ + __retVal = v; + v = v + vec4(1.0); +} + + +int __postIncr(inout int a) +{ + __retVal = a; + a = a + 1; +} + +ivec2 __postIncr(inout ivec2 v) +{ + __retVal = v; + v = v + ivec2(1); +} + +ivec3 __postIncr(inout ivec3 v) +{ + __retVal = v; + v = v + ivec3(1); +} + +ivec4 __postIncr(inout ivec4 v) +{ + __retVal = v; + v = v + ivec3(1); +} + + +mat2 __postIncr(inout mat2 m) +{ + mat2 n = m; + m[0] = m[0] + vec2(1.0); + m[1] = m[1] + vec2(1.0); + return n; +} + +mat3 __postIncr(inout mat3 m) +{ + mat3 n = m; + m[0] = m[0] + vec3(1.0); + m[1] = m[1] + vec3(1.0); + m[2] = m[2] + vec3(1.0); + return n; +} + +mat4 __postIncr(inout mat4 m) +{ + mat4 n = m; + m[0] = m[0] + vec4(1.0); + m[1] = m[1] + vec4(1.0); + m[2] = m[2] + vec4(1.0); + m[3] = m[3] + vec4(1.0); + return n; +} + + + +//// inequality operators + + +// XXX are the inequality operators for floats/ints really needed???? +bool __operator < (const float a, const float b) +{ + __asm vec4_sgt __retVal.x, b, a; +} + + +bool __operator < (const int a, const int b) { + return float (a) < float (b); +} + +bool __operator > (const float a, const float b) { + bool c; + __asm float_less c, b, a; + return c; +} + +bool __operator > (const int a, const int b) { + return float (a) > float (b); +} + +bool __operator >= (const float a, const float b) { + bool g, e; + __asm float_less g, b, a; + __asm float_equal e, a, b; + return g || e; +} + +bool __operator >= (const int a, const int b) { + return float (a) >= float (b); +} + +bool __operator <= (const float a, const float b) { + bool g, e; + __asm float_less g, a, b; + __asm float_equal e, a, b; + return g || e; +} + +bool __operator <= (const int a, const int b) { + return float (a) <= float (b); +} + + + +// +// MESA-specific extension functions. +// + +void printMESA (const float f) { + __asm float_print f; +} + +void printMESA (const int i) { + __asm int_print i; +} + +void printMESA (const bool b) { + __asm bool_print b; +} + +void printMESA (const vec2 v) { + printMESA (v.x); + printMESA (v.y); +} + +void printMESA (const vec3 v) { + printMESA (v.x); + printMESA (v.y); + printMESA (v.z); +} + +void printMESA (const vec4 v) { + printMESA (v.x); + printMESA (v.y); + printMESA (v.z); + printMESA (v.w); +} + +void printMESA (const ivec2 v) { + printMESA (v.x); + printMESA (v.y); +} + +void printMESA (const ivec3 v) { + printMESA (v.x); + printMESA (v.y); + printMESA (v.z); +} + +void printMESA (const ivec4 v) { + printMESA (v.x); + printMESA (v.y); + printMESA (v.z); + printMESA (v.w); +} + +void printMESA (const bvec2 v) { + printMESA (v.x); + printMESA (v.y); +} + +void printMESA (const bvec3 v) { + printMESA (v.x); + printMESA (v.y); + printMESA (v.z); +} + +void printMESA (const bvec4 v) { + printMESA (v.x); + printMESA (v.y); + printMESA (v.z); + printMESA (v.w); +} + +void printMESA (const mat2 m) { + printMESA (m[0]); + printMESA (m[1]); +} + +void printMESA (const mat3 m) { + printMESA (m[0]); + printMESA (m[1]); + printMESA (m[2]); +} + +void printMESA (const mat4 m) { + printMESA (m[0]); + printMESA (m[1]); + printMESA (m[2]); + printMESA (m[3]); +} + +void printMESA (const sampler1D e) { + __asm int_print e; +} + +void printMESA (const sampler2D e) { + __asm int_print e; +} + +void printMESA (const sampler3D e) { + __asm int_print e; +} + +void printMESA (const samplerCube e) { + __asm int_print e; +} + +void printMESA (const sampler1DShadow e) { + __asm int_print e; +} + +void printMESA (const sampler2DShadow e) { + __asm int_print e; +} + diff --git a/src/mesa/slang/library/slang_fragment_builtin.gc b/src/mesa/slang/library/slang_fragment_builtin.gc new file mode 100644 index 0000000000..54a80ea0e0 --- /dev/null +++ b/src/mesa/slang/library/slang_fragment_builtin.gc @@ -0,0 +1,299 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// From Shader Spec, ver. 1.10, rev. 59 +// + +__fixed_input vec4 gl_FragCoord; +__fixed_input bool gl_FrontFacing; +__fixed_output vec4 gl_FragColor; +__fixed_output vec4 gl_FragData[gl_MaxDrawBuffers]; +__fixed_output float gl_FragDepth; + +varying vec4 gl_Color; +varying vec4 gl_SecondaryColor; +varying vec4 gl_TexCoord[gl_MaxTextureCoords]; +varying float gl_FogFragCoord; + + + +//// 8.7 Texture Lookup Functions (with bias) + +vec4 texture1D(const sampler1D sampler, const float coord, const float bias) +{ + vec4 coord4; + coord4.x = coord; + coord4.w = bias; + __asm vec4_tex_1d_bias __retVal, sampler, coord4; +} + +vec4 texture1DProj(const sampler1D sampler, const vec2 coord, const float bias) +{ + // do projection here (there's no vec4_texbp1d instruction) + vec4 pcoord; + pcoord.x = coord.x / coord.y; + pcoord.w = bias; + __asm vec4_tex_1d_bias __retVal, sampler, pcoord; +} + +vec4 texture1DProj(const sampler1D sampler, const vec4 coord, const float bias) +{ + // do projection here (there's no vec4_texbp1d instruction) + vec4 pcoord; + pcoord.x = coord.x / coord.z; + pcoord.w = bias; + __asm vec4_tex_1d_bias __retVal, sampler, pcoord; +} + + + + +vec4 texture2D(const sampler2D sampler, const vec2 coord, const float bias) +{ + vec4 coord4; + coord4.xy = coord.xy; + coord4.w = bias; + __asm vec4_tex_2d_bias __retVal, sampler, coord4; +} + +vec4 texture2DProj(const sampler2D sampler, const vec3 coord, const float bias) +{ + // do projection here (there's no vec4_texbp2d instruction) + vec4 pcoord; + pcoord.xy = coord.xy / coord.z; + pcoord.w = bias; + __asm vec4_tex_2d_bias __retVal, sampler, pcoord; +} + +vec4 texture2DProj(const sampler2D sampler, const vec4 coord, const float bias) +{ + // do projection here (there's no vec4_texbp2d instruction) + vec4 pcoord; + pcoord.xy = coord.xy / coord.w; + pcoord.w = bias; + __asm vec4_tex_2d_bias __retVal, sampler, pcoord; +} + + + + +vec4 texture3D(const sampler3D sampler, const vec3 coord, const float bias) +{ + vec4 coord4; + coord4.xyz = coord.xyz; + coord4.w = bias; + __asm vec4_tex_3d_bias __retVal, sampler, coord4; +} + +vec4 texture3DProj(const sampler3D sampler, const vec4 coord, const float bias) +{ + // do projection here (there's no vec4_texbp3d instruction) + vec4 pcoord; + pcoord.xyz = coord.xyz / coord.w; + pcoord.w = bias; + __asm vec4_tex_3d_bias __retVal, sampler, pcoord; +} + + + + +vec4 textureCube(const samplerCube sampler, const vec3 coord, const float bias) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = bias; + __asm vec4_tex_cube __retVal, sampler, coord4; +} + + + +vec4 shadow1D(const sampler1DShadow sampler, const vec3 coord, const float bias) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = bias; + __asm vec4_tex_1d_bias_shadow __retVal, sampler, coord4; +} + +vec4 shadow1DProj(const sampler1DShadow sampler, const vec4 coord, const float bias) +{ + vec4 pcoord; + pcoord.x = coord.x / coord.w; + pcoord.z = coord.z; + pcoord.w = bias; + __asm vec4_tex_1d_bias_shadow __retVal, sampler, pcoord; +} + +vec4 shadow2D(const sampler2DShadow sampler, const vec3 coord, const float bias) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = bias; + __asm vec4_tex_2d_bias_shadow __retVal, sampler, coord4; +} + +vec4 shadow2DProj(const sampler2DShadow sampler, const vec4 coord, const float bias) +{ + vec4 pcoord; + pcoord.xy = coord.xy / coord.w; + pcoord.z = coord.z; + pcoord.w = bias; + __asm vec4_tex_2d_bias_shadow __retVal, sampler, pcoord; +} + + + +//// GL_EXT_texture_array + +vec4 texture1DArray(const sampler1DArray sampler, const vec2 coord) +{ + vec4 coord4; + coord4.xy = coord; + __asm vec4_tex_1d_array __retVal, sampler, coord4; +} + +vec4 texture1DArray(const sampler1DArray sampler, const vec2 coord, const float bias) +{ + vec4 coord4; + coord4.xy = coord; + coord4.w = bias; + __asm vec4_tex_1d_array_bias __retVal, sampler, coord4; +} + +vec4 texure2DArray(const sampler2DArray sampler, const vec3 coord) +{ + vec4 coord4; + coord4.xyz = coord; + __asm vec4_tex_2d_array __retVal, sampler, coord4; +} + +vec4 texture2DArray(const sampler2DArray sampler, const vec3 coord, const float bias) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = bias; + __asm vec4_tex_2d_array_bias __retVal, sampler, coord4; +} + +vec4 shadow1DArray(const sampler1DArrayShadow sampler, const vec2 coord) +{ + vec4 coord4; + coord4.xy = coord; + __asm vec4_tex_1d_array_shadow __retVal, sampler, coord4; +} + +vec4 shadow1DArray(const sampler1DArrayShadow sampler, const vec2 coord, const float bias) +{ + vec4 coord4; + coord4.xy = coord; + coord4.w = bias; + __asm vec4_tex_1d_array_bias_shadow __retVal, sampler, coord4; +} + +vec4 shadow2DArray(const sampler2DArrayShadow sampler, const vec3 coord) +{ + vec4 coord4; + coord4.xyz = coord; + __asm vec4_tex_2d_array_shadow __retVal, sampler, coord4; +} + +vec4 shadow2DArray(const sampler2DArrayShadow sampler, const vec3 coord, const float bias) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = bias; + __asm vec4_tex_2d_array_bias_shadow __retVal, sampler, coord4; +} + + + +// +// 8.8 Fragment Processing Functions +// + +float dFdx(const float p) +{ + __asm vec4_ddx __retVal.x, p.xxxx; +} + +vec2 dFdx(const vec2 p) +{ + __asm vec4_ddx __retVal.xy, p.xyyy; +} + +vec3 dFdx(const vec3 p) +{ + __asm vec4_ddx __retVal.xyz, p.xyzz; +} + +vec4 dFdx(const vec4 p) +{ + __asm vec4_ddx __retVal, p; +} + +float dFdy(const float p) +{ + __asm vec4_ddy __retVal.x, p.xxxx; +} + +vec2 dFdy(const vec2 p) +{ + __asm vec4_ddy __retVal.xy, p.xyyy; +} + +vec3 dFdy(const vec3 p) +{ + __asm vec4_ddy __retVal.xyz, p.xyzz; +} + +vec4 dFdy(const vec4 p) +{ + __asm vec4_ddy __retVal, p; +} + +float fwidth (const float p) +{ + // XXX hand-write with __asm + return abs(dFdx(p)) + abs(dFdy(p)); +} + +vec2 fwidth(const vec2 p) +{ + // XXX hand-write with __asm + return abs(dFdx(p)) + abs(dFdy(p)); +} + +vec3 fwidth(const vec3 p) +{ + // XXX hand-write with __asm + return abs(dFdx(p)) + abs(dFdy(p)); +} + +vec4 fwidth(const vec4 p) +{ + // XXX hand-write with __asm + return abs(dFdx(p)) + abs(dFdy(p)); +} + diff --git a/src/mesa/slang/library/slang_vertex_builtin.gc b/src/mesa/slang/library/slang_vertex_builtin.gc new file mode 100644 index 0000000000..0c67c2ef20 --- /dev/null +++ b/src/mesa/slang/library/slang_vertex_builtin.gc @@ -0,0 +1,210 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// From Shader Spec, ver. 1.10, rev. 59 +// + +__fixed_output vec4 gl_Position; +__fixed_output float gl_PointSize; +__fixed_output vec4 gl_ClipVertex; + +attribute vec4 gl_Color; +attribute vec4 gl_SecondaryColor; +attribute vec3 gl_Normal; +attribute vec4 gl_Vertex; +attribute vec4 gl_MultiTexCoord0; +attribute vec4 gl_MultiTexCoord1; +attribute vec4 gl_MultiTexCoord2; +attribute vec4 gl_MultiTexCoord3; +attribute vec4 gl_MultiTexCoord4; +attribute vec4 gl_MultiTexCoord5; +attribute vec4 gl_MultiTexCoord6; +attribute vec4 gl_MultiTexCoord7; +attribute float gl_FogCoord; + +varying vec4 gl_FrontColor; +varying vec4 gl_BackColor; +varying vec4 gl_FrontSecondaryColor; +varying vec4 gl_BackSecondaryColor; +varying vec4 gl_TexCoord[gl_MaxTextureCoords]; +varying float gl_FogFragCoord; + +// +// Geometric Functions +// + +vec4 ftransform() +{ + __retVal = gl_ModelViewProjectionMatrix[0] * gl_Vertex.xxxx + + gl_ModelViewProjectionMatrix[1] * gl_Vertex.yyyy + + gl_ModelViewProjectionMatrix[2] * gl_Vertex.zzzz + + gl_ModelViewProjectionMatrix[3] * gl_Vertex.wwww; +} + + + +// +// 8.7 Texture Lookup Functions +// These are pretty much identical to the ones in slang_fragment_builtin.gc +// When used in a vertex program, the texture sample instructions should not +// be using a LOD term so it's effectively zero. Adding 'lod' to that does +// what we want. +// + +vec4 texture1DLod(const sampler1D sampler, const float coord, const float lod) +{ + vec4 coord4; + coord4.x = coord; + coord4.w = lod; + __asm vec4_tex_1d_bias __retVal, sampler, coord4; +} + +vec4 texture1DProjLod(const sampler1D sampler, const vec2 coord, const float lod) +{ + vec4 pcoord; + pcoord.x = coord.x / coord.y; + pcoord.w = lod; + __asm vec4_tex_1d_bias __retVal, sampler, pcoord; +} + +vec4 texture1DProjLod(const sampler1D sampler, const vec4 coord, const float lod) +{ + vec4 pcoord; + pcoord.x = coord.x / coord.z; + pcoord.w = lod; + __asm vec4_tex_1d_bias __retVal, sampler, pcoord; +} + + + +vec4 texture2DLod(const sampler2D sampler, const vec2 coord, const float lod) +{ + vec4 coord4; + coord4.xy = coord.xy; + coord4.w = lod; + __asm vec4_tex_2d_bias __retVal, sampler, coord4; +} + +vec4 texture2DProjLod(const sampler2D sampler, const vec3 coord, const float lod) +{ + vec4 pcoord; + pcoord.xy = coord.xy / coord.z; + pcoord.w = lod; + __asm vec4_tex_2d_bias __retVal, sampler, pcoord; +} + +vec4 texture2DProjLod(const sampler2D sampler, const vec4 coord, const float lod) +{ + vec4 pcoord; + pcoord.xy = coord.xy / coord.z; + pcoord.w = lod; + __asm vec4_tex_2d_bias __retVal, sampler, pcoord; +} + + +vec4 texture3DLod(const sampler3D sampler, const vec3 coord, const float lod) +{ + vec4 coord4; + coord4.xyz = coord.xyz; + coord4.w = lod; + __asm vec4_tex_3d_bias __retVal, sampler, coord4; +} + +vec4 texture3DProjLod(const sampler3D sampler, const vec4 coord, const float lod) +{ + // do projection here (there's no vec4_tex_3d_bias_proj instruction) + vec4 pcoord; + pcoord.xyz = coord.xyz / coord.w; + pcoord.w = lod; + __asm vec4_tex_3d_bias __retVal, sampler, pcoord; +} + + +vec4 textureCubeLod(const samplerCube sampler, const vec3 coord, const float lod) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = lod; + __asm vec4_tex_cube __retVal, sampler, coord4; +} + + +vec4 shadow1DLod(const sampler1DShadow sampler, const vec3 coord, const float lod) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = lod; + __asm vec4_tex_1d_bias_shadow __retVal, sampler, coord4; +} + +vec4 shadow1DProjLod(const sampler1DShadow sampler, const vec4 coord, + const float lod) +{ + vec4 pcoord; + pcoord.x = coord.x / coord.w; + pcoord.z = coord.z; + pcoord.w = lod; + __asm vec4_tex_1d_bias_shadow __retVal, sampler, pcoord; +} + + +vec4 shadow2DLod(const sampler2DShadow sampler, const vec3 coord, const float lod) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = lod; + __asm vec4_tex_2d_bias_shadow __retVal, sampler, coord4; +} + +vec4 shadow2DProjLod(const sampler2DShadow sampler, const vec4 coord, + const float lod) +{ + vec4 pcoord; + pcoord.xy = coord.xy / coord.w; + pcoord.z = coord.z; + pcoord.w = lod; + __asm vec4_tex_2d_bias_shadow __retVal, sampler, pcoord; +} + + +//// GL_EXT_texture_array + +vec4 texture1DArrayLod(const sampler1DArray sampler, const vec2 coord, const float lod) +{ + vec4 coord4; + coord4.xy = coord; + coord4.w = lod; + __asm vec4_tex_1d_array_bias __retVal, sampler, coord4; +} + + +vec4 texture2DArrayLod(const sampler2DArray sampler, const vec3 coord, const float lod) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = lod; + __asm vec4_tex_2d_array_bias __retVal, sampler, coord4; +} + diff --git a/src/mesa/slang/slang_builtin.c b/src/mesa/slang/slang_builtin.c new file mode 100644 index 0000000000..edb6052cb5 --- /dev/null +++ b/src/mesa/slang/slang_builtin.c @@ -0,0 +1,937 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2008 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_builtin.c + * Resolve built-in uniform vars. + * \author Brian Paul + */ + +#include "main/imports.h" +#include "main/mtypes.h" +#include "shader/program.h" +#include "shader/prog_instruction.h" +#include "shader/prog_parameter.h" +#include "shader/prog_statevars.h" +#include "slang/slang_ir.h" +#include "slang/slang_builtin.h" + + +/** special state token (see below) */ +#define STATE_ARRAY ((gl_state_index) 0xfffff) + + +/** + * Lookup GL state given a variable name, 0, 1 or 2 indexes and a field. + * Allocate room for the state in the given param list and return position + * in the list. + * Yes, this is kind of ugly, but it works. + */ +static GLint +lookup_statevar(const char *var, GLint index1, GLint index2, const char *field, + GLuint *swizzleOut, + struct gl_program_parameter_list *paramList) +{ + /* + * NOTE: The ARB_vertex_program extension specified that matrices get + * loaded in registers in row-major order. With GLSL, we want column- + * major order. So, we need to transpose all matrices here... + */ + static const struct { + const char *name; + gl_state_index matrix; + gl_state_index modifier; + } matrices[] = { + { "gl_ModelViewMatrix", STATE_MODELVIEW_MATRIX, STATE_MATRIX_TRANSPOSE }, + { "gl_ModelViewMatrixInverse", STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVTRANS }, + { "gl_ModelViewMatrixTranspose", STATE_MODELVIEW_MATRIX, 0 }, + { "gl_ModelViewMatrixInverseTranspose", STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVERSE }, + + { "gl_ProjectionMatrix", STATE_PROJECTION_MATRIX, STATE_MATRIX_TRANSPOSE }, + { "gl_ProjectionMatrixInverse", STATE_PROJECTION_MATRIX, STATE_MATRIX_INVTRANS }, + { "gl_ProjectionMatrixTranspose", STATE_PROJECTION_MATRIX, 0 }, + { "gl_ProjectionMatrixInverseTranspose", STATE_PROJECTION_MATRIX, STATE_MATRIX_INVERSE }, + + { "gl_ModelViewProjectionMatrix", STATE_MVP_MATRIX, STATE_MATRIX_TRANSPOSE }, + { "gl_ModelViewProjectionMatrixInverse", STATE_MVP_MATRIX, STATE_MATRIX_INVTRANS }, + { "gl_ModelViewProjectionMatrixTranspose", STATE_MVP_MATRIX, 0 }, + { "gl_ModelViewProjectionMatrixInverseTranspose", STATE_MVP_MATRIX, STATE_MATRIX_INVERSE }, + + { "gl_TextureMatrix", STATE_TEXTURE_MATRIX, STATE_MATRIX_TRANSPOSE }, + { "gl_TextureMatrixInverse", STATE_TEXTURE_MATRIX, STATE_MATRIX_INVTRANS }, + { "gl_TextureMatrixTranspose", STATE_TEXTURE_MATRIX, 0 }, + { "gl_TextureMatrixInverseTranspose", STATE_TEXTURE_MATRIX, STATE_MATRIX_INVERSE }, + + { "gl_NormalMatrix", STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVERSE }, + + { NULL, 0, 0 } + }; + gl_state_index tokens[STATE_LENGTH]; + GLuint i; + GLboolean isMatrix = GL_FALSE; + + for (i = 0; i < STATE_LENGTH; i++) { + tokens[i] = 0; + } + *swizzleOut = SWIZZLE_NOOP; + + /* first, look if var is a pre-defined matrix */ + for (i = 0; matrices[i].name; i++) { + if (strcmp(var, matrices[i].name) == 0) { + tokens[0] = matrices[i].matrix; + /* tokens[1], [2] and [3] filled below */ + tokens[4] = matrices[i].modifier; + isMatrix = GL_TRUE; + break; + } + } + + if (isMatrix) { + if (tokens[0] == STATE_TEXTURE_MATRIX) { + /* texture_matrix[index1][index2] */ + tokens[1] = index1 >= 0 ? index1 : 0; /* which texture matrix */ + index1 = index2; /* move matrix row value to index1 */ + } + if (index1 < 0) { + /* index1 is unused: prevent extra addition at end of function */ + index1 = 0; + } + } + else if (strcmp(var, "gl_DepthRange") == 0) { + tokens[0] = STATE_DEPTH_RANGE; + assert(field); + if (strcmp(field, "near") == 0) { + *swizzleOut = SWIZZLE_XXXX; + } + else if (strcmp(field, "far") == 0) { + *swizzleOut = SWIZZLE_YYYY; + } + else if (strcmp(field, "diff") == 0) { + *swizzleOut = SWIZZLE_ZZZZ; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_ClipPlane") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_CLIPPLANE; + tokens[1] = index1; + } + else if (strcmp(var, "gl_Point") == 0) { + assert(field); + if (strcmp(field, "size") == 0) { + tokens[0] = STATE_POINT_SIZE; + *swizzleOut = SWIZZLE_XXXX; + } + else if (strcmp(field, "sizeMin") == 0) { + tokens[0] = STATE_POINT_SIZE; + *swizzleOut = SWIZZLE_YYYY; + } + else if (strcmp(field, "sizeMax") == 0) { + tokens[0] = STATE_POINT_SIZE; + *swizzleOut = SWIZZLE_ZZZZ; + } + else if (strcmp(field, "fadeThresholdSize") == 0) { + tokens[0] = STATE_POINT_SIZE; + *swizzleOut = SWIZZLE_WWWW; + } + else if (strcmp(field, "distanceConstantAttenuation") == 0) { + tokens[0] = STATE_POINT_ATTENUATION; + *swizzleOut = SWIZZLE_XXXX; + } + else if (strcmp(field, "distanceLinearAttenuation") == 0) { + tokens[0] = STATE_POINT_ATTENUATION; + *swizzleOut = SWIZZLE_YYYY; + } + else if (strcmp(field, "distanceQuadraticAttenuation") == 0) { + tokens[0] = STATE_POINT_ATTENUATION; + *swizzleOut = SWIZZLE_ZZZZ; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_FrontMaterial") == 0 || + strcmp(var, "gl_BackMaterial") == 0) { + tokens[0] = STATE_MATERIAL; + if (strcmp(var, "gl_FrontMaterial") == 0) + tokens[1] = 0; + else + tokens[1] = 1; + assert(field); + if (strcmp(field, "emission") == 0) { + tokens[2] = STATE_EMISSION; + } + else if (strcmp(field, "ambient") == 0) { + tokens[2] = STATE_AMBIENT; + } + else if (strcmp(field, "diffuse") == 0) { + tokens[2] = STATE_DIFFUSE; + } + else if (strcmp(field, "specular") == 0) { + tokens[2] = STATE_SPECULAR; + } + else if (strcmp(field, "shininess") == 0) { + tokens[2] = STATE_SHININESS; + *swizzleOut = SWIZZLE_XXXX; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_LightSource") == 0) { + if (!field || index1 < 0) + return -1; + + tokens[0] = STATE_LIGHT; + tokens[1] = index1; + + if (strcmp(field, "ambient") == 0) { + tokens[2] = STATE_AMBIENT; + } + else if (strcmp(field, "diffuse") == 0) { + tokens[2] = STATE_DIFFUSE; + } + else if (strcmp(field, "specular") == 0) { + tokens[2] = STATE_SPECULAR; + } + else if (strcmp(field, "position") == 0) { + tokens[2] = STATE_POSITION; + } + else if (strcmp(field, "halfVector") == 0) { + tokens[2] = STATE_HALF_VECTOR; + } + else if (strcmp(field, "spotDirection") == 0) { + tokens[2] = STATE_SPOT_DIRECTION; + } + else if (strcmp(field, "spotCosCutoff") == 0) { + tokens[2] = STATE_SPOT_DIRECTION; + *swizzleOut = SWIZZLE_WWWW; + } + else if (strcmp(field, "spotCutoff") == 0) { + tokens[2] = STATE_SPOT_CUTOFF; + *swizzleOut = SWIZZLE_XXXX; + } + else if (strcmp(field, "spotExponent") == 0) { + tokens[2] = STATE_ATTENUATION; + *swizzleOut = SWIZZLE_WWWW; + } + else if (strcmp(field, "constantAttenuation") == 0) { + tokens[2] = STATE_ATTENUATION; + *swizzleOut = SWIZZLE_XXXX; + } + else if (strcmp(field, "linearAttenuation") == 0) { + tokens[2] = STATE_ATTENUATION; + *swizzleOut = SWIZZLE_YYYY; + } + else if (strcmp(field, "quadraticAttenuation") == 0) { + tokens[2] = STATE_ATTENUATION; + *swizzleOut = SWIZZLE_ZZZZ; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_LightModel") == 0) { + if (strcmp(field, "ambient") == 0) { + tokens[0] = STATE_LIGHTMODEL_AMBIENT; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_FrontLightModelProduct") == 0) { + if (strcmp(field, "sceneColor") == 0) { + tokens[0] = STATE_LIGHTMODEL_SCENECOLOR; + tokens[1] = 0; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_BackLightModelProduct") == 0) { + if (strcmp(field, "sceneColor") == 0) { + tokens[0] = STATE_LIGHTMODEL_SCENECOLOR; + tokens[1] = 1; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_FrontLightProduct") == 0 || + strcmp(var, "gl_BackLightProduct") == 0) { + if (index1 < 0 || !field) + return -1; + + tokens[0] = STATE_LIGHTPROD; + tokens[1] = index1; /* light number */ + if (strcmp(var, "gl_FrontLightProduct") == 0) { + tokens[2] = 0; /* front */ + } + else { + tokens[2] = 1; /* back */ + } + if (strcmp(field, "ambient") == 0) { + tokens[3] = STATE_AMBIENT; + } + else if (strcmp(field, "diffuse") == 0) { + tokens[3] = STATE_DIFFUSE; + } + else if (strcmp(field, "specular") == 0) { + tokens[3] = STATE_SPECULAR; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_TextureEnvColor") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXENV_COLOR; + tokens[1] = index1; + } + else if (strcmp(var, "gl_EyePlaneS") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_EYE_S; + } + else if (strcmp(var, "gl_EyePlaneT") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_EYE_T; + } + else if (strcmp(var, "gl_EyePlaneR") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_EYE_R; + } + else if (strcmp(var, "gl_EyePlaneQ") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_EYE_Q; + } + else if (strcmp(var, "gl_ObjectPlaneS") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_OBJECT_S; + } + else if (strcmp(var, "gl_ObjectPlaneT") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_OBJECT_T; + } + else if (strcmp(var, "gl_ObjectPlaneR") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_OBJECT_R; + } + else if (strcmp(var, "gl_ObjectPlaneQ") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_OBJECT_Q; + } + else if (strcmp(var, "gl_Fog") == 0) { + if (strcmp(field, "color") == 0) { + tokens[0] = STATE_FOG_COLOR; + } + else if (strcmp(field, "density") == 0) { + tokens[0] = STATE_FOG_PARAMS; + *swizzleOut = SWIZZLE_XXXX; + } + else if (strcmp(field, "start") == 0) { + tokens[0] = STATE_FOG_PARAMS; + *swizzleOut = SWIZZLE_YYYY; + } + else if (strcmp(field, "end") == 0) { + tokens[0] = STATE_FOG_PARAMS; + *swizzleOut = SWIZZLE_ZZZZ; + } + else if (strcmp(field, "scale") == 0) { + tokens[0] = STATE_FOG_PARAMS; + *swizzleOut = SWIZZLE_WWWW; + } + else { + return -1; + } + } + else { + return -1; + } + + if (isMatrix) { + /* load all four columns of matrix */ + GLint pos[4]; + GLuint j; + for (j = 0; j < 4; j++) { + tokens[2] = tokens[3] = j; /* jth row of matrix */ + pos[j] = _mesa_add_state_reference(paramList, tokens); + assert(pos[j] >= 0); + ASSERT(pos[j] >= 0); + } + return pos[0] + index1; + } + else { + /* allocate a single register */ + GLint pos = _mesa_add_state_reference(paramList, tokens); + ASSERT(pos >= 0); + return pos; + } +} + + + +/** + * Given a variable name and datatype, emit uniform/constant buffer + * entries which will store that state variable. + * For example, if name="gl_LightSource" we'll emit 64 state variable + * vectors/references and return position where that data starts. This will + * allow run-time array indexing into the light source array. + * + * Note that this is a recursive function. + * + * \return -1 if error, else index of start of data in the program parameter list + */ +static GLint +emit_statevars(const char *name, int array_len, + const slang_type_specifier *type, + gl_state_index tokens[STATE_LENGTH], + struct gl_program_parameter_list *paramList) +{ + if (type->type == SLANG_SPEC_ARRAY) { + GLint i, pos = -1; + assert(array_len > 0); + if (strcmp(name, "gl_ClipPlane") == 0) { + tokens[0] = STATE_CLIPPLANE; + } + else if (strcmp(name, "gl_LightSource") == 0) { + tokens[0] = STATE_LIGHT; + } + else if (strcmp(name, "gl_FrontLightProduct") == 0) { + tokens[0] = STATE_LIGHTPROD; + tokens[2] = 0; /* front */ + } + else if (strcmp(name, "gl_BackLightProduct") == 0) { + tokens[0] = STATE_LIGHTPROD; + tokens[2] = 1; /* back */ + } + else if (strcmp(name, "gl_TextureEnvColor") == 0) { + tokens[0] = STATE_TEXENV_COLOR; + } + else if (strcmp(name, "gl_EyePlaneS") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_EYE_S; + } + else if (strcmp(name, "gl_EyePlaneT") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_EYE_T; + } + else if (strcmp(name, "gl_EyePlaneR") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_EYE_R; + } + else if (strcmp(name, "gl_EyePlaneQ") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_EYE_Q; + } + else if (strcmp(name, "gl_ObjectPlaneS") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_OBJECT_S; + } + else if (strcmp(name, "gl_ObjectPlaneT") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_OBJECT_T; + } + else if (strcmp(name, "gl_ObjectPlaneR") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_OBJECT_R; + } + else if (strcmp(name, "gl_ObjectPlaneQ") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_OBJECT_Q; + } + else { + return -1; /* invalid array name */ + } + for (i = 0; i < array_len; i++) { + GLint p; + tokens[1] = i; + p = emit_statevars(NULL, 0, type->_array, tokens, paramList); + if (i == 0) + pos = p; + } + return pos; + } + else if (type->type == SLANG_SPEC_STRUCT) { + const slang_variable_scope *fields = type->_struct->fields; + GLuint i, pos = 0; + for (i = 0; i < fields->num_variables; i++) { + const slang_variable *var = fields->variables[i]; + GLint p = emit_statevars(var->a_name, 0, &var->type.specifier, + tokens, paramList); + if (i == 0) + pos = p; + } + return pos; + } + else { + GLint pos; + assert(type->type == SLANG_SPEC_VEC4 || + type->type == SLANG_SPEC_VEC3 || + type->type == SLANG_SPEC_VEC2 || + type->type == SLANG_SPEC_FLOAT || + type->type == SLANG_SPEC_IVEC4 || + type->type == SLANG_SPEC_IVEC3 || + type->type == SLANG_SPEC_IVEC2 || + type->type == SLANG_SPEC_INT); + if (name) { + GLint t; + + if (tokens[0] == STATE_LIGHT) + t = 2; + else if (tokens[0] == STATE_LIGHTPROD) + t = 3; + else + return -1; /* invalid array name */ + + if (strcmp(name, "ambient") == 0) { + tokens[t] = STATE_AMBIENT; + } + else if (strcmp(name, "diffuse") == 0) { + tokens[t] = STATE_DIFFUSE; + } + else if (strcmp(name, "specular") == 0) { + tokens[t] = STATE_SPECULAR; + } + else if (strcmp(name, "position") == 0) { + tokens[t] = STATE_POSITION; + } + else if (strcmp(name, "halfVector") == 0) { + tokens[t] = STATE_HALF_VECTOR; + } + else if (strcmp(name, "spotDirection") == 0) { + tokens[t] = STATE_SPOT_DIRECTION; /* xyz components */ + } + else if (strcmp(name, "spotCosCutoff") == 0) { + tokens[t] = STATE_SPOT_DIRECTION; /* w component */ + } + + else if (strcmp(name, "constantAttenuation") == 0) { + tokens[t] = STATE_ATTENUATION; /* x component */ + } + else if (strcmp(name, "linearAttenuation") == 0) { + tokens[t] = STATE_ATTENUATION; /* y component */ + } + else if (strcmp(name, "quadraticAttenuation") == 0) { + tokens[t] = STATE_ATTENUATION; /* z component */ + } + else if (strcmp(name, "spotExponent") == 0) { + tokens[t] = STATE_ATTENUATION; /* w = spot exponent */ + } + + else if (strcmp(name, "spotCutoff") == 0) { + tokens[t] = STATE_SPOT_CUTOFF; /* x component */ + } + + else { + return -1; /* invalid field name */ + } + } + + pos = _mesa_add_state_reference(paramList, tokens); + return pos; + } + + return 1; +} + + +/** + * Unroll the named built-in uniform variable into a sequence of state + * vars in the given parameter list. + */ +static GLint +alloc_state_var_array(const slang_variable *var, + struct gl_program_parameter_list *paramList) +{ + gl_state_index tokens[STATE_LENGTH]; + GLuint i; + GLint pos; + + /* Initialize the state tokens array. This is very important. + * When we call _mesa_add_state_reference() it'll searches the parameter + * list to see if the given statevar token sequence is already present. + * This is normally a good thing since it prevents redundant values in the + * constant buffer. + * + * But when we're building arrays of state this can be bad. For example, + * consider this fragment of GLSL code: + * foo = gl_LightSource[3].diffuse; + * ... + * bar = gl_LightSource[i].diffuse; + * + * When we unroll the gl_LightSource array (for "bar") we want to re-emit + * gl_LightSource[3].diffuse and not re-use the first instance (from "foo") + * since that would upset the array layout. We handle this situation by + * setting the last token in the state var token array to the special + * value STATE_ARRAY. + * This token will only be set for array state. We can hijack the last + * element in the array for this since it's never used for light, clipplane + * or texture env array state. + */ + for (i = 0; i < STATE_LENGTH; i++) + tokens[i] = 0; + tokens[STATE_LENGTH - 1] = STATE_ARRAY; + + pos = emit_statevars(var->a_name, var->array_len, &var->type.specifier, + tokens, paramList); + + return pos; +} + + + +/** + * Allocate storage for a pre-defined uniform (a GL state variable). + * As a memory-saving optimization, we try to only allocate storage for + * state vars that are actually used. + * + * Arrays such as gl_LightSource are handled specially. For an expression + * like "gl_LightSource[2].diffuse", we can allocate a single uniform/constant + * slot and return the index. In this case, we return direct=TRUE. + * + * Buf for something like "gl_LightSource[i].diffuse" we don't know the value + * of 'i' at compile time so we need to "unroll" the gl_LightSource array + * into a consecutive sequence of uniform/constant slots so it can be indexed + * at runtime. In this case, we return direct=FALSE. + * + * Currently, all pre-defined uniforms are in one of these forms: + * var + * var[i] + * var.field + * var[i].field + * var[i][j] + * + * \return -1 upon error, else position in paramList of the state variable/data + */ +GLint +_slang_alloc_statevar(slang_ir_node *n, + struct gl_program_parameter_list *paramList, + GLboolean *direct) +{ + slang_ir_node *n0 = n; + const char *field = NULL; + GLint index1 = -1, index2 = -1; + GLuint swizzle; + + *direct = GL_TRUE; + + if (n->Opcode == IR_FIELD) { + field = n->Field; + n = n->Children[0]; + } + + if (n->Opcode == IR_ELEMENT) { + if (n->Children[1]->Opcode == IR_FLOAT) { + index1 = (GLint) n->Children[1]->Value[0]; + } + else { + *direct = GL_FALSE; + } + n = n->Children[0]; + } + + if (n->Opcode == IR_ELEMENT) { + /* XXX can only handle constant indexes for now */ + if (n->Children[1]->Opcode == IR_FLOAT) { + /* two-dimensional array index: mat[i][j] */ + index2 = index1; + index1 = (GLint) n->Children[1]->Value[0]; + } + else { + *direct = GL_FALSE; + } + n = n->Children[0]; + } + + assert(n->Opcode == IR_VAR); + + if (*direct) { + const char *var = (const char *) n->Var->a_name; + GLint pos = + lookup_statevar(var, index1, index2, field, &swizzle, paramList); + if (pos >= 0) { + /* newly resolved storage for the statevar/constant/uniform */ + n0->Store->File = PROGRAM_STATE_VAR; + n0->Store->Index = pos; + n0->Store->Swizzle = swizzle; + n0->Store->Parent = NULL; + return pos; + } + } + + *direct = GL_FALSE; + return alloc_state_var_array(n->Var, paramList); +} + + + + +#define SWIZZLE_ZWWW MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W) + + +/** Predefined shader inputs */ +struct input_info +{ + const char *Name; + GLuint Attrib; + GLenum Type; + GLuint Swizzle; +}; + +/** Predefined vertex shader inputs/attributes */ +static const struct input_info vertInputs[] = { + { "gl_Vertex", VERT_ATTRIB_POS, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_Normal", VERT_ATTRIB_NORMAL, GL_FLOAT_VEC3, SWIZZLE_NOOP }, + { "gl_Color", VERT_ATTRIB_COLOR0, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_SecondaryColor", VERT_ATTRIB_COLOR1, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_FogCoord", VERT_ATTRIB_FOG, GL_FLOAT, SWIZZLE_XXXX }, + { "gl_MultiTexCoord0", VERT_ATTRIB_TEX0, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord1", VERT_ATTRIB_TEX1, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord2", VERT_ATTRIB_TEX2, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord3", VERT_ATTRIB_TEX3, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord4", VERT_ATTRIB_TEX4, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord5", VERT_ATTRIB_TEX5, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord6", VERT_ATTRIB_TEX6, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord7", VERT_ATTRIB_TEX7, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { NULL, 0, GL_NONE, SWIZZLE_NOOP } +}; + +/** Predefined fragment shader inputs */ +static const struct input_info fragInputs[] = { + { "gl_FragCoord", FRAG_ATTRIB_WPOS, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_Color", FRAG_ATTRIB_COL0, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_SecondaryColor", FRAG_ATTRIB_COL1, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_TexCoord", FRAG_ATTRIB_TEX0, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_FogFragCoord", FRAG_ATTRIB_FOGC, GL_FLOAT, SWIZZLE_XXXX }, + { "gl_FrontFacing", FRAG_ATTRIB_FACE, GL_FLOAT, SWIZZLE_XXXX }, + { "gl_PointCoord", FRAG_ATTRIB_PNTC, GL_FLOAT_VEC2, SWIZZLE_XYZW }, + { NULL, 0, GL_NONE, SWIZZLE_NOOP } +}; + + +/** + * Return the VERT_ATTRIB_* or FRAG_ATTRIB_* value that corresponds to + * a vertex or fragment program input variable. Return -1 if the input + * name is invalid. + * XXX return size too + */ +GLint +_slang_input_index(const char *name, GLenum target, GLuint *swizzleOut) +{ + const struct input_info *inputs; + GLuint i; + + switch (target) { + case GL_VERTEX_PROGRAM_ARB: + inputs = vertInputs; + break; + case GL_FRAGMENT_PROGRAM_ARB: + inputs = fragInputs; + break; + /* XXX geom program */ + default: + _mesa_problem(NULL, "bad target in _slang_input_index"); + return -1; + } + + ASSERT(MAX_TEXTURE_COORD_UNITS == 8); /* if this fails, fix vertInputs above */ + + for (i = 0; inputs[i].Name; i++) { + if (strcmp(inputs[i].Name, name) == 0) { + /* found */ + *swizzleOut = inputs[i].Swizzle; + return inputs[i].Attrib; + } + } + return -1; +} + + +/** + * Return name of the given vertex attribute (VERT_ATTRIB_x). + */ +const char * +_slang_vert_attrib_name(GLuint attrib) +{ + GLuint i; + assert(attrib < VERT_ATTRIB_GENERIC0); + for (i = 0; vertInputs[i].Name; i++) { + if (vertInputs[i].Attrib == attrib) + return vertInputs[i].Name; + } + return NULL; +} + + +/** + * Return type (GL_FLOAT, GL_FLOAT_VEC2, etc) of the given vertex + * attribute (VERT_ATTRIB_x). + */ +GLenum +_slang_vert_attrib_type(GLuint attrib) +{ + GLuint i; + assert(attrib < VERT_ATTRIB_GENERIC0); + for (i = 0; vertInputs[i].Name; i++) { + if (vertInputs[i].Attrib == attrib) + return vertInputs[i].Type; + } + return GL_NONE; +} + + + + + +/** Predefined shader output info */ +struct output_info +{ + const char *Name; + GLuint Attrib; + GLenum Type; +}; + +/** Predefined vertex shader outputs */ +static const struct output_info vertOutputs[] = { + { "gl_Position", VERT_RESULT_HPOS, GL_FLOAT_VEC4 }, + { "gl_FrontColor", VERT_RESULT_COL0, GL_FLOAT_VEC4 }, + { "gl_BackColor", VERT_RESULT_BFC0, GL_FLOAT_VEC4 }, + { "gl_FrontSecondaryColor", VERT_RESULT_COL1, GL_FLOAT_VEC4 }, + { "gl_BackSecondaryColor", VERT_RESULT_BFC1, GL_FLOAT_VEC4 }, + { "gl_TexCoord", VERT_RESULT_TEX0, GL_FLOAT_VEC4 }, + { "gl_FogFragCoord", VERT_RESULT_FOGC, GL_FLOAT }, + { "gl_PointSize", VERT_RESULT_PSIZ, GL_FLOAT }, + { NULL, 0, GL_NONE } +}; + +/** Predefined fragment shader outputs */ +static const struct output_info fragOutputs[] = { + { "gl_FragColor", FRAG_RESULT_COLOR, GL_FLOAT_VEC4 }, + { "gl_FragDepth", FRAG_RESULT_DEPTH, GL_FLOAT }, + { "gl_FragData", FRAG_RESULT_DATA0, GL_FLOAT_VEC4 }, + { NULL, 0, GL_NONE } +}; + + +/** + * Return the VERT_RESULT_* or FRAG_RESULT_* value that corresponds to + * a vertex or fragment program output variable. Return -1 for an invalid + * output name. + */ +GLint +_slang_output_index(const char *name, GLenum target) +{ + const struct output_info *outputs; + GLuint i; + + switch (target) { + case GL_VERTEX_PROGRAM_ARB: + outputs = vertOutputs; + break; + case GL_FRAGMENT_PROGRAM_ARB: + outputs = fragOutputs; + break; + /* XXX geom program */ + default: + _mesa_problem(NULL, "bad target in _slang_output_index"); + return -1; + } + + for (i = 0; outputs[i].Name; i++) { + if (strcmp(outputs[i].Name, name) == 0) { + /* found */ + return outputs[i].Attrib; + } + } + return -1; +} + + +/** + * Given a VERT_RESULT_x index, return the corresponding string name. + */ +const char * +_slang_vertex_output_name(gl_vert_result index) +{ + if (index < Elements(vertOutputs)) + return vertOutputs[index].Name; + else + return NULL; +} + + +/** + * Given a FRAG_RESULT_x index, return the corresponding string name. + */ +const char * +_slang_fragment_output_name(gl_frag_result index) +{ + if (index < Elements(fragOutputs)) + return fragOutputs[index].Name; + else + return NULL; +} + + +/** + * Given a VERT_RESULT_x index, return the corresponding varying + * var's datatype. + */ +GLenum +_slang_vertex_output_type(gl_vert_result index) +{ + if (index < Elements(vertOutputs)) + return vertOutputs[index].Type; + else + return GL_NONE; +} diff --git a/src/mesa/slang/slang_builtin.h b/src/mesa/slang/slang_builtin.h new file mode 100644 index 0000000000..c3021ca33c --- /dev/null +++ b/src/mesa/slang/slang_builtin.h @@ -0,0 +1,64 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef SLANG_BUILTIN_H +#define SLANG_BUILTIN_H + +#include "shader/prog_parameter.h" +#include "slang_utility.h" +#include "slang_ir.h" + + +extern GLint +_slang_alloc_statevar(slang_ir_node *n, + struct gl_program_parameter_list *paramList, + GLboolean *direct); + + +extern GLint +_slang_input_index(const char *name, GLenum target, GLuint *swizzleOut); + +extern GLint +_slang_output_index(const char *name, GLenum target); + + +extern const char * +_slang_vert_attrib_name(GLuint attrib); + +extern GLenum +_slang_vert_attrib_type(GLuint attrib); + + +const char * +_slang_vertex_output_name(gl_vert_result index); + +const char * +_slang_fragment_output_name(gl_frag_result index); + +GLenum +_slang_vertex_output_type(gl_vert_result index); + + +#endif /* SLANG_BUILTIN_H */ diff --git a/src/mesa/slang/slang_codegen.c b/src/mesa/slang/slang_codegen.c new file mode 100644 index 0000000000..0504d47765 --- /dev/null +++ b/src/mesa/slang/slang_codegen.c @@ -0,0 +1,5357 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2008 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_codegen.c + * Generate IR tree from AST. + * \author Brian Paul + */ + + +/*** + *** NOTES: + *** The new_() functions return a new instance of a simple IR node. + *** The gen_() functions generate larger IR trees from the simple nodes. + ***/ + + + +#include "main/imports.h" +#include "main/macros.h" +#include "main/mtypes.h" +#include "shader/program.h" +#include "shader/prog_instruction.h" +#include "shader/prog_parameter.h" +#include "shader/prog_print.h" +#include "shader/prog_statevars.h" +#include "slang_typeinfo.h" +#include "slang_builtin.h" +#include "slang_codegen.h" +#include "slang_compile.h" +#include "slang_label.h" +#include "slang_mem.h" +#include "slang_simplify.h" +#include "slang_emit.h" +#include "slang_vartable.h" +#include "slang_ir.h" +#include "slang_print.h" + + +/** Max iterations to unroll */ +const GLuint MAX_FOR_LOOP_UNROLL_ITERATIONS = 32; + +/** Max for-loop body size (in slang operations) to unroll */ +const GLuint MAX_FOR_LOOP_UNROLL_BODY_SIZE = 50; + +/** Max for-loop body complexity to unroll. + * We'll compute complexity as the product of the number of iterations + * and the size of the body. So long-ish loops with very simple bodies + * can be unrolled, as well as short loops with larger bodies. + */ +const GLuint MAX_FOR_LOOP_UNROLL_COMPLEXITY = 256; + + + +static slang_ir_node * +_slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper); + +static void +slang_substitute(slang_assemble_ctx *A, slang_operation *oper, + GLuint substCount, slang_variable **substOld, + slang_operation **substNew, GLboolean isLHS); + + +/** + * Retrieves type information about an operation. + * Returns GL_TRUE on success. + * Returns GL_FALSE otherwise. + */ +static GLboolean +typeof_operation(const struct slang_assemble_ctx_ *A, + slang_operation *op, + slang_typeinfo *ti) +{ + return _slang_typeof_operation(op, &A->space, ti, A->atoms, A->log); +} + + +static GLboolean +is_sampler_type(const slang_fully_specified_type *t) +{ + switch (t->specifier.type) { + case SLANG_SPEC_SAMPLER_1D: + case SLANG_SPEC_SAMPLER_2D: + case SLANG_SPEC_SAMPLER_3D: + case SLANG_SPEC_SAMPLER_CUBE: + case SLANG_SPEC_SAMPLER_1D_SHADOW: + case SLANG_SPEC_SAMPLER_2D_SHADOW: + case SLANG_SPEC_SAMPLER_RECT: + case SLANG_SPEC_SAMPLER_RECT_SHADOW: + case SLANG_SPEC_SAMPLER_1D_ARRAY: + case SLANG_SPEC_SAMPLER_2D_ARRAY: + case SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW: + case SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Return the offset (in floats or ints) of the named field within + * the given struct. Return -1 if field not found. + * If field is NULL, return the size of the struct instead. + */ +static GLint +_slang_field_offset(const slang_type_specifier *spec, slang_atom field) +{ + GLint offset = 0; + GLuint i; + for (i = 0; i < spec->_struct->fields->num_variables; i++) { + const slang_variable *v = spec->_struct->fields->variables[i]; + const GLuint sz = _slang_sizeof_type_specifier(&v->type.specifier); + if (sz > 1) { + /* types larger than 1 float are register (4-float) aligned */ + offset = (offset + 3) & ~3; + } + if (field && v->a_name == field) { + return offset; + } + offset += sz; + } + if (field) + return -1; /* field not found */ + else + return offset; /* struct size */ +} + + +/** + * Return the size (in floats) of the given type specifier. + * If the size is greater than 4, the size should be a multiple of 4 + * so that the correct number of 4-float registers are allocated. + * For example, a mat3x2 is size 12 because we want to store the + * 3 columns in 3 float[4] registers. + */ +GLuint +_slang_sizeof_type_specifier(const slang_type_specifier *spec) +{ + GLuint sz; + switch (spec->type) { + case SLANG_SPEC_VOID: + sz = 0; + break; + case SLANG_SPEC_BOOL: + sz = 1; + break; + case SLANG_SPEC_BVEC2: + sz = 2; + break; + case SLANG_SPEC_BVEC3: + sz = 3; + break; + case SLANG_SPEC_BVEC4: + sz = 4; + break; + case SLANG_SPEC_INT: + sz = 1; + break; + case SLANG_SPEC_IVEC2: + sz = 2; + break; + case SLANG_SPEC_IVEC3: + sz = 3; + break; + case SLANG_SPEC_IVEC4: + sz = 4; + break; + case SLANG_SPEC_FLOAT: + sz = 1; + break; + case SLANG_SPEC_VEC2: + sz = 2; + break; + case SLANG_SPEC_VEC3: + sz = 3; + break; + case SLANG_SPEC_VEC4: + sz = 4; + break; + case SLANG_SPEC_MAT2: + sz = 2 * 4; /* 2 columns (regs) */ + break; + case SLANG_SPEC_MAT3: + sz = 3 * 4; + break; + case SLANG_SPEC_MAT4: + sz = 4 * 4; + break; + case SLANG_SPEC_MAT23: + sz = 2 * 4; /* 2 columns (regs) */ + break; + case SLANG_SPEC_MAT32: + sz = 3 * 4; /* 3 columns (regs) */ + break; + case SLANG_SPEC_MAT24: + sz = 2 * 4; + break; + case SLANG_SPEC_MAT42: + sz = 4 * 4; /* 4 columns (regs) */ + break; + case SLANG_SPEC_MAT34: + sz = 3 * 4; + break; + case SLANG_SPEC_MAT43: + sz = 4 * 4; /* 4 columns (regs) */ + break; + case SLANG_SPEC_SAMPLER_1D: + case SLANG_SPEC_SAMPLER_2D: + case SLANG_SPEC_SAMPLER_3D: + case SLANG_SPEC_SAMPLER_CUBE: + case SLANG_SPEC_SAMPLER_1D_SHADOW: + case SLANG_SPEC_SAMPLER_2D_SHADOW: + case SLANG_SPEC_SAMPLER_RECT: + case SLANG_SPEC_SAMPLER_RECT_SHADOW: + case SLANG_SPEC_SAMPLER_1D_ARRAY: + case SLANG_SPEC_SAMPLER_2D_ARRAY: + case SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW: + case SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW: + sz = 1; /* a sampler is basically just an integer index */ + break; + case SLANG_SPEC_STRUCT: + sz = _slang_field_offset(spec, 0); /* special use */ + if (sz == 1) { + /* 1-float structs are actually troublesome to deal with since they + * might get placed at R.x, R.y, R.z or R.z. Return size=2 to + * ensure the object is placed at R.x + */ + sz = 2; + } + else if (sz > 4) { + sz = (sz + 3) & ~0x3; /* round up to multiple of four */ + } + break; + case SLANG_SPEC_ARRAY: + sz = _slang_sizeof_type_specifier(spec->_array); + break; + default: + _mesa_problem(NULL, "Unexpected type in _slang_sizeof_type_specifier()"); + sz = 0; + } + + if (sz > 4) { + /* if size is > 4, it should be a multiple of four */ + assert((sz & 0x3) == 0); + } + return sz; +} + + +/** + * Query variable/array length (number of elements). + * This is slightly non-trivial because there are two ways to express + * arrays: "float x[3]" vs. "float[3] x". + * \return the length of the array for the given variable, or 0 if not an array + */ +static GLint +_slang_array_length(const slang_variable *var) +{ + if (var->type.array_len > 0) { + /* Ex: float[4] x; */ + return var->type.array_len; + } + if (var->array_len > 0) { + /* Ex: float x[4]; */ + return var->array_len; + } + return 0; +} + + +/** + * Compute total size of array give size of element, number of elements. + * \return size in floats + */ +static GLint +_slang_array_size(GLint elemSize, GLint arrayLen) +{ + GLint total; + assert(elemSize > 0); + if (arrayLen > 1) { + /* round up base type to multiple of 4 */ + total = ((elemSize + 3) & ~0x3) * MAX2(arrayLen, 1); + } + else { + total = elemSize; + } + return total; +} + + +/** + * Return the TEXTURE_*_INDEX value that corresponds to a sampler type, + * or -1 if the type is not a sampler. + */ +static GLint +sampler_to_texture_index(const slang_type_specifier_type type) +{ + switch (type) { + case SLANG_SPEC_SAMPLER_1D: + return TEXTURE_1D_INDEX; + case SLANG_SPEC_SAMPLER_2D: + return TEXTURE_2D_INDEX; + case SLANG_SPEC_SAMPLER_3D: + return TEXTURE_3D_INDEX; + case SLANG_SPEC_SAMPLER_CUBE: + return TEXTURE_CUBE_INDEX; + case SLANG_SPEC_SAMPLER_1D_SHADOW: + return TEXTURE_1D_INDEX; /* XXX fix */ + case SLANG_SPEC_SAMPLER_2D_SHADOW: + return TEXTURE_2D_INDEX; /* XXX fix */ + case SLANG_SPEC_SAMPLER_RECT: + return TEXTURE_RECT_INDEX; + case SLANG_SPEC_SAMPLER_RECT_SHADOW: + return TEXTURE_RECT_INDEX; /* XXX fix */ + case SLANG_SPEC_SAMPLER_1D_ARRAY: + return TEXTURE_1D_ARRAY_INDEX; + case SLANG_SPEC_SAMPLER_2D_ARRAY: + return TEXTURE_2D_ARRAY_INDEX; + case SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW: + return TEXTURE_1D_ARRAY_INDEX; + case SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW: + return TEXTURE_2D_ARRAY_INDEX; + default: + return -1; + } +} + + +/** helper to build a SLANG_OPER_IDENTIFIER node */ +static void +slang_operation_identifier(slang_operation *oper, + slang_assemble_ctx *A, + const char *name) +{ + oper->type = SLANG_OPER_IDENTIFIER; + oper->a_id = slang_atom_pool_atom(A->atoms, name); +} + + +/** + * Called when we begin code/IR generation for a new while/do/for loop. + */ +static void +push_loop(slang_assemble_ctx *A, slang_operation *loopOper, slang_ir_node *loopIR) +{ + A->LoopOperStack[A->LoopDepth] = loopOper; + A->LoopIRStack[A->LoopDepth] = loopIR; + A->LoopDepth++; +} + + +/** + * Called when we end code/IR generation for a new while/do/for loop. + */ +static void +pop_loop(slang_assemble_ctx *A) +{ + assert(A->LoopDepth > 0); + A->LoopDepth--; +} + + +/** + * Return pointer to slang_operation for the loop we're currently inside, + * or NULL if not in a loop. + */ +static const slang_operation * +current_loop_oper(const slang_assemble_ctx *A) +{ + if (A->LoopDepth > 0) + return A->LoopOperStack[A->LoopDepth - 1]; + else + return NULL; +} + + +/** + * Return pointer to slang_ir_node for the loop we're currently inside, + * or NULL if not in a loop. + */ +static slang_ir_node * +current_loop_ir(const slang_assemble_ctx *A) +{ + if (A->LoopDepth > 0) + return A->LoopIRStack[A->LoopDepth - 1]; + else + return NULL; +} + + +/**********************************************************************/ + + +/** + * Map "_asm foo" to IR_FOO, etc. + */ +typedef struct +{ + const char *Name; + slang_ir_opcode Opcode; + GLuint HaveRetValue, NumParams; +} slang_asm_info; + + +static slang_asm_info AsmInfo[] = { + /* vec4 binary op */ + { "vec4_add", IR_ADD, 1, 2 }, + { "vec4_subtract", IR_SUB, 1, 2 }, + { "vec4_multiply", IR_MUL, 1, 2 }, + { "vec4_dot", IR_DOT4, 1, 2 }, + { "vec3_dot", IR_DOT3, 1, 2 }, + { "vec2_dot", IR_DOT2, 1, 2 }, + { "vec3_nrm", IR_NRM3, 1, 1 }, + { "vec4_nrm", IR_NRM4, 1, 1 }, + { "vec3_cross", IR_CROSS, 1, 2 }, + { "vec4_lrp", IR_LRP, 1, 3 }, + { "vec4_min", IR_MIN, 1, 2 }, + { "vec4_max", IR_MAX, 1, 2 }, + { "vec4_cmp", IR_CMP, 1, 3 }, + { "vec4_clamp", IR_CLAMP, 1, 3 }, + { "vec4_seq", IR_SEQUAL, 1, 2 }, + { "vec4_sne", IR_SNEQUAL, 1, 2 }, + { "vec4_sge", IR_SGE, 1, 2 }, + { "vec4_sgt", IR_SGT, 1, 2 }, + { "vec4_sle", IR_SLE, 1, 2 }, + { "vec4_slt", IR_SLT, 1, 2 }, + /* vec4 unary */ + { "vec4_move", IR_MOVE, 1, 1 }, + { "vec4_floor", IR_FLOOR, 1, 1 }, + { "vec4_frac", IR_FRAC, 1, 1 }, + { "vec4_abs", IR_ABS, 1, 1 }, + { "vec4_negate", IR_NEG, 1, 1 }, + { "vec4_ddx", IR_DDX, 1, 1 }, + { "vec4_ddy", IR_DDY, 1, 1 }, + /* float binary op */ + { "float_power", IR_POW, 1, 2 }, + /* texture / sampler */ + { "vec4_tex_1d", IR_TEX, 1, 2 }, + { "vec4_tex_1d_bias", IR_TEXB, 1, 2 }, /* 1d w/ bias */ + { "vec4_tex_1d_proj", IR_TEXP, 1, 2 }, /* 1d w/ projection */ + { "vec4_tex_2d", IR_TEX, 1, 2 }, + { "vec4_tex_2d_bias", IR_TEXB, 1, 2 }, /* 2d w/ bias */ + { "vec4_tex_2d_proj", IR_TEXP, 1, 2 }, /* 2d w/ projection */ + { "vec4_tex_3d", IR_TEX, 1, 2 }, + { "vec4_tex_3d_bias", IR_TEXB, 1, 2 }, /* 3d w/ bias */ + { "vec4_tex_3d_proj", IR_TEXP, 1, 2 }, /* 3d w/ projection */ + { "vec4_tex_cube", IR_TEX, 1, 2 }, /* cubemap */ + { "vec4_tex_rect", IR_TEX, 1, 2 }, /* rectangle */ + { "vec4_tex_rect_bias", IR_TEX, 1, 2 }, /* rectangle w/ projection */ + { "vec4_tex_1d_array", IR_TEX, 1, 2 }, + { "vec4_tex_1d_array_bias", IR_TEXB, 1, 2 }, + { "vec4_tex_1d_array_shadow", IR_TEX, 1, 2 }, + { "vec4_tex_1d_array_bias_shadow", IR_TEXB, 1, 2 }, + { "vec4_tex_2d_array", IR_TEX, 1, 2 }, + { "vec4_tex_2d_array_bias", IR_TEXB, 1, 2 }, + { "vec4_tex_2d_array_shadow", IR_TEX, 1, 2 }, + { "vec4_tex_2d_array_bias_shadow", IR_TEXB, 1, 2 }, + + /* texture / sampler but with shadow comparison */ + { "vec4_tex_1d_shadow", IR_TEX_SH, 1, 2 }, + { "vec4_tex_1d_bias_shadow", IR_TEXB_SH, 1, 2 }, + { "vec4_tex_1d_proj_shadow", IR_TEXP_SH, 1, 2 }, + { "vec4_tex_2d_shadow", IR_TEX_SH, 1, 2 }, + { "vec4_tex_2d_bias_shadow", IR_TEXB_SH, 1, 2 }, + { "vec4_tex_2d_proj_shadow", IR_TEXP_SH, 1, 2 }, + { "vec4_tex_rect_shadow", IR_TEX_SH, 1, 2 }, + { "vec4_tex_rect_proj_shadow", IR_TEXP_SH, 1, 2 }, + + /* unary op */ + { "ivec4_to_vec4", IR_I_TO_F, 1, 1 }, /* int[4] to float[4] */ + { "vec4_to_ivec4", IR_F_TO_I, 1, 1 }, /* float[4] to int[4] */ + { "float_exp", IR_EXP, 1, 1 }, + { "float_exp2", IR_EXP2, 1, 1 }, + { "float_log2", IR_LOG2, 1, 1 }, + { "float_rsq", IR_RSQ, 1, 1 }, + { "float_rcp", IR_RCP, 1, 1 }, + { "float_sine", IR_SIN, 1, 1 }, + { "float_cosine", IR_COS, 1, 1 }, + { "float_noise1", IR_NOISE1, 1, 1}, + { "float_noise2", IR_NOISE2, 1, 1}, + { "float_noise3", IR_NOISE3, 1, 1}, + { "float_noise4", IR_NOISE4, 1, 1}, + + { NULL, IR_NOP, 0, 0 } +}; + + +static slang_ir_node * +new_node3(slang_ir_opcode op, + slang_ir_node *c0, slang_ir_node *c1, slang_ir_node *c2) +{ + slang_ir_node *n = (slang_ir_node *) _slang_alloc(sizeof(slang_ir_node)); + if (n) { + n->Opcode = op; + n->Children[0] = c0; + n->Children[1] = c1; + n->Children[2] = c2; + n->InstLocation = -1; + } + return n; +} + +static slang_ir_node * +new_node2(slang_ir_opcode op, slang_ir_node *c0, slang_ir_node *c1) +{ + return new_node3(op, c0, c1, NULL); +} + +static slang_ir_node * +new_node1(slang_ir_opcode op, slang_ir_node *c0) +{ + return new_node3(op, c0, NULL, NULL); +} + +static slang_ir_node * +new_node0(slang_ir_opcode op) +{ + return new_node3(op, NULL, NULL, NULL); +} + + +/** + * Create sequence of two nodes. + */ +static slang_ir_node * +new_seq(slang_ir_node *left, slang_ir_node *right) +{ + if (!left) + return right; + if (!right) + return left; + return new_node2(IR_SEQ, left, right); +} + +static slang_ir_node * +new_label(slang_label *label) +{ + slang_ir_node *n = new_node0(IR_LABEL); + assert(label); + if (n) + n->Label = label; + return n; +} + +static slang_ir_node * +new_float_literal(const float v[4], GLuint size) +{ + slang_ir_node *n = new_node0(IR_FLOAT); + assert(size <= 4); + COPY_4V(n->Value, v); + /* allocate a storage object, but compute actual location (Index) later */ + n->Store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, size); + return n; +} + + +static slang_ir_node * +new_not(slang_ir_node *n) +{ + return new_node1(IR_NOT, n); +} + + +/** + * Non-inlined function call. + */ +static slang_ir_node * +new_function_call(slang_ir_node *code, slang_label *name) +{ + slang_ir_node *n = new_node1(IR_CALL, code); + assert(name); + if (n) + n->Label = name; + return n; +} + + +/** + * Unconditional jump. + */ +static slang_ir_node * +new_return(slang_label *dest) +{ + slang_ir_node *n = new_node0(IR_RETURN); + assert(dest); + if (n) + n->Label = dest; + return n; +} + + +static slang_ir_node * +new_loop(slang_ir_node *body) +{ + return new_node1(IR_LOOP, body); +} + + +static slang_ir_node * +new_break(slang_ir_node *loopNode) +{ + slang_ir_node *n = new_node0(IR_BREAK); + assert(loopNode); + assert(loopNode->Opcode == IR_LOOP); + if (n) { + /* insert this node at head of linked list of cont/break instructions */ + n->List = loopNode->List; + loopNode->List = n; + } + return n; +} + + +/** + * Make new IR_BREAK_IF_TRUE. + */ +static slang_ir_node * +new_break_if_true(slang_assemble_ctx *A, slang_ir_node *cond) +{ + slang_ir_node *loopNode = current_loop_ir(A); + slang_ir_node *n; + assert(loopNode); + assert(loopNode->Opcode == IR_LOOP); + n = new_node1(IR_BREAK_IF_TRUE, cond); + if (n) { + /* insert this node at head of linked list of cont/break instructions */ + n->List = loopNode->List; + loopNode->List = n; + } + return n; +} + + +/** + * Make new IR_CONT_IF_TRUE node. + */ +static slang_ir_node * +new_cont_if_true(slang_assemble_ctx *A, slang_ir_node *cond) +{ + slang_ir_node *loopNode = current_loop_ir(A); + slang_ir_node *n; + assert(loopNode); + assert(loopNode->Opcode == IR_LOOP); + n = new_node1(IR_CONT_IF_TRUE, cond); + if (n) { + n->Parent = loopNode; /* pointer to containing loop */ + /* insert this node at head of linked list of cont/break instructions */ + n->List = loopNode->List; + loopNode->List = n; + } + return n; +} + + +static slang_ir_node * +new_cond(slang_ir_node *n) +{ + slang_ir_node *c = new_node1(IR_COND, n); + return c; +} + + +static slang_ir_node * +new_if(slang_ir_node *cond, slang_ir_node *ifPart, slang_ir_node *elsePart) +{ + return new_node3(IR_IF, cond, ifPart, elsePart); +} + + +/** + * New IR_VAR node - a reference to a previously declared variable. + */ +static slang_ir_node * +new_var(slang_assemble_ctx *A, slang_variable *var) +{ + slang_ir_node *n = new_node0(IR_VAR); + if (n) { + ASSERT(var); + ASSERT(var->store); + ASSERT(!n->Store); + ASSERT(!n->Var); + + /* Set IR node's Var and Store pointers */ + n->Var = var; + n->Store = var->store; + } + return n; +} + + +/** + * Check if the given function is really just a wrapper for a + * basic assembly instruction. + */ +static GLboolean +slang_is_asm_function(const slang_function *fun) +{ + if (fun->body->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE && + fun->body->num_children == 1 && + fun->body->children[0].type == SLANG_OPER_ASM) { + return GL_TRUE; + } + return GL_FALSE; +} + + +static GLboolean +_slang_is_noop(const slang_operation *oper) +{ + if (!oper || + oper->type == SLANG_OPER_VOID || + (oper->num_children == 1 && oper->children[0].type == SLANG_OPER_VOID)) + return GL_TRUE; + else + return GL_FALSE; +} + + +/** + * Recursively search tree for a node of the given type. + */ +#if 0 +static slang_operation * +_slang_find_node_type(slang_operation *oper, slang_operation_type type) +{ + GLuint i; + if (oper->type == type) + return oper; + for (i = 0; i < oper->num_children; i++) { + slang_operation *p = _slang_find_node_type(&oper->children[i], type); + if (p) + return p; + } + return NULL; +} +#endif + + +/** + * Count the number of operations of the given time rooted at 'oper'. + */ +static GLuint +_slang_count_node_type(const slang_operation *oper, slang_operation_type type) +{ + GLuint i, count = 0; + if (oper->type == type) { + return 1; + } + for (i = 0; i < oper->num_children; i++) { + count += _slang_count_node_type(&oper->children[i], type); + } + return count; +} + + +/** + * Check if the 'return' statement found under 'oper' is a "tail return" + * that can be no-op'd. For example: + * + * void func(void) + * { + * .. do something .. + * return; // this is a no-op + * } + * + * This is used when determining if a function can be inlined. If the + * 'return' is not the last statement, we can't inline the function since + * we still need the semantic behaviour of the 'return' but we don't want + * to accidentally return from the _calling_ function. We'd need to use an + * unconditional branch, but we don't have such a GPU instruction (not + * always, at least). + */ +static GLboolean +_slang_is_tail_return(const slang_operation *oper) +{ + GLuint k = oper->num_children; + + while (k > 0) { + const slang_operation *last = &oper->children[k - 1]; + if (last->type == SLANG_OPER_RETURN) + return GL_TRUE; + else if (last->type == SLANG_OPER_IDENTIFIER || + last->type == SLANG_OPER_LABEL) + k--; /* try prev child */ + else if (last->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE || + last->type == SLANG_OPER_BLOCK_NEW_SCOPE) + /* try sub-children */ + return _slang_is_tail_return(last); + else + break; + } + + return GL_FALSE; +} + + +/** + * Generate a variable declaration opeartion. + * I.e.: generate AST code for "bool flag = false;" + */ +static void +slang_generate_declaration(slang_assemble_ctx *A, + slang_variable_scope *scope, + slang_operation *decl, + slang_type_specifier_type type, + const char *name, + GLint initValue) +{ + slang_variable *var; + + assert(type == SLANG_SPEC_BOOL || + type == SLANG_SPEC_INT); + + decl->type = SLANG_OPER_VARIABLE_DECL; + + var = slang_variable_scope_grow(scope); + + slang_fully_specified_type_construct(&var->type); + + var->type.specifier.type = type; + var->a_name = slang_atom_pool_atom(A->atoms, name); + decl->a_id = var->a_name; + var->initializer = slang_operation_new(1); + slang_operation_literal_bool(var->initializer, initValue); +} + + +static void +slang_resolve_variable(slang_operation *oper) +{ + if (oper->type == SLANG_OPER_IDENTIFIER && !oper->var) { + oper->var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); + } +} + + +/** + * Rewrite AST code for "return expression;". + * + * We return values from functions by assinging the returned value to + * the hidden __retVal variable which is an extra 'out' parameter we add + * to the function signature. + * This code basically converts "return expr;" into "__retVal = expr; return;" + * + * \return the new AST code. + */ +static slang_operation * +gen_return_with_expression(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *blockOper, *assignOper; + + assert(oper->type == SLANG_OPER_RETURN); + + if (A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "illegal return expression"); + return NULL; + } + + blockOper = slang_operation_new(1); + blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + blockOper->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(blockOper, 2); + + if (A->UseReturnFlag) { + /* Emit: + * { + * if (__notRetFlag) + * __retVal = expr; + * __notRetFlag = 0; + * } + */ + { + slang_operation *ifOper = slang_oper_child(blockOper, 0); + ifOper->type = SLANG_OPER_IF; + slang_operation_add_children(ifOper, 3); + { + slang_operation *cond = slang_oper_child(ifOper, 0); + cond->type = SLANG_OPER_IDENTIFIER; + cond->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + } + { + slang_operation *elseOper = slang_oper_child(ifOper, 2); + elseOper->type = SLANG_OPER_VOID; + } + assignOper = slang_oper_child(ifOper, 1); + } + { + slang_operation *setOper = slang_oper_child(blockOper, 1); + setOper->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(setOper, 2); + { + slang_operation *lhs = slang_oper_child(setOper, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + } + { + slang_operation *rhs = slang_oper_child(setOper, 1); + slang_operation_literal_bool(rhs, GL_FALSE); + } + } + } + else { + /* Emit: + * { + * __retVal = expr; + * return_inlined; + * } + */ + assignOper = slang_oper_child(blockOper, 0); + { + slang_operation *returnOper = slang_oper_child(blockOper, 1); + returnOper->type = SLANG_OPER_RETURN_INLINED; + assert(returnOper->num_children == 0); + } + } + + /* __retVal = expression; */ + assignOper->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(assignOper, 2); + { + slang_operation *lhs = slang_oper_child(assignOper, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__retVal"); + } + { + slang_operation *rhs = slang_oper_child(assignOper, 1); + slang_operation_copy(rhs, &oper->children[0]); + } + + /*blockOper->locals->outer_scope = oper->locals->outer_scope;*/ + + /*slang_print_tree(blockOper, 0);*/ + + return blockOper; +} + + +/** + * Rewrite AST code for "return;" (no expression). + */ +static slang_operation * +gen_return_without_expression(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *newRet; + + assert(oper->type == SLANG_OPER_RETURN); + + if (A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "return statement requires an expression"); + return NULL; + } + + if (A->UseReturnFlag) { + /* Emit: + * __notRetFlag = 0; + */ + { + newRet = slang_operation_new(1); + newRet->locals->outer_scope = oper->locals->outer_scope; + newRet->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(newRet, 2); + { + slang_operation *lhs = slang_oper_child(newRet, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + } + { + slang_operation *rhs = slang_oper_child(newRet, 1); + slang_operation_literal_bool(rhs, GL_FALSE); + } + } + } + else { + /* Emit: + * return_inlined; + */ + newRet = slang_operation_new(1); + newRet->locals->outer_scope = oper->locals->outer_scope; + newRet->type = SLANG_OPER_RETURN_INLINED; + } + + /*slang_print_tree(newRet, 0);*/ + + return newRet; +} + + + + +/** + * Replace particular variables (SLANG_OPER_IDENTIFIER) with new expressions. + */ +static void +slang_substitute(slang_assemble_ctx *A, slang_operation *oper, + GLuint substCount, slang_variable **substOld, + slang_operation **substNew, GLboolean isLHS) +{ + switch (oper->type) { + case SLANG_OPER_VARIABLE_DECL: + { + slang_variable *v = _slang_variable_locate(oper->locals, + oper->a_id, GL_TRUE); + assert(v); + if (v->initializer && oper->num_children == 0) { + /* set child of oper to copy of initializer */ + oper->num_children = 1; + oper->children = slang_operation_new(1); + slang_operation_copy(&oper->children[0], v->initializer); + } + if (oper->num_children == 1) { + /* the initializer */ + slang_substitute(A, &oper->children[0], substCount, + substOld, substNew, GL_FALSE); + } + } + break; + case SLANG_OPER_IDENTIFIER: + assert(oper->num_children == 0); + if (1/**!isLHS XXX FIX */) { + slang_atom id = oper->a_id; + slang_variable *v; + GLuint i; + v = _slang_variable_locate(oper->locals, id, GL_TRUE); + if (!v) { + if (strcmp((char *) oper->a_id, "__notRetFlag")) + _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id); + return; + } + + /* look for a substitution */ + for (i = 0; i < substCount; i++) { + if (v == substOld[i]) { + /* OK, replace this SLANG_OPER_IDENTIFIER with a new expr */ +#if 0 /* DEBUG only */ + if (substNew[i]->type == SLANG_OPER_IDENTIFIER) { + assert(substNew[i]->var); + assert(substNew[i]->var->a_name); + printf("Substitute %s with %s in id node %p\n", + (char*)v->a_name, (char*) substNew[i]->var->a_name, + (void*) oper); + } + else { + printf("Substitute %s with %f in id node %p\n", + (char*)v->a_name, substNew[i]->literal[0], + (void*) oper); + } +#endif + slang_operation_copy(oper, substNew[i]); + break; + } + } + } + break; + + case SLANG_OPER_RETURN: + { + slang_operation *newReturn; + /* generate new 'return' code' */ + if (slang_oper_child(oper, 0)->type == SLANG_OPER_VOID) + newReturn = gen_return_without_expression(A, oper); + else + newReturn = gen_return_with_expression(A, oper); + + if (!newReturn) + return; + + /* do substitutions on the new 'return' code */ + slang_substitute(A, newReturn, + substCount, substOld, substNew, GL_FALSE); + + /* install new 'return' code */ + slang_operation_copy(oper, newReturn); + slang_operation_destruct(newReturn); + } + break; + + case SLANG_OPER_ASSIGN: + case SLANG_OPER_SUBSCRIPT: + /* special case: + * child[0] can't have substitutions but child[1] can. + */ + slang_substitute(A, &oper->children[0], + substCount, substOld, substNew, GL_TRUE); + slang_substitute(A, &oper->children[1], + substCount, substOld, substNew, GL_FALSE); + break; + case SLANG_OPER_FIELD: + /* XXX NEW - test */ + slang_substitute(A, &oper->children[0], + substCount, substOld, substNew, GL_TRUE); + break; + default: + { + GLuint i; + for (i = 0; i < oper->num_children; i++) + slang_substitute(A, &oper->children[i], + substCount, substOld, substNew, GL_FALSE); + } + } +} + + +/** + * Produce inline code for a call to an assembly instruction. + * This is typically used to compile a call to a built-in function like this: + * + * vec4 mix(const vec4 x, const vec4 y, const vec4 a) + * { + * __asm vec4_lrp __retVal, a, y, x; + * } + * + * + * A call to + * r = mix(p1, p2, p3); + * + * Becomes: + * + * mov + * / \ + * r vec4_lrp + * / | \ + * p3 p2 p1 + * + * We basically translate a SLANG_OPER_CALL into a SLANG_OPER_ASM. + */ +static slang_operation * +slang_inline_asm_function(slang_assemble_ctx *A, + slang_function *fun, slang_operation *oper) +{ + const GLuint numArgs = oper->num_children; + GLuint i; + slang_operation *inlined; + const GLboolean haveRetValue = _slang_function_has_return_value(fun); + slang_variable **substOld; + slang_operation **substNew; + + ASSERT(slang_is_asm_function(fun)); + ASSERT(fun->param_count == numArgs + haveRetValue); + + /* + printf("Inline %s as %s\n", + (char*) fun->header.a_name, + (char*) fun->body->children[0].a_id); + */ + + /* + * We'll substitute formal params with actual args in the asm call. + */ + substOld = (slang_variable **) + _slang_alloc(numArgs * sizeof(slang_variable *)); + substNew = (slang_operation **) + _slang_alloc(numArgs * sizeof(slang_operation *)); + for (i = 0; i < numArgs; i++) { + substOld[i] = fun->parameters->variables[i]; + substNew[i] = oper->children + i; + } + + /* make a copy of the code to inline */ + inlined = slang_operation_new(1); + slang_operation_copy(inlined, &fun->body->children[0]); + if (haveRetValue) { + /* get rid of the __retVal child */ + inlined->num_children--; + for (i = 0; i < inlined->num_children; i++) { + inlined->children[i] = inlined->children[i + 1]; + } + } + + /* now do formal->actual substitutions */ + slang_substitute(A, inlined, numArgs, substOld, substNew, GL_FALSE); + + _slang_free(substOld); + _slang_free(substNew); + +#if 0 + printf("+++++++++++++ inlined asm function %s +++++++++++++\n", + (char *) fun->header.a_name); + slang_print_tree(inlined, 3); + printf("+++++++++++++++++++++++++++++++++++++++++++++++++++\n"); +#endif + + return inlined; +} + + +/** + * Inline the given function call operation. + * Return a new slang_operation that corresponds to the inlined code. + */ +static slang_operation * +slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun, + slang_operation *oper, slang_operation *returnOper) +{ + typedef enum { + SUBST = 1, + COPY_IN, + COPY_OUT + } ParamMode; + ParamMode *paramMode; + const GLboolean haveRetValue = _slang_function_has_return_value(fun); + const GLuint numArgs = oper->num_children; + const GLuint totalArgs = numArgs + haveRetValue; + slang_operation *args = oper->children; + slang_operation *inlined, *top; + slang_variable **substOld; + slang_operation **substNew; + GLuint substCount, numCopyIn, i; + slang_function *prevFunction; + slang_variable_scope *newScope = NULL; + + /* save / push */ + prevFunction = A->CurFunction; + A->CurFunction = fun; + + /*assert(oper->type == SLANG_OPER_CALL); (or (matrix) multiply, etc) */ + assert(fun->param_count == totalArgs); + + /* allocate temporary arrays */ + paramMode = (ParamMode *) + _slang_alloc(totalArgs * sizeof(ParamMode)); + substOld = (slang_variable **) + _slang_alloc(totalArgs * sizeof(slang_variable *)); + substNew = (slang_operation **) + _slang_alloc(totalArgs * sizeof(slang_operation *)); + +#if 0 + printf("\nInline call to %s (total vars=%d nparams=%d)\n", + (char *) fun->header.a_name, + fun->parameters->num_variables, numArgs); +#endif + + if (haveRetValue && !returnOper) { + /* Create 3-child comma sequence for inlined code: + * child[0]: declare __resultTmp + * child[1]: inlined function body + * child[2]: __resultTmp + */ + slang_operation *commaSeq; + slang_operation *declOper = NULL; + slang_variable *resultVar; + + commaSeq = slang_operation_new(1); + commaSeq->type = SLANG_OPER_SEQUENCE; + assert(commaSeq->locals); + commaSeq->locals->outer_scope = oper->locals->outer_scope; + commaSeq->num_children = 3; + commaSeq->children = slang_operation_new(3); + /* allocate the return var */ + resultVar = slang_variable_scope_grow(commaSeq->locals); + /* + printf("Alloc __resultTmp in scope %p for retval of calling %s\n", + (void*)commaSeq->locals, (char *) fun->header.a_name); + */ + + resultVar->a_name = slang_atom_pool_atom(A->atoms, "__resultTmp"); + resultVar->type = fun->header.type; /* XXX copy? */ + resultVar->isTemp = GL_TRUE; + + /* child[0] = __resultTmp declaration */ + declOper = &commaSeq->children[0]; + declOper->type = SLANG_OPER_VARIABLE_DECL; + declOper->a_id = resultVar->a_name; + declOper->locals->outer_scope = commaSeq->locals; + + /* child[1] = function body */ + inlined = &commaSeq->children[1]; + inlined->locals->outer_scope = commaSeq->locals; + + /* child[2] = __resultTmp reference */ + returnOper = &commaSeq->children[2]; + returnOper->type = SLANG_OPER_IDENTIFIER; + returnOper->a_id = resultVar->a_name; + returnOper->locals->outer_scope = commaSeq->locals; + + top = commaSeq; + } + else { + top = inlined = slang_operation_new(1); + /* XXXX this may be inappropriate!!!! */ + inlined->locals->outer_scope = oper->locals->outer_scope; + } + + + assert(inlined->locals); + + /* Examine the parameters, look for inout/out params, look for possible + * substitutions, etc: + * param type behaviour + * in copy actual to local + * const in substitute param with actual + * out copy out + */ + substCount = 0; + for (i = 0; i < totalArgs; i++) { + slang_variable *p = fun->parameters->variables[i]; + /* + printf("Param %d: %s %s \n", i, + slang_type_qual_string(p->type.qualifier), + (char *) p->a_name); + */ + if (p->type.qualifier == SLANG_QUAL_INOUT || + p->type.qualifier == SLANG_QUAL_OUT) { + /* an output param */ + slang_operation *arg; + if (i < numArgs) + arg = &args[i]; + else + arg = returnOper; + paramMode[i] = SUBST; + + if (arg->type == SLANG_OPER_IDENTIFIER) + slang_resolve_variable(arg); + + /* replace parameter 'p' with argument 'arg' */ + substOld[substCount] = p; + substNew[substCount] = arg; /* will get copied */ + substCount++; + } + else if (p->type.qualifier == SLANG_QUAL_CONST) { + /* a constant input param */ + if (args[i].type == SLANG_OPER_IDENTIFIER || + args[i].type == SLANG_OPER_LITERAL_FLOAT || + args[i].type == SLANG_OPER_SUBSCRIPT) { + /* replace all occurances of this parameter variable with the + * actual argument variable or a literal. + */ + paramMode[i] = SUBST; + slang_resolve_variable(&args[i]); + substOld[substCount] = p; + substNew[substCount] = &args[i]; /* will get copied */ + substCount++; + } + else { + paramMode[i] = COPY_IN; + } + } + else { + paramMode[i] = COPY_IN; + } + assert(paramMode[i]); + } + + /* actual code inlining: */ + slang_operation_copy(inlined, fun->body); + + /*** XXX review this */ + assert(inlined->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE || + inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE); + inlined->type = SLANG_OPER_BLOCK_NEW_SCOPE; + +#if 0 + printf("======================= orig body code ======================\n"); + printf("=== params scope = %p\n", (void*) fun->parameters); + slang_print_tree(fun->body, 8); + printf("======================= copied code =========================\n"); + slang_print_tree(inlined, 8); +#endif + + /* do parameter substitution in inlined code: */ + slang_substitute(A, inlined, substCount, substOld, substNew, GL_FALSE); + +#if 0 + printf("======================= subst code ==========================\n"); + slang_print_tree(inlined, 8); + printf("=============================================================\n"); +#endif + + /* New prolog statements: (inserted before the inlined code) + * Copy the 'in' arguments. + */ + numCopyIn = 0; + for (i = 0; i < numArgs; i++) { + if (paramMode[i] == COPY_IN) { + slang_variable *p = fun->parameters->variables[i]; + /* declare parameter 'p' */ + slang_operation *decl = slang_operation_insert(&inlined->num_children, + &inlined->children, + numCopyIn); + + decl->type = SLANG_OPER_VARIABLE_DECL; + assert(decl->locals); + decl->locals->outer_scope = inlined->locals; + decl->a_id = p->a_name; + decl->num_children = 1; + decl->children = slang_operation_new(1); + + /* child[0] is the var's initializer */ + slang_operation_copy(&decl->children[0], args + i); + + /* add parameter 'p' to the local variable scope here */ + { + slang_variable *pCopy = slang_variable_scope_grow(inlined->locals); + pCopy->type = p->type; + pCopy->a_name = p->a_name; + pCopy->array_len = p->array_len; + } + + newScope = inlined->locals; + numCopyIn++; + } + } + + /* Now add copies of the function's local vars to the new variable scope */ + for (i = totalArgs; i < fun->parameters->num_variables; i++) { + slang_variable *p = fun->parameters->variables[i]; + slang_variable *pCopy = slang_variable_scope_grow(inlined->locals); + pCopy->type = p->type; + pCopy->a_name = p->a_name; + pCopy->array_len = p->array_len; + } + + + /* New epilog statements: + * 1. Create end of function label to jump to from return statements. + * 2. Copy the 'out' parameter vars + */ + { + slang_operation *lab = slang_operation_insert(&inlined->num_children, + &inlined->children, + inlined->num_children); + lab->type = SLANG_OPER_LABEL; + lab->label = A->curFuncEndLabel; + } + + for (i = 0; i < totalArgs; i++) { + if (paramMode[i] == COPY_OUT) { + const slang_variable *p = fun->parameters->variables[i]; + /* actualCallVar = outParam */ + /*if (i > 0 || !haveRetValue)*/ + slang_operation *ass = slang_operation_insert(&inlined->num_children, + &inlined->children, + inlined->num_children); + ass->type = SLANG_OPER_ASSIGN; + ass->num_children = 2; + ass->locals->outer_scope = inlined->locals; + ass->children = slang_operation_new(2); + ass->children[0] = args[i]; /*XXX copy */ + ass->children[1].type = SLANG_OPER_IDENTIFIER; + ass->children[1].a_id = p->a_name; + ass->children[1].locals->outer_scope = ass->locals; + } + } + + _slang_free(paramMode); + _slang_free(substOld); + _slang_free(substNew); + + /* Update scoping to use the new local vars instead of the + * original function's vars. This is especially important + * for nested inlining. + */ + if (newScope) + slang_replace_scope(inlined, fun->parameters, newScope); + +#if 0 + printf("Done Inline call to %s (total vars=%d nparams=%d)\n\n", + (char *) fun->header.a_name, + fun->parameters->num_variables, numArgs); + slang_print_tree(top, 0); +#endif + + /* pop */ + A->CurFunction = prevFunction; + + return top; +} + + +/** + * Insert declaration for "bool __notRetFlag" in given block operation. + * This is used when we can't emit "early" return statements in subroutines. + */ +static void +declare_return_flag(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *decl; + + assert(oper->type == SLANG_OPER_BLOCK_NEW_SCOPE || + oper->type == SLANG_OPER_SEQUENCE); + + decl = slang_operation_insert_child(oper, 1); + + slang_generate_declaration(A, oper->locals, decl, + SLANG_SPEC_BOOL, "__notRetFlag", GL_TRUE); + + /*slang_print_tree(oper, 0);*/ +} + + +/** + * Recursively replace instances of the old node type with the new type. + */ +static void +replace_node_type(slang_operation *oper, slang_operation_type oldType, + slang_operation_type newType) +{ + GLuint i; + + if (oper->type == oldType) + oper->type = newType; + + for (i = 0; i < slang_oper_num_children(oper); i++) { + replace_node_type(slang_oper_child(oper, i), oldType, newType); + } +} + + + +/** + * Test if the given function body has an "early return". That is, there's + * a 'return' statement that's not the very last instruction in the body. + */ +static GLboolean +has_early_return(const slang_operation *funcBody) +{ + GLuint retCount = _slang_count_node_type(funcBody, SLANG_OPER_RETURN); + if (retCount == 0) + return GL_FALSE; + else if (retCount == 1 && _slang_is_tail_return(funcBody)) + return GL_FALSE; + else + return GL_TRUE; +} + + +/** + * Emit IR code for a function call. This does one of two things: + * 1. Inline the function's code + * 2. Create an IR for the function's body and create a real call to it. + */ +static slang_ir_node * +_slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, + slang_operation *oper, slang_operation *dest) +{ + slang_ir_node *n; + slang_operation *instance; + slang_label *prevFuncEndLabel; + char name[200]; + + prevFuncEndLabel = A->curFuncEndLabel; + _mesa_snprintf(name, sizeof(name), "__endOfFunc_%s_", (char *) fun->header.a_name); + A->curFuncEndLabel = _slang_label_new(name); + assert(A->curFuncEndLabel); + + /* + * 'instance' is basically a copy of the function's body with various + * transformations. + */ + + if (slang_is_asm_function(fun) && !dest) { + /* assemble assembly function - tree style */ + instance = slang_inline_asm_function(A, fun, oper); + } + else { + /* non-assembly function */ + /* We always generate an "inline-able" block of code here. + * We may either: + * 1. insert the inline code + * 2. Generate a call to the "inline" code as a subroutine + */ + const GLboolean earlyReturn = has_early_return(fun->body); + + if (earlyReturn && !A->EmitContReturn) { + A->UseReturnFlag = GL_TRUE; + } + + instance = slang_inline_function_call(A, fun, oper, dest); + if (!instance) + return NULL; + + if (earlyReturn) { + /* The function we're calling has one or more 'return' statements + * that prevent us from inlining the function's code. + * + * In this case, change the function's body type from + * SLANG_OPER_BLOCK_NEW_SCOPE to SLANG_OPER_NON_INLINED_CALL. + * During code emit this will result in a true subroutine call. + * + * Also, convert SLANG_OPER_RETURN_INLINED nodes to SLANG_OPER_RETURN. + */ + slang_operation *callOper; + + assert(instance->type == SLANG_OPER_BLOCK_NEW_SCOPE || + instance->type == SLANG_OPER_SEQUENCE); + + if (_slang_function_has_return_value(fun) && !dest) { + assert(instance->children[0].type == SLANG_OPER_VARIABLE_DECL); + assert(instance->children[2].type == SLANG_OPER_IDENTIFIER); + callOper = &instance->children[1]; + } + else { + callOper = instance; + } + + if (A->UseReturnFlag) { + /* Early returns not supported. Create a _returnFlag variable + * that's set upon 'return' and tested elsewhere to no-op any + * remaining instructions in the subroutine. + */ + assert(callOper->type == SLANG_OPER_BLOCK_NEW_SCOPE || + callOper->type == SLANG_OPER_SEQUENCE); + declare_return_flag(A, callOper); + } + else { + /* We can emit real 'return' statements. If we generated any + * 'inline return' statements during function instantiation, + * change them back to regular 'return' statements. + */ + replace_node_type(instance, SLANG_OPER_RETURN_INLINED, + SLANG_OPER_RETURN); + } + + callOper->type = SLANG_OPER_NON_INLINED_CALL; + callOper->fun = fun; + callOper->label = _slang_label_new_unique((char*) fun->header.a_name); + } + else { + /* If there are any 'return' statements remaining, they're at the + * very end of the function and can effectively become no-ops. + */ + replace_node_type(instance, SLANG_OPER_RETURN_INLINED, + SLANG_OPER_VOID); + } + } + + if (!instance) + return NULL; + + /* Replace the function call with the instance block (or new CALL stmt) */ + slang_operation_destruct(oper); + *oper = *instance; + _slang_free(instance); + +#if 0 + assert(instance->locals); + printf("*** Inlined code for call to %s:\n", (char*) fun->header.a_name); + slang_print_tree(oper, 10); + printf("\n"); +#endif + + n = _slang_gen_operation(A, oper); + + /*_slang_label_delete(A->curFuncEndLabel);*/ + A->curFuncEndLabel = prevFuncEndLabel; + + if (A->pragmas->Debug) { + char s[1000]; + _mesa_snprintf(s, sizeof(s), "Call/inline %s()", (char *) fun->header.a_name); + n->Comment = _slang_strdup(s); + } + + A->UseReturnFlag = GL_FALSE; + + return n; +} + + +static slang_asm_info * +slang_find_asm_info(const char *name) +{ + GLuint i; + for (i = 0; AsmInfo[i].Name; i++) { + if (strcmp(AsmInfo[i].Name, name) == 0) { + return AsmInfo + i; + } + } + return NULL; +} + + +/** + * Some write-masked assignments are simple, but others are hard. + * Simple example: + * vec3 v; + * v.xy = vec2(a, b); + * Hard example: + * vec3 v; + * v.zy = vec2(a, b); + * this gets transformed/swizzled into: + * v.zy = vec2(a, b).*yx* (* = don't care) + * This function helps to determine simple vs. non-simple. + */ +static GLboolean +_slang_simple_writemask(GLuint writemask, GLuint swizzle) +{ + switch (writemask) { + case WRITEMASK_X: + return GET_SWZ(swizzle, 0) == SWIZZLE_X; + case WRITEMASK_Y: + return GET_SWZ(swizzle, 1) == SWIZZLE_Y; + case WRITEMASK_Z: + return GET_SWZ(swizzle, 2) == SWIZZLE_Z; + case WRITEMASK_W: + return GET_SWZ(swizzle, 3) == SWIZZLE_W; + case WRITEMASK_XY: + return (GET_SWZ(swizzle, 0) == SWIZZLE_X) + && (GET_SWZ(swizzle, 1) == SWIZZLE_Y); + case WRITEMASK_XYZ: + return (GET_SWZ(swizzle, 0) == SWIZZLE_X) + && (GET_SWZ(swizzle, 1) == SWIZZLE_Y) + && (GET_SWZ(swizzle, 2) == SWIZZLE_Z); + case WRITEMASK_XYZW: + return swizzle == SWIZZLE_NOOP; + default: + return GL_FALSE; + } +} + + +/** + * Convert the given swizzle into a writemask. In some cases this + * is trivial, in other cases, we'll need to also swizzle the right + * hand side to put components in the right places. + * See comment above for more info. + * XXX this function could be simplified and should probably be renamed. + * \param swizzle the incoming swizzle + * \param writemaskOut returns the writemask + * \param swizzleOut swizzle to apply to the right-hand-side + * \return GL_FALSE for simple writemasks, GL_TRUE for non-simple + */ +static GLboolean +swizzle_to_writemask(slang_assemble_ctx *A, GLuint swizzle, + GLuint *writemaskOut, GLuint *swizzleOut) +{ + GLuint mask = 0x0, newSwizzle[4]; + GLint i, size; + + /* make new dst writemask, compute size */ + for (i = 0; i < 4; i++) { + const GLuint swz = GET_SWZ(swizzle, i); + if (swz == SWIZZLE_NIL) { + /* end */ + break; + } + assert(swz <= 3); + + if (swizzle != SWIZZLE_XXXX && + swizzle != SWIZZLE_YYYY && + swizzle != SWIZZLE_ZZZZ && + swizzle != SWIZZLE_WWWW && + (mask & (1 << swz))) { + /* a channel can't be specified twice (ex: ".xyyz") */ + slang_info_log_error(A->log, "Invalid writemask '%s'", + _mesa_swizzle_string(swizzle, 0, 0)); + return GL_FALSE; + } + + mask |= (1 << swz); + } + assert(mask <= 0xf); + size = i; /* number of components in mask/swizzle */ + + *writemaskOut = mask; + + /* make new src swizzle, by inversion */ + for (i = 0; i < 4; i++) { + newSwizzle[i] = i; /*identity*/ + } + for (i = 0; i < size; i++) { + const GLuint swz = GET_SWZ(swizzle, i); + newSwizzle[swz] = i; + } + *swizzleOut = MAKE_SWIZZLE4(newSwizzle[0], + newSwizzle[1], + newSwizzle[2], + newSwizzle[3]); + + if (_slang_simple_writemask(mask, *swizzleOut)) { + if (size >= 1) + assert(GET_SWZ(*swizzleOut, 0) == SWIZZLE_X); + if (size >= 2) + assert(GET_SWZ(*swizzleOut, 1) == SWIZZLE_Y); + if (size >= 3) + assert(GET_SWZ(*swizzleOut, 2) == SWIZZLE_Z); + if (size >= 4) + assert(GET_SWZ(*swizzleOut, 3) == SWIZZLE_W); + return GL_TRUE; + } + else + return GL_FALSE; +} + + +#if 0 /* not used, but don't remove just yet */ +/** + * Recursively traverse 'oper' to produce a swizzle mask in the event + * of any vector subscripts and swizzle suffixes. + * Ex: for "vec4 v", "v[2].x" resolves to v.z + */ +static GLuint +resolve_swizzle(const slang_operation *oper) +{ + if (oper->type == SLANG_OPER_FIELD) { + /* writemask from .xyzw suffix */ + slang_swizzle swz; + if (_slang_is_swizzle((char*) oper->a_id, 4, &swz)) { + GLuint swizzle = MAKE_SWIZZLE4(swz.swizzle[0], + swz.swizzle[1], + swz.swizzle[2], + swz.swizzle[3]); + GLuint child_swizzle = resolve_swizzle(&oper->children[0]); + GLuint s = _slang_swizzle_swizzle(child_swizzle, swizzle); + return s; + } + else + return SWIZZLE_XYZW; + } + else if (oper->type == SLANG_OPER_SUBSCRIPT && + oper->children[1].type == SLANG_OPER_LITERAL_INT) { + /* writemask from [index] */ + GLuint child_swizzle = resolve_swizzle(&oper->children[0]); + GLuint i = (GLuint) oper->children[1].literal[0]; + GLuint swizzle; + GLuint s; + switch (i) { + case 0: + swizzle = SWIZZLE_XXXX; + break; + case 1: + swizzle = SWIZZLE_YYYY; + break; + case 2: + swizzle = SWIZZLE_ZZZZ; + break; + case 3: + swizzle = SWIZZLE_WWWW; + break; + default: + swizzle = SWIZZLE_XYZW; + } + s = _slang_swizzle_swizzle(child_swizzle, swizzle); + return s; + } + else { + return SWIZZLE_XYZW; + } +} +#endif + + +#if 0 +/** + * Recursively descend through swizzle nodes to find the node's storage info. + */ +static slang_ir_storage * +get_store(const slang_ir_node *n) +{ + if (n->Opcode == IR_SWIZZLE) { + return get_store(n->Children[0]); + } + return n->Store; +} +#endif + + +/** + * Generate IR tree for an asm instruction/operation such as: + * __asm vec4_dot __retVal.x, v1, v2; + */ +static slang_ir_node * +_slang_gen_asm(slang_assemble_ctx *A, slang_operation *oper, + slang_operation *dest) +{ + const slang_asm_info *info; + slang_ir_node *kids[3], *n; + GLuint j, firstOperand; + + assert(oper->type == SLANG_OPER_ASM); + + info = slang_find_asm_info((char *) oper->a_id); + if (!info) { + _mesa_problem(NULL, "undefined __asm function %s\n", + (char *) oper->a_id); + assert(info); + return NULL; + } + assert(info->NumParams <= 3); + + if (info->NumParams == oper->num_children) { + /* Storage for result is not specified. + * Children[0], [1], [2] are the operands. + */ + firstOperand = 0; + } + else { + /* Storage for result (child[0]) is specified. + * Children[1], [2], [3] are the operands. + */ + firstOperand = 1; + } + + /* assemble child(ren) */ + kids[0] = kids[1] = kids[2] = NULL; + for (j = 0; j < info->NumParams; j++) { + kids[j] = _slang_gen_operation(A, &oper->children[firstOperand + j]); + if (!kids[j]) + return NULL; + } + + n = new_node3(info->Opcode, kids[0], kids[1], kids[2]); + + if (firstOperand) { + /* Setup n->Store to be a particular location. Otherwise, storage + * for the result (a temporary) will be allocated later. + */ + slang_operation *dest_oper; + slang_ir_node *n0; + + dest_oper = &oper->children[0]; + + n0 = _slang_gen_operation(A, dest_oper); + if (!n0) + return NULL; + + assert(!n->Store); + n->Store = n0->Store; + + assert(n->Store->File != PROGRAM_UNDEFINED || n->Store->Parent); + + _slang_free(n0); + } + + return n; +} + + +#if 0 +static void +print_funcs(struct slang_function_scope_ *scope, const char *name) +{ + GLuint i; + for (i = 0; i < scope->num_functions; i++) { + slang_function *f = &scope->functions[i]; + if (!name || strcmp(name, (char*) f->header.a_name) == 0) + printf(" %s (%d args)\n", name, f->param_count); + + } + if (scope->outer_scope) + print_funcs(scope->outer_scope, name); +} +#endif + + +/** + * Find a function of the given name, taking 'numArgs' arguments. + * This is the function we'll try to call when there is no exact match + * between function parameters and call arguments. + * + * XXX we should really create a list of candidate functions and try + * all of them... + */ +static slang_function * +_slang_find_function_by_argc(slang_function_scope *scope, + const char *name, int numArgs) +{ + while (scope) { + GLuint i; + for (i = 0; i < scope->num_functions; i++) { + slang_function *f = &scope->functions[i]; + if (strcmp(name, (char*) f->header.a_name) == 0) { + int haveRetValue = _slang_function_has_return_value(f); + if (numArgs == f->param_count - haveRetValue) + return f; + } + } + scope = scope->outer_scope; + } + + return NULL; +} + + +static slang_function * +_slang_find_function_by_max_argc(slang_function_scope *scope, + const char *name) +{ + slang_function *maxFunc = NULL; + GLuint maxArgs = 0; + + while (scope) { + GLuint i; + for (i = 0; i < scope->num_functions; i++) { + slang_function *f = &scope->functions[i]; + if (strcmp(name, (char*) f->header.a_name) == 0) { + if (f->param_count > maxArgs) { + maxArgs = f->param_count; + maxFunc = f; + } + } + } + scope = scope->outer_scope; + } + + return maxFunc; +} + + +/** + * Generate a new slang_function which is a constructor for a user-defined + * struct type. + */ +static slang_function * +_slang_make_struct_constructor(slang_assemble_ctx *A, slang_struct *str) +{ + const GLint numFields = str->fields->num_variables; + slang_function *fun = slang_function_new(SLANG_FUNC_CONSTRUCTOR); + + /* function header (name, return type) */ + fun->header.a_name = str->a_name; + fun->header.type.qualifier = SLANG_QUAL_NONE; + fun->header.type.specifier.type = SLANG_SPEC_STRUCT; + fun->header.type.specifier._struct = str; + + /* function parameters (= struct's fields) */ + { + GLint i; + for (i = 0; i < numFields; i++) { + /* + printf("Field %d: %s\n", i, (char*) str->fields->variables[i]->a_name); + */ + slang_variable *p = slang_variable_scope_grow(fun->parameters); + *p = *str->fields->variables[i]; /* copy the variable and type */ + p->type.qualifier = SLANG_QUAL_CONST; + } + fun->param_count = fun->parameters->num_variables; + } + + /* Add __retVal to params */ + { + slang_variable *p = slang_variable_scope_grow(fun->parameters); + slang_atom a_retVal = slang_atom_pool_atom(A->atoms, "__retVal"); + assert(a_retVal); + p->a_name = a_retVal; + p->type = fun->header.type; + p->type.qualifier = SLANG_QUAL_OUT; + fun->param_count++; + } + + /* function body is: + * block: + * declare T; + * T.f1 = p1; + * T.f2 = p2; + * ... + * T.fn = pn; + * return T; + */ + { + slang_variable_scope *scope; + slang_variable *var; + GLint i; + + fun->body = slang_operation_new(1); + fun->body->type = SLANG_OPER_BLOCK_NEW_SCOPE; + fun->body->num_children = numFields + 2; + fun->body->children = slang_operation_new(numFields + 2); + + scope = fun->body->locals; + scope->outer_scope = fun->parameters; + + /* create local var 't' */ + var = slang_variable_scope_grow(scope); + var->a_name = slang_atom_pool_atom(A->atoms, "t"); + var->type = fun->header.type; + + /* declare t */ + { + slang_operation *decl; + + decl = &fun->body->children[0]; + decl->type = SLANG_OPER_VARIABLE_DECL; + decl->locals = _slang_variable_scope_new(scope); + decl->a_id = var->a_name; + } + + /* assign params to fields of t */ + for (i = 0; i < numFields; i++) { + slang_operation *assign = &fun->body->children[1 + i]; + + assign->type = SLANG_OPER_ASSIGN; + assign->locals = _slang_variable_scope_new(scope); + assign->num_children = 2; + assign->children = slang_operation_new(2); + + { + slang_operation *lhs = &assign->children[0]; + + lhs->type = SLANG_OPER_FIELD; + lhs->locals = _slang_variable_scope_new(scope); + lhs->num_children = 1; + lhs->children = slang_operation_new(1); + lhs->a_id = str->fields->variables[i]->a_name; + + lhs->children[0].type = SLANG_OPER_IDENTIFIER; + lhs->children[0].a_id = var->a_name; + lhs->children[0].locals = _slang_variable_scope_new(scope); + +#if 0 + lhs->children[1].num_children = 1; + lhs->children[1].children = slang_operation_new(1); + lhs->children[1].children[0].type = SLANG_OPER_IDENTIFIER; + lhs->children[1].children[0].a_id = str->fields->variables[i]->a_name; + lhs->children[1].children->locals = _slang_variable_scope_new(scope); +#endif + } + + { + slang_operation *rhs = &assign->children[1]; + + rhs->type = SLANG_OPER_IDENTIFIER; + rhs->locals = _slang_variable_scope_new(scope); + rhs->a_id = str->fields->variables[i]->a_name; + } + } + + /* return t; */ + { + slang_operation *ret = &fun->body->children[numFields + 1]; + + ret->type = SLANG_OPER_RETURN; + ret->locals = _slang_variable_scope_new(scope); + ret->num_children = 1; + ret->children = slang_operation_new(1); + ret->children[0].type = SLANG_OPER_IDENTIFIER; + ret->children[0].a_id = var->a_name; + ret->children[0].locals = _slang_variable_scope_new(scope); + } + } + /* + slang_print_function(fun, 1); + */ + return fun; +} + + +/** + * Find/create a function (constructor) for the given structure name. + */ +static slang_function * +_slang_locate_struct_constructor(slang_assemble_ctx *A, const char *name) +{ + unsigned int i; + for (i = 0; i < A->space.structs->num_structs; i++) { + slang_struct *str = &A->space.structs->structs[i]; + if (strcmp(name, (const char *) str->a_name) == 0) { + /* found a structure type that matches the function name */ + if (!str->constructor) { + /* create the constructor function now */ + str->constructor = _slang_make_struct_constructor(A, str); + } + return str->constructor; + } + } + return NULL; +} + + +/** + * Generate a new slang_function to satisfy a call to an array constructor. + * Ex: float[3](1., 2., 3.) + */ +static slang_function * +_slang_make_array_constructor(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_type_specifier_type baseType; + slang_function *fun; + int num_elements; + + fun = slang_function_new(SLANG_FUNC_CONSTRUCTOR); + if (!fun) + return NULL; + + baseType = slang_type_specifier_type_from_string((char *) oper->a_id); + + num_elements = oper->num_children; + + /* function header, return type */ + { + fun->header.a_name = oper->a_id; + fun->header.type.qualifier = SLANG_QUAL_NONE; + fun->header.type.specifier.type = SLANG_SPEC_ARRAY; + fun->header.type.specifier._array = + slang_type_specifier_new(baseType, NULL, NULL); + fun->header.type.array_len = num_elements; + } + + /* function parameters (= number of elements) */ + { + GLint i; + for (i = 0; i < num_elements; i++) { + /* + printf("Field %d: %s\n", i, (char*) str->fields->variables[i]->a_name); + */ + slang_variable *p = slang_variable_scope_grow(fun->parameters); + char name[10]; + _mesa_snprintf(name, sizeof(name), "p%d", i); + p->a_name = slang_atom_pool_atom(A->atoms, name); + p->type.qualifier = SLANG_QUAL_CONST; + p->type.specifier.type = baseType; + } + fun->param_count = fun->parameters->num_variables; + } + + /* Add __retVal to params */ + { + slang_variable *p = slang_variable_scope_grow(fun->parameters); + slang_atom a_retVal = slang_atom_pool_atom(A->atoms, "__retVal"); + assert(a_retVal); + p->a_name = a_retVal; + p->type = fun->header.type; + p->type.qualifier = SLANG_QUAL_OUT; + p->type.specifier.type = baseType; + fun->param_count++; + } + + /* function body is: + * block: + * declare T; + * T[0] = p0; + * T[1] = p1; + * ... + * T[n] = pn; + * return T; + */ + { + slang_variable_scope *scope; + slang_variable *var; + GLint i; + + fun->body = slang_operation_new(1); + fun->body->type = SLANG_OPER_BLOCK_NEW_SCOPE; + fun->body->num_children = num_elements + 2; + fun->body->children = slang_operation_new(num_elements + 2); + + scope = fun->body->locals; + scope->outer_scope = fun->parameters; + + /* create local var 't' */ + var = slang_variable_scope_grow(scope); + var->a_name = slang_atom_pool_atom(A->atoms, "ttt"); + var->type = fun->header.type;/*XXX copy*/ + + /* declare t */ + { + slang_operation *decl; + + decl = &fun->body->children[0]; + decl->type = SLANG_OPER_VARIABLE_DECL; + decl->locals = _slang_variable_scope_new(scope); + decl->a_id = var->a_name; + } + + /* assign params to elements of t */ + for (i = 0; i < num_elements; i++) { + slang_operation *assign = &fun->body->children[1 + i]; + + assign->type = SLANG_OPER_ASSIGN; + assign->locals = _slang_variable_scope_new(scope); + assign->num_children = 2; + assign->children = slang_operation_new(2); + + { + slang_operation *lhs = &assign->children[0]; + + lhs->type = SLANG_OPER_SUBSCRIPT; + lhs->locals = _slang_variable_scope_new(scope); + lhs->num_children = 2; + lhs->children = slang_operation_new(2); + + lhs->children[0].type = SLANG_OPER_IDENTIFIER; + lhs->children[0].a_id = var->a_name; + lhs->children[0].locals = _slang_variable_scope_new(scope); + + lhs->children[1].type = SLANG_OPER_LITERAL_INT; + lhs->children[1].literal[0] = (GLfloat) i; + } + + { + slang_operation *rhs = &assign->children[1]; + + rhs->type = SLANG_OPER_IDENTIFIER; + rhs->locals = _slang_variable_scope_new(scope); + rhs->a_id = fun->parameters->variables[i]->a_name; + } + } + + /* return t; */ + { + slang_operation *ret = &fun->body->children[num_elements + 1]; + + ret->type = SLANG_OPER_RETURN; + ret->locals = _slang_variable_scope_new(scope); + ret->num_children = 1; + ret->children = slang_operation_new(1); + ret->children[0].type = SLANG_OPER_IDENTIFIER; + ret->children[0].a_id = var->a_name; + ret->children[0].locals = _slang_variable_scope_new(scope); + } + } + + /* + slang_print_function(fun, 1); + */ + + return fun; +} + + +static GLboolean +_slang_is_vec_mat_type(const char *name) +{ + static const char *vecmat_types[] = { + "float", "int", "bool", + "vec2", "vec3", "vec4", + "ivec2", "ivec3", "ivec4", + "bvec2", "bvec3", "bvec4", + "mat2", "mat3", "mat4", + "mat2x3", "mat2x4", "mat3x2", "mat3x4", "mat4x2", "mat4x3", + NULL + }; + int i; + for (i = 0; vecmat_types[i]; i++) + if (strcmp(name, vecmat_types[i]) == 0) + return GL_TRUE; + return GL_FALSE; +} + + +/** + * Assemble a function call, given a particular function name. + * \param name the function's name (operators like '*' are possible). + */ +static slang_ir_node * +_slang_gen_function_call_name(slang_assemble_ctx *A, const char *name, + slang_operation *oper, slang_operation *dest) +{ + slang_operation *params = oper->children; + const GLuint param_count = oper->num_children; + slang_atom atom; + slang_function *fun; + slang_ir_node *n; + + atom = slang_atom_pool_atom(A->atoms, name); + if (atom == SLANG_ATOM_NULL) + return NULL; + + if (oper->array_constructor) { + /* this needs special handling */ + fun = _slang_make_array_constructor(A, oper); + } + else { + /* Try to find function by name and exact argument type matching */ + GLboolean error = GL_FALSE; + fun = _slang_function_locate(A->space.funcs, atom, params, param_count, + &A->space, A->atoms, A->log, &error); + if (error) { + slang_info_log_error(A->log, + "Function '%s' not found (check argument types)", + name); + return NULL; + } + } + + if (!fun) { + /* Next, try locating a constructor function for a user-defined type */ + fun = _slang_locate_struct_constructor(A, name); + } + + /* + * At this point, some heuristics are used to try to find a function + * that matches the calling signature by means of casting or "unrolling" + * of constructors. + */ + + if (!fun && _slang_is_vec_mat_type(name)) { + /* Next, if this call looks like a vec() or mat() constructor call, + * try "unwinding" the args to satisfy a constructor. + */ + fun = _slang_find_function_by_max_argc(A->space.funcs, name); + if (fun) { + if (!_slang_adapt_call(oper, fun, &A->space, A->atoms, A->log)) { + slang_info_log_error(A->log, + "Function '%s' not found (check argument types)", + name); + return NULL; + } + } + } + + if (!fun && _slang_is_vec_mat_type(name)) { + /* Next, try casting args to the types of the formal parameters */ + int numArgs = oper->num_children; + fun = _slang_find_function_by_argc(A->space.funcs, name, numArgs); + if (!fun || !_slang_cast_func_params(oper, fun, &A->space, A->atoms, A->log)) { + slang_info_log_error(A->log, + "Function '%s' not found (check argument types)", + name); + return NULL; + } + assert(fun); + } + + if (!fun) { + slang_info_log_error(A->log, + "Function '%s' not found (check argument types)", + name); + return NULL; + } + + if (!fun->body) { + /* The function body may be in another compilation unit. + * We'll try concatenating the shaders and recompile at link time. + */ + A->UnresolvedRefs = GL_TRUE; + return new_node1(IR_NOP, NULL); + } + + /* type checking to be sure function's return type matches 'dest' type */ + if (dest) { + slang_typeinfo t0; + + slang_typeinfo_construct(&t0); + typeof_operation(A, dest, &t0); + + if (!slang_type_specifier_equal(&t0.spec, &fun->header.type.specifier)) { + slang_info_log_error(A->log, + "Incompatible type returned by call to '%s'", + name); + return NULL; + } + } + + n = _slang_gen_function_call(A, fun, oper, dest); + + if (n && !n->Store && !dest + && fun->header.type.specifier.type != SLANG_SPEC_VOID) { + /* setup n->Store for the result of the function call */ + GLint size = _slang_sizeof_type_specifier(&fun->header.type.specifier); + n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, size); + /*printf("Alloc storage for function result, size %d \n", size);*/ + } + + if (oper->array_constructor) { + /* free the temporary array constructor function now */ + slang_function_destruct(fun); + } + + return n; +} + + +static slang_ir_node * +_slang_gen_method_call(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_atom *a_length = slang_atom_pool_atom(A->atoms, "length"); + slang_ir_node *n; + slang_variable *var; + + /* NOTE: In GLSL 1.20, there's only one kind of method + * call: array.length(). Anything else is an error. + */ + if (oper->a_id != a_length) { + slang_info_log_error(A->log, + "Undefined method call '%s'", (char *) oper->a_id); + return NULL; + } + + /* length() takes no arguments */ + if (oper->num_children > 0) { + slang_info_log_error(A->log, "Invalid arguments to length() method"); + return NULL; + } + + /* lookup the object/variable */ + var = _slang_variable_locate(oper->locals, oper->a_obj, GL_TRUE); + if (!var || var->type.specifier.type != SLANG_SPEC_ARRAY) { + slang_info_log_error(A->log, + "Undefined object '%s'", (char *) oper->a_obj); + return NULL; + } + + /* Create a float/literal IR node encoding the array length */ + n = new_node0(IR_FLOAT); + if (n) { + n->Value[0] = (float) _slang_array_length(var); + n->Store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, 1); + } + return n; +} + + +static GLboolean +_slang_is_constant_cond(const slang_operation *oper, GLboolean *value) +{ + if (oper->type == SLANG_OPER_LITERAL_FLOAT || + oper->type == SLANG_OPER_LITERAL_INT || + oper->type == SLANG_OPER_LITERAL_BOOL) { + if (oper->literal[0]) + *value = GL_TRUE; + else + *value = GL_FALSE; + return GL_TRUE; + } + else if (oper->type == SLANG_OPER_EXPRESSION && + oper->num_children == 1) { + return _slang_is_constant_cond(&oper->children[0], value); + } + return GL_FALSE; +} + + +/** + * Test if an operation is a scalar or boolean. + */ +static GLboolean +_slang_is_scalar_or_boolean(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_typeinfo type; + GLint size; + + slang_typeinfo_construct(&type); + typeof_operation(A, oper, &type); + size = _slang_sizeof_type_specifier(&type.spec); + slang_typeinfo_destruct(&type); + return size == 1; +} + + +/** + * Test if an operation is boolean. + */ +static GLboolean +_slang_is_boolean(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_typeinfo type; + GLboolean isBool; + + slang_typeinfo_construct(&type); + typeof_operation(A, oper, &type); + isBool = (type.spec.type == SLANG_SPEC_BOOL); + slang_typeinfo_destruct(&type); + return isBool; +} + + +/** + * Check if a loop contains a 'continue' statement. + * Stop looking if we find a nested loop. + */ +static GLboolean +_slang_loop_contains_continue(const slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_CONTINUE: + return GL_TRUE; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + return GL_FALSE; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + const slang_operation *child = slang_oper_child_const(oper, i); + if (_slang_loop_contains_continue(child)) + return GL_TRUE; + } + } + return GL_FALSE; + } +} + + +/** + * Check if a loop contains a 'continue' or 'break' statement. + * Stop looking if we find a nested loop. + */ +static GLboolean +_slang_loop_contains_continue_or_break(const slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_CONTINUE: + case SLANG_OPER_BREAK: + return GL_TRUE; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + return GL_FALSE; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + const slang_operation *child = slang_oper_child_const(oper, i); + if (_slang_loop_contains_continue_or_break(child)) + return GL_TRUE; + } + } + return GL_FALSE; + } +} + + +/** + * Replace 'break' and 'continue' statements inside a do and while loops. + * This is a recursive helper function used by + * _slang_gen_do/while_without_continue(). + */ +static void +replace_break_and_cont(slang_assemble_ctx *A, slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_BREAK: + /* replace 'break' with "_notBreakFlag = false; break" */ + { + slang_operation *block = oper; + block->type = SLANG_OPER_BLOCK_NEW_SCOPE; + slang_operation_add_children(block, 2); + { + slang_operation *assign = slang_oper_child(block, 0); + assign->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(assign, 2); + { + slang_operation *lhs = slang_oper_child(assign, 0); + slang_operation_identifier(lhs, A, "_notBreakFlag"); + } + { + slang_operation *rhs = slang_oper_child(assign, 1); + slang_operation_literal_bool(rhs, GL_FALSE); + } + } + { + slang_operation *brk = slang_oper_child(block, 1); + brk->type = SLANG_OPER_BREAK; + assert(!brk->children); + } + } + break; + case SLANG_OPER_CONTINUE: + /* convert continue into a break */ + oper->type = SLANG_OPER_BREAK; + break; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + break; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + replace_break_and_cont(A, slang_oper_child(oper, i)); + } + } + } +} + + +/** + * Transform a while-loop so that continue statements are converted to breaks. + * Then do normal IR code generation. + * + * Before: + * + * while (LOOPCOND) { + * A; + * if (IFCOND) + * continue; + * B; + * break; + * C; + * } + * + * After: + * + * { + * bool _notBreakFlag = 1; + * while (_notBreakFlag && LOOPCOND) { + * do { + * A; + * if (IFCOND) { + * break; // was continue + * } + * B; + * _notBreakFlag = 0; // was + * break; // break + * C; + * } while (0) + * } + * } + */ +static slang_ir_node * +_slang_gen_while_without_continue(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *top; + slang_operation *innerBody; + + assert(oper->type == SLANG_OPER_WHILE); + + top = slang_operation_new(1); + top->type = SLANG_OPER_BLOCK_NEW_SCOPE; + top->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(top, 2); + + /* declare: bool _notBreakFlag = true */ + { + slang_operation *condDecl = slang_oper_child(top, 0); + slang_generate_declaration(A, top->locals, condDecl, + SLANG_SPEC_BOOL, "_notBreakFlag", GL_TRUE); + } + + /* build outer while-loop: while (_notBreakFlag && LOOPCOND) { ... } */ + { + slang_operation *outerWhile = slang_oper_child(top, 1); + outerWhile->type = SLANG_OPER_WHILE; + slang_operation_add_children(outerWhile, 2); + + /* _notBreakFlag && LOOPCOND */ + { + slang_operation *cond = slang_oper_child(outerWhile, 0); + cond->type = SLANG_OPER_LOGICALAND; + slang_operation_add_children(cond, 2); + { + slang_operation *notBreak = slang_oper_child(cond, 0); + slang_operation_identifier(notBreak, A, "_notBreakFlag"); + } + { + slang_operation *origCond = slang_oper_child(cond, 1); + slang_operation_copy(origCond, slang_oper_child(oper, 0)); + } + } + + /* inner loop */ + { + slang_operation *innerDo = slang_oper_child(outerWhile, 1); + innerDo->type = SLANG_OPER_DO; + slang_operation_add_children(innerDo, 2); + + /* copy original do-loop body into inner do-loop's body */ + innerBody = slang_oper_child(innerDo, 0); + slang_operation_copy(innerBody, slang_oper_child(oper, 1)); + innerBody->locals->outer_scope = innerDo->locals; + + /* inner do-loop's condition is constant/false */ + { + slang_operation *constFalse = slang_oper_child(innerDo, 1); + slang_operation_literal_bool(constFalse, GL_FALSE); + } + } + } + + /* Finally, in innerBody, + * replace "break" with "_notBreakFlag = 0; break" + * replace "continue" with "break" + */ + replace_break_and_cont(A, innerBody); + + /*slang_print_tree(top, 0);*/ + + return _slang_gen_operation(A, top); + + return NULL; +} + + +/** + * Generate loop code using high-level IR_LOOP instruction + */ +static slang_ir_node * +_slang_gen_while(slang_assemble_ctx * A, slang_operation *oper) +{ + /* + * LOOP: + * BREAK if !expr (child[0]) + * body code (child[1]) + */ + slang_ir_node *loop, *breakIf, *body; + GLboolean isConst, constTrue = GL_FALSE; + + if (!A->EmitContReturn) { + /* We don't want to emit CONT instructions. If this while-loop has + * a continue, translate it away. + */ + if (_slang_loop_contains_continue(slang_oper_child(oper, 1))) { + return _slang_gen_while_without_continue(A, oper); + } + } + + /* type-check expression */ + if (!_slang_is_boolean(A, &oper->children[0])) { + slang_info_log_error(A->log, "scalar/boolean expression expected for 'while'"); + return NULL; + } + + /* Check if loop condition is a constant */ + isConst = _slang_is_constant_cond(&oper->children[0], &constTrue); + + if (isConst && !constTrue) { + /* loop is never executed! */ + return new_node0(IR_NOP); + } + + /* Begin new loop */ + loop = new_loop(NULL); + + /* save loop state */ + push_loop(A, oper, loop); + + if (isConst && constTrue) { + /* while(nonzero constant), no conditional break */ + breakIf = NULL; + } + else { + slang_ir_node *cond + = new_cond(new_not(_slang_gen_operation(A, &oper->children[0]))); + breakIf = new_break_if_true(A, cond); + } + body = _slang_gen_operation(A, &oper->children[1]); + loop->Children[0] = new_seq(breakIf, body); + + /* Do infinite loop detection */ + /* loop->List is head of linked list of break/continue nodes */ + if (!loop->List && isConst && constTrue) { + /* infinite loop detected */ + pop_loop(A); + slang_info_log_error(A->log, "Infinite loop detected!"); + return NULL; + } + + /* restore loop state */ + pop_loop(A); + + return loop; +} + + +/** + * Transform a do-while-loop so that continue statements are converted to breaks. + * Then do normal IR code generation. + * + * Before: + * + * do { + * A; + * if (IFCOND) + * continue; + * B; + * break; + * C; + * } while (LOOPCOND); + * + * After: + * + * { + * bool _notBreakFlag = 1; + * do { + * do { + * A; + * if (IFCOND) { + * break; // was continue + * } + * B; + * _notBreakFlag = 0; // was + * break; // break + * C; + * } while (0) + * } while (_notBreakFlag && LOOPCOND); + * } + */ +static slang_ir_node * +_slang_gen_do_without_continue(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *top; + slang_operation *innerBody; + + assert(oper->type == SLANG_OPER_DO); + + top = slang_operation_new(1); + top->type = SLANG_OPER_BLOCK_NEW_SCOPE; + top->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(top, 2); + + /* declare: bool _notBreakFlag = true */ + { + slang_operation *condDecl = slang_oper_child(top, 0); + slang_generate_declaration(A, top->locals, condDecl, + SLANG_SPEC_BOOL, "_notBreakFlag", GL_TRUE); + } + + /* build outer do-loop: do { ... } while (_notBreakFlag && LOOPCOND) */ + { + slang_operation *outerDo = slang_oper_child(top, 1); + outerDo->type = SLANG_OPER_DO; + slang_operation_add_children(outerDo, 2); + + /* inner do-loop */ + { + slang_operation *innerDo = slang_oper_child(outerDo, 0); + innerDo->type = SLANG_OPER_DO; + slang_operation_add_children(innerDo, 2); + + /* copy original do-loop body into inner do-loop's body */ + innerBody = slang_oper_child(innerDo, 0); + slang_operation_copy(innerBody, slang_oper_child(oper, 0)); + innerBody->locals->outer_scope = innerDo->locals; + + /* inner do-loop's condition is constant/false */ + { + slang_operation *constFalse = slang_oper_child(innerDo, 1); + slang_operation_literal_bool(constFalse, GL_FALSE); + } + } + + /* _notBreakFlag && LOOPCOND */ + { + slang_operation *cond = slang_oper_child(outerDo, 1); + cond->type = SLANG_OPER_LOGICALAND; + slang_operation_add_children(cond, 2); + { + slang_operation *notBreak = slang_oper_child(cond, 0); + slang_operation_identifier(notBreak, A, "_notBreakFlag"); + } + { + slang_operation *origCond = slang_oper_child(cond, 1); + slang_operation_copy(origCond, slang_oper_child(oper, 1)); + } + } + } + + /* Finally, in innerBody, + * replace "break" with "_notBreakFlag = 0; break" + * replace "continue" with "break" + */ + replace_break_and_cont(A, innerBody); + + /*slang_print_tree(top, 0);*/ + + return _slang_gen_operation(A, top); +} + + +/** + * Generate IR tree for a do-while loop using high-level LOOP, IF instructions. + */ +static slang_ir_node * +_slang_gen_do(slang_assemble_ctx * A, slang_operation *oper) +{ + /* + * LOOP: + * body code (child[0]) + * tail code: + * BREAK if !expr (child[1]) + */ + slang_ir_node *loop; + GLboolean isConst, constTrue; + + if (!A->EmitContReturn) { + /* We don't want to emit CONT instructions. If this do-loop has + * a continue, translate it away. + */ + if (_slang_loop_contains_continue(slang_oper_child(oper, 0))) { + return _slang_gen_do_without_continue(A, oper); + } + } + + /* type-check expression */ + if (!_slang_is_boolean(A, &oper->children[1])) { + slang_info_log_error(A->log, "scalar/boolean expression expected for 'do/while'"); + return NULL; + } + + loop = new_loop(NULL); + + /* save loop state */ + push_loop(A, oper, loop); + + /* loop body: */ + loop->Children[0] = _slang_gen_operation(A, &oper->children[0]); + + /* Check if loop condition is a constant */ + isConst = _slang_is_constant_cond(&oper->children[1], &constTrue); + if (isConst && constTrue) { + /* do { } while(1) ==> no conditional break */ + loop->Children[1] = NULL; /* no tail code */ + } + else { + slang_ir_node *cond + = new_cond(new_not(_slang_gen_operation(A, &oper->children[1]))); + loop->Children[1] = new_break_if_true(A, cond); + } + + /* XXX we should do infinite loop detection, as above */ + + /* restore loop state */ + pop_loop(A); + + return loop; +} + + +/** + * Recursively count the number of operations rooted at 'oper'. + * This gives some kind of indication of the size/complexity of an operation. + */ +static GLuint +sizeof_operation(const slang_operation *oper) +{ + if (oper) { + GLuint count = 1; /* me */ + GLuint i; + for (i = 0; i < oper->num_children; i++) { + count += sizeof_operation(&oper->children[i]); + } + return count; + } + else { + return 0; + } +} + + +/** + * Determine if a for-loop can be unrolled. + * At this time, only a rather narrow class of for loops can be unrolled. + * See code for details. + * When a loop can't be unrolled because it's too large we'll emit a + * message to the log. + */ +static GLboolean +_slang_can_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) +{ + GLuint bodySize; + GLint start, end; + const char *varName; + slang_atom varId; + + if (oper->type != SLANG_OPER_FOR) + return GL_FALSE; + + assert(oper->num_children == 4); + + if (_slang_loop_contains_continue_or_break(slang_oper_child_const(oper, 3))) + return GL_FALSE; + + /* children[0] must be either "int i=constant" or "i=constant" */ + if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) { + slang_variable *var; + + if (oper->children[0].children[0].type != SLANG_OPER_VARIABLE_DECL) + return GL_FALSE; + + varId = oper->children[0].children[0].a_id; + + var = _slang_variable_locate(oper->children[0].children[0].locals, + varId, GL_TRUE); + if (!var) + return GL_FALSE; + if (!var->initializer) + return GL_FALSE; + if (var->initializer->type != SLANG_OPER_LITERAL_INT) + return GL_FALSE; + start = (GLint) var->initializer->literal[0]; + } + else if (oper->children[0].type == SLANG_OPER_EXPRESSION) { + if (oper->children[0].children[0].type != SLANG_OPER_ASSIGN) + return GL_FALSE; + if (oper->children[0].children[0].children[0].type != SLANG_OPER_IDENTIFIER) + return GL_FALSE; + if (oper->children[0].children[0].children[1].type != SLANG_OPER_LITERAL_INT) + return GL_FALSE; + + varId = oper->children[0].children[0].children[0].a_id; + + start = (GLint) oper->children[0].children[0].children[1].literal[0]; + } + else { + return GL_FALSE; + } + + /* children[1] must be "ichildren[1].type != SLANG_OPER_EXPRESSION) + return GL_FALSE; + if (oper->children[1].children[0].type != SLANG_OPER_LESS) + return GL_FALSE; + if (oper->children[1].children[0].children[0].type != SLANG_OPER_IDENTIFIER) + return GL_FALSE; + if (oper->children[1].children[0].children[1].type != SLANG_OPER_LITERAL_INT) + return GL_FALSE; + + end = (GLint) oper->children[1].children[0].children[1].literal[0]; + + /* children[2] must be "i++" or "++i" */ + if (oper->children[2].type != SLANG_OPER_POSTINCREMENT && + oper->children[2].type != SLANG_OPER_PREINCREMENT) + return GL_FALSE; + if (oper->children[2].children[0].type != SLANG_OPER_IDENTIFIER) + return GL_FALSE; + + /* make sure the same variable name is used in all places */ + if ((oper->children[1].children[0].children[0].a_id != varId) || + (oper->children[2].children[0].a_id != varId)) + return GL_FALSE; + + varName = (const char *) varId; + + /* children[3], the loop body, can't be too large */ + bodySize = sizeof_operation(&oper->children[3]); + if (bodySize > MAX_FOR_LOOP_UNROLL_BODY_SIZE) { + slang_info_log_print(A->log, + "Note: 'for (%s ... )' body is too large/complex" + " to unroll", + varName); + return GL_FALSE; + } + + if (start >= end) + return GL_FALSE; /* degenerate case */ + + if ((GLuint)(end - start) > MAX_FOR_LOOP_UNROLL_ITERATIONS) { + slang_info_log_print(A->log, + "Note: 'for (%s=%d; %s<%d; ++%s)' is too" + " many iterations to unroll", + varName, start, varName, end, varName); + return GL_FALSE; + } + + if ((end - start) * bodySize > MAX_FOR_LOOP_UNROLL_COMPLEXITY) { + slang_info_log_print(A->log, + "Note: 'for (%s=%d; %s<%d; ++%s)' will generate" + " too much code to unroll", + varName, start, varName, end, varName); + return GL_FALSE; + } + + return GL_TRUE; /* we can unroll the loop */ +} + + +/** + * Unroll a for-loop. + * First we determine the number of iterations to unroll. + * Then for each iteration: + * make a copy of the loop body + * replace instances of the loop variable with the current iteration value + * generate IR code for the body + * \return pointer to generated IR code or NULL if error, out of memory, etc. + */ +static slang_ir_node * +_slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) +{ + GLint start, end, iter; + slang_ir_node *n, *root = NULL; + slang_atom varId; + + if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) { + /* for (int i=0; ... */ + slang_variable *var; + + varId = oper->children[0].children[0].a_id; + var = _slang_variable_locate(oper->children[0].children[0].locals, + varId, GL_TRUE); + assert(var); + start = (GLint) var->initializer->literal[0]; + } + else { + /* for (i=0; ... */ + varId = oper->children[0].children[0].children[0].a_id; + start = (GLint) oper->children[0].children[0].children[1].literal[0]; + } + + end = (GLint) oper->children[1].children[0].children[1].literal[0]; + + for (iter = start; iter < end; iter++) { + slang_operation *body; + + /* make a copy of the loop body */ + body = slang_operation_new(1); + if (!body) + return NULL; + + if (!slang_operation_copy(body, &oper->children[3])) + return NULL; + + /* in body, replace instances of 'varId' with literal 'iter' */ + { + slang_variable *oldVar; + slang_operation *newOper; + + oldVar = _slang_variable_locate(oper->locals, varId, GL_TRUE); + if (!oldVar) { + /* undeclared loop variable */ + slang_operation_delete(body); + return NULL; + } + + newOper = slang_operation_new(1); + newOper->type = SLANG_OPER_LITERAL_INT; + newOper->literal_size = 1; + newOper->literal[0] = (GLfloat) iter; + + /* replace instances of the loop variable with newOper */ + slang_substitute(A, body, 1, &oldVar, &newOper, GL_FALSE); + } + + /* do IR codegen for body */ + n = _slang_gen_operation(A, body); + if (!n) + return NULL; + + root = new_seq(root, n); + + slang_operation_delete(body); + } + + return root; +} + + +/** + * Replace 'continue' statement with 'break' inside a for-loop. + * This is a recursive helper function used by _slang_gen_for_without_continue(). + */ +static void +replace_continue_with_break(slang_assemble_ctx *A, slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_CONTINUE: + oper->type = SLANG_OPER_BREAK; + break; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + break; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + replace_continue_with_break(A, slang_oper_child(oper, i)); + } + } + } +} + + +/** + * Transform a for-loop so that continue statements are converted to breaks. + * Then do normal IR code generation. + * + * Before: + * + * for (INIT; LOOPCOND; INCR) { + * A; + * if (IFCOND) { + * continue; + * } + * B; + * } + * + * After: + * + * { + * bool _condFlag = 1; + * for (INIT; _condFlag; ) { + * for ( ; _condFlag = LOOPCOND; INCR) { + * A; + * if (IFCOND) { + * break; + * } + * B; + * } + * if (_condFlag) + * INCR; + * } + * } + */ +static slang_ir_node * +_slang_gen_for_without_continue(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *top; + slang_operation *outerFor, *innerFor, *init, *cond, *incr; + slang_operation *lhs, *rhs; + + assert(oper->type == SLANG_OPER_FOR); + + top = slang_operation_new(1); + top->type = SLANG_OPER_BLOCK_NEW_SCOPE; + top->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(top, 2); + + /* declare: bool _condFlag = true */ + { + slang_operation *condDecl = slang_oper_child(top, 0); + slang_generate_declaration(A, top->locals, condDecl, + SLANG_SPEC_BOOL, "_condFlag", GL_TRUE); + } + + /* build outer loop: for (INIT; _condFlag; ) { */ + outerFor = slang_oper_child(top, 1); + outerFor->type = SLANG_OPER_FOR; + slang_operation_add_children(outerFor, 4); + + init = slang_oper_child(outerFor, 0); + slang_operation_copy(init, slang_oper_child(oper, 0)); + + cond = slang_oper_child(outerFor, 1); + cond->type = SLANG_OPER_IDENTIFIER; + cond->a_id = slang_atom_pool_atom(A->atoms, "_condFlag"); + + incr = slang_oper_child(outerFor, 2); + incr->type = SLANG_OPER_VOID; + + /* body of the outer loop */ + { + slang_operation *block = slang_oper_child(outerFor, 3); + + slang_operation_add_children(block, 2); + block->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + + /* build inner loop: for ( ; _condFlag = LOOPCOND; INCR) { */ + { + innerFor = slang_oper_child(block, 0); + + /* make copy of orig loop */ + slang_operation_copy(innerFor, oper); + assert(innerFor->type == SLANG_OPER_FOR); + innerFor->locals->outer_scope = block->locals; + + init = slang_oper_child(innerFor, 0); + init->type = SLANG_OPER_VOID; /* leak? */ + + cond = slang_oper_child(innerFor, 1); + slang_operation_destruct(cond); + cond->type = SLANG_OPER_ASSIGN; + cond->locals = _slang_variable_scope_new(innerFor->locals); + slang_operation_add_children(cond, 2); + + lhs = slang_oper_child(cond, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "_condFlag"); + + rhs = slang_oper_child(cond, 1); + slang_operation_copy(rhs, slang_oper_child(oper, 1)); + } + + /* if (_condFlag) INCR; */ + { + slang_operation *ifop = slang_oper_child(block, 1); + ifop->type = SLANG_OPER_IF; + slang_operation_add_children(ifop, 2); + + /* re-use cond node build above */ + slang_operation_copy(slang_oper_child(ifop, 0), cond); + + /* incr node from original for-loop operation */ + slang_operation_copy(slang_oper_child(ifop, 1), + slang_oper_child(oper, 2)); + } + + /* finally, replace "continue" with "break" in the inner for-loop */ + replace_continue_with_break(A, slang_oper_child(innerFor, 3)); + } + + return _slang_gen_operation(A, top); +} + + + +/** + * Generate IR for a for-loop. Unrolling will be done when possible. + */ +static slang_ir_node * +_slang_gen_for(slang_assemble_ctx * A, slang_operation *oper) +{ + GLboolean unroll; + + if (!A->EmitContReturn) { + /* We don't want to emit CONT instructions. If this for-loop has + * a continue, translate it away. + */ + if (_slang_loop_contains_continue(slang_oper_child(oper, 3))) { + return _slang_gen_for_without_continue(A, oper); + } + } + + unroll = _slang_can_unroll_for_loop(A, oper); + if (unroll) { + slang_ir_node *code = _slang_unroll_for_loop(A, oper); + if (code) + return code; + } + + assert(oper->type == SLANG_OPER_FOR); + + /* conventional for-loop code generation */ + { + /* + * init code (child[0]) + * LOOP: + * BREAK if !expr (child[1]) + * body code (child[3]) + * tail code: + * incr code (child[2]) // XXX continue here + */ + slang_ir_node *loop, *cond, *breakIf, *body, *init, *incr; + init = _slang_gen_operation(A, &oper->children[0]); + loop = new_loop(NULL); + + /* save loop state */ + push_loop(A, oper, loop); + + cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[1]))); + breakIf = new_break_if_true(A, cond); + body = _slang_gen_operation(A, &oper->children[3]); + incr = _slang_gen_operation(A, &oper->children[2]); + + loop->Children[0] = new_seq(breakIf, body); + loop->Children[1] = incr; /* tail code */ + + /* restore loop state */ + pop_loop(A); + + return new_seq(init, loop); + } +} + + +static slang_ir_node * +_slang_gen_continue(slang_assemble_ctx * A, const slang_operation *oper) +{ + slang_ir_node *n, *cont, *incr = NULL, *loopNode; + + assert(oper->type == SLANG_OPER_CONTINUE); + loopNode = current_loop_ir(A); + assert(loopNode); + assert(loopNode->Opcode == IR_LOOP); + + cont = new_node0(IR_CONT); + if (cont) { + cont->Parent = loopNode; + /* insert this node at head of linked list of cont/break instructions */ + cont->List = loopNode->List; + loopNode->List = cont; + } + + n = new_seq(incr, cont); + return n; +} + + +/** + * Determine if the given operation is of a specific type. + */ +static GLboolean +is_operation_type(const slang_operation *oper, slang_operation_type type) +{ + if (oper->type == type) + return GL_TRUE; + else if ((oper->type == SLANG_OPER_BLOCK_NEW_SCOPE || + oper->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) && + oper->num_children == 1) + return is_operation_type(&oper->children[0], type); + else + return GL_FALSE; +} + + +/** + * Generate IR tree for an if/then/else conditional using high-level + * IR_IF instruction. + */ +static slang_ir_node * +_slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) +{ + /* + * eval expr (child[0]) + * IF expr THEN + * if-body code + * ELSE + * else-body code + * ENDIF + */ + const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]); + slang_ir_node *ifNode, *cond, *ifBody, *elseBody; + GLboolean isConst, constTrue; + + /* type-check expression */ + if (!_slang_is_boolean(A, &oper->children[0])) { + slang_info_log_error(A->log, "boolean expression expected for 'if'"); + return NULL; + } + + if (!_slang_is_scalar_or_boolean(A, &oper->children[0])) { + slang_info_log_error(A->log, "scalar/boolean expression expected for 'if'"); + return NULL; + } + + isConst = _slang_is_constant_cond(&oper->children[0], &constTrue); + if (isConst) { + if (constTrue) { + /* if (true) ... */ + return _slang_gen_operation(A, &oper->children[1]); + } + else { + /* if (false) ... */ + return _slang_gen_operation(A, &oper->children[2]); + } + } + + cond = _slang_gen_operation(A, &oper->children[0]); + cond = new_cond(cond); + + if (is_operation_type(&oper->children[1], SLANG_OPER_BREAK) + && !haveElseClause) { + /* Special case: generate a conditional break */ + ifBody = new_break_if_true(A, cond); + return ifBody; + } + else if (is_operation_type(&oper->children[1], SLANG_OPER_CONTINUE) + && !haveElseClause + && current_loop_oper(A) + && current_loop_oper(A)->type != SLANG_OPER_FOR) { + /* Special case: generate a conditional continue */ + ifBody = new_cont_if_true(A, cond); + return ifBody; + } + else { + /* general case */ + ifBody = _slang_gen_operation(A, &oper->children[1]); + if (haveElseClause) + elseBody = _slang_gen_operation(A, &oper->children[2]); + else + elseBody = NULL; + ifNode = new_if(cond, ifBody, elseBody); + return ifNode; + } +} + + + +static slang_ir_node * +_slang_gen_not(slang_assemble_ctx * A, const slang_operation *oper) +{ + slang_ir_node *n; + + assert(oper->type == SLANG_OPER_NOT); + + /* type-check expression */ + if (!_slang_is_scalar_or_boolean(A, &oper->children[0])) { + slang_info_log_error(A->log, + "scalar/boolean expression expected for '!'"); + return NULL; + } + + n = _slang_gen_operation(A, &oper->children[0]); + if (n) + return new_not(n); + else + return NULL; +} + + +static slang_ir_node * +_slang_gen_xor(slang_assemble_ctx * A, const slang_operation *oper) +{ + slang_ir_node *n1, *n2; + + assert(oper->type == SLANG_OPER_LOGICALXOR); + + if (!_slang_is_scalar_or_boolean(A, &oper->children[0]) || + !_slang_is_scalar_or_boolean(A, &oper->children[0])) { + slang_info_log_error(A->log, + "scalar/boolean expressions expected for '^^'"); + return NULL; + } + + n1 = _slang_gen_operation(A, &oper->children[0]); + if (!n1) + return NULL; + n2 = _slang_gen_operation(A, &oper->children[1]); + if (!n2) + return NULL; + return new_node2(IR_NOTEQUAL, n1, n2); +} + + +/** + * Generate IR node for storage of a temporary of given size. + */ +static slang_ir_node * +_slang_gen_temporary(GLint size) +{ + slang_ir_storage *store; + slang_ir_node *n = NULL; + + store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -2, size); + if (store) { + n = new_node0(IR_VAR_DECL); + if (n) { + n->Store = store; + } + else { + _slang_free(store); + } + } + return n; +} + + +/** + * Generate program constants for an array. + * Ex: const vec2[3] v = vec2[3](vec2(1,1), vec2(2,2), vec2(3,3)); + * This will allocate and initialize three vector constants, storing + * the array in constant memory, not temporaries like a non-const array. + * This can also be used for uniform array initializers. + * \return GL_TRUE for success, GL_FALSE if failure (semantic error, etc). + */ +static GLboolean +make_constant_array(slang_assemble_ctx *A, + slang_variable *var, + slang_operation *initializer) +{ + struct gl_program *prog = A->program; + const GLenum datatype = _slang_gltype_from_specifier(&var->type.specifier); + const char *varName = (char *) var->a_name; + const GLuint numElements = initializer->num_children; + GLint size; + GLuint i, j; + GLfloat *values; + + if (!var->store) { + var->store = _slang_new_ir_storage(PROGRAM_UNDEFINED, -6, -6); + } + size = var->store->Size; + + assert(var->type.qualifier == SLANG_QUAL_CONST || + var->type.qualifier == SLANG_QUAL_UNIFORM); + assert(initializer->type == SLANG_OPER_CALL); + assert(initializer->array_constructor); + + values = (GLfloat *) malloc(numElements * 4 * sizeof(GLfloat)); + + /* convert constructor params into ordinary floats */ + for (i = 0; i < numElements; i++) { + const slang_operation *op = &initializer->children[i]; + if (op->type != SLANG_OPER_LITERAL_FLOAT) { + /* unsupported type for this optimization */ + free(values); + return GL_FALSE; + } + for (j = 0; j < op->literal_size; j++) { + values[i * 4 + j] = op->literal[j]; + } + for ( ; j < 4; j++) { + values[i * 4 + j] = 0.0f; + } + } + + /* slightly different paths for constants vs. uniforms */ + if (var->type.qualifier == SLANG_QUAL_UNIFORM) { + var->store->File = PROGRAM_UNIFORM; + var->store->Index = _mesa_add_uniform(prog->Parameters, varName, + size, datatype, values); + } + else { + var->store->File = PROGRAM_CONSTANT; + var->store->Index = _mesa_add_named_constant(prog->Parameters, varName, + values, size); + } + assert(var->store->Size == size); + + free(values); + + return GL_TRUE; +} + + + +/** + * Generate IR node for allocating/declaring a variable (either a local or + * a global). + * Generally, this involves allocating an slang_ir_storage instance for the + * variable, choosing a register file (temporary, constant, etc). + * For ordinary variables we do not yet allocate storage though. We do that + * when we find the first actual use of the variable to avoid allocating temp + * regs that will never get used. + * At this time, uniforms are always allocated space in this function. + * + * \param initializer Optional initializer expression for the variable. + */ +static slang_ir_node * +_slang_gen_var_decl(slang_assemble_ctx *A, slang_variable *var, + slang_operation *initializer) +{ + const char *varName = (const char *) var->a_name; + const GLenum datatype = _slang_gltype_from_specifier(&var->type.specifier); + slang_ir_node *varDecl, *n; + slang_ir_storage *store; + GLint arrayLen, size, totalSize; /* if array then totalSize > size */ + gl_register_file file; + + /*assert(!var->declared);*/ + var->declared = GL_TRUE; + + /* determine GPU register file for simple cases */ + if (is_sampler_type(&var->type)) { + file = PROGRAM_SAMPLER; + } + else if (var->type.qualifier == SLANG_QUAL_UNIFORM) { + file = PROGRAM_UNIFORM; + } + else { + file = PROGRAM_TEMPORARY; + } + + size = _slang_sizeof_type_specifier(&var->type.specifier); + if (size <= 0) { + slang_info_log_error(A->log, "invalid declaration for '%s'", varName); + return NULL; + } + + arrayLen = _slang_array_length(var); + totalSize = _slang_array_size(size, arrayLen); + + /* Allocate IR node for the declaration */ + varDecl = new_node0(IR_VAR_DECL); + if (!varDecl) + return NULL; + + /* Allocate slang_ir_storage for this variable if needed. + * Note that we may not actually allocate a constant or temporary register + * until later. + */ + if (!var->store) { + GLint index = -7; /* TBD / unknown */ + var->store = _slang_new_ir_storage(file, index, totalSize); + if (!var->store) + return NULL; /* out of memory */ + } + + /* set the IR node's Var and Store pointers */ + varDecl->Var = var; + varDecl->Store = var->store; + + + store = var->store; + + /* if there's an initializer, generate IR for the expression */ + if (initializer) { + slang_ir_node *varRef, *init; + + if (var->type.qualifier == SLANG_QUAL_CONST) { + /* if the variable is const, the initializer must be a const + * expression as well. + */ +#if 0 + if (!_slang_is_constant_expr(initializer)) { + slang_info_log_error(A->log, + "initializer for %s not constant", varName); + return NULL; + } +#endif + } + + if (var->type.qualifier == SLANG_QUAL_UNIFORM && + !A->allow_uniform_initializers) { + slang_info_log_error(A->log, + "initializer for uniform %s not allowed", + varName); + return NULL; + } + + /* IR for the variable we're initializing */ + varRef = new_var(A, var); + if (!varRef) { + slang_info_log_error(A->log, "out of memory"); + return NULL; + } + + /* constant-folding, etc here */ + _slang_simplify(initializer, &A->space, A->atoms); + + /* look for simple constant-valued variables and uniforms */ + if (var->type.qualifier == SLANG_QUAL_CONST || + var->type.qualifier == SLANG_QUAL_UNIFORM) { + + if (initializer->type == SLANG_OPER_CALL && + initializer->array_constructor) { + /* array initializer */ + if (make_constant_array(A, var, initializer)) + return varRef; + } + else if (initializer->type == SLANG_OPER_LITERAL_FLOAT || + initializer->type == SLANG_OPER_LITERAL_INT) { + /* simple float/vector initializer */ + if (store->File == PROGRAM_UNIFORM) { + store->Index = _mesa_add_uniform(A->program->Parameters, + varName, + totalSize, datatype, + initializer->literal); + store->Swizzle = _slang_var_swizzle(size, 0); + return varRef; + } +#if 0 + else { + store->File = PROGRAM_CONSTANT; + store->Index = _mesa_add_named_constant(A->program->Parameters, + varName, + initializer->literal, + totalSize); + store->Swizzle = _slang_var_swizzle(size, 0); + return varRef; + } +#endif + } + } + + /* IR for initializer */ + init = _slang_gen_operation(A, initializer); + if (!init) + return NULL; + + /* XXX remove this when type checking is added above */ + if (init->Store && init->Store->Size != totalSize) { + slang_info_log_error(A->log, "invalid assignment (wrong types)"); + return NULL; + } + + /* assign RHS to LHS */ + n = new_node2(IR_COPY, varRef, init); + n = new_seq(varDecl, n); + } + else { + /* no initializer */ + n = varDecl; + } + + if (store->File == PROGRAM_UNIFORM && store->Index < 0) { + /* always need to allocate storage for uniforms at this point */ + store->Index = _mesa_add_uniform(A->program->Parameters, varName, + totalSize, datatype, NULL); + store->Swizzle = _slang_var_swizzle(size, 0); + } + +#if 0 + printf("%s var %p %s store=%p index=%d size=%d\n", + __FUNCTION__, (void *) var, (char *) varName, + (void *) store, store->Index, store->Size); +#endif + + return n; +} + + +/** + * Generate code for a selection expression: b ? x : y + * XXX In some cases we could implement a selection expression + * with an LRP instruction (use the boolean as the interpolant). + * Otherwise, we use an IF/ELSE/ENDIF construct. + */ +static slang_ir_node * +_slang_gen_select(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_ir_node *cond, *ifNode, *trueExpr, *falseExpr, *trueNode, *falseNode; + slang_ir_node *tmpDecl, *tmpVar, *tree; + slang_typeinfo type0, type1, type2; + int size, isBool, isEqual; + + assert(oper->type == SLANG_OPER_SELECT); + assert(oper->num_children == 3); + + /* type of children[0] must be boolean */ + slang_typeinfo_construct(&type0); + typeof_operation(A, &oper->children[0], &type0); + isBool = (type0.spec.type == SLANG_SPEC_BOOL); + slang_typeinfo_destruct(&type0); + if (!isBool) { + slang_info_log_error(A->log, "selector type is not boolean"); + return NULL; + } + + slang_typeinfo_construct(&type1); + slang_typeinfo_construct(&type2); + typeof_operation(A, &oper->children[1], &type1); + typeof_operation(A, &oper->children[2], &type2); + isEqual = slang_type_specifier_equal(&type1.spec, &type2.spec); + slang_typeinfo_destruct(&type1); + slang_typeinfo_destruct(&type2); + if (!isEqual) { + slang_info_log_error(A->log, "incompatible types for ?: operator"); + return NULL; + } + + /* size of x or y's type */ + size = _slang_sizeof_type_specifier(&type1.spec); + assert(size > 0); + + /* temporary var */ + tmpDecl = _slang_gen_temporary(size); + + /* the condition (child 0) */ + cond = _slang_gen_operation(A, &oper->children[0]); + cond = new_cond(cond); + + /* if-true body (child 1) */ + tmpVar = new_node0(IR_VAR); + tmpVar->Store = tmpDecl->Store; + trueExpr = _slang_gen_operation(A, &oper->children[1]); + trueNode = new_node2(IR_COPY, tmpVar, trueExpr); + + /* if-false body (child 2) */ + tmpVar = new_node0(IR_VAR); + tmpVar->Store = tmpDecl->Store; + falseExpr = _slang_gen_operation(A, &oper->children[2]); + falseNode = new_node2(IR_COPY, tmpVar, falseExpr); + + ifNode = new_if(cond, trueNode, falseNode); + + /* tmp var value */ + tmpVar = new_node0(IR_VAR); + tmpVar->Store = tmpDecl->Store; + + tree = new_seq(ifNode, tmpVar); + tree = new_seq(tmpDecl, tree); + + /*_slang_print_ir_tree(tree, 10);*/ + return tree; +} + + +/** + * Generate code for &&. + */ +static slang_ir_node * +_slang_gen_logical_and(slang_assemble_ctx *A, slang_operation *oper) +{ + /* rewrite "a && b" as "a ? b : false" */ + slang_operation *select; + slang_ir_node *n; + + select = slang_operation_new(1); + select->type = SLANG_OPER_SELECT; + slang_operation_add_children(select, 3); + + slang_operation_copy(slang_oper_child(select, 0), &oper->children[0]); + slang_operation_copy(slang_oper_child(select, 1), &oper->children[1]); + slang_operation_literal_bool(slang_oper_child(select, 2), GL_FALSE); + + n = _slang_gen_select(A, select); + return n; +} + + +/** + * Generate code for ||. + */ +static slang_ir_node * +_slang_gen_logical_or(slang_assemble_ctx *A, slang_operation *oper) +{ + /* rewrite "a || b" as "a ? true : b" */ + slang_operation *select; + slang_ir_node *n; + + select = slang_operation_new(1); + select->type = SLANG_OPER_SELECT; + slang_operation_add_children(select, 3); + + slang_operation_copy(slang_oper_child(select, 0), &oper->children[0]); + slang_operation_literal_bool(slang_oper_child(select, 1), GL_TRUE); + slang_operation_copy(slang_oper_child(select, 2), &oper->children[1]); + + n = _slang_gen_select(A, select); + return n; +} + + +/** + * Generate IR tree for a return statement. + */ +static slang_ir_node * +_slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) +{ + assert(oper->type == SLANG_OPER_RETURN); + return new_return(A->curFuncEndLabel); +} + + +#if 0 +/** + * Determine if the given operation/expression is const-valued. + */ +static GLboolean +_slang_is_constant_expr(const slang_operation *oper) +{ + slang_variable *var; + GLuint i; + + switch (oper->type) { + case SLANG_OPER_IDENTIFIER: + var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); + if (var && var->type.qualifier == SLANG_QUAL_CONST) + return GL_TRUE; + return GL_FALSE; + default: + for (i = 0; i < oper->num_children; i++) { + if (!_slang_is_constant_expr(&oper->children[i])) + return GL_FALSE; + } + return GL_TRUE; + } +} +#endif + + +/** + * Check if an assignment of type t1 to t0 is legal. + * XXX more cases needed. + */ +static GLboolean +_slang_assignment_compatible(slang_assemble_ctx *A, + slang_operation *op0, + slang_operation *op1) +{ + slang_typeinfo t0, t1; + GLuint sz0, sz1; + + if (op0->type == SLANG_OPER_POSTINCREMENT || + op0->type == SLANG_OPER_POSTDECREMENT) { + return GL_FALSE; + } + + slang_typeinfo_construct(&t0); + typeof_operation(A, op0, &t0); + + slang_typeinfo_construct(&t1); + typeof_operation(A, op1, &t1); + + sz0 = _slang_sizeof_type_specifier(&t0.spec); + sz1 = _slang_sizeof_type_specifier(&t1.spec); + +#if 1 + if (sz0 != sz1) { + /*printf("assignment size mismatch %u vs %u\n", sz0, sz1);*/ + return GL_FALSE; + } +#endif + + if (t0.spec.type == SLANG_SPEC_STRUCT && + t1.spec.type == SLANG_SPEC_STRUCT && + t0.spec._struct->a_name != t1.spec._struct->a_name) + return GL_FALSE; + + if (t0.spec.type == SLANG_SPEC_FLOAT && + t1.spec.type == SLANG_SPEC_BOOL) + return GL_FALSE; + +#if 0 /* not used just yet - causes problems elsewhere */ + if (t0.spec.type == SLANG_SPEC_INT && + t1.spec.type == SLANG_SPEC_FLOAT) + return GL_FALSE; +#endif + + if (t0.spec.type == SLANG_SPEC_BOOL && + t1.spec.type == SLANG_SPEC_FLOAT) + return GL_FALSE; + + if (t0.spec.type == SLANG_SPEC_BOOL && + t1.spec.type == SLANG_SPEC_INT) + return GL_FALSE; + + return GL_TRUE; +} + + +/** + * Generate IR tree for a local variable declaration. + * Basically do some error checking and call _slang_gen_var_decl(). + */ +static slang_ir_node * +_slang_gen_declaration(slang_assemble_ctx *A, slang_operation *oper) +{ + const char *varName = (char *) oper->a_id; + slang_variable *var; + slang_ir_node *varDecl; + slang_operation *initializer; + + assert(oper->type == SLANG_OPER_VARIABLE_DECL); + assert(oper->num_children <= 1); + + + /* lookup the variable by name */ + var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); + if (!var) + return NULL; /* "shouldn't happen" */ + + if (var->type.qualifier == SLANG_QUAL_ATTRIBUTE || + var->type.qualifier == SLANG_QUAL_VARYING || + var->type.qualifier == SLANG_QUAL_UNIFORM) { + /* can't declare attribute/uniform vars inside functions */ + slang_info_log_error(A->log, + "local variable '%s' cannot be an attribute/uniform/varying", + varName); + return NULL; + } + +#if 0 + if (v->declared) { + slang_info_log_error(A->log, "variable '%s' redeclared", varName); + return NULL; + } +#endif + + /* check if the var has an initializer */ + if (oper->num_children > 0) { + assert(oper->num_children == 1); + initializer = &oper->children[0]; + } + else if (var->initializer) { + initializer = var->initializer; + } + else { + initializer = NULL; + } + + if (initializer) { + /* check/compare var type and initializer type */ + if (!_slang_assignment_compatible(A, oper, initializer)) { + slang_info_log_error(A->log, "incompatible types in assignment"); + return NULL; + } + } + else { + if (var->type.qualifier == SLANG_QUAL_CONST) { + slang_info_log_error(A->log, + "const-qualified variable '%s' requires initializer", + varName); + return NULL; + } + } + + /* Generate IR node */ + varDecl = _slang_gen_var_decl(A, var, initializer); + if (!varDecl) + return NULL; + + return varDecl; +} + + +/** + * Generate IR tree for a reference to a variable (such as in an expression). + * This is different from a variable declaration. + */ +static slang_ir_node * +_slang_gen_variable(slang_assemble_ctx * A, slang_operation *oper) +{ + /* If there's a variable associated with this oper (from inlining) + * use it. Otherwise, use the oper's var id. + */ + slang_atom name = oper->var ? oper->var->a_name : oper->a_id; + slang_variable *var = _slang_variable_locate(oper->locals, name, GL_TRUE); + slang_ir_node *n; + if (!var || !var->declared) { + slang_info_log_error(A->log, "undefined variable '%s'", (char *) name); + return NULL; + } + n = new_var(A, var); + return n; +} + + + +/** + * Return the number of components actually named by the swizzle. + * Recall that swizzles may have undefined/don't-care values. + */ +static GLuint +swizzle_size(GLuint swizzle) +{ + GLuint size = 0, i; + for (i = 0; i < 4; i++) { + GLuint swz = GET_SWZ(swizzle, i); + size += (swz <= 3); + } + return size; +} + + +static slang_ir_node * +_slang_gen_swizzle(slang_ir_node *child, GLuint swizzle) +{ + slang_ir_node *n = new_node1(IR_SWIZZLE, child); + assert(child); + if (n) { + assert(!n->Store); + n->Store = _slang_new_ir_storage_relative(0, + swizzle_size(swizzle), + child->Store); + assert(n->Store); + n->Store->Swizzle = swizzle; + } + return n; +} + + +static GLboolean +is_store_writable(const slang_assemble_ctx *A, const slang_ir_storage *store) +{ + while (store->Parent) + store = store->Parent; + + if (!(store->File == PROGRAM_OUTPUT || + store->File == PROGRAM_TEMPORARY || + (store->File == PROGRAM_VARYING && + A->program->Target == GL_VERTEX_PROGRAM_ARB))) { + return GL_FALSE; + } + else { + return GL_TRUE; + } +} + + +/** + * Walk up an IR storage path to compute the final swizzle. + * This is used when we find an expression such as "foo.xz.yx". + */ +static GLuint +root_swizzle(const slang_ir_storage *st) +{ + GLuint swizzle = st->Swizzle; + while (st->Parent) { + st = st->Parent; + swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle); + } + return swizzle; +} + + +/** + * Generate IR tree for an assignment (=). + */ +static slang_ir_node * +_slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper) +{ + slang_operation *pred = NULL; + slang_ir_node *n = NULL; + + if (oper->children[0].type == SLANG_OPER_IDENTIFIER) { + /* Check that var is writeable */ + const char *varName = (char *) oper->children[0].a_id; + slang_variable *var + = _slang_variable_locate(oper->children[0].locals, + oper->children[0].a_id, GL_TRUE); + if (!var) { + slang_info_log_error(A->log, "undefined variable '%s'", varName); + return NULL; + } + + if (var->type.qualifier == SLANG_QUAL_CONST || + var->type.qualifier == SLANG_QUAL_ATTRIBUTE || + var->type.qualifier == SLANG_QUAL_UNIFORM || + (var->type.qualifier == SLANG_QUAL_VARYING && + A->program->Target == GL_FRAGMENT_PROGRAM_ARB)) { + slang_info_log_error(A->log, + "illegal assignment to read-only variable '%s'", + varName); + return NULL; + } + + /* check if we need to predicate this assignment based on __notRetFlag */ + if ((var->is_global || + var->type.qualifier == SLANG_QUAL_OUT || + var->type.qualifier == SLANG_QUAL_INOUT) && A->UseReturnFlag) { + /* create predicate, used below */ + pred = slang_operation_new(1); + pred->type = SLANG_OPER_IDENTIFIER; + pred->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + pred->locals->outer_scope = oper->locals->outer_scope; + } + } + + if (oper->children[0].type == SLANG_OPER_IDENTIFIER && + oper->children[1].type == SLANG_OPER_CALL) { + /* Special case of: x = f(a, b) + * Replace with f(a, b, x) (where x == hidden __retVal out param) + * + * XXX this could be even more effective if we could accomodate + * cases such as "v.x = f();" - would help with typical vertex + * transformation. + */ + n = _slang_gen_function_call_name(A, + (const char *) oper->children[1].a_id, + &oper->children[1], &oper->children[0]); + } + else { + slang_ir_node *lhs, *rhs; + + /* lhs and rhs type checking */ + if (!_slang_assignment_compatible(A, + &oper->children[0], + &oper->children[1])) { + slang_info_log_error(A->log, "incompatible types in assignment"); + return NULL; + } + + lhs = _slang_gen_operation(A, &oper->children[0]); + if (!lhs) { + return NULL; + } + + if (!lhs->Store) { + slang_info_log_error(A->log, + "invalid left hand side for assignment"); + return NULL; + } + + /* check that lhs is writable */ + if (!is_store_writable(A, lhs->Store)) { + slang_info_log_error(A->log, + "illegal assignment to read-only l-value"); + return NULL; + } + + rhs = _slang_gen_operation(A, &oper->children[1]); + if (lhs && rhs) { + /* convert lhs swizzle into writemask */ + const GLuint swizzle = root_swizzle(lhs->Store); + GLuint writemask, newSwizzle = 0x0; + if (!swizzle_to_writemask(A, swizzle, &writemask, &newSwizzle)) { + /* Non-simple writemask, need to swizzle right hand side in + * order to put components into the right place. + */ + rhs = _slang_gen_swizzle(rhs, newSwizzle); + } + n = new_node2(IR_COPY, lhs, rhs); + } + else { + return NULL; + } + } + + if (n && pred) { + /* predicate the assignment code on __notRetFlag */ + slang_ir_node *top, *cond; + + cond = _slang_gen_operation(A, pred); + top = new_if(cond, n, NULL); + return top; + } + return n; +} + + +/** + * Generate IR tree for referencing a field in a struct (or basic vector type) + */ +static slang_ir_node * +_slang_gen_struct_field(slang_assemble_ctx * A, slang_operation *oper) +{ + slang_typeinfo ti; + + /* type of struct */ + slang_typeinfo_construct(&ti); + typeof_operation(A, &oper->children[0], &ti); + + if (_slang_type_is_vector(ti.spec.type)) { + /* the field should be a swizzle */ + const GLuint rows = _slang_type_dim(ti.spec.type); + slang_swizzle swz; + slang_ir_node *n; + GLuint swizzle; + if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) { + slang_info_log_error(A->log, "Bad swizzle"); + return NULL; + } + swizzle = MAKE_SWIZZLE4(swz.swizzle[0], + swz.swizzle[1], + swz.swizzle[2], + swz.swizzle[3]); + + n = _slang_gen_operation(A, &oper->children[0]); + /* create new parent node with swizzle */ + if (n) + n = _slang_gen_swizzle(n, swizzle); + return n; + } + else if ( ti.spec.type == SLANG_SPEC_FLOAT + || ti.spec.type == SLANG_SPEC_INT + || ti.spec.type == SLANG_SPEC_BOOL) { + const GLuint rows = 1; + slang_swizzle swz; + slang_ir_node *n; + GLuint swizzle; + if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) { + slang_info_log_error(A->log, "Bad swizzle"); + } + swizzle = MAKE_SWIZZLE4(swz.swizzle[0], + swz.swizzle[1], + swz.swizzle[2], + swz.swizzle[3]); + n = _slang_gen_operation(A, &oper->children[0]); + /* create new parent node with swizzle */ + n = _slang_gen_swizzle(n, swizzle); + return n; + } + else { + /* the field is a structure member (base.field) */ + /* oper->children[0] is the base */ + /* oper->a_id is the field name */ + slang_ir_node *base, *n; + slang_typeinfo field_ti; + GLint fieldSize, fieldOffset = -1; + + /* type of field */ + slang_typeinfo_construct(&field_ti); + typeof_operation(A, oper, &field_ti); + + fieldSize = _slang_sizeof_type_specifier(&field_ti.spec); + if (fieldSize > 0) + fieldOffset = _slang_field_offset(&ti.spec, oper->a_id); + + if (fieldSize == 0 || fieldOffset < 0) { + const char *structName; + if (ti.spec._struct) + structName = (char *) ti.spec._struct->a_name; + else + structName = "unknown"; + slang_info_log_error(A->log, + "\"%s\" is not a member of struct \"%s\"", + (char *) oper->a_id, structName); + return NULL; + } + assert(fieldSize >= 0); + + base = _slang_gen_operation(A, &oper->children[0]); + if (!base) { + /* error msg should have already been logged */ + return NULL; + } + + n = new_node1(IR_FIELD, base); + if (!n) + return NULL; + + n->Field = (char *) oper->a_id; + + /* Store the field's offset in storage->Index */ + n->Store = _slang_new_ir_storage(base->Store->File, + fieldOffset, + fieldSize); + + return n; + } +} + + +/** + * Gen code for array indexing. + */ +static slang_ir_node * +_slang_gen_array_element(slang_assemble_ctx * A, slang_operation *oper) +{ + slang_typeinfo array_ti; + + /* get array's type info */ + slang_typeinfo_construct(&array_ti); + typeof_operation(A, &oper->children[0], &array_ti); + + if (_slang_type_is_vector(array_ti.spec.type)) { + /* indexing a simple vector type: "vec4 v; v[0]=p;" */ + /* translate the index into a swizzle/writemask: "v.x=p" */ + const GLuint max = _slang_type_dim(array_ti.spec.type); + GLint index; + slang_ir_node *n; + + index = (GLint) oper->children[1].literal[0]; + if (oper->children[1].type != SLANG_OPER_LITERAL_INT || + index >= (GLint) max) { +#if 0 + slang_info_log_error(A->log, "Invalid array index for vector type"); + printf("type = %d\n", oper->children[1].type); + printf("index = %d, max = %d\n", index, max); + printf("array = %s\n", (char*)oper->children[0].a_id); + printf("index = %s\n", (char*)oper->children[1].a_id); + return NULL; +#else + index = 0; +#endif + } + + n = _slang_gen_operation(A, &oper->children[0]); + if (n) { + /* use swizzle to access the element */ + GLuint swizzle = MAKE_SWIZZLE4(SWIZZLE_X + index, + SWIZZLE_NIL, + SWIZZLE_NIL, + SWIZZLE_NIL); + n = _slang_gen_swizzle(n, swizzle); + } + return n; + } + else { + /* conventional array */ + slang_typeinfo elem_ti; + slang_ir_node *elem, *array, *index; + GLint elemSize, arrayLen; + + /* size of array element */ + slang_typeinfo_construct(&elem_ti); + typeof_operation(A, oper, &elem_ti); + elemSize = _slang_sizeof_type_specifier(&elem_ti.spec); + + if (_slang_type_is_matrix(array_ti.spec.type)) + arrayLen = _slang_type_dim(array_ti.spec.type); + else + arrayLen = array_ti.array_len; + + slang_typeinfo_destruct(&array_ti); + slang_typeinfo_destruct(&elem_ti); + + if (elemSize <= 0) { + /* unknown var or type */ + slang_info_log_error(A->log, "Undefined variable or type"); + return NULL; + } + + array = _slang_gen_operation(A, &oper->children[0]); + index = _slang_gen_operation(A, &oper->children[1]); + if (array && index) { + /* bounds check */ + GLint constIndex = -1; + if (index->Opcode == IR_FLOAT) { + constIndex = (int) index->Value[0]; + if (constIndex < 0 || constIndex >= arrayLen) { + slang_info_log_error(A->log, + "Array index out of bounds (index=%d size=%d)", + constIndex, arrayLen); + _slang_free_ir_tree(array); + _slang_free_ir_tree(index); + return NULL; + } + } + + if (!array->Store) { + slang_info_log_error(A->log, "Invalid array"); + return NULL; + } + + elem = new_node2(IR_ELEMENT, array, index); + + /* The storage info here will be updated during code emit */ + elem->Store = _slang_new_ir_storage(array->Store->File, + array->Store->Index, + elemSize); + elem->Store->Swizzle = _slang_var_swizzle(elemSize, 0); + return elem; + } + else { + _slang_free_ir_tree(array); + _slang_free_ir_tree(index); + return NULL; + } + } +} + + +static slang_ir_node * +_slang_gen_compare(slang_assemble_ctx *A, slang_operation *oper, + slang_ir_opcode opcode) +{ + slang_typeinfo t0, t1; + slang_ir_node *n; + + slang_typeinfo_construct(&t0); + typeof_operation(A, &oper->children[0], &t0); + + slang_typeinfo_construct(&t1); + typeof_operation(A, &oper->children[0], &t1); + + if (t0.spec.type == SLANG_SPEC_ARRAY || + t1.spec.type == SLANG_SPEC_ARRAY) { + slang_info_log_error(A->log, "Illegal array comparison"); + return NULL; + } + + if (oper->type != SLANG_OPER_EQUAL && + oper->type != SLANG_OPER_NOTEQUAL) { + /* <, <=, >, >= can only be used with scalars */ + if ((t0.spec.type != SLANG_SPEC_INT && + t0.spec.type != SLANG_SPEC_FLOAT) || + (t1.spec.type != SLANG_SPEC_INT && + t1.spec.type != SLANG_SPEC_FLOAT)) { + slang_info_log_error(A->log, "Incompatible type(s) for inequality operator"); + return NULL; + } + } + + n = new_node2(opcode, + _slang_gen_operation(A, &oper->children[0]), + _slang_gen_operation(A, &oper->children[1])); + + /* result is a bool (size 1) */ + n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1); + + return n; +} + + +#if 0 +static void +print_vars(slang_variable_scope *s) +{ + int i; + printf("vars: "); + for (i = 0; i < s->num_variables; i++) { + printf("%s %d, \n", + (char*) s->variables[i]->a_name, + s->variables[i]->declared); + } + + printf("\n"); +} +#endif + + +#if 0 +static void +_slang_undeclare_vars(slang_variable_scope *locals) +{ + if (locals->num_variables > 0) { + int i; + for (i = 0; i < locals->num_variables; i++) { + slang_variable *v = locals->variables[i]; + printf("undeclare %s at %p\n", (char*) v->a_name, v); + v->declared = GL_FALSE; + } + } +} +#endif + + +/** + * Generate IR tree for a slang_operation (AST node) + */ +static slang_ir_node * +_slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_BLOCK_NEW_SCOPE: + { + slang_ir_node *n; + + _slang_push_var_table(A->vartable); + + oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; /* temp change */ + n = _slang_gen_operation(A, oper); + oper->type = SLANG_OPER_BLOCK_NEW_SCOPE; /* restore */ + + _slang_pop_var_table(A->vartable); + + /*_slang_undeclare_vars(oper->locals);*/ + /*print_vars(oper->locals);*/ + + if (n) + n = new_node1(IR_SCOPE, n); + return n; + } + break; + + case SLANG_OPER_BLOCK_NO_NEW_SCOPE: + /* list of operations */ + if (oper->num_children > 0) + { + slang_ir_node *n, *tree = NULL; + GLuint i; + + for (i = 0; i < oper->num_children; i++) { + n = _slang_gen_operation(A, &oper->children[i]); + if (!n) { + _slang_free_ir_tree(tree); + return NULL; /* error must have occured */ + } + tree = new_seq(tree, n); + } + + return tree; + } + else { + return new_node0(IR_NOP); + } + + case SLANG_OPER_EXPRESSION: + return _slang_gen_operation(A, &oper->children[0]); + + case SLANG_OPER_FOR: + return _slang_gen_for(A, oper); + case SLANG_OPER_DO: + return _slang_gen_do(A, oper); + case SLANG_OPER_WHILE: + return _slang_gen_while(A, oper); + case SLANG_OPER_BREAK: + if (!current_loop_oper(A)) { + slang_info_log_error(A->log, "'break' not in loop"); + return NULL; + } + return new_break(current_loop_ir(A)); + case SLANG_OPER_CONTINUE: + if (!current_loop_oper(A)) { + slang_info_log_error(A->log, "'continue' not in loop"); + return NULL; + } + return _slang_gen_continue(A, oper); + case SLANG_OPER_DISCARD: + return new_node0(IR_KILL); + + case SLANG_OPER_EQUAL: + return _slang_gen_compare(A, oper, IR_EQUAL); + case SLANG_OPER_NOTEQUAL: + return _slang_gen_compare(A, oper, IR_NOTEQUAL); + case SLANG_OPER_GREATER: + return _slang_gen_compare(A, oper, IR_SGT); + case SLANG_OPER_LESS: + return _slang_gen_compare(A, oper, IR_SLT); + case SLANG_OPER_GREATEREQUAL: + return _slang_gen_compare(A, oper, IR_SGE); + case SLANG_OPER_LESSEQUAL: + return _slang_gen_compare(A, oper, IR_SLE); + case SLANG_OPER_ADD: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "+", oper, NULL); + return n; + } + case SLANG_OPER_SUBTRACT: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "-", oper, NULL); + return n; + } + case SLANG_OPER_MULTIPLY: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "*", oper, NULL); + return n; + } + case SLANG_OPER_DIVIDE: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "/", oper, NULL); + return n; + } + case SLANG_OPER_MINUS: + { + slang_ir_node *n; + assert(oper->num_children == 1); + n = _slang_gen_function_call_name(A, "-", oper, NULL); + return n; + } + case SLANG_OPER_PLUS: + /* +expr --> do nothing */ + return _slang_gen_operation(A, &oper->children[0]); + case SLANG_OPER_VARIABLE_DECL: + return _slang_gen_declaration(A, oper); + case SLANG_OPER_ASSIGN: + return _slang_gen_assignment(A, oper); + case SLANG_OPER_ADDASSIGN: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "+=", oper, NULL); + return n; + } + case SLANG_OPER_SUBASSIGN: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "-=", oper, NULL); + return n; + } + break; + case SLANG_OPER_MULASSIGN: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "*=", oper, NULL); + return n; + } + case SLANG_OPER_DIVASSIGN: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "/=", oper, NULL); + return n; + } + case SLANG_OPER_LOGICALAND: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_logical_and(A, oper); + return n; + } + case SLANG_OPER_LOGICALOR: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_logical_or(A, oper); + return n; + } + case SLANG_OPER_LOGICALXOR: + return _slang_gen_xor(A, oper); + case SLANG_OPER_NOT: + return _slang_gen_not(A, oper); + case SLANG_OPER_SELECT: /* b ? x : y */ + { + slang_ir_node *n; + assert(oper->num_children == 3); + n = _slang_gen_select(A, oper); + return n; + } + + case SLANG_OPER_ASM: + return _slang_gen_asm(A, oper, NULL); + case SLANG_OPER_CALL: + return _slang_gen_function_call_name(A, (const char *) oper->a_id, + oper, NULL); + case SLANG_OPER_METHOD: + return _slang_gen_method_call(A, oper); + case SLANG_OPER_RETURN: + return _slang_gen_return(A, oper); + case SLANG_OPER_RETURN_INLINED: + return _slang_gen_return(A, oper); + case SLANG_OPER_LABEL: + return new_label(oper->label); + case SLANG_OPER_IDENTIFIER: + return _slang_gen_variable(A, oper); + case SLANG_OPER_IF: + return _slang_gen_if(A, oper); + case SLANG_OPER_FIELD: + return _slang_gen_struct_field(A, oper); + case SLANG_OPER_SUBSCRIPT: + return _slang_gen_array_element(A, oper); + case SLANG_OPER_LITERAL_FLOAT: + /* fall-through */ + case SLANG_OPER_LITERAL_INT: + /* fall-through */ + case SLANG_OPER_LITERAL_BOOL: + return new_float_literal(oper->literal, oper->literal_size); + + case SLANG_OPER_POSTINCREMENT: /* var++ */ + { + slang_ir_node *n; + assert(oper->num_children == 1); + n = _slang_gen_function_call_name(A, "__postIncr", oper, NULL); + return n; + } + case SLANG_OPER_POSTDECREMENT: /* var-- */ + { + slang_ir_node *n; + assert(oper->num_children == 1); + n = _slang_gen_function_call_name(A, "__postDecr", oper, NULL); + return n; + } + case SLANG_OPER_PREINCREMENT: /* ++var */ + { + slang_ir_node *n; + assert(oper->num_children == 1); + n = _slang_gen_function_call_name(A, "++", oper, NULL); + return n; + } + case SLANG_OPER_PREDECREMENT: /* --var */ + { + slang_ir_node *n; + assert(oper->num_children == 1); + n = _slang_gen_function_call_name(A, "--", oper, NULL); + return n; + } + + case SLANG_OPER_NON_INLINED_CALL: + case SLANG_OPER_SEQUENCE: + { + slang_ir_node *tree = NULL; + GLuint i; + for (i = 0; i < oper->num_children; i++) { + slang_ir_node *n = _slang_gen_operation(A, &oper->children[i]); + tree = new_seq(tree, n); + if (n) + tree->Store = n->Store; + } + if (oper->type == SLANG_OPER_NON_INLINED_CALL) { + tree = new_function_call(tree, oper->label); + } + return tree; + } + + case SLANG_OPER_NONE: + case SLANG_OPER_VOID: + /* returning NULL here would generate an error */ + return new_node0(IR_NOP); + + default: + _mesa_problem(NULL, "bad node type %d in _slang_gen_operation", + oper->type); + return new_node0(IR_NOP); + } + + return NULL; +} + + +/** + * Check if the given type specifier is a rectangular texture sampler. + */ +static GLboolean +is_rect_sampler_spec(const slang_type_specifier *spec) +{ + while (spec->_array) { + spec = spec->_array; + } + return spec->type == SLANG_SPEC_SAMPLER_RECT || + spec->type == SLANG_SPEC_SAMPLER_RECT_SHADOW; +} + + + +/** + * Called by compiler when a global variable has been parsed/compiled. + * Here we examine the variable's type to determine what kind of register + * storage will be used. + * + * A uniform such as "gl_Position" will become the register specification + * (PROGRAM_OUTPUT, VERT_RESULT_HPOS). Or, uniform "gl_FogFragCoord" + * will be (PROGRAM_INPUT, FRAG_ATTRIB_FOGC). + * + * Samplers are interesting. For "uniform sampler2D tex;" we'll specify + * (PROGRAM_SAMPLER, index) where index is resolved at link-time to an + * actual texture unit (as specified by the user calling glUniform1i()). + */ +GLboolean +_slang_codegen_global_variable(slang_assemble_ctx *A, slang_variable *var, + slang_unit_type type) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_program *prog = A->program; + const char *varName = (char *) var->a_name; + GLboolean success = GL_TRUE; + slang_ir_storage *store = NULL; + int dbg = 0; + const GLenum datatype = _slang_gltype_from_specifier(&var->type.specifier); + const GLint size = _slang_sizeof_type_specifier(&var->type.specifier); + const GLint arrayLen = _slang_array_length(var); + const GLint totalSize = _slang_array_size(size, arrayLen); + GLint texIndex = sampler_to_texture_index(var->type.specifier.type); + + var->is_global = GL_TRUE; + + /* check for sampler2D arrays */ + if (texIndex == -1 && var->type.specifier._array) + texIndex = sampler_to_texture_index(var->type.specifier._array->type); + + if (texIndex != -1) { + /* This is a texture sampler variable... + * store->File = PROGRAM_SAMPLER + * store->Index = sampler number (0..7, typically) + * store->Size = texture type index (1D, 2D, 3D, cube, etc) + */ + if (var->initializer) { + slang_info_log_error(A->log, "illegal assignment to '%s'", varName); + return GL_FALSE; + } +#if FEATURE_es2_glsl /* XXX should use FEATURE_texture_rect */ + /* disallow rect samplers */ + if (ctx->API == API_OPENGLES2 && + is_rect_sampler_spec(&var->type.specifier)) { + slang_info_log_error(A->log, "invalid sampler type for '%s'", varName); + return GL_FALSE; + } +#else + (void) is_rect_sampler_spec; /* silence warning */ + (void) ctx; +#endif + { + GLint sampNum = _mesa_add_sampler(prog->Parameters, varName, datatype); + store = _slang_new_ir_storage_sampler(sampNum, texIndex, totalSize); + + /* If we have a sampler array, then we need to allocate the + * additional samplers to ensure we don't allocate them elsewhere. + * We can't directly use _mesa_add_sampler() as that checks the + * varName and gets a match, so we call _mesa_add_parameter() + * directly and use the last sampler number from the call above. + */ + if (arrayLen > 0) { + GLint a = arrayLen - 1; + GLint i; + for (i = 0; i < a; i++) { + GLfloat value = (GLfloat)(i + sampNum + 1); + (void) _mesa_add_parameter(prog->Parameters, PROGRAM_SAMPLER, + varName, 1, datatype, &value, NULL, 0x0); + } + } + } + if (dbg) printf("SAMPLER "); + } + else if (var->type.qualifier == SLANG_QUAL_UNIFORM) { + /* Uniform variable */ + const GLuint swizzle = _slang_var_swizzle(totalSize, 0); + + if (prog) { + /* user-defined uniform */ + if (datatype == GL_NONE) { + if ((var->type.specifier.type == SLANG_SPEC_ARRAY && + var->type.specifier._array->type == SLANG_SPEC_STRUCT) || + (var->type.specifier.type == SLANG_SPEC_STRUCT)) { + /* temporary work-around */ + GLenum datatype = GL_FLOAT; + GLint uniformLoc = _mesa_add_uniform(prog->Parameters, varName, + totalSize, datatype, NULL); + store = _slang_new_ir_storage_swz(PROGRAM_UNIFORM, uniformLoc, + totalSize, swizzle); + + if (arrayLen > 0) { + GLint a = arrayLen - 1; + GLint i; + for (i = 0; i < a; i++) { + GLfloat value = (GLfloat)(i + uniformLoc + 1); + (void) _mesa_add_parameter(prog->Parameters, PROGRAM_UNIFORM, + varName, 1, datatype, &value, NULL, 0x0); + } + } + + /* XXX what we need to do is unroll the struct into its + * basic types, creating a uniform variable for each. + * For example: + * struct foo { + * vec3 a; + * vec4 b; + * }; + * uniform foo f; + * + * Should produce uniforms: + * "f.a" (GL_FLOAT_VEC3) + * "f.b" (GL_FLOAT_VEC4) + */ + + if (var->initializer) { + slang_info_log_error(A->log, + "unsupported initializer for uniform '%s'", varName); + return GL_FALSE; + } + } + else { + slang_info_log_error(A->log, + "invalid datatype for uniform variable %s", + varName); + return GL_FALSE; + } + } + else { + /* non-struct uniform */ + if (!_slang_gen_var_decl(A, var, var->initializer)) + return GL_FALSE; + store = var->store; + } + } + else { + /* pre-defined uniform, like gl_ModelviewMatrix */ + /* We know it's a uniform, but don't allocate storage unless + * it's really used. + */ + store = _slang_new_ir_storage_swz(PROGRAM_STATE_VAR, -1, + totalSize, swizzle); + } + if (dbg) printf("UNIFORM (sz %d) ", totalSize); + } + else if (var->type.qualifier == SLANG_QUAL_VARYING) { + /* varyings must be float, vec or mat */ + if (!_slang_type_is_float_vec_mat(var->type.specifier.type) && + var->type.specifier.type != SLANG_SPEC_ARRAY) { + slang_info_log_error(A->log, + "varying '%s' must be float/vector/matrix", + varName); + return GL_FALSE; + } + + if (var->initializer) { + slang_info_log_error(A->log, "illegal initializer for varying '%s'", + varName); + return GL_FALSE; + } + + if (prog) { + /* user-defined varying */ + GLbitfield flags; + GLint varyingLoc; + GLuint swizzle; + + flags = 0x0; + if (var->type.centroid == SLANG_CENTROID) + flags |= PROG_PARAM_BIT_CENTROID; + if (var->type.variant == SLANG_INVARIANT) + flags |= PROG_PARAM_BIT_INVARIANT; + + varyingLoc = _mesa_add_varying(prog->Varying, varName, + totalSize, GL_NONE, flags); + swizzle = _slang_var_swizzle(size, 0); + store = _slang_new_ir_storage_swz(PROGRAM_VARYING, varyingLoc, + totalSize, swizzle); + } + else { + /* pre-defined varying, like gl_Color or gl_TexCoord */ + if (type == SLANG_UNIT_FRAGMENT_BUILTIN) { + /* fragment program input */ + GLuint swizzle; + GLint index = _slang_input_index(varName, GL_FRAGMENT_PROGRAM_ARB, + &swizzle); + assert(index >= 0); + assert(index < FRAG_ATTRIB_MAX); + store = _slang_new_ir_storage_swz(PROGRAM_INPUT, index, + size, swizzle); + } + else { + /* vertex program output */ + GLint index = _slang_output_index(varName, GL_VERTEX_PROGRAM_ARB); + GLuint swizzle = _slang_var_swizzle(size, 0); + assert(index >= 0); + assert(index < VERT_RESULT_MAX); + assert(type == SLANG_UNIT_VERTEX_BUILTIN); + store = _slang_new_ir_storage_swz(PROGRAM_OUTPUT, index, + size, swizzle); + } + if (dbg) printf("V/F "); + } + if (dbg) printf("VARYING "); + } + else if (var->type.qualifier == SLANG_QUAL_ATTRIBUTE) { + GLuint swizzle; + GLint index; + /* attributes must be float, vec or mat */ + if (!_slang_type_is_float_vec_mat(var->type.specifier.type)) { + slang_info_log_error(A->log, + "attribute '%s' must be float/vector/matrix", + varName); + return GL_FALSE; + } + + if (prog) { + /* user-defined vertex attribute */ + const GLint attr = -1; /* unknown */ + swizzle = _slang_var_swizzle(size, 0); + index = _mesa_add_attribute(prog->Attributes, varName, + size, datatype, attr); + assert(index >= 0); + index = VERT_ATTRIB_GENERIC0 + index; + } + else { + /* pre-defined vertex attrib */ + index = _slang_input_index(varName, GL_VERTEX_PROGRAM_ARB, &swizzle); + assert(index >= 0); + } + store = _slang_new_ir_storage_swz(PROGRAM_INPUT, index, size, swizzle); + if (dbg) printf("ATTRIB "); + } + else if (var->type.qualifier == SLANG_QUAL_FIXEDINPUT) { + GLuint swizzle = SWIZZLE_XYZW; /* silence compiler warning */ + GLint index = _slang_input_index(varName, GL_FRAGMENT_PROGRAM_ARB, + &swizzle); + store = _slang_new_ir_storage_swz(PROGRAM_INPUT, index, size, swizzle); + if (dbg) printf("INPUT "); + } + else if (var->type.qualifier == SLANG_QUAL_FIXEDOUTPUT) { + if (type == SLANG_UNIT_VERTEX_BUILTIN) { + GLint index = _slang_output_index(varName, GL_VERTEX_PROGRAM_ARB); + store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, size); + } + else { + GLint index = _slang_output_index(varName, GL_FRAGMENT_PROGRAM_ARB); + GLint specialSize = 4; /* treat all fragment outputs as float[4] */ + assert(type == SLANG_UNIT_FRAGMENT_BUILTIN); + store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, specialSize); + } + if (dbg) printf("OUTPUT "); + } + else if (var->type.qualifier == SLANG_QUAL_CONST && !prog) { + /* pre-defined global constant, like gl_MaxLights */ + store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, size); + if (dbg) printf("CONST "); + } + else { + /* ordinary variable (may be const) */ + slang_ir_node *n; + + /* IR node to declare the variable */ + n = _slang_gen_var_decl(A, var, var->initializer); + + /* emit GPU instructions */ + success = _slang_emit_code(n, A->vartable, A->program, A->pragmas, GL_FALSE, A->log); + + _slang_free_ir_tree(n); + } + + if (dbg) printf("GLOBAL VAR %s idx %d\n", (char*) var->a_name, + store ? store->Index : -2); + + if (store) + var->store = store; /* save var's storage info */ + + var->declared = GL_TRUE; + + return success; +} + + +/** + * Produce an IR tree from a function AST (fun->body). + * Then call the code emitter to convert the IR tree into gl_program + * instructions. + */ +GLboolean +_slang_codegen_function(slang_assemble_ctx * A, slang_function * fun) +{ + slang_ir_node *n; + GLboolean success = GL_TRUE; + + if (strcmp((char *) fun->header.a_name, "main") != 0) { + /* we only really generate code for main, all other functions get + * inlined or codegen'd upon an actual call. + */ +#if 0 + /* do some basic error checking though */ + if (fun->header.type.specifier.type != SLANG_SPEC_VOID) { + /* check that non-void functions actually return something */ + slang_operation *op + = _slang_find_node_type(fun->body, SLANG_OPER_RETURN); + if (!op) { + slang_info_log_error(A->log, + "function \"%s\" has no return statement", + (char *) fun->header.a_name); + printf( + "function \"%s\" has no return statement\n", + (char *) fun->header.a_name); + return GL_FALSE; + } + } +#endif + return GL_TRUE; /* not an error */ + } + +#if 0 + printf("\n*********** codegen_function %s\n", (char *) fun->header.a_name); + slang_print_function(fun, 1); +#endif + + /* should have been allocated earlier: */ + assert(A->program->Parameters ); + assert(A->program->Varying); + assert(A->vartable); + + A->LoopDepth = 0; + A->UseReturnFlag = GL_FALSE; + A->CurFunction = fun; + + /* fold constant expressions, etc. */ + _slang_simplify(fun->body, &A->space, A->atoms); + +#if 0 + printf("\n*********** simplified %s\n", (char *) fun->header.a_name); + slang_print_function(fun, 1); +#endif + + /* Create an end-of-function label */ + A->curFuncEndLabel = _slang_label_new("__endOfFunc__main"); + + /* push new vartable scope */ + _slang_push_var_table(A->vartable); + + /* Generate IR tree for the function body code */ + n = _slang_gen_operation(A, fun->body); + if (n) + n = new_node1(IR_SCOPE, n); + + /* pop vartable, restore previous */ + _slang_pop_var_table(A->vartable); + + if (!n) { + /* XXX record error */ + return GL_FALSE; + } + + /* append an end-of-function-label to IR tree */ + n = new_seq(n, new_label(A->curFuncEndLabel)); + + /*_slang_label_delete(A->curFuncEndLabel);*/ + A->curFuncEndLabel = NULL; + +#if 0 + printf("************* New AST for %s *****\n", (char*)fun->header.a_name); + slang_print_function(fun, 1); +#endif +#if 0 + printf("************* IR for %s *******\n", (char*)fun->header.a_name); + _slang_print_ir_tree(n, 0); +#endif +#if 0 + printf("************* End codegen function ************\n\n"); +#endif + + if (A->UnresolvedRefs) { + /* Can't codegen at this time. + * At link time we'll concatenate all the vertex shaders and/or all + * the fragment shaders and try recompiling. + */ + return GL_TRUE; + } + + /* Emit program instructions */ + success = _slang_emit_code(n, A->vartable, A->program, A->pragmas, GL_TRUE, A->log); + _slang_free_ir_tree(n); + + /* free codegen context */ + /* + free(A->codegen); + */ + + return success; +} + diff --git a/src/mesa/slang/slang_codegen.h b/src/mesa/slang/slang_codegen.h new file mode 100644 index 0000000000..461633fe34 --- /dev/null +++ b/src/mesa/slang/slang_codegen.h @@ -0,0 +1,73 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef SLANG_CODEGEN_H +#define SLANG_CODEGEN_H + + +#include "main/imports.h" +#include "slang_compile.h" + + +#define MAX_LOOP_DEPTH 30 + + +typedef struct slang_assemble_ctx_ +{ + slang_atom_pool *atoms; + slang_name_space space; + struct gl_program *program; + struct gl_sl_pragmas *pragmas; + slang_var_table *vartable; + slang_info_log *log; + GLboolean allow_uniform_initializers; + + /* current loop stack */ + const slang_operation *LoopOperStack[MAX_LOOP_DEPTH]; + struct slang_ir_node_ *LoopIRStack[MAX_LOOP_DEPTH]; + GLuint LoopDepth; + + /* current function */ + struct slang_function_ *CurFunction; + struct slang_label_ *curFuncEndLabel; + GLboolean UseReturnFlag; + + GLboolean UnresolvedRefs; + GLboolean EmitContReturn; +} slang_assemble_ctx; + + +extern GLuint +_slang_sizeof_type_specifier(const slang_type_specifier *spec); + +extern GLboolean +_slang_codegen_function(slang_assemble_ctx *A , struct slang_function_ *fun); + +extern GLboolean +_slang_codegen_global_variable(slang_assemble_ctx *A, slang_variable *var, + slang_unit_type type); + + +#endif /* SLANG_CODEGEN_H */ diff --git a/src/mesa/slang/slang_compile.c b/src/mesa/slang/slang_compile.c new file mode 100644 index 0000000000..b6b1f3c990 --- /dev/null +++ b/src/mesa/slang/slang_compile.c @@ -0,0 +1,3044 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * Copyright (C) 2008 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_compile.c + * slang front-end compiler + * \author Michal Krol + */ + +#include "main/imports.h" +#include "main/context.h" +#include "shader/program.h" +#include "shader/programopt.h" +#include "shader/prog_optimize.h" +#include "shader/prog_print.h" +#include "shader/prog_parameter.h" +#include "../../glsl/pp/sl_pp_public.h" +#include "../../glsl/cl/sl_cl_parse.h" +#include "slang_codegen.h" +#include "slang_compile.h" +#include "slang_storage.h" +#include "slang_log.h" +#include "slang_mem.h" +#include "slang_vartable.h" +#include "slang_simplify.h" + +/* + * This is a straightforward implementation of the slang front-end + * compiler. Lots of error-checking functionality is missing but + * every well-formed shader source should compile successfully and + * execute as expected. However, some semantically ill-formed shaders + * may be accepted resulting in undefined behaviour. + */ + + +/** re-defined below, should be the same though */ +#define TYPE_SPECIFIER_COUNT 36 + + +/** + * Check if the given identifier is legal. + */ +static GLboolean +legal_identifier(slang_atom name) +{ + /* "gl_" is a reserved prefix */ + if (strncmp((char *) name, "gl_", 3) == 0) { + return GL_FALSE; + } + return GL_TRUE; +} + + +/* + * slang_code_unit + */ + +GLvoid +_slang_code_unit_ctr(slang_code_unit * self, + struct slang_code_object_ * object) +{ + _slang_variable_scope_ctr(&self->vars); + _slang_function_scope_ctr(&self->funs); + _slang_struct_scope_ctr(&self->structs); + self->object = object; +} + +GLvoid +_slang_code_unit_dtr(slang_code_unit * self) +{ + slang_variable_scope_destruct(&self->vars); + slang_function_scope_destruct(&self->funs); + slang_struct_scope_destruct(&self->structs); +} + +/* + * slang_code_object + */ + +GLvoid +_slang_code_object_ctr(slang_code_object * self) +{ + GLuint i; + + for (i = 0; i < SLANG_BUILTIN_TOTAL; i++) + _slang_code_unit_ctr(&self->builtin[i], self); + _slang_code_unit_ctr(&self->unit, self); + slang_atom_pool_construct(&self->atompool); +} + +GLvoid +_slang_code_object_dtr(slang_code_object * self) +{ + GLuint i; + + for (i = 0; i < SLANG_BUILTIN_TOTAL; i++) + _slang_code_unit_dtr(&self->builtin[i]); + _slang_code_unit_dtr(&self->unit); + slang_atom_pool_destruct(&self->atompool); +} + + +/* slang_parse_ctx */ + +typedef struct slang_parse_ctx_ +{ + const unsigned char *I; + slang_info_log *L; + int parsing_builtin; + GLboolean global_scope; /**< Is object being declared a global? */ + slang_atom_pool *atoms; + slang_unit_type type; /**< Vertex vs. Fragment */ + GLuint version; /**< user-specified (or default) #version */ +} slang_parse_ctx; + +/* slang_output_ctx */ + +typedef struct slang_output_ctx_ +{ + slang_variable_scope *vars; + slang_function_scope *funs; + slang_struct_scope *structs; + struct gl_program *program; + struct gl_sl_pragmas *pragmas; + slang_var_table *vartable; + GLuint default_precision[TYPE_SPECIFIER_COUNT]; + GLboolean allow_precision; + GLboolean allow_invariant; + GLboolean allow_centroid; + GLboolean allow_array_types; /* float[] syntax */ +} slang_output_ctx; + +/* _slang_compile() */ + + +/* Debugging aid, print file/line where parsing error is detected */ +#define RETURN0 \ + do { \ + if (0) \ + printf("slang error at %s:%d\n", __FILE__, __LINE__); \ + return 0; \ + } while (0) + + +static void +parse_identifier_str(slang_parse_ctx * C, char **id) +{ + *id = (char *) C->I; + C->I += strlen(*id) + 1; +} + +static slang_atom +parse_identifier(slang_parse_ctx * C) +{ + const char *id; + + id = (const char *) C->I; + C->I += strlen(id) + 1; + return slang_atom_pool_atom(C->atoms, id); +} + +static int +is_hex_digit(char c) +{ + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); +} + +static int +parse_general_number(slang_parse_ctx *ctx, float *number) +{ + char *flt = NULL; + + if (*ctx->I == '0') { + int value = 0; + const unsigned char *pi; + + if (ctx->I[1] == 'x' || ctx->I[1] == 'X') { + ctx->I += 2; + if (!is_hex_digit(*ctx->I)) { + return 0; + } + do { + int digit; + + if (*ctx->I >= '0' && *ctx->I <= '9') { + digit = (int)(*ctx->I - '0'); + } else if (*ctx->I >= 'a' && *ctx->I <= 'f') { + digit = (int)(*ctx->I - 'a') + 10; + } else { + digit = (int)(*ctx->I - 'A') + 10; + } + value = value * 0x10 + digit; + ctx->I++; + } while (is_hex_digit(*ctx->I)); + if (*ctx->I != '\0') { + return 0; + } + ctx->I++; + *number = (float)value; + return 1; + } + + pi = ctx->I; + pi++; + while (*pi >= '0' && *pi <= '7') { + int digit; + + digit = (int)(*pi - '0'); + value = value * 010 + digit; + pi++; + } + if (*pi == '\0') { + pi++; + ctx->I = pi; + *number = (float)value; + return 1; + } + } + + parse_identifier_str(ctx, &flt); + flt = _mesa_strdup(flt); + if (!flt) { + return 0; + } + if (flt[strlen(flt) - 1] == 'f' || flt[strlen(flt) - 1] == 'F') { + flt[strlen(flt) - 1] = '\0'; + } + *number = _mesa_strtof(flt, (char **)NULL); + free(flt); + + return 1; +} + +static int +parse_number(slang_parse_ctx * C, int *number) +{ + const int radix = (int) (*C->I++); + + if (radix == 1) { + float f = 0.0f; + + parse_general_number(C, &f); + *number = (int)f; + } else { + *number = 0; + while (*C->I != '\0') { + int digit; + if (*C->I >= '0' && *C->I <= '9') + digit = (int) (*C->I - '0'); + else if (*C->I >= 'A' && *C->I <= 'Z') + digit = (int) (*C->I - 'A') + 10; + else + digit = (int) (*C->I - 'a') + 10; + *number = *number * radix + digit; + C->I++; + } + C->I++; + } + if (*number > 65535) + slang_info_log_warning(C->L, "%d: literal integer overflow.", *number); + return 1; +} + +static int +parse_float(slang_parse_ctx * C, float *number) +{ + if (*C->I == 1) { + C->I++; + parse_general_number(C, number); + } else { + char *integral = NULL; + char *fractional = NULL; + char *exponent = NULL; + char *whole = NULL; + + parse_identifier_str(C, &integral); + parse_identifier_str(C, &fractional); + parse_identifier_str(C, &exponent); + + whole = (char *) _slang_alloc((strlen(integral) + + strlen(fractional) + + strlen(exponent) + 3) * sizeof(char)); + if (whole == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + + slang_string_copy(whole, integral); + slang_string_concat(whole, "."); + slang_string_concat(whole, fractional); + slang_string_concat(whole, "E"); + slang_string_concat(whole, exponent); + + *number = _mesa_strtof(whole, (char **) NULL); + + _slang_free(whole); + } + + return 1; +} + +/* revision number - increment after each change affecting emitted output */ +#define REVISION 5 + +static int +check_revision(slang_parse_ctx * C) +{ + if (*C->I != REVISION) { + slang_info_log_error(C->L, "Internal compiler error."); + RETURN0; + } + C->I++; + return 1; +} + +static int parse_statement(slang_parse_ctx *, slang_output_ctx *, + slang_operation *); +static int parse_expression(slang_parse_ctx *, slang_output_ctx *, + slang_operation *); +static int parse_type_specifier(slang_parse_ctx *, slang_output_ctx *, + slang_type_specifier *); +static int +parse_type_array_size(slang_parse_ctx *C, + slang_output_ctx *O, + GLint *array_len); + +static GLboolean +parse_array_len(slang_parse_ctx * C, slang_output_ctx * O, GLuint * len) +{ + slang_operation array_size; + slang_name_space space; + GLboolean result; + + if (!slang_operation_construct(&array_size)) + return GL_FALSE; + if (!parse_expression(C, O, &array_size)) { + slang_operation_destruct(&array_size); + return GL_FALSE; + } + + space.funcs = O->funs; + space.structs = O->structs; + space.vars = O->vars; + + /* evaluate compile-time expression which is array size */ + _slang_simplify(&array_size, &space, C->atoms); + + if (array_size.type == SLANG_OPER_LITERAL_INT) { + result = GL_TRUE; + *len = (GLint) array_size.literal[0]; + } else if (array_size.type == SLANG_OPER_IDENTIFIER) { + slang_variable *var = _slang_variable_locate(array_size.locals, array_size.a_id, GL_TRUE); + if (!var) { + slang_info_log_error(C->L, "undefined variable '%s'", + (char *) array_size.a_id); + result = GL_FALSE; + } else if (var->type.qualifier == SLANG_QUAL_CONST && + var->type.specifier.type == SLANG_SPEC_INT) { + if (var->initializer && + var->initializer->type == SLANG_OPER_LITERAL_INT) { + *len = (GLint) var->initializer->literal[0]; + result = GL_TRUE; + } else { + slang_info_log_error(C->L, "unable to parse array size declaration"); + result = GL_FALSE; + } + } else { + slang_info_log_error(C->L, "unable to parse array size declaration"); + result = GL_FALSE; + } + } else { + result = GL_FALSE; + } + + slang_operation_destruct(&array_size); + return result; +} + +static GLboolean +calculate_var_size(slang_parse_ctx * C, slang_output_ctx * O, + slang_variable * var) +{ + slang_storage_aggregate agg; + + if (!slang_storage_aggregate_construct(&agg)) + return GL_FALSE; + if (!_slang_aggregate_variable(&agg, &var->type.specifier, var->array_len, + O->funs, O->structs, O->vars, C->atoms)) { + slang_storage_aggregate_destruct(&agg); + return GL_FALSE; + } + var->size = _slang_sizeof_aggregate(&agg); + slang_storage_aggregate_destruct(&agg); + return GL_TRUE; +} + +static void +promote_type_to_array(slang_parse_ctx *C, + slang_fully_specified_type *type, + GLint array_len) +{ + slang_type_specifier *baseType = + slang_type_specifier_new(type->specifier.type, NULL, NULL); + + type->specifier.type = SLANG_SPEC_ARRAY; + type->specifier._array = baseType; + type->array_len = array_len; +} + + +static GLboolean +convert_to_array(slang_parse_ctx * C, slang_variable * var, + const slang_type_specifier * sp) +{ + /* sized array - mark it as array, copy the specifier to the array element + * and parse the expression */ + var->type.specifier.type = SLANG_SPEC_ARRAY; + var->type.specifier._array = (slang_type_specifier *) + _slang_alloc(sizeof(slang_type_specifier)); + if (var->type.specifier._array == NULL) { + slang_info_log_memory(C->L); + return GL_FALSE; + } + slang_type_specifier_ctr(var->type.specifier._array); + return slang_type_specifier_copy(var->type.specifier._array, sp); +} + +/* structure field */ +#define FIELD_NONE 0 +#define FIELD_NEXT 1 +#define FIELD_ARRAY 2 + +static GLboolean +parse_struct_field_var(slang_parse_ctx * C, slang_output_ctx * O, + slang_variable * var, slang_atom a_name, + const slang_type_specifier * sp, + GLuint array_len) +{ + var->a_name = a_name; + if (var->a_name == SLANG_ATOM_NULL) + return GL_FALSE; + + switch (*C->I++) { + case FIELD_NONE: + if (array_len != -1) { + if (!convert_to_array(C, var, sp)) + return GL_FALSE; + var->array_len = array_len; + } + else { + if (!slang_type_specifier_copy(&var->type.specifier, sp)) + return GL_FALSE; + } + break; + case FIELD_ARRAY: + if (array_len != -1) + return GL_FALSE; + if (!convert_to_array(C, var, sp)) + return GL_FALSE; + if (!parse_array_len(C, O, &var->array_len)) + return GL_FALSE; + break; + default: + return GL_FALSE; + } + + return calculate_var_size(C, O, var); +} + +static int +parse_struct_field(slang_parse_ctx * C, slang_output_ctx * O, + slang_struct * st, slang_type_specifier * sp) +{ + slang_output_ctx o = *O; + GLint array_len; + + o.structs = st->structs; + if (!parse_type_specifier(C, &o, sp)) + RETURN0; + if (!parse_type_array_size(C, &o, &array_len)) + RETURN0; + + do { + slang_atom a_name; + slang_variable *var = slang_variable_scope_grow(st->fields); + if (!var) { + slang_info_log_memory(C->L); + RETURN0; + } + a_name = parse_identifier(C); + if (_slang_variable_locate(st->fields, a_name, GL_FALSE)) { + slang_info_log_error(C->L, "duplicate field '%s'", (char *) a_name); + RETURN0; + } + + if (!parse_struct_field_var(C, &o, var, a_name, sp, array_len)) + RETURN0; + } + while (*C->I++ != FIELD_NONE); + + return 1; +} + +static int +parse_struct(slang_parse_ctx * C, slang_output_ctx * O, slang_struct ** st) +{ + slang_atom a_name; + const char *name; + + /* parse struct name (if any) and make sure it is unique in current scope */ + a_name = parse_identifier(C); + if (a_name == SLANG_ATOM_NULL) + RETURN0; + + name = slang_atom_pool_id(C->atoms, a_name); + if (name[0] != '\0' + && slang_struct_scope_find(O->structs, a_name, 0) != NULL) { + slang_info_log_error(C->L, "%s: duplicate type name.", name); + RETURN0; + } + + /* set-up a new struct */ + *st = (slang_struct *) _slang_alloc(sizeof(slang_struct)); + if (*st == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + if (!slang_struct_construct(*st)) { + _slang_free(*st); + *st = NULL; + slang_info_log_memory(C->L); + RETURN0; + } + (**st).a_name = a_name; + (**st).structs->outer_scope = O->structs; + + /* parse individual struct fields */ + do { + slang_type_specifier sp; + + slang_type_specifier_ctr(&sp); + if (!parse_struct_field(C, O, *st, &sp)) { + slang_type_specifier_dtr(&sp); + RETURN0; + } + slang_type_specifier_dtr(&sp); + } + while (*C->I++ != FIELD_NONE); + + /* if named struct, copy it to current scope */ + if (name[0] != '\0') { + slang_struct *s; + + O->structs->structs = + (slang_struct *) _slang_realloc(O->structs->structs, + O->structs->num_structs + * sizeof(slang_struct), + (O->structs->num_structs + 1) + * sizeof(slang_struct)); + if (O->structs->structs == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + s = &O->structs->structs[O->structs->num_structs]; + if (!slang_struct_construct(s)) + RETURN0; + O->structs->num_structs++; + if (!slang_struct_copy(s, *st)) + RETURN0; + } + + return 1; +} + + +/* invariant qualifer */ +#define TYPE_VARIANT 90 +#define TYPE_INVARIANT 91 + +static int +parse_type_variant(slang_parse_ctx * C, slang_type_variant *variant) +{ + GLuint invariant = *C->I++; + switch (invariant) { + case TYPE_VARIANT: + *variant = SLANG_VARIANT; + return 1; + case TYPE_INVARIANT: + *variant = SLANG_INVARIANT; + return 1; + default: + RETURN0; + } +} + + +/* centroid qualifer */ +#define TYPE_CENTER 95 +#define TYPE_CENTROID 96 + +static int +parse_type_centroid(slang_parse_ctx * C, slang_type_centroid *centroid) +{ + GLuint c = *C->I++; + switch (c) { + case TYPE_CENTER: + *centroid = SLANG_CENTER; + return 1; + case TYPE_CENTROID: + *centroid = SLANG_CENTROID; + return 1; + default: + RETURN0; + } +} + + +/* Layout qualifiers */ +#define LAYOUT_QUALIFIER_NONE 0 +#define LAYOUT_QUALIFIER_UPPER_LEFT 1 +#define LAYOUT_QUALIFIER_PIXEL_CENTER_INTEGER 2 + +static int +parse_layout_qualifiers(slang_parse_ctx * C, slang_layout_qualifier *layout) +{ + *layout = 0x0; + + /* the layout qualifiers come as a list of LAYOUT_QUALIFER_x tokens, + * terminated by LAYOUT_QUALIFIER_NONE. + */ + while (1) { + GLuint c = *C->I++; + switch (c) { + case LAYOUT_QUALIFIER_NONE: + /* end of list of qualifiers */ + return 1; + case LAYOUT_QUALIFIER_UPPER_LEFT: + *layout |= SLANG_LAYOUT_UPPER_LEFT_BIT; + break; + case LAYOUT_QUALIFIER_PIXEL_CENTER_INTEGER: + *layout |= SLANG_LAYOUT_PIXEL_CENTER_INTEGER_BIT; + break; + default: + assert(0 && "Bad layout qualifier"); + } + } +} + + +/* type qualifier */ +#define TYPE_QUALIFIER_NONE 0 +#define TYPE_QUALIFIER_CONST 1 +#define TYPE_QUALIFIER_ATTRIBUTE 2 +#define TYPE_QUALIFIER_VARYING 3 +#define TYPE_QUALIFIER_UNIFORM 4 +#define TYPE_QUALIFIER_FIXEDOUTPUT 5 +#define TYPE_QUALIFIER_FIXEDINPUT 6 + +static int +parse_type_qualifier(slang_parse_ctx * C, slang_type_qualifier * qual) +{ + GLuint qualifier = *C->I++; + switch (qualifier) { + case TYPE_QUALIFIER_NONE: + *qual = SLANG_QUAL_NONE; + break; + case TYPE_QUALIFIER_CONST: + *qual = SLANG_QUAL_CONST; + break; + case TYPE_QUALIFIER_ATTRIBUTE: + *qual = SLANG_QUAL_ATTRIBUTE; + break; + case TYPE_QUALIFIER_VARYING: + *qual = SLANG_QUAL_VARYING; + break; + case TYPE_QUALIFIER_UNIFORM: + *qual = SLANG_QUAL_UNIFORM; + break; + case TYPE_QUALIFIER_FIXEDOUTPUT: + *qual = SLANG_QUAL_FIXEDOUTPUT; + break; + case TYPE_QUALIFIER_FIXEDINPUT: + *qual = SLANG_QUAL_FIXEDINPUT; + break; + default: + RETURN0; + } + return 1; +} + +/* type specifier */ +#define TYPE_SPECIFIER_VOID 0 +#define TYPE_SPECIFIER_BOOL 1 +#define TYPE_SPECIFIER_BVEC2 2 +#define TYPE_SPECIFIER_BVEC3 3 +#define TYPE_SPECIFIER_BVEC4 4 +#define TYPE_SPECIFIER_INT 5 +#define TYPE_SPECIFIER_IVEC2 6 +#define TYPE_SPECIFIER_IVEC3 7 +#define TYPE_SPECIFIER_IVEC4 8 +#define TYPE_SPECIFIER_FLOAT 9 +#define TYPE_SPECIFIER_VEC2 10 +#define TYPE_SPECIFIER_VEC3 11 +#define TYPE_SPECIFIER_VEC4 12 +#define TYPE_SPECIFIER_MAT2 13 +#define TYPE_SPECIFIER_MAT3 14 +#define TYPE_SPECIFIER_MAT4 15 +#define TYPE_SPECIFIER_SAMPLER1D 16 +#define TYPE_SPECIFIER_SAMPLER2D 17 +#define TYPE_SPECIFIER_SAMPLER3D 18 +#define TYPE_SPECIFIER_SAMPLERCUBE 19 +#define TYPE_SPECIFIER_SAMPLER1DSHADOW 20 +#define TYPE_SPECIFIER_SAMPLER2DSHADOW 21 +#define TYPE_SPECIFIER_SAMPLER2DRECT 22 +#define TYPE_SPECIFIER_SAMPLER2DRECTSHADOW 23 +#define TYPE_SPECIFIER_STRUCT 24 +#define TYPE_SPECIFIER_TYPENAME 25 +#define TYPE_SPECIFIER_MAT23 26 +#define TYPE_SPECIFIER_MAT32 27 +#define TYPE_SPECIFIER_MAT24 28 +#define TYPE_SPECIFIER_MAT42 29 +#define TYPE_SPECIFIER_MAT34 30 +#define TYPE_SPECIFIER_MAT43 31 +#define TYPE_SPECIFIER_SAMPLER_1D_ARRAY 32 +#define TYPE_SPECIFIER_SAMPLER_2D_ARRAY 33 +#define TYPE_SPECIFIER_SAMPLER_1D_ARRAY_SHADOW 34 +#define TYPE_SPECIFIER_SAMPLER_2D_ARRAY_SHADOW 35 +#define TYPE_SPECIFIER_COUNT 36 + +static int +parse_type_specifier(slang_parse_ctx * C, slang_output_ctx * O, + slang_type_specifier * spec) +{ + int type = *C->I++; + switch (type) { + case TYPE_SPECIFIER_VOID: + spec->type = SLANG_SPEC_VOID; + break; + case TYPE_SPECIFIER_BOOL: + spec->type = SLANG_SPEC_BOOL; + break; + case TYPE_SPECIFIER_BVEC2: + spec->type = SLANG_SPEC_BVEC2; + break; + case TYPE_SPECIFIER_BVEC3: + spec->type = SLANG_SPEC_BVEC3; + break; + case TYPE_SPECIFIER_BVEC4: + spec->type = SLANG_SPEC_BVEC4; + break; + case TYPE_SPECIFIER_INT: + spec->type = SLANG_SPEC_INT; + break; + case TYPE_SPECIFIER_IVEC2: + spec->type = SLANG_SPEC_IVEC2; + break; + case TYPE_SPECIFIER_IVEC3: + spec->type = SLANG_SPEC_IVEC3; + break; + case TYPE_SPECIFIER_IVEC4: + spec->type = SLANG_SPEC_IVEC4; + break; + case TYPE_SPECIFIER_FLOAT: + spec->type = SLANG_SPEC_FLOAT; + break; + case TYPE_SPECIFIER_VEC2: + spec->type = SLANG_SPEC_VEC2; + break; + case TYPE_SPECIFIER_VEC3: + spec->type = SLANG_SPEC_VEC3; + break; + case TYPE_SPECIFIER_VEC4: + spec->type = SLANG_SPEC_VEC4; + break; + case TYPE_SPECIFIER_MAT2: + spec->type = SLANG_SPEC_MAT2; + break; + case TYPE_SPECIFIER_MAT3: + spec->type = SLANG_SPEC_MAT3; + break; + case TYPE_SPECIFIER_MAT4: + spec->type = SLANG_SPEC_MAT4; + break; + case TYPE_SPECIFIER_MAT23: + spec->type = SLANG_SPEC_MAT23; + break; + case TYPE_SPECIFIER_MAT32: + spec->type = SLANG_SPEC_MAT32; + break; + case TYPE_SPECIFIER_MAT24: + spec->type = SLANG_SPEC_MAT24; + break; + case TYPE_SPECIFIER_MAT42: + spec->type = SLANG_SPEC_MAT42; + break; + case TYPE_SPECIFIER_MAT34: + spec->type = SLANG_SPEC_MAT34; + break; + case TYPE_SPECIFIER_MAT43: + spec->type = SLANG_SPEC_MAT43; + break; + case TYPE_SPECIFIER_SAMPLER1D: + spec->type = SLANG_SPEC_SAMPLER_1D; + break; + case TYPE_SPECIFIER_SAMPLER2D: + spec->type = SLANG_SPEC_SAMPLER_2D; + break; + case TYPE_SPECIFIER_SAMPLER3D: + spec->type = SLANG_SPEC_SAMPLER_3D; + break; + case TYPE_SPECIFIER_SAMPLERCUBE: + spec->type = SLANG_SPEC_SAMPLER_CUBE; + break; + case TYPE_SPECIFIER_SAMPLER2DRECT: + spec->type = SLANG_SPEC_SAMPLER_RECT; + break; + case TYPE_SPECIFIER_SAMPLER1DSHADOW: + spec->type = SLANG_SPEC_SAMPLER_1D_SHADOW; + break; + case TYPE_SPECIFIER_SAMPLER2DSHADOW: + spec->type = SLANG_SPEC_SAMPLER_2D_SHADOW; + break; + case TYPE_SPECIFIER_SAMPLER2DRECTSHADOW: + spec->type = SLANG_SPEC_SAMPLER_RECT_SHADOW; + break; + case TYPE_SPECIFIER_SAMPLER_1D_ARRAY: + spec->type = SLANG_SPEC_SAMPLER_1D_ARRAY; + break; + case TYPE_SPECIFIER_SAMPLER_2D_ARRAY: + spec->type = SLANG_SPEC_SAMPLER_2D_ARRAY; + break; + case TYPE_SPECIFIER_SAMPLER_1D_ARRAY_SHADOW: + spec->type = SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW; + break; + case TYPE_SPECIFIER_SAMPLER_2D_ARRAY_SHADOW: + spec->type = SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW; + break; + case TYPE_SPECIFIER_STRUCT: + spec->type = SLANG_SPEC_STRUCT; + if (!parse_struct(C, O, &spec->_struct)) + RETURN0; + break; + case TYPE_SPECIFIER_TYPENAME: + spec->type = SLANG_SPEC_STRUCT; + { + slang_atom a_name; + slang_struct *stru; + + a_name = parse_identifier(C); + if (a_name == NULL) + RETURN0; + + stru = slang_struct_scope_find(O->structs, a_name, 1); + if (stru == NULL) { + slang_info_log_error(C->L, "undeclared type name '%s'", + slang_atom_pool_id(C->atoms, a_name)); + RETURN0; + } + + spec->_struct = (slang_struct *) _slang_alloc(sizeof(slang_struct)); + if (spec->_struct == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + if (!slang_struct_construct(spec->_struct)) { + _slang_free(spec->_struct); + spec->_struct = NULL; + RETURN0; + } + if (!slang_struct_copy(spec->_struct, stru)) + RETURN0; + } + break; + default: + RETURN0; + } + return 1; +} + +#define TYPE_SPECIFIER_NONARRAY 0 +#define TYPE_SPECIFIER_ARRAY 1 + +static int +parse_type_array_size(slang_parse_ctx *C, + slang_output_ctx *O, + GLint *array_len) +{ + GLuint size; + + switch (*C->I++) { + case TYPE_SPECIFIER_NONARRAY: + *array_len = -1; /* -1 = not an array */ + break; + case TYPE_SPECIFIER_ARRAY: + if (!parse_array_len(C, O, &size)) + RETURN0; + *array_len = (GLint) size; + break; + default: + assert(0); + RETURN0; + } + return 1; +} + +#define PRECISION_DEFAULT 0 +#define PRECISION_LOW 1 +#define PRECISION_MEDIUM 2 +#define PRECISION_HIGH 3 + +static int +parse_type_precision(slang_parse_ctx *C, + slang_type_precision *precision) +{ + GLint prec = *C->I++; + switch (prec) { + case PRECISION_DEFAULT: + *precision = SLANG_PREC_DEFAULT; + return 1; + case PRECISION_LOW: + *precision = SLANG_PREC_LOW; + return 1; + case PRECISION_MEDIUM: + *precision = SLANG_PREC_MEDIUM; + return 1; + case PRECISION_HIGH: + *precision = SLANG_PREC_HIGH; + return 1; + default: + RETURN0; + } +} + +static int +parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O, + slang_fully_specified_type * type) +{ + if (!parse_layout_qualifiers(C, &type->layout)) + RETURN0; + + if (!parse_type_variant(C, &type->variant)) + RETURN0; + + if (!parse_type_centroid(C, &type->centroid)) + RETURN0; + + if (!parse_type_qualifier(C, &type->qualifier)) + RETURN0; + + if (!parse_type_precision(C, &type->precision)) + RETURN0; + + if (!parse_type_specifier(C, O, &type->specifier)) + RETURN0; + + if (!parse_type_array_size(C, O, &type->array_len)) + RETURN0; + + if (!O->allow_invariant && type->variant == SLANG_INVARIANT) { + slang_info_log_error(C->L, + "'invariant' keyword not allowed (perhaps set #version 120)"); + RETURN0; + } + + if (!O->allow_centroid && type->centroid == SLANG_CENTROID) { + slang_info_log_error(C->L, + "'centroid' keyword not allowed (perhaps set #version 120)"); + RETURN0; + } + else if (type->centroid == SLANG_CENTROID && + type->qualifier != SLANG_QUAL_VARYING) { + slang_info_log_error(C->L, + "'centroid' keyword only allowed for varying vars"); + RETURN0; + } + + + /* need this? + if (type->qualifier != SLANG_QUAL_VARYING && + type->variant == SLANG_INVARIANT) { + slang_info_log_error(C->L, + "invariant qualifer only allowed for varying vars"); + RETURN0; + } + */ + + if (O->allow_precision) { + if (type->precision == SLANG_PREC_DEFAULT) { + assert(type->specifier.type < TYPE_SPECIFIER_COUNT); + /* use the default precision for this datatype */ + type->precision = O->default_precision[type->specifier.type]; + } + } + else { + /* only default is allowed */ + if (type->precision != SLANG_PREC_DEFAULT) { + slang_info_log_error(C->L, "precision qualifiers not allowed"); + RETURN0; + } + } + + if (!O->allow_array_types && type->array_len >= 0) { + slang_info_log_error(C->L, "first-class array types not allowed"); + RETURN0; + } + + if (type->array_len >= 0) { + /* convert type to array type (ex: convert "int" to "array of int" */ + promote_type_to_array(C, type, type->array_len); + } + + return 1; +} + +/* operation */ +#define OP_END 0 +#define OP_BLOCK_BEGIN_NO_NEW_SCOPE 1 +#define OP_BLOCK_BEGIN_NEW_SCOPE 2 +#define OP_DECLARE 3 +#define OP_ASM 4 +#define OP_BREAK 5 +#define OP_CONTINUE 6 +#define OP_DISCARD 7 +#define OP_RETURN 8 +#define OP_EXPRESSION 9 +#define OP_IF 10 +#define OP_WHILE 11 +#define OP_DO 12 +#define OP_FOR 13 +#define OP_PUSH_VOID 14 +#define OP_PUSH_BOOL 15 +#define OP_PUSH_INT 16 +#define OP_PUSH_FLOAT 17 +#define OP_PUSH_IDENTIFIER 18 +#define OP_SEQUENCE 19 +#define OP_ASSIGN 20 +#define OP_ADDASSIGN 21 +#define OP_SUBASSIGN 22 +#define OP_MULASSIGN 23 +#define OP_DIVASSIGN 24 +/*#define OP_MODASSIGN 25*/ +/*#define OP_LSHASSIGN 26*/ +/*#define OP_RSHASSIGN 27*/ +/*#define OP_ORASSIGN 28*/ +/*#define OP_XORASSIGN 29*/ +/*#define OP_ANDASSIGN 30*/ +#define OP_SELECT 31 +#define OP_LOGICALOR 32 +#define OP_LOGICALXOR 33 +#define OP_LOGICALAND 34 +/*#define OP_BITOR 35*/ +/*#define OP_BITXOR 36*/ +/*#define OP_BITAND 37*/ +#define OP_EQUAL 38 +#define OP_NOTEQUAL 39 +#define OP_LESS 40 +#define OP_GREATER 41 +#define OP_LESSEQUAL 42 +#define OP_GREATEREQUAL 43 +/*#define OP_LSHIFT 44*/ +/*#define OP_RSHIFT 45*/ +#define OP_ADD 46 +#define OP_SUBTRACT 47 +#define OP_MULTIPLY 48 +#define OP_DIVIDE 49 +/*#define OP_MODULUS 50*/ +#define OP_PREINCREMENT 51 +#define OP_PREDECREMENT 52 +#define OP_PLUS 53 +#define OP_MINUS 54 +/*#define OP_COMPLEMENT 55*/ +#define OP_NOT 56 +#define OP_SUBSCRIPT 57 +#define OP_CALL 58 +#define OP_FIELD 59 +#define OP_POSTINCREMENT 60 +#define OP_POSTDECREMENT 61 +#define OP_PRECISION 62 +#define OP_METHOD 63 + + +/** + * When parsing a compound production, this function is used to parse the + * children. + * For example, a while-loop compound will have two children, the + * while condition expression and the loop body. So, this function will + * be called twice to parse those two sub-expressions. + * \param C the parsing context + * \param O the output context + * \param oper the operation we're parsing + * \param statement indicates whether parsing a statement, or expression + * \return 1 if success, 0 if error + */ +static int +parse_child_operation(slang_parse_ctx * C, slang_output_ctx * O, + slang_operation * oper, GLboolean statement) +{ + slang_operation *ch; + + /* grow child array */ + ch = slang_operation_grow(&oper->num_children, &oper->children); + if (statement) + return parse_statement(C, O, ch); + return parse_expression(C, O, ch); +} + +static int parse_declaration(slang_parse_ctx * C, slang_output_ctx * O); + +static int +parse_statement(slang_parse_ctx * C, slang_output_ctx * O, + slang_operation * oper) +{ + int op; + + oper->locals->outer_scope = O->vars; + + op = *C->I++; + switch (op) { + case OP_BLOCK_BEGIN_NO_NEW_SCOPE: + /* parse child statements, do not create new variable scope */ + oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + while (*C->I != OP_END) + if (!parse_child_operation(C, O, oper, GL_TRUE)) + RETURN0; + C->I++; + break; + case OP_BLOCK_BEGIN_NEW_SCOPE: + /* parse child statements, create new variable scope */ + { + slang_output_ctx o = *O; + + oper->type = SLANG_OPER_BLOCK_NEW_SCOPE; + o.vars = oper->locals; + while (*C->I != OP_END) + if (!parse_child_operation(C, &o, oper, GL_TRUE)) + RETURN0; + C->I++; + } + break; + case OP_DECLARE: + /* local variable declaration, individual declarators are stored as + * children identifiers + */ + oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + { + const unsigned int first_var = O->vars->num_variables; + + /* parse the declaration, note that there can be zero or more + * than one declarators + */ + if (!parse_declaration(C, O)) + RETURN0; + if (first_var < O->vars->num_variables) { + const unsigned int num_vars = O->vars->num_variables - first_var; + unsigned int i; + assert(oper->num_children == 0); + oper->num_children = num_vars; + oper->children = slang_operation_new(num_vars); + if (oper->children == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + for (i = first_var; i < O->vars->num_variables; i++) { + slang_operation *o = &oper->children[i - first_var]; + slang_variable *var = O->vars->variables[i]; + o->type = SLANG_OPER_VARIABLE_DECL; + o->locals->outer_scope = O->vars; + o->a_id = var->a_name; + + /* new/someday... + calculate_var_size(C, O, var); + */ + + if (!legal_identifier(o->a_id)) { + slang_info_log_error(C->L, "illegal variable name '%s'", + (char *) o->a_id); + RETURN0; + } + } + } + } + break; + case OP_ASM: + /* the __asm statement, parse the mnemonic and all its arguments + * as expressions + */ + oper->type = SLANG_OPER_ASM; + oper->a_id = parse_identifier(C); + if (oper->a_id == SLANG_ATOM_NULL) + RETURN0; + while (*C->I != OP_END) { + if (!parse_child_operation(C, O, oper, GL_FALSE)) + RETURN0; + } + C->I++; + break; + case OP_BREAK: + oper->type = SLANG_OPER_BREAK; + break; + case OP_CONTINUE: + oper->type = SLANG_OPER_CONTINUE; + break; + case OP_DISCARD: + oper->type = SLANG_OPER_DISCARD; + break; + case OP_RETURN: + oper->type = SLANG_OPER_RETURN; + if (!parse_child_operation(C, O, oper, GL_FALSE)) + RETURN0; + break; + case OP_EXPRESSION: + oper->type = SLANG_OPER_EXPRESSION; + if (!parse_child_operation(C, O, oper, GL_FALSE)) + RETURN0; + break; + case OP_IF: + oper->type = SLANG_OPER_IF; + if (!parse_child_operation(C, O, oper, GL_FALSE)) + RETURN0; + if (!parse_child_operation(C, O, oper, GL_TRUE)) + RETURN0; + if (!parse_child_operation(C, O, oper, GL_TRUE)) + RETURN0; + break; + case OP_WHILE: + { + slang_output_ctx o = *O; + + oper->type = SLANG_OPER_WHILE; + o.vars = oper->locals; + if (!parse_child_operation(C, &o, oper, GL_TRUE)) + RETURN0; + if (!parse_child_operation(C, &o, oper, GL_TRUE)) + RETURN0; + } + break; + case OP_DO: + oper->type = SLANG_OPER_DO; + if (!parse_child_operation(C, O, oper, GL_TRUE)) + RETURN0; + if (!parse_child_operation(C, O, oper, GL_FALSE)) + RETURN0; + break; + case OP_FOR: + { + slang_output_ctx o = *O; + + oper->type = SLANG_OPER_FOR; + o.vars = oper->locals; + if (!parse_child_operation(C, &o, oper, GL_TRUE)) + RETURN0; + if (!parse_child_operation(C, &o, oper, GL_TRUE)) + RETURN0; + if (!parse_child_operation(C, &o, oper, GL_FALSE)) + RETURN0; + if (!parse_child_operation(C, &o, oper, GL_TRUE)) + RETURN0; + } + break; + case OP_PRECISION: + { + /* set default precision for a type in this scope */ + /* ignored at this time */ + int prec_qual = *C->I++; + int datatype = *C->I++; + (void) prec_qual; + (void) datatype; + } + break; + default: + /*printf("Unexpected operation %d\n", op);*/ + RETURN0; + } + return 1; +} + +static int +handle_nary_expression(slang_parse_ctx * C, slang_operation * op, + slang_operation ** ops, unsigned int *total_ops, + unsigned int n) +{ + unsigned int i; + + op->children = slang_operation_new(n); + if (op->children == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + op->num_children = n; + + for (i = 0; i < n; i++) { + slang_operation_destruct(&op->children[i]); + op->children[i] = (*ops)[*total_ops - (n + 1 - i)]; + } + + (*ops)[*total_ops - (n + 1)] = (*ops)[*total_ops - 1]; + *total_ops -= n; + + *ops = (slang_operation *) + _slang_realloc(*ops, + (*total_ops + n) * sizeof(slang_operation), + *total_ops * sizeof(slang_operation)); + if (*ops == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + return 1; +} + +static int +is_constructor_name(const char *name, slang_atom a_name, + slang_struct_scope * structs) +{ + if (slang_type_specifier_type_from_string(name) != SLANG_SPEC_VOID) + return 1; + return slang_struct_scope_find(structs, a_name, 1) != NULL; +} + +#define FUNCTION_CALL_NONARRAY 0 +#define FUNCTION_CALL_ARRAY 1 + +static int +parse_expression(slang_parse_ctx * C, slang_output_ctx * O, + slang_operation * oper) +{ + slang_operation *ops = NULL; + unsigned int num_ops = 0; + int number; + + while (*C->I != OP_END) { + slang_operation *op; + const unsigned int op_code = *C->I++; + + /* allocate default operation, becomes a no-op if not used */ + ops = (slang_operation *) + _slang_realloc(ops, + num_ops * sizeof(slang_operation), + (num_ops + 1) * sizeof(slang_operation)); + if (ops == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + op = &ops[num_ops]; + if (!slang_operation_construct(op)) { + slang_info_log_memory(C->L); + RETURN0; + } + num_ops++; + op->locals->outer_scope = O->vars; + + switch (op_code) { + case OP_PUSH_VOID: + op->type = SLANG_OPER_VOID; + break; + case OP_PUSH_BOOL: + op->type = SLANG_OPER_LITERAL_BOOL; + if (!parse_number(C, &number)) + RETURN0; + op->literal[0] = + op->literal[1] = + op->literal[2] = + op->literal[3] = (GLfloat) number; + op->literal_size = 1; + break; + case OP_PUSH_INT: + op->type = SLANG_OPER_LITERAL_INT; + if (!parse_number(C, &number)) + RETURN0; + op->literal[0] = + op->literal[1] = + op->literal[2] = + op->literal[3] = (GLfloat) number; + op->literal_size = 1; + break; + case OP_PUSH_FLOAT: + op->type = SLANG_OPER_LITERAL_FLOAT; + if (!parse_float(C, &op->literal[0])) + RETURN0; + op->literal[1] = + op->literal[2] = + op->literal[3] = op->literal[0]; + op->literal_size = 1; + break; + case OP_PUSH_IDENTIFIER: + op->type = SLANG_OPER_IDENTIFIER; + op->a_id = parse_identifier(C); + if (op->a_id == SLANG_ATOM_NULL) + RETURN0; + break; + case OP_SEQUENCE: + op->type = SLANG_OPER_SEQUENCE; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_ASSIGN: + op->type = SLANG_OPER_ASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_ADDASSIGN: + op->type = SLANG_OPER_ADDASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_SUBASSIGN: + op->type = SLANG_OPER_SUBASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_MULASSIGN: + op->type = SLANG_OPER_MULASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_DIVASSIGN: + op->type = SLANG_OPER_DIVASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + /*case OP_MODASSIGN: */ + /*case OP_LSHASSIGN: */ + /*case OP_RSHASSIGN: */ + /*case OP_ORASSIGN: */ + /*case OP_XORASSIGN: */ + /*case OP_ANDASSIGN: */ + case OP_SELECT: + op->type = SLANG_OPER_SELECT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 3)) + RETURN0; + break; + case OP_LOGICALOR: + op->type = SLANG_OPER_LOGICALOR; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_LOGICALXOR: + op->type = SLANG_OPER_LOGICALXOR; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_LOGICALAND: + op->type = SLANG_OPER_LOGICALAND; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + /*case OP_BITOR: */ + /*case OP_BITXOR: */ + /*case OP_BITAND: */ + case OP_EQUAL: + op->type = SLANG_OPER_EQUAL; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_NOTEQUAL: + op->type = SLANG_OPER_NOTEQUAL; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_LESS: + op->type = SLANG_OPER_LESS; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_GREATER: + op->type = SLANG_OPER_GREATER; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_LESSEQUAL: + op->type = SLANG_OPER_LESSEQUAL; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_GREATEREQUAL: + op->type = SLANG_OPER_GREATEREQUAL; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + /*case OP_LSHIFT: */ + /*case OP_RSHIFT: */ + case OP_ADD: + op->type = SLANG_OPER_ADD; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_SUBTRACT: + op->type = SLANG_OPER_SUBTRACT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_MULTIPLY: + op->type = SLANG_OPER_MULTIPLY; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_DIVIDE: + op->type = SLANG_OPER_DIVIDE; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + /*case OP_MODULUS: */ + case OP_PREINCREMENT: + op->type = SLANG_OPER_PREINCREMENT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + case OP_PREDECREMENT: + op->type = SLANG_OPER_PREDECREMENT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + case OP_PLUS: + op->type = SLANG_OPER_PLUS; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + case OP_MINUS: + op->type = SLANG_OPER_MINUS; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + case OP_NOT: + op->type = SLANG_OPER_NOT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + /*case OP_COMPLEMENT: */ + case OP_SUBSCRIPT: + op->type = SLANG_OPER_SUBSCRIPT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_METHOD: + op->type = SLANG_OPER_METHOD; + op->a_obj = parse_identifier(C); + if (op->a_obj == SLANG_ATOM_NULL) + RETURN0; + + op->a_id = parse_identifier(C); + if (op->a_id == SLANG_ATOM_NULL) + RETURN0; + + assert(*C->I == OP_END); + C->I++; + + while (*C->I != OP_END) + if (!parse_child_operation(C, O, op, GL_FALSE)) + RETURN0; + C->I++; +#if 0 + /* don't lookup the method (not yet anyway) */ + if (!C->parsing_builtin + && !slang_function_scope_find_by_name(O->funs, op->a_id, 1)) { + const char *id; + + id = slang_atom_pool_id(C->atoms, op->a_id); + if (!is_constructor_name(id, op->a_id, O->structs)) { + slang_info_log_error(C->L, "%s: undeclared function name.", id); + RETURN0; + } + } +#endif + break; + case OP_CALL: + { + GLboolean array_constructor = GL_FALSE; + GLint array_constructor_size = 0; + + op->type = SLANG_OPER_CALL; + op->a_id = parse_identifier(C); + if (op->a_id == SLANG_ATOM_NULL) + RETURN0; + switch (*C->I++) { + case FUNCTION_CALL_NONARRAY: + /* Nothing to do. */ + break; + case FUNCTION_CALL_ARRAY: + /* Calling an array constructor. For example: + * float[3](1.1, 2.2, 3.3); + */ + if (!O->allow_array_types) { + slang_info_log_error(C->L, + "array constructors not allowed " + "in this GLSL version"); + RETURN0; + } + else { + /* parse the array constructor size */ + slang_operation array_size; + array_constructor = GL_TRUE; + slang_operation_construct(&array_size); + if (!parse_expression(C, O, &array_size)) { + slang_operation_destruct(&array_size); + return GL_FALSE; + } + if (array_size.type != SLANG_OPER_LITERAL_INT) { + slang_info_log_error(C->L, + "constructor array size is not an integer"); + slang_operation_destruct(&array_size); + RETURN0; + } + array_constructor_size = (int) array_size.literal[0]; + op->array_constructor = GL_TRUE; + slang_operation_destruct(&array_size); + } + break; + default: + assert(0); + RETURN0; + } + while (*C->I != OP_END) + if (!parse_child_operation(C, O, op, GL_FALSE)) + RETURN0; + C->I++; + + if (array_constructor && + array_constructor_size != op->num_children) { + slang_info_log_error(C->L, "number of parameters to array" + " constructor does not match array size"); + RETURN0; + } + + if (!C->parsing_builtin + && !slang_function_scope_find_by_name(O->funs, op->a_id, 1)) { + const char *id; + + id = slang_atom_pool_id(C->atoms, op->a_id); + if (!is_constructor_name(id, op->a_id, O->structs)) { + slang_info_log_error(C->L, "%s: undeclared function name.", id); + RETURN0; + } + } + } + break; + case OP_FIELD: + op->type = SLANG_OPER_FIELD; + op->a_id = parse_identifier(C); + if (op->a_id == SLANG_ATOM_NULL) + RETURN0; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + case OP_POSTINCREMENT: + op->type = SLANG_OPER_POSTINCREMENT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + case OP_POSTDECREMENT: + op->type = SLANG_OPER_POSTDECREMENT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + default: + RETURN0; + } + } + C->I++; + + slang_operation_destruct(oper); + *oper = *ops; /* struct copy */ + _slang_free(ops); + + return 1; +} + +/* parameter qualifier */ +#define PARAM_QUALIFIER_IN 0 +#define PARAM_QUALIFIER_OUT 1 +#define PARAM_QUALIFIER_INOUT 2 + +/* function parameter array presence */ +#define PARAMETER_ARRAY_NOT_PRESENT 0 +#define PARAMETER_ARRAY_PRESENT 1 + +static int +parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O, + slang_variable * param) +{ + int param_qual, precision_qual; + + /* parse and validate the parameter's type qualifiers (there can be + * two at most) because not all combinations are valid + */ + if (!parse_type_qualifier(C, ¶m->type.qualifier)) + RETURN0; + + param_qual = *C->I++; + switch (param_qual) { + case PARAM_QUALIFIER_IN: + if (param->type.qualifier != SLANG_QUAL_CONST + && param->type.qualifier != SLANG_QUAL_NONE) { + slang_info_log_error(C->L, "Invalid type qualifier."); + RETURN0; + } + break; + case PARAM_QUALIFIER_OUT: + if (param->type.qualifier == SLANG_QUAL_NONE) + param->type.qualifier = SLANG_QUAL_OUT; + else { + slang_info_log_error(C->L, "Invalid type qualifier."); + RETURN0; + } + break; + case PARAM_QUALIFIER_INOUT: + if (param->type.qualifier == SLANG_QUAL_NONE) + param->type.qualifier = SLANG_QUAL_INOUT; + else { + slang_info_log_error(C->L, "Invalid type qualifier."); + RETURN0; + } + break; + default: + RETURN0; + } + + /* parse precision qualifier (lowp, mediump, highp */ + precision_qual = *C->I++; + /* ignored at this time */ + (void) precision_qual; + + /* parse parameter's type specifier and name */ + if (!parse_type_specifier(C, O, ¶m->type.specifier)) + RETURN0; + if (!parse_type_array_size(C, O, ¶m->type.array_len)) + RETURN0; + param->a_name = parse_identifier(C); + if (param->a_name == SLANG_ATOM_NULL) + RETURN0; + + /* first-class array + */ + if (param->type.array_len >= 0) { + slang_type_specifier p; + + slang_type_specifier_ctr(&p); + if (!slang_type_specifier_copy(&p, ¶m->type.specifier)) { + slang_type_specifier_dtr(&p); + RETURN0; + } + if (!convert_to_array(C, param, &p)) { + slang_type_specifier_dtr(&p); + RETURN0; + } + slang_type_specifier_dtr(&p); + param->array_len = param->type.array_len; + } + + /* if the parameter is an array, parse its size (the size must be + * explicitly defined + */ + if (*C->I++ == PARAMETER_ARRAY_PRESENT) { + slang_type_specifier p; + + if (param->type.array_len >= 0) { + slang_info_log_error(C->L, "multi-dimensional arrays not allowed"); + RETURN0; + } + slang_type_specifier_ctr(&p); + if (!slang_type_specifier_copy(&p, ¶m->type.specifier)) { + slang_type_specifier_dtr(&p); + RETURN0; + } + if (!convert_to_array(C, param, &p)) { + slang_type_specifier_dtr(&p); + RETURN0; + } + slang_type_specifier_dtr(&p); + if (!parse_array_len(C, O, ¶m->array_len)) + RETURN0; + } + +#if 0 + /* calculate the parameter size */ + if (!calculate_var_size(C, O, param)) + RETURN0; +#endif + /* TODO: allocate the local address here? */ + return 1; +} + +/* function type */ +#define FUNCTION_ORDINARY 0 +#define FUNCTION_CONSTRUCTOR 1 +#define FUNCTION_OPERATOR 2 + +/* function parameter */ +#define PARAMETER_NONE 0 +#define PARAMETER_NEXT 1 + +/* operator type */ +#define OPERATOR_ADDASSIGN 1 +#define OPERATOR_SUBASSIGN 2 +#define OPERATOR_MULASSIGN 3 +#define OPERATOR_DIVASSIGN 4 +/*#define OPERATOR_MODASSIGN 5*/ +/*#define OPERATOR_LSHASSIGN 6*/ +/*#define OPERATOR_RSHASSIGN 7*/ +/*#define OPERATOR_ANDASSIGN 8*/ +/*#define OPERATOR_XORASSIGN 9*/ +/*#define OPERATOR_ORASSIGN 10*/ +#define OPERATOR_LOGICALXOR 11 +/*#define OPERATOR_BITOR 12*/ +/*#define OPERATOR_BITXOR 13*/ +/*#define OPERATOR_BITAND 14*/ +#define OPERATOR_LESS 15 +#define OPERATOR_GREATER 16 +#define OPERATOR_LESSEQUAL 17 +#define OPERATOR_GREATEREQUAL 18 +/*#define OPERATOR_LSHIFT 19*/ +/*#define OPERATOR_RSHIFT 20*/ +#define OPERATOR_MULTIPLY 21 +#define OPERATOR_DIVIDE 22 +/*#define OPERATOR_MODULUS 23*/ +#define OPERATOR_INCREMENT 24 +#define OPERATOR_DECREMENT 25 +#define OPERATOR_PLUS 26 +#define OPERATOR_MINUS 27 +/*#define OPERATOR_COMPLEMENT 28*/ +#define OPERATOR_NOT 29 + +static const struct +{ + unsigned int o_code; + const char *o_name; +} operator_names[] = { + {OPERATOR_INCREMENT, "++"}, + {OPERATOR_ADDASSIGN, "+="}, + {OPERATOR_PLUS, "+"}, + {OPERATOR_DECREMENT, "--"}, + {OPERATOR_SUBASSIGN, "-="}, + {OPERATOR_MINUS, "-"}, + {OPERATOR_NOT, "!"}, + {OPERATOR_MULASSIGN, "*="}, + {OPERATOR_MULTIPLY, "*"}, + {OPERATOR_DIVASSIGN, "/="}, + {OPERATOR_DIVIDE, "/"}, + {OPERATOR_LESSEQUAL, "<="}, + /*{ OPERATOR_LSHASSIGN, "<<=" }, */ + /*{ OPERATOR_LSHIFT, "<<" }, */ + {OPERATOR_LESS, "<"}, + {OPERATOR_GREATEREQUAL, ">="}, + /*{ OPERATOR_RSHASSIGN, ">>=" }, */ + /*{ OPERATOR_RSHIFT, ">>" }, */ + {OPERATOR_GREATER, ">"}, + /*{ OPERATOR_MODASSIGN, "%=" }, */ + /*{ OPERATOR_MODULUS, "%" }, */ + /*{ OPERATOR_ANDASSIGN, "&=" }, */ + /*{ OPERATOR_BITAND, "&" }, */ + /*{ OPERATOR_ORASSIGN, "|=" }, */ + /*{ OPERATOR_BITOR, "|" }, */ + /*{ OPERATOR_COMPLEMENT, "~" }, */ + /*{ OPERATOR_XORASSIGN, "^=" }, */ + {OPERATOR_LOGICALXOR, "^^"}, + /*{ OPERATOR_BITXOR, "^" } */ +}; + +static slang_atom +parse_operator_name(slang_parse_ctx * C) +{ + unsigned int i; + + for (i = 0; i < sizeof(operator_names) / sizeof(*operator_names); i++) { + if (operator_names[i].o_code == (unsigned int) (*C->I)) { + slang_atom atom = + slang_atom_pool_atom(C->atoms, operator_names[i].o_name); + if (atom == SLANG_ATOM_NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + C->I++; + return atom; + } + } + RETURN0; +} + + +static int +parse_function_prototype(slang_parse_ctx * C, slang_output_ctx * O, + slang_function * func) +{ + GLuint functype; + /* parse function type and name */ + if (!parse_fully_specified_type(C, O, &func->header.type)) + RETURN0; + + functype = *C->I++; + switch (functype) { + case FUNCTION_ORDINARY: + func->kind = SLANG_FUNC_ORDINARY; + func->header.a_name = parse_identifier(C); + if (func->header.a_name == SLANG_ATOM_NULL) + RETURN0; + break; + case FUNCTION_CONSTRUCTOR: + func->kind = SLANG_FUNC_CONSTRUCTOR; + if (func->header.type.specifier.type == SLANG_SPEC_STRUCT) + RETURN0; + func->header.a_name = + slang_atom_pool_atom(C->atoms, + slang_type_specifier_type_to_string + (func->header.type.specifier.type)); + if (func->header.a_name == SLANG_ATOM_NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + break; + case FUNCTION_OPERATOR: + func->kind = SLANG_FUNC_OPERATOR; + func->header.a_name = parse_operator_name(C); + if (func->header.a_name == SLANG_ATOM_NULL) + RETURN0; + break; + default: + RETURN0; + } + + if (!legal_identifier(func->header.a_name)) { + slang_info_log_error(C->L, "illegal function name '%s'", + (char *) func->header.a_name); + RETURN0; + } + + /* parse function parameters */ + while (*C->I++ == PARAMETER_NEXT) { + slang_variable *p = slang_variable_scope_grow(func->parameters); + if (!p) { + slang_info_log_memory(C->L); + RETURN0; + } + if (!parse_parameter_declaration(C, O, p)) + RETURN0; + } + + /* if the function returns a value, append a hidden __retVal 'out' + * parameter that corresponds to the return value. + */ + if (_slang_function_has_return_value(func)) { + slang_variable *p = slang_variable_scope_grow(func->parameters); + slang_atom a_retVal = slang_atom_pool_atom(C->atoms, "__retVal"); + assert(a_retVal); + p->a_name = a_retVal; + p->type = func->header.type; + p->type.qualifier = SLANG_QUAL_OUT; + } + + /* function formal parameters and local variables share the same + * scope, so save the information about param count in a seperate + * place also link the scope to the global variable scope so when a + * given identifier is not found here, the search process continues + * in the global space + */ + func->param_count = func->parameters->num_variables; + func->parameters->outer_scope = O->vars; + + return 1; +} + +static int +parse_function_definition(slang_parse_ctx * C, slang_output_ctx * O, + slang_function * func) +{ + slang_output_ctx o = *O; + + if (!parse_function_prototype(C, O, func)) + RETURN0; + + /* create function's body operation */ + func->body = (slang_operation *) _slang_alloc(sizeof(slang_operation)); + if (func->body == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + if (!slang_operation_construct(func->body)) { + _slang_free(func->body); + func->body = NULL; + slang_info_log_memory(C->L); + RETURN0; + } + + /* to parse the body the parse context is modified in order to + * capture parsed variables into function's local variable scope + */ + C->global_scope = GL_FALSE; + o.vars = func->parameters; + if (!parse_statement(C, &o, func->body)) + RETURN0; + + C->global_scope = GL_TRUE; + return 1; +} + +static GLboolean +initialize_global(slang_assemble_ctx * A, slang_variable * var) +{ + slang_operation op_id, op_assign; + GLboolean result; + + /* construct the left side of assignment */ + if (!slang_operation_construct(&op_id)) + return GL_FALSE; + op_id.type = SLANG_OPER_IDENTIFIER; + op_id.a_id = var->a_name; + + /* put the variable into operation's scope */ + op_id.locals->variables = + (slang_variable **) _slang_alloc(sizeof(slang_variable *)); + if (op_id.locals->variables == NULL) { + slang_operation_destruct(&op_id); + return GL_FALSE; + } + op_id.locals->num_variables = 1; + op_id.locals->variables[0] = var; + + /* construct the assignment expression */ + if (!slang_operation_construct(&op_assign)) { + op_id.locals->num_variables = 0; + slang_operation_destruct(&op_id); + return GL_FALSE; + } + op_assign.type = SLANG_OPER_ASSIGN; + op_assign.children = + (slang_operation *) _slang_alloc(2 * sizeof(slang_operation)); + if (op_assign.children == NULL) { + slang_operation_destruct(&op_assign); + op_id.locals->num_variables = 0; + slang_operation_destruct(&op_id); + return GL_FALSE; + } + op_assign.num_children = 2; + op_assign.children[0] = op_id; + op_assign.children[1] = *var->initializer; + + result = 1; + + /* carefully destroy the operations */ + op_assign.num_children = 0; + _slang_free(op_assign.children); + op_assign.children = NULL; + slang_operation_destruct(&op_assign); + op_id.locals->num_variables = 0; + slang_operation_destruct(&op_id); + + if (!result) + return GL_FALSE; + + return GL_TRUE; +} + +/* init declarator list */ +#define DECLARATOR_NONE 0 +#define DECLARATOR_NEXT 1 + +/* variable declaration */ +#define VARIABLE_NONE 0 +#define VARIABLE_IDENTIFIER 1 +#define VARIABLE_INITIALIZER 2 +#define VARIABLE_ARRAY_EXPLICIT 3 +#define VARIABLE_ARRAY_UNKNOWN 4 + + +/** + * Check if it's OK to re-declare a variable with the given new type. + * This happens when applying layout qualifiers to gl_FragCoord or + * (re)setting an array size. + * If redeclaration is OK, return a pointer to the incoming variable + * updated with new type info. Else return NULL; + */ +static slang_variable * +redeclare_variable(slang_variable *var, + const slang_fully_specified_type *type) +{ + if (slang_fully_specified_types_compatible(&var->type, type)) { + /* replace orig var layout with new layout */ + var->type.layout = type->layout; + + /* XXX there may be other type updates in the future here */ + + return var; + } + else + return NULL; +} + + +/** + * Parse the initializer for a variable declaration. + */ +static int +parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, + const slang_fully_specified_type * type) +{ + GET_CURRENT_CONTEXT(ctx); /* a hack */ + slang_variable *var = NULL, *prevDecl; + slang_atom a_name; + + /* empty init declatator (without name, e.g. "float ;") */ + if (*C->I++ == VARIABLE_NONE) + return 1; + + a_name = parse_identifier(C); + + /* check if name is already in this scope */ + prevDecl = _slang_variable_locate(O->vars, a_name, C->global_scope); + if (prevDecl) { + /* A var with this name has already been declared. + * Check if redeclaring the var with a different type/layout is legal. + */ + if (C->global_scope) { + var = redeclare_variable(prevDecl, type); + } + if (!var) { + slang_info_log_error(C->L, + "declaration of '%s' conflicts with previous declaration", + (char *) a_name); + RETURN0; + } + } + + if (!var) { + /* make room for a new variable and initialize it */ + var = slang_variable_scope_grow(O->vars); + if (!var) { + slang_info_log_memory(C->L); + RETURN0; + } + + /* copy the declarator type qualifier/etc info, parse the identifier */ + var->type.qualifier = type->qualifier; + var->type.centroid = type->centroid; + var->type.precision = type->precision; + var->type.specifier = type->specifier;/*new*/ + var->type.variant = type->variant; + var->type.layout = type->layout; + var->type.array_len = type->array_len; + var->a_name = a_name; + if (var->a_name == SLANG_ATOM_NULL) + RETURN0; + } + + switch (*C->I++) { + case VARIABLE_NONE: + /* simple variable declarator - just copy the specifier */ + if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) + RETURN0; + break; + case VARIABLE_INITIALIZER: + /* initialized variable - copy the specifier and parse the expression */ + if (0 && type->array_len >= 0) { + /* The type was something like "float[4]" */ + convert_to_array(C, var, &type->specifier); + var->array_len = type->array_len; + } + else { + if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) + RETURN0; + } + var->initializer = + (slang_operation *) _slang_alloc(sizeof(slang_operation)); + if (var->initializer == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + if (!slang_operation_construct(var->initializer)) { + _slang_free(var->initializer); + var->initializer = NULL; + slang_info_log_memory(C->L); + RETURN0; + } + if (!parse_expression(C, O, var->initializer)) + RETURN0; + break; + case VARIABLE_ARRAY_UNKNOWN: + /* unsized array - mark it as array and copy the specifier to + * the array element + */ + if (type->array_len >= 0) { + slang_info_log_error(C->L, "multi-dimensional arrays not allowed"); + RETURN0; + } + if (!convert_to_array(C, var, &type->specifier)) + return GL_FALSE; + break; + case VARIABLE_ARRAY_EXPLICIT: + if (type->array_len >= 0) { + /* the user is trying to do something like: float[2] x[3]; */ + slang_info_log_error(C->L, "multi-dimensional arrays not allowed"); + RETURN0; + } + if (!convert_to_array(C, var, &type->specifier)) + return GL_FALSE; + if (!parse_array_len(C, O, &var->array_len)) + return GL_FALSE; + break; + default: + RETURN0; + } + + /* allocate global address space for a variable with a known size */ + if (C->global_scope + && !(var->type.specifier.type == SLANG_SPEC_ARRAY + && var->array_len == 0)) { + if (!calculate_var_size(C, O, var)) + return GL_FALSE; + } + + /* emit code for global var decl */ + if (C->global_scope) { + slang_assemble_ctx A; + memset(&A, 0, sizeof(slang_assemble_ctx)); + A.allow_uniform_initializers = C->version > 110; + A.atoms = C->atoms; + A.space.funcs = O->funs; + A.space.structs = O->structs; + A.space.vars = O->vars; + A.program = O->program; + A.pragmas = O->pragmas; + A.vartable = O->vartable; + A.log = C->L; + A.curFuncEndLabel = NULL; + A.EmitContReturn = ctx->Shader.EmitContReturn; + if (!_slang_codegen_global_variable(&A, var, C->type)) + RETURN0; + } + + /* initialize global variable */ + if (C->global_scope) { + if (var->initializer != NULL) { + slang_assemble_ctx A; + memset(&A, 0, sizeof(slang_assemble_ctx)); + A.allow_uniform_initializers = C->version > 110; + A.atoms = C->atoms; + A.space.funcs = O->funs; + A.space.structs = O->structs; + A.space.vars = O->vars; + if (!initialize_global(&A, var)) + RETURN0; + } + } + + if (var->type.qualifier == SLANG_QUAL_FIXEDINPUT && + var->a_name == slang_atom_pool_atom(C->atoms, "gl_FragCoord")) { + /* set the program's PixelCenterInteger, OriginUpperLeft fields */ + struct gl_fragment_program *fragProg = + (struct gl_fragment_program *) O->program; + + if (var->type.layout & SLANG_LAYOUT_UPPER_LEFT_BIT) { + fragProg->OriginUpperLeft = GL_TRUE; + } + if (var->type.layout & SLANG_LAYOUT_PIXEL_CENTER_INTEGER_BIT) { + fragProg->PixelCenterInteger = GL_TRUE; + } + } + + return 1; +} + +/** + * Parse a list of variable declarations. Each variable may have an + * initializer. + */ +static int +parse_init_declarator_list(slang_parse_ctx * C, slang_output_ctx * O) +{ + slang_fully_specified_type type; + + /* parse the fully specified type, common to all declarators */ + if (!slang_fully_specified_type_construct(&type)) + RETURN0; + if (!parse_fully_specified_type(C, O, &type)) { + slang_fully_specified_type_destruct(&type); + RETURN0; + } + + /* parse declarators, pass-in the parsed type */ + do { + if (!parse_init_declarator(C, O, &type)) { + slang_fully_specified_type_destruct(&type); + RETURN0; + } + } + while (*C->I++ == DECLARATOR_NEXT); + + slang_fully_specified_type_destruct(&type); + return 1; +} + + +/** + * Parse a function definition or declaration. + * \param C parsing context + * \param O output context + * \param definition if non-zero expect a definition, else a declaration + * \param parsed_func_ret returns the parsed function + * \return GL_TRUE if success, GL_FALSE if failure + */ +static GLboolean +parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, + slang_function ** parsed_func_ret) +{ + slang_function parsed_func, *found_func; + + /* parse function definition/declaration */ + if (!slang_function_construct(&parsed_func)) + return GL_FALSE; + if (definition) { + if (!parse_function_definition(C, O, &parsed_func)) { + slang_function_destruct(&parsed_func); + return GL_FALSE; + } + } + else { + if (!parse_function_prototype(C, O, &parsed_func)) { + slang_function_destruct(&parsed_func); + return GL_FALSE; + } + } + + /* find a function with a prototype matching the parsed one - only + * the current scope is being searched to allow built-in function + * overriding + */ + found_func = slang_function_scope_find(O->funs, &parsed_func, 0); + if (found_func == NULL) { + /* New function, add it to the function list */ + O->funs->functions = + (slang_function *) _slang_realloc(O->funs->functions, + O->funs->num_functions + * sizeof(slang_function), + (O->funs->num_functions + 1) + * sizeof(slang_function)); + if (O->funs->functions == NULL) { + /* Make sure that there are no functions marked, as the + * allocation is currently NULL, in order to avoid + * a potental segfault as we clean up later. + */ + O->funs->num_functions = 0; + + slang_info_log_memory(C->L); + slang_function_destruct(&parsed_func); + return GL_FALSE; + } + O->funs->functions[O->funs->num_functions] = parsed_func; + O->funs->num_functions++; + + /* return the newly parsed function */ + *parsed_func_ret = &O->funs->functions[O->funs->num_functions - 1]; + } + else { + /* previously defined or declared */ + /* TODO: check function return type qualifiers and specifiers */ + if (definition) { + if (found_func->body != NULL) { + slang_info_log_error(C->L, "%s: function already has a body.", + slang_atom_pool_id(C->atoms, + parsed_func.header. + a_name)); + slang_function_destruct(&parsed_func); + return GL_FALSE; + } + + /* destroy the existing function declaration and replace it + * with the new one + */ + slang_function_destruct(found_func); + *found_func = parsed_func; + } + else { + /* another declaration of the same function prototype - ignore it */ + slang_function_destruct(&parsed_func); + } + + /* return the found function */ + *parsed_func_ret = found_func; + } + + return GL_TRUE; +} + +/* declaration */ +#define DECLARATION_FUNCTION_PROTOTYPE 1 +#define DECLARATION_INIT_DECLARATOR_LIST 2 + +static int +parse_declaration(slang_parse_ctx * C, slang_output_ctx * O) +{ + switch (*C->I++) { + case DECLARATION_INIT_DECLARATOR_LIST: + if (!parse_init_declarator_list(C, O)) + RETURN0; + break; + case DECLARATION_FUNCTION_PROTOTYPE: + { + slang_function *dummy_func; + + if (!parse_function(C, O, 0, &dummy_func)) + RETURN0; + } + break; + default: + RETURN0; + } + return 1; +} + +static int +parse_default_precision(slang_parse_ctx * C, slang_output_ctx * O) +{ + int precision, type; + + if (!O->allow_precision) { + slang_info_log_error(C->L, "syntax error at \"precision\""); + RETURN0; + } + + precision = *C->I++; + switch (precision) { + case PRECISION_LOW: + case PRECISION_MEDIUM: + case PRECISION_HIGH: + /* OK */ + break; + default: + _mesa_problem(NULL, "unexpected precision %d at %s:%d\n", + precision, __FILE__, __LINE__); + RETURN0; + } + + type = *C->I++; + switch (type) { + case TYPE_SPECIFIER_FLOAT: + case TYPE_SPECIFIER_INT: + case TYPE_SPECIFIER_SAMPLER1D: + case TYPE_SPECIFIER_SAMPLER2D: + case TYPE_SPECIFIER_SAMPLER3D: + case TYPE_SPECIFIER_SAMPLERCUBE: + case TYPE_SPECIFIER_SAMPLER1DSHADOW: + case TYPE_SPECIFIER_SAMPLER2DSHADOW: + case TYPE_SPECIFIER_SAMPLER2DRECT: + case TYPE_SPECIFIER_SAMPLER2DRECTSHADOW: + case TYPE_SPECIFIER_SAMPLER_1D_ARRAY: + case TYPE_SPECIFIER_SAMPLER_2D_ARRAY: + case TYPE_SPECIFIER_SAMPLER_1D_ARRAY_SHADOW: + case TYPE_SPECIFIER_SAMPLER_2D_ARRAY_SHADOW: + /* OK */ + break; + default: + _mesa_problem(NULL, "unexpected type %d at %s:%d\n", + type, __FILE__, __LINE__); + RETURN0; + } + + assert(type < TYPE_SPECIFIER_COUNT); + O->default_precision[type] = precision; + + return 1; +} + + +/** + * Initialize the default precision for all types. + * XXX this info isn't used yet. + */ +static void +init_default_precision(slang_output_ctx *O, slang_unit_type type) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint i; + for (i = 0; i < TYPE_SPECIFIER_COUNT; i++) { +#if FEATURE_es2_glsl + if (ctx->API == API_OPENGLES2) + O->default_precision[i] = PRECISION_LOW; + else + O->default_precision[i] = PRECISION_HIGH; +#else + (void) ctx; + O->default_precision[i] = PRECISION_HIGH; +#endif + } + + if (type == SLANG_UNIT_VERTEX_SHADER) { + O->default_precision[TYPE_SPECIFIER_FLOAT] = PRECISION_HIGH; + O->default_precision[TYPE_SPECIFIER_INT] = PRECISION_HIGH; + } + else { + O->default_precision[TYPE_SPECIFIER_INT] = PRECISION_MEDIUM; + } +} + + +static int +parse_invariant(slang_parse_ctx * C, slang_output_ctx * O) +{ + if (O->allow_invariant) { + slang_atom *a = parse_identifier(C); + /* XXX not doing anything with this var yet */ + /*printf("ID: %s\n", (char*) a);*/ + return a ? 1 : 0; + } + else { + slang_info_log_error(C->L, "syntax error at \"invariant\""); + RETURN0; + } +} + + +/* external declaration or default precision specifier */ +#define EXTERNAL_NULL 0 +#define EXTERNAL_FUNCTION_DEFINITION 1 +#define EXTERNAL_DECLARATION 2 +#define DEFAULT_PRECISION 3 +#define INVARIANT_STMT 4 + + +static GLboolean +parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit, + struct gl_shader *shader) +{ + GET_CURRENT_CONTEXT(ctx); + slang_output_ctx o; + GLboolean success; + GLuint maxRegs; + slang_function *mainFunc = NULL; + + if (unit->type == SLANG_UNIT_FRAGMENT_BUILTIN || + unit->type == SLANG_UNIT_FRAGMENT_SHADER) { + maxRegs = ctx->Const.FragmentProgram.MaxTemps; + } + else { + assert(unit->type == SLANG_UNIT_VERTEX_BUILTIN || + unit->type == SLANG_UNIT_VERTEX_SHADER); + maxRegs = ctx->Const.VertexProgram.MaxTemps; + } + + /* setup output context */ + o.funs = &unit->funs; + o.structs = &unit->structs; + o.vars = &unit->vars; + o.program = shader ? shader->Program : NULL; + o.pragmas = shader ? &shader->Pragmas : NULL; + o.vartable = _slang_new_var_table(maxRegs); + _slang_push_var_table(o.vartable); + + /* allow 'invariant' keyword? */ +#if FEATURE_es2_glsl + o.allow_invariant = + (ctx->API == API_OPENGLES2 || C->version >= 120) ? GL_TRUE : GL_FALSE; +#else + o.allow_invariant = (C->version >= 120) ? GL_TRUE : GL_FALSE; +#endif + + /* allow 'centroid' keyword? */ + o.allow_centroid = (C->version >= 120) ? GL_TRUE : GL_FALSE; + + /* allow 'lowp/mediump/highp' keywords? */ +#if FEATURE_es2_glsl + o.allow_precision = + (ctx->API == API_OPENGLES2 || C->version >= 120) ? GL_TRUE : GL_FALSE; +#else + o.allow_precision = (C->version >= 120) ? GL_TRUE : GL_FALSE; +#endif + init_default_precision(&o, unit->type); + + /* allow 'float[]' keyword? */ + o.allow_array_types = (C->version >= 120) ? GL_TRUE : GL_FALSE; + + /* parse individual functions and declarations */ + while (*C->I != EXTERNAL_NULL) { + switch (*C->I++) { + case EXTERNAL_FUNCTION_DEFINITION: + { + slang_function *func; + success = parse_function(C, &o, 1, &func); + if (success && strcmp((char *) func->header.a_name, "main") == 0) { + /* found main() */ + mainFunc = func; + } + } + break; + case EXTERNAL_DECLARATION: + success = parse_declaration(C, &o); + break; + case DEFAULT_PRECISION: + success = parse_default_precision(C, &o); + break; + case INVARIANT_STMT: + success = parse_invariant(C, &o); + break; + default: + success = GL_FALSE; + } + + if (!success) { + /* xxx free codegen */ + _slang_pop_var_table(o.vartable); + return GL_FALSE; + } + } + C->I++; + + if (mainFunc) { + /* assemble (generate code) for main() */ + slang_assemble_ctx A; + memset(&A, 0, sizeof(slang_assemble_ctx)); + A.atoms = C->atoms; + A.space.funcs = o.funs; + A.space.structs = o.structs; + A.space.vars = o.vars; + A.program = o.program; + A.pragmas = &shader->Pragmas; + A.vartable = o.vartable; + A.EmitContReturn = ctx->Shader.EmitContReturn; + A.log = C->L; + A.allow_uniform_initializers = C->version > 110; + + /* main() takes no parameters */ + if (mainFunc->param_count > 0) { + slang_info_log_error(A.log, "main() takes no arguments"); + return GL_FALSE; + } + + _slang_codegen_function(&A, mainFunc); + + shader->Main = GL_TRUE; /* this shader defines main() */ + + shader->UnresolvedRefs = A.UnresolvedRefs; + } + + _slang_pop_var_table(o.vartable); + _slang_delete_var_table(o.vartable); + + return GL_TRUE; +} + +static GLboolean +compile_binary(const unsigned char * prod, slang_code_unit * unit, + GLuint version, + slang_unit_type type, slang_info_log * infolog, + slang_code_unit * builtin, slang_code_unit * downlink, + struct gl_shader *shader) +{ + slang_parse_ctx C; + + unit->type = type; + + /* setup parse context */ + C.I = prod; + C.L = infolog; + C.parsing_builtin = (builtin == NULL); + C.global_scope = GL_TRUE; + C.atoms = &unit->object->atompool; + C.type = type; + C.version = version; + + if (!check_revision(&C)) + return GL_FALSE; + + if (downlink != NULL) { + unit->vars.outer_scope = &downlink->vars; + unit->funs.outer_scope = &downlink->funs; + unit->structs.outer_scope = &downlink->structs; + } + + /* parse translation unit */ + return parse_code_unit(&C, unit, shader); +} + +static GLboolean +compile_with_grammar(const char *source, + slang_code_unit *unit, + slang_unit_type type, + slang_info_log *infolog, + slang_code_unit *builtin, + struct gl_shader *shader, + struct gl_sl_pragmas *pragmas, + unsigned int shader_type, + unsigned int parsing_builtin) +{ + GET_CURRENT_CONTEXT(ctx); + struct sl_pp_purify_options options; + struct sl_pp_context *context; + unsigned char *prod; + GLuint size; + unsigned int version; + unsigned int maxVersion; + int result; + char errmsg[200] = ""; + + assert(shader_type == 1 || shader_type == 2); + + memset(&options, 0, sizeof(options)); + + context = sl_pp_context_create(source, &options); + if (!context) { + slang_info_log_error(infolog, "out of memory"); + return GL_FALSE; + } + + if (sl_pp_version(context, &version)) { + slang_info_log_error(infolog, "%s", sl_pp_context_error_message(context)); + sl_pp_context_destroy(context); + return GL_FALSE; + } + + if (sl_pp_context_add_extension(context, "GL_ARB_draw_buffers") || + sl_pp_context_add_extension(context, "GL_ARB_texture_rectangle")) { + slang_info_log_error(infolog, "%s", sl_pp_context_error_message(context)); + sl_pp_context_destroy(context); + return GL_FALSE; + } + + if (type == SLANG_UNIT_FRAGMENT_SHADER) { + sl_pp_context_add_extension(context, "GL_ARB_fragment_coord_conventions"); + } + + +#if FEATURE_es2_glsl + if (ctx->API == API_OPENGLES2) { + if (sl_pp_context_add_predefined(context, "GL_ES", "1") || + sl_pp_context_add_predefined(context, "GL_FRAGMENT_PRECISION_HIGH", "1")) { + slang_info_log_error(infolog, "%s", sl_pp_context_error_message(context)); + sl_pp_context_destroy(context); + return GL_FALSE; + } + } +#else + (void) ctx; +#endif + +#if FEATURE_ARB_shading_language_120 + maxVersion = 120; +#elif FEATURE_es2_glsl + maxVersion = 100; +#else + maxVersion = 110; +#endif + + if (version > maxVersion || + (version != 100 && version != 110 && version != 120)) { + slang_info_log_error(infolog, + "language version %.2f is not supported.", + version * 0.01); + sl_pp_context_destroy(context); + return GL_FALSE; + } + + /* Finally check the syntax and generate its binary representation. */ + result = sl_cl_compile(context, + shader_type, + parsing_builtin, + &prod, + &size, + errmsg, + sizeof(errmsg)); + + sl_pp_context_destroy(context); + + if (result) { + /*GLint pos;*/ + + slang_info_log_error(infolog, errmsg); + /* syntax error (possibly in library code) */ +#if 0 + { + int line, col; + char *s; + s = (char *) _mesa_find_line_column((const GLubyte *) source, + (const GLubyte *) source + pos, + &line, &col); + printf("Error on line %d, col %d: %s\n", line, col, s); + } +#endif + return GL_FALSE; + } + + /* Syntax is okay - translate it to internal representation. */ + if (!compile_binary(prod, unit, version, type, infolog, builtin, + &builtin[SLANG_BUILTIN_TOTAL - 1], + shader)) { + free(prod); + return GL_FALSE; + } + free(prod); + return GL_TRUE; +} + +static const unsigned char slang_core_gc[] = { +#include "library/slang_core_gc.h" +}; + +static const unsigned char slang_120_core_gc[] = { +#include "library/slang_120_core_gc.h" +}; + +static const unsigned char slang_120_fragment_gc[] = { +#include "library/slang_builtin_120_fragment_gc.h" +}; + +static const unsigned char slang_common_builtin_gc[] = { +#include "library/slang_common_builtin_gc.h" +}; + +static const unsigned char slang_fragment_builtin_gc[] = { +#include "library/slang_fragment_builtin_gc.h" +}; + +static const unsigned char slang_vertex_builtin_gc[] = { +#include "library/slang_vertex_builtin_gc.h" +}; + +static GLboolean +compile_object(const char *source, + slang_code_object *object, + slang_unit_type type, + slang_info_log *infolog, + struct gl_shader *shader, + struct gl_sl_pragmas *pragmas) +{ + slang_code_unit *builtins = NULL; + GLuint base_version = 110; + unsigned int shader_type; + unsigned int parsing_builtin; + + /* set shader type - the syntax is slightly different for different shaders */ + if (type == SLANG_UNIT_FRAGMENT_SHADER || type == SLANG_UNIT_FRAGMENT_BUILTIN) { + shader_type = 1; + } else { + shader_type = 2; + } + + /* enable language extensions */ + parsing_builtin = 1; + + /* if parsing user-specified shader, load built-in library */ + if (type == SLANG_UNIT_FRAGMENT_SHADER || type == SLANG_UNIT_VERTEX_SHADER) { + /* compile core functionality first */ + if (!compile_binary(slang_core_gc, + &object->builtin[SLANG_BUILTIN_CORE], + base_version, + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, + NULL, NULL, NULL)) + return GL_FALSE; + +#if FEATURE_ARB_shading_language_120 + if (!compile_binary(slang_120_core_gc, + &object->builtin[SLANG_BUILTIN_120_CORE], + 120, + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, + NULL, &object->builtin[SLANG_BUILTIN_CORE], NULL)) + return GL_FALSE; +#endif + + /* compile common functions and variables, link to core */ + if (!compile_binary(slang_common_builtin_gc, + &object->builtin[SLANG_BUILTIN_COMMON], +#if FEATURE_ARB_shading_language_120 + 120, +#else + base_version, +#endif + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, +#if FEATURE_ARB_shading_language_120 + &object->builtin[SLANG_BUILTIN_120_CORE], +#else + &object->builtin[SLANG_BUILTIN_CORE], +#endif + NULL)) + return GL_FALSE; + + /* compile target-specific functions and variables, link to common */ + if (type == SLANG_UNIT_FRAGMENT_SHADER) { + if (!compile_binary(slang_fragment_builtin_gc, + &object->builtin[SLANG_BUILTIN_TARGET], + base_version, + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, + &object->builtin[SLANG_BUILTIN_COMMON], NULL)) + return GL_FALSE; +#if FEATURE_ARB_shading_language_120 + if (!compile_binary(slang_120_fragment_gc, + &object->builtin[SLANG_BUILTIN_TARGET], + 120, + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, + &object->builtin[SLANG_BUILTIN_COMMON], NULL)) + return GL_FALSE; +#endif + } + else if (type == SLANG_UNIT_VERTEX_SHADER) { + if (!compile_binary(slang_vertex_builtin_gc, + &object->builtin[SLANG_BUILTIN_TARGET], + base_version, + SLANG_UNIT_VERTEX_BUILTIN, infolog, NULL, + &object->builtin[SLANG_BUILTIN_COMMON], NULL)) + return GL_FALSE; + } + + /* disable language extensions */ + parsing_builtin = 0; + + builtins = object->builtin; + } + + /* compile the actual shader - pass-in built-in library for external shader */ + return compile_with_grammar(source, + &object->unit, + type, + infolog, + builtins, + shader, + pragmas, + shader_type, + parsing_builtin); +} + + +GLboolean +_slang_compile(GLcontext *ctx, struct gl_shader *shader) +{ + GLboolean success; + slang_info_log info_log; + slang_code_object obj; + slang_unit_type type; + GLenum progTarget; + + if (shader->Type == GL_VERTEX_SHADER) { + type = SLANG_UNIT_VERTEX_SHADER; + } + else { + assert(shader->Type == GL_FRAGMENT_SHADER); + type = SLANG_UNIT_FRAGMENT_SHADER; + } + + if (!shader->Source) + return GL_FALSE; + + ctx->Shader.MemPool = _slang_new_mempool(1024*1024); + + shader->Main = GL_FALSE; + + /* free the shader's old instructions, etc */ + _mesa_reference_program(ctx, &shader->Program, NULL); + + /* allocate new GPU program, parameter lists, etc. */ + if (shader->Type == GL_VERTEX_SHADER) + progTarget = GL_VERTEX_PROGRAM_ARB; + else + progTarget = GL_FRAGMENT_PROGRAM_ARB; + shader->Program = ctx->Driver.NewProgram(ctx, progTarget, 1); + shader->Program->Parameters = _mesa_new_parameter_list(); + shader->Program->Varying = _mesa_new_parameter_list(); + shader->Program->Attributes = _mesa_new_parameter_list(); + + slang_info_log_construct(&info_log); + _slang_code_object_ctr(&obj); + + success = compile_object(shader->Source, + &obj, + type, + &info_log, + shader, + &shader->Pragmas); + + /* free shader's prev info log */ + if (shader->InfoLog) { + free(shader->InfoLog); + shader->InfoLog = NULL; + } + + if (info_log.text) { + /* copy info-log string to shader object */ + shader->InfoLog = _mesa_strdup(info_log.text); + } + + if (info_log.error_flag) { + success = GL_FALSE; + } + + slang_info_log_destruct(&info_log); + _slang_code_object_dtr(&obj); + + _slang_delete_mempool((slang_mempool *) ctx->Shader.MemPool); + ctx->Shader.MemPool = NULL; + + /* remove any reads of output registers */ +#if 0 + printf("Pre-remove output reads:\n"); + _mesa_print_program(shader->Program); +#endif + _mesa_remove_output_reads(shader->Program, PROGRAM_OUTPUT); + if (shader->Type == GL_VERTEX_SHADER) { + /* and remove writes to varying vars in vertex programs */ + _mesa_remove_output_reads(shader->Program, PROGRAM_VARYING); + } +#if 0 + printf("Post-remove output reads:\n"); + _mesa_print_program(shader->Program); +#endif + + shader->CompileStatus = success; + + if (success) { + if (shader->Pragmas.Optimize && + (ctx->Shader.Flags & GLSL_NO_OPT) == 0) { + _mesa_optimize_program(ctx, shader->Program); + } + if ((ctx->Shader.Flags & GLSL_NOP_VERT) && + shader->Program->Target == GL_VERTEX_PROGRAM_ARB) { + _mesa_nop_vertex_program(ctx, + (struct gl_vertex_program *) shader->Program); + } + if ((ctx->Shader.Flags & GLSL_NOP_FRAG) && + shader->Program->Target == GL_FRAGMENT_PROGRAM_ARB) { + _mesa_nop_fragment_program(ctx, + (struct gl_fragment_program *) shader->Program); + } + } + + if (ctx->Shader.Flags & GLSL_LOG) { + _mesa_write_shader_to_file(shader); + } + + return success; +} + diff --git a/src/mesa/slang/slang_compile.h b/src/mesa/slang/slang_compile.h new file mode 100644 index 0000000000..7fb549d33d --- /dev/null +++ b/src/mesa/slang/slang_compile.h @@ -0,0 +1,100 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#if !defined SLANG_COMPILE_H +#define SLANG_COMPILE_H + +#include "main/imports.h" +#include "main/mtypes.h" +#include "slang_typeinfo.h" +#include "slang_compile_variable.h" +#include "slang_compile_struct.h" +#include "slang_compile_operation.h" +#include "slang_compile_function.h" + +#if defined __cplusplus +extern "C" { +#endif + +typedef struct slang_name_space_ +{ + struct slang_function_scope_ *funcs; + struct slang_struct_scope_ *structs; + struct slang_variable_scope_ *vars; +} slang_name_space; + +typedef enum slang_unit_type_ +{ + SLANG_UNIT_FRAGMENT_SHADER, + SLANG_UNIT_VERTEX_SHADER, + SLANG_UNIT_FRAGMENT_BUILTIN, + SLANG_UNIT_VERTEX_BUILTIN +} slang_unit_type; + + +typedef struct slang_code_unit_ +{ + slang_variable_scope vars; + slang_function_scope funs; + slang_struct_scope structs; + slang_unit_type type; + struct slang_code_object_ *object; +} slang_code_unit; + + +extern GLvoid +_slang_code_unit_ctr (slang_code_unit *, struct slang_code_object_ *); + +extern GLvoid +_slang_code_unit_dtr (slang_code_unit *); + +#define SLANG_BUILTIN_CORE 0 +#define SLANG_BUILTIN_120_CORE 1 +#define SLANG_BUILTIN_COMMON 2 +#define SLANG_BUILTIN_TARGET 3 + +#define SLANG_BUILTIN_TOTAL 4 + +typedef struct slang_code_object_ +{ + slang_code_unit builtin[SLANG_BUILTIN_TOTAL]; + slang_code_unit unit; + slang_atom_pool atompool; +} slang_code_object; + +extern GLvoid +_slang_code_object_ctr (slang_code_object *); + +extern GLvoid +_slang_code_object_dtr (slang_code_object *); + +extern GLboolean +_slang_compile (GLcontext *ctx, struct gl_shader *shader); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/mesa/slang/slang_compile_function.c b/src/mesa/slang/slang_compile_function.c new file mode 100644 index 0000000000..4dd885176d --- /dev/null +++ b/src/mesa/slang/slang_compile_function.c @@ -0,0 +1,262 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_compile_function.c + * slang front-end compiler + * \author Michal Krol + */ + +#include "main/imports.h" +#include "slang_compile.h" +#include "slang_mem.h" + + +int +slang_function_construct(slang_function * func) +{ + func->kind = SLANG_FUNC_ORDINARY; + if (!slang_variable_construct(&func->header)) + return 0; + + func->parameters = (slang_variable_scope *) + _slang_alloc(sizeof(slang_variable_scope)); + if (func->parameters == NULL) { + slang_variable_destruct(&func->header); + return 0; + } + + _slang_variable_scope_ctr(func->parameters); + func->param_count = 0; + func->body = NULL; + return 1; +} + +void +slang_function_destruct(slang_function * func) +{ + slang_variable_destruct(&func->header); + slang_variable_scope_destruct(func->parameters); + _slang_free(func->parameters); + if (func->body != NULL) { + slang_operation_destruct(func->body); + _slang_free(func->body); + } +} + + +slang_function * +slang_function_new(slang_function_kind kind) +{ + slang_function *fun = (slang_function *) + _slang_alloc(sizeof(slang_function)); + if (fun) { + slang_function_construct(fun); + fun->kind = kind; + } + return fun; +} + + +/* + * slang_function_scope + */ + +GLvoid +_slang_function_scope_ctr(slang_function_scope * self) +{ + self->functions = NULL; + self->num_functions = 0; + self->outer_scope = NULL; +} + +void +slang_function_scope_destruct(slang_function_scope * scope) +{ + unsigned int i; + + for (i = 0; i < scope->num_functions; i++) + slang_function_destruct(scope->functions + i); + _slang_free(scope->functions); +} + + +/** + * Does this function have a non-void return value? + */ +GLboolean +_slang_function_has_return_value(const slang_function *fun) +{ + return fun->header.type.specifier.type != SLANG_SPEC_VOID; +} + + +/** + * Search a list of functions for a particular function by name. + * \param funcs the list of functions to search + * \param a_name the name to search for + * \param all_scopes if non-zero, search containing scopes too. + * \return pointer to found function, or NULL. + */ +int +slang_function_scope_find_by_name(slang_function_scope * funcs, + slang_atom a_name, int all_scopes) +{ + unsigned int i; + + for (i = 0; i < funcs->num_functions; i++) + if (a_name == funcs->functions[i].header.a_name) + return 1; + if (all_scopes && funcs->outer_scope != NULL) + return slang_function_scope_find_by_name(funcs->outer_scope, a_name, 1); + return 0; +} + + +/** + * Search a list of functions for a particular function (for implementing + * function calls. Matching is done by first comparing the function's name, + * then the function's parameter list. + * + * \param funcs the list of functions to search + * \param fun the function to search for + * \param all_scopes if non-zero, search containing scopes too. + * \return pointer to found function, or NULL. + */ +slang_function * +slang_function_scope_find(slang_function_scope * funcs, slang_function * fun, + int all_scopes) +{ + unsigned int i; + + for (i = 0; i < funcs->num_functions; i++) { + slang_function *f = &funcs->functions[i]; + const GLuint haveRetValue = 0; +#if 0 + = (f->header.type.specifier.type != SLANG_SPEC_VOID); +#endif + unsigned int j; + + /* + printf("Compare name %s to %s (ret %u, %d, %d)\n", + (char *) fun->header.a_name, (char *) f->header.a_name, + haveRetValue, + fun->param_count, f->param_count); + */ + + if (fun->header.a_name != f->header.a_name) + continue; + if (fun->param_count != f->param_count) + continue; + for (j = haveRetValue; j < fun->param_count; j++) { + if (!slang_type_specifier_equal + (&fun->parameters->variables[j]->type.specifier, + &f->parameters->variables[j]->type.specifier)) + break; + } + if (j == fun->param_count) { + /* + printf("Found match\n"); + */ + return f; + } + } + /* + printf("Not found\n"); + */ + if (all_scopes && funcs->outer_scope != NULL) + return slang_function_scope_find(funcs->outer_scope, fun, 1); + return NULL; +} + + +/** + * Lookup a function according to name and parameter count/types. + */ +slang_function * +_slang_function_locate(const slang_function_scope * funcs, slang_atom a_name, + slang_operation * args, GLuint num_args, + const slang_name_space * space, slang_atom_pool * atoms, + slang_info_log *log, GLboolean *error) +{ + slang_typeinfo arg_ti[100]; + GLuint i; + + *error = GL_FALSE; + + /* determine type of each argument */ + assert(num_args < 100); + for (i = 0; i < num_args; i++) { + if (!slang_typeinfo_construct(&arg_ti[i])) + return NULL; + if (!_slang_typeof_operation(&args[i], space, &arg_ti[i], atoms, log)) { + return NULL; + } + } + + /* loop over function scopes */ + while (funcs) { + + /* look for function with matching name and argument/param types */ + for (i = 0; i < funcs->num_functions; i++) { + slang_function *f = &funcs->functions[i]; + const GLuint haveRetValue = _slang_function_has_return_value(f); + GLuint j; + + if (a_name != f->header.a_name) + continue; + if (f->param_count - haveRetValue != num_args) + continue; + + /* compare parameter / argument types */ + for (j = 0; j < num_args; j++) { + if (!slang_type_specifier_compatible(&arg_ti[j].spec, + &f->parameters->variables[j]->type.specifier)) { + /* param/arg types don't match */ + break; + } + + /* "out" and "inout" formal parameter requires the actual + * argument to be an l-value. + */ + if (!arg_ti[j].can_be_referenced && + (f->parameters->variables[j]->type.qualifier == SLANG_QUAL_OUT || + f->parameters->variables[j]->type.qualifier == SLANG_QUAL_INOUT)) { + /* param is not an lvalue! */ + *error = GL_TRUE; + return NULL; + } + } + + if (j == num_args) { + /* name and args match! */ + return f; + } + } + + funcs = funcs->outer_scope; + } + + return NULL; +} diff --git a/src/mesa/slang/slang_compile_function.h b/src/mesa/slang/slang_compile_function.h new file mode 100644 index 0000000000..a5445ec253 --- /dev/null +++ b/src/mesa/slang/slang_compile_function.h @@ -0,0 +1,92 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_COMPILE_FUNCTION_H +#define SLANG_COMPILE_FUNCTION_H + + +/** + * Types of functions. + */ +typedef enum slang_function_kind_ +{ + SLANG_FUNC_ORDINARY, + SLANG_FUNC_CONSTRUCTOR, + SLANG_FUNC_OPERATOR +} slang_function_kind; + + +/** + * Description of a compiled shader function. + */ +typedef struct slang_function_ +{ + slang_function_kind kind; + slang_variable header; /**< The function's name and return type */ + slang_variable_scope *parameters; /**< formal parameters AND local vars */ + unsigned int param_count; /**< number of formal params (no locals) */ + slang_operation *body; /**< The instruction tree */ +} slang_function; + +extern int slang_function_construct(slang_function *); +extern void slang_function_destruct(slang_function *); +extern slang_function *slang_function_new(slang_function_kind kind); + +extern GLboolean +_slang_function_has_return_value(const slang_function *fun); + + +/** + * Basically, a list of compiled functions. + */ +typedef struct slang_function_scope_ +{ + slang_function *functions; + GLuint num_functions; + struct slang_function_scope_ *outer_scope; +} slang_function_scope; + + +extern GLvoid +_slang_function_scope_ctr(slang_function_scope *); + +extern void +slang_function_scope_destruct(slang_function_scope *); + +extern int +slang_function_scope_find_by_name(slang_function_scope *, slang_atom, int); + +extern slang_function * +slang_function_scope_find(slang_function_scope *, slang_function *, int); + +extern struct slang_function_ * +_slang_function_locate(const struct slang_function_scope_ *funcs, + slang_atom name, struct slang_operation_ *params, + GLuint num_params, + const struct slang_name_space_ *space, + slang_atom_pool *atoms, slang_info_log *log, + GLboolean *error); + + +#endif /* SLANG_COMPILE_FUNCTION_H */ diff --git a/src/mesa/slang/slang_compile_operation.c b/src/mesa/slang/slang_compile_operation.c new file mode 100644 index 0000000000..5441d60df5 --- /dev/null +++ b/src/mesa/slang/slang_compile_operation.c @@ -0,0 +1,334 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_compile_operation.c + * slang front-end compiler + * \author Michal Krol + */ + +#include "main/imports.h" +#include "slang_compile.h" +#include "slang_mem.h" + + +/** + * Init a slang_operation object + */ +GLboolean +slang_operation_construct(slang_operation * oper) +{ + oper->type = SLANG_OPER_NONE; + oper->children = NULL; + oper->num_children = 0; + oper->literal[0] = 0.0; + oper->literal_size = 1; + oper->array_constructor = GL_FALSE; + oper->a_id = SLANG_ATOM_NULL; + oper->a_obj = SLANG_ATOM_NULL; + oper->locals = _slang_variable_scope_new(NULL); + if (oper->locals == NULL) + return GL_FALSE; + _slang_variable_scope_ctr(oper->locals); + oper->fun = NULL; + oper->var = NULL; + oper->label = NULL; + return GL_TRUE; +} + +void +slang_operation_destruct(slang_operation * oper) +{ + GLuint i; + + for (i = 0; i < oper->num_children; i++) + slang_operation_destruct(oper->children + i); + _slang_free(oper->children); + slang_variable_scope_destruct(oper->locals); + _slang_free(oper->locals); + oper->children = NULL; + oper->num_children = 0; + oper->locals = NULL; +} + + +/** + * Recursively traverse 'oper', replacing occurances of 'oldScope' with + * 'newScope' in the oper->locals->outer_scope field. + */ +void +slang_replace_scope(slang_operation *oper, + slang_variable_scope *oldScope, + slang_variable_scope *newScope) +{ + GLuint i; + + if (oper->locals != newScope && + oper->locals->outer_scope == oldScope) { + /* found. replace old w/ new */ + oper->locals->outer_scope = newScope; + } + + if (oper->type == SLANG_OPER_VARIABLE_DECL) { + /* search/replace in the initializer */ + slang_variable *var; + var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); + if (var && var->initializer) { + slang_replace_scope(var->initializer, oldScope, newScope); + } + } + + /* search/replace in children */ + for (i = 0; i < oper->num_children; i++) { + slang_replace_scope(&oper->children[i], oldScope, newScope); + } +} + + +/** + * Recursively copy a slang_operation node. + * \param x copy target + * \param y copy source + * \return GL_TRUE for success, GL_FALSE if failure + */ +GLboolean +slang_operation_copy(slang_operation * x, const slang_operation * y) +{ + slang_operation z; + GLuint i; + + if (!slang_operation_construct(&z)) + return GL_FALSE; + z.type = y->type; + if (y->num_children > 0) { + z.children = (slang_operation *) + _slang_alloc(y->num_children * sizeof(slang_operation)); + if (z.children == NULL) { + slang_operation_destruct(&z); + return GL_FALSE; + } + } + for (z.num_children = 0; z.num_children < y->num_children; + z.num_children++) { + if (!slang_operation_construct(&z.children[z.num_children])) { + slang_operation_destruct(&z); + return GL_FALSE; + } + } + for (i = 0; i < z.num_children; i++) { + if (!slang_operation_copy(&z.children[i], &y->children[i])) { + slang_operation_destruct(&z); + return GL_FALSE; + } + } + z.literal[0] = y->literal[0]; + z.literal[1] = y->literal[1]; + z.literal[2] = y->literal[2]; + z.literal[3] = y->literal[3]; + z.literal_size = y->literal_size; + assert(y->literal_size >= 1); + assert(y->literal_size <= 4); + z.a_id = y->a_id; + if (y->locals) { + if (!slang_variable_scope_copy(z.locals, y->locals)) { + slang_operation_destruct(&z); + return GL_FALSE; + } + } + + /* update scoping for children */ + for (i = 0; i < y->num_children; i++) { + if (y->children[i].locals && + y->children[i].locals->outer_scope == y->locals) { + z.children[i].locals->outer_scope = z.locals; + } + } + +#if 0 + z.var = y->var; + z.fun = y->fun; +#endif + slang_operation_destruct(x); + *x = z; + + /* If this operation declares a new scope, we need to make sure + * all children point to it, not the original operation's scope! + */ + if (x->type == SLANG_OPER_BLOCK_NEW_SCOPE || + x->type == SLANG_OPER_WHILE || + x->type == SLANG_OPER_FOR) { + slang_replace_scope(x, y->locals, x->locals); + } + + return GL_TRUE; +} + + +slang_operation * +slang_operation_new(GLuint count) +{ + slang_operation *ops + = (slang_operation *) _slang_alloc(count * sizeof(slang_operation)); + assert(count > 0); + if (ops) { + GLuint i; + for (i = 0; i < count; i++) + slang_operation_construct(ops + i); + } + return ops; +} + + +/** + * Delete operation and all children + */ +void +slang_operation_delete(slang_operation *oper) +{ + slang_operation_destruct(oper); + _slang_free(oper); +} + + +void +slang_operation_free_children(slang_operation *oper) +{ + GLuint i; + for (i = 0; i < slang_oper_num_children(oper); i++) { + slang_operation *child = slang_oper_child(oper, i); + slang_operation_destruct(child); + } + _slang_free(oper->children); + oper->children = NULL; + oper->num_children = 0; +} + + +slang_operation * +slang_operation_grow(GLuint *numChildren, slang_operation **children) +{ + slang_operation *ops; + + ops = (slang_operation *) + _slang_realloc(*children, + *numChildren * sizeof(slang_operation), + (*numChildren + 1) * sizeof(slang_operation)); + if (ops) { + slang_operation *newOp = ops + *numChildren; + if (!slang_operation_construct(newOp)) { + _slang_free(ops); + *children = NULL; + return NULL; + } + *children = ops; + (*numChildren)++; + return newOp; + } + return NULL; +} + +/** + * Insert a new slang_operation into an array. + * \param numElements pointer to current array size (in/out) + * \param array address of the array (in/out) + * \param pos position to insert new element + * \return pointer to the new operation/element + */ +slang_operation * +slang_operation_insert(GLuint *numElements, slang_operation **array, + GLuint pos) +{ + slang_operation *ops; + + assert(pos <= *numElements); + + ops = (slang_operation *) + _slang_alloc((*numElements + 1) * sizeof(slang_operation)); + if (ops) { + slang_operation *newOp; + newOp = ops + pos; + if (pos > 0) + memcpy(ops, *array, pos * sizeof(slang_operation)); + if (pos < *numElements) + memcpy(newOp + 1, (*array) + pos, + (*numElements - pos) * sizeof(slang_operation)); + + if (!slang_operation_construct(newOp)) { + _slang_free(ops); + *numElements = 0; + *array = NULL; + return NULL; + } + if (*array) + _slang_free(*array); + *array = ops; + (*numElements)++; + return newOp; + } + return NULL; +} + + +/** + * Add/insert new child into given node at given position. + * \return pointer to the new child node + */ +slang_operation * +slang_operation_insert_child(slang_operation *oper, GLuint pos) +{ + slang_operation *newOp; + + newOp = slang_operation_insert(&oper->num_children, + &oper->children, + pos); + if (newOp) { + newOp->locals->outer_scope = oper->locals; + } + + return newOp; +} + + +void +_slang_operation_swap(slang_operation *oper0, slang_operation *oper1) +{ + slang_operation tmp = *oper0; + *oper0 = *oper1; + *oper1 = tmp; +} + + +void +slang_operation_add_children(slang_operation *oper, GLuint num_children) +{ + GLuint i; + assert(oper->num_children == 0); + assert(oper->children == NULL); + oper->num_children = num_children; + oper->children = slang_operation_new(num_children); + for (i = 0; i < num_children; i++) { + oper->children[i].locals = _slang_variable_scope_new(oper->locals); + } +} + diff --git a/src/mesa/slang/slang_compile_operation.h b/src/mesa/slang/slang_compile_operation.h new file mode 100644 index 0000000000..1f15c19896 --- /dev/null +++ b/src/mesa/slang/slang_compile_operation.h @@ -0,0 +1,225 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_COMPILE_OPERATION_H +#define SLANG_COMPILE_OPERATION_H + + +/** + * Types of slang operations. + * These are the types of the AST (abstract syntax tree) nodes. + * [foo] indicates a sub-tree or reference to another type of node + */ +typedef enum slang_operation_type_ +{ + SLANG_OPER_NONE, + SLANG_OPER_BLOCK_NO_NEW_SCOPE, /* "{" sequence "}" */ + SLANG_OPER_BLOCK_NEW_SCOPE, /* "{" sequence "}" */ + SLANG_OPER_VARIABLE_DECL, /* [type] [var] or [var] = [expr] */ + SLANG_OPER_ASM, + SLANG_OPER_BREAK, /* "break" statement */ + SLANG_OPER_CONTINUE, /* "continue" statement */ + SLANG_OPER_DISCARD, /* "discard" (kill fragment) statement */ + SLANG_OPER_RETURN, /* "return" [expr] */ + SLANG_OPER_RETURN_INLINED, /* "return" [expr] from inlined function */ + SLANG_OPER_LABEL, /* a jump target */ + SLANG_OPER_EXPRESSION, /* [expr] */ + SLANG_OPER_IF, /* "if" [0] then [1] else [2] */ + SLANG_OPER_WHILE, /* "while" [cond] [body] */ + SLANG_OPER_DO, /* "do" [body] "while" [cond] */ + SLANG_OPER_FOR, /* "for" [init] [while] [incr] [body] */ + SLANG_OPER_VOID, /* nop */ + SLANG_OPER_LITERAL_BOOL, /* "true" or "false" */ + SLANG_OPER_LITERAL_INT, /* integer literal */ + SLANG_OPER_LITERAL_FLOAT, /* float literal */ + SLANG_OPER_IDENTIFIER, /* var name, func name, etc */ + SLANG_OPER_SEQUENCE, /* [expr] "," [expr] "," etc */ + SLANG_OPER_ASSIGN, /* [var] "=" [expr] */ + SLANG_OPER_ADDASSIGN, /* [var] "+=" [expr] */ + SLANG_OPER_SUBASSIGN, /* [var] "-=" [expr] */ + SLANG_OPER_MULASSIGN, /* [var] "*=" [expr] */ + SLANG_OPER_DIVASSIGN, /* [var] "/=" [expr] */ + /*SLANG_OPER_MODASSIGN, */ + /*SLANG_OPER_LSHASSIGN, */ + /*SLANG_OPER_RSHASSIGN, */ + /*SLANG_OPER_ORASSIGN, */ + /*SLANG_OPER_XORASSIGN, */ + /*SLANG_OPER_ANDASSIGN, */ + SLANG_OPER_SELECT, /* [expr] "?" [expr] ":" [expr] */ + SLANG_OPER_LOGICALOR, /* [expr] "||" [expr] */ + SLANG_OPER_LOGICALXOR, /* [expr] "^^" [expr] */ + SLANG_OPER_LOGICALAND, /* [expr] "&&" [expr] */ + /*SLANG_OPER_BITOR, */ + /*SLANG_OPER_BITXOR, */ + /*SLANG_OPER_BITAND, */ + SLANG_OPER_EQUAL, /* [expr] "==" [expr] */ + SLANG_OPER_NOTEQUAL, /* [expr] "!=" [expr] */ + SLANG_OPER_LESS, /* [expr] "<" [expr] */ + SLANG_OPER_GREATER, /* [expr] ">" [expr] */ + SLANG_OPER_LESSEQUAL, /* [expr] "<=" [expr] */ + SLANG_OPER_GREATEREQUAL, /* [expr] ">=" [expr] */ + /*SLANG_OPER_LSHIFT, */ + /*SLANG_OPER_RSHIFT, */ + SLANG_OPER_ADD, /* [expr] "+" [expr] */ + SLANG_OPER_SUBTRACT, /* [expr] "-" [expr] */ + SLANG_OPER_MULTIPLY, /* [expr] "*" [expr] */ + SLANG_OPER_DIVIDE, /* [expr] "/" [expr] */ + /*SLANG_OPER_MODULUS, */ + SLANG_OPER_PREINCREMENT, /* "++" [var] */ + SLANG_OPER_PREDECREMENT, /* "--" [var] */ + SLANG_OPER_PLUS, /* "-" [expr] */ + SLANG_OPER_MINUS, /* "+" [expr] */ + /*SLANG_OPER_COMPLEMENT, */ + SLANG_OPER_NOT, /* "!" [expr] */ + SLANG_OPER_SUBSCRIPT, /* [expr] "[" [expr] "]" */ + SLANG_OPER_CALL, /* [func name] [param] [param] [...] */ + SLANG_OPER_NON_INLINED_CALL, /* a real function call */ + SLANG_OPER_METHOD, /* method call, such as v.length() */ + SLANG_OPER_FIELD, /* i.e.: ".next" or ".xzy" or ".xxx" etc */ + SLANG_OPER_POSTINCREMENT, /* [var] "++" */ + SLANG_OPER_POSTDECREMENT /* [var] "--" */ +} slang_operation_type; + + +/** + * A slang_operation is basically a compiled instruction (such as assignment, + * a while-loop, a conditional, a multiply, a function call, etc). + * The AST (abstract syntax tree) is built from these nodes. + * NOTE: This structure could have been implemented as a union of simpler + * structs which would correspond to the operation types above. + */ +typedef struct slang_operation_ +{ + slang_operation_type type; + struct slang_operation_ *children; + GLuint num_children; + GLfloat literal[4]; /**< Used for float, int and bool values */ + GLuint literal_size; /**< 1, 2, 3, or 4 */ + slang_atom a_id; /**< type: asm, identifier, call, field */ + slang_atom a_obj; /**< object in a method call */ + slang_variable_scope *locals; /**< local vars for scope */ + struct slang_function_ *fun; /**< If type == SLANG_OPER_CALL */ + struct slang_variable_ *var; /**< If type == slang_oper_identier */ + struct slang_label_ *label; /**< If type == SLANG_OPER_LABEL */ + /** If type==SLANG_OPER_CALL and we're calling an array constructor, + * for which there's no real function, we need to have a flag to + * indicate such. num_children indicates number of elements. + */ + GLboolean array_constructor; +} slang_operation; + + +extern GLboolean +slang_operation_construct(slang_operation *); + +extern void +slang_operation_destruct(slang_operation *); + +extern void +slang_replace_scope(slang_operation *oper, + slang_variable_scope *oldScope, + slang_variable_scope *newScope); + +extern GLboolean +slang_operation_copy(slang_operation *, const slang_operation *); + +extern slang_operation * +slang_operation_new(GLuint count); + +extern void +slang_operation_delete(slang_operation *oper); + +extern void +slang_operation_free_children(slang_operation *oper); + +extern slang_operation * +slang_operation_grow(GLuint *numChildren, slang_operation **children); + +extern slang_operation * +slang_operation_insert(GLuint *numChildren, slang_operation **children, + GLuint pos); + +extern slang_operation * +slang_operation_insert_child(slang_operation *oper, GLuint pos); + +extern void +_slang_operation_swap(slang_operation *oper0, slang_operation *oper1); + + +extern void +slang_operation_add_children(slang_operation *oper, GLuint num_children); + + +/** Return number of children of given node */ +static INLINE GLuint +slang_oper_num_children(const slang_operation *oper) +{ + return oper->num_children; +} + +/** Return child of given operation node */ +static INLINE slang_operation * +slang_oper_child(slang_operation *oper, GLuint child) +{ + assert(child < oper->num_children); + return &oper->children[child]; +} + + +/** Return child of given operation node, const version */ +static INLINE const slang_operation * +slang_oper_child_const(const slang_operation *oper, GLuint child) +{ + assert(child < oper->num_children); + return &oper->children[child]; +} + + +/** Init oper to a boolean literal. */ +static INLINE void +slang_operation_literal_bool(slang_operation *oper, GLboolean value) +{ + oper->type = SLANG_OPER_LITERAL_BOOL; + oper->literal[0] = + oper->literal[1] = + oper->literal[2] = + oper->literal[3] = (float) value; + oper->literal_size = 1; +} + + +/** Init oper to an int literal. */ +static INLINE void +slang_operation_literal_int(slang_operation *oper, GLint value) +{ + oper->type = SLANG_OPER_LITERAL_INT; + oper->literal[0] = + oper->literal[1] = + oper->literal[2] = + oper->literal[3] = (float) value; + oper->literal_size = 1; +} + + +#endif /* SLANG_COMPILE_OPERATION_H */ diff --git a/src/mesa/slang/slang_compile_struct.c b/src/mesa/slang/slang_compile_struct.c new file mode 100644 index 0000000000..e6c38730d7 --- /dev/null +++ b/src/mesa/slang/slang_compile_struct.c @@ -0,0 +1,174 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_compile_struct.c + * slang front-end compiler + * \author Michal Krol + */ + +#include "main/imports.h" +#include "slang_mem.h" +#include "slang_compile.h" + + +GLvoid +_slang_struct_scope_ctr(slang_struct_scope * self) +{ + self->structs = NULL; + self->num_structs = 0; + self->outer_scope = NULL; +} + +void +slang_struct_scope_destruct(slang_struct_scope * scope) +{ + GLuint i; + + for (i = 0; i < scope->num_structs; i++) + slang_struct_destruct(scope->structs + i); + _slang_free(scope->structs); + /* do not free scope->outer_scope */ +} + +int +slang_struct_scope_copy(slang_struct_scope * x, const slang_struct_scope * y) +{ + slang_struct_scope z; + GLuint i; + + _slang_struct_scope_ctr(&z); + z.structs = (slang_struct *) + _slang_alloc(y->num_structs * sizeof(slang_struct)); + if (z.structs == NULL) { + slang_struct_scope_destruct(&z); + return 0; + } + for (z.num_structs = 0; z.num_structs < y->num_structs; z.num_structs++) + if (!slang_struct_construct(&z.structs[z.num_structs])) { + slang_struct_scope_destruct(&z); + return 0; + } + for (i = 0; i < z.num_structs; i++) + if (!slang_struct_copy(&z.structs[i], &y->structs[i])) { + slang_struct_scope_destruct(&z); + return 0; + } + z.outer_scope = y->outer_scope; + slang_struct_scope_destruct(x); + *x = z; + return 1; +} + +slang_struct * +slang_struct_scope_find(slang_struct_scope * stru, slang_atom a_name, + int all_scopes) +{ + GLuint i; + + for (i = 0; i < stru->num_structs; i++) + if (a_name == stru->structs[i].a_name) + return &stru->structs[i]; + if (all_scopes && stru->outer_scope != NULL) + return slang_struct_scope_find(stru->outer_scope, a_name, 1); + return NULL; +} + +/* slang_struct */ + +int +slang_struct_construct(slang_struct * stru) +{ + stru->a_name = SLANG_ATOM_NULL; + stru->fields = (slang_variable_scope *) + _slang_alloc(sizeof(slang_variable_scope)); + if (stru->fields == NULL) + return 0; + _slang_variable_scope_ctr(stru->fields); + + stru->structs = + (slang_struct_scope *) _slang_alloc(sizeof(slang_struct_scope)); + if (stru->structs == NULL) { + slang_variable_scope_destruct(stru->fields); + _slang_free(stru->fields); + return 0; + } + _slang_struct_scope_ctr(stru->structs); + stru->constructor = NULL; + return 1; +} + +void +slang_struct_destruct(slang_struct * stru) +{ + slang_variable_scope_destruct(stru->fields); + _slang_free(stru->fields); + slang_struct_scope_destruct(stru->structs); + _slang_free(stru->structs); +} + +int +slang_struct_copy(slang_struct * x, const slang_struct * y) +{ + slang_struct z; + + if (!slang_struct_construct(&z)) + return 0; + z.a_name = y->a_name; + if (!slang_variable_scope_copy(z.fields, y->fields)) { + slang_struct_destruct(&z); + return 0; + } + if (!slang_struct_scope_copy(z.structs, y->structs)) { + slang_struct_destruct(&z); + return 0; + } + slang_struct_destruct(x); + *x = z; + return 1; +} + +int +slang_struct_equal(const slang_struct * x, const slang_struct * y) +{ + GLuint i; + + if (x->fields->num_variables != y->fields->num_variables) + return 0; + + for (i = 0; i < x->fields->num_variables; i++) { + const slang_variable *varx = x->fields->variables[i]; + const slang_variable *vary = y->fields->variables[i]; + + if (varx->a_name != vary->a_name) + return 0; + if (!slang_type_specifier_equal(&varx->type.specifier, + &vary->type.specifier)) + return 0; + if (varx->type.specifier.type == SLANG_SPEC_ARRAY) + if (varx->array_len != vary->array_len) + return GL_FALSE; + } + return 1; +} diff --git a/src/mesa/slang/slang_compile_struct.h b/src/mesa/slang/slang_compile_struct.h new file mode 100644 index 0000000000..90c5512f4d --- /dev/null +++ b/src/mesa/slang/slang_compile_struct.h @@ -0,0 +1,66 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#if !defined SLANG_COMPILE_STRUCT_H +#define SLANG_COMPILE_STRUCT_H + +#if defined __cplusplus +extern "C" { +#endif + +struct slang_function_; + +typedef struct slang_struct_scope_ +{ + struct slang_struct_ *structs; + GLuint num_structs; + struct slang_struct_scope_ *outer_scope; +} slang_struct_scope; + +extern GLvoid +_slang_struct_scope_ctr (slang_struct_scope *); + +void slang_struct_scope_destruct (slang_struct_scope *); +int slang_struct_scope_copy (slang_struct_scope *, const slang_struct_scope *); +struct slang_struct_ *slang_struct_scope_find (slang_struct_scope *, slang_atom, int); + +typedef struct slang_struct_ +{ + slang_atom a_name; + struct slang_variable_scope_ *fields; + slang_struct_scope *structs; + struct slang_function_ *constructor; +} slang_struct; + +int slang_struct_construct (slang_struct *); +void slang_struct_destruct (slang_struct *); +int slang_struct_copy (slang_struct *, const slang_struct *); +int slang_struct_equal (const slang_struct *, const slang_struct *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/mesa/slang/slang_compile_variable.c b/src/mesa/slang/slang_compile_variable.c new file mode 100644 index 0000000000..23c08a9039 --- /dev/null +++ b/src/mesa/slang/slang_compile_variable.c @@ -0,0 +1,247 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_compile_variable.c + * slang front-end compiler + * \author Michal Krol + */ + +#include "main/imports.h" +#include "slang_compile.h" +#include "slang_mem.h" + + +static slang_variable * +slang_variable_new(void) +{ + slang_variable *v = (slang_variable *) _slang_alloc(sizeof(slang_variable)); + if (v) { + if (!slang_variable_construct(v)) { + _slang_free(v); + v = NULL; + } + } + return v; +} + + +static void +slang_variable_delete(slang_variable * var) +{ + slang_variable_destruct(var); + _slang_free(var); +} + + +/* + * slang_variable_scope + */ + +slang_variable_scope * +_slang_variable_scope_new(slang_variable_scope *parent) +{ + slang_variable_scope *s; + s = (slang_variable_scope *) _slang_alloc(sizeof(slang_variable_scope)); + if (s) + s->outer_scope = parent; + return s; +} + + +GLvoid +_slang_variable_scope_ctr(slang_variable_scope * self) +{ + self->variables = NULL; + self->num_variables = 0; + self->outer_scope = NULL; +} + +void +slang_variable_scope_destruct(slang_variable_scope * scope) +{ + unsigned int i; + + if (!scope) + return; + for (i = 0; i < scope->num_variables; i++) { + if (scope->variables[i]) + slang_variable_delete(scope->variables[i]); + } + _slang_free(scope->variables); + /* do not free scope->outer_scope */ +} + +int +slang_variable_scope_copy(slang_variable_scope * x, + const slang_variable_scope * y) +{ + slang_variable_scope z; + unsigned int i; + + _slang_variable_scope_ctr(&z); + z.variables = (slang_variable **) + _slang_alloc(y->num_variables * sizeof(slang_variable *)); + if (z.variables == NULL) { + slang_variable_scope_destruct(&z); + return 0; + } + for (z.num_variables = 0; z.num_variables < y->num_variables; + z.num_variables++) { + z.variables[z.num_variables] = slang_variable_new(); + if (!z.variables[z.num_variables]) { + slang_variable_scope_destruct(&z); + return 0; + } + } + for (i = 0; i < z.num_variables; i++) { + if (!slang_variable_copy(z.variables[i], y->variables[i])) { + slang_variable_scope_destruct(&z); + return 0; + } + } + z.outer_scope = y->outer_scope; + slang_variable_scope_destruct(x); + *x = z; + return 1; +} + + +/** + * Grow the variable list by one. + * \return pointer to space for the new variable (will be initialized) + */ +slang_variable * +slang_variable_scope_grow(slang_variable_scope *scope) +{ + const int n = scope->num_variables; + scope->variables = (slang_variable **) + _slang_realloc(scope->variables, + n * sizeof(slang_variable *), + (n + 1) * sizeof(slang_variable *)); + if (!scope->variables) + return NULL; + + scope->num_variables++; + + scope->variables[n] = slang_variable_new(); + if (!scope->variables[n]) + return NULL; + + return scope->variables[n]; +} + + + +/* slang_variable */ + +int +slang_variable_construct(slang_variable * var) +{ + if (!slang_fully_specified_type_construct(&var->type)) + return 0; + var->a_name = SLANG_ATOM_NULL; + var->array_len = 0; + var->initializer = NULL; + var->size = 0; + var->isTemp = GL_FALSE; + var->store = NULL; + var->declared = 0; + return 1; +} + + +void +slang_variable_destruct(slang_variable * var) +{ + slang_fully_specified_type_destruct(&var->type); + if (var->initializer != NULL) { + slang_operation_destruct(var->initializer); + _slang_free(var->initializer); + } +#if 0 + if (var->aux) { + free(var->aux); + } +#endif +} + + +int +slang_variable_copy(slang_variable * x, const slang_variable * y) +{ + slang_variable z; + + if (!slang_variable_construct(&z)) + return 0; + if (!slang_fully_specified_type_copy(&z.type, &y->type)) { + slang_variable_destruct(&z); + return 0; + } + z.a_name = y->a_name; + z.array_len = y->array_len; + if (y->initializer != NULL) { + z.initializer + = (slang_operation *) _slang_alloc(sizeof(slang_operation)); + if (z.initializer == NULL) { + slang_variable_destruct(&z); + return 0; + } + if (!slang_operation_construct(z.initializer)) { + _slang_free(z.initializer); + slang_variable_destruct(&z); + return 0; + } + if (!slang_operation_copy(z.initializer, y->initializer)) { + slang_variable_destruct(&z); + return 0; + } + } + z.size = y->size; + slang_variable_destruct(x); + *x = z; + return 1; +} + + +/** + * Search for named variable in given scope. + * \param all if true, search parent scopes too. + */ +slang_variable * +_slang_variable_locate(const slang_variable_scope * scope, + const slang_atom a_name, GLboolean all) +{ + while (scope) { + GLuint i; + for (i = 0; i < scope->num_variables; i++) + if (a_name == scope->variables[i]->a_name) + return scope->variables[i]; + if (all) + scope = scope->outer_scope; + else + scope = NULL; + } + return NULL; +} diff --git a/src/mesa/slang/slang_compile_variable.h b/src/mesa/slang/slang_compile_variable.h new file mode 100644 index 0000000000..5c9d248b35 --- /dev/null +++ b/src/mesa/slang/slang_compile_variable.h @@ -0,0 +1,90 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_COMPILE_VARIABLE_H +#define SLANG_COMPILE_VARIABLE_H + + +struct slang_ir_storage_; + + +/** + * A shading language program variable. + */ +typedef struct slang_variable_ +{ + slang_fully_specified_type type; /**< Variable's data type */ + slang_atom a_name; /**< The variable's name (char *) */ + GLuint array_len; /**< only if type == SLANG_SPEC_ARRAy */ + struct slang_operation_ *initializer; /**< Optional initializer code */ + GLuint size; /**< Variable's size in bytes */ + GLboolean is_global; + GLboolean isTemp; /**< a named temporary (__resultTmp) */ + GLboolean declared; /**< has the var been declared? */ + struct slang_ir_storage_ *store; /**< Storage for this var */ +} slang_variable; + + +/** + * Basically a list of variables, with a pointer to the parent scope. + */ +typedef struct slang_variable_scope_ +{ + slang_variable **variables; /**< Array [num_variables] of ptrs to vars */ + GLuint num_variables; + struct slang_variable_scope_ *outer_scope; +} slang_variable_scope; + + +extern slang_variable_scope * +_slang_variable_scope_new(slang_variable_scope *parent); + +extern GLvoid +_slang_variable_scope_ctr(slang_variable_scope *); + +extern void +slang_variable_scope_destruct(slang_variable_scope *); + +extern int +slang_variable_scope_copy(slang_variable_scope *, + const slang_variable_scope *); + +extern slang_variable * +slang_variable_scope_grow(slang_variable_scope *); + +extern int +slang_variable_construct(slang_variable *); + +extern void +slang_variable_destruct(slang_variable *); + +extern int +slang_variable_copy(slang_variable *, const slang_variable *); + +extern slang_variable * +_slang_variable_locate(const slang_variable_scope *, const slang_atom a_name, + GLboolean all); + + +#endif /* SLANG_COMPILE_VARIABLE_H */ diff --git a/src/mesa/slang/slang_emit.c b/src/mesa/slang/slang_emit.c new file mode 100644 index 0000000000..4d4c611dfe --- /dev/null +++ b/src/mesa/slang/slang_emit.c @@ -0,0 +1,2666 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2008 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_emit.c + * Emit program instructions (PI code) from IR trees. + * \author Brian Paul + */ + +/*** + *** NOTES + *** + *** To emit GPU instructions, we basically just do an in-order traversal + *** of the IR tree. + ***/ + + +#include "main/imports.h" +#include "main/context.h" +#include "shader/program.h" +#include "shader/prog_instruction.h" +#include "shader/prog_parameter.h" +#include "shader/prog_print.h" +#include "slang_builtin.h" +#include "slang_emit.h" +#include "slang_mem.h" + + +#define PEEPHOLE_OPTIMIZATIONS 1 +#define ANNOTATE 0 + + +typedef struct +{ + slang_info_log *log; + slang_var_table *vt; + struct gl_program *prog; + struct gl_program **Subroutines; + GLuint NumSubroutines; + + GLuint MaxInstructions; /**< size of prog->Instructions[] buffer */ + + GLboolean UnresolvedFunctions; + + /* code-gen options */ + GLboolean EmitHighLevelInstructions; + GLboolean EmitCondCodes; + GLboolean EmitComments; + GLboolean EmitBeginEndSub; /* XXX TEMPORARY */ +} slang_emit_info; + + + +static struct gl_program * +new_subroutine(slang_emit_info *emitInfo, GLuint *id) +{ + GET_CURRENT_CONTEXT(ctx); + const GLuint n = emitInfo->NumSubroutines; + + emitInfo->Subroutines = (struct gl_program **) + _mesa_realloc(emitInfo->Subroutines, + n * sizeof(struct gl_program *), + (n + 1) * sizeof(struct gl_program *)); + emitInfo->Subroutines[n] = ctx->Driver.NewProgram(ctx, emitInfo->prog->Target, 0); + emitInfo->Subroutines[n]->Parameters = emitInfo->prog->Parameters; + emitInfo->NumSubroutines++; + *id = n; + return emitInfo->Subroutines[n]; +} + + +/** + * Convert a writemask to a swizzle. Used for testing cond codes because + * we only want to test the cond code component(s) that was set by the + * previous instruction. + */ +static GLuint +writemask_to_swizzle(GLuint writemask) +{ + if (writemask == WRITEMASK_X) + return SWIZZLE_XXXX; + if (writemask == WRITEMASK_Y) + return SWIZZLE_YYYY; + if (writemask == WRITEMASK_Z) + return SWIZZLE_ZZZZ; + if (writemask == WRITEMASK_W) + return SWIZZLE_WWWW; + return SWIZZLE_XYZW; /* shouldn't be hit */ +} + + +/** + * Convert a swizzle mask to a writemask. + * Note that the slang_ir_storage->Swizzle field can represent either a + * swizzle mask or a writemask, depending on how it's used. For example, + * when we parse "direction.yz" alone, we don't know whether .yz is a + * writemask or a swizzle. In this case, we encode ".yz" in store->Swizzle + * as a swizzle mask (.yz?? actually). Later, if direction.yz is used as + * an R-value, we use store->Swizzle as-is. Otherwise, if direction.yz is + * used as an L-value, we convert it to a writemask. + */ +static GLuint +swizzle_to_writemask(GLuint swizzle) +{ + GLuint i, writemask = 0x0; + for (i = 0; i < 4; i++) { + GLuint swz = GET_SWZ(swizzle, i); + if (swz <= SWIZZLE_W) { + writemask |= (1 << swz); + } + } + return writemask; +} + + +/** + * Swizzle a swizzle (function composition). + * That is, return swz2(swz1), or said another way: swz1.szw2 + * Example: swizzle_swizzle(".zwxx", ".xxyw") yields ".zzwx" + */ +GLuint +_slang_swizzle_swizzle(GLuint swz1, GLuint swz2) +{ + GLuint i, swz, s[4]; + for (i = 0; i < 4; i++) { + GLuint c = GET_SWZ(swz2, i); + if (c <= SWIZZLE_W) + s[i] = GET_SWZ(swz1, c); + else + s[i] = c; + } + swz = MAKE_SWIZZLE4(s[0], s[1], s[2], s[3]); + return swz; +} + + +/** + * Return the default swizzle mask for accessing a variable of the + * given size (in floats). If size = 1, comp is used to identify + * which component [0..3] of the register holds the variable. + */ +GLuint +_slang_var_swizzle(GLint size, GLint comp) +{ + switch (size) { + case 1: + return MAKE_SWIZZLE4(comp, SWIZZLE_NIL, SWIZZLE_NIL, SWIZZLE_NIL); + case 2: + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_NIL, SWIZZLE_NIL); + case 3: + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_NIL); + default: + return SWIZZLE_XYZW; + } +} + + + +/** + * Allocate storage for the given node (if it hasn't already been allocated). + * + * Typically this is temporary storage for an intermediate result (such as + * for a multiply or add, etc). + * + * If n->Store does not exist it will be created and will be of the size + * specified by defaultSize. + */ +static GLboolean +alloc_node_storage(slang_emit_info *emitInfo, slang_ir_node *n, + GLint defaultSize) +{ + assert(!n->Var); + if (!n->Store) { + assert(defaultSize > 0); + n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, defaultSize); + if (!n->Store) { + return GL_FALSE; + } + } + + /* now allocate actual register(s). I.e. set n->Store->Index >= 0 */ + if (n->Store->Index < 0) { + if (!_slang_alloc_temp(emitInfo->vt, n->Store)) { + slang_info_log_error(emitInfo->log, + "Ran out of registers, too many temporaries"); + _slang_free(n->Store); + n->Store = NULL; + return GL_FALSE; + } + } + return GL_TRUE; +} + + +/** + * Free temporary storage, if n->Store is, in fact, temp storage. + * Otherwise, no-op. + */ +static void +free_node_storage(slang_var_table *vt, slang_ir_node *n) +{ + if (n->Store->File == PROGRAM_TEMPORARY && + n->Store->Index >= 0 && + n->Opcode != IR_SWIZZLE) { + if (_slang_is_temp(vt, n->Store)) { + _slang_free_temp(vt, n->Store); + n->Store->Index = -1; + n->Store = NULL; /* XXX this may not be needed */ + } + } +} + + +/** + * Helper function to allocate a short-term temporary. + * Free it with _slang_free_temp(). + */ +static GLboolean +alloc_local_temp(slang_emit_info *emitInfo, slang_ir_storage *temp, GLint size) +{ + assert(size >= 1); + assert(size <= 4); + memset(temp, 0, sizeof(*temp)); + temp->Size = size; + temp->File = PROGRAM_TEMPORARY; + temp->Index = -1; + return _slang_alloc_temp(emitInfo->vt, temp); +} + + +/** + * Remove any SWIZZLE_NIL terms from given swizzle mask. + * For a swizzle like .z??? generate .zzzz (replicate single component). + * Else, for .wx?? generate .wxzw (insert default component for the position). + */ +static GLuint +fix_swizzle(GLuint swizzle) +{ + GLuint c0 = GET_SWZ(swizzle, 0), + c1 = GET_SWZ(swizzle, 1), + c2 = GET_SWZ(swizzle, 2), + c3 = GET_SWZ(swizzle, 3); + if (c1 == SWIZZLE_NIL && c2 == SWIZZLE_NIL && c3 == SWIZZLE_NIL) { + /* smear first component across all positions */ + c1 = c2 = c3 = c0; + } + else { + /* insert default swizzle components */ + if (c0 == SWIZZLE_NIL) + c0 = SWIZZLE_X; + if (c1 == SWIZZLE_NIL) + c1 = SWIZZLE_Y; + if (c2 == SWIZZLE_NIL) + c2 = SWIZZLE_Z; + if (c3 == SWIZZLE_NIL) + c3 = SWIZZLE_W; + } + return MAKE_SWIZZLE4(c0, c1, c2, c3); +} + + + +/** + * Convert IR storage to an instruction dst register. + */ +static void +storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st) +{ + const GLboolean relAddr = st->RelAddr; + const GLint size = st->Size; + GLint index = st->Index; + GLuint swizzle = st->Swizzle; + + assert(index >= 0); + /* if this is storage relative to some parent storage, walk up the tree */ + while (st->Parent) { + st = st->Parent; + assert(st->Index >= 0); + index += st->Index; + swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle); + } + + assert(st->File != PROGRAM_UNDEFINED); + dst->File = st->File; + + assert(index >= 0); + dst->Index = index; + + assert(size >= 1); + assert(size <= 4); + + if (swizzle != SWIZZLE_XYZW) { + dst->WriteMask = swizzle_to_writemask(swizzle); + } + else { + switch (size) { + case 1: + dst->WriteMask = WRITEMASK_X << GET_SWZ(st->Swizzle, 0); + break; + case 2: + dst->WriteMask = WRITEMASK_XY; + break; + case 3: + dst->WriteMask = WRITEMASK_XYZ; + break; + case 4: + dst->WriteMask = WRITEMASK_XYZW; + break; + default: + ; /* error would have been caught above */ + } + } + + dst->RelAddr = relAddr; +} + + +/** + * Convert IR storage to an instruction src register. + */ +static void +storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st) +{ + const GLboolean relAddr = st->RelAddr; + GLint index = st->Index; + GLuint swizzle = st->Swizzle; + + /* if this is storage relative to some parent storage, walk up the tree */ + assert(index >= 0); + while (st->Parent) { + st = st->Parent; + if (st->Index < 0) { + /* an error should have been reported already */ + return; + } + assert(st->Index >= 0); + index += st->Index; + swizzle = _slang_swizzle_swizzle(fix_swizzle(st->Swizzle), swizzle); + } + + assert(st->File >= 0); +#if 1 /* XXX temporary */ + if (st->File == PROGRAM_UNDEFINED) { + slang_ir_storage *st0 = (slang_ir_storage *) st; + st0->File = PROGRAM_TEMPORARY; + } +#endif + assert(st->File < PROGRAM_FILE_MAX); + src->File = st->File; + + assert(index >= 0); + src->Index = index; + + swizzle = fix_swizzle(swizzle); + assert(GET_SWZ(swizzle, 0) <= SWIZZLE_W); + assert(GET_SWZ(swizzle, 1) <= SWIZZLE_W); + assert(GET_SWZ(swizzle, 2) <= SWIZZLE_W); + assert(GET_SWZ(swizzle, 3) <= SWIZZLE_W); + src->Swizzle = swizzle; + + src->RelAddr = relAddr; +} + + +/* + * Setup storage pointing to a scalar constant/literal. + */ +static void +constant_to_storage(slang_emit_info *emitInfo, + GLfloat val, + slang_ir_storage *store) +{ + GLuint swizzle; + GLint reg; + GLfloat value[4]; + + value[0] = val; + reg = _mesa_add_unnamed_constant(emitInfo->prog->Parameters, + value, 1, &swizzle); + + memset(store, 0, sizeof(*store)); + store->File = PROGRAM_CONSTANT; + store->Index = reg; + store->Swizzle = swizzle; +} + + +/** + * Add new instruction at end of given program. + * \param prog the program to append instruction onto + * \param opcode opcode for the new instruction + * \return pointer to the new instruction + */ +static struct prog_instruction * +new_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode) +{ + struct gl_program *prog = emitInfo->prog; + struct prog_instruction *inst; + +#if 0 + /* print prev inst */ + if (prog->NumInstructions > 0) { + _mesa_print_instruction(prog->Instructions + prog->NumInstructions - 1); + } +#endif + assert(prog->NumInstructions <= emitInfo->MaxInstructions); + + if (prog->NumInstructions == emitInfo->MaxInstructions) { + /* grow the instruction buffer */ + emitInfo->MaxInstructions += 20; + prog->Instructions = + _mesa_realloc_instructions(prog->Instructions, + prog->NumInstructions, + emitInfo->MaxInstructions); + if (!prog->Instructions) { + return NULL; + } + } + + inst = prog->Instructions + prog->NumInstructions; + prog->NumInstructions++; + _mesa_init_instructions(inst, 1); + inst->Opcode = opcode; + inst->BranchTarget = -1; /* invalid */ + /* + printf("New inst %d: %p %s\n", prog->NumInstructions-1,(void*)inst, + _mesa_opcode_string(inst->Opcode)); + */ + return inst; +} + + +static struct prog_instruction * +emit_arl_load(slang_emit_info *emitInfo, + gl_register_file file, GLint index, GLuint swizzle) +{ + struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ARL); + if (inst) { + inst->SrcReg[0].File = file; + inst->SrcReg[0].Index = index; + inst->SrcReg[0].Swizzle = fix_swizzle(swizzle); + inst->DstReg.File = PROGRAM_ADDRESS; + inst->DstReg.Index = 0; + inst->DstReg.WriteMask = WRITEMASK_X; + } + return inst; +} + + +/** + * Emit a new instruction with given opcode, operands. + * At this point the instruction may have multiple indirect register + * loads/stores. We convert those into ARL loads and address-relative + * operands. See comments inside. + * At some point in the future we could directly emit indirectly addressed + * registers in Mesa GPU instructions. + */ +static struct prog_instruction * +emit_instruction(slang_emit_info *emitInfo, + gl_inst_opcode opcode, + const slang_ir_storage *dst, + const slang_ir_storage *src0, + const slang_ir_storage *src1, + const slang_ir_storage *src2) +{ + struct prog_instruction *inst; + GLuint numIndirect = 0; + const slang_ir_storage *src[3]; + slang_ir_storage newSrc[3], newDst; + GLuint i; + GLboolean isTemp[3]; + + isTemp[0] = isTemp[1] = isTemp[2] = GL_FALSE; + + src[0] = src0; + src[1] = src1; + src[2] = src2; + + /* count up how many operands are indirect loads */ + for (i = 0; i < 3; i++) { + if (src[i] && src[i]->IsIndirect) + numIndirect++; + } + if (dst && dst->IsIndirect) + numIndirect++; + + /* Take special steps for indirect register loads. + * If we had multiple address registers this would be simpler. + * For example, this GLSL code: + * x[i] = y[j] + z[k]; + * would translate into something like: + * ARL ADDR.x, i; + * ARL ADDR.y, j; + * ARL ADDR.z, k; + * ADD TEMP[ADDR.x+5], TEMP[ADDR.y+9], TEMP[ADDR.z+4]; + * But since we currently only have one address register we have to do this: + * ARL ADDR.x, i; + * MOV t1, TEMP[ADDR.x+9]; + * ARL ADDR.x, j; + * MOV t2, TEMP[ADDR.x+4]; + * ARL ADDR.x, k; + * ADD TEMP[ADDR.x+5], t1, t2; + * The code here figures this out... + */ + if (numIndirect > 0) { + for (i = 0; i < 3; i++) { + if (src[i] && src[i]->IsIndirect) { + /* load the ARL register with the indirect register */ + emit_arl_load(emitInfo, + src[i]->IndirectFile, + src[i]->IndirectIndex, + src[i]->IndirectSwizzle); + + if (numIndirect > 1) { + /* Need to load src[i] into a temporary register */ + slang_ir_storage srcRelAddr; + alloc_local_temp(emitInfo, &newSrc[i], src[i]->Size); + isTemp[i] = GL_TRUE; + + /* set RelAddr flag on src register */ + srcRelAddr = *src[i]; + srcRelAddr.RelAddr = GL_TRUE; + srcRelAddr.IsIndirect = GL_FALSE; /* not really needed */ + + /* MOV newSrc, srcRelAddr; */ + inst = emit_instruction(emitInfo, + OPCODE_MOV, + &newSrc[i], + &srcRelAddr, + NULL, + NULL); + if (!inst) { + return NULL; + } + + src[i] = &newSrc[i]; + } + else { + /* just rewrite the src[i] storage to be ARL-relative */ + newSrc[i] = *src[i]; + newSrc[i].RelAddr = GL_TRUE; + newSrc[i].IsIndirect = GL_FALSE; /* not really needed */ + src[i] = &newSrc[i]; + } + } + } + } + + /* Take special steps for indirect dest register write */ + if (dst && dst->IsIndirect) { + /* load the ARL register with the indirect register */ + emit_arl_load(emitInfo, + dst->IndirectFile, + dst->IndirectIndex, + dst->IndirectSwizzle); + newDst = *dst; + newDst.RelAddr = GL_TRUE; + newDst.IsIndirect = GL_FALSE; + dst = &newDst; + } + + /* OK, emit the instruction and its dst, src regs */ + inst = new_instruction(emitInfo, opcode); + if (!inst) + return NULL; + + if (dst) + storage_to_dst_reg(&inst->DstReg, dst); + + for (i = 0; i < 3; i++) { + if (src[i]) + storage_to_src_reg(&inst->SrcReg[i], src[i]); + } + + /* Free any temp registers that we allocated above */ + for (i = 0; i < 3; i++) { + if (isTemp[i]) + _slang_free_temp(emitInfo->vt, &newSrc[i]); + } + + return inst; +} + + + +/** + * Put a comment on the given instruction. + */ +static void +inst_comment(struct prog_instruction *inst, const char *comment) +{ + if (inst) + inst->Comment = _mesa_strdup(comment); +} + + + +/** + * Return pointer to last instruction in program. + */ +static struct prog_instruction * +prev_instruction(slang_emit_info *emitInfo) +{ + struct gl_program *prog = emitInfo->prog; + if (prog->NumInstructions == 0) + return NULL; + else + return prog->Instructions + prog->NumInstructions - 1; +} + + +static struct prog_instruction * +emit(slang_emit_info *emitInfo, slang_ir_node *n); + + +/** + * Return an annotation string for given node's storage. + */ +static char * +storage_annotation(const slang_ir_node *n, const struct gl_program *prog) +{ +#if ANNOTATE + const slang_ir_storage *st = n->Store; + static char s[100] = ""; + + if (!st) + return _mesa_strdup(""); + + switch (st->File) { + case PROGRAM_CONSTANT: + if (st->Index >= 0) { + const GLfloat *val = prog->Parameters->ParameterValues[st->Index]; + if (st->Swizzle == SWIZZLE_NOOP) + _mesa_snprintf(s, sizeof(s), "{%g, %g, %g, %g}", val[0], val[1], val[2], val[3]); + else { + _mesa_snprintf(s, sizeof(s), "%g", val[GET_SWZ(st->Swizzle, 0)]); + } + } + break; + case PROGRAM_TEMPORARY: + if (n->Var) + _mesa_snprintf(s, sizeof(s), "%s", (char *) n->Var->a_name); + else + _mesa_snprintf(s, sizeof(s), "t[%d]", st->Index); + break; + case PROGRAM_STATE_VAR: + case PROGRAM_UNIFORM: + _mesa_snprintf(s, sizeof(s), "%s", prog->Parameters->Parameters[st->Index].Name); + break; + case PROGRAM_VARYING: + _mesa_snprintf(s, sizeof(s), "%s", prog->Varying->Parameters[st->Index].Name); + break; + case PROGRAM_INPUT: + _mesa_snprintf(s, sizeof(s), "input[%d]", st->Index); + break; + case PROGRAM_OUTPUT: + _mesa_snprintf(s, sizeof(s), "output[%d]", st->Index); + break; + default: + s[0] = 0; + } + return _mesa_strdup(s); +#else + return NULL; +#endif +} + + +/** + * Return an annotation string for an instruction. + */ +static char * +instruction_annotation(gl_inst_opcode opcode, char *dstAnnot, + char *srcAnnot0, char *srcAnnot1, char *srcAnnot2) +{ +#if ANNOTATE + const char *operator; + char *s; + int len = 50; + + if (dstAnnot) + len += strlen(dstAnnot); + else + dstAnnot = _mesa_strdup(""); + + if (srcAnnot0) + len += strlen(srcAnnot0); + else + srcAnnot0 = _mesa_strdup(""); + + if (srcAnnot1) + len += strlen(srcAnnot1); + else + srcAnnot1 = _mesa_strdup(""); + + if (srcAnnot2) + len += strlen(srcAnnot2); + else + srcAnnot2 = _mesa_strdup(""); + + switch (opcode) { + case OPCODE_ADD: + operator = "+"; + break; + case OPCODE_SUB: + operator = "-"; + break; + case OPCODE_MUL: + operator = "*"; + break; + case OPCODE_DP2: + operator = "DP2"; + break; + case OPCODE_DP3: + operator = "DP3"; + break; + case OPCODE_DP4: + operator = "DP4"; + break; + case OPCODE_XPD: + operator = "XPD"; + break; + case OPCODE_RSQ: + operator = "RSQ"; + break; + case OPCODE_SGT: + operator = ">"; + break; + default: + operator = ","; + } + + s = (char *) malloc(len); + _mesa_snprintf(s, len, "%s = %s %s %s %s", dstAnnot, + srcAnnot0, operator, srcAnnot1, srcAnnot2); + + free(dstAnnot); + free(srcAnnot0); + free(srcAnnot1); + free(srcAnnot2); + + return s; +#else + return NULL; +#endif +} + + +/** + * Emit an instruction that's just a comment. + */ +static struct prog_instruction * +emit_comment(slang_emit_info *emitInfo, const char *comment) +{ + struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_NOP); + if (inst) { + inst_comment(inst, comment); + } + return inst; +} + + +/** + * Generate code for a simple arithmetic instruction. + * Either 1, 2 or 3 operands. + */ +static struct prog_instruction * +emit_arith(slang_emit_info *emitInfo, slang_ir_node *n) +{ + const slang_ir_info *info = _slang_ir_info(n->Opcode); + struct prog_instruction *inst; + GLuint i; + + assert(info); + assert(info->InstOpcode != OPCODE_NOP); + +#if PEEPHOLE_OPTIMIZATIONS + /* Look for MAD opportunity */ + if (info->NumParams == 2 && + n->Opcode == IR_ADD && n->Children[0]->Opcode == IR_MUL) { + /* found pattern IR_ADD(IR_MUL(A, B), C) */ + emit(emitInfo, n->Children[0]->Children[0]); /* A */ + emit(emitInfo, n->Children[0]->Children[1]); /* B */ + emit(emitInfo, n->Children[1]); /* C */ + if (!alloc_node_storage(emitInfo, n, -1)) { /* dest */ + return NULL; + } + + inst = emit_instruction(emitInfo, + OPCODE_MAD, + n->Store, + n->Children[0]->Children[0]->Store, + n->Children[0]->Children[1]->Store, + n->Children[1]->Store); + + free_node_storage(emitInfo->vt, n->Children[0]->Children[0]); + free_node_storage(emitInfo->vt, n->Children[0]->Children[1]); + free_node_storage(emitInfo->vt, n->Children[1]); + return inst; + } + + if (info->NumParams == 2 && + n->Opcode == IR_ADD && n->Children[1]->Opcode == IR_MUL) { + /* found pattern IR_ADD(A, IR_MUL(B, C)) */ + emit(emitInfo, n->Children[0]); /* A */ + emit(emitInfo, n->Children[1]->Children[0]); /* B */ + emit(emitInfo, n->Children[1]->Children[1]); /* C */ + if (!alloc_node_storage(emitInfo, n, -1)) { /* dest */ + return NULL; + } + + inst = emit_instruction(emitInfo, + OPCODE_MAD, + n->Store, + n->Children[1]->Children[0]->Store, + n->Children[1]->Children[1]->Store, + n->Children[0]->Store); + + free_node_storage(emitInfo->vt, n->Children[1]->Children[0]); + free_node_storage(emitInfo->vt, n->Children[1]->Children[1]); + free_node_storage(emitInfo->vt, n->Children[0]); + return inst; + } +#endif + + /* gen code for children, may involve temp allocation */ + for (i = 0; i < info->NumParams; i++) { + emit(emitInfo, n->Children[i]); + if (!n->Children[i] || !n->Children[i]->Store) { + /* error recovery */ + return NULL; + } + } + + /* result storage */ + if (!alloc_node_storage(emitInfo, n, -1)) { + return NULL; + } + + inst = emit_instruction(emitInfo, + info->InstOpcode, + n->Store, /* dest */ + (info->NumParams > 0 ? n->Children[0]->Store : NULL), + (info->NumParams > 1 ? n->Children[1]->Store : NULL), + (info->NumParams > 2 ? n->Children[2]->Store : NULL) + ); + + /* free temps */ + for (i = 0; i < info->NumParams; i++) + free_node_storage(emitInfo->vt, n->Children[i]); + + return inst; +} + + +/** + * Emit code for == and != operators. These could normally be handled + * by emit_arith() except we need to be able to handle structure comparisons. + */ +static struct prog_instruction * +emit_compare(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst = NULL; + GLint size; + + assert(n->Opcode == IR_EQUAL || n->Opcode == IR_NOTEQUAL); + + /* gen code for children */ + emit(emitInfo, n->Children[0]); + emit(emitInfo, n->Children[1]); + + if (n->Children[0]->Store->Size != n->Children[1]->Store->Size) { + /* XXX this error should have been caught in slang_codegen.c */ + slang_info_log_error(emitInfo->log, "invalid operands to == or !="); + n->Store = NULL; + return NULL; + } + + /* final result is 1 bool */ + if (!alloc_node_storage(emitInfo, n, 1)) + return NULL; + + size = n->Children[0]->Store->Size; + + if (size == 1) { + gl_inst_opcode opcode = n->Opcode == IR_EQUAL ? OPCODE_SEQ : OPCODE_SNE; + inst = emit_instruction(emitInfo, + opcode, + n->Store, /* dest */ + n->Children[0]->Store, + n->Children[1]->Store, + NULL); + } + else if (size <= 4) { + /* compare two vectors. + * Unfortunately, there's no instruction to compare vectors and + * return a scalar result. Do it with some compare and dot product + * instructions... + */ + GLuint swizzle; + gl_inst_opcode dotOp; + slang_ir_storage tempStore; + + if (!alloc_local_temp(emitInfo, &tempStore, 4)) { + n->Store = NULL; + return NULL; + /* out of temps */ + } + + if (size == 4) { + dotOp = OPCODE_DP4; + swizzle = SWIZZLE_XYZW; + } + else if (size == 3) { + dotOp = OPCODE_DP3; + swizzle = SWIZZLE_XYZW; + } + else { + assert(size == 2); + dotOp = OPCODE_DP3; /* XXX use OPCODE_DP2 eventually */ + swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y); + } + + /* Compute inequality (temp = (A != B)) */ + inst = emit_instruction(emitInfo, + OPCODE_SNE, + &tempStore, + n->Children[0]->Store, + n->Children[1]->Store, + NULL); + if (!inst) { + return NULL; + } + inst_comment(inst, "Compare values"); + + /* Compute val = DOT(temp, temp) (reduction) */ + inst = emit_instruction(emitInfo, + dotOp, + n->Store, + &tempStore, + &tempStore, + NULL); + if (!inst) { + return NULL; + } + inst->SrcReg[0].Swizzle = inst->SrcReg[1].Swizzle = swizzle; /*override*/ + inst_comment(inst, "Reduce vec to bool"); + + _slang_free_temp(emitInfo->vt, &tempStore); /* free temp */ + + if (n->Opcode == IR_EQUAL) { + /* compute val = !val.x with SEQ val, val, 0; */ + slang_ir_storage zero; + constant_to_storage(emitInfo, 0.0, &zero); + inst = emit_instruction(emitInfo, + OPCODE_SEQ, + n->Store, /* dest */ + n->Store, + &zero, + NULL); + if (!inst) { + return NULL; + } + inst_comment(inst, "Invert true/false"); + } + } + else { + /* size > 4, struct or array compare. + * XXX this won't work reliably for structs with padding!! + */ + GLint i, num = (n->Children[0]->Store->Size + 3) / 4; + slang_ir_storage accTemp, sneTemp; + + if (!alloc_local_temp(emitInfo, &accTemp, 4)) + return NULL; + + if (!alloc_local_temp(emitInfo, &sneTemp, 4)) + return NULL; + + for (i = 0; i < num; i++) { + slang_ir_storage srcStore0 = *n->Children[0]->Store; + slang_ir_storage srcStore1 = *n->Children[1]->Store; + srcStore0.Index += i; + srcStore1.Index += i; + + if (i == 0) { + /* SNE accTemp, left[i], right[i] */ + inst = emit_instruction(emitInfo, OPCODE_SNE, + &accTemp, /* dest */ + &srcStore0, + &srcStore1, + NULL); + if (!inst) { + return NULL; + } + inst_comment(inst, "Begin struct/array comparison"); + } + else { + /* SNE sneTemp, left[i], right[i] */ + inst = emit_instruction(emitInfo, OPCODE_SNE, + &sneTemp, /* dest */ + &srcStore0, + &srcStore1, + NULL); + if (!inst) { + return NULL; + } + /* ADD accTemp, accTemp, sneTemp; # like logical-OR */ + inst = emit_instruction(emitInfo, OPCODE_ADD, + &accTemp, /* dest */ + &accTemp, + &sneTemp, + NULL); + if (!inst) { + return NULL; + } + } + } + + /* compute accTemp.x || accTemp.y || accTemp.z || accTemp.w with DOT4 */ + inst = emit_instruction(emitInfo, OPCODE_DP4, + n->Store, + &accTemp, + &accTemp, + NULL); + if (!inst) { + return NULL; + } + inst_comment(inst, "End struct/array comparison"); + + if (n->Opcode == IR_EQUAL) { + /* compute tmp.x = !tmp.x via tmp.x = (tmp.x == 0) */ + slang_ir_storage zero; + constant_to_storage(emitInfo, 0.0, &zero); + inst = emit_instruction(emitInfo, OPCODE_SEQ, + n->Store, /* dest */ + n->Store, + &zero, + NULL); + if (!inst) { + return NULL; + } + inst_comment(inst, "Invert true/false"); + } + + _slang_free_temp(emitInfo->vt, &accTemp); + _slang_free_temp(emitInfo->vt, &sneTemp); + } + + /* free temps */ + free_node_storage(emitInfo->vt, n->Children[0]); + free_node_storage(emitInfo->vt, n->Children[1]); + + return inst; +} + + + +/** + * Generate code for an IR_CLAMP instruction. + */ +static struct prog_instruction * +emit_clamp(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + slang_ir_node tmpNode; + + assert(n->Opcode == IR_CLAMP); + /* ch[0] = value + * ch[1] = min limit + * ch[2] = max limit + */ + + inst = emit(emitInfo, n->Children[0]); + + /* If lower limit == 0.0 and upper limit == 1.0, + * set prev instruction's SaturateMode field to SATURATE_ZERO_ONE. + * Else, + * emit OPCODE_MIN, OPCODE_MAX sequence. + */ +#if 0 + /* XXX this isn't quite finished yet */ + if (n->Children[1]->Opcode == IR_FLOAT && + n->Children[1]->Value[0] == 0.0 && + n->Children[1]->Value[1] == 0.0 && + n->Children[1]->Value[2] == 0.0 && + n->Children[1]->Value[3] == 0.0 && + n->Children[2]->Opcode == IR_FLOAT && + n->Children[2]->Value[0] == 1.0 && + n->Children[2]->Value[1] == 1.0 && + n->Children[2]->Value[2] == 1.0 && + n->Children[2]->Value[3] == 1.0) { + if (!inst) { + inst = prev_instruction(prog); + } + if (inst && inst->Opcode != OPCODE_NOP) { + /* and prev instruction's DstReg matches n->Children[0]->Store */ + inst->SaturateMode = SATURATE_ZERO_ONE; + n->Store = n->Children[0]->Store; + return inst; + } + } +#else + (void) inst; +#endif + + if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) + return NULL; + + emit(emitInfo, n->Children[1]); + emit(emitInfo, n->Children[2]); + + /* Some GPUs don't allow reading from output registers. So if the + * dest for this clamp() is an output reg, we can't use that reg for + * the intermediate result. Use a temp register instead. + */ + memset(&tmpNode, 0, sizeof(tmpNode)); + if (!alloc_node_storage(emitInfo, &tmpNode, n->Store->Size)) { + return NULL; + } + + /* tmp = max(ch[0], ch[1]) */ + inst = emit_instruction(emitInfo, OPCODE_MAX, + tmpNode.Store, /* dest */ + n->Children[0]->Store, + n->Children[1]->Store, + NULL); + if (!inst) { + return NULL; + } + + /* n->dest = min(tmp, ch[2]) */ + inst = emit_instruction(emitInfo, OPCODE_MIN, + n->Store, /* dest */ + tmpNode.Store, + n->Children[2]->Store, + NULL); + + free_node_storage(emitInfo->vt, &tmpNode); + + return inst; +} + + +static struct prog_instruction * +emit_negation(slang_emit_info *emitInfo, slang_ir_node *n) +{ + /* Implement as MOV dst, -src; */ + /* XXX we could look at the previous instruction and in some circumstances + * modify it to accomplish the negation. + */ + struct prog_instruction *inst; + + emit(emitInfo, n->Children[0]); + + if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) + return NULL; + + inst = emit_instruction(emitInfo, + OPCODE_MOV, + n->Store, /* dest */ + n->Children[0]->Store, + NULL, + NULL); + if (inst) { + inst->SrcReg[0].Negate = NEGATE_XYZW; + } + return inst; +} + + +static struct prog_instruction * +emit_label(slang_emit_info *emitInfo, const slang_ir_node *n) +{ + assert(n->Label); +#if 0 + /* XXX this fails in loop tail code - investigate someday */ + assert(_slang_label_get_location(n->Label) < 0); + _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, + emitInfo->prog); +#else + if (_slang_label_get_location(n->Label) < 0) + _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, + emitInfo->prog); +#endif + return NULL; +} + + +/** + * Emit code for a function call. + * Note that for each time a function is called, we emit the function's + * body code again because the set of available registers may be different. + */ +static struct prog_instruction * +emit_fcall(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct gl_program *progSave; + struct prog_instruction *inst; + GLuint subroutineId; + GLuint maxInstSave; + + assert(n->Opcode == IR_CALL); + assert(n->Label); + + /* save/push cur program */ + maxInstSave = emitInfo->MaxInstructions; + progSave = emitInfo->prog; + + emitInfo->prog = new_subroutine(emitInfo, &subroutineId); + emitInfo->MaxInstructions = emitInfo->prog->NumInstructions; + + _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, + emitInfo->prog); + + if (emitInfo->EmitBeginEndSub) { + /* BGNSUB isn't a real instruction. + * We require a label (i.e. "foobar:") though, if we're going to + * print the program in the NV format. The BNGSUB instruction is + * really just a NOP to attach the label to. + */ + inst = new_instruction(emitInfo, OPCODE_BGNSUB); + if (!inst) { + return NULL; + } + inst_comment(inst, n->Label->Name); + } + + /* body of function: */ + emit(emitInfo, n->Children[0]); + n->Store = n->Children[0]->Store; + + /* add RET instruction now, if needed */ + inst = prev_instruction(emitInfo); + if (inst && inst->Opcode != OPCODE_RET) { + inst = new_instruction(emitInfo, OPCODE_RET); + if (!inst) { + return NULL; + } + } + + if (emitInfo->EmitBeginEndSub) { + inst = new_instruction(emitInfo, OPCODE_ENDSUB); + if (!inst) { + return NULL; + } + inst_comment(inst, n->Label->Name); + } + + /* pop/restore cur program */ + emitInfo->prog = progSave; + emitInfo->MaxInstructions = maxInstSave; + + /* emit the function call */ + inst = new_instruction(emitInfo, OPCODE_CAL); + if (!inst) { + return NULL; + } + /* The branch target is just the subroutine number (changed later) */ + inst->BranchTarget = subroutineId; + inst_comment(inst, n->Label->Name); + assert(inst->BranchTarget >= 0); + + return inst; +} + + +/** + * Emit code for a 'return' statement. + */ +static struct prog_instruction * +emit_return(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + assert(n); + assert(n->Opcode == IR_RETURN); + assert(n->Label); + inst = new_instruction(emitInfo, OPCODE_RET); + if (inst) { + inst->DstReg.CondMask = COND_TR; /* always return */ + } + return inst; +} + + +static struct prog_instruction * +emit_kill(slang_emit_info *emitInfo) +{ + struct gl_fragment_program *fp; + struct prog_instruction *inst; + /* NV-KILL - discard fragment depending on condition code. + * Note that ARB-KILL depends on sign of vector operand. + */ + inst = new_instruction(emitInfo, OPCODE_KIL_NV); + if (!inst) { + return NULL; + } + inst->DstReg.CondMask = COND_TR; /* always kill */ + + assert(emitInfo->prog->Target == GL_FRAGMENT_PROGRAM_ARB); + fp = (struct gl_fragment_program *) emitInfo->prog; + fp->UsesKill = GL_TRUE; + + return inst; +} + + +static struct prog_instruction * +emit_tex(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + gl_inst_opcode opcode; + GLboolean shadow = GL_FALSE; + + switch (n->Opcode) { + case IR_TEX: + opcode = OPCODE_TEX; + break; + case IR_TEX_SH: + opcode = OPCODE_TEX; + shadow = GL_TRUE; + break; + case IR_TEXB: + opcode = OPCODE_TXB; + break; + case IR_TEXB_SH: + opcode = OPCODE_TXB; + shadow = GL_TRUE; + break; + case IR_TEXP: + opcode = OPCODE_TXP; + break; + case IR_TEXP_SH: + opcode = OPCODE_TXP; + shadow = GL_TRUE; + break; + default: + _mesa_problem(NULL, "Bad IR TEX code"); + return NULL; + } + + if (n->Children[0]->Opcode == IR_ELEMENT) { + /* array is the sampler (a uniform which'll indicate the texture unit) */ + assert(n->Children[0]->Children[0]->Store); + assert(n->Children[0]->Children[0]->Store->File == PROGRAM_SAMPLER); + + emit(emitInfo, n->Children[0]); + + n->Children[0]->Var = n->Children[0]->Children[0]->Var; + } else { + /* this is the sampler (a uniform which'll indicate the texture unit) */ + assert(n->Children[0]->Store); + assert(n->Children[0]->Store->File == PROGRAM_SAMPLER); + } + + /* emit code for the texcoord operand */ + (void) emit(emitInfo, n->Children[1]); + + /* alloc storage for result of texture fetch */ + if (!alloc_node_storage(emitInfo, n, 4)) + return NULL; + + /* emit TEX instruction; Child[1] is the texcoord */ + inst = emit_instruction(emitInfo, + opcode, + n->Store, + n->Children[1]->Store, + NULL, + NULL); + if (!inst) { + return NULL; + } + + inst->TexShadow = shadow; + + /* Store->Index is the uniform/sampler index */ + assert(n->Children[0]->Store->Index >= 0); + inst->TexSrcUnit = n->Children[0]->Store->Index; + inst->TexSrcTarget = n->Children[0]->Store->TexTarget; + + /* mark the sampler as being used */ + _mesa_use_uniform(emitInfo->prog->Parameters, + (char *) n->Children[0]->Var->a_name); + + return inst; +} + + +/** + * Assignment/copy + */ +static struct prog_instruction * +emit_copy(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + + assert(n->Opcode == IR_COPY); + + /* lhs */ + emit(emitInfo, n->Children[0]); + if (!n->Children[0]->Store || n->Children[0]->Store->Index < 0) { + /* an error should have been already recorded */ + return NULL; + } + + /* rhs */ + assert(n->Children[1]); + inst = emit(emitInfo, n->Children[1]); + + if (!n->Children[1]->Store || n->Children[1]->Store->Index < 0) { + if (!emitInfo->log->text && !emitInfo->UnresolvedFunctions) { + /* XXX this error should have been caught in slang_codegen.c */ + slang_info_log_error(emitInfo->log, "invalid assignment"); + } + return NULL; + } + + assert(n->Children[1]->Store->Index >= 0); + + /*assert(n->Children[0]->Store->Size == n->Children[1]->Store->Size);*/ + + n->Store = n->Children[0]->Store; + + if (n->Store->File == PROGRAM_SAMPLER) { + /* no code generated for sampler assignments, + * just copy the sampler index/target at compile time. + */ + n->Store->Index = n->Children[1]->Store->Index; + n->Store->TexTarget = n->Children[1]->Store->TexTarget; + return NULL; + } + +#if PEEPHOLE_OPTIMIZATIONS + if (inst && + (n->Children[1]->Opcode != IR_SWIZZLE) && + _slang_is_temp(emitInfo->vt, n->Children[1]->Store) && + (inst->DstReg.File == n->Children[1]->Store->File) && + (inst->DstReg.Index == n->Children[1]->Store->Index) && + !n->Children[0]->Store->IsIndirect && + n->Children[0]->Store->Size <= 4) { + /* Peephole optimization: + * The Right-Hand-Side has its results in a temporary place. + * Modify the RHS (and the prev instruction) to store its results + * in the destination specified by n->Children[0]. + * Then, this MOVE is a no-op. + * Ex: + * MUL tmp, x, y; + * MOV a, tmp; + * becomes: + * MUL a, x, y; + */ + + /* fixup the previous instruction (which stored the RHS result) */ + assert(n->Children[0]->Store->Index >= 0); + storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store); + return inst; + } + else +#endif + { + if (n->Children[0]->Store->Size > 4) { + /* move matrix/struct etc (block of registers) */ + slang_ir_storage dstStore = *n->Children[0]->Store; + slang_ir_storage srcStore = *n->Children[1]->Store; + GLint size = srcStore.Size; + ASSERT(n->Children[1]->Store->Swizzle == SWIZZLE_NOOP); + dstStore.Size = 4; + srcStore.Size = 4; + while (size >= 4) { + inst = emit_instruction(emitInfo, OPCODE_MOV, + &dstStore, + &srcStore, + NULL, + NULL); + if (!inst) { + return NULL; + } + inst_comment(inst, "IR_COPY block"); + srcStore.Index++; + dstStore.Index++; + size -= 4; + } + } + else { + /* single register move */ + char *srcAnnot, *dstAnnot; + assert(n->Children[0]->Store->Index >= 0); + inst = emit_instruction(emitInfo, OPCODE_MOV, + n->Children[0]->Store, /* dest */ + n->Children[1]->Store, + NULL, + NULL); + if (!inst) { + return NULL; + } + dstAnnot = storage_annotation(n->Children[0], emitInfo->prog); + srcAnnot = storage_annotation(n->Children[1], emitInfo->prog); + inst->Comment = instruction_annotation(inst->Opcode, dstAnnot, + srcAnnot, NULL, NULL); + } + free_node_storage(emitInfo->vt, n->Children[1]); + return inst; + } +} + + +/** + * An IR_COND node wraps a boolean expression which is used by an + * IF or WHILE test. This is where we'll set condition codes, if needed. + */ +static struct prog_instruction * +emit_cond(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + + assert(n->Opcode == IR_COND); + + if (!n->Children[0]) + return NULL; + + /* emit code for the expression */ + inst = emit(emitInfo, n->Children[0]); + + if (!n->Children[0]->Store) { + /* error recovery */ + return NULL; + } + + assert(n->Children[0]->Store); + /*assert(n->Children[0]->Store->Size == 1);*/ + + if (emitInfo->EmitCondCodes) { + if (inst && + n->Children[0]->Store && + inst->DstReg.File == n->Children[0]->Store->File && + inst->DstReg.Index == n->Children[0]->Store->Index) { + /* The previous instruction wrote to the register who's value + * we're testing. Just fix that instruction so that the + * condition codes are computed. + */ + inst->CondUpdate = GL_TRUE; + n->Store = n->Children[0]->Store; + return inst; + } + else { + /* This'll happen for things like "if (i) ..." where no code + * is normally generated for the expression "i". + * Generate a move instruction just to set condition codes. + */ + if (!alloc_node_storage(emitInfo, n, 1)) + return NULL; + inst = emit_instruction(emitInfo, OPCODE_MOV, + n->Store, /* dest */ + n->Children[0]->Store, + NULL, + NULL); + if (!inst) { + return NULL; + } + inst->CondUpdate = GL_TRUE; + inst_comment(inst, "COND expr"); + _slang_free_temp(emitInfo->vt, n->Store); + return inst; + } + } + else { + /* No-op: the boolean result of the expression is in a regular reg */ + n->Store = n->Children[0]->Store; + return inst; + } +} + + +/** + * Logical-NOT + */ +static struct prog_instruction * +emit_not(slang_emit_info *emitInfo, slang_ir_node *n) +{ + static const struct { + gl_inst_opcode op, opNot; + } operators[] = { + { OPCODE_SLT, OPCODE_SGE }, + { OPCODE_SLE, OPCODE_SGT }, + { OPCODE_SGT, OPCODE_SLE }, + { OPCODE_SGE, OPCODE_SLT }, + { OPCODE_SEQ, OPCODE_SNE }, + { OPCODE_SNE, OPCODE_SEQ }, + { 0, 0 } + }; + struct prog_instruction *inst; + slang_ir_storage zero; + GLuint i; + + /* child expr */ + inst = emit(emitInfo, n->Children[0]); + +#if PEEPHOLE_OPTIMIZATIONS + if (inst) { + /* if the prev instruction was a comparison instruction, invert it */ + for (i = 0; operators[i].op; i++) { + if (inst->Opcode == operators[i].op) { + inst->Opcode = operators[i].opNot; + n->Store = n->Children[0]->Store; + return inst; + } + } + } +#endif + + /* else, invert using SEQ (v = v == 0) */ + if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) + return NULL; + + constant_to_storage(emitInfo, 0.0, &zero); + inst = emit_instruction(emitInfo, + OPCODE_SEQ, + n->Store, + n->Children[0]->Store, + &zero, + NULL); + if (!inst) { + return NULL; + } + inst_comment(inst, "NOT"); + + free_node_storage(emitInfo->vt, n->Children[0]); + + return inst; +} + + +static struct prog_instruction * +emit_if(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct gl_program *prog = emitInfo->prog; + GLuint ifInstLoc, elseInstLoc = 0; + GLuint condWritemask = 0; + + /* emit condition expression code */ + { + struct prog_instruction *inst; + inst = emit(emitInfo, n->Children[0]); + if (emitInfo->EmitCondCodes) { + if (!inst) { + /* error recovery */ + return NULL; + } + condWritemask = inst->DstReg.WriteMask; + } + } + + if (!n->Children[0]->Store) + return NULL; + +#if 0 + assert(n->Children[0]->Store->Size == 1); /* a bool! */ +#endif + + ifInstLoc = prog->NumInstructions; + if (emitInfo->EmitHighLevelInstructions) { + if (emitInfo->EmitCondCodes) { + /* IF condcode THEN ... */ + struct prog_instruction *ifInst = new_instruction(emitInfo, OPCODE_IF); + if (!ifInst) { + return NULL; + } + ifInst->DstReg.CondMask = COND_NE; /* if cond is non-zero */ + /* only test the cond code (1 of 4) that was updated by the + * previous instruction. + */ + ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); + } + else { + struct prog_instruction *inst; + + /* IF src[0] THEN ... */ + inst = emit_instruction(emitInfo, OPCODE_IF, + NULL, /* dst */ + n->Children[0]->Store, /* op0 */ + NULL, + NULL); + if (!inst) { + return NULL; + } + } + } + else { + /* conditional jump to else, or endif */ + struct prog_instruction *ifInst = new_instruction(emitInfo, OPCODE_BRA); + if (!ifInst) { + return NULL; + } + ifInst->DstReg.CondMask = COND_EQ; /* BRA if cond is zero */ + inst_comment(ifInst, "if zero"); + ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); + } + + /* if body */ + emit(emitInfo, n->Children[1]); + + if (n->Children[2]) { + /* have else body */ + elseInstLoc = prog->NumInstructions; + if (emitInfo->EmitHighLevelInstructions) { + struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ELSE); + if (!inst) { + return NULL; + } + prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions - 1; + } + else { + /* jump to endif instruction */ + struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_BRA); + if (!inst) { + return NULL; + } + inst_comment(inst, "else"); + inst->DstReg.CondMask = COND_TR; /* always branch */ + prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions; + } + emit(emitInfo, n->Children[2]); + } + else { + /* no else body */ + prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions; + } + + if (emitInfo->EmitHighLevelInstructions) { + struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ENDIF); + if (!inst) { + return NULL; + } + } + + if (elseInstLoc) { + /* point ELSE instruction BranchTarget at ENDIF */ + if (emitInfo->EmitHighLevelInstructions) { + prog->Instructions[elseInstLoc].BranchTarget = prog->NumInstructions - 1; + } + else { + prog->Instructions[elseInstLoc].BranchTarget = prog->NumInstructions; + } + } + return NULL; +} + + +static struct prog_instruction * +emit_loop(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct gl_program *prog = emitInfo->prog; + struct prog_instruction *endInst; + GLuint beginInstLoc, tailInstLoc, endInstLoc; + slang_ir_node *ir; + + /* emit OPCODE_BGNLOOP */ + beginInstLoc = prog->NumInstructions; + if (emitInfo->EmitHighLevelInstructions) { + struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_BGNLOOP); + if (!inst) { + return NULL; + } + } + + /* body */ + emit(emitInfo, n->Children[0]); + + /* tail */ + tailInstLoc = prog->NumInstructions; + if (n->Children[1]) { + if (emitInfo->EmitComments) + emit_comment(emitInfo, "Loop tail code:"); + emit(emitInfo, n->Children[1]); + } + + endInstLoc = prog->NumInstructions; + if (emitInfo->EmitHighLevelInstructions) { + /* emit OPCODE_ENDLOOP */ + endInst = new_instruction(emitInfo, OPCODE_ENDLOOP); + if (!endInst) { + return NULL; + } + } + else { + /* emit unconditional BRA-nch */ + endInst = new_instruction(emitInfo, OPCODE_BRA); + if (!endInst) { + return NULL; + } + endInst->DstReg.CondMask = COND_TR; /* always true */ + } + /* ENDLOOP's BranchTarget points to the BGNLOOP inst */ + endInst->BranchTarget = beginInstLoc; + + if (emitInfo->EmitHighLevelInstructions) { + /* BGNLOOP's BranchTarget points to the ENDLOOP inst */ + prog->Instructions[beginInstLoc].BranchTarget = prog->NumInstructions -1; + } + + /* Done emitting loop code. Now walk over the loop's linked list of + * BREAK and CONT nodes, filling in their BranchTarget fields (which + * will point to the corresponding ENDLOOP instruction. + */ + for (ir = n->List; ir; ir = ir->List) { + struct prog_instruction *inst = prog->Instructions + ir->InstLocation; + assert(inst->BranchTarget < 0); + if (ir->Opcode == IR_BREAK || + ir->Opcode == IR_BREAK_IF_TRUE) { + assert(inst->Opcode == OPCODE_BRK || + inst->Opcode == OPCODE_BRA); + /* go to instruction at end of loop */ + if (emitInfo->EmitHighLevelInstructions) { + inst->BranchTarget = endInstLoc; + } + else { + inst->BranchTarget = endInstLoc + 1; + } + } + else { + assert(ir->Opcode == IR_CONT || + ir->Opcode == IR_CONT_IF_TRUE); + assert(inst->Opcode == OPCODE_CONT || + inst->Opcode == OPCODE_BRA); + /* go to instruction at tail of loop */ + inst->BranchTarget = endInstLoc; + } + } + return NULL; +} + + +/** + * Unconditional "continue" or "break" statement. + * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted. + */ +static struct prog_instruction * +emit_cont_break(slang_emit_info *emitInfo, slang_ir_node *n) +{ + gl_inst_opcode opcode; + struct prog_instruction *inst; + + if (n->Opcode == IR_CONT) { + /* we need to execute the loop's tail code before doing CONT */ + assert(n->Parent); + assert(n->Parent->Opcode == IR_LOOP); + if (n->Parent->Children[1]) { + /* emit tail code */ + if (emitInfo->EmitComments) { + emit_comment(emitInfo, "continue - tail code:"); + } + emit(emitInfo, n->Parent->Children[1]); + } + } + + /* opcode selection */ + if (emitInfo->EmitHighLevelInstructions) { + opcode = (n->Opcode == IR_CONT) ? OPCODE_CONT : OPCODE_BRK; + } + else { + opcode = OPCODE_BRA; + } + n->InstLocation = emitInfo->prog->NumInstructions; + inst = new_instruction(emitInfo, opcode); + if (inst) { + inst->DstReg.CondMask = COND_TR; /* always true */ + } + return inst; +} + + +/** + * Conditional "continue" or "break" statement. + * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted. + */ +static struct prog_instruction * +emit_cont_break_if_true(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + + assert(n->Opcode == IR_CONT_IF_TRUE || + n->Opcode == IR_BREAK_IF_TRUE); + + /* evaluate condition expr, setting cond codes */ + inst = emit(emitInfo, n->Children[0]); + if (emitInfo->EmitCondCodes) { + assert(inst); + inst->CondUpdate = GL_TRUE; + } + + n->InstLocation = emitInfo->prog->NumInstructions; + + /* opcode selection */ + if (emitInfo->EmitHighLevelInstructions) { + const gl_inst_opcode opcode + = (n->Opcode == IR_CONT_IF_TRUE) ? OPCODE_CONT : OPCODE_BRK; + if (emitInfo->EmitCondCodes) { + /* Get the writemask from the previous instruction which set + * the condcodes. Use that writemask as the CondSwizzle. + */ + const GLuint condWritemask = inst->DstReg.WriteMask; + inst = new_instruction(emitInfo, opcode); + if (inst) { + inst->DstReg.CondMask = COND_NE; + inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); + } + return inst; + } + else { + /* IF reg + * BRK/CONT; + * ENDIF + */ + GLint ifInstLoc; + ifInstLoc = emitInfo->prog->NumInstructions; + inst = emit_instruction(emitInfo, OPCODE_IF, + NULL, /* dest */ + n->Children[0]->Store, + NULL, + NULL); + if (!inst) { + return NULL; + } + n->InstLocation = emitInfo->prog->NumInstructions; + + inst = new_instruction(emitInfo, opcode); + if (!inst) { + return NULL; + } + inst = new_instruction(emitInfo, OPCODE_ENDIF); + if (!inst) { + return NULL; + } + + emitInfo->prog->Instructions[ifInstLoc].BranchTarget + = emitInfo->prog->NumInstructions - 1; + return inst; + } + } + else { + const GLuint condWritemask = inst->DstReg.WriteMask; + assert(emitInfo->EmitCondCodes); + inst = new_instruction(emitInfo, OPCODE_BRA); + if (inst) { + inst->DstReg.CondMask = COND_NE; + inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); + } + return inst; + } +} + + +/** + * Return the size of a swizzle mask given that some swizzle components + * may be NIL/undefined. For example: + * swizzle_size(".zzxx") = 4 + * swizzle_size(".xy??") = 2 + * swizzle_size(".w???") = 1 + */ +static GLuint +swizzle_size(GLuint swizzle) +{ + GLuint i; + for (i = 0; i < 4; i++) { + if (GET_SWZ(swizzle, i) == SWIZZLE_NIL) + return i; + } + return 4; +} + + +static struct prog_instruction * +emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + + inst = emit(emitInfo, n->Children[0]); + + if (!n->Store->Parent) { + /* this covers a case such as "(b ? p : q).x" */ + n->Store->Parent = n->Children[0]->Store; + assert(n->Store->Parent); + } + + { + const GLuint swizzle = n->Store->Swizzle; + /* new storage is parent storage with updated Swizzle + Size fields */ + _slang_copy_ir_storage(n->Store, n->Store->Parent); + /* Apply this node's swizzle to parent's storage */ + n->Store->Swizzle = _slang_swizzle_swizzle(n->Store->Swizzle, swizzle); + /* Update size */ + n->Store->Size = swizzle_size(n->Store->Swizzle); + } + + assert(!n->Store->Parent); + assert(n->Store->Index >= 0); + + return inst; +} + + +/** + * Dereference array element: element == array[index] + * This basically involves emitting code for computing the array index + * and updating the node/element's storage info. + */ +static struct prog_instruction * +emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n) +{ + slang_ir_storage *arrayStore, *indexStore; + const int elemSize = n->Store->Size; /* number of floats */ + const GLint elemSizeVec = (elemSize + 3) / 4; /* number of vec4 */ + struct prog_instruction *inst; + + assert(n->Opcode == IR_ELEMENT); + assert(elemSize > 0); + + /* special case for built-in state variables, like light state */ + { + slang_ir_storage *root = n->Store; + assert(!root->Parent); + while (root->Parent) + root = root->Parent; + + if (root->File == PROGRAM_STATE_VAR) { + GLboolean direct; + GLint index = + _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct); + if (index < 0) { + /* error */ + return NULL; + } + if (direct) { + n->Store->Index = index; + return NULL; /* all done */ + } + } + } + + /* do codegen for array itself */ + emit(emitInfo, n->Children[0]); + arrayStore = n->Children[0]->Store; + + /* The initial array element storage is the array's storage, + * then modified below. + */ + _slang_copy_ir_storage(n->Store, arrayStore); + + + if (n->Children[1]->Opcode == IR_FLOAT) { + /* Constant array index */ + const GLint element = (GLint) n->Children[1]->Value[0]; + + /* this element's storage is the array's storage, plus constant offset */ + n->Store->Index += elemSizeVec * element; + } + else { + /* Variable array index */ + + /* do codegen for array index expression */ + emit(emitInfo, n->Children[1]); + indexStore = n->Children[1]->Store; + + if (indexStore->IsIndirect) { + /* need to put the array index into a temporary since we can't + * directly support a[b[i]] constructs. + */ + + + /*indexStore = tempstore();*/ + } + + + if (elemSize > 4) { + /* need to multiply array index by array element size */ + struct prog_instruction *inst; + slang_ir_storage *indexTemp; + slang_ir_storage elemSizeStore; + + /* allocate 1 float indexTemp */ + indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1); + _slang_alloc_temp(emitInfo->vt, indexTemp); + + /* allocate a constant containing the element size */ + constant_to_storage(emitInfo, (float) elemSizeVec, &elemSizeStore); + + /* multiply array index by element size */ + inst = emit_instruction(emitInfo, + OPCODE_MUL, + indexTemp, /* dest */ + indexStore, /* the index */ + &elemSizeStore, + NULL); + if (!inst) { + return NULL; + } + + indexStore = indexTemp; + } + + if (arrayStore->IsIndirect) { + /* ex: in a[i][j], a[i] (the arrayStore) is indirect */ + /* Need to add indexStore to arrayStore->Indirect store */ + slang_ir_storage indirectArray; + slang_ir_storage *indexTemp; + + _slang_init_ir_storage(&indirectArray, + arrayStore->IndirectFile, + arrayStore->IndirectIndex, + 1, + arrayStore->IndirectSwizzle); + + /* allocate 1 float indexTemp */ + indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1); + _slang_alloc_temp(emitInfo->vt, indexTemp); + + inst = emit_instruction(emitInfo, + OPCODE_ADD, + indexTemp, /* dest */ + indexStore, /* the index */ + &indirectArray, /* indirect array base */ + NULL); + if (!inst) { + return NULL; + } + + indexStore = indexTemp; + } + + /* update the array element storage info */ + n->Store->IsIndirect = GL_TRUE; + n->Store->IndirectFile = indexStore->File; + n->Store->IndirectIndex = indexStore->Index; + n->Store->IndirectSwizzle = indexStore->Swizzle; + } + + n->Store->Size = elemSize; + n->Store->Swizzle = _slang_var_swizzle(elemSize, 0); + + return NULL; /* no instruction */ +} + + +/** + * Resolve storage for accessing a structure field. + */ +static struct prog_instruction * +emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n) +{ + slang_ir_storage *root = n->Store; + GLint fieldOffset, fieldSize; + + assert(n->Opcode == IR_FIELD); + + assert(!root->Parent); + while (root->Parent) + root = root->Parent; + + /* If this is the field of a state var, allocate constant/uniform + * storage for it now if we haven't already. + * Note that we allocate storage (uniform/constant slots) for state + * variables here rather than at declaration time so we only allocate + * space for the ones that we actually use! + */ + if (root->File == PROGRAM_STATE_VAR) { + GLboolean direct; + GLint index = _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct); + if (index < 0) { + slang_info_log_error(emitInfo->log, "Error parsing state variable"); + return NULL; + } + if (direct) { + root->Index = index; + return NULL; /* all done */ + } + } + + /* do codegen for struct */ + emit(emitInfo, n->Children[0]); + assert(n->Children[0]->Store->Index >= 0); + + + fieldOffset = n->Store->Index; + fieldSize = n->Store->Size; + + _slang_copy_ir_storage(n->Store, n->Children[0]->Store); + + n->Store->Index = n->Children[0]->Store->Index + fieldOffset / 4; + n->Store->Size = fieldSize; + + switch (fieldSize) { + case 1: + { + GLint swz = fieldOffset % 4; + n->Store->Swizzle = MAKE_SWIZZLE4(swz, swz, swz, swz); + } + break; + case 2: + n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, + SWIZZLE_NIL, SWIZZLE_NIL); + break; + case 3: + n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, + SWIZZLE_Z, SWIZZLE_NIL); + break; + default: + n->Store->Swizzle = SWIZZLE_XYZW; + } + + assert(n->Store->Index >= 0); + + return NULL; /* no instruction */ +} + + +/** + * Emit code for a variable declaration. + * This usually doesn't result in any code generation, but just + * memory allocation. + */ +static struct prog_instruction * +emit_var_decl(slang_emit_info *emitInfo, slang_ir_node *n) +{ + assert(n->Store); + assert(n->Store->File != PROGRAM_UNDEFINED); + assert(n->Store->Size > 0); + /*assert(n->Store->Index < 0);*/ + + if (!n->Var || n->Var->isTemp) { + /* a nameless/temporary variable, will be freed after first use */ + /*NEW*/ + if (n->Store->Index < 0 && !_slang_alloc_temp(emitInfo->vt, n->Store)) { + slang_info_log_error(emitInfo->log, + "Ran out of registers, too many temporaries"); + return NULL; + } + } + else { + /* a regular variable */ + _slang_add_variable(emitInfo->vt, n->Var); + if (!_slang_alloc_var(emitInfo->vt, n->Store)) { + slang_info_log_error(emitInfo->log, + "Ran out of registers, too many variables"); + return NULL; + } + /* + printf("IR_VAR_DECL %s %d store %p\n", + (char*) n->Var->a_name, n->Store->Index, (void*) n->Store); + */ + assert(n->Var->store == n->Store); + } + if (emitInfo->EmitComments) { + /* emit NOP with comment describing the variable's storage location */ + char s[1000]; + _mesa_snprintf(s, sizeof(s), "TEMP[%d]%s = variable %s (size %d)", + n->Store->Index, + _mesa_swizzle_string(n->Store->Swizzle, 0, GL_FALSE), + (n->Var ? (char *) n->Var->a_name : "anonymous"), + n->Store->Size); + emit_comment(emitInfo, s); + } + return NULL; +} + + +/** + * Emit code for a reference to a variable. + * Actually, no code is generated but we may do some memory allocation. + * In particular, state vars (uniforms) are allocated on an as-needed basis. + */ +static struct prog_instruction * +emit_var_ref(slang_emit_info *emitInfo, slang_ir_node *n) +{ + assert(n->Store); + assert(n->Store->File != PROGRAM_UNDEFINED); + + if (n->Store->File == PROGRAM_STATE_VAR && n->Store->Index < 0) { + GLboolean direct; + GLint index = _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct); + if (index < 0) { + /* error */ + char s[100]; + /* XXX isn't this really an out of memory/resources error? */ + _mesa_snprintf(s, sizeof(s), "Undefined variable '%s'", + (char *) n->Var->a_name); + slang_info_log_error(emitInfo->log, s); + return NULL; + } + + n->Store->Index = index; + } + else if (n->Store->File == PROGRAM_UNIFORM || + n->Store->File == PROGRAM_SAMPLER) { + /* mark var as used */ + _mesa_use_uniform(emitInfo->prog->Parameters, (char *) n->Var->a_name); + } + else if (n->Store->File == PROGRAM_INPUT) { + assert(n->Store->Index >= 0); + emitInfo->prog->InputsRead |= (1 << n->Store->Index); + } + + if (n->Store->Index < 0) { + /* probably ran out of registers */ + return NULL; + } + assert(n->Store->Size > 0); + + return NULL; +} + + +static struct prog_instruction * +emit(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + if (!n) + return NULL; + + if (emitInfo->log->error_flag) { + return NULL; + } + + if (n->Comment) { + inst = new_instruction(emitInfo, OPCODE_NOP); + if (inst) { + inst->Comment = _mesa_strdup(n->Comment); + } + inst = NULL; + } + + switch (n->Opcode) { + case IR_SEQ: + /* sequence of two sub-trees */ + assert(n->Children[0]); + assert(n->Children[1]); + emit(emitInfo, n->Children[0]); + if (emitInfo->log->error_flag) + return NULL; + inst = emit(emitInfo, n->Children[1]); +#if 0 + assert(!n->Store); +#endif + n->Store = n->Children[1]->Store; + return inst; + + case IR_SCOPE: + /* new variable scope */ + _slang_push_var_table(emitInfo->vt); + inst = emit(emitInfo, n->Children[0]); + _slang_pop_var_table(emitInfo->vt); + return inst; + + case IR_VAR_DECL: + /* Variable declaration - allocate a register for it */ + inst = emit_var_decl(emitInfo, n); + return inst; + + case IR_VAR: + /* Reference to a variable + * Storage should have already been resolved/allocated. + */ + return emit_var_ref(emitInfo, n); + + case IR_ELEMENT: + return emit_array_element(emitInfo, n); + case IR_FIELD: + return emit_struct_field(emitInfo, n); + case IR_SWIZZLE: + return emit_swizzle(emitInfo, n); + + /* Simple arithmetic */ + /* unary */ + case IR_MOVE: + case IR_RSQ: + case IR_RCP: + case IR_FLOOR: + case IR_FRAC: + case IR_F_TO_I: + case IR_I_TO_F: + case IR_ABS: + case IR_SIN: + case IR_COS: + case IR_DDX: + case IR_DDY: + case IR_EXP: + case IR_EXP2: + case IR_LOG2: + case IR_NOISE1: + case IR_NOISE2: + case IR_NOISE3: + case IR_NOISE4: + case IR_NRM4: + case IR_NRM3: + /* binary */ + case IR_ADD: + case IR_SUB: + case IR_MUL: + case IR_DOT4: + case IR_DOT3: + case IR_DOT2: + case IR_CROSS: + case IR_MIN: + case IR_MAX: + case IR_SEQUAL: + case IR_SNEQUAL: + case IR_SGE: + case IR_SGT: + case IR_SLE: + case IR_SLT: + case IR_POW: + /* trinary operators */ + case IR_LRP: + case IR_CMP: + return emit_arith(emitInfo, n); + + case IR_EQUAL: + case IR_NOTEQUAL: + return emit_compare(emitInfo, n); + + case IR_CLAMP: + return emit_clamp(emitInfo, n); + case IR_TEX: + case IR_TEXB: + case IR_TEXP: + case IR_TEX_SH: + case IR_TEXB_SH: + case IR_TEXP_SH: + return emit_tex(emitInfo, n); + case IR_NEG: + return emit_negation(emitInfo, n); + case IR_FLOAT: + /* find storage location for this float constant */ + n->Store->Index = _mesa_add_unnamed_constant(emitInfo->prog->Parameters, + n->Value, + n->Store->Size, + &n->Store->Swizzle); + if (n->Store->Index < 0) { + slang_info_log_error(emitInfo->log, "Ran out of space for constants"); + return NULL; + } + return NULL; + + case IR_COPY: + return emit_copy(emitInfo, n); + + case IR_COND: + return emit_cond(emitInfo, n); + + case IR_NOT: + return emit_not(emitInfo, n); + + case IR_LABEL: + return emit_label(emitInfo, n); + + case IR_KILL: + return emit_kill(emitInfo); + + case IR_CALL: + /* new variable scope for subroutines/function calls */ + _slang_push_var_table(emitInfo->vt); + inst = emit_fcall(emitInfo, n); + _slang_pop_var_table(emitInfo->vt); + return inst; + + case IR_IF: + return emit_if(emitInfo, n); + + case IR_LOOP: + return emit_loop(emitInfo, n); + case IR_BREAK_IF_TRUE: + case IR_CONT_IF_TRUE: + return emit_cont_break_if_true(emitInfo, n); + case IR_BREAK: + /* fall-through */ + case IR_CONT: + return emit_cont_break(emitInfo, n); + + case IR_BEGIN_SUB: + return new_instruction(emitInfo, OPCODE_BGNSUB); + case IR_END_SUB: + return new_instruction(emitInfo, OPCODE_ENDSUB); + case IR_RETURN: + return emit_return(emitInfo, n); + + case IR_NOP: + return NULL; + + default: + _mesa_problem(NULL, "Unexpected IR opcode in emit()\n"); + } + return NULL; +} + + +/** + * After code generation, any subroutines will be in separate program + * objects. This function appends all the subroutines onto the main + * program and resolves the linking of all the branch/call instructions. + * XXX this logic should really be part of the linking process... + */ +static void +_slang_resolve_subroutines(slang_emit_info *emitInfo) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_program *mainP = emitInfo->prog; + GLuint *subroutineLoc, i, total; + + subroutineLoc + = (GLuint *) malloc(emitInfo->NumSubroutines * sizeof(GLuint)); + + /* total number of instructions */ + total = mainP->NumInstructions; + for (i = 0; i < emitInfo->NumSubroutines; i++) { + subroutineLoc[i] = total; + total += emitInfo->Subroutines[i]->NumInstructions; + } + + /* adjust BranchTargets within the functions */ + for (i = 0; i < emitInfo->NumSubroutines; i++) { + struct gl_program *sub = emitInfo->Subroutines[i]; + GLuint j; + for (j = 0; j < sub->NumInstructions; j++) { + struct prog_instruction *inst = sub->Instructions + j; + if (inst->Opcode != OPCODE_CAL && inst->BranchTarget >= 0) { + inst->BranchTarget += subroutineLoc[i]; + } + } + } + + /* append subroutines' instructions after main's instructions */ + mainP->Instructions = _mesa_realloc_instructions(mainP->Instructions, + mainP->NumInstructions, + total); + mainP->NumInstructions = total; + for (i = 0; i < emitInfo->NumSubroutines; i++) { + struct gl_program *sub = emitInfo->Subroutines[i]; + _mesa_copy_instructions(mainP->Instructions + subroutineLoc[i], + sub->Instructions, + sub->NumInstructions); + /* delete subroutine code */ + sub->Parameters = NULL; /* prevent double-free */ + _mesa_reference_program(ctx, &emitInfo->Subroutines[i], NULL); + } + + /* free subroutine list */ + if (emitInfo->Subroutines) { + free(emitInfo->Subroutines); + emitInfo->Subroutines = NULL; + } + emitInfo->NumSubroutines = 0; + + /* Examine CAL instructions. + * At this point, the BranchTarget field of the CAL instruction is + * the number/id of the subroutine to call (an index into the + * emitInfo->Subroutines list). + * Translate that into an actual instruction location now. + */ + for (i = 0; i < mainP->NumInstructions; i++) { + struct prog_instruction *inst = mainP->Instructions + i; + if (inst->Opcode == OPCODE_CAL) { + const GLuint f = inst->BranchTarget; + inst->BranchTarget = subroutineLoc[f]; + } + } + + free(subroutineLoc); +} + + + +/** + * Convert the IR tree into GPU instructions. + * \param n root of IR tree + * \param vt variable table + * \param prog program to put GPU instructions into + * \param pragmas controls codegen options + * \param withEnd if true, emit END opcode at end + * \param log log for emitting errors/warnings/info + */ +GLboolean +_slang_emit_code(slang_ir_node *n, slang_var_table *vt, + struct gl_program *prog, + const struct gl_sl_pragmas *pragmas, + GLboolean withEnd, + slang_info_log *log) +{ + GET_CURRENT_CONTEXT(ctx); + GLboolean success; + slang_emit_info emitInfo; + GLuint maxUniforms; + + emitInfo.log = log; + emitInfo.vt = vt; + emitInfo.prog = prog; + emitInfo.Subroutines = NULL; + emitInfo.NumSubroutines = 0; + emitInfo.MaxInstructions = prog->NumInstructions; + + emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions; + emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes; + emitInfo.EmitComments = ctx->Shader.EmitComments || pragmas->Debug; + emitInfo.EmitBeginEndSub = GL_TRUE; + + if (!emitInfo.EmitCondCodes) { + emitInfo.EmitHighLevelInstructions = GL_TRUE; + } + + /* Check uniform/constant limits */ + if (prog->Target == GL_FRAGMENT_PROGRAM_ARB) { + maxUniforms = ctx->Const.FragmentProgram.MaxUniformComponents / 4; + } + else { + assert(prog->Target == GL_VERTEX_PROGRAM_ARB); + maxUniforms = ctx->Const.VertexProgram.MaxUniformComponents / 4; + } + if (prog->Parameters->NumParameters > maxUniforms) { + slang_info_log_error(log, "Constant/uniform register limit exceeded " + "(max=%u vec4)", maxUniforms); + + return GL_FALSE; + } + + (void) emit(&emitInfo, n); + + /* finish up by adding the END opcode to program */ + if (withEnd) { + struct prog_instruction *inst; + inst = new_instruction(&emitInfo, OPCODE_END); + if (!inst) { + return GL_FALSE; + } + } + + _slang_resolve_subroutines(&emitInfo); + + success = GL_TRUE; + +#if 0 + printf("*********** End emit code (%u inst):\n", prog->NumInstructions); + _mesa_print_program(prog); + _mesa_print_program_parameters(ctx,prog); +#endif + + return success; +} diff --git a/src/mesa/slang/slang_emit.h b/src/mesa/slang/slang_emit.h new file mode 100644 index 0000000000..ab4c202d67 --- /dev/null +++ b/src/mesa/slang/slang_emit.h @@ -0,0 +1,51 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_EMIT_H +#define SLANG_EMIT_H + + +#include "main/imports.h" +#include "slang_compile.h" +#include "slang_ir.h" +#include "main/mtypes.h" + + +extern GLuint +_slang_swizzle_swizzle(GLuint swz1, GLuint swz2); + + +extern GLuint +_slang_var_swizzle(GLint size, GLint comp); + + +extern GLboolean +_slang_emit_code(slang_ir_node *n, slang_var_table *vartable, + struct gl_program *prog, + const struct gl_sl_pragmas *pragmas, + GLboolean withEnd, + slang_info_log *log); + + +#endif /* SLANG_EMIT_H */ diff --git a/src/mesa/slang/slang_ir.c b/src/mesa/slang/slang_ir.c new file mode 100644 index 0000000000..c223004b22 --- /dev/null +++ b/src/mesa/slang/slang_ir.c @@ -0,0 +1,498 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include "main/imports.h" +#include "main/context.h" +#include "slang_ir.h" +#include "slang_mem.h" +#include "shader/prog_instruction.h" +#include "shader/prog_print.h" + + +static const slang_ir_info IrInfo[] = { + /* binary ops */ + { IR_ADD, "IR_ADD", OPCODE_ADD, 4, 2 }, + { IR_SUB, "IR_SUB", OPCODE_SUB, 4, 2 }, + { IR_MUL, "IR_MUL", OPCODE_MUL, 4, 2 }, + { IR_DIV, "IR_DIV", OPCODE_NOP, 0, 2 }, /* XXX broke */ + { IR_DOT4, "IR_DOT4", OPCODE_DP4, 1, 2 }, + { IR_DOT3, "IR_DOT3", OPCODE_DP3, 1, 2 }, + { IR_DOT2, "IR_DOT2", OPCODE_DP2, 1, 2 }, + { IR_NRM4, "IR_NRM4", OPCODE_NRM4, 1, 1 }, + { IR_NRM3, "IR_NRM3", OPCODE_NRM3, 1, 1 }, + { IR_CROSS, "IR_CROSS", OPCODE_XPD, 3, 2 }, + { IR_LRP, "IR_LRP", OPCODE_LRP, 4, 3 }, + { IR_MIN, "IR_MIN", OPCODE_MIN, 4, 2 }, + { IR_MAX, "IR_MAX", OPCODE_MAX, 4, 2 }, + { IR_CLAMP, "IR_CLAMP", OPCODE_NOP, 4, 3 }, /* special case: emit_clamp() */ + { IR_SEQUAL, "IR_SEQUAL", OPCODE_SEQ, 4, 2 }, + { IR_SNEQUAL, "IR_SNEQUAL", OPCODE_SNE, 4, 2 }, + { IR_SGE, "IR_SGE", OPCODE_SGE, 4, 2 }, + { IR_SGT, "IR_SGT", OPCODE_SGT, 4, 2 }, + { IR_SLE, "IR_SLE", OPCODE_SLE, 4, 2 }, + { IR_SLT, "IR_SLT", OPCODE_SLT, 4, 2 }, + { IR_POW, "IR_POW", OPCODE_POW, 1, 2 }, + { IR_EQUAL, "IR_EQUAL", OPCODE_NOP, 1, 2 }, + { IR_NOTEQUAL, "IR_NOTEQUAL", OPCODE_NOP, 1, 2 }, + + /* unary ops */ + { IR_MOVE, "IR_MOVE", OPCODE_MOV, 4, 1 }, + { IR_I_TO_F, "IR_I_TO_F", OPCODE_MOV, 4, 1 }, /* int[4] to float[4] */ + { IR_F_TO_I, "IR_F_TO_I", OPCODE_TRUNC, 4, 1 }, + { IR_EXP, "IR_EXP", OPCODE_EXP, 1, 1 }, + { IR_EXP2, "IR_EXP2", OPCODE_EX2, 1, 1 }, + { IR_LOG2, "IR_LOG2", OPCODE_LG2, 1, 1 }, + { IR_RSQ, "IR_RSQ", OPCODE_RSQ, 1, 1 }, + { IR_RCP, "IR_RCP", OPCODE_RCP, 1, 1 }, + { IR_FLOOR, "IR_FLOOR", OPCODE_FLR, 4, 1 }, + { IR_FRAC, "IR_FRAC", OPCODE_FRC, 4, 1 }, + { IR_ABS, "IR_ABS", OPCODE_ABS, 4, 1 }, + { IR_NEG, "IR_NEG", OPCODE_NOP, 4, 1 }, /* special case: emit_negation() */ + { IR_DDX, "IR_DDX", OPCODE_DDX, 4, 1 }, + { IR_DDY, "IR_DDY", OPCODE_DDY, 4, 1 }, + { IR_SIN, "IR_SIN", OPCODE_SIN, 1, 1 }, + { IR_COS, "IR_COS", OPCODE_COS, 1, 1 }, + { IR_NOISE1, "IR_NOISE1", OPCODE_NOISE1, 1, 1 }, + { IR_NOISE2, "IR_NOISE2", OPCODE_NOISE2, 1, 1 }, + { IR_NOISE3, "IR_NOISE3", OPCODE_NOISE3, 1, 1 }, + { IR_NOISE4, "IR_NOISE4", OPCODE_NOISE4, 1, 1 }, + + /* other */ + { IR_CMP, "IR_CMP", OPCODE_CMP, 4, 3 }, /* compare/select */ + { IR_SEQ, "IR_SEQ", OPCODE_NOP, 0, 0 }, + { IR_SCOPE, "IR_SCOPE", OPCODE_NOP, 0, 0 }, + { IR_LABEL, "IR_LABEL", OPCODE_NOP, 0, 0 }, + { IR_IF, "IR_IF", OPCODE_NOP, 0, 0 }, + { IR_KILL, "IR_KILL", OPCODE_NOP, 0, 0 }, + { IR_COND, "IR_COND", OPCODE_NOP, 0, 0 }, + { IR_CALL, "IR_CALL", OPCODE_NOP, 0, 0 }, + { IR_COPY, "IR_COPY", OPCODE_NOP, 0, 1 }, + { IR_NOT, "IR_NOT", OPCODE_NOP, 1, 1 }, + { IR_VAR, "IR_VAR", OPCODE_NOP, 0, 0 }, + { IR_VAR_DECL, "IR_VAR_DECL", OPCODE_NOP, 0, 0 }, + { IR_TEX, "IR_TEX", OPCODE_TEX, 4, 1 }, + { IR_TEXB, "IR_TEXB", OPCODE_TXB, 4, 1 }, + { IR_TEXP, "IR_TEXP", OPCODE_TXP, 4, 1 }, + { IR_TEX_SH, "IR_TEX_SH", OPCODE_TEX, 4, 1 }, + { IR_TEXB_SH, "IR_TEXB_SH", OPCODE_TXB, 4, 1 }, + { IR_TEXP_SH, "IR_TEXP_SH", OPCODE_TXP, 4, 1 }, + { IR_FLOAT, "IR_FLOAT", OPCODE_NOP, 0, 0 }, /* float literal */ + { IR_FIELD, "IR_FIELD", OPCODE_NOP, 0, 0 }, + { IR_ELEMENT, "IR_ELEMENT", OPCODE_NOP, 0, 0 }, + { IR_SWIZZLE, "IR_SWIZZLE", OPCODE_NOP, 0, 0 }, + { IR_NOP, "IR_NOP", OPCODE_NOP, 0, 0 }, + { 0, NULL, 0, 0, 0 } +}; + + +const slang_ir_info * +_slang_ir_info(slang_ir_opcode opcode) +{ + GLuint i; + for (i = 0; IrInfo[i].IrName; i++) { + if (IrInfo[i].IrOpcode == opcode) { + return IrInfo + i; + } + } + return NULL; +} + + +void +_slang_init_ir_storage(slang_ir_storage *st, + gl_register_file file, GLint index, GLint size, + GLuint swizzle) +{ + st->File = file; + st->Index = index; + st->Size = size; + st->Swizzle = swizzle; + st->Parent = NULL; + st->IsIndirect = GL_FALSE; +} + + +/** + * Return a new slang_ir_storage object. + */ +slang_ir_storage * +_slang_new_ir_storage(gl_register_file file, GLint index, GLint size) +{ + slang_ir_storage *st; + st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); + if (st) { + st->File = file; + st->Index = index; + st->Size = size; + st->Swizzle = SWIZZLE_NOOP; + st->Parent = NULL; + st->IsIndirect = GL_FALSE; + } + return st; +} + + +/** + * Return a new slang_ir_storage object. + */ +slang_ir_storage * +_slang_new_ir_storage_swz(gl_register_file file, GLint index, GLint size, + GLuint swizzle) +{ + slang_ir_storage *st; + st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); + if (st) { + st->File = file; + st->Index = index; + st->Size = size; + st->Swizzle = swizzle; + st->Parent = NULL; + st->IsIndirect = GL_FALSE; + } + return st; +} + + +/** + * Return a new slang_ir_storage object. + */ +slang_ir_storage * +_slang_new_ir_storage_relative(GLint index, GLint size, + slang_ir_storage *parent) +{ + slang_ir_storage *st; + st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); + if (st) { + st->File = PROGRAM_UNDEFINED; + st->Index = index; + st->Size = size; + st->Swizzle = SWIZZLE_NOOP; + st->Parent = parent; + st->IsIndirect = GL_FALSE; + } + return st; +} + + +slang_ir_storage * +_slang_new_ir_storage_indirect(gl_register_file file, + GLint index, + GLint size, + gl_register_file indirectFile, + GLint indirectIndex, + GLuint indirectSwizzle) +{ + slang_ir_storage *st; + st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); + if (st) { + st->File = file; + st->Index = index; + st->Size = size; + st->Swizzle = SWIZZLE_NOOP; + st->IsIndirect = GL_TRUE; + st->IndirectFile = indirectFile; + st->IndirectIndex = indirectIndex; + st->IndirectSwizzle = indirectSwizzle; + } + return st; +} + + +/** + * Allocate IR storage for a texture sampler. + * \param sampNum the sampler number/index + * \param texTarget one of TEXTURE_x_INDEX values + * \param size number of samplers (in case of sampler array) + */ +slang_ir_storage * +_slang_new_ir_storage_sampler(GLint sampNum, GLuint texTarget, GLint size) +{ + slang_ir_storage *st; + assert(texTarget < NUM_TEXTURE_TARGETS); + st = _slang_new_ir_storage(PROGRAM_SAMPLER, sampNum, size); + if (st) { + st->TexTarget = texTarget; + } + return st; +} + + + +/* XXX temporary function */ +void +_slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src) +{ + *dst = *src; + dst->Parent = NULL; +} + + + +static const char * +_slang_ir_name(slang_ir_opcode opcode) +{ + return _slang_ir_info(opcode)->IrName; +} + + + +#if 0 /* no longer needed with mempool */ +/** + * Since many IR nodes might point to the same IR storage info, we need + * to be careful when deleting things. + * Before deleting an IR tree, traverse it and do refcounting on the + * IR storage nodes. Use the refcount info during delete to free things + * properly. + */ +static void +_slang_refcount_storage(slang_ir_node *n) +{ + GLuint i; + if (!n) + return; + if (n->Store) + n->Store->RefCount++; + for (i = 0; i < 3; i++) + _slang_refcount_storage(n->Children[i]); +} +#endif + + +static void +_slang_free_ir(slang_ir_node *n) +{ + GLuint i; + if (!n) + return; + +#if 0 + if (n->Store) { + n->Store->RefCount--; + if (n->Store->RefCount == 0) { + _slang_free(n->Store); + n->Store = NULL; + } + } +#endif + + for (i = 0; i < 3; i++) + _slang_free_ir(n->Children[i]); + /* Do not free n->List since it's a child elsewhere */ + _slang_free(n); +} + + +/** + * Recursively free an IR tree. + */ +void +_slang_free_ir_tree(slang_ir_node *n) +{ +#if 0 + _slang_refcount_storage(n); +#endif + _slang_free_ir(n); +} + + +static const char * +storage_string(const slang_ir_storage *st) +{ + static const char *files[] = { + "TEMP", + "LOCAL_PARAM", + "ENV_PARAM", + "STATE", + "INPUT", + "OUTPUT", + "NAMED_PARAM", + "CONSTANT", + "UNIFORM", + "VARYING", + "WRITE_ONLY", + "ADDRESS", + "SAMPLER", + "UNDEFINED" + }; + static char s[100]; + assert(Elements(files) == PROGRAM_FILE_MAX); +#if 0 + if (st->Size == 1) + _mesa_snprintf(s, "%s[%d]", files[st->File], st->Index); + else + _mesa_snprintf(s, "%s[%d..%d]", files[st->File], st->Index, + st->Index + st->Size - 1); +#endif + assert(st->File < (GLint) (sizeof(files) / sizeof(files[0]))); + _mesa_snprintf(s, sizeof(s), "%s[%d]", files[st->File], st->Index); + return s; +} + + +static void +spaces(int n) +{ + while (n-- > 0) { + printf(" "); + } +} + + +void +_slang_print_ir_tree(const slang_ir_node *n, int indent) +{ +#define IND 0 + + if (!n) + return; +#if !IND + if (n->Opcode != IR_SEQ) +#else + printf("%3d:", indent); +#endif + spaces(indent); + + switch (n->Opcode) { + case IR_SEQ: +#if IND + printf("SEQ at %p\n", (void*) n); +#endif + assert(n->Children[0]); + assert(n->Children[1]); + _slang_print_ir_tree(n->Children[0], indent + IND); + _slang_print_ir_tree(n->Children[1], indent + IND); + break; + case IR_SCOPE: + printf("NEW SCOPE\n"); + assert(!n->Children[1]); + _slang_print_ir_tree(n->Children[0], indent + 3); + break; + case IR_COPY: + printf("COPY\n"); + _slang_print_ir_tree(n->Children[0], indent+3); + _slang_print_ir_tree(n->Children[1], indent+3); + break; + case IR_LABEL: + printf("LABEL: %s\n", n->Label->Name); + break; + case IR_COND: + printf("COND\n"); + _slang_print_ir_tree(n->Children[0], indent + 3); + break; + + case IR_IF: + printf("IF \n"); + _slang_print_ir_tree(n->Children[0], indent+3); + spaces(indent); + printf("THEN\n"); + _slang_print_ir_tree(n->Children[1], indent+3); + if (n->Children[2]) { + spaces(indent); + printf("ELSE\n"); + _slang_print_ir_tree(n->Children[2], indent+3); + } + spaces(indent); + printf("ENDIF\n"); + break; + + case IR_BEGIN_SUB: + printf("BEGIN_SUB\n"); + break; + case IR_END_SUB: + printf("END_SUB\n"); + break; + case IR_RETURN: + printf("RETURN\n"); + break; + case IR_CALL: + printf("CALL %s\n", n->Label->Name); + break; + + case IR_LOOP: + printf("LOOP\n"); + _slang_print_ir_tree(n->Children[0], indent+3); + if (n->Children[1]) { + spaces(indent); + printf("TAIL:\n"); + _slang_print_ir_tree(n->Children[1], indent+3); + } + spaces(indent); + printf("ENDLOOP\n"); + break; + case IR_CONT: + printf("CONT\n"); + break; + case IR_BREAK: + printf("BREAK\n"); + break; + case IR_BREAK_IF_TRUE: + printf("BREAK_IF_TRUE\n"); + _slang_print_ir_tree(n->Children[0], indent+3); + break; + case IR_CONT_IF_TRUE: + printf("CONT_IF_TRUE\n"); + _slang_print_ir_tree(n->Children[0], indent+3); + break; + + case IR_VAR: + printf("VAR %s%s at %s store %p\n", + (n->Var ? (char *) n->Var->a_name : "TEMP"), + _mesa_swizzle_string(n->Store->Swizzle, 0, 0), + storage_string(n->Store), (void*) n->Store); + break; + case IR_VAR_DECL: + printf("VAR_DECL %s (%p) at %s store %p\n", + (n->Var ? (char *) n->Var->a_name : "TEMP"), + (void*) n->Var, storage_string(n->Store), + (void*) n->Store); + break; + case IR_FIELD: + printf("FIELD %s of\n", n->Field); + _slang_print_ir_tree(n->Children[0], indent+3); + break; + case IR_FLOAT: + printf("FLOAT %g %g %g %g\n", + n->Value[0], n->Value[1], n->Value[2], n->Value[3]); + break; + case IR_I_TO_F: + printf("INT_TO_FLOAT\n"); + _slang_print_ir_tree(n->Children[0], indent+3); + break; + case IR_F_TO_I: + printf("FLOAT_TO_INT\n"); + _slang_print_ir_tree(n->Children[0], indent+3); + break; + case IR_SWIZZLE: + printf("SWIZZLE %s of (store %p) \n", + _mesa_swizzle_string(n->Store->Swizzle, 0, 0), (void*) n->Store); + _slang_print_ir_tree(n->Children[0], indent + 3); + break; + default: + printf("%s (%p, %p) (store %p)\n", _slang_ir_name(n->Opcode), + (void*) n->Children[0], (void*) n->Children[1], (void*) n->Store); + _slang_print_ir_tree(n->Children[0], indent+3); + _slang_print_ir_tree(n->Children[1], indent+3); + } +} diff --git a/src/mesa/slang/slang_ir.h b/src/mesa/slang/slang_ir.h new file mode 100644 index 0000000000..166b4e8043 --- /dev/null +++ b/src/mesa/slang/slang_ir.h @@ -0,0 +1,280 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_ir.h + * Mesa GLSL Intermediate Representation tree types and constants. + * \author Brian Paul + */ + + +#ifndef SLANG_IR_H +#define SLANG_IR_H + + +#include "main/imports.h" +#include "slang_compile.h" +#include "slang_label.h" +#include "main/mtypes.h" + + +/** + * Intermediate Representation opcodes + */ +typedef enum +{ + IR_NOP = 0, + IR_SEQ, /* sequence (eval left, then right) */ + IR_SCOPE, /* new variable scope (one child) */ + + IR_LABEL, /* target of a jump or cjump */ + + IR_COND, /* conditional expression/predicate */ + + IR_IF, /* high-level IF/then/else */ + /* Children[0] = conditional expression */ + /* Children[1] = if-true part */ + /* Children[2] = if-else part, or NULL */ + + IR_BEGIN_SUB, /* begin subroutine */ + IR_END_SUB, /* end subroutine */ + IR_RETURN, /* return from subroutine */ + IR_CALL, /* call subroutine */ + + IR_LOOP, /* high-level loop-begin / loop-end */ + /* Children[0] = loop body */ + /* Children[1] = loop tail code, or NULL */ + + IR_CONT, /* continue loop */ + /* n->Parent = ptr to parent IR_LOOP Node */ + IR_BREAK, /* break loop */ + + IR_BREAK_IF_TRUE, /**< Children[0] = the condition expression */ + IR_CONT_IF_TRUE, + + IR_COPY, /**< assignment/copy */ + IR_MOVE, /**< assembly MOV instruction */ + + /* vector ops: */ + IR_ADD, /**< assembly ADD instruction */ + IR_SUB, + IR_MUL, + IR_DIV, + IR_DOT4, + IR_DOT3, + IR_DOT2, + IR_NRM4, + IR_NRM3, + IR_CROSS, /* vec3 cross product */ + IR_LRP, + IR_CLAMP, + IR_MIN, + IR_MAX, + IR_CMP, /* = (op0 < 0) ? op1 : op2 */ + IR_SEQUAL, /* Set if args are equal (vector) */ + IR_SNEQUAL, /* Set if args are not equal (vector) */ + IR_SGE, /* Set if greater or equal (vector) */ + IR_SGT, /* Set if greater than (vector) */ + IR_SLE, /* Set if less or equal (vector) */ + IR_SLT, /* Set if less than (vector) */ + IR_POW, /* x^y */ + IR_EXP, /* e^x */ + IR_EXP2, /* 2^x */ + IR_LOG2, /* log base 2 */ + IR_RSQ, /* 1/sqrt() */ + IR_RCP, /* reciprocol */ + IR_FLOOR, + IR_FRAC, + IR_ABS, /* absolute value */ + IR_NEG, /* negate */ + IR_DDX, /* derivative w.r.t. X */ + IR_DDY, /* derivative w.r.t. Y */ + IR_SIN, /* sine */ + IR_COS, /* cosine */ + IR_NOISE1, /* noise(x) */ + IR_NOISE2, /* noise(x, y) */ + IR_NOISE3, /* noise(x, y, z) */ + IR_NOISE4, /* noise(x, y, z, w) */ + + IR_EQUAL, /* boolean equality */ + IR_NOTEQUAL,/* boolean inequality */ + IR_NOT, /* boolean not */ + + IR_VAR, /* variable reference */ + IR_VAR_DECL,/* var declaration */ + + IR_ELEMENT, /* array element */ + IR_FIELD, /* struct field */ + IR_SWIZZLE, /* swizzled storage access */ + + IR_TEX, /* texture lookup */ + IR_TEXB, /* texture lookup with LOD bias */ + IR_TEXP, /* texture lookup with projection */ + + IR_TEX_SH, /* texture lookup, shadow compare */ + IR_TEXB_SH, /* texture lookup with LOD bias, shadow compare */ + IR_TEXP_SH, /* texture lookup with projection, shadow compare */ + + IR_FLOAT, + IR_I_TO_F, /* int[4] to float[4] conversion */ + IR_F_TO_I, /* float[4] to int[4] conversion */ + + IR_KILL /* fragment kill/discard */ +} slang_ir_opcode; + + +/** + * Describes where data/variables are stored in the various register files. + * + * In the simple case, the File, Index and Size fields indicate where + * a variable is stored. For example, a vec3 variable may be stored + * as (File=PROGRAM_TEMPORARY, Index=6, Size=3). Or, File[Index]. + * Or, a program input like color may be stored as + * (File=PROGRAM_INPUT,Index=3,Size=4); + * + * For single-float values, the Swizzle field indicates which component + * of the vector contains the float. + * + * If IsIndirect is set, the storage is accessed through an indirect + * register lookup. The value in question will be located at: + * File[Index + IndirectFile[IndirectIndex]] + * + * This is primary used for indexing arrays. For example, consider this + * GLSL code: + * uniform int i; + * float a[10]; + * float x = a[i]; + * + * here, storage for a[i] would be described by (File=PROGRAM_TEMPORAY, + * Index=aPos, IndirectFile=PROGRAM_UNIFORM, IndirectIndex=iPos), which + * would mean TEMP[aPos + UNIFORM[iPos]] + */ +struct slang_ir_storage_ +{ + gl_register_file File; /**< PROGRAM_TEMPORARY, PROGRAM_INPUT, etc */ + GLint Index; /**< -1 means unallocated */ + GLint Size; /**< number of floats or ints */ + GLuint Swizzle; /**< Swizzle AND writemask info */ + GLint RefCount; /**< Used during IR tree delete */ + + GLboolean RelAddr; /* we'll remove this eventually */ + + GLboolean IsIndirect; + gl_register_file IndirectFile; + GLint IndirectIndex; + GLuint IndirectSwizzle; + GLuint TexTarget; /**< If File==PROGRAM_SAMPLER, one of TEXTURE_x_INDEX */ + + /** If Parent is non-null, Index is relative to parent. + * The other fields are ignored. + */ + struct slang_ir_storage_ *Parent; +}; + +typedef struct slang_ir_storage_ slang_ir_storage; + + +/** + * Intermediate Representation (IR) tree node + * Basically a binary tree, but IR_LRP and IR_CLAMP have three children. + */ +typedef struct slang_ir_node_ +{ + slang_ir_opcode Opcode; + struct slang_ir_node_ *Children[3]; + slang_ir_storage *Store; /**< location of result of this operation */ + GLint InstLocation; /**< Location of instruction emitted for this node */ + + /** special fields depending on Opcode: */ + const char *Field; /**< If Opcode == IR_FIELD */ + GLfloat Value[4]; /**< If Opcode == IR_FLOAT */ + slang_variable *Var; /**< If Opcode == IR_VAR or IR_VAR_DECL */ + struct slang_ir_node_ *List; /**< For various linked lists */ + struct slang_ir_node_ *Parent; /**< Pointer to logical parent (ie. loop) */ + slang_label *Label; /**< Used for branches */ + const char *Comment; /**< If Opcode == IR_COMMENT */ +} slang_ir_node; + + + +/** + * Assembly and IR info + */ +typedef struct +{ + slang_ir_opcode IrOpcode; + const char *IrName; + gl_inst_opcode InstOpcode; + GLuint ResultSize, NumParams; +} slang_ir_info; + + + +extern const slang_ir_info * +_slang_ir_info(slang_ir_opcode opcode); + + +extern void +_slang_init_ir_storage(slang_ir_storage *st, + gl_register_file file, GLint index, GLint size, + GLuint swizzle); + +extern slang_ir_storage * +_slang_new_ir_storage(gl_register_file file, GLint index, GLint size); + + +extern slang_ir_storage * +_slang_new_ir_storage_swz(gl_register_file file, GLint index, GLint size, + GLuint swizzle); + +extern slang_ir_storage * +_slang_new_ir_storage_relative(GLint index, GLint size, + slang_ir_storage *parent); + + +extern slang_ir_storage * +_slang_new_ir_storage_indirect(gl_register_file file, + GLint index, + GLint size, + gl_register_file indirectFile, + GLint indirectIndex, + GLuint indirectSwizzle); + +extern slang_ir_storage * +_slang_new_ir_storage_sampler(GLint sampNum, GLuint texTarget, GLint size); + + +extern void +_slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src); + + +extern void +_slang_free_ir_tree(slang_ir_node *n); + + +extern void +_slang_print_ir_tree(const slang_ir_node *n, int indent); + + +#endif /* SLANG_IR_H */ diff --git a/src/mesa/slang/slang_label.c b/src/mesa/slang/slang_label.c new file mode 100644 index 0000000000..8e3a8ebc1a --- /dev/null +++ b/src/mesa/slang/slang_label.c @@ -0,0 +1,104 @@ + + +/** + * Functions for managing instruction labels. + * Basically, this is used to manage the problem of forward branches where + * we have a branch instruciton but don't know the target address yet. + */ + + +#include "slang_label.h" +#include "slang_mem.h" + + + +slang_label * +_slang_label_new(const char *name) +{ + slang_label *l = (slang_label *) _slang_alloc(sizeof(slang_label)); + if (l) { + l->Name = _slang_strdup(name); + l->Location = -1; + } + return l; +} + +/** + * As above, but suffix the name with a unique number. + */ +slang_label * +_slang_label_new_unique(const char *name) +{ + static int id = 1; + slang_label *l = (slang_label *) _slang_alloc(sizeof(slang_label)); + if (l) { + l->Name = (char *) _slang_alloc(strlen(name) + 10); + if (!l->Name) { + free(l); + return NULL; + } + _mesa_snprintf(l->Name, strlen(name) + 10, "%s_%d", name, id); + id++; + l->Location = -1; + } + return l; +} + +void +_slang_label_delete(slang_label *l) +{ + if (l->Name) { + _slang_free(l->Name); + l->Name = NULL; + } + if (l->References) { + _slang_free(l->References); + l->References = NULL; + } + _slang_free(l); +} + + +void +_slang_label_add_reference(slang_label *l, GLuint inst) +{ + const GLuint oldSize = l->NumReferences * sizeof(GLuint); + assert(l->Location < 0); + l->References = _slang_realloc(l->References, + oldSize, oldSize + sizeof(GLuint)); + if (l->References) { + l->References[l->NumReferences] = inst; + l->NumReferences++; + } +} + + +GLint +_slang_label_get_location(const slang_label *l) +{ + return l->Location; +} + + +void +_slang_label_set_location(slang_label *l, GLint location, + struct gl_program *prog) +{ + GLuint i; + + assert(l->Location < 0); + assert(location >= 0); + + l->Location = location; + + /* for the instructions that were waiting to learn the label's location: */ + for (i = 0; i < l->NumReferences; i++) { + const GLuint j = l->References[i]; + prog->Instructions[j].BranchTarget = location; + } + + if (l->References) { + _slang_free(l->References); + l->References = NULL; + } +} diff --git a/src/mesa/slang/slang_label.h b/src/mesa/slang/slang_label.h new file mode 100644 index 0000000000..87068ae7a7 --- /dev/null +++ b/src/mesa/slang/slang_label.h @@ -0,0 +1,45 @@ +#ifndef SLANG_LABEL_H +#define SLANG_LABEL_H 1 + +#include "main/imports.h" +#include "main/mtypes.h" +#include "shader/prog_instruction.h" + + +struct slang_label_ +{ + char *Name; + GLint Location; + /** + * List of instruction references (numbered starting at zero) which need + * their BranchTarget field filled in with the location eventually + * assigned to the label. + */ + GLuint NumReferences; + GLuint *References; /** Array [NumReferences] */ +}; + +typedef struct slang_label_ slang_label; + + +extern slang_label * +_slang_label_new(const char *name); + +extern slang_label * +_slang_label_new_unique(const char *name); + +extern void +_slang_label_delete(slang_label *l); + +extern void +_slang_label_add_reference(slang_label *l, GLuint inst); + +extern GLint +_slang_label_get_location(const slang_label *l); + +extern void +_slang_label_set_location(slang_label *l, GLint location, + struct gl_program *prog); + + +#endif /* SLANG_LABEL_H */ diff --git a/src/mesa/slang/slang_link.c b/src/mesa/slang/slang_link.c new file mode 100644 index 0000000000..56d42ca0a7 --- /dev/null +++ b/src/mesa/slang/slang_link.c @@ -0,0 +1,1124 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_link.c + * GLSL linker + * \author Brian Paul + */ + +#include "main/imports.h" +#include "main/context.h" +#include "main/macros.h" +#include "main/shaderapi.h" +#include "main/shaderobj.h" +#include "main/uniforms.h" +#include "shader/program.h" +#include "shader/prog_instruction.h" +#include "shader/prog_parameter.h" +#include "shader/prog_print.h" +#include "shader/prog_statevars.h" +#include "shader/prog_uniform.h" +#include "slang_builtin.h" +#include "slang_link.h" + + +/** cast wrapper */ +static struct gl_vertex_program * +vertex_program(struct gl_program *prog) +{ + assert(prog->Target == GL_VERTEX_PROGRAM_ARB); + return (struct gl_vertex_program *) prog; +} + + +/** cast wrapper */ +static struct gl_fragment_program * +fragment_program(struct gl_program *prog) +{ + assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB); + return (struct gl_fragment_program *) prog; +} + + +/** + * Record a linking error. + */ +static void +link_error(struct gl_shader_program *shProg, const char *msg) +{ + if (shProg->InfoLog) { + free(shProg->InfoLog); + } + shProg->InfoLog = _mesa_strdup(msg); + shProg->LinkStatus = GL_FALSE; +} + + + +/** + * Check if the given bit is either set or clear in both bitfields. + */ +static GLboolean +bits_agree(GLbitfield flags1, GLbitfield flags2, GLbitfield bit) +{ + return (flags1 & bit) == (flags2 & bit); +} + + +/** + * Examine the outputs/varyings written by the vertex shader and + * append the names of those outputs onto the Varyings list. + * This will only capture the pre-defined/built-in varyings like + * gl_Position, not user-defined varyings. + */ +static void +update_varying_var_list(GLcontext *ctx, struct gl_shader_program *shProg) +{ + if (shProg->VertexProgram) { + GLbitfield64 written = shProg->VertexProgram->Base.OutputsWritten; + GLuint i; + for (i = 0; written && i < VERT_RESULT_MAX; i++) { + if (written & BITFIELD64_BIT(i)) { + const char *name = _slang_vertex_output_name(i); + if (name) + _mesa_add_varying(shProg->Varying, name, 1, GL_FLOAT_VEC4, 0x0); + written &= ~BITFIELD64_BIT(i); + } + } + } +} + + +/** + * Do link error checking related to transform feedback. + */ +static GLboolean +link_transform_feedback(GLcontext *ctx, struct gl_shader_program *shProg) +{ + GLbitfield varyingMask; + GLuint totalComps, maxComps, i; + + if (shProg->TransformFeedback.NumVarying == 0) { + /* nothing to do */ + return GL_TRUE; + } + + /* Check that there's a vertex shader */ + if (shProg->TransformFeedback.NumVarying > 0 && + !shProg->VertexProgram) { + link_error(shProg, "Transform feedback without vertex shader"); + return GL_FALSE; + } + + /* Check that all named variables exist, and that none are duplicated. + * Also, build a count of the number of varying components to feedback. + */ + totalComps = 0; + varyingMask = 0x0; + for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) { + const GLchar *name = shProg->TransformFeedback.VaryingNames[i]; + GLint v = _mesa_lookup_parameter_index(shProg->Varying, -1, name); + struct gl_program_parameter *p; + + if (v < 0) { + char msg[100]; + _mesa_snprintf(msg, sizeof(msg), + "vertex shader does not emit %s", name); + link_error(shProg, msg); + return GL_FALSE; + } + + assert(v < MAX_VARYING); + + /* already seen this varying name? */ + if (varyingMask & (1 << v)) { + char msg[100]; + _mesa_snprintf(msg, sizeof(msg), + "duplicated transform feedback varying name: %s", + name); + link_error(shProg, msg); + return GL_FALSE; + } + + varyingMask |= (1 << v); + + p = &shProg->Varying->Parameters[v]; + + totalComps += _mesa_sizeof_glsl_type(p->DataType); + } + + if (shProg->TransformFeedback.BufferMode == GL_INTERLEAVED_ATTRIBS) + maxComps = ctx->Const.MaxTransformFeedbackInterleavedComponents; + else + maxComps = ctx->Const.MaxTransformFeedbackSeparateComponents; + + /* check max varying components against the limit */ + if (totalComps > maxComps) { + char msg[100]; + _mesa_snprintf(msg, sizeof(msg), + "Too many feedback components: %u, max is %u", + totalComps, maxComps); + link_error(shProg, msg); + return GL_FALSE; + } + + return GL_TRUE; +} + + +/** + * Linking varying vars involves rearranging varying vars so that the + * vertex program's output varyings matches the order of the fragment + * program's input varyings. + * We'll then rewrite instructions to replace PROGRAM_VARYING with either + * PROGRAM_INPUT or PROGRAM_OUTPUT depending on whether it's a vertex or + * fragment shader. + * This is also where we set program Input/OutputFlags to indicate + * which inputs are centroid-sampled, invariant, etc. + */ +static GLboolean +link_varying_vars(GLcontext *ctx, + struct gl_shader_program *shProg, struct gl_program *prog) +{ + GLuint *map, i, firstVarying, newFile; + GLbitfield *inOutFlags; + + map = (GLuint *) malloc(prog->Varying->NumParameters * sizeof(GLuint)); + if (!map) + return GL_FALSE; + + /* Varying variables are treated like other vertex program outputs + * (and like other fragment program inputs). The position of the + * first varying differs for vertex/fragment programs... + * Also, replace File=PROGRAM_VARYING with File=PROGRAM_INPUT/OUTPUT. + */ + if (prog->Target == GL_VERTEX_PROGRAM_ARB) { + firstVarying = VERT_RESULT_VAR0; + newFile = PROGRAM_OUTPUT; + inOutFlags = prog->OutputFlags; + } + else { + assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB); + firstVarying = FRAG_ATTRIB_VAR0; + newFile = PROGRAM_INPUT; + inOutFlags = prog->InputFlags; + } + + for (i = 0; i < prog->Varying->NumParameters; i++) { + /* see if this varying is in the linked varying list */ + const struct gl_program_parameter *var = prog->Varying->Parameters + i; + GLint j = _mesa_lookup_parameter_index(shProg->Varying, -1, var->Name); + if (j >= 0) { + /* varying is already in list, do some error checking */ + const struct gl_program_parameter *v = + &shProg->Varying->Parameters[j]; + if (var->Size != v->Size) { + link_error(shProg, "mismatched varying variable types"); + free(map); + return GL_FALSE; + } + if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_CENTROID)) { + char msg[100]; + _mesa_snprintf(msg, sizeof(msg), + "centroid modifier mismatch for '%s'", var->Name); + link_error(shProg, msg); + free(map); + return GL_FALSE; + } + if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_INVARIANT)) { + char msg[100]; + _mesa_snprintf(msg, sizeof(msg), + "invariant modifier mismatch for '%s'", var->Name); + link_error(shProg, msg); + free(map); + return GL_FALSE; + } + } + else { + /* not already in linked list */ + j = _mesa_add_varying(shProg->Varying, var->Name, var->Size, + var->DataType, var->Flags); + } + + if (shProg->Varying->NumParameters > ctx->Const.MaxVarying) { + link_error(shProg, "Too many varying variables"); + free(map); + return GL_FALSE; + } + + /* Map varying[i] to varying[j]. + * Note: the loop here takes care of arrays or large (sz>4) vars. + */ + { + GLint sz = var->Size; + while (sz > 0) { + inOutFlags[firstVarying + j] = var->Flags; + /*printf("Link varying from %d to %d\n", i, j);*/ + map[i++] = j++; + sz -= 4; + } + i--; /* go back one */ + } + } + + + /* OK, now scan the program/shader instructions looking for varying vars, + * replacing the old index with the new index. + */ + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + GLuint j; + + if (inst->DstReg.File == PROGRAM_VARYING) { + inst->DstReg.File = newFile; + inst->DstReg.Index = map[ inst->DstReg.Index ] + firstVarying; + } + + for (j = 0; j < 3; j++) { + if (inst->SrcReg[j].File == PROGRAM_VARYING) { + inst->SrcReg[j].File = newFile; + inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ] + firstVarying; + } + } + } + + free(map); + + /* these will get recomputed before linking is completed */ + prog->InputsRead = 0x0; + prog->OutputsWritten = 0x0; + + return GL_TRUE; +} + + +/** + * Build the shProg->Uniforms list. + * This is basically a list/index of all uniforms found in either/both of + * the vertex and fragment shaders. + * + * About uniforms: + * Each uniform has two indexes, one that points into the vertex + * program's parameter array and another that points into the fragment + * program's parameter array. When the user changes a uniform's value + * we have to change the value in the vertex and/or fragment program's + * parameter array. + * + * This function will be called twice to set up the two uniform->parameter + * mappings. + * + * If a uniform is only present in the vertex program OR fragment program + * then the fragment/vertex parameter index, respectively, will be -1. + */ +static GLboolean +link_uniform_vars(GLcontext *ctx, + struct gl_shader_program *shProg, + struct gl_program *prog, + GLuint *numSamplers) +{ + GLuint samplerMap[200]; /* max number of samplers declared, not used */ + GLuint i; + + for (i = 0; i < prog->Parameters->NumParameters; i++) { + const struct gl_program_parameter *p = prog->Parameters->Parameters + i; + + /* + * XXX FIX NEEDED HERE + * We should also be adding a uniform if p->Type == PROGRAM_STATE_VAR. + * For example, modelview matrix, light pos, etc. + * Also, we need to update the state-var name-generator code to + * generate GLSL-style names, like "gl_LightSource[0].position". + * Furthermore, we'll need to fix the state-var's size/datatype info. + */ + + if ((p->Type == PROGRAM_UNIFORM || p->Type == PROGRAM_SAMPLER) + && p->Used) { + /* add this uniform, indexing into the target's Parameters list */ + struct gl_uniform *uniform = + _mesa_append_uniform(shProg->Uniforms, p->Name, prog->Target, i); + if (uniform) + uniform->Initialized = p->Initialized; + } + + /* The samplerMap[] table we build here is used to remap/re-index + * sampler references by TEX instructions. + */ + if (p->Type == PROGRAM_SAMPLER && p->Used) { + /* Allocate a new sampler index */ + GLuint oldSampNum = (GLuint) prog->Parameters->ParameterValues[i][0]; + GLuint newSampNum = *numSamplers; + if (newSampNum >= ctx->Const.MaxTextureImageUnits) { + char s[100]; + _mesa_snprintf(s, sizeof(s), + "Too many texture samplers (%u, max is %u)", + newSampNum, ctx->Const.MaxTextureImageUnits); + link_error(shProg, s); + return GL_FALSE; + } + /* save old->new mapping in the table */ + if (oldSampNum < Elements(samplerMap)) + samplerMap[oldSampNum] = newSampNum; + /* update parameter's sampler index */ + prog->Parameters->ParameterValues[i][0] = (GLfloat) newSampNum; + (*numSamplers)++; + } + } + + /* OK, now scan the program/shader instructions looking for texture + * instructions using sampler vars. Replace old sampler indexes with + * new ones. + */ + prog->SamplersUsed = 0x0; + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + if (_mesa_is_tex_instruction(inst->Opcode)) { + /* here, inst->TexSrcUnit is really the sampler unit */ + const GLint oldSampNum = inst->TexSrcUnit; + +#if 0 + printf("====== remap sampler from %d to %d\n", + inst->TexSrcUnit, samplerMap[ inst->TexSrcUnit ]); +#endif + + if (oldSampNum < Elements(samplerMap)) { + const GLuint newSampNum = samplerMap[oldSampNum]; + inst->TexSrcUnit = newSampNum; + prog->SamplerTargets[newSampNum] = inst->TexSrcTarget; + prog->SamplersUsed |= (1 << newSampNum); + if (inst->TexShadow) { + prog->ShadowSamplers |= (1 << newSampNum); + } + } + } + } + + return GL_TRUE; +} + + +/** + * Resolve binding of generic vertex attributes. + * For example, if the vertex shader declared "attribute vec4 foobar" we'll + * allocate a generic vertex attribute for "foobar" and plug that value into + * the vertex program instructions. + * But if the user called glBindAttributeLocation(), those bindings will + * have priority. + */ +static GLboolean +_slang_resolve_attributes(struct gl_shader_program *shProg, + const struct gl_program *origProg, + struct gl_program *linkedProg) +{ + GLint attribMap[MAX_VERTEX_GENERIC_ATTRIBS]; + GLuint i, j; + GLbitfield usedAttributes; /* generics only, not legacy attributes */ + GLbitfield inputsRead = 0x0; + + assert(origProg != linkedProg); + assert(origProg->Target == GL_VERTEX_PROGRAM_ARB); + assert(linkedProg->Target == GL_VERTEX_PROGRAM_ARB); + + if (!shProg->Attributes) + shProg->Attributes = _mesa_new_parameter_list(); + + if (linkedProg->Attributes) { + _mesa_free_parameter_list(linkedProg->Attributes); + } + linkedProg->Attributes = _mesa_new_parameter_list(); + + + /* Build a bitmask indicating which attribute indexes have been + * explicitly bound by the user with glBindAttributeLocation(). + */ + usedAttributes = 0x0; + for (i = 0; i < shProg->Attributes->NumParameters; i++) { + GLint attr = shProg->Attributes->Parameters[i].StateIndexes[0]; + usedAttributes |= (1 << attr); + } + + /* If gl_Vertex is used, that actually counts against the limit + * on generic vertex attributes. This avoids the ambiguity of + * whether glVertexAttrib4fv(0, v) sets legacy attribute 0 (vert pos) + * or generic attribute[0]. If gl_Vertex is used, we want the former. + */ + if (origProg->InputsRead & VERT_BIT_POS) { + usedAttributes |= 0x1; + } + + /* initialize the generic attribute map entries to -1 */ + for (i = 0; i < MAX_VERTEX_GENERIC_ATTRIBS; i++) { + attribMap[i] = -1; + } + + /* + * Scan program for generic attribute references + */ + for (i = 0; i < linkedProg->NumInstructions; i++) { + struct prog_instruction *inst = linkedProg->Instructions + i; + for (j = 0; j < 3; j++) { + if (inst->SrcReg[j].File == PROGRAM_INPUT) { + inputsRead |= (1 << inst->SrcReg[j].Index); + } + + if (inst->SrcReg[j].File == PROGRAM_INPUT && + inst->SrcReg[j].Index >= VERT_ATTRIB_GENERIC0) { + /* + * OK, we've found a generic vertex attribute reference. + */ + const GLint k = inst->SrcReg[j].Index - VERT_ATTRIB_GENERIC0; + + GLint attr = attribMap[k]; + + if (attr < 0) { + /* Need to figure out attribute mapping now. + */ + const char *name = origProg->Attributes->Parameters[k].Name; + const GLint size = origProg->Attributes->Parameters[k].Size; + const GLenum type =origProg->Attributes->Parameters[k].DataType; + GLint index; + + /* See if there's a user-defined attribute binding for + * this name. + */ + index = _mesa_lookup_parameter_index(shProg->Attributes, + -1, name); + if (index >= 0) { + /* Found a user-defined binding */ + attr = shProg->Attributes->Parameters[index].StateIndexes[0]; + } + else { + /* No user-defined binding, choose our own attribute number. + * Start at 1 since generic attribute 0 always aliases + * glVertex/position. + */ + for (attr = 0; attr < MAX_VERTEX_GENERIC_ATTRIBS; attr++) { + if (((1 << attr) & usedAttributes) == 0) + break; + } + if (attr == MAX_VERTEX_GENERIC_ATTRIBS) { + link_error(shProg, "Too many vertex attributes"); + return GL_FALSE; + } + + /* mark this attribute as used */ + usedAttributes |= (1 << attr); + } + + attribMap[k] = attr; + + /* Save the final name->attrib binding so it can be queried + * with glGetAttributeLocation(). + */ + _mesa_add_attribute(linkedProg->Attributes, name, + size, type, attr); + } + + assert(attr >= 0); + + /* update the instruction's src reg */ + inst->SrcReg[j].Index = VERT_ATTRIB_GENERIC0 + attr; + } + } + } + + /* Handle pre-defined attributes here (gl_Vertex, gl_Normal, etc). + * When the user queries the active attributes we need to include both + * the user-defined attributes and the built-in ones. + */ + for (i = VERT_ATTRIB_POS; i < VERT_ATTRIB_GENERIC0; i++) { + if (inputsRead & (1 << i)) { + _mesa_add_attribute(linkedProg->Attributes, + _slang_vert_attrib_name(i), + 4, /* size in floats */ + _slang_vert_attrib_type(i), + -1 /* attrib/input */); + } + } + + return GL_TRUE; +} + + +/** + * Scan program instructions to update the program's NumTemporaries field. + * Note: this implemenation relies on the code generator allocating + * temps in increasing order (0, 1, 2, ... ). + */ +static void +_slang_count_temporaries(struct gl_program *prog) +{ + GLuint i, j; + GLint maxIndex = -1; + + for (i = 0; i < prog->NumInstructions; i++) { + const struct prog_instruction *inst = prog->Instructions + i; + const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { + if (maxIndex < inst->SrcReg[j].Index) + maxIndex = inst->SrcReg[j].Index; + } + if (inst->DstReg.File == PROGRAM_TEMPORARY) { + if (maxIndex < (GLint) inst->DstReg.Index) + maxIndex = inst->DstReg.Index; + } + } + } + + prog->NumTemporaries = (GLuint) (maxIndex + 1); +} + + +/** + * If an input attribute is indexed with relative addressing we have + * to compute a gl_program::InputsRead bitmask which reflects the fact + * that any input may be referenced by array element. Ex: gl_TexCoord[i]. + * This function computes the bitmask of potentially read inputs. + */ +static GLbitfield +get_inputs_read_mask(GLenum target, GLuint index, GLboolean relAddr) +{ + GLbitfield mask; + + mask = 1 << index; + + if (relAddr) { + if (target == GL_VERTEX_PROGRAM_ARB) { + switch (index) { + case VERT_ATTRIB_TEX0: + mask = ((1U << (VERT_ATTRIB_TEX7 + 1)) - 1) + - ((1U << VERT_ATTRIB_TEX0) - 1); + break; + case VERT_ATTRIB_GENERIC0: + /* different code to avoid uint overflow */ + mask = ~0x0U - ((1U << VERT_ATTRIB_GENERIC0) - 1); + break; + default: + ; /* a non-array input attribute */ + } + } + else if (target == GL_FRAGMENT_PROGRAM_ARB) { + switch (index) { + case FRAG_ATTRIB_TEX0: + mask = ((1U << (FRAG_ATTRIB_TEX7 + 1)) - 1) + - ((1U << FRAG_ATTRIB_TEX0) - 1); + break; + case FRAG_ATTRIB_VAR0: + mask = ((1U << (FRAG_ATTRIB_VAR0 + MAX_VARYING)) - 1) + - ((1U << FRAG_ATTRIB_VAR0) - 1); + break; + default: + ; /* a non-array input attribute */ + } + } + else { + assert(0 && "bad program target"); + } + } + else { + } + + return mask; +} + + +/** + * If an output attribute is indexed with relative addressing we have + * to compute a gl_program::OutputsWritten bitmask which reflects the fact + * that any output may be referenced by array element. Ex: gl_TexCoord[i]. + * This function computes the bitmask of potentially written outputs. + */ +static GLbitfield64 +get_outputs_written_mask(GLenum target, GLuint index, GLboolean relAddr) +{ + GLbitfield64 mask; + + mask = BITFIELD64_BIT(index); + + if (relAddr) { + if (target == GL_VERTEX_PROGRAM_ARB) { + switch (index) { + case VERT_RESULT_TEX0: + mask = BITFIELD64_RANGE(VERT_RESULT_TEX0, + (VERT_RESULT_TEX0 + + MAX_TEXTURE_COORD_UNITS - 1)); + break; + case VERT_RESULT_VAR0: + mask = BITFIELD64_RANGE(VERT_RESULT_VAR0, + (VERT_RESULT_VAR0 + MAX_VARYING - 1)); + break; + default: + ; /* a non-array output attribute */ + } + } + else if (target == GL_FRAGMENT_PROGRAM_ARB) { + switch (index) { + case FRAG_RESULT_DATA0: + mask = BITFIELD64_RANGE(FRAG_RESULT_DATA0, + (FRAG_RESULT_DATA0 + + MAX_DRAW_BUFFERS - 1)); + break; + default: + ; /* a non-array output attribute */ + } + } + else { + assert(0 && "bad program target"); + } + } + + return mask; +} + + +/** + * Scan program instructions to update the program's InputsRead and + * OutputsWritten fields. + */ +static void +_slang_update_inputs_outputs(struct gl_program *prog) +{ + GLuint i, j; + GLuint maxAddrReg = 0; + + prog->InputsRead = 0x0; + prog->OutputsWritten = 0x0; + + for (i = 0; i < prog->NumInstructions; i++) { + const struct prog_instruction *inst = prog->Instructions + i; + const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == PROGRAM_INPUT) { + prog->InputsRead |= get_inputs_read_mask(prog->Target, + inst->SrcReg[j].Index, + inst->SrcReg[j].RelAddr); + } + else if (inst->SrcReg[j].File == PROGRAM_ADDRESS) { + maxAddrReg = MAX2(maxAddrReg, (GLuint) (inst->SrcReg[j].Index + 1)); + } + } + + if (inst->DstReg.File == PROGRAM_OUTPUT) { + prog->OutputsWritten |= get_outputs_written_mask(prog->Target, + inst->DstReg.Index, + inst->DstReg.RelAddr); + } + else if (inst->DstReg.File == PROGRAM_ADDRESS) { + maxAddrReg = MAX2(maxAddrReg, inst->DstReg.Index + 1); + } + } + prog->NumAddressRegs = maxAddrReg; +} + + + +/** + * Remove extra #version directives from the concatenated source string. + * Disable the extra ones by converting first two chars to //, a comment. + * This is a bit of hack to work around a preprocessor bug that only + * allows one #version directive per source. + */ +static void +remove_extra_version_directives(GLchar *source) +{ + GLuint verCount = 0; + while (1) { + char *ver = strstr(source, "#version"); + if (ver) { + verCount++; + if (verCount > 1) { + ver[0] = '/'; + ver[1] = '/'; + } + source += 8; + } + else { + break; + } + } +} + + + +/** + * Return a new shader whose source code is the concatenation of + * all the shader sources of the given type. + */ +static struct gl_shader * +concat_shaders(struct gl_shader_program *shProg, GLenum shaderType) +{ + struct gl_shader *newShader; + const struct gl_shader *firstShader = NULL; + GLuint *shaderLengths; + GLchar *source; + GLuint totalLen = 0, len = 0; + GLuint i; + + shaderLengths = (GLuint *)malloc(shProg->NumShaders * sizeof(GLuint)); + if (!shaderLengths) { + return NULL; + } + + /* compute total size of new shader source code */ + for (i = 0; i < shProg->NumShaders; i++) { + const struct gl_shader *shader = shProg->Shaders[i]; + if (shader->Type == shaderType) { + shaderLengths[i] = strlen(shader->Source); + totalLen += shaderLengths[i]; + if (!firstShader) + firstShader = shader; + } + } + + if (totalLen == 0) { + free(shaderLengths); + return NULL; + } + + source = (GLchar *) malloc(totalLen + 1); + if (!source) { + free(shaderLengths); + return NULL; + } + + /* concatenate shaders */ + for (i = 0; i < shProg->NumShaders; i++) { + const struct gl_shader *shader = shProg->Shaders[i]; + if (shader->Type == shaderType) { + memcpy(source + len, shader->Source, shaderLengths[i]); + len += shaderLengths[i]; + } + } + source[len] = '\0'; + /* + printf("---NEW CONCATENATED SHADER---:\n%s\n------------\n", source); + */ + + free(shaderLengths); + + remove_extra_version_directives(source); + + newShader = CALLOC_STRUCT(gl_shader); + if (!newShader) { + free(source); + return NULL; + } + + newShader->Type = shaderType; + newShader->Source = source; + newShader->Pragmas = firstShader->Pragmas; + + return newShader; +} + + +/** + * Search the shader program's list of shaders to find the one that + * defines main(). + * This will involve shader concatenation and recompilation if needed. + */ +static struct gl_shader * +get_main_shader(GLcontext *ctx, + struct gl_shader_program *shProg, GLenum type) +{ + struct gl_shader *shader = NULL; + GLuint i; + + /* + * Look for a shader that defines main() and has no unresolved references. + */ + for (i = 0; i < shProg->NumShaders; i++) { + shader = shProg->Shaders[i]; + if (shader->Type == type && + shader->Main && + !shader->UnresolvedRefs) { + /* All set! */ + return shader; + } + } + + /* + * There must have been unresolved references during the original + * compilation. Try concatenating all the shaders of the given type + * and recompile that. + */ + shader = concat_shaders(shProg, type); + + if (shader) { + _slang_compile(ctx, shader); + + /* Finally, check if recompiling failed */ + if (!shader->CompileStatus || + !shader->Main || + shader->UnresolvedRefs) { + link_error(shProg, "Unresolved symbols"); + ctx->Driver.DeleteShader(ctx, shader); + return NULL; + } + } + + return shader; +} + + +/** + * Shader linker. Currently: + * + * 1. The last attached vertex shader and fragment shader are linked. + * 2. Varying vars in the two shaders are combined so their locations + * agree between the vertex and fragment stages. They're treated as + * vertex program output attribs and as fragment program input attribs. + * 3. The vertex and fragment programs are cloned and modified to update + * src/dst register references so they use the new, linked varying + * storage locations. + */ +void +_slang_link(GLcontext *ctx, + GLhandleARB programObj, + struct gl_shader_program *shProg) +{ + const struct gl_vertex_program *vertProg = NULL; + const struct gl_fragment_program *fragProg = NULL; + GLboolean vertNotify = GL_TRUE, fragNotify = GL_TRUE; + GLuint numSamplers = 0; + GLuint i; + + _mesa_clear_shader_program_data(ctx, shProg); + + /* Initialize LinkStatus to "success". Will be cleared if error. */ + shProg->LinkStatus = GL_TRUE; + + /* check that all programs compiled successfully */ + for (i = 0; i < shProg->NumShaders; i++) { + if (!shProg->Shaders[i]->CompileStatus) { + link_error(shProg, "linking with uncompiled shader\n"); + return; + } + } + + shProg->Uniforms = _mesa_new_uniform_list(); + shProg->Varying = _mesa_new_parameter_list(); + + /* + * Find the vertex and fragment shaders which define main() + */ + { + struct gl_shader *vertShader, *fragShader; + vertShader = get_main_shader(ctx, shProg, GL_VERTEX_SHADER); + fragShader = get_main_shader(ctx, shProg, GL_FRAGMENT_SHADER); + if (vertShader) + vertProg = vertex_program(vertShader->Program); + if (fragShader) + fragProg = fragment_program(fragShader->Program); + if (!shProg->LinkStatus) + return; + } + +#if FEATURE_es2_glsl + /* must have both a vertex and fragment program for ES2 */ + if (ctx->API == API_OPENGLES2) { + if (!vertProg) { + link_error(shProg, "missing vertex shader\n"); + return; + } + if (!fragProg) { + link_error(shProg, "missing fragment shader\n"); + return; + } + } +#endif + + /* + * Make copies of the vertex/fragment programs now since we'll be + * changing src/dst registers after merging the uniforms and varying vars. + */ + _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL); + if (vertProg) { + struct gl_vertex_program *linked_vprog = + _mesa_clone_vertex_program(ctx, vertProg); + shProg->VertexProgram = linked_vprog; /* refcount OK */ + /* vertex program ID not significant; just set Id for debugging purposes */ + shProg->VertexProgram->Base.Id = shProg->Name; + ASSERT(shProg->VertexProgram->Base.RefCount == 1); + } + + _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL); + if (fragProg) { + struct gl_fragment_program *linked_fprog = + _mesa_clone_fragment_program(ctx, fragProg); + shProg->FragmentProgram = linked_fprog; /* refcount OK */ + /* vertex program ID not significant; just set Id for debugging purposes */ + shProg->FragmentProgram->Base.Id = shProg->Name; + ASSERT(shProg->FragmentProgram->Base.RefCount == 1); + } + + /* link varying vars */ + if (shProg->VertexProgram) { + if (!link_varying_vars(ctx, shProg, &shProg->VertexProgram->Base)) + return; + } + if (shProg->FragmentProgram) { + if (!link_varying_vars(ctx, shProg, &shProg->FragmentProgram->Base)) + return; + } + + /* link uniform vars */ + if (shProg->VertexProgram) { + if (!link_uniform_vars(ctx, shProg, &shProg->VertexProgram->Base, + &numSamplers)) { + return; + } + } + if (shProg->FragmentProgram) { + if (!link_uniform_vars(ctx, shProg, &shProg->FragmentProgram->Base, + &numSamplers)) { + return; + } + } + + /*_mesa_print_uniforms(shProg->Uniforms);*/ + + if (shProg->VertexProgram) { + if (!_slang_resolve_attributes(shProg, &vertProg->Base, + &shProg->VertexProgram->Base)) { + return; + } + } + + if (shProg->VertexProgram) { + _slang_update_inputs_outputs(&shProg->VertexProgram->Base); + _slang_count_temporaries(&shProg->VertexProgram->Base); + if (!(shProg->VertexProgram->Base.OutputsWritten + & BITFIELD64_BIT(VERT_RESULT_HPOS))) { + /* the vertex program did not compute a vertex position */ + link_error(shProg, + "gl_Position was not written by vertex shader\n"); + return; + } + } + if (shProg->FragmentProgram) { + _slang_count_temporaries(&shProg->FragmentProgram->Base); + _slang_update_inputs_outputs(&shProg->FragmentProgram->Base); + } + + /* Check that all the varying vars needed by the fragment shader are + * actually produced by the vertex shader. + */ + if (shProg->FragmentProgram) { + const GLbitfield varyingRead + = shProg->FragmentProgram->Base.InputsRead >> FRAG_ATTRIB_VAR0; + const GLbitfield64 varyingWritten = shProg->VertexProgram ? + shProg->VertexProgram->Base.OutputsWritten >> VERT_RESULT_VAR0 : 0x0; + if ((varyingRead & varyingWritten) != varyingRead) { + link_error(shProg, + "Fragment program using varying vars not written by vertex shader\n"); + return; + } + } + + /* check that gl_FragColor and gl_FragData are not both written to */ + if (shProg->FragmentProgram) { + const GLbitfield64 outputsWritten = + shProg->FragmentProgram->Base.OutputsWritten; + if ((outputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) && + (outputsWritten >= BITFIELD64_BIT(FRAG_RESULT_DATA0))) { + link_error(shProg, "Fragment program cannot write both gl_FragColor" + " and gl_FragData[].\n"); + return; + } + } + + update_varying_var_list(ctx, shProg); + + /* checks related to transform feedback */ + if (!link_transform_feedback(ctx, shProg)) { + return; + } + + if (fragProg && shProg->FragmentProgram) { + /* Compute initial program's TexturesUsed info */ + _mesa_update_shader_textures_used(&shProg->FragmentProgram->Base); + + /* notify driver that a new fragment program has been compiled/linked */ + vertNotify = ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB, + &shProg->FragmentProgram->Base); + if (ctx->Shader.Flags & GLSL_DUMP) { + printf("Mesa pre-link fragment program:\n"); + _mesa_print_program(&fragProg->Base); + _mesa_print_program_parameters(ctx, &fragProg->Base); + + printf("Mesa post-link fragment program:\n"); + _mesa_print_program(&shProg->FragmentProgram->Base); + _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base); + } + } + + if (vertProg && shProg->VertexProgram) { + /* Compute initial program's TexturesUsed info */ + _mesa_update_shader_textures_used(&shProg->VertexProgram->Base); + + /* notify driver that a new vertex program has been compiled/linked */ + fragNotify = ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, + &shProg->VertexProgram->Base); + if (ctx->Shader.Flags & GLSL_DUMP) { + printf("Mesa pre-link vertex program:\n"); + _mesa_print_program(&vertProg->Base); + _mesa_print_program_parameters(ctx, &vertProg->Base); + + printf("Mesa post-link vertex program:\n"); + _mesa_print_program(&shProg->VertexProgram->Base); + _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base); + } + } + + /* Debug: */ + if (0) { + if (shProg->VertexProgram) + _mesa_postprocess_program(ctx, &shProg->VertexProgram->Base); + if (shProg->FragmentProgram) + _mesa_postprocess_program(ctx, &shProg->FragmentProgram->Base); + } + + if (ctx->Shader.Flags & GLSL_DUMP) { + printf("Varying vars:\n"); + _mesa_print_parameter_list(shProg->Varying); + if (shProg->InfoLog) { + printf("Info Log: %s\n", shProg->InfoLog); + } + } + + if (!vertNotify || !fragNotify) { + /* driver rejected one/both of the vertex/fragment programs */ + if (!shProg->InfoLog) { + link_error(shProg, + "Vertex and/or fragment program rejected by driver\n"); + } + } + else { + shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram); + } +} + diff --git a/src/mesa/slang/slang_link.h b/src/mesa/slang/slang_link.h new file mode 100644 index 0000000000..2b44d20787 --- /dev/null +++ b/src/mesa/slang/slang_link.h @@ -0,0 +1,37 @@ +/* + * Mesa 3-D graphics library + * Version: 7.2 + * + * Copyright (C) 2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_LINK_H +#define SLANG_LINK_H 1 + +#include "slang_compile.h" + + +extern void +_slang_link(GLcontext *ctx, GLhandleARB h, + struct gl_shader_program *shProg); + + +#endif + diff --git a/src/mesa/slang/slang_log.c b/src/mesa/slang/slang_log.c new file mode 100644 index 0000000000..9ff21417bc --- /dev/null +++ b/src/mesa/slang/slang_log.c @@ -0,0 +1,133 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "main/imports.h" +#include "slang_log.h" +#include "slang_utility.h" + + + +static char *out_of_memory = "Error: Out of memory.\n"; + +void +slang_info_log_construct(slang_info_log * log) +{ + log->text = NULL; + log->dont_free_text = GL_FALSE; + log->error_flag = GL_FALSE; +} + +void +slang_info_log_destruct(slang_info_log * log) +{ + if (!log->dont_free_text) + free(log->text); +} + +static int +slang_info_log_message(slang_info_log * log, const char *prefix, + const char *msg) +{ + GLuint size; + + if (log->dont_free_text) + return 0; + size = slang_string_length(msg) + 2; + if (prefix != NULL) + size += slang_string_length(prefix) + 2; + if (log->text != NULL) { + GLuint old_len = slang_string_length(log->text); + log->text = (char *) + _mesa_realloc(log->text, old_len + 1, old_len + size); + } + else { + log->text = (char *) (malloc(size)); + if (log->text != NULL) + log->text[0] = '\0'; + } + if (log->text == NULL) + return 0; + if (prefix != NULL) { + slang_string_concat(log->text, prefix); + slang_string_concat(log->text, ": "); + } + slang_string_concat(log->text, msg); + slang_string_concat(log->text, "\n"); + + return 1; +} + +int +slang_info_log_print(slang_info_log * log, const char *msg, ...) +{ + va_list va; + char buf[1024]; + + va_start(va, msg); + vsprintf(buf, msg, va); + va_end(va); + return slang_info_log_message(log, NULL, buf); +} + +int +slang_info_log_error(slang_info_log * log, const char *msg, ...) +{ + va_list va; + char buf[1024]; + + va_start(va, msg); + vsprintf(buf, msg, va); + va_end(va); + log->error_flag = GL_TRUE; + if (slang_info_log_message(log, "Error", buf)) + return 1; + slang_info_log_memory(log); + return 0; +} + +int +slang_info_log_warning(slang_info_log * log, const char *msg, ...) +{ + va_list va; + char buf[1024]; + + va_start(va, msg); + vsprintf(buf, msg, va); + va_end(va); + if (slang_info_log_message(log, "Warning", buf)) + return 1; + slang_info_log_memory(log); + return 0; +} + +void +slang_info_log_memory(slang_info_log * log) +{ + if (!slang_info_log_message(log, "Error", "Out of memory.")) { + log->dont_free_text = GL_TRUE; + log->error_flag = GL_TRUE; + log->text = out_of_memory; + } +} diff --git a/src/mesa/slang/slang_log.h b/src/mesa/slang/slang_log.h new file mode 100644 index 0000000000..dcaba0285a --- /dev/null +++ b/src/mesa/slang/slang_log.h @@ -0,0 +1,57 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef SLANG_LOG_H +#define SLANG_LOG_H + + +typedef struct slang_info_log_ +{ + char *text; + GLboolean dont_free_text; + GLboolean error_flag; +} slang_info_log; + + +extern void +slang_info_log_construct(slang_info_log *); + +extern void +slang_info_log_destruct(slang_info_log *); + +extern int +slang_info_log_print(slang_info_log *, const char *, ...); + +extern int +slang_info_log_error(slang_info_log *, const char *, ...); + +extern int +slang_info_log_warning(slang_info_log *, const char *, ...); + +extern void +slang_info_log_memory(slang_info_log *); + + +#endif /* SLANG_LOG_H */ diff --git a/src/mesa/slang/slang_mem.c b/src/mesa/slang/slang_mem.c new file mode 100644 index 0000000000..5eaa7c4427 --- /dev/null +++ b/src/mesa/slang/slang_mem.c @@ -0,0 +1,243 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_mem.c + * + * Memory manager for GLSL compiler. The general idea is to do all + * allocations out of a large pool then just free the pool when done + * compiling to avoid intricate malloc/free tracking and memory leaks. + * + * \author Brian Paul + */ + +#include "main/context.h" +#include "main/macros.h" +#include "slang_mem.h" + + +#define GRANULARITY 8 +#define ROUND_UP(B) ( ((B) + (GRANULARITY - 1)) & ~(GRANULARITY - 1) ) + + +/** If 1, use conventional malloc/free. Helpful for debugging */ +#define USE_MALLOC_FREE 0 + + +struct slang_mempool_ +{ + GLuint Size, Used, Count, Largest; + char *Data; + struct slang_mempool_ *Next; +}; + + +slang_mempool * +_slang_new_mempool(GLuint initialSize) +{ + slang_mempool *pool = (slang_mempool *) calloc(1, sizeof(slang_mempool)); + if (pool) { + pool->Data = (char *) calloc(1, initialSize); + /*printf("ALLOC MEMPOOL %d at %p\n", initialSize, pool->Data);*/ + if (!pool->Data) { + free(pool); + return NULL; + } + pool->Size = initialSize; + pool->Used = 0; + } + return pool; +} + + +void +_slang_delete_mempool(slang_mempool *pool) +{ + GLuint total = 0; + while (pool) { + slang_mempool *next = pool->Next; + /* + printf("DELETE MEMPOOL %u / %u count=%u largest=%u\n", + pool->Used, pool->Size, pool->Count, pool->Largest); + */ + total += pool->Used; + free(pool->Data); + free(pool); + pool = next; + } + /*printf("TOTAL ALLOCATED: %u\n", total);*/ +} + + +#ifdef DEBUG +static void +check_zero(const char *addr, GLuint n) +{ + GLuint i; + for (i = 0; i < n; i++) { + assert(addr[i]==0); + } +} +#endif + + +#ifdef DEBUG +static GLboolean +is_valid_address(const slang_mempool *pool, void *addr) +{ + while (pool) { + if ((char *) addr >= pool->Data && + (char *) addr < pool->Data + pool->Used) + return GL_TRUE; + + pool = pool->Next; + } + return GL_FALSE; +} +#endif + + +/** + * Alloc 'bytes' from shader mempool. + */ +void * +_slang_alloc(GLuint bytes) +{ +#if USE_MALLOC_FREE + return calloc(1, bytes); +#else + slang_mempool *pool; + GET_CURRENT_CONTEXT(ctx); + pool = (slang_mempool *) ctx->Shader.MemPool; + + if (bytes == 0) + bytes = 1; + + while (pool) { + if (pool->Used + bytes <= pool->Size) { + /* found room */ + void *addr = (void *) (pool->Data + pool->Used); +#ifdef DEBUG + check_zero((char*) addr, bytes); +#endif + pool->Used += ROUND_UP(bytes); + pool->Largest = MAX2(pool->Largest, bytes); + pool->Count++; + /*printf("alloc %u Used %u\n", bytes, pool->Used);*/ + return addr; + } + else if (pool->Next) { + /* try next block */ + pool = pool->Next; + } + else { + /* alloc new pool */ + const GLuint sz = MAX2(bytes, pool->Size); + pool->Next = _slang_new_mempool(sz); + if (!pool->Next) { + /* we're _really_ out of memory */ + return NULL; + } + else { + pool = pool->Next; + pool->Largest = bytes; + pool->Count++; + pool->Used = ROUND_UP(bytes); +#ifdef DEBUG + check_zero((char*) pool->Data, bytes); +#endif + return (void *) pool->Data; + } + } + } + return NULL; +#endif +} + + +void * +_slang_realloc(void *oldBuffer, GLuint oldSize, GLuint newSize) +{ +#if USE_MALLOC_FREE + return _mesa_realloc(oldBuffer, oldSize, newSize); +#else + GET_CURRENT_CONTEXT(ctx); + slang_mempool *pool = (slang_mempool *) ctx->Shader.MemPool; + (void) pool; + + if (newSize < oldSize) { + return oldBuffer; + } + else { + const GLuint copySize = (oldSize < newSize) ? oldSize : newSize; + void *newBuffer = _slang_alloc(newSize); + + if (oldBuffer) + ASSERT(is_valid_address(pool, oldBuffer)); + + if (newBuffer && oldBuffer && copySize > 0) + memcpy(newBuffer, oldBuffer, copySize); + + return newBuffer; + } +#endif +} + + +/** + * Clone string, storing in current mempool. + */ +char * +_slang_strdup(const char *s) +{ + if (s) { + size_t l = strlen(s); + char *s2 = (char *) _slang_alloc(l + 1); + if (s2) + strcpy(s2, s); + return s2; + } + else { + return NULL; + } +} + + +/** + * Don't actually free memory, but mark it (for debugging). + */ +void +_slang_free(void *addr) +{ +#if USE_MALLOC_FREE + free(addr); +#else + if (addr) { + GET_CURRENT_CONTEXT(ctx); + slang_mempool *pool = (slang_mempool *) ctx->Shader.MemPool; + (void) pool; + ASSERT(is_valid_address(pool, addr)); + } +#endif +} diff --git a/src/mesa/slang/slang_mem.h b/src/mesa/slang/slang_mem.h new file mode 100644 index 0000000000..b5bfae2479 --- /dev/null +++ b/src/mesa/slang/slang_mem.h @@ -0,0 +1,55 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef SLANG_MEM_H +#define SLANG_MEM_H + + +#include "main/imports.h" + + +typedef struct slang_mempool_ slang_mempool; + + +extern slang_mempool * +_slang_new_mempool(GLuint initialSize); + +extern void +_slang_delete_mempool(slang_mempool *pool); + +extern void * +_slang_alloc(GLuint bytes); + +extern void * +_slang_realloc(void *oldBuffer, GLuint oldSize, GLuint newSize); + +extern char * +_slang_strdup(const char *s); + +extern void +_slang_free(void *addr); + + +#endif diff --git a/src/mesa/slang/slang_print.c b/src/mesa/slang/slang_print.c new file mode 100644 index 0000000000..6b34f395fd --- /dev/null +++ b/src/mesa/slang/slang_print.c @@ -0,0 +1,883 @@ + +/** + * Dump/print a slang_operation tree + */ + + +#include "main/imports.h" +#include "slang_compile.h" +#include "slang_print.h" + + +static void +spaces(int n) +{ + while (n--) + printf(" "); +} + + +static void +print_type(const slang_fully_specified_type *t) +{ + switch (t->qualifier) { + case SLANG_QUAL_NONE: + /*printf("");*/ + break; + case SLANG_QUAL_CONST: + printf("const "); + break; + case SLANG_QUAL_ATTRIBUTE: + printf("attrib "); + break; + case SLANG_QUAL_VARYING: + printf("varying "); + break; + case SLANG_QUAL_UNIFORM: + printf("uniform "); + break; + case SLANG_QUAL_OUT: + printf("output "); + break; + case SLANG_QUAL_INOUT: + printf("inout "); + break; + case SLANG_QUAL_FIXEDOUTPUT: + printf("fixedoutput"); + break; + case SLANG_QUAL_FIXEDINPUT: + printf("fixedinput"); + break; + default: + printf("unknown qualifer!"); + } + + switch (t->specifier.type) { + case SLANG_SPEC_VOID: + printf("void"); + break; + case SLANG_SPEC_BOOL: + printf("bool"); + break; + case SLANG_SPEC_BVEC2: + printf("bvec2"); + break; + case SLANG_SPEC_BVEC3: + printf("bvec3"); + break; + case SLANG_SPEC_BVEC4: + printf("bvec4"); + break; + case SLANG_SPEC_INT: + printf("int"); + break; + case SLANG_SPEC_IVEC2: + printf("ivec2"); + break; + case SLANG_SPEC_IVEC3: + printf("ivec3"); + break; + case SLANG_SPEC_IVEC4: + printf("ivec4"); + break; + case SLANG_SPEC_FLOAT: + printf("float"); + break; + case SLANG_SPEC_VEC2: + printf("vec2"); + break; + case SLANG_SPEC_VEC3: + printf("vec3"); + break; + case SLANG_SPEC_VEC4: + printf("vec4"); + break; + case SLANG_SPEC_MAT2: + printf("mat2"); + break; + case SLANG_SPEC_MAT3: + printf("mat3"); + break; + case SLANG_SPEC_MAT4: + printf("mat4"); + break; + case SLANG_SPEC_MAT23: + printf("mat2x3"); + break; + case SLANG_SPEC_MAT32: + printf("mat3x2"); + break; + case SLANG_SPEC_MAT24: + printf("mat2x4"); + break; + case SLANG_SPEC_MAT42: + printf("mat4x2"); + break; + case SLANG_SPEC_MAT34: + printf("mat3x4"); + break; + case SLANG_SPEC_MAT43: + printf("mat4x3"); + break; + case SLANG_SPEC_SAMPLER_1D: + printf("sampler1D"); + break; + case SLANG_SPEC_SAMPLER_2D: + printf("sampler2D"); + break; + case SLANG_SPEC_SAMPLER_3D: + printf("sampler3D"); + break; + case SLANG_SPEC_SAMPLER_CUBE: + printf("samplerCube"); + break; + case SLANG_SPEC_SAMPLER_1D_SHADOW: + printf("sampler1DShadow"); + break; + case SLANG_SPEC_SAMPLER_2D_SHADOW: + printf("sampler2DShadow"); + break; + case SLANG_SPEC_STRUCT: + printf("struct"); + break; + case SLANG_SPEC_ARRAY: + printf("array"); + break; + default: + printf("unknown type"); + } + /*printf("\n");*/ +} + + +static void +print_variable(const slang_variable *v, int indent) +{ + spaces(indent); + printf("VAR "); + print_type(&v->type); + printf(" %s (at %p)", (char *) v->a_name, (void *) v); + if (v->initializer) { + printf(" :=\n"); + slang_print_tree(v->initializer, indent + 3); + } + else { + printf(";\n"); + } +} + + +static void +print_binary(const slang_operation *op, const char *oper, int indent) +{ + assert(op->num_children == 2); +#if 0 + printf("binary at %p locals=%p outer=%p\n", + (void *) op, + (void *) op->locals, + (void *) op->locals->outer_scope); +#endif + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("%s at %p locals=%p outer=%p\n", + oper, (void *) op, (void *) op->locals, + (void *) op->locals->outer_scope); + slang_print_tree(&op->children[1], indent + 3); +} + + +static void +print_generic2(const slang_operation *op, const char *oper, + const char *s, int indent) +{ + GLuint i; + if (oper) { + spaces(indent); + printf("%s %s at %p locals=%p outer=%p\n", + oper, s, (void *) op, (void *) op->locals, + (void *) op->locals->outer_scope); + } + for (i = 0; i < op->num_children; i++) { + spaces(indent); + printf("//child %u of %u:\n", i, op->num_children); + slang_print_tree(&op->children[i], indent); + } +} + +static void +print_generic(const slang_operation *op, const char *oper, int indent) +{ + print_generic2(op, oper, "", indent); +} + + +static const slang_variable_scope * +find_scope(const slang_variable_scope *s, slang_atom name) +{ + GLuint i; + for (i = 0; i < s->num_variables; i++) { + if (s->variables[i]->a_name == name) + return s; + } + if (s->outer_scope) + return find_scope(s->outer_scope, name); + else + return NULL; +} + +static const slang_variable * +find_var(const slang_variable_scope *s, slang_atom name) +{ + GLuint i; + for (i = 0; i < s->num_variables; i++) { + if (s->variables[i]->a_name == name) + return s->variables[i]; + } + if (s->outer_scope) + return find_var(s->outer_scope, name); + else + return NULL; +} + + +void +slang_print_tree(const slang_operation *op, int indent) +{ + GLuint i; + + switch (op->type) { + + case SLANG_OPER_NONE: + spaces(indent); + printf("SLANG_OPER_NONE\n"); + break; + + case SLANG_OPER_BLOCK_NO_NEW_SCOPE: + spaces(indent); + printf("{ locals=%p outer=%p\n", (void*)op->locals, (void*)op->locals->outer_scope); + print_generic(op, NULL, indent+3); + spaces(indent); + printf("}\n"); + break; + + case SLANG_OPER_BLOCK_NEW_SCOPE: + case SLANG_OPER_NON_INLINED_CALL: + spaces(indent); + printf("{{ // new scope locals=%p outer=%p: ", + (void *) op->locals, + (void *) op->locals->outer_scope); + for (i = 0; i < op->locals->num_variables; i++) { + printf("%s ", (char *) op->locals->variables[i]->a_name); + } + printf("\n"); + print_generic(op, NULL, indent+3); + spaces(indent); + printf("}}\n"); + break; + + case SLANG_OPER_VARIABLE_DECL: + assert(op->num_children == 0 || op->num_children == 1); + { + slang_variable *v; + v = _slang_variable_locate(op->locals, op->a_id, GL_TRUE); + if (v) { + const slang_variable_scope *scope; + spaces(indent); + printf("DECL (locals=%p outer=%p) ", (void*)op->locals, (void*) op->locals->outer_scope); + print_type(&v->type); + printf(" %s (%p)", (char *) op->a_id, + (void *) find_var(op->locals, op->a_id)); + + scope = find_scope(op->locals, op->a_id); + printf(" (in scope %p) ", (void *) scope); + assert(scope); + if (op->num_children == 1) { + printf(" :=\n"); + slang_print_tree(&op->children[0], indent + 3); + } + else if (v->initializer) { + printf(" := INITIALIZER\n"); + slang_print_tree(v->initializer, indent + 3); + } + else { + printf(";\n"); + } + /* + spaces(indent); + printf("TYPE: "); + print_type(&v->type); + spaces(indent); + printf("ADDR: %d size: %d\n", v->address, v->size); + */ + } + else { + spaces(indent); + printf("DECL %s (anonymous variable!!!!)\n", (char *) op->a_id); + } + } + break; + + case SLANG_OPER_ASM: + spaces(indent); + printf("ASM: %s at %p locals=%p outer=%p\n", + (char *) op->a_id, + (void *) op, + (void *) op->locals, + (void *) op->locals->outer_scope); + print_generic(op, "ASM", indent+3); + break; + + case SLANG_OPER_BREAK: + spaces(indent); + printf("BREAK\n"); + break; + + case SLANG_OPER_CONTINUE: + spaces(indent); + printf("CONTINUE\n"); + break; + + case SLANG_OPER_DISCARD: + spaces(indent); + printf("DISCARD\n"); + break; + + case SLANG_OPER_RETURN: + spaces(indent); + printf("RETURN\n"); + if (op->num_children > 0) + slang_print_tree(&op->children[0], indent + 3); + break; + + case SLANG_OPER_RETURN_INLINED: + spaces(indent); + printf("RETURN_INLINED\n"); + if (op->num_children > 0) + slang_print_tree(&op->children[0], indent + 3); + break; + + case SLANG_OPER_LABEL: + spaces(indent); + printf("LABEL %s\n", (char *) op->a_id); + break; + + case SLANG_OPER_EXPRESSION: + spaces(indent); + printf("EXPR: locals=%p outer=%p\n", + (void *) op->locals, + (void *) op->locals->outer_scope); + /*print_generic(op, "SLANG_OPER_EXPRESSION", indent);*/ + slang_print_tree(&op->children[0], indent + 3); + break; + + case SLANG_OPER_IF: + spaces(indent); + printf("IF\n"); + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("THEN\n"); + slang_print_tree(&op->children[1], indent + 3); + spaces(indent); + printf("ELSE\n"); + slang_print_tree(&op->children[2], indent + 3); + spaces(indent); + printf("ENDIF\n"); + break; + + case SLANG_OPER_WHILE: + assert(op->num_children == 2); + spaces(indent); + printf("WHILE LOOP: locals = %p\n", (void *) op->locals); + indent += 3; + spaces(indent); + printf("WHILE cond:\n"); + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("WHILE body:\n"); + slang_print_tree(&op->children[1], indent + 3); + indent -= 3; + spaces(indent); + printf("END WHILE LOOP\n"); + break; + + case SLANG_OPER_DO: + spaces(indent); + printf("DO LOOP: locals = %p\n", (void *) op->locals); + indent += 3; + spaces(indent); + printf("DO body:\n"); + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("DO cond:\n"); + slang_print_tree(&op->children[1], indent + 3); + indent -= 3; + spaces(indent); + printf("END DO LOOP\n"); + break; + + case SLANG_OPER_FOR: + spaces(indent); + printf("FOR LOOP: locals = %p\n", (void *) op->locals); + indent += 3; + spaces(indent); + printf("FOR init:\n"); + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("FOR condition:\n"); + slang_print_tree(&op->children[1], indent + 3); + spaces(indent); + printf("FOR step:\n"); + slang_print_tree(&op->children[2], indent + 3); + spaces(indent); + printf("FOR body:\n"); + slang_print_tree(&op->children[3], indent + 3); + indent -= 3; + spaces(indent); + printf("ENDFOR\n"); + /* + print_generic(op, "FOR", indent + 3); + */ + break; + + case SLANG_OPER_VOID: + spaces(indent); + printf("(oper-void)\n"); + break; + + case SLANG_OPER_LITERAL_BOOL: + spaces(indent); + printf("LITERAL ("); + for (i = 0; i < op->literal_size; i++) + printf("%s ", op->literal[0] ? "TRUE" : "FALSE"); + printf(")\n"); + + break; + + case SLANG_OPER_LITERAL_INT: + spaces(indent); + printf("LITERAL ("); + for (i = 0; i < op->literal_size; i++) + printf("%d ", (int) op->literal[i]); + printf(")\n"); + break; + + case SLANG_OPER_LITERAL_FLOAT: + spaces(indent); + printf("LITERAL ("); + for (i = 0; i < op->literal_size; i++) + printf("%f ", op->literal[i]); + printf(")\n"); + break; + + case SLANG_OPER_IDENTIFIER: + { + const slang_variable_scope *scope; + spaces(indent); + if (op->var && op->var->a_name) { + scope = find_scope(op->locals, op->var->a_name); + printf("VAR %s (in scope %p)\n", (char *) op->var->a_name, + (void *) scope); + assert(scope); + } + else { + scope = find_scope(op->locals, op->a_id); + printf("VAR' %s (in scope %p) locals=%p outer=%p\n", + (char *) op->a_id, + (void *) scope, + (void *) op->locals, + (void *) op->locals->outer_scope); + /*assert(scope);*/ + } + } + break; + + case SLANG_OPER_SEQUENCE: + print_generic(op, "COMMA-SEQ", indent+3); + break; + + case SLANG_OPER_ASSIGN: + spaces(indent); + printf("ASSIGNMENT locals=%p outer=%p\n", + (void *) op->locals, + (void *) op->locals->outer_scope); + print_binary(op, ":=", indent); + break; + + case SLANG_OPER_ADDASSIGN: + spaces(indent); + printf("ASSIGN\n"); + print_binary(op, "+=", indent); + break; + + case SLANG_OPER_SUBASSIGN: + spaces(indent); + printf("ASSIGN\n"); + print_binary(op, "-=", indent); + break; + + case SLANG_OPER_MULASSIGN: + spaces(indent); + printf("ASSIGN\n"); + print_binary(op, "*=", indent); + break; + + case SLANG_OPER_DIVASSIGN: + spaces(indent); + printf("ASSIGN\n"); + print_binary(op, "/=", indent); + break; + + /*SLANG_OPER_MODASSIGN,*/ + /*SLANG_OPER_LSHASSIGN,*/ + /*SLANG_OPER_RSHASSIGN,*/ + /*SLANG_OPER_ORASSIGN,*/ + /*SLANG_OPER_XORASSIGN,*/ + /*SLANG_OPER_ANDASSIGN,*/ + case SLANG_OPER_SELECT: + spaces(indent); + printf("SLANG_OPER_SELECT n=%d\n", op->num_children); + assert(op->num_children == 3); + slang_print_tree(&op->children[0], indent+3); + spaces(indent); + printf("?\n"); + slang_print_tree(&op->children[1], indent+3); + spaces(indent); + printf(":\n"); + slang_print_tree(&op->children[2], indent+3); + break; + + case SLANG_OPER_LOGICALOR: + print_binary(op, "||", indent); + break; + + case SLANG_OPER_LOGICALXOR: + print_binary(op, "^^", indent); + break; + + case SLANG_OPER_LOGICALAND: + print_binary(op, "&&", indent); + break; + + /*SLANG_OPER_BITOR*/ + /*SLANG_OPER_BITXOR*/ + /*SLANG_OPER_BITAND*/ + case SLANG_OPER_EQUAL: + print_binary(op, "==", indent); + break; + + case SLANG_OPER_NOTEQUAL: + print_binary(op, "!=", indent); + break; + + case SLANG_OPER_LESS: + print_binary(op, "<", indent); + break; + + case SLANG_OPER_GREATER: + print_binary(op, ">", indent); + break; + + case SLANG_OPER_LESSEQUAL: + print_binary(op, "<=", indent); + break; + + case SLANG_OPER_GREATEREQUAL: + print_binary(op, ">=", indent); + break; + + /*SLANG_OPER_LSHIFT*/ + /*SLANG_OPER_RSHIFT*/ + case SLANG_OPER_ADD: + print_binary(op, "+", indent); + break; + + case SLANG_OPER_SUBTRACT: + print_binary(op, "-", indent); + break; + + case SLANG_OPER_MULTIPLY: + print_binary(op, "*", indent); + break; + + case SLANG_OPER_DIVIDE: + print_binary(op, "/", indent); + break; + + /*SLANG_OPER_MODULUS*/ + case SLANG_OPER_PREINCREMENT: + spaces(indent); + printf("PRE++\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + case SLANG_OPER_PREDECREMENT: + spaces(indent); + printf("PRE--\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + case SLANG_OPER_PLUS: + spaces(indent); + printf("SLANG_OPER_PLUS\n"); + break; + + case SLANG_OPER_MINUS: + spaces(indent); + printf("SLANG_OPER_MINUS\n"); + break; + + /*SLANG_OPER_COMPLEMENT*/ + case SLANG_OPER_NOT: + spaces(indent); + printf("NOT\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + case SLANG_OPER_SUBSCRIPT: + spaces(indent); + printf("SLANG_OPER_SUBSCRIPT locals=%p outer=%p\n", + (void *) op->locals, + (void *) op->locals->outer_scope); + print_generic(op, NULL, indent+3); + break; + + case SLANG_OPER_CALL: +#if 0 + slang_function *fun + = _slang_function_locate(A->space.funcs, oper->a_id, + oper->children, + oper->num_children, &A->space, A->atoms); +#endif + spaces(indent); + printf("CALL %s(\n", (char *) op->a_id); + for (i = 0; i < op->num_children; i++) { + slang_print_tree(&op->children[i], indent+3); + if (i + 1 < op->num_children) { + spaces(indent + 3); + printf(",\n"); + } + } + spaces(indent); + printf(")\n"); + break; + + case SLANG_OPER_METHOD: + spaces(indent); + printf("METHOD CALL %s.%s\n", (char *) op->a_obj, (char *) op->a_id); + break; + + case SLANG_OPER_FIELD: + spaces(indent); + printf("FIELD %s of\n", (char*) op->a_id); + slang_print_tree(&op->children[0], indent+3); + break; + + case SLANG_OPER_POSTINCREMENT: + spaces(indent); + printf("POST++\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + case SLANG_OPER_POSTDECREMENT: + spaces(indent); + printf("POST--\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + default: + printf("unknown op->type %d\n", (int) op->type); + } + +} + + + +void +slang_print_function(const slang_function *f, GLboolean body) +{ + GLuint i; + +#if 0 + if (strcmp((char *) f->header.a_name, "main") != 0) + return; +#endif + + printf("FUNCTION %s ( scope=%p\n", + (char *) f->header.a_name, (void *) f->parameters); + + for (i = 0; i < f->param_count; i++) { + print_variable(f->parameters->variables[i], 3); + } + + printf(") param scope = %p\n", (void *) f->parameters); + + if (body && f->body) + slang_print_tree(f->body, 0); +} + + + + + +const char * +slang_type_qual_string(slang_type_qualifier q) +{ + switch (q) { + case SLANG_QUAL_NONE: + return "none"; + case SLANG_QUAL_CONST: + return "const"; + case SLANG_QUAL_ATTRIBUTE: + return "attribute"; + case SLANG_QUAL_VARYING: + return "varying"; + case SLANG_QUAL_UNIFORM: + return "uniform"; + case SLANG_QUAL_OUT: + return "out"; + case SLANG_QUAL_INOUT: + return "inout"; + case SLANG_QUAL_FIXEDOUTPUT: + return "fixedoutput"; + case SLANG_QUAL_FIXEDINPUT: + return "fixedinputk"; + default: + return "qual?"; + } +} + + +static const char * +slang_type_string(slang_type_specifier_type t) +{ + switch (t) { + case SLANG_SPEC_VOID: + return "void"; + case SLANG_SPEC_BOOL: + return "bool"; + case SLANG_SPEC_BVEC2: + return "bvec2"; + case SLANG_SPEC_BVEC3: + return "bvec3"; + case SLANG_SPEC_BVEC4: + return "bvec4"; + case SLANG_SPEC_INT: + return "int"; + case SLANG_SPEC_IVEC2: + return "ivec2"; + case SLANG_SPEC_IVEC3: + return "ivec3"; + case SLANG_SPEC_IVEC4: + return "ivec4"; + case SLANG_SPEC_FLOAT: + return "float"; + case SLANG_SPEC_VEC2: + return "vec2"; + case SLANG_SPEC_VEC3: + return "vec3"; + case SLANG_SPEC_VEC4: + return "vec4"; + case SLANG_SPEC_MAT2: + return "mat2"; + case SLANG_SPEC_MAT3: + return "mat3"; + case SLANG_SPEC_MAT4: + return "mat4"; + case SLANG_SPEC_SAMPLER_1D: + return "sampler1D"; + case SLANG_SPEC_SAMPLER_2D: + return "sampler2D"; + case SLANG_SPEC_SAMPLER_3D: + return "sampler3D"; + case SLANG_SPEC_SAMPLER_CUBE: + return "samplerCube"; + case SLANG_SPEC_SAMPLER_1D_SHADOW: + return "sampler1DShadow"; + case SLANG_SPEC_SAMPLER_2D_SHADOW: + return "sampler2DShadow"; + case SLANG_SPEC_SAMPLER_RECT: + return "sampler2DRect"; + case SLANG_SPEC_SAMPLER_RECT_SHADOW: + return "sampler2DRectShadow"; + case SLANG_SPEC_STRUCT: + return "struct"; + case SLANG_SPEC_ARRAY: + return "array"; + default: + return "type?"; + } +} + + +static const char * +slang_fq_type_string(const slang_fully_specified_type *t) +{ + static char str[1000]; + _mesa_snprintf(str, sizeof(str), "%s %s", slang_type_qual_string(t->qualifier), + slang_type_string(t->specifier.type)); + return str; +} + + +void +slang_print_type(const slang_fully_specified_type *t) +{ + printf("%s %s", slang_type_qual_string(t->qualifier), + slang_type_string(t->specifier.type)); +} + + +#if 0 +static char * +slang_var_string(const slang_variable *v) +{ + static char str[1000]; + _mesa_snprintf(str, sizeof(str), "%s : %s", + (char *) v->a_name, + slang_fq_type_string(&v->type)); + return str; +} +#endif + + +void +slang_print_variable(const slang_variable *v) +{ + printf("Name: %s\n", (char *) v->a_name); + printf("Type: %s\n", slang_fq_type_string(&v->type)); +} + + +void +_slang_print_var_scope(const slang_variable_scope *vars, int indent) +{ + GLuint i; + + spaces(indent); + printf("Var scope %p %d vars:\n", (void *) vars, vars->num_variables); + for (i = 0; i < vars->num_variables; i++) { + spaces(indent + 3); + printf("%s (at %p)\n", (char *) vars->variables[i]->a_name, (void*) (vars->variables + i)); + } + spaces(indent + 3); + printf("outer_scope = %p\n", (void*) vars->outer_scope); + + if (vars->outer_scope) { + /*spaces(indent + 3);*/ + _slang_print_var_scope(vars->outer_scope, indent + 3); + } +} + + + +int +slang_checksum_tree(const slang_operation *op) +{ + int s = op->num_children; + GLuint i; + + for (i = 0; i < op->num_children; i++) { + s += slang_checksum_tree(&op->children[i]); + } + return s; +} diff --git a/src/mesa/slang/slang_print.h b/src/mesa/slang/slang_print.h new file mode 100644 index 0000000000..46605c8061 --- /dev/null +++ b/src/mesa/slang/slang_print.h @@ -0,0 +1,29 @@ + + +#ifndef SLANG_PRINT +#define SLANG_PRINT + +extern void +slang_print_function(const slang_function *f, GLboolean body); + +extern void +slang_print_tree(const slang_operation *op, int indent); + +extern const char * +slang_type_qual_string(slang_type_qualifier q); + +extern void +slang_print_type(const slang_fully_specified_type *t); + +extern void +slang_print_variable(const slang_variable *v); + +extern void +_slang_print_var_scope(const slang_variable_scope *s, int indent); + + +extern int +slang_checksum_tree(const slang_operation *op); + +#endif /* SLANG_PRINT */ + diff --git a/src/mesa/slang/slang_simplify.c b/src/mesa/slang/slang_simplify.c new file mode 100644 index 0000000000..13b9ca3c87 --- /dev/null +++ b/src/mesa/slang/slang_simplify.c @@ -0,0 +1,527 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Functions for constant folding, built-in constant lookup, and function + * call casting. + */ + + +#include "main/imports.h" +#include "main/macros.h" +#include "main/get.h" +#include "slang_compile.h" +#include "slang_codegen.h" +#include "slang_simplify.h" +#include "slang_print.h" + + +#ifndef GL_MAX_FRAGMENT_UNIFORM_VECTORS +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#endif +#ifndef GL_MAX_VERTEX_UNIFORM_VECTORS +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#endif +#ifndef GL_MAX_VARYING_VECTORS +#define GL_MAX_VARYING_VECTORS 0x8DFC +#endif + + +/** + * Lookup the value of named constant, such as gl_MaxLights. + * \return value of constant, or -1 if unknown + */ +GLint +_slang_lookup_constant(const char *name) +{ + struct constant_info { + const char *Name; + const GLenum Token; + }; + static const struct constant_info info[] = { + { "gl_MaxClipPlanes", GL_MAX_CLIP_PLANES }, + { "gl_MaxCombinedTextureImageUnits", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS }, + { "gl_MaxDrawBuffers", GL_MAX_DRAW_BUFFERS }, + { "gl_MaxFragmentUniformComponents", GL_MAX_FRAGMENT_UNIFORM_COMPONENTS }, + { "gl_MaxLights", GL_MAX_LIGHTS }, + { "gl_MaxTextureUnits", GL_MAX_TEXTURE_UNITS }, + { "gl_MaxTextureCoords", GL_MAX_TEXTURE_COORDS }, + { "gl_MaxVertexAttribs", GL_MAX_VERTEX_ATTRIBS }, + { "gl_MaxVertexUniformComponents", GL_MAX_VERTEX_UNIFORM_COMPONENTS }, + { "gl_MaxVaryingFloats", GL_MAX_VARYING_FLOATS }, + { "gl_MaxVertexTextureImageUnits", GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS }, + { "gl_MaxTextureImageUnits", GL_MAX_TEXTURE_IMAGE_UNITS }, +#if FEATURE_es2_glsl + { "gl_MaxVertexUniformVectors", GL_MAX_VERTEX_UNIFORM_VECTORS }, + { "gl_MaxVaryingVectors", GL_MAX_VARYING_VECTORS }, + { "gl_MaxFragmentUniformVectors", GL_MAX_FRAGMENT_UNIFORM_VECTORS }, +#endif + { NULL, 0 } + }; + GLuint i; + + for (i = 0; info[i].Name; i++) { + if (strcmp(info[i].Name, name) == 0) { + /* found */ + GLint values[16]; + values[0] = -1; + _mesa_GetIntegerv(info[i].Token, values); + ASSERT(values[0] >= 0); /* sanity check that glGetFloatv worked */ + return values[0]; + } + } + return -1; +} + + +static slang_operation_type +literal_type(slang_operation_type t1, slang_operation_type t2) +{ + if (t1 == SLANG_OPER_LITERAL_FLOAT || t2 == SLANG_OPER_LITERAL_FLOAT) + return SLANG_OPER_LITERAL_FLOAT; + else + return SLANG_OPER_LITERAL_INT; +} + + +/** + * Recursively traverse an AST tree, applying simplifications wherever + * possible. + * At the least, we do constant folding. We need to do that much so that + * compile-time expressions can be evaluated for things like array + * declarations. I.e.: float foo[3 + 5]; + */ +void +_slang_simplify(slang_operation *oper, + const slang_name_space * space, + slang_atom_pool * atoms) +{ + GLboolean isFloat[4]; + GLboolean isBool[4]; + GLuint i, n; + + if (oper->type == SLANG_OPER_IDENTIFIER) { + /* see if it's a named constant */ + GLint value = _slang_lookup_constant((char *) oper->a_id); + /*printf("value[%s] = %d\n", (char*) oper->a_id, value);*/ + if (value >= 0) { + oper->literal[0] = + oper->literal[1] = + oper->literal[2] = + oper->literal[3] = (GLfloat) value; + oper->type = SLANG_OPER_LITERAL_INT; + return; + } + /* look for user-defined constant */ + { + slang_variable *var; + var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); + if (var) { + if (var->type.qualifier == SLANG_QUAL_CONST && + var->initializer && + (var->initializer->type == SLANG_OPER_LITERAL_INT || + var->initializer->type == SLANG_OPER_LITERAL_FLOAT)) { + oper->literal[0] = var->initializer->literal[0]; + oper->literal[1] = var->initializer->literal[1]; + oper->literal[2] = var->initializer->literal[2]; + oper->literal[3] = var->initializer->literal[3]; + oper->literal_size = var->initializer->literal_size; + oper->type = var->initializer->type; + /* + printf("value[%s] = %f\n", + (char*) oper->a_id, oper->literal[0]); + */ + return; + } + } + } + } + + /* first, simplify children */ + for (i = 0; i < oper->num_children; i++) { + _slang_simplify(&oper->children[i], space, atoms); + } + + /* examine children */ + n = MIN2(oper->num_children, 4); + for (i = 0; i < n; i++) { + isFloat[i] = (oper->children[i].type == SLANG_OPER_LITERAL_FLOAT || + oper->children[i].type == SLANG_OPER_LITERAL_INT); + isBool[i] = (oper->children[i].type == SLANG_OPER_LITERAL_BOOL); + } + + if (oper->num_children == 2 && isFloat[0] && isFloat[1]) { + /* probably simple arithmetic */ + switch (oper->type) { + case SLANG_OPER_ADD: + for (i = 0; i < 4; i++) { + oper->literal[i] + = oper->children[0].literal[i] + oper->children[1].literal[i]; + } + oper->literal_size = oper->children[0].literal_size; + oper->type = literal_type(oper->children[0].type, + oper->children[1].type); + slang_operation_destruct(oper); /* frees unused children */ + return; + case SLANG_OPER_SUBTRACT: + for (i = 0; i < 4; i++) { + oper->literal[i] + = oper->children[0].literal[i] - oper->children[1].literal[i]; + } + oper->literal_size = oper->children[0].literal_size; + oper->type = literal_type(oper->children[0].type, + oper->children[1].type); + slang_operation_destruct(oper); + return; + case SLANG_OPER_MULTIPLY: + for (i = 0; i < 4; i++) { + oper->literal[i] + = oper->children[0].literal[i] * oper->children[1].literal[i]; + } + oper->literal_size = oper->children[0].literal_size; + oper->type = literal_type(oper->children[0].type, + oper->children[1].type); + slang_operation_destruct(oper); + return; + case SLANG_OPER_DIVIDE: + for (i = 0; i < 4; i++) { + oper->literal[i] + = oper->children[0].literal[i] / oper->children[1].literal[i]; + } + oper->literal_size = oper->children[0].literal_size; + oper->type = literal_type(oper->children[0].type, + oper->children[1].type); + slang_operation_destruct(oper); + return; + default: + ; /* nothing */ + } + } + + if (oper->num_children == 1 && isFloat[0]) { + switch (oper->type) { + case SLANG_OPER_MINUS: + for (i = 0; i < 4; i++) { + oper->literal[i] = -oper->children[0].literal[i]; + } + oper->literal_size = oper->children[0].literal_size; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_FLOAT; + return; + case SLANG_OPER_PLUS: + COPY_4V(oper->literal, oper->children[0].literal); + oper->literal_size = oper->children[0].literal_size; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_FLOAT; + return; + default: + ; /* nothing */ + } + } + + if (oper->num_children == 2 && isBool[0] && isBool[1]) { + /* simple boolean expression */ + switch (oper->type) { + case SLANG_OPER_LOGICALAND: + for (i = 0; i < 4; i++) { + const GLint a = oper->children[0].literal[i] ? 1 : 0; + const GLint b = oper->children[1].literal[i] ? 1 : 0; + oper->literal[i] = (GLfloat) (a && b); + } + oper->literal_size = oper->children[0].literal_size; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_BOOL; + return; + case SLANG_OPER_LOGICALOR: + for (i = 0; i < 4; i++) { + const GLint a = oper->children[0].literal[i] ? 1 : 0; + const GLint b = oper->children[1].literal[i] ? 1 : 0; + oper->literal[i] = (GLfloat) (a || b); + } + oper->literal_size = oper->children[0].literal_size; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_BOOL; + return; + case SLANG_OPER_LOGICALXOR: + for (i = 0; i < 4; i++) { + const GLint a = oper->children[0].literal[i] ? 1 : 0; + const GLint b = oper->children[1].literal[i] ? 1 : 0; + oper->literal[i] = (GLfloat) (a ^ b); + } + oper->literal_size = oper->children[0].literal_size; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_BOOL; + return; + default: + ; /* nothing */ + } + } + + if (oper->num_children == 4 + && isFloat[0] && isFloat[1] && isFloat[2] && isFloat[3]) { + /* vec4(flt, flt, flt, flt) constructor */ + if (oper->type == SLANG_OPER_CALL) { + if (strcmp((char *) oper->a_id, "vec4") == 0) { + oper->literal[0] = oper->children[0].literal[0]; + oper->literal[1] = oper->children[1].literal[0]; + oper->literal[2] = oper->children[2].literal[0]; + oper->literal[3] = oper->children[3].literal[0]; + oper->literal_size = 4; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_FLOAT; + return; + } + } + } + + if (oper->num_children == 3 && isFloat[0] && isFloat[1] && isFloat[2]) { + /* vec3(flt, flt, flt) constructor */ + if (oper->type == SLANG_OPER_CALL) { + if (strcmp((char *) oper->a_id, "vec3") == 0) { + oper->literal[0] = oper->children[0].literal[0]; + oper->literal[1] = oper->children[1].literal[0]; + oper->literal[2] = oper->children[2].literal[0]; + oper->literal[3] = oper->literal[2]; + oper->literal_size = 3; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_FLOAT; + return; + } + } + } + + if (oper->num_children == 2 && isFloat[0] && isFloat[1]) { + /* vec2(flt, flt) constructor */ + if (oper->type == SLANG_OPER_CALL) { + if (strcmp((char *) oper->a_id, "vec2") == 0) { + oper->literal[0] = oper->children[0].literal[0]; + oper->literal[1] = oper->children[1].literal[0]; + oper->literal[2] = oper->literal[1]; + oper->literal[3] = oper->literal[1]; + oper->literal_size = 2; + slang_operation_destruct(oper); /* XXX oper->locals goes NULL! */ + oper->type = SLANG_OPER_LITERAL_FLOAT; + assert(oper->num_children == 0); + return; + } + } + } + + if (oper->num_children == 1 && isFloat[0]) { + /* vec2/3/4(flt, flt) constructor */ + if (oper->type == SLANG_OPER_CALL) { + const char *func = (const char *) oper->a_id; + if (strncmp(func, "vec", 3) == 0 && func[3] >= '2' && func[3] <= '4') { + oper->literal[0] = + oper->literal[1] = + oper->literal[2] = + oper->literal[3] = oper->children[0].literal[0]; + oper->literal_size = func[3] - '0'; + assert(oper->literal_size >= 2); + assert(oper->literal_size <= 4); + slang_operation_destruct(oper); /* XXX oper->locals goes NULL! */ + oper->type = SLANG_OPER_LITERAL_FLOAT; + assert(oper->num_children == 0); + return; + } + } + } +} + + + +/** + * Insert casts to try to adapt actual parameters to formal parameters for a + * function call when an exact match for the parameter types is not found. + * Example: + * void foo(int i, bool b) {} + * x = foo(3.15, 9); + * Gets translated into: + * x = foo(int(3.15), bool(9)) + */ +GLboolean +_slang_cast_func_params(slang_operation *callOper, const slang_function *fun, + const slang_name_space * space, + slang_atom_pool * atoms, slang_info_log *log) +{ + const GLboolean haveRetValue = _slang_function_has_return_value(fun); + const int numParams = fun->param_count - haveRetValue; + int i; + int dbg = 0; + + if (dbg) + printf("Adapt call of %d args to func %s (%d params)\n", + callOper->num_children, (char*) fun->header.a_name, numParams); + + for (i = 0; i < numParams; i++) { + slang_typeinfo argType; + slang_variable *paramVar = fun->parameters->variables[i]; + + /* Get type of arg[i] */ + if (!slang_typeinfo_construct(&argType)) + return GL_FALSE; + if (!_slang_typeof_operation(&callOper->children[i], space, + &argType, atoms, log)) { + slang_typeinfo_destruct(&argType); + return GL_FALSE; + } + + /* see if arg type matches parameter type */ + if (!slang_type_specifier_equal(&argType.spec, + ¶mVar->type.specifier)) { + /* need to adapt arg type to match param type */ + const char *constructorName = + slang_type_specifier_type_to_string(paramVar->type.specifier.type); + slang_operation *child = slang_operation_new(1); + + if (dbg) + printf("Need to adapt types of arg %d\n", i); + + slang_operation_copy(child, &callOper->children[i]); + child->locals->outer_scope = callOper->children[i].locals; + +#if 0 + if (_slang_sizeof_type_specifier(&argType.spec) > + _slang_sizeof_type_specifier(¶mVar->type.specifier)) { + } +#endif + + callOper->children[i].type = SLANG_OPER_CALL; + callOper->children[i].a_id = slang_atom_pool_atom(atoms, constructorName); + callOper->children[i].num_children = 1; + callOper->children[i].children = child; + } + + slang_typeinfo_destruct(&argType); + } + + if (dbg) { + printf("===== New call to %s with cast arguments ===============\n", + (char*) fun->header.a_name); + slang_print_tree(callOper, 5); + } + + return GL_TRUE; +} + + +/** + * Adapt the arguments for a function call to match the parameters of + * the given function. + * This is for: + * 1. converting/casting argument types to match parameters + * 2. breaking up vector/matrix types into individual components to + * satisfy constructors. + */ +GLboolean +_slang_adapt_call(slang_operation *callOper, const slang_function *fun, + const slang_name_space * space, + slang_atom_pool * atoms, slang_info_log *log) +{ + const GLboolean haveRetValue = _slang_function_has_return_value(fun); + const int numParams = fun->param_count - haveRetValue; + int i; + int dbg = 0; + + if (dbg) + printf("Adapt %d args to %d parameters for %s\n", + callOper->num_children, numParams, (char *) fun->header.a_name); + + /* Only try adapting for constructors */ + if (fun->kind != SLANG_FUNC_CONSTRUCTOR) + return GL_FALSE; + + if (callOper->num_children != numParams) { + /* number of arguments doesn't match number of parameters */ + + /* For constructor calls, we can try to unroll vector/matrix args + * into individual floats/ints and try to match the function params. + */ + for (i = 0; i < numParams; i++) { + slang_typeinfo argType; + GLint argSz, j; + + /* Get type of arg[i] */ + if (!slang_typeinfo_construct(&argType)) + return GL_FALSE; + if (!_slang_typeof_operation(&callOper->children[i], space, + &argType, atoms, log)) { + slang_typeinfo_destruct(&argType); + return GL_FALSE; + } + + /* + paramSz = _slang_sizeof_type_specifier(¶mVar->type.specifier); + assert(paramSz == 1); + */ + argSz = _slang_sizeof_type_specifier(&argType.spec); + if (argSz > 1) { + slang_operation origArg; + /* break up arg[i] into components */ + if (dbg) + printf("Break up arg %d from 1 to %d elements\n", i, argSz); + + slang_operation_construct(&origArg); + slang_operation_copy(&origArg, &callOper->children[i]); + + /* insert argSz-1 new children/args */ + for (j = 0; j < argSz - 1; j++) { + (void) slang_operation_insert(&callOper->num_children, + &callOper->children, i); + } + + /* replace arg[i+j] with subscript/index oper */ + for (j = 0; j < argSz; j++) { + callOper->children[i + j].type = SLANG_OPER_SUBSCRIPT; + callOper->children[i + j].locals = _slang_variable_scope_new(callOper->locals); + callOper->children[i + j].num_children = 2; + callOper->children[i + j].children = slang_operation_new(2); + slang_operation_copy(&callOper->children[i + j].children[0], + &origArg); + callOper->children[i + j].children[1].type + = SLANG_OPER_LITERAL_INT; + callOper->children[i + j].children[1].literal[0] = (GLfloat) j; + } + } + } + } + + if (callOper->num_children < (GLuint) numParams) { + /* still not enough args for all params */ + return GL_FALSE; + } + else if (callOper->num_children > (GLuint) numParams) { + /* now too many arguments */ + /* just truncate */ + callOper->num_children = (GLuint) numParams; + } + + if (dbg) { + printf("===== New call to %s with adapted arguments ===============\n", + (char*) fun->header.a_name); + slang_print_tree(callOper, 5); + } + + return GL_TRUE; +} diff --git a/src/mesa/slang/slang_simplify.h b/src/mesa/slang/slang_simplify.h new file mode 100644 index 0000000000..8689c23b1a --- /dev/null +++ b/src/mesa/slang/slang_simplify.h @@ -0,0 +1,50 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_SIMPLIFY_H +#define SLANG_SIMPLIFY_H + + +extern GLint +_slang_lookup_constant(const char *name); + + +extern void +_slang_simplify(slang_operation *oper, + const slang_name_space * space, + slang_atom_pool * atoms); + + +extern GLboolean +_slang_cast_func_params(slang_operation *callOper, const slang_function *fun, + const slang_name_space * space, + slang_atom_pool * atoms, slang_info_log *log); + +extern GLboolean +_slang_adapt_call(slang_operation *callOper, const slang_function *fun, + const slang_name_space * space, + slang_atom_pool * atoms, slang_info_log *log); + + +#endif /* SLANG_SIMPLIFY_H */ diff --git a/src/mesa/slang/slang_storage.c b/src/mesa/slang/slang_storage.c new file mode 100644 index 0000000000..656e15670d --- /dev/null +++ b/src/mesa/slang/slang_storage.c @@ -0,0 +1,321 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_storage.c + * slang variable storage + * \author Michal Krol + */ + +#include "main/imports.h" +#include "slang_storage.h" +#include "slang_mem.h" + +/* slang_storage_array */ + +GLboolean +slang_storage_array_construct(slang_storage_array * arr) +{ + arr->type = SLANG_STORE_AGGREGATE; + arr->aggregate = NULL; + arr->length = 0; + return GL_TRUE; +} + +GLvoid +slang_storage_array_destruct(slang_storage_array * arr) +{ + if (arr->aggregate != NULL) { + slang_storage_aggregate_destruct(arr->aggregate); + _slang_free(arr->aggregate); + } +} + +/* slang_storage_aggregate */ + +GLboolean +slang_storage_aggregate_construct(slang_storage_aggregate * agg) +{ + agg->arrays = NULL; + agg->count = 0; + return GL_TRUE; +} + +GLvoid +slang_storage_aggregate_destruct(slang_storage_aggregate * agg) +{ + GLuint i; + + for (i = 0; i < agg->count; i++) + slang_storage_array_destruct(agg->arrays + i); + _slang_free(agg->arrays); +} + +static slang_storage_array * +slang_storage_aggregate_push_new(slang_storage_aggregate * agg) +{ + slang_storage_array *arr = NULL; + + agg->arrays = (slang_storage_array *) + _slang_realloc(agg->arrays, + agg->count * sizeof(slang_storage_array), + (agg->count + 1) * sizeof(slang_storage_array)); + if (agg->arrays != NULL) { + arr = agg->arrays + agg->count; + if (!slang_storage_array_construct(arr)) + return NULL; + agg->count++; + } + return arr; +} + +/* _slang_aggregate_variable() */ + +static GLboolean +aggregate_vector(slang_storage_aggregate * agg, slang_storage_type basic_type, + GLuint row_count) +{ + slang_storage_array *arr = slang_storage_aggregate_push_new(agg); + if (arr == NULL) + return GL_FALSE; + arr->type = basic_type; + arr->length = row_count; + return GL_TRUE; +} + +static GLboolean +aggregate_matrix(slang_storage_aggregate * agg, slang_storage_type basic_type, + GLuint columns, GLuint rows) +{ + slang_storage_array *arr = slang_storage_aggregate_push_new(agg); + if (arr == NULL) + return GL_FALSE; + arr->type = SLANG_STORE_AGGREGATE; + arr->length = columns; + arr->aggregate = (slang_storage_aggregate *) + _slang_alloc(sizeof(slang_storage_aggregate)); + if (arr->aggregate == NULL) + return GL_FALSE; + if (!slang_storage_aggregate_construct(arr->aggregate)) { + _slang_free(arr->aggregate); + arr->aggregate = NULL; + return GL_FALSE; + } + if (!aggregate_vector(arr->aggregate, basic_type, rows)) + return GL_FALSE; + return GL_TRUE; +} + + +static GLboolean +aggregate_variables(slang_storage_aggregate * agg, + slang_variable_scope * vars, slang_function_scope * funcs, + slang_struct_scope * structs, + slang_variable_scope * globals, + slang_atom_pool * atoms) +{ + GLuint i; + + for (i = 0; i < vars->num_variables; i++) + if (!_slang_aggregate_variable(agg, &vars->variables[i]->type.specifier, + vars->variables[i]->array_len, funcs, + structs, globals, atoms)) + return GL_FALSE; + return GL_TRUE; +} + + +GLboolean +_slang_aggregate_variable(slang_storage_aggregate * agg, + slang_type_specifier * spec, GLuint array_len, + slang_function_scope * funcs, + slang_struct_scope * structs, + slang_variable_scope * vars, + slang_atom_pool * atoms) +{ + switch (spec->type) { + case SLANG_SPEC_BOOL: + return aggregate_vector(agg, SLANG_STORE_BOOL, 1); + case SLANG_SPEC_BVEC2: + return aggregate_vector(agg, SLANG_STORE_BOOL, 2); + case SLANG_SPEC_BVEC3: + return aggregate_vector(agg, SLANG_STORE_BOOL, 3); + case SLANG_SPEC_BVEC4: + return aggregate_vector(agg, SLANG_STORE_BOOL, 4); + case SLANG_SPEC_INT: + return aggregate_vector(agg, SLANG_STORE_INT, 1); + case SLANG_SPEC_IVEC2: + return aggregate_vector(agg, SLANG_STORE_INT, 2); + case SLANG_SPEC_IVEC3: + return aggregate_vector(agg, SLANG_STORE_INT, 3); + case SLANG_SPEC_IVEC4: + return aggregate_vector(agg, SLANG_STORE_INT, 4); + case SLANG_SPEC_FLOAT: + return aggregate_vector(agg, SLANG_STORE_FLOAT, 1); + case SLANG_SPEC_VEC2: + return aggregate_vector(agg, SLANG_STORE_FLOAT, 2); + case SLANG_SPEC_VEC3: + return aggregate_vector(agg, SLANG_STORE_FLOAT, 3); + case SLANG_SPEC_VEC4: + return aggregate_vector(agg, SLANG_STORE_FLOAT, 4); + case SLANG_SPEC_MAT2: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 2, 2); + case SLANG_SPEC_MAT3: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 3, 3); + case SLANG_SPEC_MAT4: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 4, 4); + + case SLANG_SPEC_MAT23: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 2, 3); + case SLANG_SPEC_MAT32: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 3, 2); + case SLANG_SPEC_MAT24: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 2, 4); + case SLANG_SPEC_MAT42: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 4, 2); + case SLANG_SPEC_MAT34: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 3, 4); + case SLANG_SPEC_MAT43: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 4, 3); + + case SLANG_SPEC_SAMPLER_1D: + case SLANG_SPEC_SAMPLER_2D: + case SLANG_SPEC_SAMPLER_3D: + case SLANG_SPEC_SAMPLER_CUBE: + case SLANG_SPEC_SAMPLER_1D_SHADOW: + case SLANG_SPEC_SAMPLER_2D_SHADOW: + case SLANG_SPEC_SAMPLER_RECT: + case SLANG_SPEC_SAMPLER_RECT_SHADOW: + case SLANG_SPEC_SAMPLER_1D_ARRAY: + case SLANG_SPEC_SAMPLER_2D_ARRAY: + case SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW: + case SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW: + + return aggregate_vector(agg, SLANG_STORE_INT, 1); + case SLANG_SPEC_STRUCT: + return aggregate_variables(agg, spec->_struct->fields, funcs, structs, + vars, atoms); + case SLANG_SPEC_ARRAY: + { + slang_storage_array *arr; + + arr = slang_storage_aggregate_push_new(agg); + if (arr == NULL) + return GL_FALSE; + arr->type = SLANG_STORE_AGGREGATE; + arr->aggregate = (slang_storage_aggregate *) + _slang_alloc(sizeof(slang_storage_aggregate)); + if (arr->aggregate == NULL) + return GL_FALSE; + if (!slang_storage_aggregate_construct(arr->aggregate)) { + _slang_free(arr->aggregate); + arr->aggregate = NULL; + return GL_FALSE; + } + if (!_slang_aggregate_variable(arr->aggregate, spec->_array, 0, + funcs, structs, vars, atoms)) + return GL_FALSE; + arr->length = array_len; + /* TODO: check if 0 < arr->length <= 65535 */ + } + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +GLuint +_slang_sizeof_type(slang_storage_type type) +{ + if (type == SLANG_STORE_AGGREGATE) + return 0; + if (type == SLANG_STORE_VEC4) + return 4 * sizeof(GLfloat); + return sizeof(GLfloat); +} + + +GLuint +_slang_sizeof_aggregate(const slang_storage_aggregate * agg) +{ + GLuint i, size = 0; + + for (i = 0; i < agg->count; i++) { + slang_storage_array *arr = &agg->arrays[i]; + GLuint element_size; + + if (arr->type == SLANG_STORE_AGGREGATE) + element_size = _slang_sizeof_aggregate(arr->aggregate); + else + element_size = _slang_sizeof_type(arr->type); + size += element_size * arr->length; + } + return size; +} + + +#if 0 +GLboolean +_slang_flatten_aggregate(slang_storage_aggregate * flat, + const slang_storage_aggregate * agg) +{ + GLuint i; + + for (i = 0; i < agg->count; i++) { + GLuint j; + + for (j = 0; j < agg->arrays[i].length; j++) { + if (agg->arrays[i].type == SLANG_STORE_AGGREGATE) { + if (!_slang_flatten_aggregate(flat, agg->arrays[i].aggregate)) + return GL_FALSE; + } + else { + GLuint k, count; + slang_storage_type type; + + if (agg->arrays[i].type == SLANG_STORE_VEC4) { + count = 4; + type = SLANG_STORE_FLOAT; + } + else { + count = 1; + type = agg->arrays[i].type; + } + + for (k = 0; k < count; k++) { + slang_storage_array *arr; + + arr = slang_storage_aggregate_push_new(flat); + if (arr == NULL) + return GL_FALSE; + arr->type = type; + arr->length = 1; + } + } + } + } + return GL_TRUE; +} +#endif diff --git a/src/mesa/slang/slang_storage.h b/src/mesa/slang/slang_storage.h new file mode 100644 index 0000000000..1876a36dd6 --- /dev/null +++ b/src/mesa/slang/slang_storage.h @@ -0,0 +1,139 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_STORAGE_H +#define SLANG_STORAGE_H + +#include "slang_compile.h" + + +/* + * Program variable data storage is kept completely transparent to the + * front-end compiler. It is up to the back-end how the data is + * actually allocated. The slang_storage_type enum provides the basic + * information about how the memory is interpreted. This abstract + * piece of memory is called a data slot. A data slot of a particular + * type has a fixed size. + * + * For now, only the three basic types are supported, that is bool, + * int and float. Other built-in types like vector or matrix can + * easily be decomposed into a series of basic types. + * + * If the vec4 module is enabled, 4-component vectors of floats are + * used when possible. 4x4 matrices are constructed of 4 vec4 slots. + */ +typedef enum slang_storage_type_ +{ + /* core */ + SLANG_STORE_AGGREGATE, + SLANG_STORE_BOOL, + SLANG_STORE_INT, + SLANG_STORE_FLOAT, + /* vec4 */ + SLANG_STORE_VEC4 +} slang_storage_type; + + +/** + * The slang_storage_array structure groups data slots of the same + * type into an array. This array has a fixed length. Arrays are + * required to have a size equal to the sum of sizes of its + * elements. They are also required to support indirect + * addressing. That is, if B references first data slot in the array, + * S is the size of the data slot and I is the integral index that is + * not known at compile time, B+I*S references I-th data slot. + * + * This structure is also used to break down built-in data types that + * are not supported directly. Vectors, like vec3, are constructed + * from arrays of their basic types. Matrices are formed of an array + * of column vectors, which are in turn processed as other vectors. + */ +typedef struct slang_storage_array_ +{ + slang_storage_type type; + struct slang_storage_aggregate_ *aggregate; + GLuint length; +} slang_storage_array; + +GLboolean slang_storage_array_construct (slang_storage_array *); +GLvoid slang_storage_array_destruct (slang_storage_array *); + + +/** + * The slang_storage_aggregate structure relaxes the indirect + * addressing requirement for slang_storage_array + * structure. Aggregates are always accessed statically - its member + * addresses are well-known at compile time. For example, user-defined + * types are implemented as aggregates. Aggregates can collect data of + * a different type. + */ +typedef struct slang_storage_aggregate_ +{ + slang_storage_array *arrays; + GLuint count; +} slang_storage_aggregate; + +GLboolean slang_storage_aggregate_construct (slang_storage_aggregate *); +GLvoid slang_storage_aggregate_destruct (slang_storage_aggregate *); + + +extern GLboolean +_slang_aggregate_variable(slang_storage_aggregate *agg, + slang_type_specifier *spec, + GLuint array_len, + slang_function_scope *funcs, + slang_struct_scope *structs, + slang_variable_scope *vars, + slang_atom_pool *atoms); + +/* + * Returns the size (in machine units) of the given storage type. + * It is an error to pass-in SLANG_STORE_AGGREGATE. + * Returns 0 on error. + */ +extern GLuint +_slang_sizeof_type (slang_storage_type); + + +/** + * Returns total size (in machine units) of the given aggregate. + * Returns 0 on error. + */ +extern GLuint +_slang_sizeof_aggregate (const slang_storage_aggregate *); + + +#if 0 +/** + * Converts structured aggregate to a flat one, with arrays of generic + * type being one-element long. Returns GL_TRUE on success. Returns + * GL_FALSE otherwise. + */ +extern GLboolean +_slang_flatten_aggregate (slang_storage_aggregate *, + const slang_storage_aggregate *); + +#endif + +#endif /* SLANG_STORAGE_H */ diff --git a/src/mesa/slang/slang_typeinfo.c b/src/mesa/slang/slang_typeinfo.c new file mode 100644 index 0000000000..0f96768b02 --- /dev/null +++ b/src/mesa/slang/slang_typeinfo.c @@ -0,0 +1,1177 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_typeinfo.c + * slang type info + * \author Michal Krol + */ + +#include "main/imports.h" +#include "shader/prog_instruction.h" +#include "slang_typeinfo.h" +#include "slang_compile.h" +#include "slang_log.h" +#include "slang_mem.h" + + +/** + * Checks if a field selector is a general swizzle (an r-value swizzle + * with replicated components or an l-value swizzle mask) for a + * vector. Returns GL_TRUE if this is the case, is filled with + * swizzle information. Returns GL_FALSE otherwise. + */ +GLboolean +_slang_is_swizzle(const char *field, GLuint rows, slang_swizzle * swz) +{ + GLuint i; + GLboolean xyzw = GL_FALSE, rgba = GL_FALSE, stpq = GL_FALSE; + + /* init to undefined. + * We rely on undefined/nil values to distinguish between + * regular swizzles and writemasks. + * For example, the swizzle ".xNNN" is the writemask ".x". + * That's different than the swizzle ".xxxx". + */ + for (i = 0; i < 4; i++) + swz->swizzle[i] = SWIZZLE_NIL; + + /* the swizzle can be at most 4-component long */ + swz->num_components = slang_string_length(field); + if (swz->num_components > 4) + return GL_FALSE; + + for (i = 0; i < swz->num_components; i++) { + /* mark which swizzle group is used */ + switch (field[i]) { + case 'x': + case 'y': + case 'z': + case 'w': + xyzw = GL_TRUE; + break; + case 'r': + case 'g': + case 'b': + case 'a': + rgba = GL_TRUE; + break; + case 's': + case 't': + case 'p': + case 'q': + stpq = GL_TRUE; + break; + default: + return GL_FALSE; + } + + /* collect swizzle component */ + switch (field[i]) { + case 'x': + case 'r': + case 's': + swz->swizzle[i] = 0; + break; + case 'y': + case 'g': + case 't': + swz->swizzle[i] = 1; + break; + case 'z': + case 'b': + case 'p': + swz->swizzle[i] = 2; + break; + case 'w': + case 'a': + case 'q': + swz->swizzle[i] = 3; + break; + } + + /* check if the component is valid for given vector's row count */ + if (rows <= swz->swizzle[i]) + return GL_FALSE; + } + + /* only one swizzle group can be used */ + if ((xyzw && rgba) || (xyzw && stpq) || (rgba && stpq)) + return GL_FALSE; + + return GL_TRUE; +} + + + +/** + * Checks if a general swizzle is an l-value swizzle - these swizzles + * do not have duplicated fields. Returns GL_TRUE if this is a + * swizzle mask. Returns GL_FALSE otherwise + */ +static GLboolean +_slang_is_swizzle_mask(const slang_swizzle * swz, GLuint rows) +{ + GLuint i, c = 0; + + /* the swizzle may not be longer than the vector dim */ + if (swz->num_components > rows) + return GL_FALSE; + + /* the swizzle components cannot be duplicated */ + for (i = 0; i < swz->num_components; i++) { + if ((c & (1 << swz->swizzle[i])) != 0) + return GL_FALSE; + c |= 1 << swz->swizzle[i]; + } + + return GL_TRUE; +} + + +/** + * Combines (multiplies) two swizzles to form single swizzle. + * Example: "vec.wzyx.yx" --> "vec.zw". + */ +static void +_slang_multiply_swizzles(slang_swizzle * dst, const slang_swizzle * left, + const slang_swizzle * right) +{ + GLuint i; + + dst->num_components = right->num_components; + for (i = 0; i < right->num_components; i++) + dst->swizzle[i] = left->swizzle[right->swizzle[i]]; +} + + +typedef struct +{ + const char *name; + slang_type_specifier_type type; +} type_specifier_type_name; + +static const type_specifier_type_name type_specifier_type_names[] = { + {"void", SLANG_SPEC_VOID}, + {"bool", SLANG_SPEC_BOOL}, + {"bvec2", SLANG_SPEC_BVEC2}, + {"bvec3", SLANG_SPEC_BVEC3}, + {"bvec4", SLANG_SPEC_BVEC4}, + {"int", SLANG_SPEC_INT}, + {"ivec2", SLANG_SPEC_IVEC2}, + {"ivec3", SLANG_SPEC_IVEC3}, + {"ivec4", SLANG_SPEC_IVEC4}, + {"float", SLANG_SPEC_FLOAT}, + {"vec2", SLANG_SPEC_VEC2}, + {"vec3", SLANG_SPEC_VEC3}, + {"vec4", SLANG_SPEC_VEC4}, + {"mat2", SLANG_SPEC_MAT2}, + {"mat3", SLANG_SPEC_MAT3}, + {"mat4", SLANG_SPEC_MAT4}, + {"mat2x3", SLANG_SPEC_MAT23}, + {"mat3x2", SLANG_SPEC_MAT32}, + {"mat2x4", SLANG_SPEC_MAT24}, + {"mat4x2", SLANG_SPEC_MAT42}, + {"mat3x4", SLANG_SPEC_MAT34}, + {"mat4x3", SLANG_SPEC_MAT43}, + {"sampler1D", SLANG_SPEC_SAMPLER_1D}, + {"sampler2D", SLANG_SPEC_SAMPLER_2D}, + {"sampler3D", SLANG_SPEC_SAMPLER_3D}, + {"samplerCube", SLANG_SPEC_SAMPLER_CUBE}, + {"sampler1DShadow", SLANG_SPEC_SAMPLER_1D_SHADOW}, + {"sampler2DShadow", SLANG_SPEC_SAMPLER_2D_SHADOW}, + {"sampler2DRect", SLANG_SPEC_SAMPLER_RECT}, + {"sampler2DRectShadow", SLANG_SPEC_SAMPLER_RECT_SHADOW}, + {"sampler1DArray", SLANG_SPEC_SAMPLER_1D_ARRAY}, + {"sampler2DArray", SLANG_SPEC_SAMPLER_2D_ARRAY}, + {"sampler1DArrayShadow", SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW}, + {"sampler2DArrayShadow", SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW}, + {NULL, SLANG_SPEC_VOID} +}; + +slang_type_specifier_type +slang_type_specifier_type_from_string(const char *name) +{ + const type_specifier_type_name *p = type_specifier_type_names; + while (p->name != NULL) { + if (slang_string_compare(p->name, name) == 0) + break; + p++; + } + return p->type; +} + +const char * +slang_type_specifier_type_to_string(slang_type_specifier_type type) +{ + const type_specifier_type_name *p = type_specifier_type_names; + while (p->name != NULL) { + if (p->type == type) + break; + p++; + } + return p->name; +} + +/* slang_fully_specified_type */ + +int +slang_fully_specified_type_construct(slang_fully_specified_type * type) +{ + type->qualifier = SLANG_QUAL_NONE; + slang_type_specifier_ctr(&type->specifier); + return 1; +} + +void +slang_fully_specified_type_destruct(slang_fully_specified_type * type) +{ + slang_type_specifier_dtr(&type->specifier); +} + +int +slang_fully_specified_type_copy(slang_fully_specified_type * x, + const slang_fully_specified_type * y) +{ + slang_fully_specified_type z; + + if (!slang_fully_specified_type_construct(&z)) + return 0; + z.qualifier = y->qualifier; + z.precision = y->precision; + z.variant = y->variant; + z.centroid = y->centroid; + z.layout = y->layout; + z.array_len = y->array_len; + if (!slang_type_specifier_copy(&z.specifier, &y->specifier)) { + slang_fully_specified_type_destruct(&z); + return 0; + } + slang_fully_specified_type_destruct(x); + *x = z; + return 1; +} + + +/** + * Test if two fully specified types are compatible. This is a bit + * looser than testing for equality. We don't check the precision, + * variant, centroid, etc. information. + * XXX this may need some tweaking. + */ +GLboolean +slang_fully_specified_types_compatible(const slang_fully_specified_type * x, + const slang_fully_specified_type * y) +{ + if (!slang_type_specifier_equal(&x->specifier, &y->specifier)) + return GL_FALSE; + + if (x->qualifier == SLANG_QUAL_FIXEDINPUT && + y->qualifier == SLANG_QUAL_VARYING) + ; /* ok */ + else if (x->qualifier != y->qualifier) + return GL_FALSE; + + /* Note: don't compare precision, variant, centroid */ + + /* XXX array length? */ + + return GL_TRUE; +} + + +GLvoid +slang_type_specifier_ctr(slang_type_specifier * self) +{ + self->type = SLANG_SPEC_VOID; + self->_struct = NULL; + self->_array = NULL; +} + +GLvoid +slang_type_specifier_dtr(slang_type_specifier * self) +{ + if (self->_struct != NULL) { + slang_struct_destruct(self->_struct); + _slang_free(self->_struct); + } + if (self->_array != NULL) { + slang_type_specifier_dtr(self->_array); + _slang_free(self->_array); + } +} + +slang_type_specifier * +slang_type_specifier_new(slang_type_specifier_type type, + struct slang_struct_ *_struct, + struct slang_type_specifier_ *_array) +{ + slang_type_specifier *spec = + (slang_type_specifier *) _slang_alloc(sizeof(slang_type_specifier)); + if (spec) { + spec->type = type; + spec->_struct = _struct; + spec->_array = _array; + } + return spec; +} + +GLboolean +slang_type_specifier_copy(slang_type_specifier * x, + const slang_type_specifier * y) +{ + slang_type_specifier z; + + slang_type_specifier_ctr(&z); + z.type = y->type; + if (z.type == SLANG_SPEC_STRUCT) { + z._struct = (slang_struct *) _slang_alloc(sizeof(slang_struct)); + if (z._struct == NULL) { + slang_type_specifier_dtr(&z); + return GL_FALSE; + } + if (!slang_struct_construct(z._struct)) { + _slang_free(z._struct); + slang_type_specifier_dtr(&z); + return GL_FALSE; + } + if (!slang_struct_copy(z._struct, y->_struct)) { + slang_type_specifier_dtr(&z); + return GL_FALSE; + } + } + else if (z.type == SLANG_SPEC_ARRAY) { + z._array = (slang_type_specifier *) + _slang_alloc(sizeof(slang_type_specifier)); + if (z._array == NULL) { + slang_type_specifier_dtr(&z); + return GL_FALSE; + } + slang_type_specifier_ctr(z._array); + if (!slang_type_specifier_copy(z._array, y->_array)) { + slang_type_specifier_dtr(&z); + return GL_FALSE; + } + } + slang_type_specifier_dtr(x); + *x = z; + return GL_TRUE; +} + + +/** + * Test if two types are equal. + */ +GLboolean +slang_type_specifier_equal(const slang_type_specifier * x, + const slang_type_specifier * y) +{ + if (x->type != y->type) + return GL_FALSE; + if (x->type == SLANG_SPEC_STRUCT) + return slang_struct_equal(x->_struct, y->_struct); + if (x->type == SLANG_SPEC_ARRAY) + return slang_type_specifier_equal(x->_array, y->_array); + return GL_TRUE; +} + + +/** + * As above, but allow float/int casting. + */ +GLboolean +slang_type_specifier_compatible(const slang_type_specifier * x, + const slang_type_specifier * y) +{ + /* special case: float == int */ + if (x->type == SLANG_SPEC_INT && y->type == SLANG_SPEC_FLOAT) { + return GL_TRUE; + } + /* XXX may need to add bool/int compatibility, etc */ + + if (x->type != y->type) + return GL_FALSE; + if (x->type == SLANG_SPEC_STRUCT) + return slang_struct_equal(x->_struct, y->_struct); + if (x->type == SLANG_SPEC_ARRAY) + return slang_type_specifier_compatible(x->_array, y->_array); + return GL_TRUE; +} + + +GLboolean +slang_typeinfo_construct(slang_typeinfo * ti) +{ + memset(ti, 0, sizeof(*ti)); + slang_type_specifier_ctr(&ti->spec); + ti->array_len = 0; + return GL_TRUE; +} + +GLvoid +slang_typeinfo_destruct(slang_typeinfo * ti) +{ + slang_type_specifier_dtr(&ti->spec); +} + + + +/** + * Determine the return type of a function. + * \param a_name the function name + * \param param function parameters (overloading) + * \param num_params number of parameters to function + * \param space namespace to search + * \param spec returns the type + * \param funFound returns pointer to the function, or NULL if not found. + * \return GL_TRUE for success, GL_FALSE if failure (bad function name) + */ +static GLboolean +_slang_typeof_function(slang_atom a_name, + slang_operation * params, GLuint num_params, + const slang_name_space * space, + slang_type_specifier * spec, + slang_function **funFound, + slang_atom_pool *atoms, slang_info_log *log) +{ + GLboolean error; + + *funFound = _slang_function_locate(space->funcs, a_name, params, + num_params, space, atoms, log, &error); + if (error) + return GL_FALSE; + + if (!*funFound) + return GL_TRUE; /* yes, not false */ + + return slang_type_specifier_copy(spec, &(*funFound)->header.type.specifier); +} + + +/** + * Determine the type of a math function. + * \param name name of the operator, one of +,-,*,/ or unary - + * \param params array of function parameters + * \param num_params number of parameters + * \param space namespace to use + * \param spec returns the function's type + * \param atoms atom pool + * \return GL_TRUE for success, GL_FALSE if failure + */ +static GLboolean +typeof_math_call(const char *name, slang_operation *call, + const slang_name_space * space, + slang_type_specifier * spec, + slang_atom_pool * atoms, + slang_info_log *log) +{ + if (call->fun) { + /* we've previously resolved this function call */ + slang_type_specifier_copy(spec, &call->fun->header.type.specifier); + return GL_TRUE; + } + else { + slang_atom atom; + slang_function *fun; + + /* number of params: */ + assert(call->num_children == 1 || call->num_children == 2); + + atom = slang_atom_pool_atom(atoms, name); + if (!_slang_typeof_function(atom, call->children, call->num_children, + space, spec, &fun, atoms, log)) + return GL_FALSE; + + if (fun) { + /* Save pointer to save time in future */ + call->fun = fun; + return GL_TRUE; + } + return GL_FALSE; + } +} + + +/** + * Determine the return type of an operation. + * \param op the operation node + * \param space the namespace to use + * \param ti the returned type + * \param atoms atom pool + * \return GL_TRUE for success, GL_FALSE if failure + */ +GLboolean +_slang_typeof_operation(slang_operation * op, + const slang_name_space * space, + slang_typeinfo * ti, + slang_atom_pool * atoms, + slang_info_log *log) +{ + ti->can_be_referenced = GL_FALSE; + ti->is_swizzled = GL_FALSE; + + switch (op->type) { + case SLANG_OPER_BLOCK_NO_NEW_SCOPE: + case SLANG_OPER_BLOCK_NEW_SCOPE: + case SLANG_OPER_ASM: + case SLANG_OPER_BREAK: + case SLANG_OPER_CONTINUE: + case SLANG_OPER_DISCARD: + case SLANG_OPER_RETURN: + case SLANG_OPER_IF: + case SLANG_OPER_WHILE: + case SLANG_OPER_DO: + case SLANG_OPER_FOR: + case SLANG_OPER_VOID: + ti->spec.type = SLANG_SPEC_VOID; + break; + case SLANG_OPER_EXPRESSION: + case SLANG_OPER_ASSIGN: + case SLANG_OPER_ADDASSIGN: + case SLANG_OPER_SUBASSIGN: + case SLANG_OPER_MULASSIGN: + case SLANG_OPER_DIVASSIGN: + case SLANG_OPER_PREINCREMENT: + case SLANG_OPER_PREDECREMENT: + if (!_slang_typeof_operation(op->children, space, ti, atoms, log)) + return GL_FALSE; + break; + case SLANG_OPER_LITERAL_BOOL: + if (op->literal_size == 1) + ti->spec.type = SLANG_SPEC_BOOL; + else if (op->literal_size == 2) + ti->spec.type = SLANG_SPEC_BVEC2; + else if (op->literal_size == 3) + ti->spec.type = SLANG_SPEC_BVEC3; + else if (op->literal_size == 4) + ti->spec.type = SLANG_SPEC_BVEC4; + else { + _mesa_problem(NULL, + "Unexpected bool literal_size %d in _slang_typeof_operation()", + op->literal_size); + ti->spec.type = SLANG_SPEC_BOOL; + } + break; + case SLANG_OPER_LOGICALOR: + case SLANG_OPER_LOGICALXOR: + case SLANG_OPER_LOGICALAND: + case SLANG_OPER_EQUAL: + case SLANG_OPER_NOTEQUAL: + case SLANG_OPER_LESS: + case SLANG_OPER_GREATER: + case SLANG_OPER_LESSEQUAL: + case SLANG_OPER_GREATEREQUAL: + case SLANG_OPER_NOT: + ti->spec.type = SLANG_SPEC_BOOL; + break; + case SLANG_OPER_LITERAL_INT: + if (op->literal_size == 1) + ti->spec.type = SLANG_SPEC_INT; + else if (op->literal_size == 2) + ti->spec.type = SLANG_SPEC_IVEC2; + else if (op->literal_size == 3) + ti->spec.type = SLANG_SPEC_IVEC3; + else if (op->literal_size == 4) + ti->spec.type = SLANG_SPEC_IVEC4; + else { + _mesa_problem(NULL, + "Unexpected int literal_size %d in _slang_typeof_operation()", + op->literal_size); + ti->spec.type = SLANG_SPEC_INT; + } + break; + case SLANG_OPER_LITERAL_FLOAT: + if (op->literal_size == 1) + ti->spec.type = SLANG_SPEC_FLOAT; + else if (op->literal_size == 2) + ti->spec.type = SLANG_SPEC_VEC2; + else if (op->literal_size == 3) + ti->spec.type = SLANG_SPEC_VEC3; + else if (op->literal_size == 4) + ti->spec.type = SLANG_SPEC_VEC4; + else { + _mesa_problem(NULL, + "Unexpected float literal_size %d in _slang_typeof_operation()", + op->literal_size); + ti->spec.type = SLANG_SPEC_FLOAT; + } + break; + case SLANG_OPER_IDENTIFIER: + case SLANG_OPER_VARIABLE_DECL: + { + slang_variable *var; + var = _slang_variable_locate(op->locals, op->a_id, GL_TRUE); + if (!var) { + slang_info_log_error(log, "undefined variable '%s'", + (char *) op->a_id); + return GL_FALSE; + } + if (!slang_type_specifier_copy(&ti->spec, &var->type.specifier)) { + slang_info_log_memory(log); + return GL_FALSE; + } + ti->can_be_referenced = GL_TRUE; + if (var->type.specifier.type == SLANG_SPEC_ARRAY && + var->type.array_len >= 1) { + /* the datatype is an array, ex: float[3] x; */ + ti->array_len = var->type.array_len; + } + else { + /* the variable is an array, ex: float x[3]; */ + ti->array_len = var->array_len; + } + } + break; + case SLANG_OPER_SEQUENCE: + /* TODO: check [0] and [1] if they match */ + if (!_slang_typeof_operation(&op->children[1], space, ti, atoms, log)) { + return GL_FALSE; + } + ti->can_be_referenced = GL_FALSE; + ti->is_swizzled = GL_FALSE; + break; + /*case SLANG_OPER_MODASSIGN: */ + /*case SLANG_OPER_LSHASSIGN: */ + /*case SLANG_OPER_RSHASSIGN: */ + /*case SLANG_OPER_ORASSIGN: */ + /*case SLANG_OPER_XORASSIGN: */ + /*case SLANG_OPER_ANDASSIGN: */ + case SLANG_OPER_SELECT: + /* TODO: check [1] and [2] if they match */ + if (!_slang_typeof_operation(&op->children[1], space, ti, atoms, log)) { + return GL_FALSE; + } + ti->can_be_referenced = GL_FALSE; + ti->is_swizzled = GL_FALSE; + break; + /*case SLANG_OPER_BITOR: */ + /*case SLANG_OPER_BITXOR: */ + /*case SLANG_OPER_BITAND: */ + /*case SLANG_OPER_LSHIFT: */ + /*case SLANG_OPER_RSHIFT: */ + case SLANG_OPER_ADD: + assert(op->num_children == 2); + if (!typeof_math_call("+", op, space, &ti->spec, atoms, log)) + return GL_FALSE; + break; + case SLANG_OPER_SUBTRACT: + assert(op->num_children == 2); + if (!typeof_math_call("-", op, space, &ti->spec, atoms, log)) + return GL_FALSE; + break; + case SLANG_OPER_MULTIPLY: + assert(op->num_children == 2); + if (!typeof_math_call("*", op, space, &ti->spec, atoms, log)) + return GL_FALSE; + break; + case SLANG_OPER_DIVIDE: + assert(op->num_children == 2); + if (!typeof_math_call("/", op, space, &ti->spec, atoms, log)) + return GL_FALSE; + break; + /*case SLANG_OPER_MODULUS: */ + case SLANG_OPER_PLUS: + if (!_slang_typeof_operation(op->children, space, ti, atoms, log)) + return GL_FALSE; + ti->can_be_referenced = GL_FALSE; + ti->is_swizzled = GL_FALSE; + break; + case SLANG_OPER_MINUS: + assert(op->num_children == 1); + if (!typeof_math_call("-", op, space, &ti->spec, atoms, log)) + return GL_FALSE; + break; + /*case SLANG_OPER_COMPLEMENT: */ + case SLANG_OPER_SUBSCRIPT: + { + slang_typeinfo _ti; + + if (!slang_typeinfo_construct(&_ti)) + return GL_FALSE; + if (!_slang_typeof_operation(op->children, space, &_ti, atoms, log)) { + slang_typeinfo_destruct(&_ti); + return GL_FALSE; + } + ti->can_be_referenced = _ti.can_be_referenced; + if (_ti.spec.type == SLANG_SPEC_ARRAY) { + if (!slang_type_specifier_copy(&ti->spec, _ti.spec._array)) { + slang_typeinfo_destruct(&_ti); + return GL_FALSE; + } + } + else { + if (!_slang_type_is_vector(_ti.spec.type) + && !_slang_type_is_matrix(_ti.spec.type)) { + slang_typeinfo_destruct(&_ti); + slang_info_log_error(log, "cannot index a non-array type"); + return GL_FALSE; + } + ti->spec.type = _slang_type_base(_ti.spec.type); + } + slang_typeinfo_destruct(&_ti); + } + break; + case SLANG_OPER_CALL: + if (op->array_constructor) { + /* build array typeinfo */ + ti->spec.type = SLANG_SPEC_ARRAY; + ti->spec._array = (slang_type_specifier *) + _slang_alloc(sizeof(slang_type_specifier)); + slang_type_specifier_ctr(ti->spec._array); + + ti->spec._array->type = + slang_type_specifier_type_from_string((char *) op->a_id); + ti->array_len = op->num_children; + } + else if (op->fun) { + /* we've resolved this call before */ + slang_type_specifier_copy(&ti->spec, &op->fun->header.type.specifier); + } + else { + slang_function *fun; + if (!_slang_typeof_function(op->a_id, op->children, op->num_children, + space, &ti->spec, &fun, atoms, log)) + return GL_FALSE; + if (fun) { + /* save result for future use */ + op->fun = fun; + } + else { + slang_struct *s = + slang_struct_scope_find(space->structs, op->a_id, GL_TRUE); + if (s) { + /* struct initializer */ + ti->spec.type = SLANG_SPEC_STRUCT; + ti->spec._struct = + (slang_struct *) _slang_alloc(sizeof(slang_struct)); + if (ti->spec._struct == NULL) + return GL_FALSE; + if (!slang_struct_construct(ti->spec._struct)) { + _slang_free(ti->spec._struct); + ti->spec._struct = NULL; + return GL_FALSE; + } + if (!slang_struct_copy(ti->spec._struct, s)) + return GL_FALSE; + } + else { + /* float, int, vec4, mat3, etc. constructor? */ + const char *name; + slang_type_specifier_type type; + + name = slang_atom_pool_id(atoms, op->a_id); + type = slang_type_specifier_type_from_string(name); + if (type == SLANG_SPEC_VOID) { + slang_info_log_error(log, "undefined function '%s'", name); + return GL_FALSE; + } + ti->spec.type = type; + } + } + } + break; + case SLANG_OPER_METHOD: + /* at this time, GLSL 1.20 only has one method: array.length() + * which returns an integer. + */ + ti->spec.type = SLANG_SPEC_INT; + break; + case SLANG_OPER_FIELD: + { + slang_typeinfo _ti; + + if (!slang_typeinfo_construct(&_ti)) + return GL_FALSE; + if (!_slang_typeof_operation(op->children, space, &_ti, atoms, log)) { + slang_typeinfo_destruct(&_ti); + return GL_FALSE; + } + if (_ti.spec.type == SLANG_SPEC_STRUCT) { + slang_variable *field; + + field = _slang_variable_locate(_ti.spec._struct->fields, op->a_id, + GL_FALSE); + if (field == NULL) { + slang_typeinfo_destruct(&_ti); + return GL_FALSE; + } + if (!slang_type_specifier_copy(&ti->spec, &field->type.specifier)) { + slang_typeinfo_destruct(&_ti); + return GL_FALSE; + } + ti->can_be_referenced = _ti.can_be_referenced; + ti->array_len = field->array_len; + } + else { + GLuint rows; + const char *swizzle; + slang_type_specifier_type base; + + /* determine the swizzle of the field expression */ + if (!_slang_type_is_vector(_ti.spec.type)) { + slang_typeinfo_destruct(&_ti); + slang_info_log_error(log, "Can't swizzle scalar expression"); + return GL_FALSE; + } + rows = _slang_type_dim(_ti.spec.type); + swizzle = slang_atom_pool_id(atoms, op->a_id); + if (!_slang_is_swizzle(swizzle, rows, &ti->swz)) { + slang_typeinfo_destruct(&_ti); + slang_info_log_error(log, "bad swizzle '%s'", swizzle); + return GL_FALSE; + } + ti->is_swizzled = GL_TRUE; + ti->can_be_referenced = _ti.can_be_referenced + && _slang_is_swizzle_mask(&ti->swz, rows); + if (_ti.is_swizzled) { + slang_swizzle swz; + + /* swizzle the swizzle */ + _slang_multiply_swizzles(&swz, &_ti.swz, &ti->swz); + ti->swz = swz; + } + base = _slang_type_base(_ti.spec.type); + switch (ti->swz.num_components) { + case 1: + ti->spec.type = base; + break; + case 2: + switch (base) { + case SLANG_SPEC_FLOAT: + ti->spec.type = SLANG_SPEC_VEC2; + break; + case SLANG_SPEC_INT: + ti->spec.type = SLANG_SPEC_IVEC2; + break; + case SLANG_SPEC_BOOL: + ti->spec.type = SLANG_SPEC_BVEC2; + break; + default: + break; + } + break; + case 3: + switch (base) { + case SLANG_SPEC_FLOAT: + ti->spec.type = SLANG_SPEC_VEC3; + break; + case SLANG_SPEC_INT: + ti->spec.type = SLANG_SPEC_IVEC3; + break; + case SLANG_SPEC_BOOL: + ti->spec.type = SLANG_SPEC_BVEC3; + break; + default: + break; + } + break; + case 4: + switch (base) { + case SLANG_SPEC_FLOAT: + ti->spec.type = SLANG_SPEC_VEC4; + break; + case SLANG_SPEC_INT: + ti->spec.type = SLANG_SPEC_IVEC4; + break; + case SLANG_SPEC_BOOL: + ti->spec.type = SLANG_SPEC_BVEC4; + break; + default: + break; + } + break; + default: + break; + } + } + slang_typeinfo_destruct(&_ti); + } + break; + case SLANG_OPER_POSTINCREMENT: + case SLANG_OPER_POSTDECREMENT: + if (!_slang_typeof_operation(op->children, space, ti, atoms, log)) + return GL_FALSE; + ti->can_be_referenced = GL_FALSE; + ti->is_swizzled = GL_FALSE; + break; + default: + return GL_FALSE; + } + + return GL_TRUE; +} + + +/** + * Determine if a type is a matrix. + * \return GL_TRUE if is a matrix, GL_FALSE otherwise. + */ +GLboolean +_slang_type_is_matrix(slang_type_specifier_type ty) +{ + switch (ty) { + case SLANG_SPEC_MAT2: + case SLANG_SPEC_MAT3: + case SLANG_SPEC_MAT4: + case SLANG_SPEC_MAT23: + case SLANG_SPEC_MAT32: + case SLANG_SPEC_MAT24: + case SLANG_SPEC_MAT42: + case SLANG_SPEC_MAT34: + case SLANG_SPEC_MAT43: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Determine if a type is a vector. + * \return GL_TRUE if is a vector, GL_FALSE otherwise. + */ +GLboolean +_slang_type_is_vector(slang_type_specifier_type ty) +{ + switch (ty) { + case SLANG_SPEC_VEC2: + case SLANG_SPEC_VEC3: + case SLANG_SPEC_VEC4: + case SLANG_SPEC_IVEC2: + case SLANG_SPEC_IVEC3: + case SLANG_SPEC_IVEC4: + case SLANG_SPEC_BVEC2: + case SLANG_SPEC_BVEC3: + case SLANG_SPEC_BVEC4: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Determine if a type is a float, float vector or float matrix. + * \return GL_TRUE if so, GL_FALSE otherwise + */ +GLboolean +_slang_type_is_float_vec_mat(slang_type_specifier_type ty) +{ + switch (ty) { + case SLANG_SPEC_FLOAT: + case SLANG_SPEC_VEC2: + case SLANG_SPEC_VEC3: + case SLANG_SPEC_VEC4: + case SLANG_SPEC_MAT2: + case SLANG_SPEC_MAT3: + case SLANG_SPEC_MAT4: + case SLANG_SPEC_MAT23: + case SLANG_SPEC_MAT32: + case SLANG_SPEC_MAT24: + case SLANG_SPEC_MAT42: + case SLANG_SPEC_MAT34: + case SLANG_SPEC_MAT43: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Given a vector type, return the type of the vector's elements. + * For a matrix, return the type of the columns. + */ +slang_type_specifier_type +_slang_type_base(slang_type_specifier_type ty) +{ + switch (ty) { + case SLANG_SPEC_FLOAT: + case SLANG_SPEC_VEC2: + case SLANG_SPEC_VEC3: + case SLANG_SPEC_VEC4: + return SLANG_SPEC_FLOAT; + case SLANG_SPEC_INT: + case SLANG_SPEC_IVEC2: + case SLANG_SPEC_IVEC3: + case SLANG_SPEC_IVEC4: + return SLANG_SPEC_INT; + case SLANG_SPEC_BOOL: + case SLANG_SPEC_BVEC2: + case SLANG_SPEC_BVEC3: + case SLANG_SPEC_BVEC4: + return SLANG_SPEC_BOOL; + case SLANG_SPEC_MAT2: + return SLANG_SPEC_VEC2; + case SLANG_SPEC_MAT3: + return SLANG_SPEC_VEC3; + case SLANG_SPEC_MAT4: + return SLANG_SPEC_VEC4; + case SLANG_SPEC_MAT23: + return SLANG_SPEC_VEC3; + case SLANG_SPEC_MAT32: + return SLANG_SPEC_VEC2; + case SLANG_SPEC_MAT24: + return SLANG_SPEC_VEC4; + case SLANG_SPEC_MAT42: + return SLANG_SPEC_VEC2; + case SLANG_SPEC_MAT34: + return SLANG_SPEC_VEC4; + case SLANG_SPEC_MAT43: + return SLANG_SPEC_VEC3; + default: + return SLANG_SPEC_VOID; + } +} + + +/** + * Return the dimensionality of a vector, or for a matrix, return number + * of columns. + */ +GLuint +_slang_type_dim(slang_type_specifier_type ty) +{ + switch (ty) { + case SLANG_SPEC_FLOAT: + case SLANG_SPEC_INT: + case SLANG_SPEC_BOOL: + return 1; + case SLANG_SPEC_VEC2: + case SLANG_SPEC_IVEC2: + case SLANG_SPEC_BVEC2: + case SLANG_SPEC_MAT2: + return 2; + case SLANG_SPEC_VEC3: + case SLANG_SPEC_IVEC3: + case SLANG_SPEC_BVEC3: + case SLANG_SPEC_MAT3: + return 3; + case SLANG_SPEC_VEC4: + case SLANG_SPEC_IVEC4: + case SLANG_SPEC_BVEC4: + case SLANG_SPEC_MAT4: + return 4; + + case SLANG_SPEC_MAT23: + return 2; + case SLANG_SPEC_MAT32: + return 3; + case SLANG_SPEC_MAT24: + return 2; + case SLANG_SPEC_MAT42: + return 4; + case SLANG_SPEC_MAT34: + return 3; + case SLANG_SPEC_MAT43: + return 4; + + default: + return 0; + } +} + + +/** + * Return the GL_* type that corresponds to a SLANG_SPEC_* type. + */ +GLenum +_slang_gltype_from_specifier(const slang_type_specifier *type) +{ + switch (type->type) { + case SLANG_SPEC_BOOL: + return GL_BOOL; + case SLANG_SPEC_BVEC2: + return GL_BOOL_VEC2; + case SLANG_SPEC_BVEC3: + return GL_BOOL_VEC3; + case SLANG_SPEC_BVEC4: + return GL_BOOL_VEC4; + case SLANG_SPEC_INT: + return GL_INT; + case SLANG_SPEC_IVEC2: + return GL_INT_VEC2; + case SLANG_SPEC_IVEC3: + return GL_INT_VEC3; + case SLANG_SPEC_IVEC4: + return GL_INT_VEC4; + case SLANG_SPEC_FLOAT: + return GL_FLOAT; + case SLANG_SPEC_VEC2: + return GL_FLOAT_VEC2; + case SLANG_SPEC_VEC3: + return GL_FLOAT_VEC3; + case SLANG_SPEC_VEC4: + return GL_FLOAT_VEC4; + case SLANG_SPEC_MAT2: + return GL_FLOAT_MAT2; + case SLANG_SPEC_MAT3: + return GL_FLOAT_MAT3; + case SLANG_SPEC_MAT4: + return GL_FLOAT_MAT4; + case SLANG_SPEC_MAT23: + return GL_FLOAT_MAT2x3; + case SLANG_SPEC_MAT32: + return GL_FLOAT_MAT3x2; + case SLANG_SPEC_MAT24: + return GL_FLOAT_MAT2x4; + case SLANG_SPEC_MAT42: + return GL_FLOAT_MAT4x2; + case SLANG_SPEC_MAT34: + return GL_FLOAT_MAT3x4; + case SLANG_SPEC_MAT43: + return GL_FLOAT_MAT4x3; + case SLANG_SPEC_SAMPLER_1D: + return GL_SAMPLER_1D; + case SLANG_SPEC_SAMPLER_2D: + return GL_SAMPLER_2D; + case SLANG_SPEC_SAMPLER_3D: + return GL_SAMPLER_3D; + case SLANG_SPEC_SAMPLER_CUBE: + return GL_SAMPLER_CUBE; + case SLANG_SPEC_SAMPLER_1D_SHADOW: + return GL_SAMPLER_1D_SHADOW; + case SLANG_SPEC_SAMPLER_2D_SHADOW: + return GL_SAMPLER_2D_SHADOW; + case SLANG_SPEC_SAMPLER_RECT: + return GL_SAMPLER_2D_RECT_ARB; + case SLANG_SPEC_SAMPLER_RECT_SHADOW: + return GL_SAMPLER_2D_RECT_SHADOW_ARB; + case SLANG_SPEC_SAMPLER_1D_ARRAY: + return GL_SAMPLER_1D_ARRAY_EXT; + case SLANG_SPEC_SAMPLER_2D_ARRAY: + return GL_SAMPLER_2D_ARRAY_EXT; + case SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW: + return GL_SAMPLER_1D_ARRAY_SHADOW_EXT; + case SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW: + return GL_SAMPLER_2D_ARRAY_SHADOW_EXT; + case SLANG_SPEC_ARRAY: + return _slang_gltype_from_specifier(type->_array); + case SLANG_SPEC_STRUCT: + /* fall-through */ + default: + return GL_NONE; + } +} + diff --git a/src/mesa/slang/slang_typeinfo.h b/src/mesa/slang/slang_typeinfo.h new file mode 100644 index 0000000000..9a6407a31b --- /dev/null +++ b/src/mesa/slang/slang_typeinfo.h @@ -0,0 +1,259 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_TYPEINFO_H +#define SLANG_TYPEINFO_H 1 + +#include "main/imports.h" +#include "main/mtypes.h" +#include "slang_log.h" +#include "slang_utility.h" +#include "slang_vartable.h" + + +struct slang_operation_; + +struct slang_name_space_; + + + +/** + * Holds complete information about vector swizzle - the + * array contains vector component source indices, where 0 is "x", 1 + * is "y", 2 is "z" and 3 is "w". + * Example: "xwz" --> { 3, { 0, 3, 2, not used } }. + */ +typedef struct slang_swizzle_ +{ + GLuint num_components; + GLuint swizzle[4]; +} slang_swizzle; + +extern GLboolean +_slang_is_swizzle(const char *field, GLuint rows, slang_swizzle *swz); + + +typedef enum slang_type_variant_ +{ + SLANG_VARIANT, /* the default */ + SLANG_INVARIANT /* indicates the "invariant" keyword */ +} slang_type_variant; + + +typedef enum slang_type_centroid_ +{ + SLANG_CENTER, /* the default */ + SLANG_CENTROID /* indicates the "centroid" keyword */ +} slang_type_centroid; + + +/** + * These only apply to gl_FragCoord, but other layout qualifiers may + * appear in the future. + */ +typedef enum slang_layout_qualifier_ +{ + SLANG_LAYOUT_NONE = 0x0, + SLANG_LAYOUT_UPPER_LEFT_BIT = 0x1, + SLANG_LAYOUT_PIXEL_CENTER_INTEGER_BIT = 0x2 +} slang_layout_qualifier; + + +typedef enum slang_type_qualifier_ +{ + SLANG_QUAL_NONE, + SLANG_QUAL_CONST, + SLANG_QUAL_ATTRIBUTE, + SLANG_QUAL_VARYING, + SLANG_QUAL_UNIFORM, + SLANG_QUAL_OUT, + SLANG_QUAL_INOUT, + SLANG_QUAL_FIXEDOUTPUT, /* internal */ + SLANG_QUAL_FIXEDINPUT /* internal */ +} slang_type_qualifier; + + +typedef enum slang_type_precision_ +{ + SLANG_PREC_DEFAULT, + SLANG_PREC_LOW, + SLANG_PREC_MEDIUM, + SLANG_PREC_HIGH +} slang_type_precision; + + +/** + * The basic shading language types (float, vec4, mat3, etc) + */ +typedef enum slang_type_specifier_type_ +{ + SLANG_SPEC_VOID, + SLANG_SPEC_BOOL, + SLANG_SPEC_BVEC2, + SLANG_SPEC_BVEC3, + SLANG_SPEC_BVEC4, + SLANG_SPEC_INT, + SLANG_SPEC_IVEC2, + SLANG_SPEC_IVEC3, + SLANG_SPEC_IVEC4, + SLANG_SPEC_FLOAT, + SLANG_SPEC_VEC2, + SLANG_SPEC_VEC3, + SLANG_SPEC_VEC4, + SLANG_SPEC_MAT2, + SLANG_SPEC_MAT3, + SLANG_SPEC_MAT4, + SLANG_SPEC_MAT23, + SLANG_SPEC_MAT32, + SLANG_SPEC_MAT24, + SLANG_SPEC_MAT42, + SLANG_SPEC_MAT34, + SLANG_SPEC_MAT43, + SLANG_SPEC_SAMPLER_1D, + SLANG_SPEC_SAMPLER_2D, + SLANG_SPEC_SAMPLER_3D, + SLANG_SPEC_SAMPLER_CUBE, + SLANG_SPEC_SAMPLER_RECT, + SLANG_SPEC_SAMPLER_1D_SHADOW, + SLANG_SPEC_SAMPLER_2D_SHADOW, + SLANG_SPEC_SAMPLER_RECT_SHADOW, + SLANG_SPEC_SAMPLER_1D_ARRAY, + SLANG_SPEC_SAMPLER_2D_ARRAY, + SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW, + SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW, + SLANG_SPEC_STRUCT, + SLANG_SPEC_ARRAY +} slang_type_specifier_type; + + +extern slang_type_specifier_type +slang_type_specifier_type_from_string(const char *); + +extern const char * +slang_type_specifier_type_to_string(slang_type_specifier_type); + + +/** + * Describes more sophisticated types, like structs and arrays. + */ +typedef struct slang_type_specifier_ +{ + slang_type_specifier_type type; + struct slang_struct_ *_struct; /**< if type == SLANG_SPEC_STRUCT */ + struct slang_type_specifier_ *_array; /**< if type == SLANG_SPEC_ARRAY */ +} slang_type_specifier; + + +extern GLvoid +slang_type_specifier_ctr(slang_type_specifier *); + +extern GLvoid +slang_type_specifier_dtr(slang_type_specifier *); + +extern slang_type_specifier * +slang_type_specifier_new(slang_type_specifier_type type, + struct slang_struct_ *_struct, + struct slang_type_specifier_ *_array); + + +extern GLboolean +slang_type_specifier_copy(slang_type_specifier *, const slang_type_specifier *); + +extern GLboolean +slang_type_specifier_equal(const slang_type_specifier *, + const slang_type_specifier *); + + +extern GLboolean +slang_type_specifier_compatible(const slang_type_specifier *x, + const slang_type_specifier *y); + + +typedef struct slang_fully_specified_type_ +{ + slang_type_qualifier qualifier; + slang_type_specifier specifier; + slang_type_precision precision; + slang_type_variant variant; + slang_type_centroid centroid; + slang_layout_qualifier layout; + GLint array_len; /**< -1 if not an array type */ +} slang_fully_specified_type; + +extern int +slang_fully_specified_type_construct(slang_fully_specified_type *); + +extern void +slang_fully_specified_type_destruct(slang_fully_specified_type *); + +extern int +slang_fully_specified_type_copy(slang_fully_specified_type *, + const slang_fully_specified_type *); + +GLboolean +slang_fully_specified_types_compatible(const slang_fully_specified_type * x, + const slang_fully_specified_type * y); + + +typedef struct slang_typeinfo_ +{ + GLboolean can_be_referenced; + GLboolean is_swizzled; + slang_swizzle swz; + slang_type_specifier spec; + GLuint array_len; +} slang_typeinfo; + +extern GLboolean +slang_typeinfo_construct(slang_typeinfo *); + +extern GLvoid +slang_typeinfo_destruct(slang_typeinfo *); + + +extern GLboolean +_slang_typeof_operation(struct slang_operation_ *, + const struct slang_name_space_ *, + slang_typeinfo *, slang_atom_pool *, + slang_info_log *log); + +extern GLboolean +_slang_type_is_matrix(slang_type_specifier_type); + +extern GLboolean +_slang_type_is_vector(slang_type_specifier_type); + +extern GLboolean +_slang_type_is_float_vec_mat(slang_type_specifier_type); + +extern slang_type_specifier_type +_slang_type_base(slang_type_specifier_type); + +extern GLuint +_slang_type_dim(slang_type_specifier_type); + +extern GLenum +_slang_gltype_from_specifier(const slang_type_specifier *type); + +#endif diff --git a/src/mesa/slang/slang_utility.c b/src/mesa/slang/slang_utility.c new file mode 100644 index 0000000000..c1d57409a4 --- /dev/null +++ b/src/mesa/slang/slang_utility.c @@ -0,0 +1,228 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_utility.c + * slang utilities + * \author Michal Krol + */ + +#include "main/imports.h" +#include "slang_utility.h" +#include "slang_mem.h" + +char * +slang_string_concat (char *dst, const char *src) +{ + return strcpy (dst + strlen (dst), src); +} + + +/* slang_string */ + +GLvoid +slang_string_init (slang_string *self) +{ + self->data = NULL; + self->capacity = 0; + self->length = 0; + self->fail = GL_FALSE; +} + +GLvoid +slang_string_free (slang_string *self) +{ + if (self->data != NULL) + free(self->data); +} + +GLvoid +slang_string_reset (slang_string *self) +{ + self->length = 0; + self->fail = GL_FALSE; +} + +static GLboolean +grow (slang_string *self, GLuint size) +{ + if (self->fail) + return GL_FALSE; + if (size > self->capacity) { + /* do not overflow 32-bit range */ + assert (size < 0x80000000); + + self->data = (char *) (_mesa_realloc (self->data, self->capacity, size * 2)); + self->capacity = size * 2; + if (self->data == NULL) { + self->capacity = 0; + self->fail = GL_TRUE; + return GL_FALSE; + } + } + return GL_TRUE; +} + +GLvoid +slang_string_push (slang_string *self, const slang_string *str) +{ + if (str->fail) { + self->fail = GL_TRUE; + return; + } + if (grow (self, self->length + str->length)) { + memcpy (&self->data[self->length], str->data, str->length); + self->length += str->length; + } +} + +GLvoid +slang_string_pushc (slang_string *self, const char c) +{ + if (grow (self, self->length + 1)) { + self->data[self->length] = c; + self->length++; + } +} + +GLvoid +slang_string_pushs (slang_string *self, const char *cstr, GLuint len) +{ + if (grow (self, self->length + len)) { + memcpy (&self->data[self->length], cstr, len); + self->length += len; + } +} + +GLvoid +slang_string_pushi (slang_string *self, GLint i) +{ + char buffer[12]; + + _mesa_snprintf (buffer, sizeof(buffer), "%d", i); + slang_string_pushs (self, buffer, strlen (buffer)); +} + +const char * +slang_string_cstr (slang_string *self) +{ + if (grow (self, self->length + 1)) + self->data[self->length] = '\0'; + return self->data; +} + +/* slang_atom_pool */ + +void +slang_atom_pool_construct(slang_atom_pool * pool) +{ + GLuint i; + + for (i = 0; i < SLANG_ATOM_POOL_SIZE; i++) + pool->entries[i] = NULL; +} + +void +slang_atom_pool_destruct (slang_atom_pool * pool) +{ + GLuint i; + + for (i = 0; i < SLANG_ATOM_POOL_SIZE; i++) { + slang_atom_entry * entry; + + entry = pool->entries[i]; + while (entry != NULL) { + slang_atom_entry *next = entry->next; + _slang_free(entry->id); + _slang_free(entry); + entry = next; + } + } +} + +/* + * Search the atom pool for an atom with a given name. + * If atom is not found, create and add it to the pool. + * Returns ATOM_NULL if the atom was not found and the function failed + * to create a new atom. + */ +slang_atom +slang_atom_pool_atom(slang_atom_pool * pool, const char * id) +{ + GLuint hash; + const char * p = id; + slang_atom_entry ** entry; + + /* Hash a given string to a number in the range [0, ATOM_POOL_SIZE). */ + hash = 0; + while (*p != '\0') { + GLuint g; + + hash = (hash << 4) + (GLuint) (*p++); + g = hash & 0xf0000000; + if (g != 0) + hash ^= g >> 24; + hash &= ~g; + } + hash %= SLANG_ATOM_POOL_SIZE; + + /* Now the hash points to a linked list of atoms with names that + * have the same hash value. Search the linked list for a given + * name. + */ + entry = &pool->entries[hash]; + while (*entry != NULL) { + /* If the same, return the associated atom. */ + if (slang_string_compare((**entry).id, id) == 0) + return (slang_atom) (**entry).id; + /* Grab the next atom in the linked list. */ + entry = &(**entry).next; + } + + /* Okay, we have not found an atom. Create a new entry for it. + * Note that the points to the last entry's field. + */ + *entry = (slang_atom_entry *) _slang_alloc(sizeof(slang_atom_entry)); + if (*entry == NULL) + return SLANG_ATOM_NULL; + + /* Initialize a new entry. Because we'll need the actual name of + * the atom, we use the pointer to this string as an actual atom's + * value. + */ + (**entry).next = NULL; + (**entry).id = _slang_strdup(id); + if ((**entry).id == NULL) + return SLANG_ATOM_NULL; + return (slang_atom) (**entry).id; +} + +/** + * Return the name of a given atom. + */ +const char * +slang_atom_pool_id(slang_atom_pool * pool, slang_atom atom) +{ + return (const char *) (atom); +} diff --git a/src/mesa/slang/slang_utility.h b/src/mesa/slang/slang_utility.h new file mode 100644 index 0000000000..2c0d0bcbb2 --- /dev/null +++ b/src/mesa/slang/slang_utility.h @@ -0,0 +1,100 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_UTILITY_H +#define SLANG_UTILITY_H + + +/* Compile-time assertions. If the expression is zero, try to declare an + * array of size [-1] to cause compilation error. + */ +#define static_assert(expr) do { int _array[(expr) ? 1 : -1]; (void) _array[0]; } while (0) + + +#define slang_string_compare(str1, str2) strcmp (str1, str2) +#define slang_string_copy(dst, src) strcpy (dst, src) +#define slang_string_length(str) strlen (str) + +char *slang_string_concat (char *, const char *); + +/* slang_string */ + +typedef struct +{ + char *data; + GLuint length; + GLuint capacity; + GLboolean fail; +} slang_string; + +GLvoid +slang_string_init (slang_string *); + +GLvoid +slang_string_free (slang_string *); + +GLvoid +slang_string_reset (slang_string *); + +GLvoid +slang_string_push (slang_string *, const slang_string *); + +GLvoid +slang_string_pushc (slang_string *, const char); + +GLvoid +slang_string_pushs (slang_string *, const char *, GLuint); + +GLvoid +slang_string_pushi (slang_string *, GLint); + +const char * +slang_string_cstr (slang_string *); + +/* slang_atom */ + +typedef GLvoid *slang_atom; + +#define SLANG_ATOM_NULL ((slang_atom) 0) + +typedef struct slang_atom_entry_ +{ + char *id; + struct slang_atom_entry_ *next; +} slang_atom_entry; + +#define SLANG_ATOM_POOL_SIZE 1023 + +typedef struct slang_atom_pool_ +{ + slang_atom_entry *entries[SLANG_ATOM_POOL_SIZE]; +} slang_atom_pool; + +GLvoid slang_atom_pool_construct (slang_atom_pool *); +GLvoid slang_atom_pool_destruct (slang_atom_pool *); +slang_atom slang_atom_pool_atom (slang_atom_pool *, const char *); +const char *slang_atom_pool_id (slang_atom_pool *, slang_atom); + + +#endif diff --git a/src/mesa/slang/slang_vartable.c b/src/mesa/slang/slang_vartable.c new file mode 100644 index 0000000000..e07e3a226a --- /dev/null +++ b/src/mesa/slang/slang_vartable.c @@ -0,0 +1,362 @@ + +#include "main/imports.h" +#include "shader/program.h" +#include "shader/prog_print.h" +#include "slang_compile.h" +#include "slang_compile_variable.h" +#include "slang_emit.h" +#include "slang_mem.h" +#include "slang_vartable.h" +#include "slang_ir.h" + + +static int dbg = 0; + + +typedef enum { + FREE, + VAR, + TEMP +} TempState; + + +/** + * Variable/register info for one variable scope. + */ +struct table +{ + int Level; + int NumVars; + slang_variable **Vars; /* array [NumVars] */ + + TempState Temps[MAX_PROGRAM_TEMPS * 4]; /* per-component state */ + int ValSize[MAX_PROGRAM_TEMPS * 4]; /**< For debug only */ + + struct table *Parent; /** Parent scope table */ +}; + + +/** + * A variable table is a stack of tables, one per scope. + */ +struct slang_var_table_ +{ + GLint CurLevel; + GLuint MaxRegisters; + struct table *Top; /**< Table at top of stack */ +}; + + + +slang_var_table * +_slang_new_var_table(GLuint maxRegisters) +{ + slang_var_table *vt + = (slang_var_table *) _slang_alloc(sizeof(slang_var_table)); + if (vt) { + vt->MaxRegisters = maxRegisters; + } + return vt; +} + + +void +_slang_delete_var_table(slang_var_table *vt) +{ + if (vt->Top) { + _mesa_problem(NULL, "non-empty var table in _slang_delete_var_table()"); + return; + } + _slang_free(vt); +} + + + +/** + * Create new table on top of vartable stack. + * Used when we enter a {} block. + */ +void +_slang_push_var_table(slang_var_table *vt) +{ + struct table *t = (struct table *) _slang_alloc(sizeof(struct table)); + if (t) { + t->Level = vt->CurLevel++; + t->Parent = vt->Top; + if (t->Parent) { + /* copy the info indicating which temp regs are in use */ + memcpy(t->Temps, t->Parent->Temps, sizeof(t->Temps)); + memcpy(t->ValSize, t->Parent->ValSize, sizeof(t->ValSize)); + } + vt->Top = t; + if (dbg) printf("Pushing level %d\n", t->Level); + } +} + + +/** + * Pop top entry from variable table. + * Used when we leave a {} block. + */ +void +_slang_pop_var_table(slang_var_table *vt) +{ + struct table *t = vt->Top; + int i; + + if (dbg) printf("Popping level %d\n", t->Level); + + /* free the storage allocated for each variable */ + for (i = 0; i < t->NumVars; i++) { + slang_ir_storage *store = t->Vars[i]->store; + GLint j; + GLuint comp; + if (dbg) printf(" Free var %s, size %d at %d.%s\n", + (char*) t->Vars[i]->a_name, store->Size, + store->Index, + _mesa_swizzle_string(store->Swizzle, 0, 0)); + + if (store->File == PROGRAM_SAMPLER) { + /* samplers have no storage */ + continue; + } + + if (store->Size == 1) + comp = GET_SWZ(store->Swizzle, 0); + else + comp = 0; + + /* store->Index may be -1 if we run out of registers */ + if (store->Index >= 0) { + for (j = 0; j < store->Size; j++) { + assert(t->Temps[store->Index * 4 + j + comp] == VAR); + t->Temps[store->Index * 4 + j + comp] = FREE; + } + } + store->Index = -1; + } + if (t->Parent) { + /* just verify that any remaining allocations in this scope + * were for temps + */ + for (i = 0; i < (int) vt->MaxRegisters * 4; i++) { + if (t->Temps[i] != FREE && t->Parent->Temps[i] == FREE) { + if (dbg) printf(" Free reg %d\n", i/4); + assert(t->Temps[i] == TEMP); + } + } + } + + if (t->Vars) { + _slang_free(t->Vars); + t->Vars = NULL; + } + + vt->Top = t->Parent; + _slang_free(t); + vt->CurLevel--; +} + + +/** + * Add a new variable to the given var/symbol table. + */ +void +_slang_add_variable(slang_var_table *vt, slang_variable *v) +{ + struct table *t; + assert(vt); + t = vt->Top; + assert(t); + if (dbg) printf("Adding var %s, store %p\n", (char *) v->a_name, (void *) v->store); + t->Vars = (slang_variable **) + _slang_realloc(t->Vars, + t->NumVars * sizeof(slang_variable *), + (t->NumVars + 1) * sizeof(slang_variable *)); + t->Vars[t->NumVars] = v; + t->NumVars++; +} + + +/** + * Look for variable by name in given table. + * If not found, Parent table will be searched. + */ +slang_variable * +_slang_find_variable(const slang_var_table *vt, slang_atom name) +{ + struct table *t = vt->Top; + while (1) { + int i; + for (i = 0; i < t->NumVars; i++) { + if (t->Vars[i]->a_name == name) + return t->Vars[i]; + } + if (t->Parent) + t = t->Parent; + else + return NULL; + } +} + + +/** + * Allocation helper. + * \param size var size in floats + * \return position for var, measured in floats + */ +static GLint +alloc_reg(slang_var_table *vt, GLint size, GLboolean isTemp) +{ + struct table *t = vt->Top; + /* if size == 1, allocate anywhere, else, pos must be multiple of 4 */ + const GLuint step = (size == 1) ? 1 : 4; + GLuint i, j; + assert(size > 0); /* number of floats */ + + for (i = 0; i <= vt->MaxRegisters * 4 - size; i += step) { + GLuint found = 0; + for (j = 0; j < (GLuint) size; j++) { + assert(i + j < 4 * MAX_PROGRAM_TEMPS); + if (i + j < vt->MaxRegisters * 4 && t->Temps[i + j] == FREE) { + found++; + } + else { + break; + } + } + if (found == size) { + /* found block of size free regs */ + if (size > 1) + assert(i % 4 == 0); + for (j = 0; j < (GLuint) size; j++) { + assert(i + j < 4 * MAX_PROGRAM_TEMPS); + t->Temps[i + j] = isTemp ? TEMP : VAR; + } + assert(i < MAX_PROGRAM_TEMPS * 4); + t->ValSize[i] = size; + return i; + } + } + + /* if we get here, we ran out of registers */ + return -1; +} + + +/** + * Allocate temp register(s) for storing a variable. + * \param size size needed, in floats + * \param swizzle returns swizzle mask for accessing var in register + * \return register allocated, or -1 + */ +GLboolean +_slang_alloc_var(slang_var_table *vt, slang_ir_storage *store) +{ + struct table *t = vt->Top; + int i; + + if (store->File == PROGRAM_SAMPLER) { + /* don't really allocate storage */ + store->Index = 0; + return GL_TRUE; + } + + i = alloc_reg(vt, store->Size, GL_FALSE); + if (i < 0) + return GL_FALSE; + + store->Index = i / 4; + store->Swizzle = _slang_var_swizzle(store->Size, i % 4); + + if (dbg) + printf("Alloc var storage sz %d at %d.%s (level %d) store %p\n", + store->Size, store->Index, + _mesa_swizzle_string(store->Swizzle, 0, 0), + t->Level, + (void*) store); + + return GL_TRUE; +} + + + +/** + * Allocate temp register(s) for storing an unnamed intermediate value. + */ +GLboolean +_slang_alloc_temp(slang_var_table *vt, slang_ir_storage *store) +{ + struct table *t = vt->Top; + const int i = alloc_reg(vt, store->Size, GL_TRUE); + if (i < 0) + return GL_FALSE; + + assert(store->Index < 0); + + store->Index = i / 4; + store->Swizzle = _slang_var_swizzle(store->Size, i % 4); + + if (dbg) printf("Alloc temp sz %d at %d.%s (level %d) store %p\n", + store->Size, store->Index, + _mesa_swizzle_string(store->Swizzle, 0, 0), t->Level, + (void *) store); + + return GL_TRUE; +} + + +void +_slang_free_temp(slang_var_table *vt, slang_ir_storage *store) +{ + struct table *t = vt->Top; + GLuint i; + GLint r = store->Index; + assert(store->Size > 0); + assert(r >= 0); + assert((GLuint)r + store->Size <= vt->MaxRegisters * 4); + if (dbg) printf("Free temp sz %d at %d.%s (level %d) store %p\n", + store->Size, r, + _mesa_swizzle_string(store->Swizzle, 0, 0), + t->Level, (void *) store); + if (store->Size == 1) { + const GLuint comp = GET_SWZ(store->Swizzle, 0); + /* we can actually fail some of these assertions because of the + * troublesome IR_SWIZZLE handling. + */ +#if 0 + assert(store->Swizzle == MAKE_SWIZZLE4(comp, comp, comp, comp)); + assert(comp < 4); + assert(t->ValSize[r * 4 + comp] == 1); +#endif + assert(t->Temps[r * 4 + comp] == TEMP); + t->Temps[r * 4 + comp] = FREE; + } + else { + /*assert(store->Swizzle == SWIZZLE_NOOP);*/ + assert(t->ValSize[r*4] == store->Size); + for (i = 0; i < (GLuint) store->Size; i++) { + assert(t->Temps[r * 4 + i] == TEMP); + t->Temps[r * 4 + i] = FREE; + } + } +} + + +GLboolean +_slang_is_temp(const slang_var_table *vt, const slang_ir_storage *store) +{ + struct table *t = vt->Top; + GLuint comp; + assert(store->Index >= 0); + assert(store->Index < (int) vt->MaxRegisters); + if (store->Swizzle == SWIZZLE_NOOP) + comp = 0; + else + comp = GET_SWZ(store->Swizzle, 0); + + if (t->Temps[store->Index * 4 + comp] == TEMP) + return GL_TRUE; + else + return GL_FALSE; +} diff --git a/src/mesa/slang/slang_vartable.h b/src/mesa/slang/slang_vartable.h new file mode 100644 index 0000000000..94bcd63f45 --- /dev/null +++ b/src/mesa/slang/slang_vartable.h @@ -0,0 +1,42 @@ + +#ifndef SLANG_VARTABLE_H +#define SLANG_VARTABLE_H + +struct slang_ir_storage_; + +typedef struct slang_var_table_ slang_var_table; + +struct slang_variable_; + +extern slang_var_table * +_slang_new_var_table(GLuint maxRegisters); + +extern void +_slang_delete_var_table(slang_var_table *vt); + +extern void +_slang_push_var_table(slang_var_table *parent); + +extern void +_slang_pop_var_table(slang_var_table *t); + +extern void +_slang_add_variable(slang_var_table *t, struct slang_variable_ *v); + +extern struct slang_variable_ * +_slang_find_variable(const slang_var_table *t, slang_atom name); + +extern GLboolean +_slang_alloc_var(slang_var_table *t, struct slang_ir_storage_ *store); + +extern GLboolean +_slang_alloc_temp(slang_var_table *t, struct slang_ir_storage_ *store); + +extern void +_slang_free_temp(slang_var_table *t, struct slang_ir_storage_ *store); + +extern GLboolean +_slang_is_temp(const slang_var_table *t, const struct slang_ir_storage_ *store); + + +#endif /* SLANG_VARTABLE_H */ -- cgit v1.2.3 From ec2b92f98c2e7f161521b447cc1d9a36bce3707c Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 10 Jun 2010 23:02:41 -0600 Subject: mesa: rename src/mesa/shader/ to src/mesa/program/ --- Makefile | 6 +- src/mesa/Makefile.mgw | 4 +- src/mesa/SConscript | 46 +- src/mesa/drivers/common/driverfuncs.c | 2 +- src/mesa/drivers/common/meta.c | 2 +- src/mesa/drivers/dri/common/dri_metaops.c | 2 +- src/mesa/drivers/dri/i915/i915_fragprog.c | 10 +- src/mesa/drivers/dri/i965/brw_clip_line.c | 2 +- src/mesa/drivers/dri/i965/brw_clip_point.c | 2 +- src/mesa/drivers/dri/i965/brw_clip_tri.c | 2 +- src/mesa/drivers/dri/i965/brw_clip_unfilled.c | 2 +- src/mesa/drivers/dri/i965/brw_clip_util.c | 2 +- src/mesa/drivers/dri/i965/brw_context.c | 2 +- src/mesa/drivers/dri/i965/brw_curbe.c | 6 +- src/mesa/drivers/dri/i965/brw_eu.h | 2 +- src/mesa/drivers/dri/i965/brw_gs_emit.c | 2 +- src/mesa/drivers/dri/i965/brw_optimize.c | 4 +- src/mesa/drivers/dri/i965/brw_program.c | 8 +- src/mesa/drivers/dri/i965/brw_sf.h | 2 +- src/mesa/drivers/dri/i965/brw_util.c | 2 +- src/mesa/drivers/dri/i965/brw_vs.c | 4 +- src/mesa/drivers/dri/i965/brw_vs.h | 2 +- src/mesa/drivers/dri/i965/brw_vs_emit.c | 6 +- src/mesa/drivers/dri/i965/brw_vs_surface_state.c | 2 +- src/mesa/drivers/dri/i965/brw_wm.h | 2 +- src/mesa/drivers/dri/i965/brw_wm_fp.c | 6 +- src/mesa/drivers/dri/i965/brw_wm_glsl.c | 6 +- src/mesa/drivers/dri/i965/brw_wm_pass0.c | 2 +- src/mesa/drivers/dri/i965/brw_wm_surface_state.c | 2 +- src/mesa/drivers/dri/i965/gen6_vs_state.c | 4 +- src/mesa/drivers/dri/i965/gen6_wm_state.c | 4 +- src/mesa/drivers/dri/r200/r200_fragshader.c | 2 +- src/mesa/drivers/dri/r200/r200_vertprog.c | 10 +- src/mesa/drivers/dri/r300/r300_context.h | 2 +- src/mesa/drivers/dri/r300/r300_fragprog_common.c | 4 +- src/mesa/drivers/dri/r300/r300_shader.c | 2 +- src/mesa/drivers/dri/r300/r300_state.c | 4 +- src/mesa/drivers/dri/r300/r300_vertprog.c | 12 +- src/mesa/drivers/dri/r300/radeon_mesa_to_rc.c | 4 +- src/mesa/drivers/dri/r600/r700_assembler.c | 2 +- src/mesa/drivers/dri/r600/r700_assembler.h | 2 +- src/mesa/drivers/dri/r600/r700_fragprog.c | 6 +- src/mesa/drivers/dri/r600/r700_oglprog.c | 2 +- src/mesa/drivers/dri/r600/r700_state.c | 4 +- src/mesa/drivers/dri/r600/r700_vertprog.c | 8 +- src/mesa/drivers/glslcompiler/glslcompiler.c | 4 +- src/mesa/main/arbprogram.c | 8 +- src/mesa/main/context.c | 4 +- src/mesa/main/ffvertex_prog.c | 12 +- src/mesa/main/get.c | 2 +- src/mesa/main/nvprogram.c | 12 +- src/mesa/main/shaderapi.c | 6 +- src/mesa/main/shaderobj.c | 6 +- src/mesa/main/shared.c | 2 +- src/mesa/main/state.c | 4 +- src/mesa/main/texenvprogram.c | 14 +- src/mesa/main/texobj.c | 2 +- src/mesa/main/texparam.c | 2 +- src/mesa/main/texstate.c | 2 +- src/mesa/main/transformfeedback.c | 4 +- src/mesa/main/uniforms.c | 6 +- src/mesa/program/.gitignore | 1 + src/mesa/program/Makefile | 7 + src/mesa/program/arbprogparse.c | 217 + src/mesa/program/arbprogparse.h | 41 + src/mesa/program/descrip.mms | 93 + src/mesa/program/hash_table.c | 159 + src/mesa/program/hash_table.h | 117 + src/mesa/program/lex.yy.c | 3654 ++++++++++++++ src/mesa/program/nvfragparse.c | 1588 ++++++ src/mesa/program/nvfragparse.h | 43 + src/mesa/program/nvvertparse.c | 1454 ++++++ src/mesa/program/nvvertparse.h | 45 + src/mesa/program/prog_cache.c | 206 + src/mesa/program/prog_cache.h | 55 + src/mesa/program/prog_execute.c | 1798 +++++++ src/mesa/program/prog_execute.h | 85 + src/mesa/program/prog_instruction.c | 352 ++ src/mesa/program/prog_instruction.h | 437 ++ src/mesa/program/prog_noise.c | 638 +++ src/mesa/program/prog_noise.h | 34 + src/mesa/program/prog_optimize.c | 1035 ++++ src/mesa/program/prog_optimize.h | 45 + src/mesa/program/prog_parameter.c | 751 +++ src/mesa/program/prog_parameter.h | 182 + src/mesa/program/prog_parameter_layout.c | 213 + src/mesa/program/prog_parameter_layout.h | 42 + src/mesa/program/prog_print.c | 1065 ++++ src/mesa/program/prog_print.h | 100 + src/mesa/program/prog_statevars.c | 1187 +++++ src/mesa/program/prog_statevars.h | 147 + src/mesa/program/prog_uniform.c | 165 + src/mesa/program/prog_uniform.h | 92 + src/mesa/program/program.c | 913 ++++ src/mesa/program/program.h | 151 + src/mesa/program/program_lexer.l | 494 ++ src/mesa/program/program_parse.tab.c | 5729 ++++++++++++++++++++++ src/mesa/program/program_parse.tab.h | 209 + src/mesa/program/program_parse.y | 2767 +++++++++++ src/mesa/program/program_parse_extra.c | 255 + src/mesa/program/program_parser.h | 302 ++ src/mesa/program/programopt.c | 669 +++ src/mesa/program/programopt.h | 52 + src/mesa/program/symbol_table.c | 362 ++ src/mesa/program/symbol_table.h | 55 + src/mesa/shader/.gitignore | 1 - src/mesa/shader/Makefile | 7 - src/mesa/shader/arbprogparse.c | 217 - src/mesa/shader/arbprogparse.h | 41 - src/mesa/shader/descrip.mms | 93 - src/mesa/shader/hash_table.c | 159 - src/mesa/shader/hash_table.h | 117 - src/mesa/shader/lex.yy.c | 3655 -------------- src/mesa/shader/nvfragparse.c | 1588 ------ src/mesa/shader/nvfragparse.h | 43 - src/mesa/shader/nvvertparse.c | 1454 ------ src/mesa/shader/nvvertparse.h | 45 - src/mesa/shader/prog_cache.c | 206 - src/mesa/shader/prog_cache.h | 55 - src/mesa/shader/prog_execute.c | 1798 ------- src/mesa/shader/prog_execute.h | 85 - src/mesa/shader/prog_instruction.c | 352 -- src/mesa/shader/prog_instruction.h | 437 -- src/mesa/shader/prog_noise.c | 638 --- src/mesa/shader/prog_noise.h | 34 - src/mesa/shader/prog_optimize.c | 1035 ---- src/mesa/shader/prog_optimize.h | 45 - src/mesa/shader/prog_parameter.c | 751 --- src/mesa/shader/prog_parameter.h | 182 - src/mesa/shader/prog_parameter_layout.c | 213 - src/mesa/shader/prog_parameter_layout.h | 42 - src/mesa/shader/prog_print.c | 1065 ---- src/mesa/shader/prog_print.h | 100 - src/mesa/shader/prog_statevars.c | 1187 ----- src/mesa/shader/prog_statevars.h | 147 - src/mesa/shader/prog_uniform.c | 165 - src/mesa/shader/prog_uniform.h | 92 - src/mesa/shader/program.c | 913 ---- src/mesa/shader/program.h | 151 - src/mesa/shader/program_lexer.l | 495 -- src/mesa/shader/program_parse.tab.c | 5729 ---------------------- src/mesa/shader/program_parse.tab.h | 209 - src/mesa/shader/program_parse.y | 2767 ----------- src/mesa/shader/program_parse_extra.c | 255 - src/mesa/shader/program_parser.h | 302 -- src/mesa/shader/programopt.c | 669 --- src/mesa/shader/programopt.h | 52 - src/mesa/shader/symbol_table.c | 362 -- src/mesa/shader/symbol_table.h | 55 - src/mesa/slang/library/Makefile | 2 +- src/mesa/slang/library/SConscript | 28 +- src/mesa/slang/slang_builtin.c | 8 +- src/mesa/slang/slang_builtin.h | 2 +- src/mesa/slang/slang_codegen.c | 10 +- src/mesa/slang/slang_compile.c | 10 +- src/mesa/slang/slang_emit.c | 8 +- src/mesa/slang/slang_ir.c | 4 +- src/mesa/slang/slang_label.h | 2 +- src/mesa/slang/slang_link.c | 12 +- src/mesa/slang/slang_typeinfo.c | 2 +- src/mesa/slang/slang_vartable.c | 4 +- src/mesa/sources.mak | 46 +- src/mesa/state_tracker/st_atom_constbuf.c | 4 +- src/mesa/state_tracker/st_atom_pixeltransfer.c | 8 +- src/mesa/state_tracker/st_atom_shader.c | 2 +- src/mesa/state_tracker/st_atom_texture.c | 2 +- src/mesa/state_tracker/st_cb_bitmap.c | 6 +- src/mesa/state_tracker/st_cb_clear.c | 2 +- src/mesa/state_tracker/st_cb_drawpixels.c | 6 +- src/mesa/state_tracker/st_cb_drawtex.c | 4 +- src/mesa/state_tracker/st_cb_program.c | 6 +- src/mesa/state_tracker/st_context.h | 2 +- src/mesa/state_tracker/st_debug.c | 2 +- src/mesa/state_tracker/st_draw.c | 2 +- src/mesa/state_tracker/st_mesa_to_tgsi.c | 4 +- src/mesa/state_tracker/st_program.c | 4 +- src/mesa/state_tracker/st_program.h | 2 +- src/mesa/swrast/s_context.c | 4 +- src/mesa/swrast/s_context.h | 2 +- src/mesa/swrast/s_fragprog.c | 2 +- src/mesa/swrast/s_texcombine.c | 2 +- src/mesa/swrast/s_triangle.c | 2 +- src/mesa/tnl/t_vb_program.c | 6 +- 183 files changed, 28264 insertions(+), 28266 deletions(-) create mode 100644 src/mesa/program/.gitignore create mode 100644 src/mesa/program/Makefile create mode 100644 src/mesa/program/arbprogparse.c create mode 100644 src/mesa/program/arbprogparse.h create mode 100644 src/mesa/program/descrip.mms create mode 100644 src/mesa/program/hash_table.c create mode 100644 src/mesa/program/hash_table.h create mode 100644 src/mesa/program/lex.yy.c create mode 100644 src/mesa/program/nvfragparse.c create mode 100644 src/mesa/program/nvfragparse.h create mode 100644 src/mesa/program/nvvertparse.c create mode 100644 src/mesa/program/nvvertparse.h create mode 100644 src/mesa/program/prog_cache.c create mode 100644 src/mesa/program/prog_cache.h create mode 100644 src/mesa/program/prog_execute.c create mode 100644 src/mesa/program/prog_execute.h create mode 100644 src/mesa/program/prog_instruction.c create mode 100644 src/mesa/program/prog_instruction.h create mode 100644 src/mesa/program/prog_noise.c create mode 100644 src/mesa/program/prog_noise.h create mode 100644 src/mesa/program/prog_optimize.c create mode 100644 src/mesa/program/prog_optimize.h create mode 100644 src/mesa/program/prog_parameter.c create mode 100644 src/mesa/program/prog_parameter.h create mode 100644 src/mesa/program/prog_parameter_layout.c create mode 100644 src/mesa/program/prog_parameter_layout.h create mode 100644 src/mesa/program/prog_print.c create mode 100644 src/mesa/program/prog_print.h create mode 100644 src/mesa/program/prog_statevars.c create mode 100644 src/mesa/program/prog_statevars.h create mode 100644 src/mesa/program/prog_uniform.c create mode 100644 src/mesa/program/prog_uniform.h create mode 100644 src/mesa/program/program.c create mode 100644 src/mesa/program/program.h create mode 100644 src/mesa/program/program_lexer.l create mode 100644 src/mesa/program/program_parse.tab.c create mode 100644 src/mesa/program/program_parse.tab.h create mode 100644 src/mesa/program/program_parse.y create mode 100644 src/mesa/program/program_parse_extra.c create mode 100644 src/mesa/program/program_parser.h create mode 100644 src/mesa/program/programopt.c create mode 100644 src/mesa/program/programopt.h create mode 100644 src/mesa/program/symbol_table.c create mode 100644 src/mesa/program/symbol_table.h delete mode 100644 src/mesa/shader/.gitignore delete mode 100644 src/mesa/shader/Makefile delete mode 100644 src/mesa/shader/arbprogparse.c delete mode 100644 src/mesa/shader/arbprogparse.h delete mode 100644 src/mesa/shader/descrip.mms delete mode 100644 src/mesa/shader/hash_table.c delete mode 100644 src/mesa/shader/hash_table.h delete mode 100644 src/mesa/shader/lex.yy.c delete mode 100644 src/mesa/shader/nvfragparse.c delete mode 100644 src/mesa/shader/nvfragparse.h delete mode 100644 src/mesa/shader/nvvertparse.c delete mode 100644 src/mesa/shader/nvvertparse.h delete mode 100644 src/mesa/shader/prog_cache.c delete mode 100644 src/mesa/shader/prog_cache.h delete mode 100644 src/mesa/shader/prog_execute.c delete mode 100644 src/mesa/shader/prog_execute.h delete mode 100644 src/mesa/shader/prog_instruction.c delete mode 100644 src/mesa/shader/prog_instruction.h delete mode 100644 src/mesa/shader/prog_noise.c delete mode 100644 src/mesa/shader/prog_noise.h delete mode 100644 src/mesa/shader/prog_optimize.c delete mode 100644 src/mesa/shader/prog_optimize.h delete mode 100644 src/mesa/shader/prog_parameter.c delete mode 100644 src/mesa/shader/prog_parameter.h delete mode 100644 src/mesa/shader/prog_parameter_layout.c delete mode 100644 src/mesa/shader/prog_parameter_layout.h delete mode 100644 src/mesa/shader/prog_print.c delete mode 100644 src/mesa/shader/prog_print.h delete mode 100644 src/mesa/shader/prog_statevars.c delete mode 100644 src/mesa/shader/prog_statevars.h delete mode 100644 src/mesa/shader/prog_uniform.c delete mode 100644 src/mesa/shader/prog_uniform.h delete mode 100644 src/mesa/shader/program.c delete mode 100644 src/mesa/shader/program.h delete mode 100644 src/mesa/shader/program_lexer.l delete mode 100644 src/mesa/shader/program_parse.tab.c delete mode 100644 src/mesa/shader/program_parse.tab.h delete mode 100644 src/mesa/shader/program_parse.y delete mode 100644 src/mesa/shader/program_parse_extra.c delete mode 100644 src/mesa/shader/program_parser.h delete mode 100644 src/mesa/shader/programopt.c delete mode 100644 src/mesa/shader/programopt.h delete mode 100644 src/mesa/shader/symbol_table.c delete mode 100644 src/mesa/shader/symbol_table.h (limited to 'src/mesa/slang') diff --git a/Makefile b/Makefile index bf4f2d5218..ca46504715 100644 --- a/Makefile +++ b/Makefile @@ -243,9 +243,9 @@ MAIN_FILES = \ $(DIRECTORY)/src/mesa/main/descrip.mms \ $(DIRECTORY)/src/mesa/math/*.[ch] \ $(DIRECTORY)/src/mesa/math/descrip.mms \ - $(DIRECTORY)/src/mesa/shader/*.[chly] \ - $(DIRECTORY)/src/mesa/shader/Makefile \ - $(DIRECTORY)/src/mesa/shader/descrip.mms \ + $(DIRECTORY)/src/mesa/program/*.[chly] \ + $(DIRECTORY)/src/mesa/program/Makefile \ + $(DIRECTORY)/src/mesa/program/descrip.mms \ $(DIRECTORY)/src/mesa/slang/*.[ch] \ $(DIRECTORY)/src/mesa/slang/descrip.mms \ $(DIRECTORY)/src/mesa/slang/library/*.gc \ diff --git a/src/mesa/Makefile.mgw b/src/mesa/Makefile.mgw index b90384d04a..fc0ff28d69 100644 --- a/src/mesa/Makefile.mgw +++ b/src/mesa/Makefile.mgw @@ -216,8 +216,8 @@ clean: -$(call UNLINK,main/*.o) -$(call UNLINK,math/*.o) -$(call UNLINK,vbo/*.o) - -$(call UNLINK,shader/*.o) - -$(call UNLINK,shader/slang/*.o) + -$(call UNLINK,program/*.o) + -$(call UNLINK,slang/*.o) -$(call UNLINK,sparc/*.o) -$(call UNLINK,ppc/*.o) -$(call UNLINK,swrast/*.o) diff --git a/src/mesa/SConscript b/src/mesa/SConscript index 405b5c8830..79e9b4553b 100644 --- a/src/mesa/SConscript +++ b/src/mesa/SConscript @@ -197,27 +197,27 @@ if env['platform'] != 'winddk': 'state_tracker/st_texture.c', ] - shader_sources = [ - 'shader/arbprogparse.c', - 'shader/hash_table.c', - 'shader/lex.yy.c', - 'shader/nvfragparse.c', - 'shader/nvvertparse.c', - 'shader/program.c', - 'shader/program_parse.tab.c', - 'shader/program_parse_extra.c', - 'shader/prog_cache.c', - 'shader/prog_execute.c', - 'shader/prog_instruction.c', - 'shader/prog_noise.c', - 'shader/prog_optimize.c', - 'shader/prog_parameter.c', - 'shader/prog_parameter_layout.c', - 'shader/prog_print.c', - 'shader/prog_statevars.c', - 'shader/prog_uniform.c', - 'shader/programopt.c', - 'shader/symbol_table.c', + program_sources = [ + 'program/arbprogparse.c', + 'program/hash_table.c', + 'program/lex.yy.c', + 'program/nvfragparse.c', + 'program/nvvertparse.c', + 'program/program.c', + 'program/program_parse.tab.c', + 'program/program_parse_extra.c', + 'program/prog_cache.c', + 'program/prog_execute.c', + 'program/prog_instruction.c', + 'program/prog_noise.c', + 'program/prog_optimize.c', + 'program/prog_parameter.c', + 'program/prog_parameter_layout.c', + 'program/prog_print.c', + 'program/prog_statevars.c', + 'program/prog_uniform.c', + 'program/programopt.c', + 'program/symbol_table.c', ] slang_sources = [ @@ -245,10 +245,10 @@ if env['platform'] != 'winddk': mesa_sources = ( main_sources + math_sources + + program_sources + vbo_sources + vf_sources + statetracker_sources + - shader_sources + slang_sources ) @@ -327,7 +327,7 @@ if env['platform'] != 'winddk': # build dir) to the include path env.Append(CPPPATH = [matypes[0].dir]) - SConscript('shader/slang/library/SConscript') + SConscript('slang/library/SConscript') # # Libraries diff --git a/src/mesa/drivers/common/driverfuncs.c b/src/mesa/drivers/common/driverfuncs.c index 6677bc4252..227710fb02 100644 --- a/src/mesa/drivers/common/driverfuncs.c +++ b/src/mesa/drivers/common/driverfuncs.c @@ -52,7 +52,7 @@ #include "main/transformfeedback.h" #endif -#include "shader/program.h" +#include "program/program.h" #include "tnl/tnl.h" #include "swrast/swrast.h" diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c index 93848287dd..629ec0ffec 100644 --- a/src/mesa/drivers/common/meta.c +++ b/src/mesa/drivers/common/meta.c @@ -62,7 +62,7 @@ #include "main/texstate.h" #include "main/varray.h" #include "main/viewport.h" -#include "shader/program.h" +#include "program/program.h" #include "swrast/swrast.h" #include "drivers/common/meta.h" diff --git a/src/mesa/drivers/dri/common/dri_metaops.c b/src/mesa/drivers/dri/common/dri_metaops.c index 9151c03b5e..86e59a8e51 100644 --- a/src/mesa/drivers/dri/common/dri_metaops.c +++ b/src/mesa/drivers/dri/common/dri_metaops.c @@ -34,7 +34,7 @@ #include "main/texstate.h" #include "main/varray.h" #include "main/viewport.h" -#include "shader/program.h" +#include "program/program.h" #include "dri_metaops.h" void diff --git a/src/mesa/drivers/dri/i915/i915_fragprog.c b/src/mesa/drivers/dri/i915/i915_fragprog.c index e60157f377..f1505dc5e7 100644 --- a/src/mesa/drivers/dri/i915/i915_fragprog.c +++ b/src/mesa/drivers/dri/i915/i915_fragprog.c @@ -29,11 +29,11 @@ #include "main/macros.h" #include "main/enums.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" -#include "shader/program.h" -#include "shader/programopt.h" -#include "shader/prog_print.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "program/program.h" +#include "program/programopt.h" +#include "program/prog_print.h" #include "tnl/tnl.h" #include "tnl/t_context.h" diff --git a/src/mesa/drivers/dri/i965/brw_clip_line.c b/src/mesa/drivers/dri/i965/brw_clip_line.c index ceb62a3116..4b9117bb0b 100644 --- a/src/mesa/drivers/dri/i965/brw_clip_line.c +++ b/src/mesa/drivers/dri/i965/brw_clip_line.c @@ -32,7 +32,7 @@ #include "main/glheader.h" #include "main/macros.h" #include "main/enums.h" -#include "shader/program.h" +#include "program/program.h" #include "intel_batchbuffer.h" diff --git a/src/mesa/drivers/dri/i965/brw_clip_point.c b/src/mesa/drivers/dri/i965/brw_clip_point.c index 7f47634dca..b994a32bc3 100644 --- a/src/mesa/drivers/dri/i965/brw_clip_point.c +++ b/src/mesa/drivers/dri/i965/brw_clip_point.c @@ -32,7 +32,7 @@ #include "main/glheader.h" #include "main/macros.h" #include "main/enums.h" -#include "shader/program.h" +#include "program/program.h" #include "intel_batchbuffer.h" diff --git a/src/mesa/drivers/dri/i965/brw_clip_tri.c b/src/mesa/drivers/dri/i965/brw_clip_tri.c index 916a99ea00..fd425b39ad 100644 --- a/src/mesa/drivers/dri/i965/brw_clip_tri.c +++ b/src/mesa/drivers/dri/i965/brw_clip_tri.c @@ -32,7 +32,7 @@ #include "main/glheader.h" #include "main/macros.h" #include "main/enums.h" -#include "shader/program.h" +#include "program/program.h" #include "intel_batchbuffer.h" diff --git a/src/mesa/drivers/dri/i965/brw_clip_unfilled.c b/src/mesa/drivers/dri/i965/brw_clip_unfilled.c index f36d22fdbf..afd93f8be0 100644 --- a/src/mesa/drivers/dri/i965/brw_clip_unfilled.c +++ b/src/mesa/drivers/dri/i965/brw_clip_unfilled.c @@ -32,7 +32,7 @@ #include "main/glheader.h" #include "main/macros.h" #include "main/enums.h" -#include "shader/program.h" +#include "program/program.h" #include "intel_batchbuffer.h" diff --git a/src/mesa/drivers/dri/i965/brw_clip_util.c b/src/mesa/drivers/dri/i965/brw_clip_util.c index 2148bc8244..9708d7e618 100644 --- a/src/mesa/drivers/dri/i965/brw_clip_util.c +++ b/src/mesa/drivers/dri/i965/brw_clip_util.c @@ -33,7 +33,7 @@ #include "main/glheader.h" #include "main/macros.h" #include "main/enums.h" -#include "shader/program.h" +#include "program/program.h" #include "intel_batchbuffer.h" diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c index 3e7cf6b867..e688431b12 100644 --- a/src/mesa/drivers/dri/i965/brw_context.c +++ b/src/mesa/drivers/dri/i965/brw_context.c @@ -34,7 +34,7 @@ #include "main/api_noop.h" #include "main/macros.h" #include "main/simple_list.h" -#include "shader/shader_api.h" +#include "program/shader_api.h" #include "brw_context.h" #include "brw_defines.h" diff --git a/src/mesa/drivers/dri/i965/brw_curbe.c b/src/mesa/drivers/dri/i965/brw_curbe.c index c79b0a79e5..3d52f6f604 100644 --- a/src/mesa/drivers/dri/i965/brw_curbe.c +++ b/src/mesa/drivers/dri/i965/brw_curbe.c @@ -35,9 +35,9 @@ #include "main/context.h" #include "main/macros.h" #include "main/enums.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" -#include "shader/prog_statevars.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" +#include "program/prog_statevars.h" #include "intel_batchbuffer.h" #include "intel_regions.h" #include "brw_context.h" diff --git a/src/mesa/drivers/dri/i965/brw_eu.h b/src/mesa/drivers/dri/i965/brw_eu.h index 3a32ad26c1..a6fcd832f7 100644 --- a/src/mesa/drivers/dri/i965/brw_eu.h +++ b/src/mesa/drivers/dri/i965/brw_eu.h @@ -35,7 +35,7 @@ #include "brw_structs.h" #include "brw_defines.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" #define BRW_SWIZZLE4(a,b,c,d) (((a)<<0) | ((b)<<2) | ((c)<<4) | ((d)<<6)) #define BRW_GET_SWZ(swz, idx) (((swz) >> ((idx)*2)) & 0x3) diff --git a/src/mesa/drivers/dri/i965/brw_gs_emit.c b/src/mesa/drivers/dri/i965/brw_gs_emit.c index 99a6f6be11..a01d5576f8 100644 --- a/src/mesa/drivers/dri/i965/brw_gs_emit.c +++ b/src/mesa/drivers/dri/i965/brw_gs_emit.c @@ -34,7 +34,7 @@ #include "main/macros.h" #include "main/enums.h" -#include "shader/program.h" +#include "program/program.h" #include "intel_batchbuffer.h" #include "brw_defines.h" diff --git a/src/mesa/drivers/dri/i965/brw_optimize.c b/src/mesa/drivers/dri/i965/brw_optimize.c index e79b3ddea3..a364b15820 100644 --- a/src/mesa/drivers/dri/i965/brw_optimize.c +++ b/src/mesa/drivers/dri/i965/brw_optimize.c @@ -26,8 +26,8 @@ */ #include "main/macros.h" -#include "shader/program.h" -#include "shader/prog_print.h" +#include "program/program.h" +#include "program/prog_print.h" #include "brw_context.h" #include "brw_defines.h" #include "brw_eu.h" diff --git a/src/mesa/drivers/dri/i965/brw_program.c b/src/mesa/drivers/dri/i965/brw_program.c index b44742b765..cc9ac6d574 100644 --- a/src/mesa/drivers/dri/i965/brw_program.c +++ b/src/mesa/drivers/dri/i965/brw_program.c @@ -31,10 +31,10 @@ #include "main/imports.h" #include "main/enums.h" -#include "shader/prog_parameter.h" -#include "shader/program.h" -#include "shader/programopt.h" -#include "shader/shader_api.h" +#include "program/prog_parameter.h" +#include "program/program.h" +#include "program/programopt.h" +#include "program/shader_api.h" #include "tnl/tnl.h" #include "brw_context.h" diff --git a/src/mesa/drivers/dri/i965/brw_sf.h b/src/mesa/drivers/dri/i965/brw_sf.h index a0680a56f2..e525c730d3 100644 --- a/src/mesa/drivers/dri/i965/brw_sf.h +++ b/src/mesa/drivers/dri/i965/brw_sf.h @@ -34,7 +34,7 @@ #define BRW_SF_H -#include "shader/program.h" +#include "program/program.h" #include "brw_context.h" #include "brw_eu.h" diff --git a/src/mesa/drivers/dri/i965/brw_util.c b/src/mesa/drivers/dri/i965/brw_util.c index bba9249d1b..1db2a210d4 100644 --- a/src/mesa/drivers/dri/i965/brw_util.c +++ b/src/mesa/drivers/dri/i965/brw_util.c @@ -31,7 +31,7 @@ #include "main/mtypes.h" -#include "shader/prog_parameter.h" +#include "program/prog_parameter.h" #include "brw_util.h" #include "brw_defines.h" diff --git a/src/mesa/drivers/dri/i965/brw_vs.c b/src/mesa/drivers/dri/i965/brw_vs.c index 3c12f11ea7..9a832af9a9 100644 --- a/src/mesa/drivers/dri/i965/brw_vs.c +++ b/src/mesa/drivers/dri/i965/brw_vs.c @@ -34,8 +34,8 @@ #include "brw_vs.h" #include "brw_util.h" #include "brw_state.h" -#include "shader/prog_print.h" -#include "shader/prog_parameter.h" +#include "program/prog_print.h" +#include "program/prog_parameter.h" diff --git a/src/mesa/drivers/dri/i965/brw_vs.h b/src/mesa/drivers/dri/i965/brw_vs.h index 6493744f3e..9338a6b7db 100644 --- a/src/mesa/drivers/dri/i965/brw_vs.h +++ b/src/mesa/drivers/dri/i965/brw_vs.h @@ -36,7 +36,7 @@ #include "brw_context.h" #include "brw_eu.h" -#include "shader/program.h" +#include "program/program.h" struct brw_vs_prog_key { diff --git a/src/mesa/drivers/dri/i965/brw_vs_emit.c b/src/mesa/drivers/dri/i965/brw_vs_emit.c index 0b44deeb63..3b87fdcfc4 100644 --- a/src/mesa/drivers/dri/i965/brw_vs_emit.c +++ b/src/mesa/drivers/dri/i965/brw_vs_emit.c @@ -31,9 +31,9 @@ #include "main/macros.h" -#include "shader/program.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" +#include "program/program.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" #include "brw_context.h" #include "brw_vs.h" diff --git a/src/mesa/drivers/dri/i965/brw_vs_surface_state.c b/src/mesa/drivers/dri/i965/brw_vs_surface_state.c index 9bc585586c..568c2e3b03 100644 --- a/src/mesa/drivers/dri/i965/brw_vs_surface_state.c +++ b/src/mesa/drivers/dri/i965/brw_vs_surface_state.c @@ -31,7 +31,7 @@ #include "main/mtypes.h" #include "main/texstore.h" -#include "shader/prog_parameter.h" +#include "program/prog_parameter.h" #include "brw_context.h" #include "brw_state.h" diff --git a/src/mesa/drivers/dri/i965/brw_wm.h b/src/mesa/drivers/dri/i965/brw_wm.h index 277b6de442..f40977fab8 100644 --- a/src/mesa/drivers/dri/i965/brw_wm.h +++ b/src/mesa/drivers/dri/i965/brw_wm.h @@ -34,7 +34,7 @@ #define BRW_WM_H -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" #include "brw_context.h" #include "brw_eu.h" diff --git a/src/mesa/drivers/dri/i965/brw_wm_fp.c b/src/mesa/drivers/dri/i965/brw_wm_fp.c index d73c391582..0bef874b88 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_fp.c +++ b/src/mesa/drivers/dri/i965/brw_wm_fp.c @@ -37,9 +37,9 @@ #include "brw_wm.h" #include "brw_util.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" -#include "shader/prog_statevars.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" +#include "program/prog_statevars.h" /** An invalid texture target */ diff --git a/src/mesa/drivers/dri/i965/brw_wm_glsl.c b/src/mesa/drivers/dri/i965/brw_wm_glsl.c index fe3c89b721..575f89b17f 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_glsl.c +++ b/src/mesa/drivers/dri/i965/brw_wm_glsl.c @@ -1,7 +1,7 @@ #include "main/macros.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" -#include "shader/prog_optimize.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" +#include "program/prog_optimize.h" #include "brw_context.h" #include "brw_eu.h" #include "brw_wm.h" diff --git a/src/mesa/drivers/dri/i965/brw_wm_pass0.c b/src/mesa/drivers/dri/i965/brw_wm_pass0.c index 60bd92ed22..05de85a957 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_pass0.c +++ b/src/mesa/drivers/dri/i965/brw_wm_pass0.c @@ -32,7 +32,7 @@ #include "brw_context.h" #include "brw_wm.h" -#include "shader/prog_parameter.h" +#include "program/prog_parameter.h" diff --git a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c index 3998054eb4..c7b61240e7 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c +++ b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c @@ -32,7 +32,7 @@ #include "main/mtypes.h" #include "main/texstore.h" -#include "shader/prog_parameter.h" +#include "program/prog_parameter.h" #include "intel_mipmap_tree.h" #include "intel_batchbuffer.h" diff --git a/src/mesa/drivers/dri/i965/gen6_vs_state.c b/src/mesa/drivers/dri/i965/gen6_vs_state.c index 5916a13994..4080a9dedf 100644 --- a/src/mesa/drivers/dri/i965/gen6_vs_state.c +++ b/src/mesa/drivers/dri/i965/gen6_vs_state.c @@ -29,8 +29,8 @@ #include "brw_state.h" #include "brw_defines.h" #include "brw_util.h" -#include "shader/prog_parameter.h" -#include "shader/prog_statevars.h" +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" #include "intel_batchbuffer.h" static void diff --git a/src/mesa/drivers/dri/i965/gen6_wm_state.c b/src/mesa/drivers/dri/i965/gen6_wm_state.c index 1eb17ca627..325f6b43d3 100644 --- a/src/mesa/drivers/dri/i965/gen6_wm_state.c +++ b/src/mesa/drivers/dri/i965/gen6_wm_state.c @@ -29,8 +29,8 @@ #include "brw_state.h" #include "brw_defines.h" #include "brw_util.h" -#include "shader/prog_parameter.h" -#include "shader/prog_statevars.h" +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" #include "intel_batchbuffer.h" static void diff --git a/src/mesa/drivers/dri/r200/r200_fragshader.c b/src/mesa/drivers/dri/r200/r200_fragshader.c index 68e67377d9..2a9268dd34 100644 --- a/src/mesa/drivers/dri/r200/r200_fragshader.c +++ b/src/mesa/drivers/dri/r200/r200_fragshader.c @@ -30,7 +30,7 @@ #include "main/macros.h" #include "main/enums.h" #include "tnl/t_context.h" -#include "shader/program.h" +#include "program/program.h" #include "r200_context.h" #include "r200_ioctl.h" #include "r200_tex.h" diff --git a/src/mesa/drivers/dri/r200/r200_vertprog.c b/src/mesa/drivers/dri/r200/r200_vertprog.c index 12f869d96f..5d268319f3 100644 --- a/src/mesa/drivers/dri/r200/r200_vertprog.c +++ b/src/mesa/drivers/dri/r200/r200_vertprog.c @@ -33,11 +33,11 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include "main/glheader.h" #include "main/macros.h" #include "main/enums.h" -#include "shader/program.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" -#include "shader/prog_statevars.h" -#include "shader/programopt.h" +#include "program/program.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" +#include "program/programopt.h" #include "tnl/tnl.h" #include "r200_context.h" diff --git a/src/mesa/drivers/dri/r300/r300_context.h b/src/mesa/drivers/dri/r300/r300_context.h index fbb609b9f6..99540e3354 100644 --- a/src/mesa/drivers/dri/r300/r300_context.h +++ b/src/mesa/drivers/dri/r300/r300_context.h @@ -43,7 +43,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "radeon_common.h" #include "main/mtypes.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" #include "compiler/radeon_code.h" struct r300_context; diff --git a/src/mesa/drivers/dri/r300/r300_fragprog_common.c b/src/mesa/drivers/dri/r300/r300_fragprog_common.c index 7be2f74b5b..95f4306f60 100644 --- a/src/mesa/drivers/dri/r300/r300_fragprog_common.c +++ b/src/mesa/drivers/dri/r300/r300_fragprog_common.c @@ -38,8 +38,8 @@ #include "r300_fragprog_common.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" #include "compiler/radeon_compiler.h" diff --git a/src/mesa/drivers/dri/r300/r300_shader.c b/src/mesa/drivers/dri/r300/r300_shader.c index 9c24166ec5..a9bddf0577 100644 --- a/src/mesa/drivers/dri/r300/r300_shader.c +++ b/src/mesa/drivers/dri/r300/r300_shader.c @@ -27,7 +27,7 @@ #include "main/glheader.h" -#include "shader/program.h" +#include "program/program.h" #include "tnl/tnl.h" #include "r300_context.h" #include "r300_fragprog_common.h" diff --git a/src/mesa/drivers/dri/r300/r300_state.c b/src/mesa/drivers/dri/r300/r300_state.c index fa33be4998..0113eecaa3 100644 --- a/src/mesa/drivers/dri/r300/r300_state.c +++ b/src/mesa/drivers/dri/r300/r300_state.c @@ -49,8 +49,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "drivers/common/meta.h" #include "swrast/swrast.h" #include "swrast_setup/swrast_setup.h" -#include "shader/prog_parameter.h" -#include "shader/prog_statevars.h" +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" #include "vbo/vbo.h" #include "tnl/tnl.h" diff --git a/src/mesa/drivers/dri/r300/r300_vertprog.c b/src/mesa/drivers/dri/r300/r300_vertprog.c index a1fe378029..67d8b2b328 100644 --- a/src/mesa/drivers/dri/r300/r300_vertprog.c +++ b/src/mesa/drivers/dri/r300/r300_vertprog.c @@ -31,12 +31,12 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include "main/glheader.h" #include "main/macros.h" #include "main/enums.h" -#include "shader/program.h" -#include "shader/programopt.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" -#include "shader/prog_statevars.h" +#include "program/program.h" +#include "program/programopt.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" +#include "program/prog_statevars.h" #include "tnl/tnl.h" #include "compiler/radeon_compiler.h" diff --git a/src/mesa/drivers/dri/r300/radeon_mesa_to_rc.c b/src/mesa/drivers/dri/r300/radeon_mesa_to_rc.c index 9f9dec840b..471a3723cb 100644 --- a/src/mesa/drivers/dri/r300/radeon_mesa_to_rc.c +++ b/src/mesa/drivers/dri/r300/radeon_mesa_to_rc.c @@ -28,8 +28,8 @@ #include "radeon_mesa_to_rc.h" #include "main/mtypes.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" #include "compiler/radeon_compiler.h" #include "compiler/radeon_program.h" diff --git a/src/mesa/drivers/dri/r600/r700_assembler.c b/src/mesa/drivers/dri/r600/r700_assembler.c index 7b4d478596..61133e686f 100644 --- a/src/mesa/drivers/dri/r600/r700_assembler.c +++ b/src/mesa/drivers/dri/r600/r700_assembler.c @@ -32,7 +32,7 @@ #include "main/mtypes.h" #include "main/imports.h" -#include "shader/prog_parameter.h" +#include "program/prog_parameter.h" #include "radeon_debug.h" #include "r600_context.h" diff --git a/src/mesa/drivers/dri/r600/r700_assembler.h b/src/mesa/drivers/dri/r600/r700_assembler.h index 2d3c32487e..dbc6cdb190 100644 --- a/src/mesa/drivers/dri/r600/r700_assembler.h +++ b/src/mesa/drivers/dri/r600/r700_assembler.h @@ -28,7 +28,7 @@ #define _R700_ASSEMBLER_H_ #include "main/mtypes.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" #include "r700_chip.h" #include "r700_shaderinst.h" diff --git a/src/mesa/drivers/dri/r600/r700_fragprog.c b/src/mesa/drivers/dri/r600/r700_fragprog.c index 80fab71cf8..5a90f729e6 100644 --- a/src/mesa/drivers/dri/r600/r700_fragprog.c +++ b/src/mesa/drivers/dri/r600/r700_fragprog.c @@ -32,9 +32,9 @@ #include #include "main/imports.h" -#include "shader/prog_parameter.h" -#include "shader/prog_statevars.h" -#include "shader/program.h" +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" +#include "program/program.h" #include "r600_context.h" #include "r600_cmdbuf.h" diff --git a/src/mesa/drivers/dri/r600/r700_oglprog.c b/src/mesa/drivers/dri/r600/r700_oglprog.c index b7124e644a..8351792511 100644 --- a/src/mesa/drivers/dri/r600/r700_oglprog.c +++ b/src/mesa/drivers/dri/r600/r700_oglprog.c @@ -29,7 +29,7 @@ #include "main/glheader.h" #include "main/imports.h" -#include "shader/program.h" +#include "program/program.h" #include "tnl/tnl.h" #include "r600_context.h" diff --git a/src/mesa/drivers/dri/r600/r700_state.c b/src/mesa/drivers/dri/r600/r700_state.c index ac64bbf874..5ea8918611 100644 --- a/src/mesa/drivers/dri/r600/r700_state.c +++ b/src/mesa/drivers/dri/r600/r700_state.c @@ -41,8 +41,8 @@ #include "main/framebuffer.h" #include "drivers/common/meta.h" -#include "shader/prog_parameter.h" -#include "shader/prog_statevars.h" +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" #include "vbo/vbo.h" #include "r600_context.h" diff --git a/src/mesa/drivers/dri/r600/r700_vertprog.c b/src/mesa/drivers/dri/r600/r700_vertprog.c index 14dd2a5482..32f538f1c3 100644 --- a/src/mesa/drivers/dri/r600/r700_vertprog.c +++ b/src/mesa/drivers/dri/r600/r700_vertprog.c @@ -35,14 +35,14 @@ #include "main/mtypes.h" #include "tnl/t_context.h" -#include "shader/program.h" -#include "shader/prog_parameter.h" -#include "shader/prog_statevars.h" +#include "program/program.h" +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" #include "radeon_debug.h" #include "r600_context.h" #include "r600_cmdbuf.h" -#include "shader/programopt.h" +#include "program/programopt.h" #include "r700_debug.h" #include "r700_vertprog.h" diff --git a/src/mesa/drivers/glslcompiler/glslcompiler.c b/src/mesa/drivers/glslcompiler/glslcompiler.c index d58f32b293..5166600bed 100644 --- a/src/mesa/drivers/glslcompiler/glslcompiler.c +++ b/src/mesa/drivers/glslcompiler/glslcompiler.c @@ -50,8 +50,8 @@ #include "main/extensions.h" #include "main/framebuffer.h" #include "main/shaders.h" -#include "shader/shader_api.h" -#include "shader/prog_print.h" +#include "program/shader_api.h" +#include "program/prog_print.h" #include "drivers/common/driverfuncs.h" #include "tnl/tnl.h" #include "tnl/t_context.h" diff --git a/src/mesa/main/arbprogram.c b/src/mesa/main/arbprogram.c index b6577b81fb..26d781954e 100644 --- a/src/mesa/main/arbprogram.c +++ b/src/mesa/main/arbprogram.c @@ -36,10 +36,10 @@ #include "main/macros.h" #include "main/mtypes.h" #include "main/arbprogram.h" -#include "shader/arbprogparse.h" -#include "shader/nvfragparse.h" -#include "shader/nvvertparse.h" -#include "shader/program.h" +#include "program/arbprogparse.h" +#include "program/nvfragparse.h" +#include "program/nvvertparse.h" +#include "program/program.h" diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index 5b79e68769..0afd77d375 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -130,8 +130,8 @@ #include "version.h" #include "viewport.h" #include "vtxfmt.h" -#include "shader/program.h" -#include "shader/prog_print.h" +#include "program/program.h" +#include "program/prog_print.h" #if _HAVE_FULL_GL #include "math/m_matrix.h" #endif diff --git a/src/mesa/main/ffvertex_prog.c b/src/mesa/main/ffvertex_prog.c index 70ac47f36d..92fec09bad 100644 --- a/src/mesa/main/ffvertex_prog.c +++ b/src/mesa/main/ffvertex_prog.c @@ -38,12 +38,12 @@ #include "main/macros.h" #include "main/enums.h" #include "main/ffvertex_prog.h" -#include "shader/program.h" -#include "shader/prog_cache.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" -#include "shader/prog_statevars.h" +#include "program/program.h" +#include "program/prog_cache.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" +#include "program/prog_statevars.h" /** Max of number of lights and texture coord units */ diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c index 03f2707f4f..c121957aea 100644 --- a/src/mesa/main/get.c +++ b/src/mesa/main/get.c @@ -667,7 +667,7 @@ static const struct value_desc values[] = { { GL_MAX_3D_TEXTURE_SIZE, LOC_CUSTOM, TYPE_INT, offsetof(GLcontext, Const.Max3DTextureLevels), NO_EXTRA }, - /* GL_ARB_fragment_shader/OES_standard_derivatives */ + /* GL_ARB_fragment_program/OES_standard_derivatives */ { GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB, CONTEXT_ENUM(Hint.FragmentShaderDerivative), extra_ARB_fragment_shader }, #endif /* FEATURE_GL || FEATURE_ES2 */ diff --git a/src/mesa/main/nvprogram.c b/src/mesa/main/nvprogram.c index 7781648f4b..100ff2c4ab 100644 --- a/src/mesa/main/nvprogram.c +++ b/src/mesa/main/nvprogram.c @@ -43,12 +43,12 @@ #include "main/imports.h" #include "main/macros.h" #include "main/nvprogram.h" -#include "shader/arbprogparse.h" -#include "shader/nvfragparse.h" -#include "shader/nvvertparse.h" -#include "shader/program.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" +#include "program/arbprogparse.h" +#include "program/nvfragparse.h" +#include "program/nvvertparse.h" +#include "program/program.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c index 81c3964f93..0bd44154f2 100644 --- a/src/mesa/main/shaderapi.c +++ b/src/mesa/main/shaderapi.c @@ -42,9 +42,9 @@ #include "main/hash.h" #include "main/shaderapi.h" #include "main/shaderobj.h" -#include "shader/program.h" -#include "shader/prog_parameter.h" -#include "shader/prog_uniform.h" +#include "program/program.h" +#include "program/prog_parameter.h" +#include "program/prog_uniform.h" #include "slang/slang_compile.h" #include "slang/slang_link.h" diff --git a/src/mesa/main/shaderobj.c b/src/mesa/main/shaderobj.c index 01ed3c5c46..d4d2349d4b 100644 --- a/src/mesa/main/shaderobj.c +++ b/src/mesa/main/shaderobj.c @@ -34,9 +34,9 @@ #include "main/dispatch.h" #include "main/hash.h" #include "main/shaderobj.h" -#include "shader/program.h" -#include "shader/prog_parameter.h" -#include "shader/prog_uniform.h" +#include "program/program.h" +#include "program/prog_parameter.h" +#include "program/prog_uniform.h" /**********************************************************************/ diff --git a/src/mesa/main/shared.c b/src/mesa/main/shared.c index a44d2d51c4..f9d10f3bbe 100644 --- a/src/mesa/main/shared.c +++ b/src/mesa/main/shared.c @@ -38,7 +38,7 @@ #endif #include "bufferobj.h" #include "shared.h" -#include "shader/program.h" +#include "program/program.h" #include "dlist.h" #include "shaderobj.h" #if FEATURE_ARB_sync diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c index b971cc976e..2239ea4a85 100644 --- a/src/mesa/main/state.c +++ b/src/mesa/main/state.c @@ -41,8 +41,8 @@ #include "light.h" #include "matrix.h" #include "pixel.h" -#include "shader/program.h" -#include "shader/prog_parameter.h" +#include "program/program.h" +#include "program/prog_parameter.h" #include "state.h" #include "stencil.h" #include "texenvprogram.h" diff --git a/src/mesa/main/texenvprogram.c b/src/mesa/main/texenvprogram.c index 964ba13c70..30963bdf7d 100644 --- a/src/mesa/main/texenvprogram.c +++ b/src/mesa/main/texenvprogram.c @@ -28,13 +28,13 @@ #include "glheader.h" #include "imports.h" -#include "shader/program.h" -#include "shader/prog_parameter.h" -#include "shader/prog_cache.h" -#include "shader/prog_instruction.h" -#include "shader/prog_print.h" -#include "shader/prog_statevars.h" -#include "shader/programopt.h" +#include "program/program.h" +#include "program/prog_parameter.h" +#include "program/prog_cache.h" +#include "program/prog_instruction.h" +#include "program/prog_print.h" +#include "program/prog_statevars.h" +#include "program/programopt.h" #include "texenvprogram.h" diff --git a/src/mesa/main/texobj.c b/src/mesa/main/texobj.c index de37e34039..1df165cf6a 100644 --- a/src/mesa/main/texobj.c +++ b/src/mesa/main/texobj.c @@ -40,7 +40,7 @@ #include "teximage.h" #include "texobj.h" #include "mtypes.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" diff --git a/src/mesa/main/texparam.c b/src/mesa/main/texparam.c index ca03404f12..745a0aeec9 100644 --- a/src/mesa/main/texparam.c +++ b/src/mesa/main/texparam.c @@ -39,7 +39,7 @@ #include "main/texparam.h" #include "main/teximage.h" #include "main/texstate.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" /** diff --git a/src/mesa/main/texstate.c b/src/mesa/main/texstate.c index fce17c2b66..dae173d1bd 100644 --- a/src/mesa/main/texstate.c +++ b/src/mesa/main/texstate.c @@ -528,7 +528,7 @@ update_texture_state( GLcontext *ctx ) /* Get the bitmask of texture target enables. * enableBits will be a mask of the TEXTURE_*_BIT flags indicating * which texture targets are enabled (fixed function) or referenced - * by a fragment shader/program. When multiple flags are set, we'll + * by a fragment program/program. When multiple flags are set, we'll * settle on the one with highest priority (see below). */ if (vprog) { diff --git a/src/mesa/main/transformfeedback.c b/src/mesa/main/transformfeedback.c index 68a14d47c8..6126f1286d 100644 --- a/src/mesa/main/transformfeedback.c +++ b/src/mesa/main/transformfeedback.c @@ -39,8 +39,8 @@ #include "shaderobj.h" #include "main/dispatch.h" -#include "shader/prog_parameter.h" -//#include "shader/shader_api.h" +#include "program/prog_parameter.h" +//#include "program/shader_api.h" #if FEATURE_EXT_transform_feedback diff --git a/src/mesa/main/uniforms.c b/src/mesa/main/uniforms.c index 6452980e9c..aac4177f40 100644 --- a/src/mesa/main/uniforms.c +++ b/src/mesa/main/uniforms.c @@ -41,9 +41,9 @@ #include "main/shaderapi.h" #include "main/shaderobj.h" #include "main/uniforms.h" -#include "shader/prog_parameter.h" -#include "shader/prog_statevars.h" -#include "shader/prog_uniform.h" +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" +#include "program/prog_uniform.h" diff --git a/src/mesa/program/.gitignore b/src/mesa/program/.gitignore new file mode 100644 index 0000000000..086fd9a705 --- /dev/null +++ b/src/mesa/program/.gitignore @@ -0,0 +1 @@ +program_parse.output diff --git a/src/mesa/program/Makefile b/src/mesa/program/Makefile new file mode 100644 index 0000000000..400a543bda --- /dev/null +++ b/src/mesa/program/Makefile @@ -0,0 +1,7 @@ +all: program_parse.tab.c lex.yy.c + +program_parse.tab.c program_parse.tab.h: program_parse.y + bison -v -d $< + +lex.yy.c: program_lexer.l + flex --never-interactive $< diff --git a/src/mesa/program/arbprogparse.c b/src/mesa/program/arbprogparse.c new file mode 100644 index 0000000000..6373529e4e --- /dev/null +++ b/src/mesa/program/arbprogparse.c @@ -0,0 +1,217 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#define DEBUG_PARSING 0 + +/** + * \file arbprogparse.c + * ARB_*_program parser core + * \author Karl Rasche + */ + +/** +Notes on program parameters, etc. + +The instructions we emit will use six kinds of source registers: + + PROGRAM_INPUT - input registers + PROGRAM_TEMPORARY - temp registers + PROGRAM_ADDRESS - address/indirect register + PROGRAM_SAMPLER - texture sampler + PROGRAM_CONSTANT - indexes into program->Parameters, a known constant/literal + PROGRAM_STATE_VAR - indexes into program->Parameters, and may actually be: + + a state variable, like "state.fog.color", or + + a pointer to a "program.local[k]" parameter, or + + a pointer to a "program.env[k]" parameter + +Basically, all the program.local[] and program.env[] values will get mapped +into the unified gl_program->Parameters array. This solves the problem of +having three separate program parameter arrays. +*/ + + +#include "main/glheader.h" +#include "main/imports.h" +#include "main/context.h" +#include "main/mtypes.h" +#include "arbprogparse.h" +#include "programopt.h" +#include "prog_parameter.h" +#include "prog_statevars.h" +#include "prog_instruction.h" +#include "program_parser.h" + + +void +_mesa_parse_arb_fragment_program(GLcontext* ctx, GLenum target, + const GLvoid *str, GLsizei len, + struct gl_fragment_program *program) +{ + struct gl_program prog; + struct asm_parser_state state; + GLuint i; + + ASSERT(target == GL_FRAGMENT_PROGRAM_ARB); + + memset(&prog, 0, sizeof(prog)); + memset(&state, 0, sizeof(state)); + state.prog = &prog; + + if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len, + &state)) { + /* Error in the program. Just return. */ + return; + } + + if (program->Base.String != NULL) + free(program->Base.String); + + /* Copy the relevant contents of the arb_program struct into the + * fragment_program struct. + */ + program->Base.String = prog.String; + program->Base.NumInstructions = prog.NumInstructions; + program->Base.NumTemporaries = prog.NumTemporaries; + program->Base.NumParameters = prog.NumParameters; + program->Base.NumAttributes = prog.NumAttributes; + program->Base.NumAddressRegs = prog.NumAddressRegs; + program->Base.NumNativeInstructions = prog.NumNativeInstructions; + program->Base.NumNativeTemporaries = prog.NumNativeTemporaries; + program->Base.NumNativeParameters = prog.NumNativeParameters; + program->Base.NumNativeAttributes = prog.NumNativeAttributes; + program->Base.NumNativeAddressRegs = prog.NumNativeAddressRegs; + program->Base.NumAluInstructions = prog.NumAluInstructions; + program->Base.NumTexInstructions = prog.NumTexInstructions; + program->Base.NumTexIndirections = prog.NumTexIndirections; + program->Base.NumNativeAluInstructions = prog.NumAluInstructions; + program->Base.NumNativeTexInstructions = prog.NumTexInstructions; + program->Base.NumNativeTexIndirections = prog.NumTexIndirections; + program->Base.InputsRead = prog.InputsRead; + program->Base.OutputsWritten = prog.OutputsWritten; + for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++) { + program->Base.TexturesUsed[i] = prog.TexturesUsed[i]; + if (prog.TexturesUsed[i]) + program->Base.SamplersUsed |= (1 << i); + } + program->Base.ShadowSamplers = prog.ShadowSamplers; + switch (state.option.Fog) { + case OPTION_FOG_EXP: program->FogOption = GL_EXP; break; + case OPTION_FOG_EXP2: program->FogOption = GL_EXP2; break; + case OPTION_FOG_LINEAR: program->FogOption = GL_LINEAR; break; + default: program->FogOption = GL_NONE; break; + } + program->OriginUpperLeft = state.option.OriginUpperLeft; + program->PixelCenterInteger = state.option.PixelCenterInteger; + + program->UsesKill = state.fragment.UsesKill; + + if (program->FogOption) + program->Base.InputsRead |= FRAG_BIT_FOGC; + + if (program->Base.Instructions) + free(program->Base.Instructions); + program->Base.Instructions = prog.Instructions; + + if (program->Base.Parameters) + _mesa_free_parameter_list(program->Base.Parameters); + program->Base.Parameters = prog.Parameters; + + /* Append fog instructions now if the program has "OPTION ARB_fog_exp" + * or similar. We used to leave this up to drivers, but it appears + * there's no hardware that wants to do fog in a discrete stage separate + * from the fragment shader. + */ + if (program->FogOption != GL_NONE) { + _mesa_append_fog_code(ctx, program); + program->FogOption = GL_NONE; + } + +#if DEBUG_FP + printf("____________Fragment program %u ________\n", program->Base.Id); + _mesa_print_program(&program->Base); +#endif +} + + + +/** + * Parse the vertex program string. If success, update the given + * vertex_program object with the new program. Else, leave the vertex_program + * object unchanged. + */ +void +_mesa_parse_arb_vertex_program(GLcontext *ctx, GLenum target, + const GLvoid *str, GLsizei len, + struct gl_vertex_program *program) +{ + struct gl_program prog; + struct asm_parser_state state; + + ASSERT(target == GL_VERTEX_PROGRAM_ARB); + + memset(&prog, 0, sizeof(prog)); + memset(&state, 0, sizeof(state)); + state.prog = &prog; + + if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len, + &state)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramString(bad program)"); + return; + } + + if (program->Base.String != NULL) + free(program->Base.String); + + /* Copy the relevant contents of the arb_program struct into the + * vertex_program struct. + */ + program->Base.String = prog.String; + program->Base.NumInstructions = prog.NumInstructions; + program->Base.NumTemporaries = prog.NumTemporaries; + program->Base.NumParameters = prog.NumParameters; + program->Base.NumAttributes = prog.NumAttributes; + program->Base.NumAddressRegs = prog.NumAddressRegs; + program->Base.NumNativeInstructions = prog.NumNativeInstructions; + program->Base.NumNativeTemporaries = prog.NumNativeTemporaries; + program->Base.NumNativeParameters = prog.NumNativeParameters; + program->Base.NumNativeAttributes = prog.NumNativeAttributes; + program->Base.NumNativeAddressRegs = prog.NumNativeAddressRegs; + program->Base.InputsRead = prog.InputsRead; + program->Base.OutputsWritten = prog.OutputsWritten; + program->IsPositionInvariant = (state.option.PositionInvariant) + ? GL_TRUE : GL_FALSE; + + if (program->Base.Instructions) + free(program->Base.Instructions); + program->Base.Instructions = prog.Instructions; + + if (program->Base.Parameters) + _mesa_free_parameter_list(program->Base.Parameters); + program->Base.Parameters = prog.Parameters; + +#if DEBUG_VP + printf("____________Vertex program %u __________\n", program->Base.Id); + _mesa_print_program(&program->Base); +#endif +} diff --git a/src/mesa/program/arbprogparse.h b/src/mesa/program/arbprogparse.h new file mode 100644 index 0000000000..980d39fb9f --- /dev/null +++ b/src/mesa/program/arbprogparse.h @@ -0,0 +1,41 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef ARBPROGPARSE_H +#define ARBPROGPARSE_H + +#include "main/mtypes.h" + +extern void +_mesa_parse_arb_vertex_program(GLcontext *ctx, GLenum target, + const GLvoid *str, GLsizei len, + struct gl_vertex_program *program); + +extern void +_mesa_parse_arb_fragment_program(GLcontext *ctx, GLenum target, + const GLvoid *str, GLsizei len, + struct gl_fragment_program *program); + +#endif diff --git a/src/mesa/program/descrip.mms b/src/mesa/program/descrip.mms new file mode 100644 index 0000000000..59730020d0 --- /dev/null +++ b/src/mesa/program/descrip.mms @@ -0,0 +1,93 @@ +# Makefile for core library for VMS +# contributed by Jouk Jansen joukj@hrem.nano.tudelft.nl +# Last revision : 29 September 2008 +.first + define gl [---.include.gl] + define math [-.math] + define swrast [-.swrast] + define array_cache [-.array_cache] + define glapi [-.glapi] + define main [-.main] + define shader [-.shader] + +.include [---]mms-config. + +##### MACROS ##### + +VPATH = RCS + +INCDIR = [---.include],[-.main],[-.glapi],[.slang] +LIBDIR = [---.lib] +CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1,"__extension__=")/name=(as_is,short)/float=ieee/ieee=denorm + +SOURCES = \ + atifragshader.c \ + arbprogparse.c \ + arbprogram.c \ + nvfragparse.c \ + nvprogram.c \ + nvvertparse.c \ + program.c \ + programopt.c \ + prog_debug.c \ + prog_execute.c \ + prog_instruction.c \ + prog_parameter.c \ + prog_print.c \ + prog_cache.c \ + prog_statevars.c \ + shader_api.c prog_uniform.c + +OBJECTS = \ + atifragshader.obj,\ + arbprogparse.obj,\ + arbprogram.obj,\ + nvfragparse.obj,\ + nvprogram.obj,\ + nvvertparse.obj,\ + program.obj,\ + programopt.obj,\ + prog_debug.obj,\ + prog_execute.obj,\ + prog_instruction.obj,\ + prog_parameter.obj,\ + prog_print.obj,\ + prog_statevars.obj,\ + shader_api.obj,prog_uniform.obj,prog_cache.obj + +##### RULES ##### + +VERSION=Mesa V3.4 + +##### TARGETS ##### +all : + $(MMS)$(MMSQUALIFIERS) $(LIBDIR)$(GL_LIB) + set def [.slang] + $(MMS)$(MMSQUALIFIERS) + set def [-] + +# Make the library +$(LIBDIR)$(GL_LIB) : $(OBJECTS) + @ library $(LIBDIR)$(GL_LIB) $(OBJECTS) + +clean : + purge + delete *.obj;* + +atifragshader.obj : atifragshader.c +arbprogparse.obj : arbprogparse.c +arbprogram.obj : arbprogram.c +nvfragparse.obj : nvfragparse.c +nvprogram.obj : nvprogram.c +nvvertparse.obj : nvvertparse.c +program.obj : program.c +programopt. obj : programopt.c +prog_debug.obj : prog_debug.c +prog_execute.obj : prog_execute.c +prog_instruction.obj : prog_instruction.c +prog_parameter.obj : prog_parameter.c +prog_print.obj : prog_print.c +prog_statevars.obj : prog_statevars.c +shader_api.obj : shader_api.c +prog_uniform.obj : prog_uniform.c +prog_cache.obj : prog_cache.c diff --git a/src/mesa/program/hash_table.c b/src/mesa/program/hash_table.c new file mode 100644 index 0000000000..fa6ba2bfdf --- /dev/null +++ b/src/mesa/program/hash_table.c @@ -0,0 +1,159 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file hash_table.c + * \brief Implementation of a generic, opaque hash table data type. + * + * \author Ian Romanick + */ + +#include "main/imports.h" +#include "main/simple_list.h" +#include "hash_table.h" + +struct node { + struct node *next; + struct node *prev; +}; + +struct hash_table { + hash_func_t hash; + hash_compare_func_t compare; + + unsigned num_buckets; + struct node buckets[1]; +}; + + +struct hash_node { + struct node link; + const void *key; + void *data; +}; + + +struct hash_table * +hash_table_ctor(unsigned num_buckets, hash_func_t hash, + hash_compare_func_t compare) +{ + struct hash_table *ht; + unsigned i; + + + if (num_buckets < 16) { + num_buckets = 16; + } + + ht = malloc(sizeof(*ht) + ((num_buckets - 1) + * sizeof(ht->buckets[0]))); + if (ht != NULL) { + ht->hash = hash; + ht->compare = compare; + ht->num_buckets = num_buckets; + + for (i = 0; i < num_buckets; i++) { + make_empty_list(& ht->buckets[i]); + } + } + + return ht; +} + + +void +hash_table_dtor(struct hash_table *ht) +{ + hash_table_clear(ht); + free(ht); +} + + +void +hash_table_clear(struct hash_table *ht) +{ + struct node *node; + struct node *temp; + unsigned i; + + + for (i = 0; i < ht->num_buckets; i++) { + foreach_s(node, temp, & ht->buckets[i]) { + remove_from_list(node); + free(node); + } + + assert(is_empty_list(& ht->buckets[i])); + } +} + + +void * +hash_table_find(struct hash_table *ht, const void *key) +{ + const unsigned hash_value = (*ht->hash)(key); + const unsigned bucket = hash_value % ht->num_buckets; + struct node *node; + + foreach(node, & ht->buckets[bucket]) { + struct hash_node *hn = (struct hash_node *) node; + + if ((*ht->compare)(hn->key, key) == 0) { + return hn->data; + } + } + + return NULL; +} + + +void +hash_table_insert(struct hash_table *ht, void *data, const void *key) +{ + const unsigned hash_value = (*ht->hash)(key); + const unsigned bucket = hash_value % ht->num_buckets; + struct hash_node *node; + + node = calloc(1, sizeof(*node)); + + node->data = data; + node->key = key; + + insert_at_head(& ht->buckets[bucket], & node->link); +} + + +unsigned +hash_table_string_hash(const void *key) +{ + const char *str = (const char *) key; + unsigned hash = 5381; + + + while (*str != '\0') { + hash = (hash * 33) + *str; + str++; + } + + return hash; +} diff --git a/src/mesa/program/hash_table.h b/src/mesa/program/hash_table.h new file mode 100644 index 0000000000..7b302f5dbe --- /dev/null +++ b/src/mesa/program/hash_table.h @@ -0,0 +1,117 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file hash_table.h + * \brief Implementation of a generic, opaque hash table data type. + * + * \author Ian Romanick + */ + +#ifndef HASH_TABLE_H +#define HASH_TABLE_H + +#include + +struct hash_table; + +typedef unsigned (*hash_func_t)(const void *key); +typedef int (*hash_compare_func_t)(const void *key1, const void *key2); + +/** + * Hash table constructor + * + * Creates a hash table with the specified number of buckets. The supplied + * \c hash and \c compare routines are used when adding elements to the table + * and when searching for elements in the table. + * + * \param num_buckets Number of buckets (bins) in the hash table. + * \param hash Function used to compute hash value of input keys. + * \param compare Function used to compare keys. + */ +extern struct hash_table *hash_table_ctor(unsigned num_buckets, + hash_func_t hash, hash_compare_func_t compare); + + +/** + * Release all memory associated with a hash table + * + * \warning + * This function cannot release memory occupied either by keys or data. + */ +extern void hash_table_dtor(struct hash_table *ht); + + +/** + * Flush all entries from a hash table + * + * \param ht Table to be cleared of its entries. + */ +extern void hash_table_clear(struct hash_table *ht); + + +/** + * Search a hash table for a specific element + * + * \param ht Table to be searched + * \param key Key of the desired element + * + * \return + * The \c data value supplied to \c hash_table_insert when the element with + * the matching key was added. If no matching key exists in the table, + * \c NULL is returned. + */ +extern void *hash_table_find(struct hash_table *ht, const void *key); + + +/** + * Add an element to a hash table + */ +extern void hash_table_insert(struct hash_table *ht, void *data, + const void *key); + + +/** + * Compute hash value of a string + * + * Computes the hash value of a string using the DJB2 algorithm developed by + * Professor Daniel J. Bernstein. It was published on comp.lang.c once upon + * a time. I was unable to find the original posting in the archives. + * + * \param key Pointer to a NUL terminated string to be hashed. + * + * \sa hash_table_string_compare + */ +extern unsigned hash_table_string_hash(const void *key); + + +/** + * Compare two strings used as keys + * + * This is just a macro wrapper around \c strcmp. + * + * \sa hash_table_string_hash + */ +#define hash_table_string_compare ((hash_compare_func_t) strcmp) + +#endif /* HASH_TABLE_H */ diff --git a/src/mesa/program/lex.yy.c b/src/mesa/program/lex.yy.c new file mode 100644 index 0000000000..5b3cae7650 --- /dev/null +++ b/src/mesa/program/lex.yy.c @@ -0,0 +1,3654 @@ + +#line 3 "lex.yy.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart (FILE *input_file ,yyscan_t yyscanner ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void yypop_buffer_state (yyscan_t yyscanner ); + +static void yyensure_buffer_stack (yyscan_t yyscanner ); +static void yy_load_buffer_state (yyscan_t yyscanner ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *yyalloc (yy_size_t ,yyscan_t yyscanner ); +void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); +void yyfree (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 170 +#define YY_END_OF_BUFFER 171 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[850] = + { 0, + 0, 0, 171, 169, 167, 166, 169, 169, 139, 165, + 141, 141, 141, 141, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 167, 0, 0, 168, 139, + 0, 140, 142, 162, 162, 0, 0, 0, 0, 162, + 0, 0, 0, 0, 0, 0, 0, 119, 163, 120, + 121, 153, 153, 153, 153, 0, 141, 0, 127, 128, + 129, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 161, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 160, 160, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 159, 159, 159, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 150, 150, 150, 151, 151, 152, 143, + 142, 143, 0, 144, 11, 12, 139, 13, 139, 139, + 14, 15, 139, 16, 17, 18, 19, 20, 21, 6, + + 22, 23, 24, 25, 26, 28, 27, 29, 30, 31, + 32, 33, 34, 35, 139, 139, 139, 139, 139, 40, + 41, 139, 42, 43, 44, 45, 46, 47, 48, 139, + 49, 50, 51, 52, 53, 54, 55, 139, 56, 57, + 58, 59, 139, 139, 64, 65, 139, 139, 139, 139, + 139, 139, 0, 0, 0, 0, 142, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 80, 81, 83, + 0, 158, 0, 0, 0, 0, 0, 0, 97, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, + 156, 156, 109, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 147, 147, 148, 149, 0, 145, 11, + 11, 139, 12, 12, 12, 139, 139, 139, 139, 139, + 15, 15, 139, 130, 16, 16, 139, 17, 17, 139, + 18, 18, 139, 19, 19, 139, 20, 20, 139, 21, + 21, 139, 22, 22, 139, 24, 24, 139, 25, 25, + 139, 28, 28, 139, 27, 27, 139, 30, 30, 139, + 31, 31, 139, 32, 32, 139, 33, 33, 139, 34, + 34, 139, 35, 35, 139, 139, 139, 139, 36, 139, + 38, 139, 40, 40, 139, 41, 41, 139, 131, 42, + 42, 139, 43, 43, 139, 139, 45, 45, 139, 46, + + 46, 139, 47, 47, 139, 48, 48, 139, 139, 49, + 49, 139, 50, 50, 139, 51, 51, 139, 52, 52, + 139, 53, 53, 139, 54, 54, 139, 139, 10, 56, + 139, 57, 139, 58, 139, 59, 139, 60, 139, 62, + 139, 64, 64, 139, 139, 139, 139, 139, 139, 139, + 139, 0, 164, 0, 0, 0, 73, 74, 0, 0, + 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 155, 0, 0, 0, 113, 0, + 115, 0, 0, 0, 0, 0, 0, 154, 146, 139, + + 139, 139, 4, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 9, 37, 39, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 60, 139, 61, 62, 139, 63, 139, 139, 139, 139, + 139, 69, 139, 139, 0, 0, 0, 0, 0, 75, + 76, 0, 0, 0, 0, 84, 0, 0, 88, 91, + 0, 0, 0, 0, 0, 0, 0, 102, 103, 0, + 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 139, 139, 139, 139, 139, 139, + 5, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 7, 8, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 61, 139, 139, 63, 139, 139, + 139, 139, 139, 70, 139, 66, 0, 0, 0, 0, + 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 94, 0, 98, 99, 0, 101, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 117, 118, 0, 0, + + 125, 11, 3, 12, 135, 136, 139, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 24, 25, 28, 27, + 30, 31, 32, 33, 34, 35, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 139, 139, 139, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 139, + 139, 139, 139, 64, 65, 139, 68, 126, 0, 0, + 71, 0, 77, 0, 0, 0, 86, 0, 0, 0, + 0, 0, 0, 100, 0, 0, 106, 93, 0, 0, + 0, 0, 0, 0, 122, 0, 139, 132, 133, 139, + 60, 139, 62, 139, 67, 0, 0, 0, 0, 79, + + 82, 87, 0, 0, 92, 0, 0, 0, 105, 0, + 0, 0, 0, 114, 116, 0, 139, 139, 61, 63, + 2, 1, 0, 78, 0, 90, 0, 96, 104, 0, + 0, 111, 112, 123, 139, 134, 0, 89, 0, 107, + 110, 139, 72, 95, 139, 139, 137, 138, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 5, 1, 6, 7, 1, 1, 1, 1, + 1, 1, 8, 1, 8, 9, 1, 10, 11, 12, + 13, 14, 15, 15, 15, 15, 15, 1, 1, 1, + 1, 1, 1, 1, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 7, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 1, 1, 1, 1, 41, 1, 42, 43, 44, 45, + + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[68] = + { 0, + 1, 1, 1, 1, 1, 1, 2, 1, 3, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2 + } ; + +static yyconst flex_int16_t yy_base[853] = + { 0, + 0, 0, 1299, 1300, 66, 1300, 1293, 1294, 0, 69, + 85, 128, 140, 152, 151, 58, 56, 63, 76, 1272, + 158, 160, 39, 163, 173, 189, 52, 1265, 76, 1235, + 1234, 1246, 1230, 1244, 1243, 105, 1272, 1284, 1300, 0, + 225, 1300, 218, 160, 157, 20, 123, 66, 119, 192, + 1244, 1230, 54, 162, 1228, 1240, 194, 1300, 200, 195, + 98, 227, 196, 231, 235, 293, 305, 316, 1300, 1300, + 1300, 1249, 1262, 1256, 223, 1245, 1248, 1244, 1259, 107, + 298, 1241, 1255, 246, 1241, 1254, 1245, 1258, 1235, 1246, + 1237, 182, 1238, 1229, 1238, 1229, 1228, 1229, 144, 1223, + + 1229, 1240, 1231, 1225, 1222, 1223, 1227, 289, 1236, 1223, + 302, 1230, 1217, 1231, 1207, 65, 315, 276, 1227, 1226, + 1202, 1187, 1182, 1199, 1175, 1180, 1206, 279, 1195, 293, + 1190, 342, 299, 1192, 1173, 317, 1183, 1179, 1174, 207, + 1180, 1166, 1182, 1179, 1170, 320, 324, 1172, 1161, 1175, + 1178, 1160, 1175, 1162, 1159, 1166, 284, 1174, 227, 288, + 327, 342, 345, 1151, 1168, 1169, 1162, 1144, 318, 1145, + 1167, 1158, 330, 341, 345, 349, 353, 357, 361, 1300, + 419, 430, 436, 442, 440, 441, 1191, 0, 1190, 1173, + 1163, 443, 1183, 444, 451, 468, 470, 472, 471, 0, + + 496, 0, 497, 498, 0, 499, 500, 0, 524, 525, + 526, 536, 537, 553, 1178, 1171, 1184, 354, 356, 561, + 563, 1165, 564, 565, 1157, 580, 590, 591, 592, 1178, + 593, 617, 618, 619, 629, 630, 1155, 1165, 330, 362, + 419, 483, 445, 364, 646, 1153, 1145, 1144, 1129, 1129, + 1128, 1127, 1170, 1142, 1130, 662, 669, 643, 1134, 487, + 1131, 1125, 1125, 1119, 1132, 1132, 1117, 1300, 1300, 1132, + 1120, 646, 1127, 135, 1124, 1130, 561, 1125, 1300, 1116, + 1123, 1122, 1125, 1111, 1110, 1114, 1109, 448, 1114, 650, + 653, 665, 1300, 1106, 1104, 1104, 1112, 1113, 1095, 670, + + 1100, 1106, 486, 579, 655, 661, 668, 726, 732, 1112, + 682, 1119, 1110, 688, 730, 1117, 1116, 1109, 1123, 1113, + 1104, 712, 1111, 0, 1102, 731, 1109, 1100, 733, 1107, + 1098, 734, 1105, 1096, 736, 1103, 1094, 737, 1101, 1092, + 738, 1099, 1090, 739, 1097, 1088, 740, 1095, 1086, 741, + 1093, 1084, 742, 1091, 1082, 743, 1089, 1080, 744, 1087, + 1078, 745, 1085, 1076, 746, 1083, 1074, 747, 1081, 1072, + 748, 1079, 1070, 749, 1077, 1080, 1073, 1080, 0, 1073, + 0, 1088, 1063, 750, 1070, 1061, 751, 1068, 0, 1059, + 752, 1066, 1057, 755, 1064, 1063, 1054, 758, 1061, 1052, + + 776, 1059, 1050, 777, 1057, 1048, 779, 1055, 1058, 1045, + 780, 1052, 1043, 782, 1050, 1041, 783, 1048, 1039, 784, + 1046, 1037, 785, 1044, 1035, 786, 1042, 1041, 0, 1032, + 1039, 1030, 1037, 1028, 1035, 1026, 1033, 787, 1032, 788, + 1047, 1022, 789, 1029, 1028, 1006, 1000, 1005, 1011, 994, + 1009, 424, 1300, 1008, 998, 1002, 1300, 1300, 992, 1001, + 987, 1004, 987, 990, 984, 1300, 985, 984, 981, 988, + 981, 989, 985, 995, 992, 974, 980, 987, 971, 970, + 988, 970, 982, 981, 1300, 980, 970, 974, 1300, 961, + 1300, 966, 966, 974, 957, 958, 968, 1300, 1300, 1000, + + 982, 998, 0, 798, 996, 996, 995, 994, 993, 992, + 991, 990, 989, 988, 987, 986, 985, 984, 983, 982, + 981, 980, 979, 978, 965, 958, 0, 0, 0, 975, + 974, 973, 972, 971, 970, 969, 968, 967, 945, 965, + 964, 963, 962, 961, 960, 959, 958, 957, 956, 955, + 929, 936, 793, 927, 934, 794, 950, 949, 918, 921, + 901, 0, 902, 895, 902, 901, 902, 894, 912, 1300, + 1300, 894, 892, 902, 895, 1300, 890, 907, 516, 1300, + 898, 882, 883, 892, 883, 882, 882, 1300, 881, 890, + 880, 896, 893, 1300, 892, 890, 879, 880, 876, 868, + + 875, 870, 871, 866, 892, 892, 890, 904, 903, 898, + 0, 886, 885, 884, 883, 882, 881, 880, 879, 878, + 877, 876, 875, 874, 873, 872, 871, 870, 869, 868, + 0, 0, 867, 866, 865, 864, 863, 862, 861, 860, + 859, 804, 858, 857, 856, 855, 854, 853, 852, 851, + 850, 849, 848, 865, 839, 846, 862, 836, 843, 841, + 840, 818, 818, 0, 825, 0, 859, 858, 807, 825, + 1300, 820, 815, 808, 804, 816, 806, 804, 800, 816, + 807, 806, 1300, 1300, 809, 1300, 804, 797, 786, 797, + 789, 793, 806, 801, 804, 786, 1300, 1300, 798, 787, + + 1300, 0, 0, 0, 0, 0, 826, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 814, 813, 802, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 785, + 798, 779, 792, 0, 0, 656, 0, 0, 706, 702, + 1300, 649, 1300, 648, 648, 654, 1300, 637, 645, 610, + 612, 608, 608, 1300, 572, 583, 1300, 1300, 577, 573, + 560, 557, 542, 555, 1300, 539, 573, 0, 0, 572, + 0, 555, 0, 546, 0, 562, 551, 495, 479, 1300, + + 1300, 1300, 481, 481, 1300, 480, 443, 31, 1300, 141, + 166, 171, 186, 1300, 1300, 211, 236, 276, 0, 0, + 1300, 1300, 290, 1300, 325, 1300, 346, 1300, 1300, 343, + 341, 1300, 1300, 1300, 365, 0, 380, 1300, 371, 1300, + 1300, 486, 1300, 1300, 451, 458, 0, 0, 1300, 836, + 503, 839 + } ; + +static yyconst flex_int16_t yy_def[853] = + { 0, + 849, 1, 849, 849, 849, 849, 849, 850, 851, 849, + 849, 849, 849, 849, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 849, 849, 850, 849, 851, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 852, 849, 849, 849, 849, + 849, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + + 849, 849, 849, 849, 849, 849, 849, 849, 849, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 851, + + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + + 849, 849, 849, 849, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + + 849, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 851, 851, 851, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 851, 851, 851, 851, + 851, 851, 851, 851, 851, 849, 849, 849, 849, 849, + + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 851, 851, 851, 851, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 851, 851, 849, 849, 849, 849, + 849, 851, 849, 849, 851, 851, 851, 851, 0, 849, + 849, 849 + } ; + +static yyconst flex_int16_t yy_nxt[1368] = + { 0, + 4, 5, 6, 5, 7, 8, 9, 4, 10, 11, + 12, 13, 14, 11, 11, 15, 9, 16, 17, 18, + 19, 9, 9, 9, 20, 21, 22, 9, 23, 24, + 9, 25, 26, 27, 28, 9, 9, 29, 9, 9, + 9, 9, 9, 9, 9, 9, 30, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 31, 9, 32, 33, + 34, 9, 35, 9, 9, 9, 9, 36, 96, 36, + 41, 116, 137, 97, 80, 138, 829, 42, 43, 43, + 43, 43, 43, 43, 77, 81, 78, 119, 82, 117, + 83, 238, 79, 66, 67, 67, 67, 67, 67, 67, + + 84, 85, 239, 150, 68, 120, 36, 86, 36, 151, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 141, + 142, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 68, 143, 62, 63, 64, 65, 66, 67, 67, 67, + 67, 67, 67, 170, 194, 195, 69, 68, 66, 67, + 67, 67, 67, 67, 67, 218, 171, 219, 70, 68, + 66, 67, 67, 67, 67, 67, 67, 72, 139, 73, + 71, 68, 140, 68, 144, 92, 74, 145, 98, 88, + 467, 89, 75, 93, 76, 68, 90, 99, 94, 91, + 101, 100, 102, 103, 95, 468, 830, 68, 136, 133, + + 210, 133, 133, 152, 133, 104, 105, 133, 106, 107, + 108, 109, 110, 134, 111, 133, 112, 153, 133, 211, + 135, 831, 113, 114, 154, 115, 41, 43, 43, 43, + 43, 43, 43, 146, 147, 157, 832, 132, 165, 133, + 166, 161, 162, 167, 168, 833, 158, 163, 188, 159, + 133, 169, 160, 265, 189, 164, 834, 201, 133, 174, + 173, 175, 176, 132, 835, 266, 128, 129, 46, 47, + 48, 49, 172, 51, 52, 202, 285, 53, 54, 55, + 56, 57, 58, 130, 60, 61, 286, 243, 131, 244, + 173, 173, 173, 173, 177, 173, 173, 178, 179, 173, + + 173, 173, 181, 181, 181, 181, 181, 181, 228, 836, + 196, 197, 182, 66, 67, 67, 67, 67, 67, 67, + 198, 232, 229, 183, 68, 184, 184, 184, 184, 184, + 184, 240, 134, 241, 255, 233, 282, 287, 182, 135, + 258, 258, 283, 288, 242, 837, 258, 430, 164, 256, + 68, 257, 257, 257, 257, 257, 257, 258, 258, 258, + 261, 258, 258, 298, 258, 272, 258, 258, 258, 258, + 431, 258, 381, 299, 258, 258, 379, 838, 258, 432, + 440, 289, 258, 290, 258, 258, 291, 292, 380, 258, + 382, 839, 258, 303, 303, 303, 303, 840, 441, 841, + + 258, 842, 433, 258, 303, 303, 303, 303, 304, 303, + 303, 305, 306, 303, 303, 303, 303, 303, 303, 303, + 307, 303, 303, 303, 303, 303, 303, 303, 43, 43, + 43, 43, 43, 43, 843, 844, 434, 308, 132, 309, + 309, 309, 309, 309, 309, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 310, 313, 435, + 321, 325, 311, 314, 132, 322, 326, 438, 328, 847, + 565, 311, 315, 329, 322, 326, 848, 311, 314, 439, + 312, 316, 329, 323, 327, 331, 566, 334, 340, 337, + 332, 330, 335, 341, 338, 482, 845, 846, 483, 332, + + 436, 335, 341, 338, 40, 332, 828, 335, 333, 338, + 336, 342, 339, 343, 346, 349, 352, 355, 344, 347, + 350, 353, 356, 437, 827, 826, 825, 344, 347, 350, + 353, 356, 455, 824, 347, 350, 345, 348, 351, 354, + 357, 358, 361, 364, 823, 456, 359, 362, 365, 498, + 498, 498, 498, 367, 370, 359, 362, 365, 368, 371, + 822, 359, 362, 365, 360, 363, 366, 368, 371, 678, + 373, 821, 679, 368, 371, 374, 369, 372, 383, 820, + 386, 390, 393, 384, 374, 387, 391, 394, 819, 818, + 374, 817, 384, 375, 387, 391, 394, 397, 816, 815, + + 814, 385, 398, 388, 392, 395, 471, 400, 403, 406, + 410, 398, 401, 404, 407, 411, 813, 398, 812, 472, + 399, 401, 404, 407, 411, 811, 810, 401, 404, 407, + 402, 405, 408, 412, 413, 416, 419, 809, 808, 414, + 417, 420, 498, 498, 498, 498, 422, 425, 414, 417, + 420, 423, 426, 807, 414, 417, 420, 415, 418, 421, + 423, 426, 806, 442, 805, 804, 423, 426, 443, 424, + 427, 257, 257, 257, 257, 257, 257, 443, 257, 257, + 257, 257, 257, 257, 453, 453, 444, 453, 453, 803, + 453, 453, 453, 453, 453, 453, 802, 453, 801, 310, + + 453, 453, 800, 799, 453, 313, 485, 453, 453, 798, + 797, 453, 453, 492, 796, 493, 795, 494, 499, 498, + 498, 498, 312, 453, 498, 498, 498, 498, 316, 321, + 495, 498, 498, 498, 498, 309, 309, 309, 309, 309, + 309, 309, 309, 309, 309, 309, 309, 313, 325, 501, + 328, 331, 323, 334, 337, 340, 343, 346, 349, 352, + 355, 358, 361, 364, 367, 370, 373, 383, 386, 390, + 316, 327, 393, 330, 333, 397, 336, 339, 342, 345, + 348, 351, 354, 357, 360, 363, 366, 369, 372, 375, + 385, 388, 392, 400, 403, 395, 406, 410, 399, 413, + + 416, 419, 422, 425, 551, 554, 442, 794, 608, 609, + 655, 658, 793, 792, 736, 737, 402, 405, 791, 408, + 412, 790, 415, 418, 421, 424, 427, 552, 555, 444, + 610, 789, 788, 656, 659, 738, 38, 38, 38, 180, + 180, 787, 786, 785, 784, 783, 782, 781, 780, 779, + 778, 777, 776, 775, 774, 773, 772, 771, 770, 769, + 768, 767, 766, 765, 764, 763, 762, 761, 760, 759, + 758, 757, 756, 755, 754, 753, 659, 752, 751, 656, + 750, 749, 748, 747, 746, 745, 744, 743, 742, 741, + 740, 739, 735, 734, 733, 732, 731, 730, 729, 728, + + 727, 726, 725, 724, 723, 722, 721, 720, 719, 718, + 717, 716, 715, 714, 713, 712, 711, 710, 709, 708, + 707, 706, 705, 704, 703, 702, 701, 700, 699, 698, + 697, 696, 695, 694, 693, 692, 691, 690, 689, 688, + 687, 686, 685, 684, 683, 682, 681, 680, 677, 676, + 675, 674, 673, 672, 671, 670, 669, 668, 667, 666, + 665, 664, 663, 662, 661, 660, 657, 555, 654, 552, + 653, 652, 651, 650, 649, 648, 647, 646, 645, 644, + 643, 642, 641, 640, 639, 638, 637, 636, 635, 634, + 633, 632, 631, 630, 629, 628, 627, 626, 625, 624, + + 623, 622, 621, 620, 619, 618, 617, 616, 615, 614, + 613, 612, 611, 607, 606, 605, 604, 603, 602, 601, + 600, 599, 598, 597, 596, 595, 594, 593, 592, 591, + 590, 589, 588, 587, 586, 585, 584, 583, 582, 581, + 580, 579, 578, 577, 576, 575, 574, 573, 572, 571, + 570, 569, 568, 567, 564, 563, 562, 561, 560, 559, + 558, 557, 444, 556, 553, 550, 437, 549, 435, 548, + 433, 547, 431, 546, 545, 427, 544, 424, 543, 421, + 542, 418, 541, 415, 540, 412, 539, 538, 408, 537, + 405, 536, 402, 535, 399, 534, 533, 395, 532, 392, + + 531, 388, 530, 385, 529, 528, 527, 526, 525, 524, + 375, 523, 372, 522, 369, 521, 366, 520, 363, 519, + 360, 518, 357, 517, 354, 516, 351, 515, 348, 514, + 345, 513, 342, 512, 339, 511, 336, 510, 333, 509, + 330, 508, 327, 507, 323, 506, 505, 504, 503, 502, + 316, 500, 312, 497, 496, 491, 490, 489, 488, 487, + 486, 484, 481, 480, 479, 478, 477, 476, 475, 474, + 473, 470, 469, 466, 465, 464, 463, 462, 461, 460, + 459, 458, 457, 454, 289, 261, 452, 451, 450, 449, + 448, 447, 446, 445, 429, 428, 409, 396, 389, 378, + + 377, 376, 324, 320, 319, 318, 317, 302, 301, 300, + 297, 296, 295, 294, 293, 284, 281, 280, 279, 278, + 277, 276, 275, 274, 273, 271, 270, 269, 268, 267, + 264, 263, 262, 260, 259, 172, 254, 253, 252, 251, + 250, 249, 248, 247, 246, 245, 237, 236, 235, 234, + 231, 230, 227, 226, 225, 224, 223, 222, 221, 220, + 217, 216, 215, 214, 213, 212, 209, 208, 207, 206, + 205, 204, 203, 200, 199, 193, 192, 191, 190, 187, + 186, 185, 156, 155, 149, 148, 39, 127, 126, 125, + 124, 123, 122, 121, 118, 87, 39, 37, 849, 3, + + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849 + } ; + +static yyconst flex_int16_t yy_chk[1368] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5, 23, 5, + 10, 27, 46, 23, 17, 46, 808, 10, 10, 10, + 10, 10, 10, 10, 16, 17, 16, 29, 17, 27, + 18, 116, 16, 11, 11, 11, 11, 11, 11, 11, + + 18, 19, 116, 53, 11, 29, 36, 19, 36, 53, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 48, + 48, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 11, 48, 10, 10, 10, 10, 12, 12, 12, 12, + 12, 12, 12, 61, 80, 80, 12, 12, 13, 13, + 13, 13, 13, 13, 13, 99, 61, 99, 13, 13, + 14, 14, 14, 14, 14, 14, 14, 15, 47, 15, + 14, 14, 47, 12, 49, 22, 15, 49, 24, 21, + 274, 21, 15, 22, 15, 13, 21, 24, 22, 21, + 25, 24, 25, 25, 22, 274, 810, 14, 45, 45, + + 92, 44, 44, 54, 45, 25, 26, 44, 26, 26, + 26, 26, 26, 44, 26, 45, 26, 54, 44, 92, + 44, 811, 26, 26, 54, 26, 41, 43, 43, 43, + 43, 43, 43, 50, 50, 57, 812, 43, 60, 50, + 60, 59, 59, 60, 60, 813, 57, 59, 75, 57, + 50, 60, 57, 140, 75, 59, 816, 84, 59, 63, + 63, 63, 63, 43, 817, 140, 41, 41, 41, 41, + 41, 41, 62, 41, 41, 84, 159, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 159, 118, 41, 118, + 62, 62, 62, 62, 64, 64, 64, 64, 65, 65, + + 65, 65, 66, 66, 66, 66, 66, 66, 108, 818, + 81, 81, 66, 67, 67, 67, 67, 67, 67, 67, + 81, 111, 108, 68, 67, 68, 68, 68, 68, 68, + 68, 117, 128, 117, 130, 111, 157, 160, 66, 128, + 133, 133, 157, 160, 117, 823, 133, 239, 130, 132, + 67, 132, 132, 132, 132, 132, 132, 133, 136, 136, + 136, 146, 146, 169, 136, 147, 147, 146, 161, 161, + 239, 147, 219, 169, 161, 136, 218, 825, 146, 240, + 244, 161, 147, 162, 162, 161, 163, 163, 218, 162, + 219, 827, 163, 173, 173, 173, 173, 830, 244, 831, + + 162, 835, 240, 163, 174, 174, 174, 174, 175, 175, + 175, 175, 176, 176, 176, 176, 177, 177, 177, 177, + 178, 178, 178, 178, 179, 179, 179, 179, 181, 181, + 181, 181, 181, 181, 837, 839, 241, 182, 181, 182, + 182, 182, 182, 182, 182, 183, 183, 183, 183, 183, + 183, 184, 184, 184, 184, 184, 184, 185, 186, 241, + 192, 194, 185, 186, 181, 192, 194, 243, 195, 845, + 452, 185, 186, 195, 192, 194, 846, 185, 186, 243, + 185, 186, 195, 192, 194, 196, 452, 197, 199, 198, + 196, 195, 197, 199, 198, 288, 842, 842, 288, 196, + + 242, 197, 199, 198, 851, 196, 807, 197, 196, 198, + 197, 199, 198, 201, 203, 204, 206, 207, 201, 203, + 204, 206, 207, 242, 806, 804, 803, 201, 203, 204, + 206, 207, 260, 799, 203, 204, 201, 203, 204, 206, + 207, 209, 210, 211, 798, 260, 209, 210, 211, 303, + 303, 303, 303, 212, 213, 209, 210, 211, 212, 213, + 797, 209, 210, 211, 209, 210, 211, 212, 213, 579, + 214, 796, 579, 212, 213, 214, 212, 213, 220, 794, + 221, 223, 224, 220, 214, 221, 223, 224, 792, 790, + 214, 787, 220, 214, 221, 223, 224, 226, 786, 784, + + 783, 220, 226, 221, 223, 224, 277, 227, 228, 229, + 231, 226, 227, 228, 229, 231, 782, 226, 781, 277, + 226, 227, 228, 229, 231, 780, 779, 227, 228, 229, + 227, 228, 229, 231, 232, 233, 234, 776, 775, 232, + 233, 234, 304, 304, 304, 304, 235, 236, 232, 233, + 234, 235, 236, 773, 232, 233, 234, 232, 233, 234, + 235, 236, 772, 245, 771, 770, 235, 236, 245, 235, + 236, 256, 256, 256, 256, 256, 256, 245, 257, 257, + 257, 257, 257, 257, 258, 258, 245, 272, 272, 769, + 258, 290, 290, 272, 291, 291, 768, 290, 766, 311, + + 291, 258, 765, 764, 272, 314, 292, 292, 290, 762, + 760, 291, 292, 300, 759, 300, 756, 300, 305, 305, + 305, 305, 311, 292, 306, 306, 306, 306, 314, 322, + 300, 307, 307, 307, 307, 308, 308, 308, 308, 308, + 308, 309, 309, 309, 309, 309, 309, 315, 326, 315, + 329, 332, 322, 335, 338, 341, 344, 347, 350, 353, + 356, 359, 362, 365, 368, 371, 374, 384, 387, 391, + 315, 326, 394, 329, 332, 398, 335, 338, 341, 344, + 347, 350, 353, 356, 359, 362, 365, 368, 371, 374, + 384, 387, 391, 401, 404, 394, 407, 411, 398, 414, + + 417, 420, 423, 426, 438, 440, 443, 753, 504, 504, + 553, 556, 752, 751, 642, 642, 401, 404, 750, 407, + 411, 738, 414, 417, 420, 423, 426, 438, 440, 443, + 504, 737, 736, 553, 556, 642, 850, 850, 850, 852, + 852, 707, 700, 699, 696, 695, 694, 693, 692, 691, + 690, 689, 688, 687, 685, 682, 681, 680, 679, 678, + 677, 676, 675, 674, 673, 672, 670, 669, 668, 667, + 665, 663, 662, 661, 660, 659, 658, 657, 656, 655, + 654, 653, 652, 651, 650, 649, 648, 647, 646, 645, + 644, 643, 641, 640, 639, 638, 637, 636, 635, 634, + + 633, 630, 629, 628, 627, 626, 625, 624, 623, 622, + 621, 620, 619, 618, 617, 616, 615, 614, 613, 612, + 610, 609, 608, 607, 606, 605, 604, 603, 602, 601, + 600, 599, 598, 597, 596, 595, 593, 592, 591, 590, + 589, 587, 586, 585, 584, 583, 582, 581, 578, 577, + 575, 574, 573, 572, 569, 568, 567, 566, 565, 564, + 563, 561, 560, 559, 558, 557, 555, 554, 552, 551, + 550, 549, 548, 547, 546, 545, 544, 543, 542, 541, + 540, 539, 538, 537, 536, 535, 534, 533, 532, 531, + 530, 526, 525, 524, 523, 522, 521, 520, 519, 518, + + 517, 516, 515, 514, 513, 512, 511, 510, 509, 508, + 507, 506, 505, 502, 501, 500, 497, 496, 495, 494, + 493, 492, 490, 488, 487, 486, 484, 483, 482, 481, + 480, 479, 478, 477, 476, 475, 474, 473, 472, 471, + 470, 469, 468, 467, 465, 464, 463, 462, 461, 460, + 459, 456, 455, 454, 451, 450, 449, 448, 447, 446, + 445, 444, 442, 441, 439, 437, 436, 435, 434, 433, + 432, 431, 430, 428, 427, 425, 424, 422, 421, 419, + 418, 416, 415, 413, 412, 410, 409, 408, 406, 405, + 403, 402, 400, 399, 397, 396, 395, 393, 392, 390, + + 388, 386, 385, 383, 382, 380, 378, 377, 376, 375, + 373, 372, 370, 369, 367, 366, 364, 363, 361, 360, + 358, 357, 355, 354, 352, 351, 349, 348, 346, 345, + 343, 342, 340, 339, 337, 336, 334, 333, 331, 330, + 328, 327, 325, 323, 321, 320, 319, 318, 317, 316, + 313, 312, 310, 302, 301, 299, 298, 297, 296, 295, + 294, 289, 287, 286, 285, 284, 283, 282, 281, 280, + 278, 276, 275, 273, 271, 270, 267, 266, 265, 264, + 263, 262, 261, 259, 255, 254, 253, 252, 251, 250, + 249, 248, 247, 246, 238, 237, 230, 225, 222, 217, + + 216, 215, 193, 191, 190, 189, 187, 172, 171, 170, + 168, 167, 166, 165, 164, 158, 156, 155, 154, 153, + 152, 151, 150, 149, 148, 145, 144, 143, 142, 141, + 139, 138, 137, 135, 134, 131, 129, 127, 126, 125, + 124, 123, 122, 121, 120, 119, 115, 114, 113, 112, + 110, 109, 107, 106, 105, 104, 103, 102, 101, 100, + 98, 97, 96, 95, 94, 93, 91, 90, 89, 88, + 87, 86, 85, 83, 82, 79, 78, 77, 76, 74, + 73, 72, 56, 55, 52, 51, 38, 37, 35, 34, + 33, 32, 31, 30, 28, 20, 8, 7, 3, 849, + + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, + 849, 849, 849, 849, 849, 849, 849 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "program_lexer.l" +#line 2 "program_lexer.l" +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "main/glheader.h" +#include "main/imports.h" +#include "program/prog_instruction.h" +#include "program/prog_statevars.h" +#include "program/symbol_table.h" +#include "program/program_parser.h" +#include "program/program_parse.tab.h" + +#define require_ARB_vp (yyextra->mode == ARB_vertex) +#define require_ARB_fp (yyextra->mode == ARB_fragment) +#define require_NV_fp (yyextra->option.NV_fragment) +#define require_shadow (yyextra->option.Shadow) +#define require_rect (yyextra->option.TexRect) +#define require_texarray (yyextra->option.TexArray) + +#ifndef HAVE_UNISTD_H +#define YY_NO_UNISTD_H +#endif + +#define return_token_or_IDENTIFIER(condition, token) \ + do { \ + if (condition) { \ + return token; \ + } else { \ + return handle_ident(yyextra, yytext, yylval); \ + } \ + } while (0) + +#define return_token_or_DOT(condition, token) \ + do { \ + if (condition) { \ + return token; \ + } else { \ + yyless(1); \ + return DOT; \ + } \ + } while (0) + + +#define return_opcode(condition, token, opcode, len) \ + do { \ + if (condition && \ + _mesa_parse_instruction_suffix(yyextra, \ + yytext + len, \ + & yylval->temp_inst)) { \ + yylval->temp_inst.Opcode = OPCODE_ ## opcode; \ + return token; \ + } else { \ + return handle_ident(yyextra, yytext, yylval); \ + } \ + } while (0) + +#define SWIZZLE_INVAL MAKE_SWIZZLE4(SWIZZLE_NIL, SWIZZLE_NIL, \ + SWIZZLE_NIL, SWIZZLE_NIL) + +static unsigned +mask_from_char(char c) +{ + switch (c) { + case 'x': + case 'r': + return WRITEMASK_X; + case 'y': + case 'g': + return WRITEMASK_Y; + case 'z': + case 'b': + return WRITEMASK_Z; + case 'w': + case 'a': + return WRITEMASK_W; + } + + return 0; +} + +static unsigned +swiz_from_char(char c) +{ + switch (c) { + case 'x': + case 'r': + return SWIZZLE_X; + case 'y': + case 'g': + return SWIZZLE_Y; + case 'z': + case 'b': + return SWIZZLE_Z; + case 'w': + case 'a': + return SWIZZLE_W; + } + + return 0; +} + +static int +handle_ident(struct asm_parser_state *state, const char *text, YYSTYPE *lval) +{ + lval->string = strdup(text); + + return (_mesa_symbol_table_find_symbol(state->st, 0, text) == NULL) + ? IDENTIFIER : USED_IDENTIFIER; +} + +#define YY_USER_ACTION \ + do { \ + yylloc->first_column = yylloc->last_column; \ + yylloc->last_column += yyleng; \ + if ((yylloc->first_line == 1) \ + && (yylloc->first_column == 1)) { \ + yylloc->position = 1; \ + } else { \ + yylloc->position += yylloc->last_column - yylloc->first_column; \ + } \ + } while(0); + +#define YY_EXTRA_TYPE struct asm_parser_state * +#line 1155 "lex.yy.c" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + YYLTYPE * yylloc_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + + # define yylloc yyg->yylloc_r + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (yyscan_t yyscanner ); + +int yyget_debug (yyscan_t yyscanner ); + +void yyset_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *yyget_in (yyscan_t yyscanner ); + +void yyset_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *yyget_out (yyscan_t yyscanner ); + +void yyset_out (FILE * out_str ,yyscan_t yyscanner ); + +int yyget_leng (yyscan_t yyscanner ); + +char *yyget_text (yyscan_t yyscanner ); + +int yyget_lineno (yyscan_t yyscanner ); + +void yyset_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * yyget_lval (yyscan_t yyscanner ); + +void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + + YYLTYPE *yyget_lloc (yyscan_t yyscanner ); + + void yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (yyscan_t yyscanner ); +#else +extern int yywrap (yyscan_t yyscanner ); +#endif +#endif + + static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner); + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + unsigned n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + +#line 156 "program_lexer.l" + + +#line 1399 "lex.yy.c" + + yylval = yylval_param; + + yylloc = yylloc_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + yy_load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 850 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 1300 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 158 "program_lexer.l" +{ return ARBvp_10; } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 159 "program_lexer.l" +{ return ARBfp_10; } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 160 "program_lexer.l" +{ + yylval->integer = at_address; + return_token_or_IDENTIFIER(require_ARB_vp, ADDRESS); +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 164 "program_lexer.l" +{ return ALIAS; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 165 "program_lexer.l" +{ return ATTRIB; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 166 "program_lexer.l" +{ return END; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 167 "program_lexer.l" +{ return OPTION; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 168 "program_lexer.l" +{ return OUTPUT; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 169 "program_lexer.l" +{ return PARAM; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 170 "program_lexer.l" +{ yylval->integer = at_temp; return TEMP; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 172 "program_lexer.l" +{ return_opcode( 1, VECTOR_OP, ABS, 3); } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 173 "program_lexer.l" +{ return_opcode( 1, BIN_OP, ADD, 3); } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 174 "program_lexer.l" +{ return_opcode(require_ARB_vp, ARL, ARL, 3); } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 176 "program_lexer.l" +{ return_opcode(require_ARB_fp, TRI_OP, CMP, 3); } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 177 "program_lexer.l" +{ return_opcode(require_ARB_fp, SCALAR_OP, COS, 3); } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 179 "program_lexer.l" +{ return_opcode(require_NV_fp, VECTOR_OP, DDX, 3); } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 180 "program_lexer.l" +{ return_opcode(require_NV_fp, VECTOR_OP, DDY, 3); } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 181 "program_lexer.l" +{ return_opcode( 1, BIN_OP, DP3, 3); } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 182 "program_lexer.l" +{ return_opcode( 1, BIN_OP, DP4, 3); } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 183 "program_lexer.l" +{ return_opcode( 1, BIN_OP, DPH, 3); } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 184 "program_lexer.l" +{ return_opcode( 1, BIN_OP, DST, 3); } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 186 "program_lexer.l" +{ return_opcode( 1, SCALAR_OP, EX2, 3); } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 187 "program_lexer.l" +{ return_opcode(require_ARB_vp, SCALAR_OP, EXP, 3); } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 189 "program_lexer.l" +{ return_opcode( 1, VECTOR_OP, FLR, 3); } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 190 "program_lexer.l" +{ return_opcode( 1, VECTOR_OP, FRC, 3); } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 192 "program_lexer.l" +{ return_opcode(require_ARB_fp, KIL, KIL, 3); } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 194 "program_lexer.l" +{ return_opcode( 1, VECTOR_OP, LIT, 3); } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 195 "program_lexer.l" +{ return_opcode( 1, SCALAR_OP, LG2, 3); } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 196 "program_lexer.l" +{ return_opcode(require_ARB_vp, SCALAR_OP, LOG, 3); } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 197 "program_lexer.l" +{ return_opcode(require_ARB_fp, TRI_OP, LRP, 3); } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 199 "program_lexer.l" +{ return_opcode( 1, TRI_OP, MAD, 3); } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 200 "program_lexer.l" +{ return_opcode( 1, BIN_OP, MAX, 3); } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 201 "program_lexer.l" +{ return_opcode( 1, BIN_OP, MIN, 3); } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 202 "program_lexer.l" +{ return_opcode( 1, VECTOR_OP, MOV, 3); } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 203 "program_lexer.l" +{ return_opcode( 1, BIN_OP, MUL, 3); } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 205 "program_lexer.l" +{ return_opcode(require_NV_fp, VECTOR_OP, PK2H, 4); } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 206 "program_lexer.l" +{ return_opcode(require_NV_fp, VECTOR_OP, PK2US, 5); } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 207 "program_lexer.l" +{ return_opcode(require_NV_fp, VECTOR_OP, PK4B, 4); } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 208 "program_lexer.l" +{ return_opcode(require_NV_fp, VECTOR_OP, PK4UB, 5); } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 209 "program_lexer.l" +{ return_opcode( 1, BINSC_OP, POW, 3); } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 211 "program_lexer.l" +{ return_opcode( 1, SCALAR_OP, RCP, 3); } + YY_BREAK +case 42: +YY_RULE_SETUP +#line 212 "program_lexer.l" +{ return_opcode(require_NV_fp, BIN_OP, RFL, 3); } + YY_BREAK +case 43: +YY_RULE_SETUP +#line 213 "program_lexer.l" +{ return_opcode( 1, SCALAR_OP, RSQ, 3); } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 215 "program_lexer.l" +{ return_opcode(require_ARB_fp, SCALAR_OP, SCS, 3); } + YY_BREAK +case 45: +YY_RULE_SETUP +#line 216 "program_lexer.l" +{ return_opcode(require_NV_fp, BIN_OP, SEQ, 3); } + YY_BREAK +case 46: +YY_RULE_SETUP +#line 217 "program_lexer.l" +{ return_opcode(require_NV_fp, BIN_OP, SFL, 3); } + YY_BREAK +case 47: +YY_RULE_SETUP +#line 218 "program_lexer.l" +{ return_opcode( 1, BIN_OP, SGE, 3); } + YY_BREAK +case 48: +YY_RULE_SETUP +#line 219 "program_lexer.l" +{ return_opcode(require_NV_fp, BIN_OP, SGT, 3); } + YY_BREAK +case 49: +YY_RULE_SETUP +#line 220 "program_lexer.l" +{ return_opcode(require_ARB_fp, SCALAR_OP, SIN, 3); } + YY_BREAK +case 50: +YY_RULE_SETUP +#line 221 "program_lexer.l" +{ return_opcode(require_NV_fp, BIN_OP, SLE, 3); } + YY_BREAK +case 51: +YY_RULE_SETUP +#line 222 "program_lexer.l" +{ return_opcode( 1, BIN_OP, SLT, 3); } + YY_BREAK +case 52: +YY_RULE_SETUP +#line 223 "program_lexer.l" +{ return_opcode(require_NV_fp, BIN_OP, SNE, 3); } + YY_BREAK +case 53: +YY_RULE_SETUP +#line 224 "program_lexer.l" +{ return_opcode(require_NV_fp, BIN_OP, STR, 3); } + YY_BREAK +case 54: +YY_RULE_SETUP +#line 225 "program_lexer.l" +{ return_opcode( 1, BIN_OP, SUB, 3); } + YY_BREAK +case 55: +YY_RULE_SETUP +#line 226 "program_lexer.l" +{ return_opcode( 1, SWZ, SWZ, 3); } + YY_BREAK +case 56: +YY_RULE_SETUP +#line 228 "program_lexer.l" +{ return_opcode(require_ARB_fp, SAMPLE_OP, TEX, 3); } + YY_BREAK +case 57: +YY_RULE_SETUP +#line 229 "program_lexer.l" +{ return_opcode(require_ARB_fp, SAMPLE_OP, TXB, 3); } + YY_BREAK +case 58: +YY_RULE_SETUP +#line 230 "program_lexer.l" +{ return_opcode(require_NV_fp, TXD_OP, TXD, 3); } + YY_BREAK +case 59: +YY_RULE_SETUP +#line 231 "program_lexer.l" +{ return_opcode(require_ARB_fp, SAMPLE_OP, TXP, 3); } + YY_BREAK +case 60: +YY_RULE_SETUP +#line 233 "program_lexer.l" +{ return_opcode(require_NV_fp, SCALAR_OP, UP2H, 4); } + YY_BREAK +case 61: +YY_RULE_SETUP +#line 234 "program_lexer.l" +{ return_opcode(require_NV_fp, SCALAR_OP, UP2US, 5); } + YY_BREAK +case 62: +YY_RULE_SETUP +#line 235 "program_lexer.l" +{ return_opcode(require_NV_fp, SCALAR_OP, UP4B, 4); } + YY_BREAK +case 63: +YY_RULE_SETUP +#line 236 "program_lexer.l" +{ return_opcode(require_NV_fp, SCALAR_OP, UP4UB, 5); } + YY_BREAK +case 64: +YY_RULE_SETUP +#line 238 "program_lexer.l" +{ return_opcode(require_NV_fp, TRI_OP, X2D, 3); } + YY_BREAK +case 65: +YY_RULE_SETUP +#line 239 "program_lexer.l" +{ return_opcode( 1, BIN_OP, XPD, 3); } + YY_BREAK +case 66: +YY_RULE_SETUP +#line 241 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_vp, VERTEX); } + YY_BREAK +case 67: +YY_RULE_SETUP +#line 242 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp, FRAGMENT); } + YY_BREAK +case 68: +YY_RULE_SETUP +#line 243 "program_lexer.l" +{ return PROGRAM; } + YY_BREAK +case 69: +YY_RULE_SETUP +#line 244 "program_lexer.l" +{ return STATE; } + YY_BREAK +case 70: +YY_RULE_SETUP +#line 245 "program_lexer.l" +{ return RESULT; } + YY_BREAK +case 71: +YY_RULE_SETUP +#line 247 "program_lexer.l" +{ return AMBIENT; } + YY_BREAK +case 72: +YY_RULE_SETUP +#line 248 "program_lexer.l" +{ return ATTENUATION; } + YY_BREAK +case 73: +YY_RULE_SETUP +#line 249 "program_lexer.l" +{ return BACK; } + YY_BREAK +case 74: +YY_RULE_SETUP +#line 250 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, CLIP); } + YY_BREAK +case 75: +YY_RULE_SETUP +#line 251 "program_lexer.l" +{ return COLOR; } + YY_BREAK +case 76: +YY_RULE_SETUP +#line 252 "program_lexer.l" +{ return_token_or_DOT(require_ARB_fp, DEPTH); } + YY_BREAK +case 77: +YY_RULE_SETUP +#line 253 "program_lexer.l" +{ return DIFFUSE; } + YY_BREAK +case 78: +YY_RULE_SETUP +#line 254 "program_lexer.l" +{ return DIRECTION; } + YY_BREAK +case 79: +YY_RULE_SETUP +#line 255 "program_lexer.l" +{ return EMISSION; } + YY_BREAK +case 80: +YY_RULE_SETUP +#line 256 "program_lexer.l" +{ return ENV; } + YY_BREAK +case 81: +YY_RULE_SETUP +#line 257 "program_lexer.l" +{ return EYE; } + YY_BREAK +case 82: +YY_RULE_SETUP +#line 258 "program_lexer.l" +{ return FOGCOORD; } + YY_BREAK +case 83: +YY_RULE_SETUP +#line 259 "program_lexer.l" +{ return FOG; } + YY_BREAK +case 84: +YY_RULE_SETUP +#line 260 "program_lexer.l" +{ return FRONT; } + YY_BREAK +case 85: +YY_RULE_SETUP +#line 261 "program_lexer.l" +{ return HALF; } + YY_BREAK +case 86: +YY_RULE_SETUP +#line 262 "program_lexer.l" +{ return INVERSE; } + YY_BREAK +case 87: +YY_RULE_SETUP +#line 263 "program_lexer.l" +{ return INVTRANS; } + YY_BREAK +case 88: +YY_RULE_SETUP +#line 264 "program_lexer.l" +{ return LIGHT; } + YY_BREAK +case 89: +YY_RULE_SETUP +#line 265 "program_lexer.l" +{ return LIGHTMODEL; } + YY_BREAK +case 90: +YY_RULE_SETUP +#line 266 "program_lexer.l" +{ return LIGHTPROD; } + YY_BREAK +case 91: +YY_RULE_SETUP +#line 267 "program_lexer.l" +{ return LOCAL; } + YY_BREAK +case 92: +YY_RULE_SETUP +#line 268 "program_lexer.l" +{ return MATERIAL; } + YY_BREAK +case 93: +YY_RULE_SETUP +#line 269 "program_lexer.l" +{ return MAT_PROGRAM; } + YY_BREAK +case 94: +YY_RULE_SETUP +#line 270 "program_lexer.l" +{ return MATRIX; } + YY_BREAK +case 95: +YY_RULE_SETUP +#line 271 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, MATRIXINDEX); } + YY_BREAK +case 96: +YY_RULE_SETUP +#line 272 "program_lexer.l" +{ return MODELVIEW; } + YY_BREAK +case 97: +YY_RULE_SETUP +#line 273 "program_lexer.l" +{ return MVP; } + YY_BREAK +case 98: +YY_RULE_SETUP +#line 274 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, NORMAL); } + YY_BREAK +case 99: +YY_RULE_SETUP +#line 275 "program_lexer.l" +{ return OBJECT; } + YY_BREAK +case 100: +YY_RULE_SETUP +#line 276 "program_lexer.l" +{ return PALETTE; } + YY_BREAK +case 101: +YY_RULE_SETUP +#line 277 "program_lexer.l" +{ return PARAMS; } + YY_BREAK +case 102: +YY_RULE_SETUP +#line 278 "program_lexer.l" +{ return PLANE; } + YY_BREAK +case 103: +YY_RULE_SETUP +#line 279 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, POINT_TOK); } + YY_BREAK +case 104: +YY_RULE_SETUP +#line 280 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, POINTSIZE); } + YY_BREAK +case 105: +YY_RULE_SETUP +#line 281 "program_lexer.l" +{ return POSITION; } + YY_BREAK +case 106: +YY_RULE_SETUP +#line 282 "program_lexer.l" +{ return PRIMARY; } + YY_BREAK +case 107: +YY_RULE_SETUP +#line 283 "program_lexer.l" +{ return PROJECTION; } + YY_BREAK +case 108: +YY_RULE_SETUP +#line 284 "program_lexer.l" +{ return_token_or_DOT(require_ARB_fp, RANGE); } + YY_BREAK +case 109: +YY_RULE_SETUP +#line 285 "program_lexer.l" +{ return ROW; } + YY_BREAK +case 110: +YY_RULE_SETUP +#line 286 "program_lexer.l" +{ return SCENECOLOR; } + YY_BREAK +case 111: +YY_RULE_SETUP +#line 287 "program_lexer.l" +{ return SECONDARY; } + YY_BREAK +case 112: +YY_RULE_SETUP +#line 288 "program_lexer.l" +{ return SHININESS; } + YY_BREAK +case 113: +YY_RULE_SETUP +#line 289 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, SIZE_TOK); } + YY_BREAK +case 114: +YY_RULE_SETUP +#line 290 "program_lexer.l" +{ return SPECULAR; } + YY_BREAK +case 115: +YY_RULE_SETUP +#line 291 "program_lexer.l" +{ return SPOT; } + YY_BREAK +case 116: +YY_RULE_SETUP +#line 292 "program_lexer.l" +{ return TEXCOORD; } + YY_BREAK +case 117: +YY_RULE_SETUP +#line 293 "program_lexer.l" +{ return_token_or_DOT(require_ARB_fp, TEXENV); } + YY_BREAK +case 118: +YY_RULE_SETUP +#line 294 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, TEXGEN); } + YY_BREAK +case 119: +YY_RULE_SETUP +#line 295 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, TEXGEN_Q); } + YY_BREAK +case 120: +YY_RULE_SETUP +#line 296 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, TEXGEN_S); } + YY_BREAK +case 121: +YY_RULE_SETUP +#line 297 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, TEXGEN_T); } + YY_BREAK +case 122: +YY_RULE_SETUP +#line 298 "program_lexer.l" +{ return TEXTURE; } + YY_BREAK +case 123: +YY_RULE_SETUP +#line 299 "program_lexer.l" +{ return TRANSPOSE; } + YY_BREAK +case 124: +YY_RULE_SETUP +#line 300 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, VTXATTRIB); } + YY_BREAK +case 125: +YY_RULE_SETUP +#line 301 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, WEIGHT); } + YY_BREAK +case 126: +YY_RULE_SETUP +#line 303 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp, TEXTURE_UNIT); } + YY_BREAK +case 127: +YY_RULE_SETUP +#line 304 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp, TEX_1D); } + YY_BREAK +case 128: +YY_RULE_SETUP +#line 305 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp, TEX_2D); } + YY_BREAK +case 129: +YY_RULE_SETUP +#line 306 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp, TEX_3D); } + YY_BREAK +case 130: +YY_RULE_SETUP +#line 307 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp, TEX_CUBE); } + YY_BREAK +case 131: +YY_RULE_SETUP +#line 308 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_rect, TEX_RECT); } + YY_BREAK +case 132: +YY_RULE_SETUP +#line 309 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow, TEX_SHADOW1D); } + YY_BREAK +case 133: +YY_RULE_SETUP +#line 310 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow, TEX_SHADOW2D); } + YY_BREAK +case 134: +YY_RULE_SETUP +#line 311 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_rect, TEX_SHADOWRECT); } + YY_BREAK +case 135: +YY_RULE_SETUP +#line 312 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_texarray, TEX_ARRAY1D); } + YY_BREAK +case 136: +YY_RULE_SETUP +#line 313 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_texarray, TEX_ARRAY2D); } + YY_BREAK +case 137: +YY_RULE_SETUP +#line 314 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_texarray, TEX_ARRAYSHADOW1D); } + YY_BREAK +case 138: +YY_RULE_SETUP +#line 315 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_texarray, TEX_ARRAYSHADOW2D); } + YY_BREAK +case 139: +YY_RULE_SETUP +#line 317 "program_lexer.l" +{ return handle_ident(yyextra, yytext, yylval); } + YY_BREAK +case 140: +YY_RULE_SETUP +#line 319 "program_lexer.l" +{ return DOT_DOT; } + YY_BREAK +case 141: +YY_RULE_SETUP +#line 321 "program_lexer.l" +{ + yylval->integer = strtol(yytext, NULL, 10); + return INTEGER; +} + YY_BREAK +case 142: +YY_RULE_SETUP +#line 325 "program_lexer.l" +{ + yylval->real = _mesa_strtof(yytext, NULL); + return REAL; +} + YY_BREAK +case 143: +/* rule 143 can match eol */ +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ +yyg->yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 329 "program_lexer.l" +{ + yylval->real = _mesa_strtof(yytext, NULL); + return REAL; +} + YY_BREAK +case 144: +YY_RULE_SETUP +#line 333 "program_lexer.l" +{ + yylval->real = _mesa_strtof(yytext, NULL); + return REAL; +} + YY_BREAK +case 145: +YY_RULE_SETUP +#line 337 "program_lexer.l" +{ + yylval->real = _mesa_strtof(yytext, NULL); + return REAL; +} + YY_BREAK +case 146: +YY_RULE_SETUP +#line 342 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_NOOP; + yylval->swiz_mask.mask = WRITEMASK_XYZW; + return MASK4; +} + YY_BREAK +case 147: +YY_RULE_SETUP +#line 348 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XY + | mask_from_char(yytext[3]); + return MASK3; +} + YY_BREAK +case 148: +YY_RULE_SETUP +#line 354 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XZW; + return MASK3; +} + YY_BREAK +case 149: +YY_RULE_SETUP +#line 359 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_YZW; + return MASK3; +} + YY_BREAK +case 150: +YY_RULE_SETUP +#line 365 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_X + | mask_from_char(yytext[2]); + return MASK2; +} + YY_BREAK +case 151: +YY_RULE_SETUP +#line 371 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_Y + | mask_from_char(yytext[2]); + return MASK2; +} + YY_BREAK +case 152: +YY_RULE_SETUP +#line 377 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_ZW; + return MASK2; +} + YY_BREAK +case 153: +YY_RULE_SETUP +#line 383 "program_lexer.l" +{ + const unsigned s = swiz_from_char(yytext[1]); + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(s, s, s, s); + yylval->swiz_mask.mask = mask_from_char(yytext[1]); + return MASK1; +} + YY_BREAK +case 154: +YY_RULE_SETUP +#line 390 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(swiz_from_char(yytext[1]), + swiz_from_char(yytext[2]), + swiz_from_char(yytext[3]), + swiz_from_char(yytext[4])); + yylval->swiz_mask.mask = 0; + return SWIZZLE; +} + YY_BREAK +case 155: +YY_RULE_SETUP +#line 399 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_NOOP; + yylval->swiz_mask.mask = WRITEMASK_XYZW; + return_token_or_DOT(require_ARB_fp, MASK4); +} + YY_BREAK +case 156: +YY_RULE_SETUP +#line 405 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XY + | mask_from_char(yytext[3]); + return_token_or_DOT(require_ARB_fp, MASK3); +} + YY_BREAK +case 157: +YY_RULE_SETUP +#line 411 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XZW; + return_token_or_DOT(require_ARB_fp, MASK3); +} + YY_BREAK +case 158: +YY_RULE_SETUP +#line 416 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_YZW; + return_token_or_DOT(require_ARB_fp, MASK3); +} + YY_BREAK +case 159: +YY_RULE_SETUP +#line 422 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_X + | mask_from_char(yytext[2]); + return_token_or_DOT(require_ARB_fp, MASK2); +} + YY_BREAK +case 160: +YY_RULE_SETUP +#line 428 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_Y + | mask_from_char(yytext[2]); + return_token_or_DOT(require_ARB_fp, MASK2); +} + YY_BREAK +case 161: +YY_RULE_SETUP +#line 434 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_ZW; + return_token_or_DOT(require_ARB_fp, MASK2); +} + YY_BREAK +case 162: +YY_RULE_SETUP +#line 440 "program_lexer.l" +{ + const unsigned s = swiz_from_char(yytext[1]); + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(s, s, s, s); + yylval->swiz_mask.mask = mask_from_char(yytext[1]); + return_token_or_DOT(require_ARB_fp, MASK1); +} + YY_BREAK +case 163: +YY_RULE_SETUP +#line 448 "program_lexer.l" +{ + if (require_ARB_vp) { + return TEXGEN_R; + } else { + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, + SWIZZLE_X, SWIZZLE_X); + yylval->swiz_mask.mask = WRITEMASK_X; + return MASK1; + } +} + YY_BREAK +case 164: +YY_RULE_SETUP +#line 459 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(swiz_from_char(yytext[1]), + swiz_from_char(yytext[2]), + swiz_from_char(yytext[3]), + swiz_from_char(yytext[4])); + yylval->swiz_mask.mask = 0; + return_token_or_DOT(require_ARB_fp, SWIZZLE); +} + YY_BREAK +case 165: +YY_RULE_SETUP +#line 468 "program_lexer.l" +{ return DOT; } + YY_BREAK +case 166: +/* rule 166 can match eol */ +YY_RULE_SETUP +#line 470 "program_lexer.l" +{ + yylloc->first_line++; + yylloc->first_column = 1; + yylloc->last_line++; + yylloc->last_column = 1; + yylloc->position++; +} + YY_BREAK +case 167: +YY_RULE_SETUP +#line 477 "program_lexer.l" +/* eat whitespace */ ; + YY_BREAK +case 168: +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ +yyg->yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 478 "program_lexer.l" +/* eat comments */ ; + YY_BREAK +case 169: +YY_RULE_SETUP +#line 479 "program_lexer.l" +{ return yytext[0]; } + YY_BREAK +case 170: +YY_RULE_SETUP +#line 480 "program_lexer.l" +ECHO; + YY_BREAK +#line 2463 "lex.yy.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 850 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + register char *yy_cp = yyg->yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 850 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 849); + + return yy_is_jam ? 0 : yy_current_state; +} + + static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner) +{ + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_cp = yyg->yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yyg->yy_hold_char; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yyg->yy_n_chars + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + yyg->yytext_ptr = yy_bp; + yyg->yy_hold_char = *yy_cp; + yyg->yy_c_buf_p = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + yy_load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ,yyscanner ); + + yyfree((void *) b ,yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + int num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "yyset_lineno called with no buffer" , yyscanner); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void yyset_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "yyset_column called with no buffer" , yyscanner); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void yyset_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +YYLTYPE *yyget_lloc (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylloc; +} + +void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylloc = yylloc_param; +} + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int yylex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ + +int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) + +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 480 "program_lexer.l" + + + +void +_mesa_program_lexer_ctor(void **scanner, struct asm_parser_state *state, + const char *string, size_t len) +{ + yylex_init_extra(state,scanner); + yy_scan_bytes(string,len,*scanner); +} + +void +_mesa_program_lexer_dtor(void *scanner) +{ + yylex_destroy(scanner); +} + diff --git a/src/mesa/program/nvfragparse.c b/src/mesa/program/nvfragparse.c new file mode 100644 index 0000000000..0de3c5804d --- /dev/null +++ b/src/mesa/program/nvfragparse.c @@ -0,0 +1,1588 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file nvfragparse.c + * NVIDIA fragment program parser. + * \author Brian Paul + */ + +/* + * Regarding GL_NV_fragment_program: + * + * Portions of this software may use or implement intellectual + * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims + * any and all warranties with respect to such intellectual property, + * including any use thereof or modifications thereto. + */ + +#include "main/glheader.h" +#include "main/context.h" +#include "main/imports.h" +#include "main/macros.h" +#include "program.h" +#include "prog_parameter.h" +#include "prog_print.h" +#include "prog_instruction.h" +#include "nvfragparse.h" + + +#define INPUT_1V 1 +#define INPUT_2V 2 +#define INPUT_3V 3 +#define INPUT_1S 4 +#define INPUT_2S 5 +#define INPUT_CC 6 +#define INPUT_1V_T 7 /* one source vector, plus textureId */ +#define INPUT_3V_T 8 /* one source vector, plus textureId */ +#define INPUT_NONE 9 +#define INPUT_1V_S 10 /* a string and a vector register */ +#define OUTPUT_V 20 +#define OUTPUT_S 21 +#define OUTPUT_NONE 22 + +/* IRIX defines some of these */ +#undef _R +#undef _H +#undef _X +#undef _C +#undef _S + +/* Optional suffixes */ +#define _R FLOAT32 /* float */ +#define _H FLOAT16 /* half-float */ +#define _X FIXED12 /* fixed */ +#define _C 0x08 /* set cond codes */ +#define _S 0x10 /* saturate, clamp result to [0,1] */ + +struct instruction_pattern { + const char *name; + enum prog_opcode opcode; + GLuint inputs; + GLuint outputs; + GLuint suffixes; +}; + +static const struct instruction_pattern Instructions[] = { + { "ADD", OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "COS", OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, + { "DDX", OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, + { "DDY", OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, + { "DP3", OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S }, + { "DP4", OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S }, + { "DST", OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H | _C | _S }, + { "EX2", OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, + { "FLR", OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "FRC", OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "KIL", OPCODE_KIL_NV, INPUT_CC, OUTPUT_NONE, 0 }, + { "LG2", OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, + { "LIT", OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, + { "LRP", OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "MAD", OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "MAX", OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "MIN", OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "MOV", OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "MUL", OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "PK2H", OPCODE_PK2H, INPUT_1V, OUTPUT_S, 0 }, + { "PK2US", OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0 }, + { "PK4B", OPCODE_PK4B, INPUT_1V, OUTPUT_S, 0 }, + { "PK4UB", OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0 }, + { "POW", OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H | _C | _S }, + { "RCP", OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, + { "RFL", OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H | _C | _S }, + { "RSQ", OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, + { "SEQ", OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SFL", OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SGE", OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SGT", OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SIN", OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, + { "SLE", OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SLT", OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SNE", OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "STR", OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SUB", OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "TEX", OPCODE_TEX, INPUT_1V_T, OUTPUT_V, _C | _S }, + { "TXD", OPCODE_TXD, INPUT_3V_T, OUTPUT_V, _C | _S }, + { "TXP", OPCODE_TXP_NV, INPUT_1V_T, OUTPUT_V, _C | _S }, + { "UP2H", OPCODE_UP2H, INPUT_1S, OUTPUT_V, _C | _S }, + { "UP2US", OPCODE_UP2US, INPUT_1S, OUTPUT_V, _C | _S }, + { "UP4B", OPCODE_UP4B, INPUT_1S, OUTPUT_V, _C | _S }, + { "UP4UB", OPCODE_UP4UB, INPUT_1S, OUTPUT_V, _C | _S }, + { "X2D", OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H | _C | _S }, + { "PRINT", OPCODE_PRINT, INPUT_1V_S, OUTPUT_NONE, 0 }, + { NULL, (enum prog_opcode) -1, 0, 0, 0 } +}; + + +/* + * Information needed or computed during parsing. + * Remember, we can't modify the target program object until we've + * _successfully_ parsed the program text. + */ +struct parse_state { + GLcontext *ctx; + const GLubyte *start; /* start of program string */ + const GLubyte *pos; /* current position */ + const GLubyte *curLine; + struct gl_fragment_program *program; /* current program */ + + struct gl_program_parameter_list *parameters; + + GLuint numInst; /* number of instructions parsed */ + GLuint inputsRead; /* bitmask of input registers used */ + GLuint outputsWritten; /* bitmask of 1 << FRAG_OUTPUT_* bits */ + GLuint texturesUsed[MAX_TEXTURE_IMAGE_UNITS]; +}; + + + +/* + * Called whenever we find an error during parsing. + */ +static void +record_error(struct parse_state *parseState, const char *msg, int lineNo) +{ +#ifdef DEBUG + GLint line, column; + const GLubyte *lineStr; + lineStr = _mesa_find_line_column(parseState->start, + parseState->pos, &line, &column); + _mesa_debug(parseState->ctx, + "nvfragparse.c(%d): line %d, column %d:%s (%s)\n", + lineNo, line, column, (char *) lineStr, msg); + free((void *) lineStr); +#else + (void) lineNo; +#endif + + /* Check that no error was already recorded. Only record the first one. */ + if (parseState->ctx->Program.ErrorString[0] == 0) { + _mesa_set_program_error(parseState->ctx, + parseState->pos - parseState->start, + msg); + } +} + + +#define RETURN_ERROR \ +do { \ + record_error(parseState, "Unexpected end of input.", __LINE__); \ + return GL_FALSE; \ +} while(0) + +#define RETURN_ERROR1(msg) \ +do { \ + record_error(parseState, msg, __LINE__); \ + return GL_FALSE; \ +} while(0) + +#define RETURN_ERROR2(msg1, msg2) \ +do { \ + char err[1000]; \ + sprintf(err, "%s %s", msg1, msg2); \ + record_error(parseState, err, __LINE__); \ + return GL_FALSE; \ +} while(0) + + + + +/* + * Search a list of instruction structures for a match. + */ +static struct instruction_pattern +MatchInstruction(const GLubyte *token) +{ + const struct instruction_pattern *inst; + struct instruction_pattern result; + + result.name = NULL; + result.opcode = MAX_OPCODE; /* i.e. invalid instruction */ + result.inputs = 0; + result.outputs = 0; + result.suffixes = 0; + + for (inst = Instructions; inst->name; inst++) { + if (strncmp((const char *) token, inst->name, 3) == 0) { + /* matched! */ + int i = 3; + result = *inst; + result.suffixes = 0; + /* look at suffix */ + if (token[i] == 'R') { + result.suffixes |= _R; + i++; + } + else if (token[i] == 'H') { + result.suffixes |= _H; + i++; + } + else if (token[i] == 'X') { + result.suffixes |= _X; + i++; + } + if (token[i] == 'C') { + result.suffixes |= _C; + i++; + } + if (token[i] == '_' && token[i+1] == 'S' && + token[i+2] == 'A' && token[i+3] == 'T') { + result.suffixes |= _S; + } + return result; + } + } + + return result; +} + + + + +/**********************************************************************/ + + +static GLboolean IsLetter(GLubyte b) +{ + return (b >= 'a' && b <= 'z') || + (b >= 'A' && b <= 'Z') || + (b == '_') || + (b == '$'); +} + + +static GLboolean IsDigit(GLubyte b) +{ + return b >= '0' && b <= '9'; +} + + +static GLboolean IsWhitespace(GLubyte b) +{ + return b == ' ' || b == '\t' || b == '\n' || b == '\r'; +} + + +/** + * Starting at 'str' find the next token. A token can be an integer, + * an identifier or punctuation symbol. + * \return <= 0 we found an error, else, return number of characters parsed. + */ +static GLint +GetToken(struct parse_state *parseState, GLubyte *token) +{ + const GLubyte *str = parseState->pos; + GLint i = 0, j = 0; + + token[0] = 0; + + /* skip whitespace and comments */ + while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) { + if (str[i] == '#') { + /* skip comment */ + while (str[i] && (str[i] != '\n' && str[i] != '\r')) { + i++; + } + if (str[i] == '\n' || str[i] == '\r') + parseState->curLine = str + i + 1; + } + else { + /* skip whitespace */ + if (str[i] == '\n' || str[i] == '\r') + parseState->curLine = str + i + 1; + i++; + } + } + + if (str[i] == 0) + return -i; + + /* try matching an integer */ + while (str[i] && IsDigit(str[i])) { + token[j++] = str[i++]; + } + if (j > 0 || !str[i]) { + token[j] = 0; + return i; + } + + /* try matching an identifier */ + if (IsLetter(str[i])) { + while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) { + token[j++] = str[i++]; + } + token[j] = 0; + return i; + } + + /* punctuation character */ + if (str[i]) { + token[0] = str[i++]; + token[1] = 0; + return i; + } + + /* end of input */ + token[0] = 0; + return i; +} + + +/** + * Get next token from input stream and increment stream pointer past token. + */ +static GLboolean +Parse_Token(struct parse_state *parseState, GLubyte *token) +{ + GLint i; + i = GetToken(parseState, token); + if (i <= 0) { + parseState->pos += (-i); + return GL_FALSE; + } + parseState->pos += i; + return GL_TRUE; +} + + +/** + * Get next token from input stream but don't increment stream pointer. + */ +static GLboolean +Peek_Token(struct parse_state *parseState, GLubyte *token) +{ + GLint i, len; + i = GetToken(parseState, token); + if (i <= 0) { + parseState->pos += (-i); + return GL_FALSE; + } + len = (GLint) strlen((const char *) token); + parseState->pos += (i - len); + return GL_TRUE; +} + + +/**********************************************************************/ + +static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = { + "WPOS", "COL0", "COL1", "FOGC", + "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL +}; + + + +/**********************************************************************/ + +/** + * Try to match 'pattern' as the next token after any whitespace/comments. + */ +static GLboolean +Parse_String(struct parse_state *parseState, const char *pattern) +{ + const GLubyte *m; + GLint i; + + /* skip whitespace and comments */ + while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') { + if (*parseState->pos == '#') { + while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) { + parseState->pos += 1; + } + if (*parseState->pos == '\n' || *parseState->pos == '\r') + parseState->curLine = parseState->pos + 1; + } + else { + /* skip whitespace */ + if (*parseState->pos == '\n' || *parseState->pos == '\r') + parseState->curLine = parseState->pos + 1; + parseState->pos += 1; + } + } + + /* Try to match the pattern */ + m = parseState->pos; + for (i = 0; pattern[i]; i++) { + if (*m != (GLubyte) pattern[i]) + return GL_FALSE; + m += 1; + } + parseState->pos = m; + + return GL_TRUE; /* success */ +} + + +static GLboolean +Parse_Identifier(struct parse_state *parseState, GLubyte *ident) +{ + if (!Parse_Token(parseState, ident)) + RETURN_ERROR; + if (IsLetter(ident[0])) + return GL_TRUE; + else + RETURN_ERROR1("Expected an identfier"); +} + + +/** + * Parse a floating point constant, or a defined symbol name. + * [+/-]N[.N[eN]] + * Output: number[0 .. 3] will get the value. + */ +static GLboolean +Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number) +{ + char *end = NULL; + + *number = (GLfloat) _mesa_strtof((const char *) parseState->pos, &end); + + if (end && end > (char *) parseState->pos) { + /* got a number */ + parseState->pos = (GLubyte *) end; + number[1] = *number; + number[2] = *number; + number[3] = *number; + return GL_TRUE; + } + else { + /* should be an identifier */ + GLubyte ident[100]; + const GLfloat *constant; + if (!Parse_Identifier(parseState, ident)) + RETURN_ERROR1("Expected an identifier"); + constant = _mesa_lookup_parameter_value(parseState->parameters, + -1, (const char *) ident); + /* XXX Check that it's a constant and not a parameter */ + if (!constant) { + RETURN_ERROR1("Undefined symbol"); + } + else { + COPY_4V(number, constant); + return GL_TRUE; + } + } +} + + + +/** + * Parse a vector constant, one of: + * { float } + * { float, float } + * { float, float, float } + * { float, float, float, float } + */ +static GLboolean +Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec) +{ + /* "{" was already consumed */ + + ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0); + + if (!Parse_ScalarConstant(parseState, vec+0)) /* X */ + return GL_FALSE; + + if (Parse_String(parseState, "}")) { + return GL_TRUE; + } + + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected comma in vector constant"); + + if (!Parse_ScalarConstant(parseState, vec+1)) /* Y */ + return GL_FALSE; + + if (Parse_String(parseState, "}")) { + return GL_TRUE; + } + + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected comma in vector constant"); + + if (!Parse_ScalarConstant(parseState, vec+2)) /* Z */ + return GL_FALSE; + + if (Parse_String(parseState, "}")) { + return GL_TRUE; + } + + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected comma in vector constant"); + + if (!Parse_ScalarConstant(parseState, vec+3)) /* W */ + return GL_FALSE; + + if (!Parse_String(parseState, "}")) + RETURN_ERROR1("Expected closing brace in vector constant"); + + return GL_TRUE; +} + + +/** + * Parse , or {a, b, c, d}. + * Return number of values in the vector or scalar, or zero if parse error. + */ +static GLuint +Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec) +{ + if (Parse_String(parseState, "{")) { + return Parse_VectorConstant(parseState, vec); + } + else { + GLboolean b = Parse_ScalarConstant(parseState, vec); + if (b) { + vec[1] = vec[2] = vec[3] = vec[0]; + } + return b; + } +} + + +/** + * Parse a texture image source: + * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT] + */ +static GLboolean +Parse_TextureImageId(struct parse_state *parseState, + GLubyte *texUnit, GLubyte *texTargetBit) +{ + GLubyte imageSrc[100]; + GLint unit; + + if (!Parse_Token(parseState, imageSrc)) + RETURN_ERROR; + + if (imageSrc[0] != 'T' || + imageSrc[1] != 'E' || + imageSrc[2] != 'X') { + RETURN_ERROR1("Expected TEX# source"); + } + unit = atoi((const char *) imageSrc + 3); + if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) || + (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) { + RETURN_ERROR1("Invalied TEX# source index"); + } + *texUnit = unit; + + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + + if (Parse_String(parseState, "1D")) { + *texTargetBit = TEXTURE_1D_BIT; + } + else if (Parse_String(parseState, "2D")) { + *texTargetBit = TEXTURE_2D_BIT; + } + else if (Parse_String(parseState, "3D")) { + *texTargetBit = TEXTURE_3D_BIT; + } + else if (Parse_String(parseState, "CUBE")) { + *texTargetBit = TEXTURE_CUBE_BIT; + } + else if (Parse_String(parseState, "RECT")) { + *texTargetBit = TEXTURE_RECT_BIT; + } + else { + RETURN_ERROR1("Invalid texture target token"); + } + + /* update record of referenced texture units */ + parseState->texturesUsed[*texUnit] |= *texTargetBit; + if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) { + RETURN_ERROR1("Only one texture target can be used per texture unit."); + } + + return GL_TRUE; +} + + +/** + * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix + * like .wxyz, .xxyy, etc and return the swizzle indexes. + */ +static GLboolean +Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4]) +{ + if (token[1] == 0) { + /* single letter swizzle (scalar) */ + if (token[0] == 'x') + ASSIGN_4V(swizzle, 0, 0, 0, 0); + else if (token[0] == 'y') + ASSIGN_4V(swizzle, 1, 1, 1, 1); + else if (token[0] == 'z') + ASSIGN_4V(swizzle, 2, 2, 2, 2); + else if (token[0] == 'w') + ASSIGN_4V(swizzle, 3, 3, 3, 3); + else + return GL_FALSE; + } + else { + /* 4-component swizzle (vector) */ + GLint k; + for (k = 0; k < 4 && token[k]; k++) { + if (token[k] == 'x') + swizzle[k] = 0; + else if (token[k] == 'y') + swizzle[k] = 1; + else if (token[k] == 'z') + swizzle[k] = 2; + else if (token[k] == 'w') + swizzle[k] = 3; + else + return GL_FALSE; + } + if (k != 4) + return GL_FALSE; + } + return GL_TRUE; +} + + +static GLboolean +Parse_CondCodeMask(struct parse_state *parseState, + struct prog_dst_register *dstReg) +{ + if (Parse_String(parseState, "EQ")) + dstReg->CondMask = COND_EQ; + else if (Parse_String(parseState, "GE")) + dstReg->CondMask = COND_GE; + else if (Parse_String(parseState, "GT")) + dstReg->CondMask = COND_GT; + else if (Parse_String(parseState, "LE")) + dstReg->CondMask = COND_LE; + else if (Parse_String(parseState, "LT")) + dstReg->CondMask = COND_LT; + else if (Parse_String(parseState, "NE")) + dstReg->CondMask = COND_NE; + else if (Parse_String(parseState, "TR")) + dstReg->CondMask = COND_TR; + else if (Parse_String(parseState, "FL")) + dstReg->CondMask = COND_FL; + else + RETURN_ERROR1("Invalid condition code mask"); + + /* look for optional .xyzw swizzle */ + if (Parse_String(parseState, ".")) { + GLubyte token[100]; + GLuint swz[4]; + + if (!Parse_Token(parseState, token)) /* get xyzw suffix */ + RETURN_ERROR; + + if (!Parse_SwizzleSuffix(token, swz)) + RETURN_ERROR1("Invalid swizzle suffix"); + + dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]); + } + + return GL_TRUE; +} + + +/** + * Parse a temporary register: Rnn or Hnn + */ +static GLboolean +Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum) +{ + GLubyte token[100]; + + /* Should be 'R##' or 'H##' */ + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + if (token[0] != 'R' && token[0] != 'H') + RETURN_ERROR1("Expected R## or H##"); + + if (IsDigit(token[1])) { + GLint reg = atoi((const char *) (token + 1)); + if (token[0] == 'H') + reg += 32; + if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS) + RETURN_ERROR1("Invalid temporary register name"); + *tempRegNum = reg; + } + else { + RETURN_ERROR1("Invalid temporary register name"); + } + + return GL_TRUE; +} + + +/** + * Parse a write-only dummy register: RC or HC. + */ +static GLboolean +Parse_DummyReg(struct parse_state *parseState, GLint *regNum) +{ + if (Parse_String(parseState, "RC")) { + *regNum = 0; + } + else if (Parse_String(parseState, "HC")) { + *regNum = 1; + } + else { + RETURN_ERROR1("Invalid write-only register name"); + } + + return GL_TRUE; +} + + +/** + * Parse a program local parameter register "p[##]" + */ +static GLboolean +Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum) +{ + GLubyte token[100]; + + if (!Parse_String(parseState, "p[")) + RETURN_ERROR1("Expected p["); + + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (IsDigit(token[0])) { + /* a numbered program parameter register */ + GLint reg = atoi((const char *) token); + if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS) + RETURN_ERROR1("Invalid constant program number"); + *regNum = reg; + } + else { + RETURN_ERROR; + } + + if (!Parse_String(parseState, "]")) + RETURN_ERROR1("Expected ]"); + + return GL_TRUE; +} + + +/** + * Parse f[name] - fragment input register + */ +static GLboolean +Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum) +{ + GLubyte token[100]; + GLint j; + + /* Match 'f[' */ + if (!Parse_String(parseState, "f[")) + RETURN_ERROR1("Expected f["); + + /* get and look for match */ + if (!Parse_Token(parseState, token)) { + RETURN_ERROR; + } + for (j = 0; InputRegisters[j]; j++) { + if (strcmp((const char *) token, InputRegisters[j]) == 0) { + *tempRegNum = j; + parseState->inputsRead |= (1 << j); + break; + } + } + if (!InputRegisters[j]) { + /* unknown input register label */ + RETURN_ERROR2("Invalid register name", token); + } + + /* Match '[' */ + if (!Parse_String(parseState, "]")) + RETURN_ERROR1("Expected ]"); + + return GL_TRUE; +} + + +static GLboolean +Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum) +{ + GLubyte token[100]; + + /* Match "o[" */ + if (!Parse_String(parseState, "o[")) + RETURN_ERROR1("Expected o["); + + /* Get output reg name */ + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + /* try to match an output register name */ + if (strcmp((char *) token, "COLR") == 0 || + strcmp((char *) token, "COLH") == 0) { + /* note that we don't distinguish between COLR and COLH */ + *outputRegNum = FRAG_RESULT_COLOR; + parseState->outputsWritten |= (1 << FRAG_RESULT_COLOR); + } + else if (strcmp((char *) token, "DEPR") == 0) { + *outputRegNum = FRAG_RESULT_DEPTH; + parseState->outputsWritten |= (1 << FRAG_RESULT_DEPTH); + } + else { + RETURN_ERROR1("Invalid output register name"); + } + + /* Match ']' */ + if (!Parse_String(parseState, "]")) + RETURN_ERROR1("Expected ]"); + + return GL_TRUE; +} + + +static GLboolean +Parse_MaskedDstReg(struct parse_state *parseState, + struct prog_dst_register *dstReg) +{ + GLubyte token[100]; + GLint idx; + + /* Dst reg can be R, H, o[n], RC or HC */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + if (strcmp((const char *) token, "RC") == 0 || + strcmp((const char *) token, "HC") == 0) { + /* a write-only register */ + dstReg->File = PROGRAM_WRITE_ONLY; + if (!Parse_DummyReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else if (token[0] == 'R' || token[0] == 'H') { + /* a temporary register */ + dstReg->File = PROGRAM_TEMPORARY; + if (!Parse_TempReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else if (token[0] == 'o') { + /* an output register */ + dstReg->File = PROGRAM_OUTPUT; + if (!Parse_OutputReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else { + RETURN_ERROR1("Invalid destination register name"); + } + + /* Parse optional write mask */ + if (Parse_String(parseState, ".")) { + /* got a mask */ + GLint k = 0; + + if (!Parse_Token(parseState, token)) /* get xyzw writemask */ + RETURN_ERROR; + + dstReg->WriteMask = 0; + + if (token[k] == 'x') { + dstReg->WriteMask |= WRITEMASK_X; + k++; + } + if (token[k] == 'y') { + dstReg->WriteMask |= WRITEMASK_Y; + k++; + } + if (token[k] == 'z') { + dstReg->WriteMask |= WRITEMASK_Z; + k++; + } + if (token[k] == 'w') { + dstReg->WriteMask |= WRITEMASK_W; + k++; + } + if (k == 0) { + RETURN_ERROR1("Invalid writemask character"); + } + + } + else { + dstReg->WriteMask = WRITEMASK_XYZW; + } + + /* optional condition code mask */ + if (Parse_String(parseState, "(")) { + /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */ + /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */ + if (!Parse_CondCodeMask(parseState, dstReg)) + RETURN_ERROR; + + if (!Parse_String(parseState, ")")) /* consume ")" */ + RETURN_ERROR1("Expected )"); + + return GL_TRUE; + } + else { + /* no cond code mask */ + dstReg->CondMask = COND_TR; + dstReg->CondSwizzle = SWIZZLE_NOOP; + return GL_TRUE; + } +} + + +/** + * Parse a vector source (register, constant, etc): + * ::= + * | + * ::= "|" "|" + */ +static GLboolean +Parse_VectorSrc(struct parse_state *parseState, + struct prog_src_register *srcReg) +{ + GLfloat sign = 1.0F; + GLubyte token[100]; + GLint idx; + GLuint negateBase, negateAbs; + + /* + * First, take care of +/- and absolute value stuff. + */ + if (Parse_String(parseState, "-")) + sign = -1.0F; + else if (Parse_String(parseState, "+")) + sign = +1.0F; + + if (Parse_String(parseState, "|")) { + srcReg->Abs = GL_TRUE; + negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; + + if (Parse_String(parseState, "-")) + negateBase = NEGATE_XYZW; + else if (Parse_String(parseState, "+")) + negateBase = NEGATE_NONE; + else + negateBase = NEGATE_NONE; + } + else { + srcReg->Abs = GL_FALSE; + negateAbs = NEGATE_NONE; + negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; + } + + srcReg->Negate = srcReg->Abs ? negateAbs : negateBase; + + /* This should be the real src vector/register name */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar + * literal or vector literal. + */ + if (token[0] == 'R' || token[0] == 'H') { + srcReg->File = PROGRAM_TEMPORARY; + if (!Parse_TempReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else if (token[0] == 'f') { + /* XXX this might be an identifier! */ + srcReg->File = PROGRAM_INPUT; + if (!Parse_FragReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else if (token[0] == 'p') { + /* XXX this might be an identifier! */ + srcReg->File = PROGRAM_LOCAL_PARAM; + if (!Parse_ProgramParamReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else if (IsLetter(token[0])){ + GLubyte ident[100]; + GLint paramIndex; + if (!Parse_Identifier(parseState, ident)) + RETURN_ERROR; + paramIndex = _mesa_lookup_parameter_index(parseState->parameters, + -1, (const char *) ident); + if (paramIndex < 0) { + RETURN_ERROR2("Undefined constant or parameter: ", ident); + } + srcReg->File = PROGRAM_NAMED_PARAM; + srcReg->Index = paramIndex; + } + else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){ + /* literal scalar constant */ + GLfloat values[4]; + GLuint paramIndex; + if (!Parse_ScalarConstant(parseState, values)) + RETURN_ERROR; + paramIndex = _mesa_add_unnamed_constant(parseState->parameters, + values, 4, NULL); + srcReg->File = PROGRAM_NAMED_PARAM; + srcReg->Index = paramIndex; + } + else if (token[0] == '{'){ + /* literal vector constant */ + GLfloat values[4]; + GLuint paramIndex; + (void) Parse_String(parseState, "{"); + if (!Parse_VectorConstant(parseState, values)) + RETURN_ERROR; + paramIndex = _mesa_add_unnamed_constant(parseState->parameters, + values, 4, NULL); + srcReg->File = PROGRAM_NAMED_PARAM; + srcReg->Index = paramIndex; + } + else { + RETURN_ERROR2("Invalid source register name", token); + } + + /* init swizzle fields */ + srcReg->Swizzle = SWIZZLE_NOOP; + + /* Look for optional swizzle suffix */ + if (Parse_String(parseState, ".")) { + GLuint swz[4]; + + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (!Parse_SwizzleSuffix(token, swz)) + RETURN_ERROR1("Invalid swizzle suffix"); + + srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]); + } + + /* Finish absolute value */ + if (srcReg->Abs && !Parse_String(parseState, "|")) { + RETURN_ERROR1("Expected |"); + } + + return GL_TRUE; +} + + +static GLboolean +Parse_ScalarSrcReg(struct parse_state *parseState, + struct prog_src_register *srcReg) +{ + GLubyte token[100]; + GLfloat sign = 1.0F; + GLboolean needSuffix = GL_TRUE; + GLint idx; + GLuint negateBase, negateAbs; + + /* + * First, take care of +/- and absolute value stuff. + */ + if (Parse_String(parseState, "-")) + sign = -1.0F; + else if (Parse_String(parseState, "+")) + sign = +1.0F; + + if (Parse_String(parseState, "|")) { + srcReg->Abs = GL_TRUE; + negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; + + if (Parse_String(parseState, "-")) + negateBase = NEGATE_XYZW; + else if (Parse_String(parseState, "+")) + negateBase = NEGATE_NONE; + else + negateBase = NEGATE_NONE; + } + else { + srcReg->Abs = GL_FALSE; + negateAbs = NEGATE_NONE; + negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; + } + + srcReg->Negate = srcReg->Abs ? negateAbs : negateBase; + + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + /* Src reg can be R, H or a named fragment attrib */ + if (token[0] == 'R' || token[0] == 'H') { + srcReg->File = PROGRAM_TEMPORARY; + if (!Parse_TempReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else if (token[0] == 'f') { + srcReg->File = PROGRAM_INPUT; + if (!Parse_FragReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else if (token[0] == '{') { + /* vector literal */ + GLfloat values[4]; + GLuint paramIndex; + (void) Parse_String(parseState, "{"); + if (!Parse_VectorConstant(parseState, values)) + RETURN_ERROR; + paramIndex = _mesa_add_unnamed_constant(parseState->parameters, + values, 4, NULL); + srcReg->File = PROGRAM_NAMED_PARAM; + srcReg->Index = paramIndex; + } + else if (IsLetter(token[0])){ + /* named param/constant */ + GLubyte ident[100]; + GLint paramIndex; + if (!Parse_Identifier(parseState, ident)) + RETURN_ERROR; + paramIndex = _mesa_lookup_parameter_index(parseState->parameters, + -1, (const char *) ident); + if (paramIndex < 0) { + RETURN_ERROR2("Undefined constant or parameter: ", ident); + } + srcReg->File = PROGRAM_NAMED_PARAM; + srcReg->Index = paramIndex; + } + else if (IsDigit(token[0])) { + /* scalar literal */ + GLfloat values[4]; + GLuint paramIndex; + if (!Parse_ScalarConstant(parseState, values)) + RETURN_ERROR; + paramIndex = _mesa_add_unnamed_constant(parseState->parameters, + values, 4, NULL); + srcReg->Index = paramIndex; + srcReg->File = PROGRAM_NAMED_PARAM; + needSuffix = GL_FALSE; + } + else { + RETURN_ERROR2("Invalid scalar source argument", token); + } + + srcReg->Swizzle = 0; + if (needSuffix) { + /* parse .[xyzw] suffix */ + if (!Parse_String(parseState, ".")) + RETURN_ERROR1("Expected ."); + + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (token[0] == 'x' && token[1] == 0) { + srcReg->Swizzle = 0; + } + else if (token[0] == 'y' && token[1] == 0) { + srcReg->Swizzle = 1; + } + else if (token[0] == 'z' && token[1] == 0) { + srcReg->Swizzle = 2; + } + else if (token[0] == 'w' && token[1] == 0) { + srcReg->Swizzle = 3; + } + else { + RETURN_ERROR1("Invalid scalar source suffix"); + } + } + + /* Finish absolute value */ + if (srcReg->Abs && !Parse_String(parseState, "|")) { + RETURN_ERROR1("Expected |"); + } + + return GL_TRUE; +} + + +static GLboolean +Parse_PrintInstruction(struct parse_state *parseState, + struct prog_instruction *inst) +{ + const GLubyte *str; + GLubyte *msg; + GLuint len; + GLint idx; + + /* The first argument is a literal string 'just like this' */ + if (!Parse_String(parseState, "'")) + RETURN_ERROR1("Expected '"); + + str = parseState->pos; + for (len = 0; str[len] != '\''; len++) /* find closing quote */ + ; + parseState->pos += len + 1; + msg = (GLubyte*) malloc(len + 1); + + memcpy(msg, str, len); + msg[len] = 0; + inst->Data = msg; + + if (Parse_String(parseState, ",")) { + /* got an optional register to print */ + GLubyte token[100]; + GetToken(parseState, token); + if (token[0] == 'o') { + /* dst reg */ + if (!Parse_OutputReg(parseState, &idx)) + RETURN_ERROR; + inst->SrcReg[0].Index = idx; + inst->SrcReg[0].File = PROGRAM_OUTPUT; + } + else { + /* src reg */ + if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + } + } + else { + inst->SrcReg[0].File = PROGRAM_UNDEFINED; + } + + inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; + inst->SrcReg[0].Abs = GL_FALSE; + inst->SrcReg[0].Negate = NEGATE_NONE; + + return GL_TRUE; +} + + +static GLboolean +Parse_InstructionSequence(struct parse_state *parseState, + struct prog_instruction program[]) +{ + while (1) { + struct prog_instruction *inst = program + parseState->numInst; + struct instruction_pattern instMatch; + GLubyte token[100]; + + /* Initialize the instruction */ + _mesa_init_instructions(inst, 1); + + /* special instructions */ + if (Parse_String(parseState, "DEFINE")) { + GLubyte id[100]; + GLfloat value[7]; /* yes, 7 to be safe */ + if (!Parse_Identifier(parseState, id)) + RETURN_ERROR; + /* XXX make sure id is not a reserved identifer, like R9 */ + if (!Parse_String(parseState, "=")) + RETURN_ERROR1("Expected ="); + if (!Parse_VectorOrScalarConstant(parseState, value)) + RETURN_ERROR; + if (!Parse_String(parseState, ";")) + RETURN_ERROR1("Expected ;"); + if (_mesa_lookup_parameter_index(parseState->parameters, + -1, (const char *) id) >= 0) { + RETURN_ERROR2(id, "already defined"); + } + _mesa_add_named_parameter(parseState->parameters, + (const char *) id, value); + } + else if (Parse_String(parseState, "DECLARE")) { + GLubyte id[100]; + GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */ + if (!Parse_Identifier(parseState, id)) + RETURN_ERROR; + /* XXX make sure id is not a reserved identifer, like R9 */ + if (Parse_String(parseState, "=")) { + if (!Parse_VectorOrScalarConstant(parseState, value)) + RETURN_ERROR; + } + if (!Parse_String(parseState, ";")) + RETURN_ERROR1("Expected ;"); + if (_mesa_lookup_parameter_index(parseState->parameters, + -1, (const char *) id) >= 0) { + RETURN_ERROR2(id, "already declared"); + } + _mesa_add_named_parameter(parseState->parameters, + (const char *) id, value); + } + else if (Parse_String(parseState, "END")) { + inst->Opcode = OPCODE_END; + parseState->numInst++; + if (Parse_Token(parseState, token)) { + RETURN_ERROR1("Code after END opcode."); + } + break; + } + else { + /* general/arithmetic instruction */ + + /* get token */ + if (!Parse_Token(parseState, token)) { + RETURN_ERROR1("Missing END instruction."); + } + + /* try to find matching instuction */ + instMatch = MatchInstruction(token); + if (instMatch.opcode >= MAX_OPCODE) { + /* bad instruction name */ + RETURN_ERROR2("Unexpected token: ", token); + } + + inst->Opcode = instMatch.opcode; + inst->Precision = instMatch.suffixes & (_R | _H | _X); + inst->SaturateMode = (instMatch.suffixes & (_S)) + ? SATURATE_ZERO_ONE : SATURATE_OFF; + inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE; + + /* + * parse the input and output operands + */ + if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) { + if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + } + else if (instMatch.outputs == OUTPUT_NONE) { + if (instMatch.opcode == OPCODE_KIL_NV) { + /* This is a little weird, the cond code info is in + * the dest register. + */ + if (!Parse_CondCodeMask(parseState, &inst->DstReg)) + RETURN_ERROR; + } + else { + ASSERT(instMatch.opcode == OPCODE_PRINT); + } + } + + if (instMatch.inputs == INPUT_1V) { + if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + } + else if (instMatch.inputs == INPUT_2V) { + if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) + RETURN_ERROR; + } + else if (instMatch.inputs == INPUT_3V) { + if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_VectorSrc(parseState, &inst->SrcReg[2])) + RETURN_ERROR; + } + else if (instMatch.inputs == INPUT_1S) { + if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + } + else if (instMatch.inputs == INPUT_2S) { + if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1])) + RETURN_ERROR; + } + else if (instMatch.inputs == INPUT_CC) { + /* XXX to-do */ + } + else if (instMatch.inputs == INPUT_1V_T) { + GLubyte unit, idx; + if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_TextureImageId(parseState, &unit, &idx)) + RETURN_ERROR; + inst->TexSrcUnit = unit; + inst->TexSrcTarget = idx; + } + else if (instMatch.inputs == INPUT_3V_T) { + GLubyte unit, idx; + if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_VectorSrc(parseState, &inst->SrcReg[2])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_TextureImageId(parseState, &unit, &idx)) + RETURN_ERROR; + inst->TexSrcUnit = unit; + inst->TexSrcTarget = idx; + } + else if (instMatch.inputs == INPUT_1V_S) { + if (!Parse_PrintInstruction(parseState, inst)) + RETURN_ERROR; + } + + /* end of statement semicolon */ + if (!Parse_String(parseState, ";")) + RETURN_ERROR1("Expected ;"); + + parseState->numInst++; + + if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS) + RETURN_ERROR1("Program too long"); + } + } + return GL_TRUE; +} + + + +/** + * Parse/compile the 'str' returning the compiled 'program'. + * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos + * indicates the position of the error in 'str'. + */ +void +_mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget, + const GLubyte *str, GLsizei len, + struct gl_fragment_program *program) +{ + struct parse_state parseState; + struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS]; + struct prog_instruction *newInst; + GLenum target; + GLubyte *programString; + + /* Make a null-terminated copy of the program string */ + programString = (GLubyte *) MALLOC(len + 1); + if (!programString) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; + } + memcpy(programString, str, len); + programString[len] = 0; + + /* Get ready to parse */ + memset(&parseState, 0, sizeof(struct parse_state)); + parseState.ctx = ctx; + parseState.start = programString; + parseState.program = program; + parseState.numInst = 0; + parseState.curLine = programString; + parseState.parameters = _mesa_new_parameter_list(); + + /* Reset error state */ + _mesa_set_program_error(ctx, -1, NULL); + + /* check the program header */ + if (strncmp((const char *) programString, "!!FP1.0", 7) == 0) { + target = GL_FRAGMENT_PROGRAM_NV; + parseState.pos = programString + 7; + } + else if (strncmp((const char *) programString, "!!FCP1.0", 8) == 0) { + /* fragment / register combiner program - not supported */ + _mesa_set_program_error(ctx, 0, "Invalid fragment program header"); + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); + return; + } + else { + /* invalid header */ + _mesa_set_program_error(ctx, 0, "Invalid fragment program header"); + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); + return; + } + + /* make sure target and header match */ + if (target != dstTarget) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glLoadProgramNV(target mismatch 0x%x != 0x%x)", + target, dstTarget); + return; + } + + if (Parse_InstructionSequence(&parseState, instBuffer)) { + GLuint u; + /* successful parse! */ + + if (parseState.outputsWritten == 0) { + /* must write at least one output! */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "Invalid fragment program - no outputs written."); + return; + } + + /* copy the compiled instructions */ + assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS); + newInst = _mesa_alloc_instructions(parseState.numInst); + if (!newInst) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; /* out of memory */ + } + _mesa_copy_instructions(newInst, instBuffer, parseState.numInst); + + /* install the program */ + program->Base.Target = target; + if (program->Base.String) { + FREE(program->Base.String); + } + program->Base.String = programString; + program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB; + if (program->Base.Instructions) { + free(program->Base.Instructions); + } + program->Base.Instructions = newInst; + program->Base.NumInstructions = parseState.numInst; + program->Base.InputsRead = parseState.inputsRead; + program->Base.OutputsWritten = parseState.outputsWritten; + for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++) + program->Base.TexturesUsed[u] = parseState.texturesUsed[u]; + + /* save program parameters */ + program->Base.Parameters = parseState.parameters; + + /* allocate registers for declared program parameters */ +#if 00 + _mesa_assign_program_registers(&(program->SymbolTable)); +#endif + +#ifdef DEBUG_foo + printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id); + _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0); + printf("----------------------------------\n"); +#endif + } + else { + /* Error! */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV"); + /* NOTE: _mesa_set_program_error would have been called already */ + } +} + + +const char * +_mesa_nv_fragment_input_register_name(GLuint i) +{ + ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS); + return InputRegisters[i]; +} + diff --git a/src/mesa/program/nvfragparse.h b/src/mesa/program/nvfragparse.h new file mode 100644 index 0000000000..544ab80c56 --- /dev/null +++ b/src/mesa/program/nvfragparse.h @@ -0,0 +1,43 @@ + +/* + * Mesa 3-D graphics library + * Version: 5.1 + * + * Copyright (C) 1999-2002 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Brian Paul + */ + + +#ifndef NVFRAGPARSE_H +#define NVFRAGPARSE_H + + +extern void +_mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum target, + const GLubyte *str, GLsizei len, + struct gl_fragment_program *program); + + +extern const char * +_mesa_nv_fragment_input_register_name(GLuint i); + +#endif diff --git a/src/mesa/program/nvvertparse.c b/src/mesa/program/nvvertparse.c new file mode 100644 index 0000000000..e2afcfd4ce --- /dev/null +++ b/src/mesa/program/nvvertparse.c @@ -0,0 +1,1454 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file nvvertparse.c + * NVIDIA vertex program parser. + * \author Brian Paul + */ + +/* + * Regarding GL_NV_vertex_program, GL_NV_vertex_program1_1: + * + * Portions of this software may use or implement intellectual + * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims + * any and all warranties with respect to such intellectual property, + * including any use thereof or modifications thereto. + */ + +#include "main/glheader.h" +#include "main/context.h" +#include "main/imports.h" +#include "main/nvprogram.h" +#include "nvvertparse.h" +#include "prog_instruction.h" +#include "prog_parameter.h" +#include "prog_print.h" +#include "program.h" + + +/** + * Current parsing state. This structure is passed among the parsing + * functions and keeps track of the current parser position and various + * program attributes. + */ +struct parse_state { + GLcontext *ctx; + const GLubyte *start; + const GLubyte *pos; + const GLubyte *curLine; + GLboolean isStateProgram; + GLboolean isPositionInvariant; + GLboolean isVersion1_1; + GLbitfield inputsRead; + GLbitfield outputsWritten; + GLboolean anyProgRegsWritten; + GLuint numInst; /* number of instructions parsed */ +}; + + +/* + * Called whenever we find an error during parsing. + */ +static void +record_error(struct parse_state *parseState, const char *msg, int lineNo) +{ +#ifdef DEBUG + GLint line, column; + const GLubyte *lineStr; + lineStr = _mesa_find_line_column(parseState->start, + parseState->pos, &line, &column); + _mesa_debug(parseState->ctx, + "nvfragparse.c(%d): line %d, column %d:%s (%s)\n", + lineNo, line, column, (char *) lineStr, msg); + free((void *) lineStr); +#else + (void) lineNo; +#endif + + /* Check that no error was already recorded. Only record the first one. */ + if (parseState->ctx->Program.ErrorString[0] == 0) { + _mesa_set_program_error(parseState->ctx, + parseState->pos - parseState->start, + msg); + } +} + + +#define RETURN_ERROR \ +do { \ + record_error(parseState, "Unexpected end of input.", __LINE__); \ + return GL_FALSE; \ +} while(0) + +#define RETURN_ERROR1(msg) \ +do { \ + record_error(parseState, msg, __LINE__); \ + return GL_FALSE; \ +} while(0) + +#define RETURN_ERROR2(msg1, msg2) \ +do { \ + char err[1000]; \ + sprintf(err, "%s %s", msg1, msg2); \ + record_error(parseState, err, __LINE__); \ + return GL_FALSE; \ +} while(0) + + + + + +static GLboolean IsLetter(GLubyte b) +{ + return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z'); +} + + +static GLboolean IsDigit(GLubyte b) +{ + return b >= '0' && b <= '9'; +} + + +static GLboolean IsWhitespace(GLubyte b) +{ + return b == ' ' || b == '\t' || b == '\n' || b == '\r'; +} + + +/** + * Starting at 'str' find the next token. A token can be an integer, + * an identifier or punctuation symbol. + * \return <= 0 we found an error, else, return number of characters parsed. + */ +static GLint +GetToken(struct parse_state *parseState, GLubyte *token) +{ + const GLubyte *str = parseState->pos; + GLint i = 0, j = 0; + + token[0] = 0; + + /* skip whitespace and comments */ + while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) { + if (str[i] == '#') { + /* skip comment */ + while (str[i] && (str[i] != '\n' && str[i] != '\r')) { + i++; + } + if (str[i] == '\n' || str[i] == '\r') + parseState->curLine = str + i + 1; + } + else { + /* skip whitespace */ + if (str[i] == '\n' || str[i] == '\r') + parseState->curLine = str + i + 1; + i++; + } + } + + if (str[i] == 0) + return -i; + + /* try matching an integer */ + while (str[i] && IsDigit(str[i])) { + token[j++] = str[i++]; + } + if (j > 0 || !str[i]) { + token[j] = 0; + return i; + } + + /* try matching an identifier */ + if (IsLetter(str[i])) { + while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) { + token[j++] = str[i++]; + } + token[j] = 0; + return i; + } + + /* punctuation character */ + if (str[i]) { + token[0] = str[i++]; + token[1] = 0; + return i; + } + + /* end of input */ + token[0] = 0; + return i; +} + + +/** + * Get next token from input stream and increment stream pointer past token. + */ +static GLboolean +Parse_Token(struct parse_state *parseState, GLubyte *token) +{ + GLint i; + i = GetToken(parseState, token); + if (i <= 0) { + parseState->pos += (-i); + return GL_FALSE; + } + parseState->pos += i; + return GL_TRUE; +} + + +/** + * Get next token from input stream but don't increment stream pointer. + */ +static GLboolean +Peek_Token(struct parse_state *parseState, GLubyte *token) +{ + GLint i, len; + i = GetToken(parseState, token); + if (i <= 0) { + parseState->pos += (-i); + return GL_FALSE; + } + len = (GLint) strlen((const char *) token); + parseState->pos += (i - len); + return GL_TRUE; +} + + +/** + * Try to match 'pattern' as the next token after any whitespace/comments. + * Advance the current parsing position only if we match the pattern. + * \return GL_TRUE if pattern is matched, GL_FALSE otherwise. + */ +static GLboolean +Parse_String(struct parse_state *parseState, const char *pattern) +{ + const GLubyte *m; + GLint i; + + /* skip whitespace and comments */ + while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') { + if (*parseState->pos == '#') { + while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) { + parseState->pos += 1; + } + if (*parseState->pos == '\n' || *parseState->pos == '\r') + parseState->curLine = parseState->pos + 1; + } + else { + /* skip whitespace */ + if (*parseState->pos == '\n' || *parseState->pos == '\r') + parseState->curLine = parseState->pos + 1; + parseState->pos += 1; + } + } + + /* Try to match the pattern */ + m = parseState->pos; + for (i = 0; pattern[i]; i++) { + if (*m != (GLubyte) pattern[i]) + return GL_FALSE; + m += 1; + } + parseState->pos = m; + + return GL_TRUE; /* success */ +} + + +/**********************************************************************/ + +static const char *InputRegisters[MAX_NV_VERTEX_PROGRAM_INPUTS + 1] = { + "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7", + "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL +}; + +static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = { + "HPOS", "COL0", "COL1", "FOGC", + "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", + "PSIZ", "BFC0", "BFC1", NULL +}; + + + +/** + * Parse a temporary register: Rnn + */ +static GLboolean +Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum) +{ + GLubyte token[100]; + + /* Should be 'R##' */ + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + if (token[0] != 'R') + RETURN_ERROR1("Expected R##"); + + if (IsDigit(token[1])) { + GLint reg = atoi((char *) (token + 1)); + if (reg >= MAX_NV_VERTEX_PROGRAM_TEMPS) + RETURN_ERROR1("Bad temporary register name"); + *tempRegNum = reg; + } + else { + RETURN_ERROR1("Bad temporary register name"); + } + + return GL_TRUE; +} + + +/** + * Parse address register "A0.x" + */ +static GLboolean +Parse_AddrReg(struct parse_state *parseState) +{ + /* match 'A0' */ + if (!Parse_String(parseState, "A0")) + RETURN_ERROR; + + /* match '.' */ + if (!Parse_String(parseState, ".")) + RETURN_ERROR; + + /* match 'x' */ + if (!Parse_String(parseState, "x")) + RETURN_ERROR; + + return GL_TRUE; +} + + +/** + * Parse absolute program parameter register "c[##]" + */ +static GLboolean +Parse_AbsParamReg(struct parse_state *parseState, GLint *regNum) +{ + GLubyte token[100]; + + if (!Parse_String(parseState, "c")) + RETURN_ERROR; + + if (!Parse_String(parseState, "[")) + RETURN_ERROR; + + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (IsDigit(token[0])) { + /* a numbered program parameter register */ + GLint reg = atoi((char *) token); + if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS) + RETURN_ERROR1("Bad program parameter number"); + *regNum = reg; + } + else { + RETURN_ERROR; + } + + if (!Parse_String(parseState, "]")) + RETURN_ERROR; + + return GL_TRUE; +} + + +static GLboolean +Parse_ParamReg(struct parse_state *parseState, struct prog_src_register *srcReg) +{ + GLubyte token[100]; + + if (!Parse_String(parseState, "c")) + RETURN_ERROR; + + if (!Parse_String(parseState, "[")) + RETURN_ERROR; + + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + if (IsDigit(token[0])) { + /* a numbered program parameter register */ + GLint reg; + (void) Parse_Token(parseState, token); + reg = atoi((char *) token); + if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS) + RETURN_ERROR1("Bad program parameter number"); + srcReg->File = PROGRAM_ENV_PARAM; + srcReg->Index = reg; + } + else if (strcmp((const char *) token, "A0") == 0) { + /* address register "A0.x" */ + if (!Parse_AddrReg(parseState)) + RETURN_ERROR; + + srcReg->RelAddr = GL_TRUE; + srcReg->File = PROGRAM_ENV_PARAM; + /* Look for +/-N offset */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + if (token[0] == '-' || token[0] == '+') { + const GLubyte sign = token[0]; + (void) Parse_Token(parseState, token); /* consume +/- */ + + /* an integer should be next */ + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (IsDigit(token[0])) { + const GLint k = atoi((char *) token); + if (sign == '-') { + if (k > 64) + RETURN_ERROR1("Bad address offset"); + srcReg->Index = -k; + } + else { + if (k > 63) + RETURN_ERROR1("Bad address offset"); + srcReg->Index = k; + } + } + else { + RETURN_ERROR; + } + } + else { + /* probably got a ']', catch it below */ + } + } + else { + RETURN_ERROR; + } + + /* Match closing ']' */ + if (!Parse_String(parseState, "]")) + RETURN_ERROR; + + return GL_TRUE; +} + + +/** + * Parse v[#] or v[] + */ +static GLboolean +Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum) +{ + GLubyte token[100]; + GLint j; + + /* Match 'v' */ + if (!Parse_String(parseState, "v")) + RETURN_ERROR; + + /* Match '[' */ + if (!Parse_String(parseState, "[")) + RETURN_ERROR; + + /* match number or named register */ + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (parseState->isStateProgram && token[0] != '0') + RETURN_ERROR1("Only v[0] accessible in vertex state programs"); + + if (IsDigit(token[0])) { + GLint reg = atoi((char *) token); + if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS) + RETURN_ERROR1("Bad vertex attribute register name"); + *tempRegNum = reg; + } + else { + for (j = 0; InputRegisters[j]; j++) { + if (strcmp((const char *) token, InputRegisters[j]) == 0) { + *tempRegNum = j; + break; + } + } + if (!InputRegisters[j]) { + /* unknown input register label */ + RETURN_ERROR2("Bad register name", token); + } + } + + /* Match '[' */ + if (!Parse_String(parseState, "]")) + RETURN_ERROR; + + return GL_TRUE; +} + + +static GLboolean +Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum) +{ + GLubyte token[100]; + GLint start, j; + + /* Match 'o' */ + if (!Parse_String(parseState, "o")) + RETURN_ERROR; + + /* Match '[' */ + if (!Parse_String(parseState, "[")) + RETURN_ERROR; + + /* Get output reg name */ + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (parseState->isPositionInvariant) + start = 1; /* skip HPOS register name */ + else + start = 0; + + /* try to match an output register name */ + for (j = start; OutputRegisters[j]; j++) { + if (strcmp((const char *) token, OutputRegisters[j]) == 0) { + *outputRegNum = j; + break; + } + } + if (!OutputRegisters[j]) + RETURN_ERROR1("Unrecognized output register name"); + + /* Match ']' */ + if (!Parse_String(parseState, "]")) + RETURN_ERROR1("Expected ]"); + + return GL_TRUE; +} + + +static GLboolean +Parse_MaskedDstReg(struct parse_state *parseState, struct prog_dst_register *dstReg) +{ + GLubyte token[100]; + GLint idx; + + /* Dst reg can be R or o[n] */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + if (token[0] == 'R') { + /* a temporary register */ + dstReg->File = PROGRAM_TEMPORARY; + if (!Parse_TempReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else if (!parseState->isStateProgram && token[0] == 'o') { + /* an output register */ + dstReg->File = PROGRAM_OUTPUT; + if (!Parse_OutputReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else if (parseState->isStateProgram && token[0] == 'c' && + parseState->isStateProgram) { + /* absolute program parameter register */ + /* Only valid for vertex state programs */ + dstReg->File = PROGRAM_ENV_PARAM; + if (!Parse_AbsParamReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else { + RETURN_ERROR1("Bad destination register name"); + } + + /* Parse optional write mask */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + if (token[0] == '.') { + /* got a mask */ + GLint k = 0; + + if (!Parse_String(parseState, ".")) + RETURN_ERROR; + + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + dstReg->WriteMask = 0; + + if (token[k] == 'x') { + dstReg->WriteMask |= WRITEMASK_X; + k++; + } + if (token[k] == 'y') { + dstReg->WriteMask |= WRITEMASK_Y; + k++; + } + if (token[k] == 'z') { + dstReg->WriteMask |= WRITEMASK_Z; + k++; + } + if (token[k] == 'w') { + dstReg->WriteMask |= WRITEMASK_W; + k++; + } + if (k == 0) { + RETURN_ERROR1("Bad writemask character"); + } + return GL_TRUE; + } + else { + dstReg->WriteMask = WRITEMASK_XYZW; + return GL_TRUE; + } +} + + +static GLboolean +Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg) +{ + GLubyte token[100]; + GLint idx; + + srcReg->RelAddr = GL_FALSE; + + /* check for '-' */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + if (token[0] == '-') { + (void) Parse_String(parseState, "-"); + srcReg->Negate = NEGATE_XYZW; + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + } + else { + srcReg->Negate = NEGATE_NONE; + } + + /* Src reg can be R, c[n], c[n +/- offset], or a named vertex attrib */ + if (token[0] == 'R') { + srcReg->File = PROGRAM_TEMPORARY; + if (!Parse_TempReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else if (token[0] == 'c') { + if (!Parse_ParamReg(parseState, srcReg)) + RETURN_ERROR; + } + else if (token[0] == 'v') { + srcReg->File = PROGRAM_INPUT; + if (!Parse_AttribReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else { + RETURN_ERROR2("Bad source register name", token); + } + + /* init swizzle fields */ + srcReg->Swizzle = SWIZZLE_NOOP; + + /* Look for optional swizzle suffix */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + if (token[0] == '.') { + (void) Parse_String(parseState, "."); /* consume . */ + + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (token[1] == 0) { + /* single letter swizzle */ + if (token[0] == 'x') + srcReg->Swizzle = SWIZZLE_XXXX; + else if (token[0] == 'y') + srcReg->Swizzle = SWIZZLE_YYYY; + else if (token[0] == 'z') + srcReg->Swizzle = SWIZZLE_ZZZZ; + else if (token[0] == 'w') + srcReg->Swizzle = SWIZZLE_WWWW; + else + RETURN_ERROR1("Expected x, y, z, or w"); + } + else { + /* 2, 3 or 4-component swizzle */ + GLint k; + + srcReg->Swizzle = 0; + + for (k = 0; token[k] && k < 5; k++) { + if (token[k] == 'x') + srcReg->Swizzle |= 0 << (k*3); + else if (token[k] == 'y') + srcReg->Swizzle |= 1 << (k*3); + else if (token[k] == 'z') + srcReg->Swizzle |= 2 << (k*3); + else if (token[k] == 'w') + srcReg->Swizzle |= 3 << (k*3); + else + RETURN_ERROR; + } + if (k >= 5) + RETURN_ERROR; + } + } + + return GL_TRUE; +} + + +static GLboolean +Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg) +{ + GLubyte token[100]; + GLint idx; + + srcReg->RelAddr = GL_FALSE; + + /* check for '-' */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + if (token[0] == '-') { + srcReg->Negate = NEGATE_XYZW; + (void) Parse_String(parseState, "-"); /* consume '-' */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + } + else { + srcReg->Negate = NEGATE_NONE; + } + + /* Src reg can be R, c[n], c[n +/- offset], or a named vertex attrib */ + if (token[0] == 'R') { + srcReg->File = PROGRAM_TEMPORARY; + if (!Parse_TempReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else if (token[0] == 'c') { + if (!Parse_ParamReg(parseState, srcReg)) + RETURN_ERROR; + } + else if (token[0] == 'v') { + srcReg->File = PROGRAM_INPUT; + if (!Parse_AttribReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else { + RETURN_ERROR2("Bad source register name", token); + } + + /* Look for .[xyzw] suffix */ + if (!Parse_String(parseState, ".")) + RETURN_ERROR; + + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (token[0] == 'x' && token[1] == 0) { + srcReg->Swizzle = 0; + } + else if (token[0] == 'y' && token[1] == 0) { + srcReg->Swizzle = 1; + } + else if (token[0] == 'z' && token[1] == 0) { + srcReg->Swizzle = 2; + } + else if (token[0] == 'w' && token[1] == 0) { + srcReg->Swizzle = 3; + } + else { + RETURN_ERROR1("Bad scalar source suffix"); + } + + return GL_TRUE; +} + + +static GLint +Parse_UnaryOpInstruction(struct parse_state *parseState, + struct prog_instruction *inst, + enum prog_opcode opcode) +{ + if (opcode == OPCODE_ABS && !parseState->isVersion1_1) + RETURN_ERROR1("ABS illegal for vertex program 1.0"); + + inst->Opcode = opcode; + + /* dest reg */ + if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) + RETURN_ERROR; + + /* comma */ + if (!Parse_String(parseState, ",")) + RETURN_ERROR; + + /* src arg */ + if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + + /* semicolon */ + if (!Parse_String(parseState, ";")) + RETURN_ERROR; + + return GL_TRUE; +} + + +static GLboolean +Parse_BiOpInstruction(struct parse_state *parseState, + struct prog_instruction *inst, + enum prog_opcode opcode) +{ + if (opcode == OPCODE_DPH && !parseState->isVersion1_1) + RETURN_ERROR1("DPH illegal for vertex program 1.0"); + if (opcode == OPCODE_SUB && !parseState->isVersion1_1) + RETURN_ERROR1("SUB illegal for vertex program 1.0"); + + inst->Opcode = opcode; + + /* dest reg */ + if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) + RETURN_ERROR; + + /* comma */ + if (!Parse_String(parseState, ",")) + RETURN_ERROR; + + /* first src arg */ + if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + + /* comma */ + if (!Parse_String(parseState, ",")) + RETURN_ERROR; + + /* second src arg */ + if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1])) + RETURN_ERROR; + + /* semicolon */ + if (!Parse_String(parseState, ";")) + RETURN_ERROR; + + /* make sure we don't reference more than one program parameter register */ + if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM && + inst->SrcReg[1].File == PROGRAM_ENV_PARAM && + inst->SrcReg[0].Index != inst->SrcReg[1].Index) + RETURN_ERROR1("Can't reference two program parameter registers"); + + /* make sure we don't reference more than one vertex attribute register */ + if (inst->SrcReg[0].File == PROGRAM_INPUT && + inst->SrcReg[1].File == PROGRAM_INPUT && + inst->SrcReg[0].Index != inst->SrcReg[1].Index) + RETURN_ERROR1("Can't reference two vertex attribute registers"); + + return GL_TRUE; +} + + +static GLboolean +Parse_TriOpInstruction(struct parse_state *parseState, + struct prog_instruction *inst, + enum prog_opcode opcode) +{ + inst->Opcode = opcode; + + /* dest reg */ + if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) + RETURN_ERROR; + + /* comma */ + if (!Parse_String(parseState, ",")) + RETURN_ERROR; + + /* first src arg */ + if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + + /* comma */ + if (!Parse_String(parseState, ",")) + RETURN_ERROR; + + /* second src arg */ + if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1])) + RETURN_ERROR; + + /* comma */ + if (!Parse_String(parseState, ",")) + RETURN_ERROR; + + /* third src arg */ + if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2])) + RETURN_ERROR; + + /* semicolon */ + if (!Parse_String(parseState, ";")) + RETURN_ERROR; + + /* make sure we don't reference more than one program parameter register */ + if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM && + inst->SrcReg[1].File == PROGRAM_ENV_PARAM && + inst->SrcReg[0].Index != inst->SrcReg[1].Index) || + (inst->SrcReg[0].File == PROGRAM_ENV_PARAM && + inst->SrcReg[2].File == PROGRAM_ENV_PARAM && + inst->SrcReg[0].Index != inst->SrcReg[2].Index) || + (inst->SrcReg[1].File == PROGRAM_ENV_PARAM && + inst->SrcReg[2].File == PROGRAM_ENV_PARAM && + inst->SrcReg[1].Index != inst->SrcReg[2].Index)) + RETURN_ERROR1("Can only reference one program register"); + + /* make sure we don't reference more than one vertex attribute register */ + if ((inst->SrcReg[0].File == PROGRAM_INPUT && + inst->SrcReg[1].File == PROGRAM_INPUT && + inst->SrcReg[0].Index != inst->SrcReg[1].Index) || + (inst->SrcReg[0].File == PROGRAM_INPUT && + inst->SrcReg[2].File == PROGRAM_INPUT && + inst->SrcReg[0].Index != inst->SrcReg[2].Index) || + (inst->SrcReg[1].File == PROGRAM_INPUT && + inst->SrcReg[2].File == PROGRAM_INPUT && + inst->SrcReg[1].Index != inst->SrcReg[2].Index)) + RETURN_ERROR1("Can only reference one input register"); + + return GL_TRUE; +} + + +static GLboolean +Parse_ScalarInstruction(struct parse_state *parseState, + struct prog_instruction *inst, + enum prog_opcode opcode) +{ + if (opcode == OPCODE_RCC && !parseState->isVersion1_1) + RETURN_ERROR1("RCC illegal for vertex program 1.0"); + + inst->Opcode = opcode; + + /* dest reg */ + if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) + RETURN_ERROR; + + /* comma */ + if (!Parse_String(parseState, ",")) + RETURN_ERROR; + + /* first src arg */ + if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + + /* semicolon */ + if (!Parse_String(parseState, ";")) + RETURN_ERROR; + + return GL_TRUE; +} + + +static GLboolean +Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst) +{ + inst->Opcode = OPCODE_ARL; + + /* Make ARB_vp backends happy */ + inst->DstReg.File = PROGRAM_ADDRESS; + inst->DstReg.WriteMask = WRITEMASK_X; + inst->DstReg.Index = 0; + + /* dest A0 reg */ + if (!Parse_AddrReg(parseState)) + RETURN_ERROR; + + /* comma */ + if (!Parse_String(parseState, ",")) + RETURN_ERROR; + + /* parse src reg */ + if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + + /* semicolon */ + if (!Parse_String(parseState, ";")) + RETURN_ERROR; + + return GL_TRUE; +} + + +static GLboolean +Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *inst) +{ + GLubyte token[100]; + + inst->Opcode = OPCODE_END; + + /* this should fail! */ + if (Parse_Token(parseState, token)) + RETURN_ERROR2("Unexpected token after END:", token); + else + return GL_TRUE; +} + + +/** + * The PRINT instruction is Mesa-specific and is meant as a debugging aid for + * the vertex program developer. + * The NV_vertex_program extension grammar is modified as follows: + * + * ::= + * | ... + * | + * + * ::= "PRINT" + * | "PRINT" "," + * | "PRINT" "," + */ +static GLboolean +Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *inst) +{ + const GLubyte *str; + GLubyte *msg; + GLuint len; + GLubyte token[100]; + struct prog_src_register *srcReg = &inst->SrcReg[0]; + GLint idx; + + inst->Opcode = OPCODE_PRINT; + + /* The first argument is a literal string 'just like this' */ + if (!Parse_String(parseState, "'")) + RETURN_ERROR; + + str = parseState->pos; + for (len = 0; str[len] != '\''; len++) /* find closing quote */ + ; + parseState->pos += len + 1; + msg = (GLubyte*) malloc(len + 1); + + memcpy(msg, str, len); + msg[len] = 0; + inst->Data = msg; + + /* comma */ + if (Parse_String(parseState, ",")) { + + /* The second argument is a register name */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + srcReg->RelAddr = GL_FALSE; + srcReg->Negate = NEGATE_NONE; + srcReg->Swizzle = SWIZZLE_NOOP; + + /* Register can be R, c[n], c[n +/- offset], a named vertex attrib, + * or an o[n] output register. + */ + if (token[0] == 'R') { + srcReg->File = PROGRAM_TEMPORARY; + if (!Parse_TempReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else if (token[0] == 'c') { + srcReg->File = PROGRAM_ENV_PARAM; + if (!Parse_ParamReg(parseState, srcReg)) + RETURN_ERROR; + } + else if (token[0] == 'v') { + srcReg->File = PROGRAM_INPUT; + if (!Parse_AttribReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else if (token[0] == 'o') { + srcReg->File = PROGRAM_OUTPUT; + if (!Parse_OutputReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else { + RETURN_ERROR2("Bad source register name", token); + } + } + else { + srcReg->File = PROGRAM_UNDEFINED; + } + + /* semicolon */ + if (!Parse_String(parseState, ";")) + RETURN_ERROR; + + return GL_TRUE; +} + + +static GLboolean +Parse_OptionSequence(struct parse_state *parseState, + struct prog_instruction program[]) +{ + (void) program; + while (1) { + if (!Parse_String(parseState, "OPTION")) + return GL_TRUE; /* ok, not an OPTION statement */ + if (Parse_String(parseState, "NV_position_invariant")) { + parseState->isPositionInvariant = GL_TRUE; + } + else { + RETURN_ERROR1("unexpected OPTION statement"); + } + if (!Parse_String(parseState, ";")) + return GL_FALSE; + } +} + + +static GLboolean +Parse_InstructionSequence(struct parse_state *parseState, + struct prog_instruction program[]) +{ + while (1) { + struct prog_instruction *inst = program + parseState->numInst; + + /* Initialize the instruction */ + _mesa_init_instructions(inst, 1); + + if (Parse_String(parseState, "MOV")) { + if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_MOV)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "LIT")) { + if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_LIT)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "ABS")) { + if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_ABS)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "MUL")) { + if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MUL)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "ADD")) { + if (!Parse_BiOpInstruction(parseState, inst, OPCODE_ADD)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "DP3")) { + if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP3)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "DP4")) { + if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP4)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "DST")) { + if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DST)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "MIN")) { + if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MIN)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "MAX")) { + if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MAX)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "SLT")) { + if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SLT)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "SGE")) { + if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SGE)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "DPH")) { + if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DPH)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "SUB")) { + if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SUB)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "MAD")) { + if (!Parse_TriOpInstruction(parseState, inst, OPCODE_MAD)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "RCP")) { + if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCP)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "RSQ")) { + if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RSQ)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "EXP")) { + if (!Parse_ScalarInstruction(parseState, inst, OPCODE_EXP)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "LOG")) { + if (!Parse_ScalarInstruction(parseState, inst, OPCODE_LOG)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "RCC")) { + if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCC)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "ARL")) { + if (!Parse_AddressInstruction(parseState, inst)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "PRINT")) { + if (!Parse_PrintInstruction(parseState, inst)) + RETURN_ERROR; + } + else if (Parse_String(parseState, "END")) { + if (!Parse_EndInstruction(parseState, inst)) + RETURN_ERROR; + else { + parseState->numInst++; + return GL_TRUE; /* all done */ + } + } + else { + /* bad instruction name */ + RETURN_ERROR1("Unexpected token"); + } + + /* examine input/output registers */ + if (inst->DstReg.File == PROGRAM_OUTPUT) + parseState->outputsWritten |= (1 << inst->DstReg.Index); + else if (inst->DstReg.File == PROGRAM_ENV_PARAM) + parseState->anyProgRegsWritten = GL_TRUE; + + if (inst->SrcReg[0].File == PROGRAM_INPUT) + parseState->inputsRead |= (1 << inst->SrcReg[0].Index); + if (inst->SrcReg[1].File == PROGRAM_INPUT) + parseState->inputsRead |= (1 << inst->SrcReg[1].Index); + if (inst->SrcReg[2].File == PROGRAM_INPUT) + parseState->inputsRead |= (1 << inst->SrcReg[2].Index); + + parseState->numInst++; + + if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS) + RETURN_ERROR1("Program too long"); + } + + RETURN_ERROR; +} + + +static GLboolean +Parse_Program(struct parse_state *parseState, + struct prog_instruction instBuffer[]) +{ + if (parseState->isVersion1_1) { + if (!Parse_OptionSequence(parseState, instBuffer)) { + return GL_FALSE; + } + } + return Parse_InstructionSequence(parseState, instBuffer); +} + + +/** + * Parse/compile the 'str' returning the compiled 'program'. + * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos + * indicates the position of the error in 'str'. + */ +void +_mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget, + const GLubyte *str, GLsizei len, + struct gl_vertex_program *program) +{ + struct parse_state parseState; + struct prog_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS]; + struct prog_instruction *newInst; + GLenum target; + GLubyte *programString; + + /* Make a null-terminated copy of the program string */ + programString = (GLubyte *) MALLOC(len + 1); + if (!programString) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; + } + memcpy(programString, str, len); + programString[len] = 0; + + /* Get ready to parse */ + parseState.ctx = ctx; + parseState.start = programString; + parseState.isPositionInvariant = GL_FALSE; + parseState.isVersion1_1 = GL_FALSE; + parseState.numInst = 0; + parseState.inputsRead = 0; + parseState.outputsWritten = 0; + parseState.anyProgRegsWritten = GL_FALSE; + + /* Reset error state */ + _mesa_set_program_error(ctx, -1, NULL); + + /* check the program header */ + if (strncmp((const char *) programString, "!!VP1.0", 7) == 0) { + target = GL_VERTEX_PROGRAM_NV; + parseState.pos = programString + 7; + parseState.isStateProgram = GL_FALSE; + } + else if (strncmp((const char *) programString, "!!VP1.1", 7) == 0) { + target = GL_VERTEX_PROGRAM_NV; + parseState.pos = programString + 7; + parseState.isStateProgram = GL_FALSE; + parseState.isVersion1_1 = GL_TRUE; + } + else if (strncmp((const char *) programString, "!!VSP1.0", 8) == 0) { + target = GL_VERTEX_STATE_PROGRAM_NV; + parseState.pos = programString + 8; + parseState.isStateProgram = GL_TRUE; + } + else { + /* invalid header */ + ctx->Program.ErrorPos = 0; + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); + return; + } + + /* make sure target and header match */ + if (target != dstTarget) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glLoadProgramNV(target mismatch)"); + return; + } + + + if (Parse_Program(&parseState, instBuffer)) { + gl_state_index state_tokens[STATE_LENGTH] = {0, 0, 0, 0, 0}; + int i; + + /* successful parse! */ + + if (parseState.isStateProgram) { + if (!parseState.anyProgRegsWritten) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glLoadProgramNV(c[#] not written)"); + return; + } + } + else { + if (!parseState.isPositionInvariant && + !(parseState.outputsWritten & (1 << VERT_RESULT_HPOS))) { + /* bit 1 = HPOS register */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glLoadProgramNV(HPOS not written)"); + return; + } + } + + /* copy the compiled instructions */ + assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS); + newInst = _mesa_alloc_instructions(parseState.numInst); + if (!newInst) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + free(programString); + return; /* out of memory */ + } + _mesa_copy_instructions(newInst, instBuffer, parseState.numInst); + + /* install the program */ + program->Base.Target = target; + if (program->Base.String) { + free(program->Base.String); + } + program->Base.String = programString; + program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB; + if (program->Base.Instructions) { + free(program->Base.Instructions); + } + program->Base.Instructions = newInst; + program->Base.InputsRead = parseState.inputsRead; + if (parseState.isPositionInvariant) + program->Base.InputsRead |= VERT_BIT_POS; + program->Base.NumInstructions = parseState.numInst; + program->Base.OutputsWritten = parseState.outputsWritten; + program->IsPositionInvariant = parseState.isPositionInvariant; + program->IsNVProgram = GL_TRUE; + +#ifdef DEBUG_foo + printf("--- glLoadProgramNV result ---\n"); + _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0); + printf("------------------------------\n"); +#endif + + if (program->Base.Parameters) + _mesa_free_parameter_list(program->Base.Parameters); + + program->Base.Parameters = _mesa_new_parameter_list (); + program->Base.NumParameters = 0; + + state_tokens[0] = STATE_VERTEX_PROGRAM; + state_tokens[1] = STATE_ENV; + /* Add refs to all of the potential params, in order. If we want to not + * upload everything, _mesa_layout_parameters is the answer. + */ + for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS; i++) { + GLint index; + state_tokens[2] = i; + index = _mesa_add_state_reference(program->Base.Parameters, + state_tokens); + assert(index == i); + } + program->Base.NumParameters = program->Base.Parameters->NumParameters; + + _mesa_setup_nv_temporary_count(ctx, &program->Base); + _mesa_emit_nv_temp_initialization(ctx, &program->Base); + } + else { + /* Error! */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV"); + /* NOTE: _mesa_set_program_error would have been called already */ + /* GL_NV_vertex_program isn't supposed to set the error string + * so we reset it here. + */ + _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL); + } +} + + +const char * +_mesa_nv_vertex_input_register_name(GLuint i) +{ + ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS); + return InputRegisters[i]; +} + + +const char * +_mesa_nv_vertex_output_register_name(GLuint i) +{ + ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS); + return OutputRegisters[i]; +} + diff --git a/src/mesa/program/nvvertparse.h b/src/mesa/program/nvvertparse.h new file mode 100644 index 0000000000..9919e22388 --- /dev/null +++ b/src/mesa/program/nvvertparse.h @@ -0,0 +1,45 @@ +/* + * Mesa 3-D graphics library + * Version: 5.1 + * + * Copyright (C) 1999-2003 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Brian Paul + */ + + +#ifndef NVVERTPARSE_H +#define NVVERTPARSE_H + + +extern void +_mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum target, + const GLubyte *str, GLsizei len, + struct gl_vertex_program *program); + + +extern const char * +_mesa_nv_vertex_input_register_name(GLuint i); + +extern const char * +_mesa_nv_vertex_output_register_name(GLuint i); + +#endif diff --git a/src/mesa/program/prog_cache.c b/src/mesa/program/prog_cache.c new file mode 100644 index 0000000000..8af689754b --- /dev/null +++ b/src/mesa/program/prog_cache.c @@ -0,0 +1,206 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "main/glheader.h" +#include "main/mtypes.h" +#include "main/imports.h" +#include "program/prog_cache.h" +#include "program/program.h" + + +struct cache_item +{ + GLuint hash; + void *key; + struct gl_program *program; + struct cache_item *next; +}; + +struct gl_program_cache +{ + struct cache_item **items; + struct cache_item *last; + GLuint size, n_items; +}; + + + +/** + * Compute hash index from state key. + */ +static GLuint +hash_key(const void *key, GLuint key_size) +{ + const GLuint *ikey = (const GLuint *) key; + GLuint hash = 0, i; + + assert(key_size >= 4); + + /* Make a slightly better attempt at a hash function: + */ + for (i = 0; i < key_size / sizeof(*ikey); i++) + { + hash += ikey[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + + return hash; +} + + +/** + * Rebuild/expand the hash table to accomodate more entries + */ +static void +rehash(struct gl_program_cache *cache) +{ + struct cache_item **items; + struct cache_item *c, *next; + GLuint size, i; + + cache->last = NULL; + + size = cache->size * 3; + items = (struct cache_item**) malloc(size * sizeof(*items)); + memset(items, 0, size * sizeof(*items)); + + for (i = 0; i < cache->size; i++) + for (c = cache->items[i]; c; c = next) { + next = c->next; + c->next = items[c->hash % size]; + items[c->hash % size] = c; + } + + free(cache->items); + cache->items = items; + cache->size = size; +} + + +static void +clear_cache(GLcontext *ctx, struct gl_program_cache *cache) +{ + struct cache_item *c, *next; + GLuint i; + + cache->last = NULL; + + for (i = 0; i < cache->size; i++) { + for (c = cache->items[i]; c; c = next) { + next = c->next; + free(c->key); + _mesa_reference_program(ctx, &c->program, NULL); + free(c); + } + cache->items[i] = NULL; + } + + + cache->n_items = 0; +} + + + +struct gl_program_cache * +_mesa_new_program_cache(void) +{ + struct gl_program_cache *cache = CALLOC_STRUCT(gl_program_cache); + if (cache) { + cache->size = 17; + cache->items = (struct cache_item **) + calloc(1, cache->size * sizeof(struct cache_item)); + if (!cache->items) { + free(cache); + return NULL; + } + } + return cache; +} + + +void +_mesa_delete_program_cache(GLcontext *ctx, struct gl_program_cache *cache) +{ + clear_cache(ctx, cache); + free(cache->items); + free(cache); +} + + +struct gl_program * +_mesa_search_program_cache(struct gl_program_cache *cache, + const void *key, GLuint keysize) +{ + if (cache->last && + memcmp(cache->last->key, key, keysize) == 0) { + return cache->last->program; + } + else { + const GLuint hash = hash_key(key, keysize); + struct cache_item *c; + + for (c = cache->items[hash % cache->size]; c; c = c->next) { + if (c->hash == hash && memcmp(c->key, key, keysize) == 0) { + cache->last = c; + return c->program; + } + } + + return NULL; + } +} + + +void +_mesa_program_cache_insert(GLcontext *ctx, + struct gl_program_cache *cache, + const void *key, GLuint keysize, + struct gl_program *program) +{ + const GLuint hash = hash_key(key, keysize); + struct cache_item *c = CALLOC_STRUCT(cache_item); + + c->hash = hash; + + c->key = malloc(keysize); + memcpy(c->key, key, keysize); + + c->program = program; /* no refcount change */ + + if (cache->n_items > cache->size * 1.5) { + if (cache->size < 1000) + rehash(cache); + else + clear_cache(ctx, cache); + } + + cache->n_items++; + c->next = cache->items[hash % cache->size]; + cache->items[hash % cache->size] = c; +} diff --git a/src/mesa/program/prog_cache.h b/src/mesa/program/prog_cache.h new file mode 100644 index 0000000000..4e1ccac03f --- /dev/null +++ b/src/mesa/program/prog_cache.h @@ -0,0 +1,55 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef PROG_CACHE_H +#define PROG_CACHE_H + + +/** Opaque type */ +struct gl_program_cache; + + +extern struct gl_program_cache * +_mesa_new_program_cache(void); + +extern void +_mesa_delete_program_cache(GLcontext *ctx, struct gl_program_cache *pc); + + +extern struct gl_program * +_mesa_search_program_cache(struct gl_program_cache *cache, + const void *key, GLuint keysize); + +extern void +_mesa_program_cache_insert(GLcontext *ctx, + struct gl_program_cache *cache, + const void *key, GLuint keysize, + struct gl_program *program); + + +#endif /* PROG_CACHE_H */ diff --git a/src/mesa/program/prog_execute.c b/src/mesa/program/prog_execute.c new file mode 100644 index 0000000000..f85c6513f3 --- /dev/null +++ b/src/mesa/program/prog_execute.c @@ -0,0 +1,1798 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file prog_execute.c + * Software interpreter for vertex/fragment programs. + * \author Brian Paul + */ + +/* + * NOTE: we do everything in single-precision floating point; we don't + * currently observe the single/half/fixed-precision qualifiers. + * + */ + + +#include "main/glheader.h" +#include "main/colormac.h" +#include "main/context.h" +#include "prog_execute.h" +#include "prog_instruction.h" +#include "prog_parameter.h" +#include "prog_print.h" +#include "prog_noise.h" + + +/* debug predicate */ +#define DEBUG_PROG 0 + + +/** + * Set x to positive or negative infinity. + */ +#if defined(USE_IEEE) || defined(_WIN32) +#define SET_POS_INFINITY(x) \ + do { \ + fi_type fi; \ + fi.i = 0x7F800000; \ + x = fi.f; \ + } while (0) +#define SET_NEG_INFINITY(x) \ + do { \ + fi_type fi; \ + fi.i = 0xFF800000; \ + x = fi.f; \ + } while (0) +#elif defined(VMS) +#define SET_POS_INFINITY(x) x = __MAXFLOAT +#define SET_NEG_INFINITY(x) x = -__MAXFLOAT +#else +#define SET_POS_INFINITY(x) x = (GLfloat) HUGE_VAL +#define SET_NEG_INFINITY(x) x = (GLfloat) -HUGE_VAL +#endif + +#define SET_FLOAT_BITS(x, bits) ((fi_type *) (void *) &(x))->i = bits + + +static const GLfloat ZeroVec[4] = { 0.0F, 0.0F, 0.0F, 0.0F }; + + + +/** + * Return a pointer to the 4-element float vector specified by the given + * source register. + */ +static INLINE const GLfloat * +get_src_register_pointer(const struct prog_src_register *source, + const struct gl_program_machine *machine) +{ + const struct gl_program *prog = machine->CurProgram; + GLint reg = source->Index; + + if (source->RelAddr) { + /* add address register value to src index/offset */ + reg += machine->AddressReg[0][0]; + if (reg < 0) { + return ZeroVec; + } + } + + switch (source->File) { + case PROGRAM_TEMPORARY: + if (reg >= MAX_PROGRAM_TEMPS) + return ZeroVec; + return machine->Temporaries[reg]; + + case PROGRAM_INPUT: + if (prog->Target == GL_VERTEX_PROGRAM_ARB) { + if (reg >= VERT_ATTRIB_MAX) + return ZeroVec; + return machine->VertAttribs[reg]; + } + else { + if (reg >= FRAG_ATTRIB_MAX) + return ZeroVec; + return machine->Attribs[reg][machine->CurElement]; + } + + case PROGRAM_OUTPUT: + if (reg >= MAX_PROGRAM_OUTPUTS) + return ZeroVec; + return machine->Outputs[reg]; + + case PROGRAM_LOCAL_PARAM: + if (reg >= MAX_PROGRAM_LOCAL_PARAMS) + return ZeroVec; + return machine->CurProgram->LocalParams[reg]; + + case PROGRAM_ENV_PARAM: + if (reg >= MAX_PROGRAM_ENV_PARAMS) + return ZeroVec; + return machine->EnvParams[reg]; + + case PROGRAM_STATE_VAR: + /* Fallthrough */ + case PROGRAM_CONSTANT: + /* Fallthrough */ + case PROGRAM_UNIFORM: + /* Fallthrough */ + case PROGRAM_NAMED_PARAM: + if (reg >= (GLint) prog->Parameters->NumParameters) + return ZeroVec; + return prog->Parameters->ParameterValues[reg]; + + default: + _mesa_problem(NULL, + "Invalid src register file %d in get_src_register_pointer()", + source->File); + return NULL; + } +} + + +/** + * Return a pointer to the 4-element float vector specified by the given + * destination register. + */ +static INLINE GLfloat * +get_dst_register_pointer(const struct prog_dst_register *dest, + struct gl_program_machine *machine) +{ + static GLfloat dummyReg[4]; + GLint reg = dest->Index; + + if (dest->RelAddr) { + /* add address register value to src index/offset */ + reg += machine->AddressReg[0][0]; + if (reg < 0) { + return dummyReg; + } + } + + switch (dest->File) { + case PROGRAM_TEMPORARY: + if (reg >= MAX_PROGRAM_TEMPS) + return dummyReg; + return machine->Temporaries[reg]; + + case PROGRAM_OUTPUT: + if (reg >= MAX_PROGRAM_OUTPUTS) + return dummyReg; + return machine->Outputs[reg]; + + case PROGRAM_WRITE_ONLY: + return dummyReg; + + default: + _mesa_problem(NULL, + "Invalid dest register file %d in get_dst_register_pointer()", + dest->File); + return NULL; + } +} + + + +/** + * Fetch a 4-element float vector from the given source register. + * Apply swizzling and negating as needed. + */ +static void +fetch_vector4(const struct prog_src_register *source, + const struct gl_program_machine *machine, GLfloat result[4]) +{ + const GLfloat *src = get_src_register_pointer(source, machine); + ASSERT(src); + + if (source->Swizzle == SWIZZLE_NOOP) { + /* no swizzling */ + COPY_4V(result, src); + } + else { + ASSERT(GET_SWZ(source->Swizzle, 0) <= 3); + ASSERT(GET_SWZ(source->Swizzle, 1) <= 3); + ASSERT(GET_SWZ(source->Swizzle, 2) <= 3); + ASSERT(GET_SWZ(source->Swizzle, 3) <= 3); + result[0] = src[GET_SWZ(source->Swizzle, 0)]; + result[1] = src[GET_SWZ(source->Swizzle, 1)]; + result[2] = src[GET_SWZ(source->Swizzle, 2)]; + result[3] = src[GET_SWZ(source->Swizzle, 3)]; + } + + if (source->Abs) { + result[0] = FABSF(result[0]); + result[1] = FABSF(result[1]); + result[2] = FABSF(result[2]); + result[3] = FABSF(result[3]); + } + if (source->Negate) { + ASSERT(source->Negate == NEGATE_XYZW); + result[0] = -result[0]; + result[1] = -result[1]; + result[2] = -result[2]; + result[3] = -result[3]; + } + +#ifdef NAN_CHECK + assert(!IS_INF_OR_NAN(result[0])); + assert(!IS_INF_OR_NAN(result[0])); + assert(!IS_INF_OR_NAN(result[0])); + assert(!IS_INF_OR_NAN(result[0])); +#endif +} + + +/** + * Fetch a 4-element uint vector from the given source register. + * Apply swizzling but not negation/abs. + */ +static void +fetch_vector4ui(const struct prog_src_register *source, + const struct gl_program_machine *machine, GLuint result[4]) +{ + const GLuint *src = (GLuint *) get_src_register_pointer(source, machine); + ASSERT(src); + + if (source->Swizzle == SWIZZLE_NOOP) { + /* no swizzling */ + COPY_4V(result, src); + } + else { + ASSERT(GET_SWZ(source->Swizzle, 0) <= 3); + ASSERT(GET_SWZ(source->Swizzle, 1) <= 3); + ASSERT(GET_SWZ(source->Swizzle, 2) <= 3); + ASSERT(GET_SWZ(source->Swizzle, 3) <= 3); + result[0] = src[GET_SWZ(source->Swizzle, 0)]; + result[1] = src[GET_SWZ(source->Swizzle, 1)]; + result[2] = src[GET_SWZ(source->Swizzle, 2)]; + result[3] = src[GET_SWZ(source->Swizzle, 3)]; + } + + /* Note: no Negate or Abs here */ +} + + + +/** + * Fetch the derivative with respect to X or Y for the given register. + * XXX this currently only works for fragment program input attribs. + */ +static void +fetch_vector4_deriv(GLcontext * ctx, + const struct prog_src_register *source, + const struct gl_program_machine *machine, + char xOrY, GLfloat result[4]) +{ + if (source->File == PROGRAM_INPUT && + source->Index < (GLint) machine->NumDeriv) { + const GLint col = machine->CurElement; + const GLfloat w = machine->Attribs[FRAG_ATTRIB_WPOS][col][3]; + const GLfloat invQ = 1.0f / w; + GLfloat deriv[4]; + + if (xOrY == 'X') { + deriv[0] = machine->DerivX[source->Index][0] * invQ; + deriv[1] = machine->DerivX[source->Index][1] * invQ; + deriv[2] = machine->DerivX[source->Index][2] * invQ; + deriv[3] = machine->DerivX[source->Index][3] * invQ; + } + else { + deriv[0] = machine->DerivY[source->Index][0] * invQ; + deriv[1] = machine->DerivY[source->Index][1] * invQ; + deriv[2] = machine->DerivY[source->Index][2] * invQ; + deriv[3] = machine->DerivY[source->Index][3] * invQ; + } + + result[0] = deriv[GET_SWZ(source->Swizzle, 0)]; + result[1] = deriv[GET_SWZ(source->Swizzle, 1)]; + result[2] = deriv[GET_SWZ(source->Swizzle, 2)]; + result[3] = deriv[GET_SWZ(source->Swizzle, 3)]; + + if (source->Abs) { + result[0] = FABSF(result[0]); + result[1] = FABSF(result[1]); + result[2] = FABSF(result[2]); + result[3] = FABSF(result[3]); + } + if (source->Negate) { + ASSERT(source->Negate == NEGATE_XYZW); + result[0] = -result[0]; + result[1] = -result[1]; + result[2] = -result[2]; + result[3] = -result[3]; + } + } + else { + ASSIGN_4V(result, 0.0, 0.0, 0.0, 0.0); + } +} + + +/** + * As above, but only return result[0] element. + */ +static void +fetch_vector1(const struct prog_src_register *source, + const struct gl_program_machine *machine, GLfloat result[4]) +{ + const GLfloat *src = get_src_register_pointer(source, machine); + ASSERT(src); + + result[0] = src[GET_SWZ(source->Swizzle, 0)]; + + if (source->Abs) { + result[0] = FABSF(result[0]); + } + if (source->Negate) { + result[0] = -result[0]; + } +} + + +static GLuint +fetch_vector1ui(const struct prog_src_register *source, + const struct gl_program_machine *machine) +{ + const GLuint *src = (GLuint *) get_src_register_pointer(source, machine); + return src[GET_SWZ(source->Swizzle, 0)]; +} + + +/** + * Fetch texel from texture. Use partial derivatives when possible. + */ +static INLINE void +fetch_texel(GLcontext *ctx, + const struct gl_program_machine *machine, + const struct prog_instruction *inst, + const GLfloat texcoord[4], GLfloat lodBias, + GLfloat color[4]) +{ + const GLuint unit = machine->Samplers[inst->TexSrcUnit]; + + /* Note: we only have the right derivatives for fragment input attribs. + */ + if (machine->NumDeriv > 0 && + inst->SrcReg[0].File == PROGRAM_INPUT && + inst->SrcReg[0].Index == FRAG_ATTRIB_TEX0 + inst->TexSrcUnit) { + /* simple texture fetch for which we should have derivatives */ + GLuint attr = inst->SrcReg[0].Index; + machine->FetchTexelDeriv(ctx, texcoord, + machine->DerivX[attr], + machine->DerivY[attr], + lodBias, unit, color); + } + else { + machine->FetchTexelLod(ctx, texcoord, lodBias, unit, color); + } +} + + +/** + * Test value against zero and return GT, LT, EQ or UN if NaN. + */ +static INLINE GLuint +generate_cc(float value) +{ + if (value != value) + return COND_UN; /* NaN */ + if (value > 0.0F) + return COND_GT; + if (value < 0.0F) + return COND_LT; + return COND_EQ; +} + + +/** + * Test if the ccMaskRule is satisfied by the given condition code. + * Used to mask destination writes according to the current condition code. + */ +static INLINE GLboolean +test_cc(GLuint condCode, GLuint ccMaskRule) +{ + switch (ccMaskRule) { + case COND_EQ: return (condCode == COND_EQ); + case COND_NE: return (condCode != COND_EQ); + case COND_LT: return (condCode == COND_LT); + case COND_GE: return (condCode == COND_GT || condCode == COND_EQ); + case COND_LE: return (condCode == COND_LT || condCode == COND_EQ); + case COND_GT: return (condCode == COND_GT); + case COND_TR: return GL_TRUE; + case COND_FL: return GL_FALSE; + default: return GL_TRUE; + } +} + + +/** + * Evaluate the 4 condition codes against a predicate and return GL_TRUE + * or GL_FALSE to indicate result. + */ +static INLINE GLboolean +eval_condition(const struct gl_program_machine *machine, + const struct prog_instruction *inst) +{ + const GLuint swizzle = inst->DstReg.CondSwizzle; + const GLuint condMask = inst->DstReg.CondMask; + if (test_cc(machine->CondCodes[GET_SWZ(swizzle, 0)], condMask) || + test_cc(machine->CondCodes[GET_SWZ(swizzle, 1)], condMask) || + test_cc(machine->CondCodes[GET_SWZ(swizzle, 2)], condMask) || + test_cc(machine->CondCodes[GET_SWZ(swizzle, 3)], condMask)) { + return GL_TRUE; + } + else { + return GL_FALSE; + } +} + + + +/** + * Store 4 floats into a register. Observe the instructions saturate and + * set-condition-code flags. + */ +static void +store_vector4(const struct prog_instruction *inst, + struct gl_program_machine *machine, const GLfloat value[4]) +{ + const struct prog_dst_register *dstReg = &(inst->DstReg); + const GLboolean clamp = inst->SaturateMode == SATURATE_ZERO_ONE; + GLuint writeMask = dstReg->WriteMask; + GLfloat clampedValue[4]; + GLfloat *dst = get_dst_register_pointer(dstReg, machine); + +#if 0 + if (value[0] > 1.0e10 || + IS_INF_OR_NAN(value[0]) || + IS_INF_OR_NAN(value[1]) || + IS_INF_OR_NAN(value[2]) || IS_INF_OR_NAN(value[3])) + printf("store %g %g %g %g\n", value[0], value[1], value[2], value[3]); +#endif + + if (clamp) { + clampedValue[0] = CLAMP(value[0], 0.0F, 1.0F); + clampedValue[1] = CLAMP(value[1], 0.0F, 1.0F); + clampedValue[2] = CLAMP(value[2], 0.0F, 1.0F); + clampedValue[3] = CLAMP(value[3], 0.0F, 1.0F); + value = clampedValue; + } + + if (dstReg->CondMask != COND_TR) { + /* condition codes may turn off some writes */ + if (writeMask & WRITEMASK_X) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 0)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_X; + } + if (writeMask & WRITEMASK_Y) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 1)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_Y; + } + if (writeMask & WRITEMASK_Z) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 2)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_Z; + } + if (writeMask & WRITEMASK_W) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 3)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_W; + } + } + +#ifdef NAN_CHECK + assert(!IS_INF_OR_NAN(value[0])); + assert(!IS_INF_OR_NAN(value[0])); + assert(!IS_INF_OR_NAN(value[0])); + assert(!IS_INF_OR_NAN(value[0])); +#endif + + if (writeMask & WRITEMASK_X) + dst[0] = value[0]; + if (writeMask & WRITEMASK_Y) + dst[1] = value[1]; + if (writeMask & WRITEMASK_Z) + dst[2] = value[2]; + if (writeMask & WRITEMASK_W) + dst[3] = value[3]; + + if (inst->CondUpdate) { + if (writeMask & WRITEMASK_X) + machine->CondCodes[0] = generate_cc(value[0]); + if (writeMask & WRITEMASK_Y) + machine->CondCodes[1] = generate_cc(value[1]); + if (writeMask & WRITEMASK_Z) + machine->CondCodes[2] = generate_cc(value[2]); + if (writeMask & WRITEMASK_W) + machine->CondCodes[3] = generate_cc(value[3]); +#if DEBUG_PROG + printf("CondCodes=(%s,%s,%s,%s) for:\n", + _mesa_condcode_string(machine->CondCodes[0]), + _mesa_condcode_string(machine->CondCodes[1]), + _mesa_condcode_string(machine->CondCodes[2]), + _mesa_condcode_string(machine->CondCodes[3])); +#endif + } +} + + +/** + * Store 4 uints into a register. Observe the set-condition-code flags. + */ +static void +store_vector4ui(const struct prog_instruction *inst, + struct gl_program_machine *machine, const GLuint value[4]) +{ + const struct prog_dst_register *dstReg = &(inst->DstReg); + GLuint writeMask = dstReg->WriteMask; + GLuint *dst = (GLuint *) get_dst_register_pointer(dstReg, machine); + + if (dstReg->CondMask != COND_TR) { + /* condition codes may turn off some writes */ + if (writeMask & WRITEMASK_X) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 0)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_X; + } + if (writeMask & WRITEMASK_Y) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 1)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_Y; + } + if (writeMask & WRITEMASK_Z) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 2)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_Z; + } + if (writeMask & WRITEMASK_W) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 3)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_W; + } + } + + if (writeMask & WRITEMASK_X) + dst[0] = value[0]; + if (writeMask & WRITEMASK_Y) + dst[1] = value[1]; + if (writeMask & WRITEMASK_Z) + dst[2] = value[2]; + if (writeMask & WRITEMASK_W) + dst[3] = value[3]; + + if (inst->CondUpdate) { + if (writeMask & WRITEMASK_X) + machine->CondCodes[0] = generate_cc((float)value[0]); + if (writeMask & WRITEMASK_Y) + machine->CondCodes[1] = generate_cc((float)value[1]); + if (writeMask & WRITEMASK_Z) + machine->CondCodes[2] = generate_cc((float)value[2]); + if (writeMask & WRITEMASK_W) + machine->CondCodes[3] = generate_cc((float)value[3]); +#if DEBUG_PROG + printf("CondCodes=(%s,%s,%s,%s) for:\n", + _mesa_condcode_string(machine->CondCodes[0]), + _mesa_condcode_string(machine->CondCodes[1]), + _mesa_condcode_string(machine->CondCodes[2]), + _mesa_condcode_string(machine->CondCodes[3])); +#endif + } +} + + + +/** + * Execute the given vertex/fragment program. + * + * \param ctx rendering context + * \param program the program to execute + * \param machine machine state (must be initialized) + * \return GL_TRUE if program completed or GL_FALSE if program executed KIL. + */ +GLboolean +_mesa_execute_program(GLcontext * ctx, + const struct gl_program *program, + struct gl_program_machine *machine) +{ + const GLuint numInst = program->NumInstructions; + const GLuint maxExec = 10000; + GLuint pc, numExec = 0; + + machine->CurProgram = program; + + if (DEBUG_PROG) { + printf("execute program %u --------------------\n", program->Id); + } + + if (program->Target == GL_VERTEX_PROGRAM_ARB) { + machine->EnvParams = ctx->VertexProgram.Parameters; + } + else { + machine->EnvParams = ctx->FragmentProgram.Parameters; + } + + for (pc = 0; pc < numInst; pc++) { + const struct prog_instruction *inst = program->Instructions + pc; + + if (DEBUG_PROG) { + _mesa_print_instruction(inst); + } + + switch (inst->Opcode) { + case OPCODE_ABS: + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = FABSF(a[0]); + result[1] = FABSF(a[1]); + result[2] = FABSF(a[2]); + result[3] = FABSF(a[3]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_ADD: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = a[0] + b[0]; + result[1] = a[1] + b[1]; + result[2] = a[2] + b[2]; + result[3] = a[3] + b[3]; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("ADD (%g %g %g %g) = (%g %g %g %g) + (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_AND: /* bitwise AND */ + { + GLuint a[4], b[4], result[4]; + fetch_vector4ui(&inst->SrcReg[0], machine, a); + fetch_vector4ui(&inst->SrcReg[1], machine, b); + result[0] = a[0] & b[0]; + result[1] = a[1] & b[1]; + result[2] = a[2] & b[2]; + result[3] = a[3] & b[3]; + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_ARL: + { + GLfloat t[4]; + fetch_vector4(&inst->SrcReg[0], machine, t); + machine->AddressReg[0][0] = IFLOOR(t[0]); + if (DEBUG_PROG) { + printf("ARL %d\n", machine->AddressReg[0][0]); + } + } + break; + case OPCODE_BGNLOOP: + /* no-op */ + ASSERT(program->Instructions[inst->BranchTarget].Opcode + == OPCODE_ENDLOOP); + break; + case OPCODE_ENDLOOP: + /* subtract 1 here since pc is incremented by for(pc) loop */ + ASSERT(program->Instructions[inst->BranchTarget].Opcode + == OPCODE_BGNLOOP); + pc = inst->BranchTarget - 1; /* go to matching BNGLOOP */ + break; + case OPCODE_BGNSUB: /* begin subroutine */ + break; + case OPCODE_ENDSUB: /* end subroutine */ + break; + case OPCODE_BRA: /* branch (conditional) */ + if (eval_condition(machine, inst)) { + /* take branch */ + /* Subtract 1 here since we'll do pc++ below */ + pc = inst->BranchTarget - 1; + } + break; + case OPCODE_BRK: /* break out of loop (conditional) */ + ASSERT(program->Instructions[inst->BranchTarget].Opcode + == OPCODE_ENDLOOP); + if (eval_condition(machine, inst)) { + /* break out of loop */ + /* pc++ at end of for-loop will put us after the ENDLOOP inst */ + pc = inst->BranchTarget; + } + break; + case OPCODE_CONT: /* continue loop (conditional) */ + ASSERT(program->Instructions[inst->BranchTarget].Opcode + == OPCODE_ENDLOOP); + if (eval_condition(machine, inst)) { + /* continue at ENDLOOP */ + /* Subtract 1 here since we'll do pc++ at end of for-loop */ + pc = inst->BranchTarget - 1; + } + break; + case OPCODE_CAL: /* Call subroutine (conditional) */ + if (eval_condition(machine, inst)) { + /* call the subroutine */ + if (machine->StackDepth >= MAX_PROGRAM_CALL_DEPTH) { + return GL_TRUE; /* Per GL_NV_vertex_program2 spec */ + } + machine->CallStack[machine->StackDepth++] = pc + 1; /* next inst */ + /* Subtract 1 here since we'll do pc++ at end of for-loop */ + pc = inst->BranchTarget - 1; + } + break; + case OPCODE_CMP: + { + GLfloat a[4], b[4], c[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + fetch_vector4(&inst->SrcReg[2], machine, c); + result[0] = a[0] < 0.0F ? b[0] : c[0]; + result[1] = a[1] < 0.0F ? b[1] : c[1]; + result[2] = a[2] < 0.0F ? b[2] : c[2]; + result[3] = a[3] < 0.0F ? b[3] : c[3]; + store_vector4(inst, machine, result); + } + break; + case OPCODE_COS: + { + GLfloat a[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + result[0] = result[1] = result[2] = result[3] + = (GLfloat) cos(a[0]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_DDX: /* Partial derivative with respect to X */ + { + GLfloat result[4]; + fetch_vector4_deriv(ctx, &inst->SrcReg[0], machine, + 'X', result); + store_vector4(inst, machine, result); + } + break; + case OPCODE_DDY: /* Partial derivative with respect to Y */ + { + GLfloat result[4]; + fetch_vector4_deriv(ctx, &inst->SrcReg[0], machine, + 'Y', result); + store_vector4(inst, machine, result); + } + break; + case OPCODE_DP2: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = result[1] = result[2] = result[3] = DOT2(a, b); + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("DP2 %g = (%g %g) . (%g %g)\n", + result[0], a[0], a[1], b[0], b[1]); + } + } + break; + case OPCODE_DP2A: + { + GLfloat a[4], b[4], c, result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + fetch_vector1(&inst->SrcReg[1], machine, &c); + result[0] = result[1] = result[2] = result[3] = DOT2(a, b) + c; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("DP2A %g = (%g %g) . (%g %g) + %g\n", + result[0], a[0], a[1], b[0], b[1], c); + } + } + break; + case OPCODE_DP3: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = result[1] = result[2] = result[3] = DOT3(a, b); + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("DP3 %g = (%g %g %g) . (%g %g %g)\n", + result[0], a[0], a[1], a[2], b[0], b[1], b[2]); + } + } + break; + case OPCODE_DP4: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = result[1] = result[2] = result[3] = DOT4(a, b); + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("DP4 %g = (%g, %g %g %g) . (%g, %g %g %g)\n", + result[0], a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_DPH: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = result[1] = result[2] = result[3] = DOT3(a, b) + b[3]; + store_vector4(inst, machine, result); + } + break; + case OPCODE_DST: /* Distance vector */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = 1.0F; + result[1] = a[1] * b[1]; + result[2] = a[2]; + result[3] = b[3]; + store_vector4(inst, machine, result); + } + break; + case OPCODE_EXP: + { + GLfloat t[4], q[4], floor_t0; + fetch_vector1(&inst->SrcReg[0], machine, t); + floor_t0 = FLOORF(t[0]); + if (floor_t0 > FLT_MAX_EXP) { + SET_POS_INFINITY(q[0]); + SET_POS_INFINITY(q[2]); + } + else if (floor_t0 < FLT_MIN_EXP) { + q[0] = 0.0F; + q[2] = 0.0F; + } + else { + q[0] = LDEXPF(1.0, (int) floor_t0); + /* Note: GL_NV_vertex_program expects + * result.z = result.x * APPX(result.y) + * We do what the ARB extension says. + */ + q[2] = (GLfloat) pow(2.0, t[0]); + } + q[1] = t[0] - floor_t0; + q[3] = 1.0F; + store_vector4( inst, machine, q ); + } + break; + case OPCODE_EX2: /* Exponential base 2 */ + { + GLfloat a[4], result[4], val; + fetch_vector1(&inst->SrcReg[0], machine, a); + val = (GLfloat) pow(2.0, a[0]); + /* + if (IS_INF_OR_NAN(val)) + val = 1.0e10; + */ + result[0] = result[1] = result[2] = result[3] = val; + store_vector4(inst, machine, result); + } + break; + case OPCODE_FLR: + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = FLOORF(a[0]); + result[1] = FLOORF(a[1]); + result[2] = FLOORF(a[2]); + result[3] = FLOORF(a[3]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_FRC: + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = a[0] - FLOORF(a[0]); + result[1] = a[1] - FLOORF(a[1]); + result[2] = a[2] - FLOORF(a[2]); + result[3] = a[3] - FLOORF(a[3]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_IF: + { + GLboolean cond; + ASSERT(program->Instructions[inst->BranchTarget].Opcode + == OPCODE_ELSE || + program->Instructions[inst->BranchTarget].Opcode + == OPCODE_ENDIF); + /* eval condition */ + if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { + GLfloat a[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + cond = (a[0] != 0.0); + } + else { + cond = eval_condition(machine, inst); + } + if (DEBUG_PROG) { + printf("IF: %d\n", cond); + } + /* do if/else */ + if (cond) { + /* do if-clause (just continue execution) */ + } + else { + /* go to the instruction after ELSE or ENDIF */ + assert(inst->BranchTarget >= 0); + pc = inst->BranchTarget; + } + } + break; + case OPCODE_ELSE: + /* goto ENDIF */ + ASSERT(program->Instructions[inst->BranchTarget].Opcode + == OPCODE_ENDIF); + assert(inst->BranchTarget >= 0); + pc = inst->BranchTarget; + break; + case OPCODE_ENDIF: + /* nothing */ + break; + case OPCODE_KIL_NV: /* NV_f_p only (conditional) */ + if (eval_condition(machine, inst)) { + return GL_FALSE; + } + break; + case OPCODE_KIL: /* ARB_f_p only */ + { + GLfloat a[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + if (DEBUG_PROG) { + printf("KIL if (%g %g %g %g) <= 0.0\n", + a[0], a[1], a[2], a[3]); + } + + if (a[0] < 0.0F || a[1] < 0.0F || a[2] < 0.0F || a[3] < 0.0F) { + return GL_FALSE; + } + } + break; + case OPCODE_LG2: /* log base 2 */ + { + GLfloat a[4], result[4], val; + fetch_vector1(&inst->SrcReg[0], machine, a); + /* The fast LOG2 macro doesn't meet the precision requirements. + */ + if (a[0] == 0.0F) { + val = -FLT_MAX; + } + else { + val = (float)(log(a[0]) * 1.442695F); + } + result[0] = result[1] = result[2] = result[3] = val; + store_vector4(inst, machine, result); + } + break; + case OPCODE_LIT: + { + const GLfloat epsilon = 1.0F / 256.0F; /* from NV VP spec */ + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + a[0] = MAX2(a[0], 0.0F); + a[1] = MAX2(a[1], 0.0F); + /* XXX ARB version clamps a[3], NV version doesn't */ + a[3] = CLAMP(a[3], -(128.0F - epsilon), (128.0F - epsilon)); + result[0] = 1.0F; + result[1] = a[0]; + /* XXX we could probably just use pow() here */ + if (a[0] > 0.0F) { + if (a[1] == 0.0 && a[3] == 0.0) + result[2] = 1.0F; + else + result[2] = (GLfloat) pow(a[1], a[3]); + } + else { + result[2] = 0.0F; + } + result[3] = 1.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("LIT (%g %g %g %g) : (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3]); + } + } + break; + case OPCODE_LOG: + { + GLfloat t[4], q[4], abs_t0; + fetch_vector1(&inst->SrcReg[0], machine, t); + abs_t0 = FABSF(t[0]); + if (abs_t0 != 0.0F) { + /* Since we really can't handle infinite values on VMS + * like other OSes we'll use __MAXFLOAT to represent + * infinity. This may need some tweaking. + */ +#ifdef VMS + if (abs_t0 == __MAXFLOAT) +#else + if (IS_INF_OR_NAN(abs_t0)) +#endif + { + SET_POS_INFINITY(q[0]); + q[1] = 1.0F; + SET_POS_INFINITY(q[2]); + } + else { + int exponent; + GLfloat mantissa = FREXPF(t[0], &exponent); + q[0] = (GLfloat) (exponent - 1); + q[1] = (GLfloat) (2.0 * mantissa); /* map [.5, 1) -> [1, 2) */ + + /* The fast LOG2 macro doesn't meet the precision + * requirements. + */ + q[2] = (float)(log(t[0]) * 1.442695F); + } + } + else { + SET_NEG_INFINITY(q[0]); + q[1] = 1.0F; + SET_NEG_INFINITY(q[2]); + } + q[3] = 1.0; + store_vector4(inst, machine, q); + } + break; + case OPCODE_LRP: + { + GLfloat a[4], b[4], c[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + fetch_vector4(&inst->SrcReg[2], machine, c); + result[0] = a[0] * b[0] + (1.0F - a[0]) * c[0]; + result[1] = a[1] * b[1] + (1.0F - a[1]) * c[1]; + result[2] = a[2] * b[2] + (1.0F - a[2]) * c[2]; + result[3] = a[3] * b[3] + (1.0F - a[3]) * c[3]; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("LRP (%g %g %g %g) = (%g %g %g %g), " + "(%g %g %g %g), (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]); + } + } + break; + case OPCODE_MAD: + { + GLfloat a[4], b[4], c[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + fetch_vector4(&inst->SrcReg[2], machine, c); + result[0] = a[0] * b[0] + c[0]; + result[1] = a[1] * b[1] + c[1]; + result[2] = a[2] * b[2] + c[2]; + result[3] = a[3] * b[3] + c[3]; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("MAD (%g %g %g %g) = (%g %g %g %g) * " + "(%g %g %g %g) + (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]); + } + } + break; + case OPCODE_MAX: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = MAX2(a[0], b[0]); + result[1] = MAX2(a[1], b[1]); + result[2] = MAX2(a[2], b[2]); + result[3] = MAX2(a[3], b[3]); + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("MAX (%g %g %g %g) = (%g %g %g %g), (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_MIN: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = MIN2(a[0], b[0]); + result[1] = MIN2(a[1], b[1]); + result[2] = MIN2(a[2], b[2]); + result[3] = MIN2(a[3], b[3]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_MOV: + { + GLfloat result[4]; + fetch_vector4(&inst->SrcReg[0], machine, result); + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("MOV (%g %g %g %g)\n", + result[0], result[1], result[2], result[3]); + } + } + break; + case OPCODE_MUL: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = a[0] * b[0]; + result[1] = a[1] * b[1]; + result[2] = a[2] * b[2]; + result[3] = a[3] * b[3]; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("MUL (%g %g %g %g) = (%g %g %g %g) * (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_NOISE1: + { + GLfloat a[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + result[0] = + result[1] = + result[2] = + result[3] = _mesa_noise1(a[0]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_NOISE2: + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = + result[1] = + result[2] = result[3] = _mesa_noise2(a[0], a[1]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_NOISE3: + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = + result[1] = + result[2] = + result[3] = _mesa_noise3(a[0], a[1], a[2]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_NOISE4: + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = + result[1] = + result[2] = + result[3] = _mesa_noise4(a[0], a[1], a[2], a[3]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_NOP: + break; + case OPCODE_NOT: /* bitwise NOT */ + { + GLuint a[4], result[4]; + fetch_vector4ui(&inst->SrcReg[0], machine, a); + result[0] = ~a[0]; + result[1] = ~a[1]; + result[2] = ~a[2]; + result[3] = ~a[3]; + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_NRM3: /* 3-component normalization */ + { + GLfloat a[4], result[4]; + GLfloat tmp; + fetch_vector4(&inst->SrcReg[0], machine, a); + tmp = a[0] * a[0] + a[1] * a[1] + a[2] * a[2]; + if (tmp != 0.0F) + tmp = INV_SQRTF(tmp); + result[0] = tmp * a[0]; + result[1] = tmp * a[1]; + result[2] = tmp * a[2]; + result[3] = 0.0; /* undefined, but prevent valgrind warnings */ + store_vector4(inst, machine, result); + } + break; + case OPCODE_NRM4: /* 4-component normalization */ + { + GLfloat a[4], result[4]; + GLfloat tmp; + fetch_vector4(&inst->SrcReg[0], machine, a); + tmp = a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3]; + if (tmp != 0.0F) + tmp = INV_SQRTF(tmp); + result[0] = tmp * a[0]; + result[1] = tmp * a[1]; + result[2] = tmp * a[2]; + result[3] = tmp * a[3]; + store_vector4(inst, machine, result); + } + break; + case OPCODE_OR: /* bitwise OR */ + { + GLuint a[4], b[4], result[4]; + fetch_vector4ui(&inst->SrcReg[0], machine, a); + fetch_vector4ui(&inst->SrcReg[1], machine, b); + result[0] = a[0] | b[0]; + result[1] = a[1] | b[1]; + result[2] = a[2] | b[2]; + result[3] = a[3] | b[3]; + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_PK2H: /* pack two 16-bit floats in one 32-bit float */ + { + GLfloat a[4]; + GLuint result[4]; + GLhalfNV hx, hy; + fetch_vector4(&inst->SrcReg[0], machine, a); + hx = _mesa_float_to_half(a[0]); + hy = _mesa_float_to_half(a[1]); + result[0] = + result[1] = + result[2] = + result[3] = hx | (hy << 16); + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_PK2US: /* pack two GLushorts into one 32-bit float */ + { + GLfloat a[4]; + GLuint result[4], usx, usy; + fetch_vector4(&inst->SrcReg[0], machine, a); + a[0] = CLAMP(a[0], 0.0F, 1.0F); + a[1] = CLAMP(a[1], 0.0F, 1.0F); + usx = IROUND(a[0] * 65535.0F); + usy = IROUND(a[1] * 65535.0F); + result[0] = + result[1] = + result[2] = + result[3] = usx | (usy << 16); + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_PK4B: /* pack four GLbytes into one 32-bit float */ + { + GLfloat a[4]; + GLuint result[4], ubx, uby, ubz, ubw; + fetch_vector4(&inst->SrcReg[0], machine, a); + a[0] = CLAMP(a[0], -128.0F / 127.0F, 1.0F); + a[1] = CLAMP(a[1], -128.0F / 127.0F, 1.0F); + a[2] = CLAMP(a[2], -128.0F / 127.0F, 1.0F); + a[3] = CLAMP(a[3], -128.0F / 127.0F, 1.0F); + ubx = IROUND(127.0F * a[0] + 128.0F); + uby = IROUND(127.0F * a[1] + 128.0F); + ubz = IROUND(127.0F * a[2] + 128.0F); + ubw = IROUND(127.0F * a[3] + 128.0F); + result[0] = + result[1] = + result[2] = + result[3] = ubx | (uby << 8) | (ubz << 16) | (ubw << 24); + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_PK4UB: /* pack four GLubytes into one 32-bit float */ + { + GLfloat a[4]; + GLuint result[4], ubx, uby, ubz, ubw; + fetch_vector4(&inst->SrcReg[0], machine, a); + a[0] = CLAMP(a[0], 0.0F, 1.0F); + a[1] = CLAMP(a[1], 0.0F, 1.0F); + a[2] = CLAMP(a[2], 0.0F, 1.0F); + a[3] = CLAMP(a[3], 0.0F, 1.0F); + ubx = IROUND(255.0F * a[0]); + uby = IROUND(255.0F * a[1]); + ubz = IROUND(255.0F * a[2]); + ubw = IROUND(255.0F * a[3]); + result[0] = + result[1] = + result[2] = + result[3] = ubx | (uby << 8) | (ubz << 16) | (ubw << 24); + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_POW: + { + GLfloat a[4], b[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + fetch_vector1(&inst->SrcReg[1], machine, b); + result[0] = result[1] = result[2] = result[3] + = (GLfloat) pow(a[0], b[0]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_RCP: + { + GLfloat a[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + if (DEBUG_PROG) { + if (a[0] == 0) + printf("RCP(0)\n"); + else if (IS_INF_OR_NAN(a[0])) + printf("RCP(inf)\n"); + } + result[0] = result[1] = result[2] = result[3] = 1.0F / a[0]; + store_vector4(inst, machine, result); + } + break; + case OPCODE_RET: /* return from subroutine (conditional) */ + if (eval_condition(machine, inst)) { + if (machine->StackDepth == 0) { + return GL_TRUE; /* Per GL_NV_vertex_program2 spec */ + } + /* subtract one because of pc++ in the for loop */ + pc = machine->CallStack[--machine->StackDepth] - 1; + } + break; + case OPCODE_RFL: /* reflection vector */ + { + GLfloat axis[4], dir[4], result[4], tmpX, tmpW; + fetch_vector4(&inst->SrcReg[0], machine, axis); + fetch_vector4(&inst->SrcReg[1], machine, dir); + tmpW = DOT3(axis, axis); + tmpX = (2.0F * DOT3(axis, dir)) / tmpW; + result[0] = tmpX * axis[0] - dir[0]; + result[1] = tmpX * axis[1] - dir[1]; + result[2] = tmpX * axis[2] - dir[2]; + /* result[3] is never written! XXX enforce in parser! */ + store_vector4(inst, machine, result); + } + break; + case OPCODE_RSQ: /* 1 / sqrt() */ + { + GLfloat a[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + a[0] = FABSF(a[0]); + result[0] = result[1] = result[2] = result[3] = INV_SQRTF(a[0]); + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("RSQ %g = 1/sqrt(|%g|)\n", result[0], a[0]); + } + } + break; + case OPCODE_SCS: /* sine and cos */ + { + GLfloat a[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + result[0] = (GLfloat) cos(a[0]); + result[1] = (GLfloat) sin(a[0]); + result[2] = 0.0; /* undefined! */ + result[3] = 0.0; /* undefined! */ + store_vector4(inst, machine, result); + } + break; + case OPCODE_SEQ: /* set on equal */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = (a[0] == b[0]) ? 1.0F : 0.0F; + result[1] = (a[1] == b[1]) ? 1.0F : 0.0F; + result[2] = (a[2] == b[2]) ? 1.0F : 0.0F; + result[3] = (a[3] == b[3]) ? 1.0F : 0.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SEQ (%g %g %g %g) = (%g %g %g %g) == (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SFL: /* set false, operands ignored */ + { + static const GLfloat result[4] = { 0.0F, 0.0F, 0.0F, 0.0F }; + store_vector4(inst, machine, result); + } + break; + case OPCODE_SGE: /* set on greater or equal */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = (a[0] >= b[0]) ? 1.0F : 0.0F; + result[1] = (a[1] >= b[1]) ? 1.0F : 0.0F; + result[2] = (a[2] >= b[2]) ? 1.0F : 0.0F; + result[3] = (a[3] >= b[3]) ? 1.0F : 0.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SGE (%g %g %g %g) = (%g %g %g %g) >= (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SGT: /* set on greater */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = (a[0] > b[0]) ? 1.0F : 0.0F; + result[1] = (a[1] > b[1]) ? 1.0F : 0.0F; + result[2] = (a[2] > b[2]) ? 1.0F : 0.0F; + result[3] = (a[3] > b[3]) ? 1.0F : 0.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SGT (%g %g %g %g) = (%g %g %g %g) > (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SIN: + { + GLfloat a[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + result[0] = result[1] = result[2] = result[3] + = (GLfloat) sin(a[0]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_SLE: /* set on less or equal */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = (a[0] <= b[0]) ? 1.0F : 0.0F; + result[1] = (a[1] <= b[1]) ? 1.0F : 0.0F; + result[2] = (a[2] <= b[2]) ? 1.0F : 0.0F; + result[3] = (a[3] <= b[3]) ? 1.0F : 0.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SLE (%g %g %g %g) = (%g %g %g %g) <= (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SLT: /* set on less */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = (a[0] < b[0]) ? 1.0F : 0.0F; + result[1] = (a[1] < b[1]) ? 1.0F : 0.0F; + result[2] = (a[2] < b[2]) ? 1.0F : 0.0F; + result[3] = (a[3] < b[3]) ? 1.0F : 0.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SLT (%g %g %g %g) = (%g %g %g %g) < (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SNE: /* set on not equal */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = (a[0] != b[0]) ? 1.0F : 0.0F; + result[1] = (a[1] != b[1]) ? 1.0F : 0.0F; + result[2] = (a[2] != b[2]) ? 1.0F : 0.0F; + result[3] = (a[3] != b[3]) ? 1.0F : 0.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SNE (%g %g %g %g) = (%g %g %g %g) != (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SSG: /* set sign (-1, 0 or +1) */ + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = (GLfloat) ((a[0] > 0.0F) - (a[0] < 0.0F)); + result[1] = (GLfloat) ((a[1] > 0.0F) - (a[1] < 0.0F)); + result[2] = (GLfloat) ((a[2] > 0.0F) - (a[2] < 0.0F)); + result[3] = (GLfloat) ((a[3] > 0.0F) - (a[3] < 0.0F)); + store_vector4(inst, machine, result); + } + break; + case OPCODE_STR: /* set true, operands ignored */ + { + static const GLfloat result[4] = { 1.0F, 1.0F, 1.0F, 1.0F }; + store_vector4(inst, machine, result); + } + break; + case OPCODE_SUB: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = a[0] - b[0]; + result[1] = a[1] - b[1]; + result[2] = a[2] - b[2]; + result[3] = a[3] - b[3]; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SUB (%g %g %g %g) = (%g %g %g %g) - (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SWZ: /* extended swizzle */ + { + const struct prog_src_register *source = &inst->SrcReg[0]; + const GLfloat *src = get_src_register_pointer(source, machine); + GLfloat result[4]; + GLuint i; + for (i = 0; i < 4; i++) { + const GLuint swz = GET_SWZ(source->Swizzle, i); + if (swz == SWIZZLE_ZERO) + result[i] = 0.0; + else if (swz == SWIZZLE_ONE) + result[i] = 1.0; + else { + ASSERT(swz >= 0); + ASSERT(swz <= 3); + result[i] = src[swz]; + } + if (source->Negate & (1 << i)) + result[i] = -result[i]; + } + store_vector4(inst, machine, result); + } + break; + case OPCODE_TEX: /* Both ARB and NV frag prog */ + /* Simple texel lookup */ + { + GLfloat texcoord[4], color[4]; + fetch_vector4(&inst->SrcReg[0], machine, texcoord); + + fetch_texel(ctx, machine, inst, texcoord, 0.0, color); + + if (DEBUG_PROG) { + printf("TEX (%g, %g, %g, %g) = texture[%d][%g, %g, %g, %g]\n", + color[0], color[1], color[2], color[3], + inst->TexSrcUnit, + texcoord[0], texcoord[1], texcoord[2], texcoord[3]); + } + store_vector4(inst, machine, color); + } + break; + case OPCODE_TXB: /* GL_ARB_fragment_program only */ + /* Texel lookup with LOD bias */ + { + GLfloat texcoord[4], color[4], lodBias; + + fetch_vector4(&inst->SrcReg[0], machine, texcoord); + + /* texcoord[3] is the bias to add to lambda */ + lodBias = texcoord[3]; + + fetch_texel(ctx, machine, inst, texcoord, lodBias, color); + + store_vector4(inst, machine, color); + } + break; + case OPCODE_TXD: /* GL_NV_fragment_program only */ + /* Texture lookup w/ partial derivatives for LOD */ + { + GLfloat texcoord[4], dtdx[4], dtdy[4], color[4]; + fetch_vector4(&inst->SrcReg[0], machine, texcoord); + fetch_vector4(&inst->SrcReg[1], machine, dtdx); + fetch_vector4(&inst->SrcReg[2], machine, dtdy); + machine->FetchTexelDeriv(ctx, texcoord, dtdx, dtdy, + 0.0, /* lodBias */ + inst->TexSrcUnit, color); + store_vector4(inst, machine, color); + } + break; + case OPCODE_TXP: /* GL_ARB_fragment_program only */ + /* Texture lookup w/ projective divide */ + { + GLfloat texcoord[4], color[4]; + + fetch_vector4(&inst->SrcReg[0], machine, texcoord); + /* Not so sure about this test - if texcoord[3] is + * zero, we'd probably be fine except for an ASSERT in + * IROUND_POS() which gets triggered by the inf values created. + */ + if (texcoord[3] != 0.0) { + texcoord[0] /= texcoord[3]; + texcoord[1] /= texcoord[3]; + texcoord[2] /= texcoord[3]; + } + + fetch_texel(ctx, machine, inst, texcoord, 0.0, color); + + store_vector4(inst, machine, color); + } + break; + case OPCODE_TXP_NV: /* GL_NV_fragment_program only */ + /* Texture lookup w/ projective divide, as above, but do not + * do the divide by w if sampling from a cube map. + */ + { + GLfloat texcoord[4], color[4]; + + fetch_vector4(&inst->SrcReg[0], machine, texcoord); + if (inst->TexSrcTarget != TEXTURE_CUBE_INDEX && + texcoord[3] != 0.0) { + texcoord[0] /= texcoord[3]; + texcoord[1] /= texcoord[3]; + texcoord[2] /= texcoord[3]; + } + + fetch_texel(ctx, machine, inst, texcoord, 0.0, color); + + store_vector4(inst, machine, color); + } + break; + case OPCODE_TRUNC: /* truncate toward zero */ + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = (GLfloat) (GLint) a[0]; + result[1] = (GLfloat) (GLint) a[1]; + result[2] = (GLfloat) (GLint) a[2]; + result[3] = (GLfloat) (GLint) a[3]; + store_vector4(inst, machine, result); + } + break; + case OPCODE_UP2H: /* unpack two 16-bit floats */ + { + const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine); + GLfloat result[4]; + GLushort hx, hy; + hx = raw & 0xffff; + hy = raw >> 16; + result[0] = result[2] = _mesa_half_to_float(hx); + result[1] = result[3] = _mesa_half_to_float(hy); + store_vector4(inst, machine, result); + } + break; + case OPCODE_UP2US: /* unpack two GLushorts */ + { + const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine); + GLfloat result[4]; + GLushort usx, usy; + usx = raw & 0xffff; + usy = raw >> 16; + result[0] = result[2] = usx * (1.0f / 65535.0f); + result[1] = result[3] = usy * (1.0f / 65535.0f); + store_vector4(inst, machine, result); + } + break; + case OPCODE_UP4B: /* unpack four GLbytes */ + { + const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine); + GLfloat result[4]; + result[0] = (((raw >> 0) & 0xff) - 128) / 127.0F; + result[1] = (((raw >> 8) & 0xff) - 128) / 127.0F; + result[2] = (((raw >> 16) & 0xff) - 128) / 127.0F; + result[3] = (((raw >> 24) & 0xff) - 128) / 127.0F; + store_vector4(inst, machine, result); + } + break; + case OPCODE_UP4UB: /* unpack four GLubytes */ + { + const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine); + GLfloat result[4]; + result[0] = ((raw >> 0) & 0xff) / 255.0F; + result[1] = ((raw >> 8) & 0xff) / 255.0F; + result[2] = ((raw >> 16) & 0xff) / 255.0F; + result[3] = ((raw >> 24) & 0xff) / 255.0F; + store_vector4(inst, machine, result); + } + break; + case OPCODE_XOR: /* bitwise XOR */ + { + GLuint a[4], b[4], result[4]; + fetch_vector4ui(&inst->SrcReg[0], machine, a); + fetch_vector4ui(&inst->SrcReg[1], machine, b); + result[0] = a[0] ^ b[0]; + result[1] = a[1] ^ b[1]; + result[2] = a[2] ^ b[2]; + result[3] = a[3] ^ b[3]; + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_XPD: /* cross product */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = a[1] * b[2] - a[2] * b[1]; + result[1] = a[2] * b[0] - a[0] * b[2]; + result[2] = a[0] * b[1] - a[1] * b[0]; + result[3] = 1.0; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("XPD (%g %g %g %g) = (%g %g %g) X (%g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], b[0], b[1], b[2]); + } + } + break; + case OPCODE_X2D: /* 2-D matrix transform */ + { + GLfloat a[4], b[4], c[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + fetch_vector4(&inst->SrcReg[2], machine, c); + result[0] = a[0] + b[0] * c[0] + b[1] * c[1]; + result[1] = a[1] + b[0] * c[2] + b[1] * c[3]; + result[2] = a[2] + b[0] * c[0] + b[1] * c[1]; + result[3] = a[3] + b[0] * c[2] + b[1] * c[3]; + store_vector4(inst, machine, result); + } + break; + case OPCODE_PRINT: + { + if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { + GLfloat a[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + printf("%s%g, %g, %g, %g\n", (const char *) inst->Data, + a[0], a[1], a[2], a[3]); + } + else { + printf("%s\n", (const char *) inst->Data); + } + } + break; + case OPCODE_END: + return GL_TRUE; + default: + _mesa_problem(ctx, "Bad opcode %d in _mesa_execute_program", + inst->Opcode); + return GL_TRUE; /* return value doesn't matter */ + } + + numExec++; + if (numExec > maxExec) { + _mesa_problem(ctx, "Infinite loop detected in fragment program"); + return GL_TRUE; + } + + } /* for pc */ + + return GL_TRUE; +} diff --git a/src/mesa/program/prog_execute.h b/src/mesa/program/prog_execute.h new file mode 100644 index 0000000000..adefc5439d --- /dev/null +++ b/src/mesa/program/prog_execute.h @@ -0,0 +1,85 @@ +/* + * Mesa 3-D graphics library + * Version: 7.0.3 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef PROG_EXECUTE_H +#define PROG_EXECUTE_H + +#include "main/config.h" + + +typedef void (*FetchTexelLodFunc)(GLcontext *ctx, const GLfloat texcoord[4], + GLfloat lambda, GLuint unit, GLfloat color[4]); + +typedef void (*FetchTexelDerivFunc)(GLcontext *ctx, const GLfloat texcoord[4], + const GLfloat texdx[4], + const GLfloat texdy[4], + GLfloat lodBias, + GLuint unit, GLfloat color[4]); + + +/** + * Virtual machine state used during execution of vertex/fragment programs. + */ +struct gl_program_machine +{ + const struct gl_program *CurProgram; + + /** Fragment Input attributes */ + GLfloat (*Attribs)[MAX_WIDTH][4]; + GLfloat (*DerivX)[4]; + GLfloat (*DerivY)[4]; + GLuint NumDeriv; /**< Max index into DerivX/Y arrays */ + GLuint CurElement; /**< Index into Attribs arrays */ + + /** Vertex Input attribs */ + GLfloat VertAttribs[VERT_ATTRIB_MAX][4]; + + GLfloat Temporaries[MAX_PROGRAM_TEMPS][4]; + GLfloat Outputs[MAX_PROGRAM_OUTPUTS][4]; + GLfloat (*EnvParams)[4]; /**< Vertex or Fragment env parameters */ + GLuint CondCodes[4]; /**< COND_* value for x/y/z/w */ + GLint AddressReg[MAX_PROGRAM_ADDRESS_REGS][4]; + + const GLubyte *Samplers; /** Array mapping sampler var to tex unit */ + + GLuint CallStack[MAX_PROGRAM_CALL_DEPTH]; /**< For CAL/RET instructions */ + GLuint StackDepth; /**< Index/ptr to top of CallStack[] */ + + /** Texture fetch functions */ + FetchTexelLodFunc FetchTexelLod; + FetchTexelDerivFunc FetchTexelDeriv; +}; + + +extern void +_mesa_get_program_register(GLcontext *ctx, gl_register_file file, + GLuint index, GLfloat val[4]); + +extern GLboolean +_mesa_execute_program(GLcontext *ctx, + const struct gl_program *program, + struct gl_program_machine *machine); + + +#endif /* PROG_EXECUTE_H */ diff --git a/src/mesa/program/prog_instruction.c b/src/mesa/program/prog_instruction.c new file mode 100644 index 0000000000..81099cb99c --- /dev/null +++ b/src/mesa/program/prog_instruction.c @@ -0,0 +1,352 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include "main/glheader.h" +#include "main/imports.h" +#include "main/mtypes.h" +#include "prog_instruction.h" + + +/** + * Initialize program instruction fields to defaults. + * \param inst first instruction to initialize + * \param count number of instructions to initialize + */ +void +_mesa_init_instructions(struct prog_instruction *inst, GLuint count) +{ + GLuint i; + + memset(inst, 0, count * sizeof(struct prog_instruction)); + + for (i = 0; i < count; i++) { + inst[i].SrcReg[0].File = PROGRAM_UNDEFINED; + inst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP; + inst[i].SrcReg[1].File = PROGRAM_UNDEFINED; + inst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; + inst[i].SrcReg[2].File = PROGRAM_UNDEFINED; + inst[i].SrcReg[2].Swizzle = SWIZZLE_NOOP; + + inst[i].DstReg.File = PROGRAM_UNDEFINED; + inst[i].DstReg.WriteMask = WRITEMASK_XYZW; + inst[i].DstReg.CondMask = COND_TR; + inst[i].DstReg.CondSwizzle = SWIZZLE_NOOP; + + inst[i].SaturateMode = SATURATE_OFF; + inst[i].Precision = FLOAT32; + } +} + + +/** + * Allocate an array of program instructions. + * \param numInst number of instructions + * \return pointer to instruction memory + */ +struct prog_instruction * +_mesa_alloc_instructions(GLuint numInst) +{ + return (struct prog_instruction *) + calloc(1, numInst * sizeof(struct prog_instruction)); +} + + +/** + * Reallocate memory storing an array of program instructions. + * This is used when we need to append additional instructions onto an + * program. + * \param oldInst pointer to first of old/src instructions + * \param numOldInst number of instructions at + * \param numNewInst desired size of new instruction array. + * \return pointer to start of new instruction array. + */ +struct prog_instruction * +_mesa_realloc_instructions(struct prog_instruction *oldInst, + GLuint numOldInst, GLuint numNewInst) +{ + struct prog_instruction *newInst; + + newInst = (struct prog_instruction *) + _mesa_realloc(oldInst, + numOldInst * sizeof(struct prog_instruction), + numNewInst * sizeof(struct prog_instruction)); + + return newInst; +} + + +/** + * Copy an array of program instructions. + * \param dest pointer to destination. + * \param src pointer to source. + * \param n number of instructions to copy. + * \return pointer to destination. + */ +struct prog_instruction * +_mesa_copy_instructions(struct prog_instruction *dest, + const struct prog_instruction *src, GLuint n) +{ + GLuint i; + memcpy(dest, src, n * sizeof(struct prog_instruction)); + for (i = 0; i < n; i++) { + if (src[i].Comment) + dest[i].Comment = _mesa_strdup(src[i].Comment); + } + return dest; +} + + +/** + * Free an array of instructions + */ +void +_mesa_free_instructions(struct prog_instruction *inst, GLuint count) +{ + GLuint i; + for (i = 0; i < count; i++) { + if (inst[i].Data) + free(inst[i].Data); + if (inst[i].Comment) + free((char *) inst[i].Comment); + } + free(inst); +} + + +/** + * Basic info about each instruction + */ +struct instruction_info +{ + gl_inst_opcode Opcode; + const char *Name; + GLuint NumSrcRegs; + GLuint NumDstRegs; +}; + +/** + * Instruction info + * \note Opcode should equal array index! + */ +static const struct instruction_info InstInfo[MAX_OPCODE] = { + { OPCODE_NOP, "NOP", 0, 0 }, + { OPCODE_ABS, "ABS", 1, 1 }, + { OPCODE_ADD, "ADD", 2, 1 }, + { OPCODE_AND, "AND", 2, 1 }, + { OPCODE_ARA, "ARA", 1, 1 }, + { OPCODE_ARL, "ARL", 1, 1 }, + { OPCODE_ARL_NV, "ARL_NV", 1, 1 }, + { OPCODE_ARR, "ARL", 1, 1 }, + { OPCODE_BGNLOOP,"BGNLOOP", 0, 0 }, + { OPCODE_BGNSUB, "BGNSUB", 0, 0 }, + { OPCODE_BRA, "BRA", 0, 0 }, + { OPCODE_BRK, "BRK", 0, 0 }, + { OPCODE_CAL, "CAL", 0, 0 }, + { OPCODE_CMP, "CMP", 3, 1 }, + { OPCODE_CONT, "CONT", 0, 0 }, + { OPCODE_COS, "COS", 1, 1 }, + { OPCODE_DDX, "DDX", 1, 1 }, + { OPCODE_DDY, "DDY", 1, 1 }, + { OPCODE_DP2, "DP2", 2, 1 }, + { OPCODE_DP2A, "DP2A", 3, 1 }, + { OPCODE_DP3, "DP3", 2, 1 }, + { OPCODE_DP4, "DP4", 2, 1 }, + { OPCODE_DPH, "DPH", 2, 1 }, + { OPCODE_DST, "DST", 2, 1 }, + { OPCODE_ELSE, "ELSE", 0, 0 }, + { OPCODE_END, "END", 0, 0 }, + { OPCODE_ENDIF, "ENDIF", 0, 0 }, + { OPCODE_ENDLOOP,"ENDLOOP", 0, 0 }, + { OPCODE_ENDSUB, "ENDSUB", 0, 0 }, + { OPCODE_EX2, "EX2", 1, 1 }, + { OPCODE_EXP, "EXP", 1, 1 }, + { OPCODE_FLR, "FLR", 1, 1 }, + { OPCODE_FRC, "FRC", 1, 1 }, + { OPCODE_IF, "IF", 1, 0 }, + { OPCODE_KIL, "KIL", 1, 0 }, + { OPCODE_KIL_NV, "KIL_NV", 0, 0 }, + { OPCODE_LG2, "LG2", 1, 1 }, + { OPCODE_LIT, "LIT", 1, 1 }, + { OPCODE_LOG, "LOG", 1, 1 }, + { OPCODE_LRP, "LRP", 3, 1 }, + { OPCODE_MAD, "MAD", 3, 1 }, + { OPCODE_MAX, "MAX", 2, 1 }, + { OPCODE_MIN, "MIN", 2, 1 }, + { OPCODE_MOV, "MOV", 1, 1 }, + { OPCODE_MUL, "MUL", 2, 1 }, + { OPCODE_NOISE1, "NOISE1", 1, 1 }, + { OPCODE_NOISE2, "NOISE2", 1, 1 }, + { OPCODE_NOISE3, "NOISE3", 1, 1 }, + { OPCODE_NOISE4, "NOISE4", 1, 1 }, + { OPCODE_NOT, "NOT", 1, 1 }, + { OPCODE_NRM3, "NRM3", 1, 1 }, + { OPCODE_NRM4, "NRM4", 1, 1 }, + { OPCODE_OR, "OR", 2, 1 }, + { OPCODE_PK2H, "PK2H", 1, 1 }, + { OPCODE_PK2US, "PK2US", 1, 1 }, + { OPCODE_PK4B, "PK4B", 1, 1 }, + { OPCODE_PK4UB, "PK4UB", 1, 1 }, + { OPCODE_POW, "POW", 2, 1 }, + { OPCODE_POPA, "POPA", 0, 0 }, + { OPCODE_PRINT, "PRINT", 1, 0 }, + { OPCODE_PUSHA, "PUSHA", 0, 0 }, + { OPCODE_RCC, "RCC", 1, 1 }, + { OPCODE_RCP, "RCP", 1, 1 }, + { OPCODE_RET, "RET", 0, 0 }, + { OPCODE_RFL, "RFL", 1, 1 }, + { OPCODE_RSQ, "RSQ", 1, 1 }, + { OPCODE_SCS, "SCS", 1, 1 }, + { OPCODE_SEQ, "SEQ", 2, 1 }, + { OPCODE_SFL, "SFL", 0, 1 }, + { OPCODE_SGE, "SGE", 2, 1 }, + { OPCODE_SGT, "SGT", 2, 1 }, + { OPCODE_SIN, "SIN", 1, 1 }, + { OPCODE_SLE, "SLE", 2, 1 }, + { OPCODE_SLT, "SLT", 2, 1 }, + { OPCODE_SNE, "SNE", 2, 1 }, + { OPCODE_SSG, "SSG", 1, 1 }, + { OPCODE_STR, "STR", 0, 1 }, + { OPCODE_SUB, "SUB", 2, 1 }, + { OPCODE_SWZ, "SWZ", 1, 1 }, + { OPCODE_TEX, "TEX", 1, 1 }, + { OPCODE_TXB, "TXB", 1, 1 }, + { OPCODE_TXD, "TXD", 3, 1 }, + { OPCODE_TXL, "TXL", 1, 1 }, + { OPCODE_TXP, "TXP", 1, 1 }, + { OPCODE_TXP_NV, "TXP_NV", 1, 1 }, + { OPCODE_TRUNC, "TRUNC", 1, 1 }, + { OPCODE_UP2H, "UP2H", 1, 1 }, + { OPCODE_UP2US, "UP2US", 1, 1 }, + { OPCODE_UP4B, "UP4B", 1, 1 }, + { OPCODE_UP4UB, "UP4UB", 1, 1 }, + { OPCODE_X2D, "X2D", 3, 1 }, + { OPCODE_XOR, "XOR", 2, 1 }, + { OPCODE_XPD, "XPD", 2, 1 } +}; + + +/** + * Return the number of src registers for the given instruction/opcode. + */ +GLuint +_mesa_num_inst_src_regs(gl_inst_opcode opcode) +{ + ASSERT(opcode < MAX_OPCODE); + ASSERT(opcode == InstInfo[opcode].Opcode); + ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode); + return InstInfo[opcode].NumSrcRegs; +} + + +/** + * Return the number of dst registers for the given instruction/opcode. + */ +GLuint +_mesa_num_inst_dst_regs(gl_inst_opcode opcode) +{ + ASSERT(opcode < MAX_OPCODE); + ASSERT(opcode == InstInfo[opcode].Opcode); + ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode); + return InstInfo[opcode].NumDstRegs; +} + + +GLboolean +_mesa_is_tex_instruction(gl_inst_opcode opcode) +{ + return (opcode == OPCODE_TEX || + opcode == OPCODE_TXB || + opcode == OPCODE_TXD || + opcode == OPCODE_TXL || + opcode == OPCODE_TXP); +} + + +/** + * Check if there's a potential src/dst register data dependency when + * using SOA execution. + * Example: + * MOV T, T.yxwz; + * This would expand into: + * MOV t0, t1; + * MOV t1, t0; + * MOV t2, t3; + * MOV t3, t2; + * The second instruction will have the wrong value for t0 if executed as-is. + */ +GLboolean +_mesa_check_soa_dependencies(const struct prog_instruction *inst) +{ + GLuint i, chan; + + if (inst->DstReg.WriteMask == WRITEMASK_X || + inst->DstReg.WriteMask == WRITEMASK_Y || + inst->DstReg.WriteMask == WRITEMASK_Z || + inst->DstReg.WriteMask == WRITEMASK_W || + inst->DstReg.WriteMask == 0x0) { + /* no chance of data dependency */ + return GL_FALSE; + } + + /* loop over src regs */ + for (i = 0; i < 3; i++) { + if (inst->SrcReg[i].File == inst->DstReg.File && + inst->SrcReg[i].Index == inst->DstReg.Index) { + /* loop over dest channels */ + GLuint channelsWritten = 0x0; + for (chan = 0; chan < 4; chan++) { + if (inst->DstReg.WriteMask & (1 << chan)) { + /* check if we're reading a channel that's been written */ + GLuint swizzle = GET_SWZ(inst->SrcReg[i].Swizzle, chan); + if (swizzle <= SWIZZLE_W && + (channelsWritten & (1 << swizzle))) { + return GL_TRUE; + } + + channelsWritten |= (1 << chan); + } + } + } + } + return GL_FALSE; +} + + +/** + * Return string name for given program opcode. + */ +const char * +_mesa_opcode_string(gl_inst_opcode opcode) +{ + if (opcode < MAX_OPCODE) + return InstInfo[opcode].Name; + else { + static char s[20]; + _mesa_snprintf(s, sizeof(s), "OP%u", opcode); + return s; + } +} + diff --git a/src/mesa/program/prog_instruction.h b/src/mesa/program/prog_instruction.h new file mode 100644 index 0000000000..28c797a4ba --- /dev/null +++ b/src/mesa/program/prog_instruction.h @@ -0,0 +1,437 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * \file prog_instruction.h + * + * Vertex/fragment program instruction datatypes and constants. + * + * \author Brian Paul + * \author Keith Whitwell + * \author Ian Romanick + */ + + +#ifndef PROG_INSTRUCTION_H +#define PROG_INSTRUCTION_H + + +#include "main/mfeatures.h" + + +/** + * Swizzle indexes. + * Do not change! + */ +/*@{*/ +#define SWIZZLE_X 0 +#define SWIZZLE_Y 1 +#define SWIZZLE_Z 2 +#define SWIZZLE_W 3 +#define SWIZZLE_ZERO 4 /**< For SWZ instruction only */ +#define SWIZZLE_ONE 5 /**< For SWZ instruction only */ +#define SWIZZLE_NIL 7 /**< used during shader code gen (undefined value) */ +/*@}*/ + +#define MAKE_SWIZZLE4(a,b,c,d) (((a)<<0) | ((b)<<3) | ((c)<<6) | ((d)<<9)) +#define SWIZZLE_NOOP MAKE_SWIZZLE4(0,1,2,3) +#define GET_SWZ(swz, idx) (((swz) >> ((idx)*3)) & 0x7) +#define GET_BIT(msk, idx) (((msk) >> (idx)) & 0x1) + +#define SWIZZLE_XYZW MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W) +#define SWIZZLE_XXXX MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X) +#define SWIZZLE_YYYY MAKE_SWIZZLE4(SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y) +#define SWIZZLE_ZZZZ MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z) +#define SWIZZLE_WWWW MAKE_SWIZZLE4(SWIZZLE_W, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W) + + +/** + * Writemask values, 1 bit per component. + */ +/*@{*/ +#define WRITEMASK_X 0x1 +#define WRITEMASK_Y 0x2 +#define WRITEMASK_XY 0x3 +#define WRITEMASK_Z 0x4 +#define WRITEMASK_XZ 0x5 +#define WRITEMASK_YZ 0x6 +#define WRITEMASK_XYZ 0x7 +#define WRITEMASK_W 0x8 +#define WRITEMASK_XW 0x9 +#define WRITEMASK_YW 0xa +#define WRITEMASK_XYW 0xb +#define WRITEMASK_ZW 0xc +#define WRITEMASK_XZW 0xd +#define WRITEMASK_YZW 0xe +#define WRITEMASK_XYZW 0xf +/*@}*/ + + +/** + * Condition codes + */ +/*@{*/ +#define COND_GT 1 /**< greater than zero */ +#define COND_EQ 2 /**< equal to zero */ +#define COND_LT 3 /**< less than zero */ +#define COND_UN 4 /**< unordered (NaN) */ +#define COND_GE 5 /**< greater than or equal to zero */ +#define COND_LE 6 /**< less than or equal to zero */ +#define COND_NE 7 /**< not equal to zero */ +#define COND_TR 8 /**< always true */ +#define COND_FL 9 /**< always false */ +/*@}*/ + + +/** + * Instruction precision for GL_NV_fragment_program + */ +/*@{*/ +#define FLOAT32 0x1 +#define FLOAT16 0x2 +#define FIXED12 0x4 +/*@}*/ + + +/** + * Saturation modes when storing values. + */ +/*@{*/ +#define SATURATE_OFF 0 +#define SATURATE_ZERO_ONE 1 +/*@}*/ + + +/** + * Per-component negation masks + */ +/*@{*/ +#define NEGATE_X 0x1 +#define NEGATE_Y 0x2 +#define NEGATE_Z 0x4 +#define NEGATE_W 0x8 +#define NEGATE_XYZ 0x7 +#define NEGATE_XYZW 0xf +#define NEGATE_NONE 0x0 +/*@}*/ + + +/** + * Program instruction opcodes, for both vertex and fragment programs. + * \note changes to this opcode list must be reflected in t_vb_arbprogram.c + */ +typedef enum prog_opcode { + /* ARB_vp ARB_fp NV_vp NV_fp GLSL */ + /*------------------------------------------*/ + OPCODE_NOP = 0, /* X */ + OPCODE_ABS, /* X X 1.1 X */ + OPCODE_ADD, /* X X X X X */ + OPCODE_AND, /* */ + OPCODE_ARA, /* 2 */ + OPCODE_ARL, /* X X */ + OPCODE_ARL_NV, /* 2 */ + OPCODE_ARR, /* 2 */ + OPCODE_BGNLOOP, /* opt */ + OPCODE_BGNSUB, /* opt */ + OPCODE_BRA, /* 2 X */ + OPCODE_BRK, /* 2 opt */ + OPCODE_CAL, /* 2 2 */ + OPCODE_CMP, /* X */ + OPCODE_CONT, /* opt */ + OPCODE_COS, /* X 2 X X */ + OPCODE_DDX, /* X X */ + OPCODE_DDY, /* X X */ + OPCODE_DP2, /* 2 */ + OPCODE_DP2A, /* 2 */ + OPCODE_DP3, /* X X X X X */ + OPCODE_DP4, /* X X X X X */ + OPCODE_DPH, /* X X 1.1 */ + OPCODE_DST, /* X X X X */ + OPCODE_ELSE, /* X */ + OPCODE_END, /* X X X X opt */ + OPCODE_ENDIF, /* opt */ + OPCODE_ENDLOOP, /* opt */ + OPCODE_ENDSUB, /* opt */ + OPCODE_EX2, /* X X 2 X X */ + OPCODE_EXP, /* X X X */ + OPCODE_FLR, /* X X 2 X X */ + OPCODE_FRC, /* X X 2 X X */ + OPCODE_IF, /* opt */ + OPCODE_KIL, /* X */ + OPCODE_KIL_NV, /* X X */ + OPCODE_LG2, /* X X 2 X X */ + OPCODE_LIT, /* X X X X */ + OPCODE_LOG, /* X X X */ + OPCODE_LRP, /* X X */ + OPCODE_MAD, /* X X X X X */ + OPCODE_MAX, /* X X X X X */ + OPCODE_MIN, /* X X X X X */ + OPCODE_MOV, /* X X X X X */ + OPCODE_MUL, /* X X X X X */ + OPCODE_NOISE1, /* X */ + OPCODE_NOISE2, /* X */ + OPCODE_NOISE3, /* X */ + OPCODE_NOISE4, /* X */ + OPCODE_NOT, /* */ + OPCODE_NRM3, /* */ + OPCODE_NRM4, /* */ + OPCODE_OR, /* */ + OPCODE_PK2H, /* X */ + OPCODE_PK2US, /* X */ + OPCODE_PK4B, /* X */ + OPCODE_PK4UB, /* X */ + OPCODE_POW, /* X X X X */ + OPCODE_POPA, /* 3 */ + OPCODE_PRINT, /* X X */ + OPCODE_PUSHA, /* 3 */ + OPCODE_RCC, /* 1.1 */ + OPCODE_RCP, /* X X X X X */ + OPCODE_RET, /* 2 2 */ + OPCODE_RFL, /* X X */ + OPCODE_RSQ, /* X X X X X */ + OPCODE_SCS, /* X */ + OPCODE_SEQ, /* 2 X X */ + OPCODE_SFL, /* 2 X */ + OPCODE_SGE, /* X X X X X */ + OPCODE_SGT, /* 2 X X */ + OPCODE_SIN, /* X 2 X X */ + OPCODE_SLE, /* 2 X X */ + OPCODE_SLT, /* X X X X X */ + OPCODE_SNE, /* 2 X X */ + OPCODE_SSG, /* 2 */ + OPCODE_STR, /* 2 X */ + OPCODE_SUB, /* X X 1.1 X X */ + OPCODE_SWZ, /* X X */ + OPCODE_TEX, /* X 3 X X */ + OPCODE_TXB, /* X 3 X */ + OPCODE_TXD, /* X X */ + OPCODE_TXL, /* 3 2 X */ + OPCODE_TXP, /* X X */ + OPCODE_TXP_NV, /* 3 X */ + OPCODE_TRUNC, /* X */ + OPCODE_UP2H, /* X */ + OPCODE_UP2US, /* X */ + OPCODE_UP4B, /* X */ + OPCODE_UP4UB, /* X */ + OPCODE_X2D, /* X */ + OPCODE_XOR, /* */ + OPCODE_XPD, /* X X X */ + MAX_OPCODE +} gl_inst_opcode; + + +/** + * Number of bits for the src/dst register Index field. + * This limits the size of temp/uniform register files. + */ +#define INST_INDEX_BITS 10 + + +/** + * Instruction source register. + */ +struct prog_src_register +{ + GLuint File:4; /**< One of the PROGRAM_* register file values. */ + GLint Index:(INST_INDEX_BITS+1); /**< Extra bit here for sign bit. + * May be negative for relative addressing. + */ + GLuint Swizzle:12; + GLuint RelAddr:1; + + /** Take the component-wise absolute value */ + GLuint Abs:1; + + /** + * Post-Abs negation. + * This will either be NEGATE_NONE or NEGATE_XYZW, except for the SWZ + * instruction which allows per-component negation. + */ + GLuint Negate:4; +}; + + +/** + * Instruction destination register. + */ +struct prog_dst_register +{ + GLuint File:4; /**< One of the PROGRAM_* register file values */ + GLuint Index:INST_INDEX_BITS; /**< Unsigned, never negative */ + GLuint WriteMask:4; + GLuint RelAddr:1; + + /** + * \name Conditional destination update control. + * + * \since + * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2, + * NV_vertex_program2_option. + */ + /*@{*/ + /** + * Takes one of the 9 possible condition values (EQ, FL, GT, GE, LE, LT, + * NE, TR, or UN). Dest reg is only written to if the matching + * (swizzled) condition code value passes. When a conditional update mask + * is not specified, this will be \c COND_TR. + */ + GLuint CondMask:4; + + /** + * Condition code swizzle value. + */ + GLuint CondSwizzle:12; + + /** + * Selects the condition code register to use for conditional destination + * update masking. In NV_fragmnet_program or NV_vertex_program2 mode, only + * condition code register 0 is available. In NV_vertex_program3 mode, + * condition code registers 0 and 1 are available. + */ + GLuint CondSrc:1; + /*@}*/ +}; + + +/** + * Vertex/fragment program instruction. + */ +struct prog_instruction +{ + gl_inst_opcode Opcode; + struct prog_src_register SrcReg[3]; + struct prog_dst_register DstReg; + + /** + * Indicates that the instruction should update the condition code + * register. + * + * \since + * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2, + * NV_vertex_program2_option. + */ + GLuint CondUpdate:1; + + /** + * If prog_instruction::CondUpdate is \c GL_TRUE, this value selects the + * condition code register that is to be updated. + * + * In GL_NV_fragment_program or GL_NV_vertex_program2 mode, only condition + * code register 0 is available. In GL_NV_vertex_program3 mode, condition + * code registers 0 and 1 are available. + * + * \since + * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2, + * NV_vertex_program2_option. + */ + GLuint CondDst:1; + + /** + * Saturate each value of the vectored result to the range [0,1] or the + * range [-1,1]. \c SSAT mode (i.e., saturation to the range [-1,1]) is + * only available in NV_fragment_program2 mode. + * Value is one of the SATURATE_* tokens. + * + * \since + * NV_fragment_program, NV_fragment_program_option, NV_vertex_program3. + */ + GLuint SaturateMode:2; + + /** + * Per-instruction selectable precision: FLOAT32, FLOAT16, FIXED12. + * + * \since + * NV_fragment_program, NV_fragment_program_option. + */ + GLuint Precision:3; + + /** + * \name Extra fields for TEX, TXB, TXD, TXL, TXP instructions. + */ + /*@{*/ + /** Source texture unit. */ + GLuint TexSrcUnit:5; + + /** Source texture target, one of TEXTURE_{1D,2D,3D,CUBE,RECT}_INDEX */ + GLuint TexSrcTarget:3; + + /** True if tex instruction should do shadow comparison */ + GLuint TexShadow:1; + /*@}*/ + + /** + * For BRA and CAL instructions, the location to jump to. + * For BGNLOOP, points to ENDLOOP (and vice-versa). + * For BRK, points to BGNLOOP (which points to ENDLOOP). + * For IF, points to ELSE or ENDIF. + * For ELSE, points to ENDIF. + */ + GLint BranchTarget; + + /** for debugging purposes */ + const char *Comment; + + /** Arbitrary data. Used for OPCODE_PRINT and some drivers */ + void *Data; + + /** for driver use (try to remove someday) */ + GLint Aux; +}; + + +extern void +_mesa_init_instructions(struct prog_instruction *inst, GLuint count); + +extern struct prog_instruction * +_mesa_alloc_instructions(GLuint numInst); + +extern struct prog_instruction * +_mesa_realloc_instructions(struct prog_instruction *oldInst, + GLuint numOldInst, GLuint numNewInst); + +extern struct prog_instruction * +_mesa_copy_instructions(struct prog_instruction *dest, + const struct prog_instruction *src, GLuint n); + +extern void +_mesa_free_instructions(struct prog_instruction *inst, GLuint count); + +extern GLuint +_mesa_num_inst_src_regs(gl_inst_opcode opcode); + +extern GLuint +_mesa_num_inst_dst_regs(gl_inst_opcode opcode); + +extern GLboolean +_mesa_is_tex_instruction(gl_inst_opcode opcode); + +extern GLboolean +_mesa_check_soa_dependencies(const struct prog_instruction *inst); + +extern const char * +_mesa_opcode_string(gl_inst_opcode opcode); + + +#endif /* PROG_INSTRUCTION_H */ diff --git a/src/mesa/program/prog_noise.c b/src/mesa/program/prog_noise.c new file mode 100644 index 0000000000..1713ddb5f3 --- /dev/null +++ b/src/mesa/program/prog_noise.c @@ -0,0 +1,638 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * SimplexNoise1234 + * Copyright (c) 2003-2005, Stefan Gustavson + * + * Contact: stegu@itn.liu.se + */ + +/** + * \file + * \brief C implementation of Perlin Simplex Noise over 1, 2, 3 and 4 dims. + * \author Stefan Gustavson (stegu@itn.liu.se) + * + * + * This implementation is "Simplex Noise" as presented by + * Ken Perlin at a relatively obscure and not often cited course + * session "Real-Time Shading" at Siggraph 2001 (before real + * time shading actually took on), under the title "hardware noise". + * The 3D function is numerically equivalent to his Java reference + * code available in the PDF course notes, although I re-implemented + * it from scratch to get more readable code. The 1D, 2D and 4D cases + * were implemented from scratch by me from Ken Perlin's text. + * + * This file has no dependencies on any other file, not even its own + * header file. The header file is made for use by external code only. + */ + + +#include "main/imports.h" +#include "prog_noise.h" + +#define FASTFLOOR(x) ( ((x)>0) ? ((int)x) : (((int)x)-1) ) + +/* + * --------------------------------------------------------------------- + * Static data + */ + +/** + * Permutation table. This is just a random jumble of all numbers 0-255, + * repeated twice to avoid wrapping the index at 255 for each lookup. + * This needs to be exactly the same for all instances on all platforms, + * so it's easiest to just keep it as static explicit data. + * This also removes the need for any initialisation of this class. + * + * Note that making this an int[] instead of a char[] might make the + * code run faster on platforms with a high penalty for unaligned single + * byte addressing. Intel x86 is generally single-byte-friendly, but + * some other CPUs are faster with 4-aligned reads. + * However, a char[] is smaller, which avoids cache trashing, and that + * is probably the most important aspect on most architectures. + * This array is accessed a *lot* by the noise functions. + * A vector-valued noise over 3D accesses it 96 times, and a + * float-valued 4D noise 64 times. We want this to fit in the cache! + */ +unsigned char perm[512] = { 151, 160, 137, 91, 90, 15, + 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, + 99, 37, 240, 21, 10, 23, + 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, + 11, 32, 57, 177, 33, + 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, + 134, 139, 48, 27, 166, + 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, + 55, 46, 245, 40, 244, + 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, + 18, 169, 200, 196, + 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, + 226, 250, 124, 123, + 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, + 17, 182, 189, 28, 42, + 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, + 167, 43, 172, 9, + 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, + 218, 246, 97, 228, + 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, + 249, 14, 239, 107, + 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, + 127, 4, 150, 254, + 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, + 215, 61, 156, 180, + 151, 160, 137, 91, 90, 15, + 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, + 99, 37, 240, 21, 10, 23, + 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, + 11, 32, 57, 177, 33, + 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, + 134, 139, 48, 27, 166, + 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, + 55, 46, 245, 40, 244, + 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, + 18, 169, 200, 196, + 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, + 226, 250, 124, 123, + 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, + 17, 182, 189, 28, 42, + 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, + 167, 43, 172, 9, + 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, + 218, 246, 97, 228, + 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, + 249, 14, 239, 107, + 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, + 127, 4, 150, 254, + 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, + 215, 61, 156, 180 +}; + +/* + * --------------------------------------------------------------------- + */ + +/* + * Helper functions to compute gradients-dot-residualvectors (1D to 4D) + * Note that these generate gradients of more than unit length. To make + * a close match with the value range of classic Perlin noise, the final + * noise values need to be rescaled to fit nicely within [-1,1]. + * (The simplex noise functions as such also have different scaling.) + * Note also that these noise functions are the most practical and useful + * signed version of Perlin noise. To return values according to the + * RenderMan specification from the SL noise() and pnoise() functions, + * the noise values need to be scaled and offset to [0,1], like this: + * float SLnoise = (SimplexNoise1234::noise(x,y,z) + 1.0) * 0.5; + */ + +static float +grad1(int hash, float x) +{ + int h = hash & 15; + float grad = 1.0f + (h & 7); /* Gradient value 1.0, 2.0, ..., 8.0 */ + if (h & 8) + grad = -grad; /* Set a random sign for the gradient */ + return (grad * x); /* Multiply the gradient with the distance */ +} + +static float +grad2(int hash, float x, float y) +{ + int h = hash & 7; /* Convert low 3 bits of hash code */ + float u = h < 4 ? x : y; /* into 8 simple gradient directions, */ + float v = h < 4 ? y : x; /* and compute the dot product with (x,y). */ + return ((h & 1) ? -u : u) + ((h & 2) ? -2.0f * v : 2.0f * v); +} + +static float +grad3(int hash, float x, float y, float z) +{ + int h = hash & 15; /* Convert low 4 bits of hash code into 12 simple */ + float u = h < 8 ? x : y; /* gradient directions, and compute dot product. */ + float v = h < 4 ? y : h == 12 || h == 14 ? x : z; /* Fix repeats at h = 12 to 15 */ + return ((h & 1) ? -u : u) + ((h & 2) ? -v : v); +} + +static float +grad4(int hash, float x, float y, float z, float t) +{ + int h = hash & 31; /* Convert low 5 bits of hash code into 32 simple */ + float u = h < 24 ? x : y; /* gradient directions, and compute dot product. */ + float v = h < 16 ? y : z; + float w = h < 8 ? z : t; + return ((h & 1) ? -u : u) + ((h & 2) ? -v : v) + ((h & 4) ? -w : w); +} + +/** + * A lookup table to traverse the simplex around a given point in 4D. + * Details can be found where this table is used, in the 4D noise method. + * TODO: This should not be required, backport it from Bill's GLSL code! + */ +static unsigned char simplex[64][4] = { + {0, 1, 2, 3}, {0, 1, 3, 2}, {0, 0, 0, 0}, {0, 2, 3, 1}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 2, 3, 0}, + {0, 2, 1, 3}, {0, 0, 0, 0}, {0, 3, 1, 2}, {0, 3, 2, 1}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 3, 2, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {1, 2, 0, 3}, {0, 0, 0, 0}, {1, 3, 0, 2}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {2, 3, 0, 1}, {2, 3, 1, 0}, + {1, 0, 2, 3}, {1, 0, 3, 2}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {2, 0, 3, 1}, {0, 0, 0, 0}, {2, 1, 3, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {2, 0, 1, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {3, 0, 1, 2}, {3, 0, 2, 1}, {0, 0, 0, 0}, {3, 1, 2, 0}, + {2, 1, 0, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {3, 1, 0, 2}, {0, 0, 0, 0}, {3, 2, 0, 1}, {3, 2, 1, 0} +}; + + +/** 1D simplex noise */ +GLfloat +_mesa_noise1(GLfloat x) +{ + int i0 = FASTFLOOR(x); + int i1 = i0 + 1; + float x0 = x - i0; + float x1 = x0 - 1.0f; + float t1 = 1.0f - x1 * x1; + float n0, n1; + + float t0 = 1.0f - x0 * x0; +/* if(t0 < 0.0f) t0 = 0.0f; // this never happens for the 1D case */ + t0 *= t0; + n0 = t0 * t0 * grad1(perm[i0 & 0xff], x0); + +/* if(t1 < 0.0f) t1 = 0.0f; // this never happens for the 1D case */ + t1 *= t1; + n1 = t1 * t1 * grad1(perm[i1 & 0xff], x1); + /* The maximum value of this noise is 8*(3/4)^4 = 2.53125 */ + /* A factor of 0.395 would scale to fit exactly within [-1,1], but */ + /* we want to match PRMan's 1D noise, so we scale it down some more. */ + return 0.25f * (n0 + n1); +} + + +/** 2D simplex noise */ +GLfloat +_mesa_noise2(GLfloat x, GLfloat y) +{ +#define F2 0.366025403f /* F2 = 0.5*(sqrt(3.0)-1.0) */ +#define G2 0.211324865f /* G2 = (3.0-Math.sqrt(3.0))/6.0 */ + + float n0, n1, n2; /* Noise contributions from the three corners */ + + /* Skew the input space to determine which simplex cell we're in */ + float s = (x + y) * F2; /* Hairy factor for 2D */ + float xs = x + s; + float ys = y + s; + int i = FASTFLOOR(xs); + int j = FASTFLOOR(ys); + + float t = (float) (i + j) * G2; + float X0 = i - t; /* Unskew the cell origin back to (x,y) space */ + float Y0 = j - t; + float x0 = x - X0; /* The x,y distances from the cell origin */ + float y0 = y - Y0; + + float x1, y1, x2, y2; + int ii, jj; + float t0, t1, t2; + + /* For the 2D case, the simplex shape is an equilateral triangle. */ + /* Determine which simplex we are in. */ + int i1, j1; /* Offsets for second (middle) corner of simplex in (i,j) coords */ + if (x0 > y0) { + i1 = 1; + j1 = 0; + } /* lower triangle, XY order: (0,0)->(1,0)->(1,1) */ + else { + i1 = 0; + j1 = 1; + } /* upper triangle, YX order: (0,0)->(0,1)->(1,1) */ + + /* A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and */ + /* a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where */ + /* c = (3-sqrt(3))/6 */ + + x1 = x0 - i1 + G2; /* Offsets for middle corner in (x,y) unskewed coords */ + y1 = y0 - j1 + G2; + x2 = x0 - 1.0f + 2.0f * G2; /* Offsets for last corner in (x,y) unskewed coords */ + y2 = y0 - 1.0f + 2.0f * G2; + + /* Wrap the integer indices at 256, to avoid indexing perm[] out of bounds */ + ii = i % 256; + jj = j % 256; + + /* Calculate the contribution from the three corners */ + t0 = 0.5f - x0 * x0 - y0 * y0; + if (t0 < 0.0f) + n0 = 0.0f; + else { + t0 *= t0; + n0 = t0 * t0 * grad2(perm[ii + perm[jj]], x0, y0); + } + + t1 = 0.5f - x1 * x1 - y1 * y1; + if (t1 < 0.0f) + n1 = 0.0f; + else { + t1 *= t1; + n1 = t1 * t1 * grad2(perm[ii + i1 + perm[jj + j1]], x1, y1); + } + + t2 = 0.5f - x2 * x2 - y2 * y2; + if (t2 < 0.0f) + n2 = 0.0f; + else { + t2 *= t2; + n2 = t2 * t2 * grad2(perm[ii + 1 + perm[jj + 1]], x2, y2); + } + + /* Add contributions from each corner to get the final noise value. */ + /* The result is scaled to return values in the interval [-1,1]. */ + return 40.0f * (n0 + n1 + n2); /* TODO: The scale factor is preliminary! */ +} + + +/** 3D simplex noise */ +GLfloat +_mesa_noise3(GLfloat x, GLfloat y, GLfloat z) +{ +/* Simple skewing factors for the 3D case */ +#define F3 0.333333333f +#define G3 0.166666667f + + float n0, n1, n2, n3; /* Noise contributions from the four corners */ + + /* Skew the input space to determine which simplex cell we're in */ + float s = (x + y + z) * F3; /* Very nice and simple skew factor for 3D */ + float xs = x + s; + float ys = y + s; + float zs = z + s; + int i = FASTFLOOR(xs); + int j = FASTFLOOR(ys); + int k = FASTFLOOR(zs); + + float t = (float) (i + j + k) * G3; + float X0 = i - t; /* Unskew the cell origin back to (x,y,z) space */ + float Y0 = j - t; + float Z0 = k - t; + float x0 = x - X0; /* The x,y,z distances from the cell origin */ + float y0 = y - Y0; + float z0 = z - Z0; + + float x1, y1, z1, x2, y2, z2, x3, y3, z3; + int ii, jj, kk; + float t0, t1, t2, t3; + + /* For the 3D case, the simplex shape is a slightly irregular tetrahedron. */ + /* Determine which simplex we are in. */ + int i1, j1, k1; /* Offsets for second corner of simplex in (i,j,k) coords */ + int i2, j2, k2; /* Offsets for third corner of simplex in (i,j,k) coords */ + +/* This code would benefit from a backport from the GLSL version! */ + if (x0 >= y0) { + if (y0 >= z0) { + i1 = 1; + j1 = 0; + k1 = 0; + i2 = 1; + j2 = 1; + k2 = 0; + } /* X Y Z order */ + else if (x0 >= z0) { + i1 = 1; + j1 = 0; + k1 = 0; + i2 = 1; + j2 = 0; + k2 = 1; + } /* X Z Y order */ + else { + i1 = 0; + j1 = 0; + k1 = 1; + i2 = 1; + j2 = 0; + k2 = 1; + } /* Z X Y order */ + } + else { /* x0 y0) ? 32 : 0; + int c2 = (x0 > z0) ? 16 : 0; + int c3 = (y0 > z0) ? 8 : 0; + int c4 = (x0 > w0) ? 4 : 0; + int c5 = (y0 > w0) ? 2 : 0; + int c6 = (z0 > w0) ? 1 : 0; + int c = c1 + c2 + c3 + c4 + c5 + c6; + + int i1, j1, k1, l1; /* The integer offsets for the second simplex corner */ + int i2, j2, k2, l2; /* The integer offsets for the third simplex corner */ + int i3, j3, k3, l3; /* The integer offsets for the fourth simplex corner */ + + float x1, y1, z1, w1, x2, y2, z2, w2, x3, y3, z3, w3, x4, y4, z4, w4; + int ii, jj, kk, ll; + float t0, t1, t2, t3, t4; + + /* + * simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some + * order. Many values of c will never occur, since e.g. x>y>z>w + * makes x= 3 ? 1 : 0; + j1 = simplex[c][1] >= 3 ? 1 : 0; + k1 = simplex[c][2] >= 3 ? 1 : 0; + l1 = simplex[c][3] >= 3 ? 1 : 0; + /* The number 2 in the "simplex" array is at the second largest coordinate. */ + i2 = simplex[c][0] >= 2 ? 1 : 0; + j2 = simplex[c][1] >= 2 ? 1 : 0; + k2 = simplex[c][2] >= 2 ? 1 : 0; + l2 = simplex[c][3] >= 2 ? 1 : 0; + /* The number 1 in the "simplex" array is at the second smallest coordinate. */ + i3 = simplex[c][0] >= 1 ? 1 : 0; + j3 = simplex[c][1] >= 1 ? 1 : 0; + k3 = simplex[c][2] >= 1 ? 1 : 0; + l3 = simplex[c][3] >= 1 ? 1 : 0; + /* The fifth corner has all coordinate offsets = 1, so no need to look that up. */ + + x1 = x0 - i1 + G4; /* Offsets for second corner in (x,y,z,w) coords */ + y1 = y0 - j1 + G4; + z1 = z0 - k1 + G4; + w1 = w0 - l1 + G4; + x2 = x0 - i2 + 2.0f * G4; /* Offsets for third corner in (x,y,z,w) coords */ + y2 = y0 - j2 + 2.0f * G4; + z2 = z0 - k2 + 2.0f * G4; + w2 = w0 - l2 + 2.0f * G4; + x3 = x0 - i3 + 3.0f * G4; /* Offsets for fourth corner in (x,y,z,w) coords */ + y3 = y0 - j3 + 3.0f * G4; + z3 = z0 - k3 + 3.0f * G4; + w3 = w0 - l3 + 3.0f * G4; + x4 = x0 - 1.0f + 4.0f * G4; /* Offsets for last corner in (x,y,z,w) coords */ + y4 = y0 - 1.0f + 4.0f * G4; + z4 = z0 - 1.0f + 4.0f * G4; + w4 = w0 - 1.0f + 4.0f * G4; + + /* Wrap the integer indices at 256, to avoid indexing perm[] out of bounds */ + ii = i % 256; + jj = j % 256; + kk = k % 256; + ll = l % 256; + + /* Calculate the contribution from the five corners */ + t0 = 0.6f - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0; + if (t0 < 0.0f) + n0 = 0.0f; + else { + t0 *= t0; + n0 = + t0 * t0 * grad4(perm[ii + perm[jj + perm[kk + perm[ll]]]], x0, y0, + z0, w0); + } + + t1 = 0.6f - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1; + if (t1 < 0.0f) + n1 = 0.0f; + else { + t1 *= t1; + n1 = + t1 * t1 * + grad4(perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]]]], + x1, y1, z1, w1); + } + + t2 = 0.6f - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2; + if (t2 < 0.0f) + n2 = 0.0f; + else { + t2 *= t2; + n2 = + t2 * t2 * + grad4(perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]]]], + x2, y2, z2, w2); + } + + t3 = 0.6f - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3; + if (t3 < 0.0f) + n3 = 0.0f; + else { + t3 *= t3; + n3 = + t3 * t3 * + grad4(perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]]]], + x3, y3, z3, w3); + } + + t4 = 0.6f - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4; + if (t4 < 0.0f) + n4 = 0.0f; + else { + t4 *= t4; + n4 = + t4 * t4 * + grad4(perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]]]], x4, + y4, z4, w4); + } + + /* Sum up and scale the result to cover the range [-1,1] */ + return 27.0f * (n0 + n1 + n2 + n3 + n4); /* TODO: The scale factor is preliminary! */ +} diff --git a/src/mesa/program/prog_noise.h b/src/mesa/program/prog_noise.h new file mode 100644 index 0000000000..c4779479f9 --- /dev/null +++ b/src/mesa/program/prog_noise.h @@ -0,0 +1,34 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef PROG_NOISE +#define PROG_NOISE + +extern GLfloat _mesa_noise1(GLfloat); +extern GLfloat _mesa_noise2(GLfloat, GLfloat); +extern GLfloat _mesa_noise3(GLfloat, GLfloat, GLfloat); +extern GLfloat _mesa_noise4(GLfloat, GLfloat, GLfloat, GLfloat); + +#endif + diff --git a/src/mesa/program/prog_optimize.c b/src/mesa/program/prog_optimize.c new file mode 100644 index 0000000000..2941a17da3 --- /dev/null +++ b/src/mesa/program/prog_optimize.c @@ -0,0 +1,1035 @@ +/* + * Mesa 3-D graphics library + * Version: 7.5 + * + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VMWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/macros.h" +#include "program.h" +#include "prog_instruction.h" +#include "prog_optimize.h" +#include "prog_print.h" + + +#define MAX_LOOP_NESTING 50 + + +static GLboolean dbg = GL_FALSE; + +/* Returns the mask of channels read from the given srcreg in this instruction. + */ +static GLuint +get_src_arg_mask(const struct prog_instruction *inst, int arg) +{ + int writemask = inst->DstReg.WriteMask; + + if (inst->CondUpdate) + writemask = WRITEMASK_XYZW; + + switch (inst->Opcode) { + case OPCODE_MOV: + case OPCODE_ABS: + case OPCODE_ADD: + case OPCODE_MUL: + case OPCODE_SUB: + return writemask; + case OPCODE_RCP: + case OPCODE_SIN: + case OPCODE_COS: + case OPCODE_RSQ: + case OPCODE_POW: + case OPCODE_EX2: + return WRITEMASK_X; + case OPCODE_DP2: + return WRITEMASK_XY; + case OPCODE_DP3: + case OPCODE_XPD: + return WRITEMASK_XYZ; + default: + return WRITEMASK_XYZW; + } +} + +/** + * In 'prog' remove instruction[i] if removeFlags[i] == TRUE. + * \return number of instructions removed + */ +static GLuint +remove_instructions(struct gl_program *prog, const GLboolean *removeFlags) +{ + GLint i, removeEnd = 0, removeCount = 0; + GLuint totalRemoved = 0; + + /* go backward */ + for (i = prog->NumInstructions - 1; i >= 0; i--) { + if (removeFlags[i]) { + totalRemoved++; + if (removeCount == 0) { + /* begin a run of instructions to remove */ + removeEnd = i; + removeCount = 1; + } + else { + /* extend the run of instructions to remove */ + removeCount++; + } + } + else { + /* don't remove this instruction, but check if the preceeding + * instructions are to be removed. + */ + if (removeCount > 0) { + GLint removeStart = removeEnd - removeCount + 1; + _mesa_delete_instructions(prog, removeStart, removeCount); + removeStart = removeCount = 0; /* reset removal info */ + } + } + } + /* Finish removing if the first instruction was to be removed. */ + if (removeCount > 0) { + GLint removeStart = removeEnd - removeCount + 1; + _mesa_delete_instructions(prog, removeStart, removeCount); + } + return totalRemoved; +} + + +/** + * Remap register indexes according to map. + * \param prog the program to search/replace + * \param file the type of register file to search/replace + * \param map maps old register indexes to new indexes + */ +static void +replace_regs(struct gl_program *prog, gl_register_file file, const GLint map[]) +{ + GLuint i; + + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); + GLuint j; + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == file) { + GLuint index = inst->SrcReg[j].Index; + ASSERT(map[index] >= 0); + inst->SrcReg[j].Index = map[index]; + } + } + if (inst->DstReg.File == file) { + const GLuint index = inst->DstReg.Index; + ASSERT(map[index] >= 0); + inst->DstReg.Index = map[index]; + } + } +} + + +/** + * Consolidate temporary registers to use low numbers. For example, if the + * shader only uses temps 4, 5, 8, replace them with 0, 1, 2. + */ +static void +_mesa_consolidate_registers(struct gl_program *prog) +{ + GLboolean tempUsed[MAX_PROGRAM_TEMPS]; + GLint tempMap[MAX_PROGRAM_TEMPS]; + GLuint tempMax = 0, i; + + if (dbg) { + printf("Optimize: Begin register consolidation\n"); + } + + memset(tempUsed, 0, sizeof(tempUsed)); + + for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { + tempMap[i] = -1; + } + + /* set tempUsed[i] if temporary [i] is referenced */ + for (i = 0; i < prog->NumInstructions; i++) { + const struct prog_instruction *inst = prog->Instructions + i; + const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); + GLuint j; + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { + const GLuint index = inst->SrcReg[j].Index; + ASSERT(index < MAX_PROGRAM_TEMPS); + tempUsed[index] = GL_TRUE; + tempMax = MAX2(tempMax, index); + break; + } + } + if (inst->DstReg.File == PROGRAM_TEMPORARY) { + const GLuint index = inst->DstReg.Index; + ASSERT(index < MAX_PROGRAM_TEMPS); + tempUsed[index] = GL_TRUE; + tempMax = MAX2(tempMax, index); + } + } + + /* allocate a new index for each temp that's used */ + { + GLuint freeTemp = 0; + for (i = 0; i <= tempMax; i++) { + if (tempUsed[i]) { + tempMap[i] = freeTemp++; + /*printf("replace %u with %u\n", i, tempMap[i]);*/ + } + } + if (freeTemp == tempMax + 1) { + /* no consolidation possible */ + return; + } + if (dbg) { + printf("Replace regs 0..%u with 0..%u\n", tempMax, freeTemp-1); + } + } + + replace_regs(prog, PROGRAM_TEMPORARY, tempMap); + + if (dbg) { + printf("Optimize: End register consolidation\n"); + } +} + + +/** + * Remove dead instructions from the given program. + * This is very primitive for now. Basically look for temp registers + * that are written to but never read. Remove any instructions that + * write to such registers. Be careful with condition code setters. + */ +static void +_mesa_remove_dead_code(struct gl_program *prog) +{ + GLboolean tempRead[MAX_PROGRAM_TEMPS][4]; + GLboolean *removeInst; /* per-instruction removal flag */ + GLuint i, rem = 0, comp; + + memset(tempRead, 0, sizeof(tempRead)); + + if (dbg) { + printf("Optimize: Begin dead code removal\n"); + /*_mesa_print_program(prog);*/ + } + + removeInst = (GLboolean *) + calloc(1, prog->NumInstructions * sizeof(GLboolean)); + + /* Determine which temps are read and written */ + for (i = 0; i < prog->NumInstructions; i++) { + const struct prog_instruction *inst = prog->Instructions + i; + const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); + GLuint j; + + /* check src regs */ + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { + const GLuint index = inst->SrcReg[j].Index; + GLuint read_mask; + ASSERT(index < MAX_PROGRAM_TEMPS); + read_mask = get_src_arg_mask(inst, j); + + if (inst->SrcReg[j].RelAddr) { + if (dbg) + printf("abort remove dead code (indirect temp)\n"); + goto done; + } + + for (comp = 0; comp < 4; comp++) { + GLuint swz = (inst->SrcReg[j].Swizzle >> (3 * comp)) & 0x7; + + if ((read_mask & (1 << comp)) == 0) + continue; + + switch (swz) { + case SWIZZLE_X: + tempRead[index][0] = GL_TRUE; + break; + case SWIZZLE_Y: + tempRead[index][1] = GL_TRUE; + break; + case SWIZZLE_Z: + tempRead[index][2] = GL_TRUE; + break; + case SWIZZLE_W: + tempRead[index][3] = GL_TRUE; + break; + } + } + } + } + + /* check dst reg */ + if (inst->DstReg.File == PROGRAM_TEMPORARY) { + const GLuint index = inst->DstReg.Index; + ASSERT(index < MAX_PROGRAM_TEMPS); + + if (inst->DstReg.RelAddr) { + if (dbg) + printf("abort remove dead code (indirect temp)\n"); + goto done; + } + + if (inst->CondUpdate) { + /* If we're writing to this register and setting condition + * codes we cannot remove the instruction. Prevent removal + * by setting the 'read' flag. + */ + tempRead[index][0] = GL_TRUE; + tempRead[index][1] = GL_TRUE; + tempRead[index][2] = GL_TRUE; + tempRead[index][3] = GL_TRUE; + } + } + } + + /* find instructions that write to dead registers, flag for removal */ + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + const GLuint numDst = _mesa_num_inst_dst_regs(inst->Opcode); + + if (numDst != 0 && inst->DstReg.File == PROGRAM_TEMPORARY) { + GLint chan, index = inst->DstReg.Index; + + for (chan = 0; chan < 4; chan++) { + if (!tempRead[index][chan] && + inst->DstReg.WriteMask & (1 << chan)) { + if (dbg) { + printf("Remove writemask on %u.%c\n", i, + chan == 3 ? 'w' : 'x' + chan); + } + inst->DstReg.WriteMask &= ~(1 << chan); + rem++; + } + } + + if (inst->DstReg.WriteMask == 0) { + /* If we cleared all writes, the instruction can be removed. */ + if (dbg) + printf("Remove instruction %u: \n", i); + removeInst[i] = GL_TRUE; + } + } + } + + /* now remove the instructions which aren't needed */ + rem = remove_instructions(prog, removeInst); + + if (dbg) { + printf("Optimize: End dead code removal.\n"); + printf(" %u channel writes removed\n", rem); + printf(" %u instructions removed\n", rem); + /*_mesa_print_program(prog);*/ + } + +done: + free(removeInst); +} + + +enum temp_use +{ + READ, + WRITE, + FLOW, + END +}; + +/** + * Scan forward in program from 'start' for the next occurance of TEMP[index]. + * Return READ, WRITE, FLOW or END to indicate the next usage or an indicator + * that we can't look further. + */ +static enum temp_use +find_next_temp_use(const struct gl_program *prog, GLuint start, GLuint index) +{ + GLuint i; + + for (i = start; i < prog->NumInstructions; i++) { + const struct prog_instruction *inst = prog->Instructions + i; + switch (inst->Opcode) { + case OPCODE_BGNLOOP: + case OPCODE_ENDLOOP: + case OPCODE_BGNSUB: + case OPCODE_ENDSUB: + return FLOW; + default: + { + const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); + GLuint j; + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == PROGRAM_TEMPORARY && + inst->SrcReg[j].Index == index) + return READ; + } + if (inst->DstReg.File == PROGRAM_TEMPORARY && + inst->DstReg.Index == index) + return WRITE; + } + } + } + + return END; +} + +static GLboolean _mesa_is_flow_control_opcode(enum prog_opcode opcode) +{ + switch (opcode) { + case OPCODE_BGNLOOP: + case OPCODE_BGNSUB: + case OPCODE_BRA: + case OPCODE_CAL: + case OPCODE_CONT: + case OPCODE_IF: + case OPCODE_ELSE: + case OPCODE_END: + case OPCODE_ENDIF: + case OPCODE_ENDLOOP: + case OPCODE_ENDSUB: + case OPCODE_RET: + return GL_TRUE; + default: + return GL_FALSE; + } +} + +/** + * Try to remove use of extraneous MOV instructions, to free them up for dead + * code removal. + */ +static void +_mesa_remove_extra_move_use(struct gl_program *prog) +{ + GLuint i, j; + + if (dbg) { + printf("Optimize: Begin remove extra move use\n"); + _mesa_print_program(prog); + } + + /* + * Look for sequences such as this: + * MOV tmpX, arg0; + * ... + * FOO tmpY, tmpX, arg1; + * and convert into: + * MOV tmpX, arg0; + * ... + * FOO tmpY, arg0, arg1; + */ + + for (i = 0; i + 1 < prog->NumInstructions; i++) { + const struct prog_instruction *mov = prog->Instructions + i; + + if (mov->Opcode != OPCODE_MOV || + mov->DstReg.File != PROGRAM_TEMPORARY || + mov->DstReg.RelAddr || + mov->DstReg.CondMask != COND_TR || + mov->SaturateMode != SATURATE_OFF || + mov->SrcReg[0].RelAddr) + continue; + + /* Walk through remaining instructions until the or src reg gets + * rewritten or we get into some flow-control, eliminating the use of + * this MOV. + */ + for (j = i + 1; j < prog->NumInstructions; j++) { + struct prog_instruction *inst2 = prog->Instructions + j; + GLuint arg; + + if (_mesa_is_flow_control_opcode(inst2->Opcode)) + break; + + /* First rewrite this instruction's args if appropriate. */ + for (arg = 0; arg < _mesa_num_inst_src_regs(inst2->Opcode); arg++) { + int comp; + int read_mask = get_src_arg_mask(inst2, arg); + + if (inst2->SrcReg[arg].File != mov->DstReg.File || + inst2->SrcReg[arg].Index != mov->DstReg.Index || + inst2->SrcReg[arg].RelAddr || + inst2->SrcReg[arg].Abs) + continue; + + /* Check that all the sources for this arg of inst2 come from inst1 + * or constants. + */ + for (comp = 0; comp < 4; comp++) { + int src_swz = GET_SWZ(inst2->SrcReg[arg].Swizzle, comp); + + /* If the MOV didn't write that channel, can't use it. */ + if ((read_mask & (1 << comp)) && + src_swz <= SWIZZLE_W && + (mov->DstReg.WriteMask & (1 << src_swz)) == 0) + break; + } + if (comp != 4) + continue; + + /* Adjust the swizzles of inst2 to point at MOV's source */ + for (comp = 0; comp < 4; comp++) { + int inst2_swz = GET_SWZ(inst2->SrcReg[arg].Swizzle, comp); + + if (inst2_swz <= SWIZZLE_W) { + GLuint s = GET_SWZ(mov->SrcReg[0].Swizzle, inst2_swz); + inst2->SrcReg[arg].Swizzle &= ~(7 << (3 * comp)); + inst2->SrcReg[arg].Swizzle |= s << (3 * comp); + inst2->SrcReg[arg].Negate ^= (((mov->SrcReg[0].Negate >> + inst2_swz) & 0x1) << comp); + } + } + inst2->SrcReg[arg].File = mov->SrcReg[0].File; + inst2->SrcReg[arg].Index = mov->SrcReg[0].Index; + } + + /* If this instruction overwrote part of the move, our time is up. */ + if ((inst2->DstReg.File == mov->DstReg.File && + (inst2->DstReg.RelAddr || + inst2->DstReg.Index == mov->DstReg.Index)) || + (inst2->DstReg.File == mov->SrcReg[0].File && + (inst2->DstReg.RelAddr || + inst2->DstReg.Index == mov->SrcReg[0].Index))) + break; + } + } + + if (dbg) { + printf("Optimize: End remove extra move use.\n"); + /*_mesa_print_program(prog);*/ + } +} + +/** + * Try to remove extraneous MOV instructions from the given program. + */ +static void +_mesa_remove_extra_moves(struct gl_program *prog) +{ + GLboolean *removeInst; /* per-instruction removal flag */ + GLuint i, rem, loopNesting = 0, subroutineNesting = 0; + + if (dbg) { + printf("Optimize: Begin remove extra moves\n"); + _mesa_print_program(prog); + } + + removeInst = (GLboolean *) + calloc(1, prog->NumInstructions * sizeof(GLboolean)); + + /* + * Look for sequences such as this: + * FOO tmpX, arg0, arg1; + * MOV tmpY, tmpX; + * and convert into: + * FOO tmpY, arg0, arg1; + */ + + for (i = 0; i < prog->NumInstructions; i++) { + const struct prog_instruction *inst = prog->Instructions + i; + + switch (inst->Opcode) { + case OPCODE_BGNLOOP: + loopNesting++; + break; + case OPCODE_ENDLOOP: + loopNesting--; + break; + case OPCODE_BGNSUB: + subroutineNesting++; + break; + case OPCODE_ENDSUB: + subroutineNesting--; + break; + case OPCODE_MOV: + if (i > 0 && + loopNesting == 0 && + subroutineNesting == 0 && + inst->SrcReg[0].File == PROGRAM_TEMPORARY && + inst->SrcReg[0].Swizzle == SWIZZLE_XYZW) { + /* see if this MOV can be removed */ + const GLuint tempIndex = inst->SrcReg[0].Index; + struct prog_instruction *prevInst; + GLuint prevI; + + /* get pointer to previous instruction */ + prevI = i - 1; + while (prevI > 0 && removeInst[prevI]) + prevI--; + prevInst = prog->Instructions + prevI; + + if (prevInst->DstReg.File == PROGRAM_TEMPORARY && + prevInst->DstReg.Index == tempIndex && + prevInst->DstReg.WriteMask == WRITEMASK_XYZW) { + + enum temp_use next_use = + find_next_temp_use(prog, i + 1, tempIndex); + + if (next_use == WRITE || next_use == END) { + /* OK, we can safely remove this MOV instruction. + * Transform: + * prevI: FOO tempIndex, x, y; + * i: MOV z, tempIndex; + * Into: + * prevI: FOO z, x, y; + */ + + /* patch up prev inst */ + prevInst->DstReg.File = inst->DstReg.File; + prevInst->DstReg.Index = inst->DstReg.Index; + + /* flag this instruction for removal */ + removeInst[i] = GL_TRUE; + + if (dbg) { + printf("Remove MOV at %u\n", i); + printf("new prev inst %u: ", prevI); + _mesa_print_instruction(prevInst); + } + } + } + } + break; + default: + ; /* nothing */ + } + } + + /* now remove the instructions which aren't needed */ + rem = remove_instructions(prog, removeInst); + + free(removeInst); + + if (dbg) { + printf("Optimize: End remove extra moves. %u instructions removed\n", rem); + /*_mesa_print_program(prog);*/ + } +} + + +/** A live register interval */ +struct interval +{ + GLuint Reg; /** The temporary register index */ + GLuint Start, End; /** Start/end instruction numbers */ +}; + + +/** A list of register intervals */ +struct interval_list +{ + GLuint Num; + struct interval Intervals[MAX_PROGRAM_TEMPS]; +}; + + +static void +append_interval(struct interval_list *list, const struct interval *inv) +{ + list->Intervals[list->Num++] = *inv; +} + + +/** Insert interval inv into list, sorted by interval end */ +static void +insert_interval_by_end(struct interval_list *list, const struct interval *inv) +{ + /* XXX we could do a binary search insertion here since list is sorted */ + GLint i = list->Num - 1; + while (i >= 0 && list->Intervals[i].End > inv->End) { + list->Intervals[i + 1] = list->Intervals[i]; + i--; + } + list->Intervals[i + 1] = *inv; + list->Num++; + +#ifdef DEBUG + { + GLuint i; + for (i = 0; i + 1 < list->Num; i++) { + ASSERT(list->Intervals[i].End <= list->Intervals[i + 1].End); + } + } +#endif +} + + +/** Remove the given interval from the interval list */ +static void +remove_interval(struct interval_list *list, const struct interval *inv) +{ + /* XXX we could binary search since list is sorted */ + GLuint k; + for (k = 0; k < list->Num; k++) { + if (list->Intervals[k].Reg == inv->Reg) { + /* found, remove it */ + ASSERT(list->Intervals[k].Start == inv->Start); + ASSERT(list->Intervals[k].End == inv->End); + while (k < list->Num - 1) { + list->Intervals[k] = list->Intervals[k + 1]; + k++; + } + list->Num--; + return; + } + } +} + + +/** called by qsort() */ +static int +compare_start(const void *a, const void *b) +{ + const struct interval *ia = (const struct interval *) a; + const struct interval *ib = (const struct interval *) b; + if (ia->Start < ib->Start) + return -1; + else if (ia->Start > ib->Start) + return +1; + else + return 0; +} + +/** sort the interval list according to interval starts */ +static void +sort_interval_list_by_start(struct interval_list *list) +{ + qsort(list->Intervals, list->Num, sizeof(struct interval), compare_start); +#ifdef DEBUG + { + GLuint i; + for (i = 0; i + 1 < list->Num; i++) { + ASSERT(list->Intervals[i].Start <= list->Intervals[i + 1].Start); + } + } +#endif +} + + +/** + * Update the intermediate interval info for register 'index' and + * instruction 'ic'. + */ +static void +update_interval(GLint intBegin[], GLint intEnd[], GLuint index, GLuint ic) +{ + ASSERT(index < MAX_PROGRAM_TEMPS); + if (intBegin[index] == -1) { + ASSERT(intEnd[index] == -1); + intBegin[index] = intEnd[index] = ic; + } + else { + intEnd[index] = ic; + } +} + + +/** + * Find first/last instruction that references each temporary register. + */ +GLboolean +_mesa_find_temp_intervals(const struct prog_instruction *instructions, + GLuint numInstructions, + GLint intBegin[MAX_PROGRAM_TEMPS], + GLint intEnd[MAX_PROGRAM_TEMPS]) +{ + struct loop_info + { + GLuint Start, End; /**< Start, end instructions of loop */ + }; + struct loop_info loopStack[MAX_LOOP_NESTING]; + GLuint loopStackDepth = 0; + GLuint i; + + for (i = 0; i < MAX_PROGRAM_TEMPS; i++){ + intBegin[i] = intEnd[i] = -1; + } + + /* Scan instructions looking for temporary registers */ + for (i = 0; i < numInstructions; i++) { + const struct prog_instruction *inst = instructions + i; + if (inst->Opcode == OPCODE_BGNLOOP) { + loopStack[loopStackDepth].Start = i; + loopStack[loopStackDepth].End = inst->BranchTarget; + loopStackDepth++; + } + else if (inst->Opcode == OPCODE_ENDLOOP) { + loopStackDepth--; + } + else if (inst->Opcode == OPCODE_CAL) { + return GL_FALSE; + } + else { + const GLuint numSrc = 3;/*_mesa_num_inst_src_regs(inst->Opcode);*/ + GLuint j; + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { + const GLuint index = inst->SrcReg[j].Index; + if (inst->SrcReg[j].RelAddr) + return GL_FALSE; + update_interval(intBegin, intEnd, index, i); + if (loopStackDepth > 0) { + /* extend temp register's interval to end of loop */ + GLuint loopEnd = loopStack[loopStackDepth - 1].End; + update_interval(intBegin, intEnd, index, loopEnd); + } + } + } + if (inst->DstReg.File == PROGRAM_TEMPORARY) { + const GLuint index = inst->DstReg.Index; + if (inst->DstReg.RelAddr) + return GL_FALSE; + update_interval(intBegin, intEnd, index, i); + if (loopStackDepth > 0) { + /* extend temp register's interval to end of loop */ + GLuint loopEnd = loopStack[loopStackDepth - 1].End; + update_interval(intBegin, intEnd, index, loopEnd); + } + } + } + } + + return GL_TRUE; +} + + +/** + * Find the live intervals for each temporary register in the program. + * For register R, the interval [A,B] indicates that R is referenced + * from instruction A through instruction B. + * Special consideration is needed for loops and subroutines. + * \return GL_TRUE if success, GL_FALSE if we cannot proceed for some reason + */ +static GLboolean +find_live_intervals(struct gl_program *prog, + struct interval_list *liveIntervals) +{ + GLint intBegin[MAX_PROGRAM_TEMPS], intEnd[MAX_PROGRAM_TEMPS]; + GLuint i; + + /* + * Note: we'll return GL_FALSE below if we find relative indexing + * into the TEMP register file. We can't handle that yet. + * We also give up on subroutines for now. + */ + + if (dbg) { + printf("Optimize: Begin find intervals\n"); + } + + /* build intermediate arrays */ + if (!_mesa_find_temp_intervals(prog->Instructions, prog->NumInstructions, + intBegin, intEnd)) + return GL_FALSE; + + /* Build live intervals list from intermediate arrays */ + liveIntervals->Num = 0; + for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { + if (intBegin[i] >= 0) { + struct interval inv; + inv.Reg = i; + inv.Start = intBegin[i]; + inv.End = intEnd[i]; + append_interval(liveIntervals, &inv); + } + } + + /* Sort the list according to interval starts */ + sort_interval_list_by_start(liveIntervals); + + if (dbg) { + /* print interval info */ + for (i = 0; i < liveIntervals->Num; i++) { + const struct interval *inv = liveIntervals->Intervals + i; + printf("Reg[%d] live [%d, %d]:", + inv->Reg, inv->Start, inv->End); + if (1) { + GLuint j; + for (j = 0; j < inv->Start; j++) + printf(" "); + for (j = inv->Start; j <= inv->End; j++) + printf("x"); + } + printf("\n"); + } + } + + return GL_TRUE; +} + + +/** Scan the array of used register flags to find free entry */ +static GLint +alloc_register(GLboolean usedRegs[MAX_PROGRAM_TEMPS]) +{ + GLuint k; + for (k = 0; k < MAX_PROGRAM_TEMPS; k++) { + if (!usedRegs[k]) { + usedRegs[k] = GL_TRUE; + return k; + } + } + return -1; +} + + +/** + * This function implements "Linear Scan Register Allocation" to reduce + * the number of temporary registers used by the program. + * + * We compute the "live interval" for all temporary registers then + * examine the overlap of the intervals to allocate new registers. + * Basically, if two intervals do not overlap, they can use the same register. + */ +static void +_mesa_reallocate_registers(struct gl_program *prog) +{ + struct interval_list liveIntervals; + GLint registerMap[MAX_PROGRAM_TEMPS]; + GLboolean usedRegs[MAX_PROGRAM_TEMPS]; + GLuint i; + GLint maxTemp = -1; + + if (dbg) { + printf("Optimize: Begin live-interval register reallocation\n"); + _mesa_print_program(prog); + } + + for (i = 0; i < MAX_PROGRAM_TEMPS; i++){ + registerMap[i] = -1; + usedRegs[i] = GL_FALSE; + } + + if (!find_live_intervals(prog, &liveIntervals)) { + if (dbg) + printf("Aborting register reallocation\n"); + return; + } + + { + struct interval_list activeIntervals; + activeIntervals.Num = 0; + + /* loop over live intervals, allocating a new register for each */ + for (i = 0; i < liveIntervals.Num; i++) { + const struct interval *live = liveIntervals.Intervals + i; + + if (dbg) + printf("Consider register %u\n", live->Reg); + + /* Expire old intervals. Intervals which have ended with respect + * to the live interval can have their remapped registers freed. + */ + { + GLint j; + for (j = 0; j < (GLint) activeIntervals.Num; j++) { + const struct interval *inv = activeIntervals.Intervals + j; + if (inv->End >= live->Start) { + /* Stop now. Since the activeInterval list is sorted + * we know we don't have to go further. + */ + break; + } + else { + /* Interval 'inv' has expired */ + const GLint regNew = registerMap[inv->Reg]; + ASSERT(regNew >= 0); + + if (dbg) + printf(" expire interval for reg %u\n", inv->Reg); + + /* remove interval j from active list */ + remove_interval(&activeIntervals, inv); + j--; /* counter-act j++ in for-loop above */ + + /* return register regNew to the free pool */ + if (dbg) + printf(" free reg %d\n", regNew); + ASSERT(usedRegs[regNew] == GL_TRUE); + usedRegs[regNew] = GL_FALSE; + } + } + } + + /* find a free register for this live interval */ + { + const GLint k = alloc_register(usedRegs); + if (k < 0) { + /* out of registers, give up */ + return; + } + registerMap[live->Reg] = k; + maxTemp = MAX2(maxTemp, k); + if (dbg) + printf(" remap register %u -> %d\n", live->Reg, k); + } + + /* Insert this live interval into the active list which is sorted + * by increasing end points. + */ + insert_interval_by_end(&activeIntervals, live); + } + } + + if (maxTemp + 1 < (GLint) liveIntervals.Num) { + /* OK, we've reduced the number of registers needed. + * Scan the program and replace all the old temporary register + * indexes with the new indexes. + */ + replace_regs(prog, PROGRAM_TEMPORARY, registerMap); + + prog->NumTemporaries = maxTemp + 1; + } + + if (dbg) { + printf("Optimize: End live-interval register reallocation\n"); + printf("Num temp regs before: %u after: %u\n", + liveIntervals.Num, maxTemp + 1); + _mesa_print_program(prog); + } +} + + +/** + * Apply optimizations to the given program to eliminate unnecessary + * instructions, temp regs, etc. + */ +void +_mesa_optimize_program(GLcontext *ctx, struct gl_program *program) +{ + _mesa_remove_extra_move_use(program); + + if (1) + _mesa_remove_dead_code(program); + + if (0) /* not tested much yet */ + _mesa_remove_extra_moves(program); + + if (0) + _mesa_consolidate_registers(program); + else + _mesa_reallocate_registers(program); +} diff --git a/src/mesa/program/prog_optimize.h b/src/mesa/program/prog_optimize.h new file mode 100644 index 0000000000..43894a2723 --- /dev/null +++ b/src/mesa/program/prog_optimize.h @@ -0,0 +1,45 @@ +/* + * Mesa 3-D graphics library + * Version: 7.5 + * + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VMWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef PROG_OPT_H +#define PROG_OPT_H + + +#include "main/config.h" + + +struct gl_program; +struct prog_instruction; + + +extern GLboolean +_mesa_find_temp_intervals(const struct prog_instruction *instructions, + GLuint numInstructions, + GLint intBegin[MAX_PROGRAM_TEMPS], + GLint intEnd[MAX_PROGRAM_TEMPS]); + +extern void +_mesa_optimize_program(GLcontext *ctx, struct gl_program *program); + +#endif diff --git a/src/mesa/program/prog_parameter.c b/src/mesa/program/prog_parameter.c new file mode 100644 index 0000000000..aac488c79a --- /dev/null +++ b/src/mesa/program/prog_parameter.c @@ -0,0 +1,751 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file prog_parameter.c + * Program parameter lists and functions. + * \author Brian Paul + */ + + +#include "main/glheader.h" +#include "main/imports.h" +#include "main/macros.h" +#include "prog_instruction.h" +#include "prog_parameter.h" +#include "prog_statevars.h" + + +struct gl_program_parameter_list * +_mesa_new_parameter_list(void) +{ + return CALLOC_STRUCT(gl_program_parameter_list); +} + + +struct gl_program_parameter_list * +_mesa_new_parameter_list_sized(unsigned size) +{ + struct gl_program_parameter_list *p = _mesa_new_parameter_list(); + + if ((p != NULL) && (size != 0)) { + p->Size = size; + + /* alloc arrays */ + p->Parameters = (struct gl_program_parameter *) + calloc(1, size * sizeof(struct gl_program_parameter)); + + p->ParameterValues = (GLfloat (*)[4]) + _mesa_align_malloc(size * 4 *sizeof(GLfloat), 16); + + + if ((p->Parameters == NULL) || (p->ParameterValues == NULL)) { + free(p->Parameters); + _mesa_align_free(p->ParameterValues); + free(p); + p = NULL; + } + } + + return p; +} + + +/** + * Free a parameter list and all its parameters + */ +void +_mesa_free_parameter_list(struct gl_program_parameter_list *paramList) +{ + GLuint i; + for (i = 0; i < paramList->NumParameters; i++) { + if (paramList->Parameters[i].Name) + free((void *) paramList->Parameters[i].Name); + } + free(paramList->Parameters); + if (paramList->ParameterValues) + _mesa_align_free(paramList->ParameterValues); + free(paramList); +} + + +/** + * Add a new parameter to a parameter list. + * Note that parameter values are usually 4-element GLfloat vectors. + * When size > 4 we'll allocate a sequential block of parameters to + * store all the values (in blocks of 4). + * + * \param paramList the list to add the parameter to + * \param type type of parameter, such as + * \param name the parameter name, will be duplicated/copied! + * \param size number of elements in 'values' vector (1..4, or more) + * \param datatype GL_FLOAT, GL_FLOAT_VECx, GL_INT, GL_INT_VECx or GL_NONE. + * \param values initial parameter value, up to 4 GLfloats, or NULL + * \param state state indexes, or NULL + * \return index of new parameter in the list, or -1 if error (out of mem) + */ +GLint +_mesa_add_parameter(struct gl_program_parameter_list *paramList, + gl_register_file type, const char *name, + GLuint size, GLenum datatype, const GLfloat *values, + const gl_state_index state[STATE_LENGTH], + GLbitfield flags) +{ + const GLuint oldNum = paramList->NumParameters; + const GLuint sz4 = (size + 3) / 4; /* no. of new param slots needed */ + + assert(size > 0); + + if (oldNum + sz4 > paramList->Size) { + /* Need to grow the parameter list array (alloc some extra) */ + paramList->Size = paramList->Size + 4 * sz4; + + /* realloc arrays */ + paramList->Parameters = (struct gl_program_parameter *) + _mesa_realloc(paramList->Parameters, + oldNum * sizeof(struct gl_program_parameter), + paramList->Size * sizeof(struct gl_program_parameter)); + + paramList->ParameterValues = (GLfloat (*)[4]) + _mesa_align_realloc(paramList->ParameterValues, /* old buf */ + oldNum * 4 * sizeof(GLfloat), /* old size */ + paramList->Size * 4 *sizeof(GLfloat), /* new sz */ + 16); + } + + if (!paramList->Parameters || + !paramList->ParameterValues) { + /* out of memory */ + paramList->NumParameters = 0; + paramList->Size = 0; + return -1; + } + else { + GLuint i; + + paramList->NumParameters = oldNum + sz4; + + memset(¶mList->Parameters[oldNum], 0, + sz4 * sizeof(struct gl_program_parameter)); + + for (i = 0; i < sz4; i++) { + struct gl_program_parameter *p = paramList->Parameters + oldNum + i; + p->Name = name ? _mesa_strdup(name) : NULL; + p->Type = type; + p->Size = size; + p->DataType = datatype; + p->Flags = flags; + if (values) { + COPY_4V(paramList->ParameterValues[oldNum + i], values); + values += 4; + p->Initialized = GL_TRUE; + } + else { + /* silence valgrind */ + ASSIGN_4V(paramList->ParameterValues[oldNum + i], 0, 0, 0, 0); + } + size -= 4; + } + + if (state) { + for (i = 0; i < STATE_LENGTH; i++) + paramList->Parameters[oldNum].StateIndexes[i] = state[i]; + } + + return (GLint) oldNum; + } +} + + +/** + * Add a new named program parameter (Ex: NV_fragment_program DEFINE statement) + * \return index of the new entry in the parameter list + */ +GLint +_mesa_add_named_parameter(struct gl_program_parameter_list *paramList, + const char *name, const GLfloat values[4]) +{ + return _mesa_add_parameter(paramList, PROGRAM_NAMED_PARAM, name, + 4, GL_NONE, values, NULL, 0x0); + +} + + +/** + * Add a new named constant to the parameter list. + * This will be used when the program contains something like this: + * PARAM myVals = { 0, 1, 2, 3 }; + * + * \param paramList the parameter list + * \param name the name for the constant + * \param values four float values + * \return index/position of the new parameter in the parameter list + */ +GLint +_mesa_add_named_constant(struct gl_program_parameter_list *paramList, + const char *name, const GLfloat values[4], + GLuint size) +{ + /* first check if this is a duplicate constant */ + GLint pos; + for (pos = 0; pos < (GLint)paramList->NumParameters; pos++) { + const GLfloat *pvals = paramList->ParameterValues[pos]; + if (pvals[0] == values[0] && + pvals[1] == values[1] && + pvals[2] == values[2] && + pvals[3] == values[3] && + strcmp(paramList->Parameters[pos].Name, name) == 0) { + /* Same name and value is already in the param list - reuse it */ + return pos; + } + } + /* not found, add new parameter */ + return _mesa_add_parameter(paramList, PROGRAM_CONSTANT, name, + size, GL_NONE, values, NULL, 0x0); +} + + +/** + * Add a new unnamed constant to the parameter list. This will be used + * when a fragment/vertex program contains something like this: + * MOV r, { 0, 1, 2, 3 }; + * If swizzleOut is non-null we'll search the parameter list for an + * existing instance of the constant which matches with a swizzle. + * + * \param paramList the parameter list + * \param values four float values + * \param swizzleOut returns swizzle mask for accessing the constant + * \return index/position of the new parameter in the parameter list. + */ +GLint +_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList, + const GLfloat values[4], GLuint size, + GLuint *swizzleOut) +{ + GLint pos; + ASSERT(size >= 1); + ASSERT(size <= 4); + + if (swizzleOut && + _mesa_lookup_parameter_constant(paramList, values, + size, &pos, swizzleOut)) { + return pos; + } + + /* Look for empty space in an already unnamed constant parameter + * to add this constant. This will only work for single-element + * constants because we rely on smearing (i.e. .yyyy or .zzzz). + */ + if (size == 1 && swizzleOut) { + for (pos = 0; pos < (GLint) paramList->NumParameters; pos++) { + struct gl_program_parameter *p = paramList->Parameters + pos; + if (p->Type == PROGRAM_CONSTANT && p->Size + size <= 4) { + /* ok, found room */ + GLfloat *pVal = paramList->ParameterValues[pos]; + GLuint swz = p->Size; /* 1, 2 or 3 for Y, Z, W */ + pVal[p->Size] = values[0]; + p->Size++; + *swizzleOut = MAKE_SWIZZLE4(swz, swz, swz, swz); + return pos; + } + } + } + + /* add a new parameter to store this constant */ + pos = _mesa_add_parameter(paramList, PROGRAM_CONSTANT, NULL, + size, GL_NONE, values, NULL, 0x0); + if (pos >= 0 && swizzleOut) { + if (size == 1) + *swizzleOut = SWIZZLE_XXXX; + else + *swizzleOut = SWIZZLE_NOOP; + } + return pos; +} + + +/** + * Add a uniform to the parameter list. + * Note that if the uniform is an array, size may be greater than + * what's implied by the datatype. + * \param name uniform's name + * \param size number of floats to allocate + * \param datatype GL_FLOAT_VEC3, GL_FLOAT_MAT4, etc. + */ +GLint +_mesa_add_uniform(struct gl_program_parameter_list *paramList, + const char *name, GLuint size, GLenum datatype, + const GLfloat *values) +{ + GLint i = _mesa_lookup_parameter_index(paramList, -1, name); + ASSERT(datatype != GL_NONE); + if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_UNIFORM) { + ASSERT(paramList->Parameters[i].Size == size); + ASSERT(paramList->Parameters[i].DataType == datatype); + /* already in list */ + return i; + } + else { + i = _mesa_add_parameter(paramList, PROGRAM_UNIFORM, name, + size, datatype, values, NULL, 0x0); + return i; + } +} + + +/** + * Mark the named uniform as 'used'. + */ +void +_mesa_use_uniform(struct gl_program_parameter_list *paramList, + const char *name) +{ + GLuint i; + for (i = 0; i < paramList->NumParameters; i++) { + struct gl_program_parameter *p = paramList->Parameters + i; + if ((p->Type == PROGRAM_UNIFORM || p->Type == PROGRAM_SAMPLER) && + strcmp(p->Name, name) == 0) { + p->Used = GL_TRUE; + /* Note that large uniforms may occupy several slots so we're + * not done searching yet. + */ + } + } +} + + +/** + * Add a sampler to the parameter list. + * \param name uniform's name + * \param datatype GL_SAMPLER_2D, GL_SAMPLER_2D_RECT_ARB, etc. + * \param index the sampler number (as seen in TEX instructions) + * \return sampler index (starting at zero) or -1 if error + */ +GLint +_mesa_add_sampler(struct gl_program_parameter_list *paramList, + const char *name, GLenum datatype) +{ + GLint i = _mesa_lookup_parameter_index(paramList, -1, name); + if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_SAMPLER) { + ASSERT(paramList->Parameters[i].Size == 1); + ASSERT(paramList->Parameters[i].DataType == datatype); + /* already in list */ + return (GLint) paramList->ParameterValues[i][0]; + } + else { + GLuint i; + const GLint size = 1; /* a sampler is basically a texture unit number */ + GLfloat value[4]; + GLint numSamplers = 0; + for (i = 0; i < paramList->NumParameters; i++) { + if (paramList->Parameters[i].Type == PROGRAM_SAMPLER) + numSamplers++; + } + value[0] = (GLfloat) numSamplers; + value[1] = value[2] = value[3] = 0.0F; + (void) _mesa_add_parameter(paramList, PROGRAM_SAMPLER, name, + size, datatype, value, NULL, 0x0); + return numSamplers; + } +} + + +/** + * Add parameter representing a varying variable. + */ +GLint +_mesa_add_varying(struct gl_program_parameter_list *paramList, + const char *name, GLuint size, GLenum datatype, + GLbitfield flags) +{ + GLint i = _mesa_lookup_parameter_index(paramList, -1, name); + if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_VARYING) { + /* already in list */ + return i; + } + else { + /*assert(size == 4);*/ + i = _mesa_add_parameter(paramList, PROGRAM_VARYING, name, + size, datatype, NULL, NULL, flags); + return i; + } +} + + +/** + * Add parameter representing a vertex program attribute. + * \param size size of attribute (in floats), may be -1 if unknown + * \param attrib the attribute index, or -1 if unknown + */ +GLint +_mesa_add_attribute(struct gl_program_parameter_list *paramList, + const char *name, GLint size, GLenum datatype, GLint attrib) +{ + GLint i = _mesa_lookup_parameter_index(paramList, -1, name); + if (i >= 0) { + /* replace */ + if (attrib < 0) + attrib = i; + paramList->Parameters[i].StateIndexes[0] = attrib; + } + else { + /* add */ + gl_state_index state[STATE_LENGTH]; + state[0] = (gl_state_index) attrib; + if (size < 0) + size = 4; + i = _mesa_add_parameter(paramList, PROGRAM_INPUT, name, + size, datatype, NULL, state, 0x0); + } + return i; +} + + + +#if 0 /* not used yet */ +/** + * Returns the number of 4-component registers needed to store a piece + * of GL state. For matrices this may be as many as 4 registers, + * everything else needs + * just 1 register. + */ +static GLuint +sizeof_state_reference(const GLint *stateTokens) +{ + if (stateTokens[0] == STATE_MATRIX) { + GLuint rows = stateTokens[4] - stateTokens[3] + 1; + assert(rows >= 1); + assert(rows <= 4); + return rows; + } + else { + return 1; + } +} +#endif + + +/** + * Add a new state reference to the parameter list. + * This will be used when the program contains something like this: + * PARAM ambient = state.material.front.ambient; + * + * \param paramList the parameter list + * \param stateTokens an array of 5 (STATE_LENGTH) state tokens + * \return index of the new parameter. + */ +GLint +_mesa_add_state_reference(struct gl_program_parameter_list *paramList, + const gl_state_index stateTokens[STATE_LENGTH]) +{ + const GLuint size = 4; /* XXX fix */ + char *name; + GLint index; + + /* Check if the state reference is already in the list */ + for (index = 0; index < (GLint) paramList->NumParameters; index++) { + GLuint i, match = 0; + for (i = 0; i < STATE_LENGTH; i++) { + if (paramList->Parameters[index].StateIndexes[i] == stateTokens[i]) { + match++; + } + else { + break; + } + } + if (match == STATE_LENGTH) { + /* this state reference is already in the parameter list */ + return index; + } + } + + name = _mesa_program_state_string(stateTokens); + index = _mesa_add_parameter(paramList, PROGRAM_STATE_VAR, name, + size, GL_NONE, + NULL, (gl_state_index *) stateTokens, 0x0); + paramList->StateFlags |= _mesa_program_state_flags(stateTokens); + + /* free name string here since we duplicated it in add_parameter() */ + free(name); + + return index; +} + + +/** + * Lookup a parameter value by name in the given parameter list. + * \return pointer to the float[4] values. + */ +GLfloat * +_mesa_lookup_parameter_value(const struct gl_program_parameter_list *paramList, + GLsizei nameLen, const char *name) +{ + GLint i = _mesa_lookup_parameter_index(paramList, nameLen, name); + if (i < 0) + return NULL; + else + return paramList->ParameterValues[i]; +} + + +/** + * Given a program parameter name, find its position in the list of parameters. + * \param paramList the parameter list to search + * \param nameLen length of name (in chars). + * If length is negative, assume that name is null-terminated. + * \param name the name to search for + * \return index of parameter in the list. + */ +GLint +_mesa_lookup_parameter_index(const struct gl_program_parameter_list *paramList, + GLsizei nameLen, const char *name) +{ + GLint i; + + if (!paramList) + return -1; + + if (nameLen == -1) { + /* name is null-terminated */ + for (i = 0; i < (GLint) paramList->NumParameters; i++) { + if (paramList->Parameters[i].Name && + strcmp(paramList->Parameters[i].Name, name) == 0) + return i; + } + } + else { + /* name is not null-terminated, use nameLen */ + for (i = 0; i < (GLint) paramList->NumParameters; i++) { + if (paramList->Parameters[i].Name && + strncmp(paramList->Parameters[i].Name, name, nameLen) == 0 + && strlen(paramList->Parameters[i].Name) == (size_t)nameLen) + return i; + } + } + return -1; +} + + +/** + * Look for a float vector in the given parameter list. The float vector + * may be of length 1, 2, 3 or 4. If swizzleOut is non-null, we'll try + * swizzling to find a match. + * \param list the parameter list to search + * \param v the float vector to search for + * \param vSize number of element in v + * \param posOut returns the position of the constant, if found + * \param swizzleOut returns a swizzle mask describing location of the + * vector elements if found. + * \return GL_TRUE if found, GL_FALSE if not found + */ +GLboolean +_mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list, + const GLfloat v[], GLuint vSize, + GLint *posOut, GLuint *swizzleOut) +{ + GLuint i; + + assert(vSize >= 1); + assert(vSize <= 4); + + if (!list) + return -1; + + for (i = 0; i < list->NumParameters; i++) { + if (list->Parameters[i].Type == PROGRAM_CONSTANT) { + if (!swizzleOut) { + /* swizzle not allowed */ + GLuint j, match = 0; + for (j = 0; j < vSize; j++) { + if (v[j] == list->ParameterValues[i][j]) + match++; + } + if (match == vSize) { + *posOut = i; + return GL_TRUE; + } + } + else { + /* try matching w/ swizzle */ + if (vSize == 1) { + /* look for v[0] anywhere within float[4] value */ + GLuint j; + for (j = 0; j < 4; j++) { + if (list->ParameterValues[i][j] == v[0]) { + /* found it */ + *posOut = i; + *swizzleOut = MAKE_SWIZZLE4(j, j, j, j); + return GL_TRUE; + } + } + } + else if (vSize <= list->Parameters[i].Size) { + /* see if we can match this constant (with a swizzle) */ + GLuint swz[4]; + GLuint match = 0, j, k; + for (j = 0; j < vSize; j++) { + if (v[j] == list->ParameterValues[i][j]) { + swz[j] = j; + match++; + } + else { + for (k = 0; k < list->Parameters[i].Size; k++) { + if (v[j] == list->ParameterValues[i][k]) { + swz[j] = k; + match++; + break; + } + } + } + } + /* smear last value to remaining positions */ + for (; j < 4; j++) + swz[j] = swz[j-1]; + + if (match == vSize) { + *posOut = i; + *swizzleOut = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]); + return GL_TRUE; + } + } + } + } + } + + *posOut = -1; + return GL_FALSE; +} + + +struct gl_program_parameter_list * +_mesa_clone_parameter_list(const struct gl_program_parameter_list *list) +{ + struct gl_program_parameter_list *clone; + GLuint i; + + clone = _mesa_new_parameter_list(); + if (!clone) + return NULL; + + /** Not too efficient, but correct */ + for (i = 0; i < list->NumParameters; i++) { + struct gl_program_parameter *p = list->Parameters + i; + struct gl_program_parameter *pCopy; + GLuint size = MIN2(p->Size, 4); + GLint j = _mesa_add_parameter(clone, p->Type, p->Name, size, p->DataType, + list->ParameterValues[i], NULL, 0x0); + ASSERT(j >= 0); + pCopy = clone->Parameters + j; + pCopy->Used = p->Used; + pCopy->Flags = p->Flags; + /* copy state indexes */ + if (p->Type == PROGRAM_STATE_VAR) { + GLint k; + for (k = 0; k < STATE_LENGTH; k++) { + pCopy->StateIndexes[k] = p->StateIndexes[k]; + } + } + else { + clone->Parameters[j].Size = p->Size; + } + + } + + clone->StateFlags = list->StateFlags; + + return clone; +} + + +/** + * Return a new parameter list which is listA + listB. + */ +struct gl_program_parameter_list * +_mesa_combine_parameter_lists(const struct gl_program_parameter_list *listA, + const struct gl_program_parameter_list *listB) +{ + struct gl_program_parameter_list *list; + + if (listA) { + list = _mesa_clone_parameter_list(listA); + if (list && listB) { + GLuint i; + for (i = 0; i < listB->NumParameters; i++) { + struct gl_program_parameter *param = listB->Parameters + i; + _mesa_add_parameter(list, param->Type, param->Name, param->Size, + param->DataType, + listB->ParameterValues[i], + param->StateIndexes, + param->Flags); + } + } + } + else if (listB) { + list = _mesa_clone_parameter_list(listB); + } + else { + list = NULL; + } + return list; +} + + + +/** + * Find longest name of all uniform parameters in list. + */ +GLuint +_mesa_longest_parameter_name(const struct gl_program_parameter_list *list, + gl_register_file type) +{ + GLuint i, maxLen = 0; + if (!list) + return 0; + for (i = 0; i < list->NumParameters; i++) { + if (list->Parameters[i].Type == type) { + GLuint len = strlen(list->Parameters[i].Name); + if (len > maxLen) + maxLen = len; + } + } + return maxLen; +} + + +/** + * Count the number of parameters in the last that match the given type. + */ +GLuint +_mesa_num_parameters_of_type(const struct gl_program_parameter_list *list, + gl_register_file type) +{ + GLuint i, count = 0; + if (list) { + for (i = 0; i < list->NumParameters; i++) { + if (list->Parameters[i].Type == type) + count++; + } + } + return count; +} diff --git a/src/mesa/program/prog_parameter.h b/src/mesa/program/prog_parameter.h new file mode 100644 index 0000000000..cc3378ae20 --- /dev/null +++ b/src/mesa/program/prog_parameter.h @@ -0,0 +1,182 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file prog_parameter.c + * Program parameter lists and functions. + * \author Brian Paul + */ + +#ifndef PROG_PARAMETER_H +#define PROG_PARAMETER_H + +#include "main/mtypes.h" +#include "prog_statevars.h" + + +/** + * Program parameter flags + */ +/*@{*/ +#define PROG_PARAM_BIT_CENTROID 0x1 /**< for varying vars (GLSL 1.20) */ +#define PROG_PARAM_BIT_INVARIANT 0x2 /**< for varying vars (GLSL 1.20) */ +#define PROG_PARAM_BIT_FLAT 0x4 /**< for varying vars (GLSL 1.30) */ +#define PROG_PARAM_BIT_LINEAR 0x8 /**< for varying vars (GLSL 1.30) */ +#define PROG_PARAM_BIT_CYL_WRAP 0x10 /**< XXX gallium debug */ +/*@}*/ + + + +/** + * Program parameter. + * Used by shaders/programs for uniforms, constants, varying vars, etc. + */ +struct gl_program_parameter +{ + const char *Name; /**< Null-terminated string */ + gl_register_file Type; /**< PROGRAM_NAMED_PARAM, CONSTANT or STATE_VAR */ + GLenum DataType; /**< GL_FLOAT, GL_FLOAT_VEC2, etc */ + /** + * Number of components (1..4), or more. + * If the number of components is greater than 4, + * this parameter is part of a larger uniform like a GLSL matrix or array. + * The next program parameter's Size will be Size-4 of this parameter. + */ + GLuint Size; + GLboolean Used; /**< Helper flag for GLSL uniform tracking */ + GLboolean Initialized; /**< Has the ParameterValue[] been set? */ + GLbitfield Flags; /**< Bitmask of PROG_PARAM_*_BIT */ + /** + * A sequence of STATE_* tokens and integers to identify GL state. + */ + gl_state_index StateIndexes[STATE_LENGTH]; +}; + + +/** + * List of gl_program_parameter instances. + */ +struct gl_program_parameter_list +{ + GLuint Size; /**< allocated size of Parameters, ParameterValues */ + GLuint NumParameters; /**< number of parameters in arrays */ + struct gl_program_parameter *Parameters; /**< Array [Size] */ + GLfloat (*ParameterValues)[4]; /**< Array [Size] of GLfloat[4] */ + GLbitfield StateFlags; /**< _NEW_* flags indicating which state changes + might invalidate ParameterValues[] */ +}; + + +extern struct gl_program_parameter_list * +_mesa_new_parameter_list(void); + +extern struct gl_program_parameter_list * +_mesa_new_parameter_list_sized(unsigned size); + +extern void +_mesa_free_parameter_list(struct gl_program_parameter_list *paramList); + +extern struct gl_program_parameter_list * +_mesa_clone_parameter_list(const struct gl_program_parameter_list *list); + +extern struct gl_program_parameter_list * +_mesa_combine_parameter_lists(const struct gl_program_parameter_list *a, + const struct gl_program_parameter_list *b); + +static INLINE GLuint +_mesa_num_parameters(const struct gl_program_parameter_list *list) +{ + return list ? list->NumParameters : 0; +} + +extern GLint +_mesa_add_parameter(struct gl_program_parameter_list *paramList, + gl_register_file type, const char *name, + GLuint size, GLenum datatype, const GLfloat *values, + const gl_state_index state[STATE_LENGTH], + GLbitfield flags); + +extern GLint +_mesa_add_named_parameter(struct gl_program_parameter_list *paramList, + const char *name, const GLfloat values[4]); + +extern GLint +_mesa_add_named_constant(struct gl_program_parameter_list *paramList, + const char *name, const GLfloat values[4], + GLuint size); + +extern GLint +_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList, + const GLfloat values[4], GLuint size, + GLuint *swizzleOut); + +extern GLint +_mesa_add_uniform(struct gl_program_parameter_list *paramList, + const char *name, GLuint size, GLenum datatype, + const GLfloat *values); + +extern void +_mesa_use_uniform(struct gl_program_parameter_list *paramList, + const char *name); + +extern GLint +_mesa_add_sampler(struct gl_program_parameter_list *paramList, + const char *name, GLenum datatype); + +extern GLint +_mesa_add_varying(struct gl_program_parameter_list *paramList, + const char *name, GLuint size, GLenum datatype, + GLbitfield flags); + +extern GLint +_mesa_add_attribute(struct gl_program_parameter_list *paramList, + const char *name, GLint size, GLenum datatype, GLint attrib); + +extern GLint +_mesa_add_state_reference(struct gl_program_parameter_list *paramList, + const gl_state_index stateTokens[STATE_LENGTH]); + +extern GLfloat * +_mesa_lookup_parameter_value(const struct gl_program_parameter_list *paramList, + GLsizei nameLen, const char *name); + +extern GLint +_mesa_lookup_parameter_index(const struct gl_program_parameter_list *paramList, + GLsizei nameLen, const char *name); + +extern GLboolean +_mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list, + const GLfloat v[], GLuint vSize, + GLint *posOut, GLuint *swizzleOut); + +extern GLuint +_mesa_longest_parameter_name(const struct gl_program_parameter_list *list, + gl_register_file type); + +extern GLuint +_mesa_num_parameters_of_type(const struct gl_program_parameter_list *list, + gl_register_file type); + + +#endif /* PROG_PARAMETER_H */ diff --git a/src/mesa/program/prog_parameter_layout.c b/src/mesa/program/prog_parameter_layout.c new file mode 100644 index 0000000000..a888573832 --- /dev/null +++ b/src/mesa/program/prog_parameter_layout.c @@ -0,0 +1,213 @@ +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file prog_parameter_layout.c + * \brief Helper functions to layout storage for program parameters + * + * \author Ian Romanick + */ + +#include "main/mtypes.h" +#include "prog_parameter.h" +#include "prog_parameter_layout.h" +#include "prog_instruction.h" +#include "program_parser.h" + +unsigned +_mesa_combine_swizzles(unsigned base, unsigned applied) +{ + unsigned swiz = 0; + unsigned i; + + for (i = 0; i < 4; i++) { + const unsigned s = GET_SWZ(applied, i); + + swiz |= ((s <= SWIZZLE_W) ? GET_SWZ(base, s) : s) << (i * 3); + } + + return swiz; +} + + +/** + * Copy indirect access array from one parameter list to another + * + * \param src Parameter array copied from + * \param dst Parameter array copied to + * \param first Index of first element in \c src to copy + * \param count Number of elements to copy + * + * \return + * The location in \c dst of the first element copied from \c src on + * success. -1 on failure. + * + * \warning + * This function assumes that there is already enough space available in + * \c dst to hold all of the elements that will be copied over. + */ +static int +copy_indirect_accessed_array(struct gl_program_parameter_list *src, + struct gl_program_parameter_list *dst, + unsigned first, unsigned count) +{ + const int base = dst->NumParameters; + unsigned i, j; + + for (i = first; i < (first + count); i++) { + struct gl_program_parameter *curr = & src->Parameters[i]; + + if (curr->Type == PROGRAM_CONSTANT) { + j = dst->NumParameters; + } else { + for (j = 0; j < dst->NumParameters; j++) { + if (memcmp(dst->Parameters[j].StateIndexes, curr->StateIndexes, + sizeof(curr->StateIndexes)) == 0) { + return -1; + } + } + } + + assert(j == dst->NumParameters); + + /* copy src parameter [i] to dest parameter [j] */ + memcpy(& dst->Parameters[j], curr, + sizeof(dst->Parameters[j])); + memcpy(dst->ParameterValues[j], src->ParameterValues[i], + sizeof(GLfloat) * 4); + + /* Pointer to the string name was copied. Null-out src param name + * to prevent double free later. + */ + curr->Name = NULL; + + dst->NumParameters++; + } + + return base; +} + + +/** + * XXX description??? + * \return GL_TRUE for success, GL_FALSE for failure + */ +GLboolean +_mesa_layout_parameters(struct asm_parser_state *state) +{ + struct gl_program_parameter_list *layout; + struct asm_instruction *inst; + unsigned i; + + layout = + _mesa_new_parameter_list_sized(state->prog->Parameters->NumParameters); + + /* PASS 1: Move any parameters that are accessed indirectly from the + * original parameter list to the new parameter list. + */ + for (inst = state->inst_head; inst != NULL; inst = inst->next) { + for (i = 0; i < 3; i++) { + if (inst->SrcReg[i].Base.RelAddr) { + /* Only attempt to add the to the new parameter list once. + */ + if (!inst->SrcReg[i].Symbol->pass1_done) { + const int new_begin = + copy_indirect_accessed_array(state->prog->Parameters, layout, + inst->SrcReg[i].Symbol->param_binding_begin, + inst->SrcReg[i].Symbol->param_binding_length); + + if (new_begin < 0) { + return GL_FALSE; + } + + inst->SrcReg[i].Symbol->param_binding_begin = new_begin; + inst->SrcReg[i].Symbol->pass1_done = 1; + } + + /* Previously the Index was just the offset from the parameter + * array. Now that the base of the parameter array is known, the + * index can be updated to its actual value. + */ + inst->Base.SrcReg[i] = inst->SrcReg[i].Base; + inst->Base.SrcReg[i].Index += + inst->SrcReg[i].Symbol->param_binding_begin; + } + } + } + + /* PASS 2: Move any parameters that are not accessed indirectly from the + * original parameter list to the new parameter list. + */ + for (inst = state->inst_head; inst != NULL; inst = inst->next) { + for (i = 0; i < 3; i++) { + const struct gl_program_parameter *p; + const int idx = inst->SrcReg[i].Base.Index; + unsigned swizzle = SWIZZLE_NOOP; + + /* All relative addressed operands were processed on the first + * pass. Just skip them here. + */ + if (inst->SrcReg[i].Base.RelAddr) { + continue; + } + + if ((inst->SrcReg[i].Base.File <= PROGRAM_VARYING ) + || (inst->SrcReg[i].Base.File >= PROGRAM_WRITE_ONLY)) { + continue; + } + + inst->Base.SrcReg[i] = inst->SrcReg[i].Base; + p = & state->prog->Parameters->Parameters[idx]; + + switch (p->Type) { + case PROGRAM_CONSTANT: { + const float *const v = + state->prog->Parameters->ParameterValues[idx]; + + inst->Base.SrcReg[i].Index = + _mesa_add_unnamed_constant(layout, v, p->Size, & swizzle); + + inst->Base.SrcReg[i].Swizzle = + _mesa_combine_swizzles(swizzle, inst->Base.SrcReg[i].Swizzle); + break; + } + + case PROGRAM_STATE_VAR: + inst->Base.SrcReg[i].Index = + _mesa_add_state_reference(layout, p->StateIndexes); + break; + + default: + break; + } + + inst->SrcReg[i].Base.File = p->Type; + inst->Base.SrcReg[i].File = p->Type; + } + } + + _mesa_free_parameter_list(state->prog->Parameters); + state->prog->Parameters = layout; + + return GL_TRUE; +} diff --git a/src/mesa/program/prog_parameter_layout.h b/src/mesa/program/prog_parameter_layout.h new file mode 100644 index 0000000000..99a7b6c726 --- /dev/null +++ b/src/mesa/program/prog_parameter_layout.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file prog_parameter_layout.h + * \brief Helper functions to layout storage for program parameters + * + * \author Ian Romanick + */ + +#pragma once + +#ifndef PROG_PARAMETER_LAYOUT_H +#define PROG_PARAMETER_LAYOUT_H + +extern unsigned _mesa_combine_swizzles(unsigned base, unsigned applied); + +struct asm_parser_state; + +extern GLboolean _mesa_layout_parameters(struct asm_parser_state *state); + +#endif /* PROG_PARAMETER_LAYOUT_H */ diff --git a/src/mesa/program/prog_print.c b/src/mesa/program/prog_print.c new file mode 100644 index 0000000000..05aae83f0c --- /dev/null +++ b/src/mesa/program/prog_print.c @@ -0,0 +1,1065 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file prog_print.c + * Print vertex/fragment programs - for debugging. + * \author Brian Paul + */ + +#include "main/glheader.h" +#include "main/context.h" +#include "main/imports.h" +#include "prog_instruction.h" +#include "prog_parameter.h" +#include "prog_print.h" +#include "prog_statevars.h" + + + +/** + * Return string name for given program/register file. + */ +static const char * +file_string(gl_register_file f, gl_prog_print_mode mode) +{ + switch (f) { + case PROGRAM_TEMPORARY: + return "TEMP"; + case PROGRAM_LOCAL_PARAM: + return "LOCAL"; + case PROGRAM_ENV_PARAM: + return "ENV"; + case PROGRAM_STATE_VAR: + return "STATE"; + case PROGRAM_INPUT: + return "INPUT"; + case PROGRAM_OUTPUT: + return "OUTPUT"; + case PROGRAM_NAMED_PARAM: + return "NAMED"; + case PROGRAM_CONSTANT: + return "CONST"; + case PROGRAM_UNIFORM: + return "UNIFORM"; + case PROGRAM_VARYING: + return "VARYING"; + case PROGRAM_WRITE_ONLY: + return "WRITE_ONLY"; + case PROGRAM_ADDRESS: + return "ADDR"; + case PROGRAM_SAMPLER: + return "SAMPLER"; + case PROGRAM_UNDEFINED: + return "UNDEFINED"; + default: + { + static char s[20]; + _mesa_snprintf(s, sizeof(s), "FILE%u", f); + return s; + } + } +} + + +/** + * Return ARB_v/f_prog-style input attrib string. + */ +static const char * +arb_input_attrib_string(GLint index, GLenum progType) +{ + /* + * These strings should match the VERT_ATTRIB_x and FRAG_ATTRIB_x tokens. + */ + const char *vertAttribs[] = { + "vertex.position", + "vertex.weight", + "vertex.normal", + "vertex.color.primary", + "vertex.color.secondary", + "vertex.fogcoord", + "vertex.(six)", + "vertex.(seven)", + "vertex.texcoord[0]", + "vertex.texcoord[1]", + "vertex.texcoord[2]", + "vertex.texcoord[3]", + "vertex.texcoord[4]", + "vertex.texcoord[5]", + "vertex.texcoord[6]", + "vertex.texcoord[7]", + "vertex.attrib[0]", + "vertex.attrib[1]", + "vertex.attrib[2]", + "vertex.attrib[3]", + "vertex.attrib[4]", + "vertex.attrib[5]", + "vertex.attrib[6]", + "vertex.attrib[7]", + "vertex.attrib[8]", + "vertex.attrib[9]", + "vertex.attrib[10]", + "vertex.attrib[11]", + "vertex.attrib[12]", + "vertex.attrib[13]", + "vertex.attrib[14]", + "vertex.attrib[15]" + }; + const char *fragAttribs[] = { + "fragment.position", + "fragment.color.primary", + "fragment.color.secondary", + "fragment.fogcoord", + "fragment.texcoord[0]", + "fragment.texcoord[1]", + "fragment.texcoord[2]", + "fragment.texcoord[3]", + "fragment.texcoord[4]", + "fragment.texcoord[5]", + "fragment.texcoord[6]", + "fragment.texcoord[7]", + "fragment.varying[0]", + "fragment.varying[1]", + "fragment.varying[2]", + "fragment.varying[3]", + "fragment.varying[4]", + "fragment.varying[5]", + "fragment.varying[6]", + "fragment.varying[7]" + }; + + /* sanity checks */ + assert(strcmp(vertAttribs[VERT_ATTRIB_TEX0], "vertex.texcoord[0]") == 0); + assert(strcmp(vertAttribs[VERT_ATTRIB_GENERIC15], "vertex.attrib[15]") == 0); + + if (progType == GL_VERTEX_PROGRAM_ARB) { + assert(index < sizeof(vertAttribs) / sizeof(vertAttribs[0])); + return vertAttribs[index]; + } + else { + assert(index < sizeof(fragAttribs) / sizeof(fragAttribs[0])); + return fragAttribs[index]; + } +} + + +/** + * Print a vertex program's InputsRead field in human-readable format. + * For debugging. + */ +void +_mesa_print_vp_inputs(GLbitfield inputs) +{ + printf("VP Inputs 0x%x: \n", inputs); + while (inputs) { + GLint attr = _mesa_ffs(inputs) - 1; + const char *name = arb_input_attrib_string(attr, + GL_VERTEX_PROGRAM_ARB); + printf(" %d: %s\n", attr, name); + inputs &= ~(1 << attr); + } +} + + +/** + * Print a fragment program's InputsRead field in human-readable format. + * For debugging. + */ +void +_mesa_print_fp_inputs(GLbitfield inputs) +{ + printf("FP Inputs 0x%x: \n", inputs); + while (inputs) { + GLint attr = _mesa_ffs(inputs) - 1; + const char *name = arb_input_attrib_string(attr, + GL_FRAGMENT_PROGRAM_ARB); + printf(" %d: %s\n", attr, name); + inputs &= ~(1 << attr); + } +} + + + +/** + * Return ARB_v/f_prog-style output attrib string. + */ +static const char * +arb_output_attrib_string(GLint index, GLenum progType) +{ + /* + * These strings should match the VERT_RESULT_x and FRAG_RESULT_x tokens. + */ + const char *vertResults[] = { + "result.position", + "result.color.primary", + "result.color.secondary", + "result.fogcoord", + "result.texcoord[0]", + "result.texcoord[1]", + "result.texcoord[2]", + "result.texcoord[3]", + "result.texcoord[4]", + "result.texcoord[5]", + "result.texcoord[6]", + "result.texcoord[7]", + "result.varying[0]", + "result.varying[1]", + "result.varying[2]", + "result.varying[3]", + "result.varying[4]", + "result.varying[5]", + "result.varying[6]", + "result.varying[7]" + }; + const char *fragResults[] = { + "result.color", + "result.color(half)", + "result.depth", + "result.color[0]", + "result.color[1]", + "result.color[2]", + "result.color[3]" + }; + + if (progType == GL_VERTEX_PROGRAM_ARB) { + assert(index < sizeof(vertResults) / sizeof(vertResults[0])); + return vertResults[index]; + } + else { + assert(index < sizeof(fragResults) / sizeof(fragResults[0])); + return fragResults[index]; + } +} + + +/** + * Return string representation of the given register. + * Note that some types of registers (like PROGRAM_UNIFORM) aren't defined + * by the ARB/NV program languages so we've taken some liberties here. + * \param f the register file (PROGRAM_INPUT, PROGRAM_TEMPORARY, etc) + * \param index number of the register in the register file + * \param mode the output format/mode/style + * \param prog pointer to containing program + */ +static const char * +reg_string(gl_register_file f, GLint index, gl_prog_print_mode mode, + GLboolean relAddr, const struct gl_program *prog) +{ + static char str[100]; + const char *addr = relAddr ? "ADDR+" : ""; + + str[0] = 0; + + switch (mode) { + case PROG_PRINT_DEBUG: + sprintf(str, "%s[%s%d]", file_string(f, mode), addr, index); + break; + + case PROG_PRINT_ARB: + switch (f) { + case PROGRAM_INPUT: + sprintf(str, "%s", arb_input_attrib_string(index, prog->Target)); + break; + case PROGRAM_OUTPUT: + sprintf(str, "%s", arb_output_attrib_string(index, prog->Target)); + break; + case PROGRAM_TEMPORARY: + sprintf(str, "temp%d", index); + break; + case PROGRAM_ENV_PARAM: + sprintf(str, "program.env[%s%d]", addr, index); + break; + case PROGRAM_LOCAL_PARAM: + sprintf(str, "program.local[%s%d]", addr, index); + break; + case PROGRAM_VARYING: /* extension */ + sprintf(str, "varying[%s%d]", addr, index); + break; + case PROGRAM_CONSTANT: /* extension */ + sprintf(str, "constant[%s%d]", addr, index); + break; + case PROGRAM_UNIFORM: /* extension */ + sprintf(str, "uniform[%s%d]", addr, index); + break; + case PROGRAM_STATE_VAR: + { + struct gl_program_parameter *param + = prog->Parameters->Parameters + index; + char *state = _mesa_program_state_string(param->StateIndexes); + sprintf(str, "%s", state); + free(state); + } + break; + case PROGRAM_ADDRESS: + sprintf(str, "A%d", index); + break; + default: + _mesa_problem(NULL, "bad file in reg_string()"); + } + break; + + case PROG_PRINT_NV: + switch (f) { + case PROGRAM_INPUT: + if (prog->Target == GL_VERTEX_PROGRAM_ARB) + sprintf(str, "v[%d]", index); + else + sprintf(str, "f[%d]", index); + break; + case PROGRAM_OUTPUT: + sprintf(str, "o[%d]", index); + break; + case PROGRAM_TEMPORARY: + sprintf(str, "R%d", index); + break; + case PROGRAM_ENV_PARAM: + sprintf(str, "c[%d]", index); + break; + case PROGRAM_VARYING: /* extension */ + sprintf(str, "varying[%s%d]", addr, index); + break; + case PROGRAM_UNIFORM: /* extension */ + sprintf(str, "uniform[%s%d]", addr, index); + break; + case PROGRAM_CONSTANT: /* extension */ + sprintf(str, "constant[%s%d]", addr, index); + break; + case PROGRAM_STATE_VAR: /* extension */ + sprintf(str, "state[%s%d]", addr, index); + break; + default: + _mesa_problem(NULL, "bad file in reg_string()"); + } + break; + + default: + _mesa_problem(NULL, "bad mode in reg_string()"); + } + + return str; +} + + +/** + * Return a string representation of the given swizzle word. + * If extended is true, use extended (comma-separated) format. + * \param swizzle the swizzle field + * \param negateBase 4-bit negation vector + * \param extended if true, also allow 0, 1 values + */ +const char * +_mesa_swizzle_string(GLuint swizzle, GLuint negateMask, GLboolean extended) +{ + static const char swz[] = "xyzw01!?"; /* See SWIZZLE_x definitions */ + static char s[20]; + GLuint i = 0; + + if (!extended && swizzle == SWIZZLE_NOOP && negateMask == 0) + return ""; /* no swizzle/negation */ + + if (!extended) + s[i++] = '.'; + + if (negateMask & NEGATE_X) + s[i++] = '-'; + s[i++] = swz[GET_SWZ(swizzle, 0)]; + + if (extended) { + s[i++] = ','; + } + + if (negateMask & NEGATE_Y) + s[i++] = '-'; + s[i++] = swz[GET_SWZ(swizzle, 1)]; + + if (extended) { + s[i++] = ','; + } + + if (negateMask & NEGATE_Z) + s[i++] = '-'; + s[i++] = swz[GET_SWZ(swizzle, 2)]; + + if (extended) { + s[i++] = ','; + } + + if (negateMask & NEGATE_W) + s[i++] = '-'; + s[i++] = swz[GET_SWZ(swizzle, 3)]; + + s[i] = 0; + return s; +} + + +void +_mesa_print_swizzle(GLuint swizzle) +{ + if (swizzle == SWIZZLE_XYZW) { + printf(".xyzw\n"); + } + else { + const char *s = _mesa_swizzle_string(swizzle, 0, 0); + printf("%s\n", s); + } +} + + +const char * +_mesa_writemask_string(GLuint writeMask) +{ + static char s[10]; + GLuint i = 0; + + if (writeMask == WRITEMASK_XYZW) + return ""; + + s[i++] = '.'; + if (writeMask & WRITEMASK_X) + s[i++] = 'x'; + if (writeMask & WRITEMASK_Y) + s[i++] = 'y'; + if (writeMask & WRITEMASK_Z) + s[i++] = 'z'; + if (writeMask & WRITEMASK_W) + s[i++] = 'w'; + + s[i] = 0; + return s; +} + + +const char * +_mesa_condcode_string(GLuint condcode) +{ + switch (condcode) { + case COND_GT: return "GT"; + case COND_EQ: return "EQ"; + case COND_LT: return "LT"; + case COND_UN: return "UN"; + case COND_GE: return "GE"; + case COND_LE: return "LE"; + case COND_NE: return "NE"; + case COND_TR: return "TR"; + case COND_FL: return "FL"; + default: return "cond???"; + } +} + + +static void +fprint_dst_reg(FILE * f, + const struct prog_dst_register *dstReg, + gl_prog_print_mode mode, + const struct gl_program *prog) +{ + fprintf(f, "%s%s", + reg_string((gl_register_file) dstReg->File, + dstReg->Index, mode, dstReg->RelAddr, prog), + _mesa_writemask_string(dstReg->WriteMask)); + + if (dstReg->CondMask != COND_TR) { + fprintf(f, " (%s.%s)", + _mesa_condcode_string(dstReg->CondMask), + _mesa_swizzle_string(dstReg->CondSwizzle, + GL_FALSE, GL_FALSE)); + } + +#if 0 + fprintf(f, "%s[%d]%s", + file_string((gl_register_file) dstReg->File, mode), + dstReg->Index, + _mesa_writemask_string(dstReg->WriteMask)); +#endif +} + + +static void +fprint_src_reg(FILE *f, + const struct prog_src_register *srcReg, + gl_prog_print_mode mode, + const struct gl_program *prog) +{ + const char *abs = srcReg->Abs ? "|" : ""; + + fprintf(f, "%s%s%s%s", + abs, + reg_string((gl_register_file) srcReg->File, + srcReg->Index, mode, srcReg->RelAddr, prog), + _mesa_swizzle_string(srcReg->Swizzle, + srcReg->Negate, GL_FALSE), + abs); +#if 0 + fprintf(f, "%s[%d]%s", + file_string((gl_register_file) srcReg->File, mode), + srcReg->Index, + _mesa_swizzle_string(srcReg->Swizzle, + srcReg->Negate, GL_FALSE)); +#endif +} + + +static void +fprint_comment(FILE *f, const struct prog_instruction *inst) +{ + if (inst->Comment) + fprintf(f, "; # %s\n", inst->Comment); + else + fprintf(f, ";\n"); +} + + +static void +fprint_alu_instruction(FILE *f, + const struct prog_instruction *inst, + const char *opcode_string, GLuint numRegs, + gl_prog_print_mode mode, + const struct gl_program *prog) +{ + GLuint j; + + fprintf(f, "%s", opcode_string); + if (inst->CondUpdate) + fprintf(f, ".C"); + + /* frag prog only */ + if (inst->SaturateMode == SATURATE_ZERO_ONE) + fprintf(f, "_SAT"); + + fprintf(f, " "); + if (inst->DstReg.File != PROGRAM_UNDEFINED) { + fprint_dst_reg(f, &inst->DstReg, mode, prog); + } + else { + fprintf(f, " ???"); + } + + if (numRegs > 0) + fprintf(f, ", "); + + for (j = 0; j < numRegs; j++) { + fprint_src_reg(f, inst->SrcReg + j, mode, prog); + if (j + 1 < numRegs) + fprintf(f, ", "); + } + + fprint_comment(f, inst); +} + + +void +_mesa_print_alu_instruction(const struct prog_instruction *inst, + const char *opcode_string, GLuint numRegs) +{ + fprint_alu_instruction(stderr, inst, opcode_string, + numRegs, PROG_PRINT_DEBUG, NULL); +} + + +/** + * Print a single vertex/fragment program instruction. + */ +GLint +_mesa_fprint_instruction_opt(FILE *f, + const struct prog_instruction *inst, + GLint indent, + gl_prog_print_mode mode, + const struct gl_program *prog) +{ + GLint i; + + if (inst->Opcode == OPCODE_ELSE || + inst->Opcode == OPCODE_ENDIF || + inst->Opcode == OPCODE_ENDLOOP || + inst->Opcode == OPCODE_ENDSUB) { + indent -= 3; + } + for (i = 0; i < indent; i++) { + fprintf(f, " "); + } + + switch (inst->Opcode) { + case OPCODE_PRINT: + fprintf(f, "PRINT '%s'", (char *) inst->Data); + if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { + fprintf(f, ", "); + fprintf(f, "%s[%d]%s", + file_string((gl_register_file) inst->SrcReg[0].File, + mode), + inst->SrcReg[0].Index, + _mesa_swizzle_string(inst->SrcReg[0].Swizzle, + inst->SrcReg[0].Negate, GL_FALSE)); + } + if (inst->Comment) + fprintf(f, " # %s", inst->Comment); + fprint_comment(f, inst); + break; + case OPCODE_SWZ: + fprintf(f, "SWZ"); + if (inst->SaturateMode == SATURATE_ZERO_ONE) + fprintf(f, "_SAT"); + fprintf(f, " "); + fprint_dst_reg(f, &inst->DstReg, mode, prog); + fprintf(f, ", %s[%d], %s", + file_string((gl_register_file) inst->SrcReg[0].File, + mode), + inst->SrcReg[0].Index, + _mesa_swizzle_string(inst->SrcReg[0].Swizzle, + inst->SrcReg[0].Negate, GL_TRUE)); + fprint_comment(f, inst); + break; + case OPCODE_TEX: + case OPCODE_TXP: + case OPCODE_TXL: + case OPCODE_TXB: + fprintf(f, "%s", _mesa_opcode_string(inst->Opcode)); + if (inst->SaturateMode == SATURATE_ZERO_ONE) + fprintf(f, "_SAT"); + fprintf(f, " "); + fprint_dst_reg(f, &inst->DstReg, mode, prog); + fprintf(f, ", "); + fprint_src_reg(f, &inst->SrcReg[0], mode, prog); + fprintf(f, ", texture[%d], ", inst->TexSrcUnit); + switch (inst->TexSrcTarget) { + case TEXTURE_1D_INDEX: fprintf(f, "1D"); break; + case TEXTURE_2D_INDEX: fprintf(f, "2D"); break; + case TEXTURE_3D_INDEX: fprintf(f, "3D"); break; + case TEXTURE_CUBE_INDEX: fprintf(f, "CUBE"); break; + case TEXTURE_RECT_INDEX: fprintf(f, "RECT"); break; + case TEXTURE_1D_ARRAY_INDEX: fprintf(f, "1D_ARRAY"); break; + case TEXTURE_2D_ARRAY_INDEX: fprintf(f, "2D_ARRAY"); break; + default: + ; + } + if (inst->TexShadow) + fprintf(f, " SHADOW"); + fprint_comment(f, inst); + break; + + case OPCODE_KIL: + fprintf(f, "%s", _mesa_opcode_string(inst->Opcode)); + fprintf(f, " "); + fprint_src_reg(f, &inst->SrcReg[0], mode, prog); + fprint_comment(f, inst); + break; + case OPCODE_KIL_NV: + fprintf(f, "%s", _mesa_opcode_string(inst->Opcode)); + fprintf(f, " "); + fprintf(f, "%s.%s", + _mesa_condcode_string(inst->DstReg.CondMask), + _mesa_swizzle_string(inst->DstReg.CondSwizzle, + GL_FALSE, GL_FALSE)); + fprint_comment(f, inst); + break; + + case OPCODE_ARL: + fprintf(f, "ARL "); + fprint_dst_reg(f, &inst->DstReg, mode, prog); + fprintf(f, ", "); + fprint_src_reg(f, &inst->SrcReg[0], mode, prog); + fprint_comment(f, inst); + break; + case OPCODE_BRA: + fprintf(f, "BRA %d (%s%s)", + inst->BranchTarget, + _mesa_condcode_string(inst->DstReg.CondMask), + _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE)); + fprint_comment(f, inst); + break; + case OPCODE_IF: + if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { + /* Use ordinary register */ + fprintf(f, "IF "); + fprint_src_reg(f, &inst->SrcReg[0], mode, prog); + fprintf(f, "; "); + } + else { + /* Use cond codes */ + fprintf(f, "IF (%s%s);", + _mesa_condcode_string(inst->DstReg.CondMask), + _mesa_swizzle_string(inst->DstReg.CondSwizzle, + 0, GL_FALSE)); + } + fprintf(f, " # (if false, goto %d)", inst->BranchTarget); + fprint_comment(f, inst); + return indent + 3; + case OPCODE_ELSE: + fprintf(f, "ELSE; # (goto %d)\n", inst->BranchTarget); + return indent + 3; + case OPCODE_ENDIF: + fprintf(f, "ENDIF;\n"); + break; + case OPCODE_BGNLOOP: + fprintf(f, "BGNLOOP; # (end at %d)\n", inst->BranchTarget); + return indent + 3; + case OPCODE_ENDLOOP: + fprintf(f, "ENDLOOP; # (goto %d)\n", inst->BranchTarget); + break; + case OPCODE_BRK: + case OPCODE_CONT: + fprintf(f, "%s (%s%s); # (goto %d)", + _mesa_opcode_string(inst->Opcode), + _mesa_condcode_string(inst->DstReg.CondMask), + _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE), + inst->BranchTarget); + fprint_comment(f, inst); + break; + + case OPCODE_BGNSUB: + if (mode == PROG_PRINT_NV) { + fprintf(f, "%s:\n", inst->Comment); /* comment is label */ + return indent; + } + else { + fprintf(f, "BGNSUB"); + fprint_comment(f, inst); + return indent + 3; + } + case OPCODE_ENDSUB: + if (mode == PROG_PRINT_DEBUG) { + fprintf(f, "ENDSUB"); + fprint_comment(f, inst); + } + break; + case OPCODE_CAL: + if (mode == PROG_PRINT_NV) { + fprintf(f, "CAL %s; # (goto %d)\n", inst->Comment, inst->BranchTarget); + } + else { + fprintf(f, "CAL %u", inst->BranchTarget); + fprint_comment(f, inst); + } + break; + case OPCODE_RET: + fprintf(f, "RET (%s%s)", + _mesa_condcode_string(inst->DstReg.CondMask), + _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE)); + fprint_comment(f, inst); + break; + + case OPCODE_END: + fprintf(f, "END\n"); + break; + case OPCODE_NOP: + if (mode == PROG_PRINT_DEBUG) { + fprintf(f, "NOP"); + fprint_comment(f, inst); + } + else if (inst->Comment) { + /* ARB/NV extensions don't have NOP instruction */ + fprintf(f, "# %s\n", inst->Comment); + } + break; + /* XXX may need other special-case instructions */ + default: + if (inst->Opcode < MAX_OPCODE) { + /* typical alu instruction */ + fprint_alu_instruction(f, inst, + _mesa_opcode_string(inst->Opcode), + _mesa_num_inst_src_regs(inst->Opcode), + mode, prog); + } + else { + fprint_alu_instruction(f, inst, + _mesa_opcode_string(inst->Opcode), + 3/*_mesa_num_inst_src_regs(inst->Opcode)*/, + mode, prog); + } + break; + } + return indent; +} + + +GLint +_mesa_print_instruction_opt(const struct prog_instruction *inst, + GLint indent, + gl_prog_print_mode mode, + const struct gl_program *prog) +{ + return _mesa_fprint_instruction_opt(stderr, inst, indent, mode, prog); +} + + +void +_mesa_print_instruction(const struct prog_instruction *inst) +{ + /* note: 4th param should be ignored for PROG_PRINT_DEBUG */ + _mesa_fprint_instruction_opt(stderr, inst, 0, PROG_PRINT_DEBUG, NULL); +} + + + +/** + * Print program, with options. + */ +void +_mesa_fprint_program_opt(FILE *f, + const struct gl_program *prog, + gl_prog_print_mode mode, + GLboolean lineNumbers) +{ + GLuint i, indent = 0; + + switch (prog->Target) { + case GL_VERTEX_PROGRAM_ARB: + if (mode == PROG_PRINT_ARB) + fprintf(f, "!!ARBvp1.0\n"); + else if (mode == PROG_PRINT_NV) + fprintf(f, "!!VP1.0\n"); + else + fprintf(f, "# Vertex Program/Shader %u\n", prog->Id); + break; + case GL_FRAGMENT_PROGRAM_ARB: + case GL_FRAGMENT_PROGRAM_NV: + if (mode == PROG_PRINT_ARB) + fprintf(f, "!!ARBfp1.0\n"); + else if (mode == PROG_PRINT_NV) + fprintf(f, "!!FP1.0\n"); + else + fprintf(f, "# Fragment Program/Shader %u\n", prog->Id); + break; + } + + for (i = 0; i < prog->NumInstructions; i++) { + if (lineNumbers) + fprintf(f, "%3d: ", i); + indent = _mesa_fprint_instruction_opt(f, prog->Instructions + i, + indent, mode, prog); + } +} + + +/** + * Print program to stderr, default options. + */ +void +_mesa_print_program(const struct gl_program *prog) +{ + _mesa_fprint_program_opt(stderr, prog, PROG_PRINT_DEBUG, GL_TRUE); +} + + +/** + * Return binary representation of 64-bit value (as a string). + * Insert a comma to separate each group of 8 bits. + * Note we return a pointer to local static storage so this is not + * re-entrant, etc. + * XXX move to imports.[ch] if useful elsewhere. + */ +static const char * +binary(GLbitfield64 val) +{ + static char buf[80]; + GLint i, len = 0; + for (i = 63; i >= 0; --i) { + if (val & (BITFIELD64_BIT(i))) + buf[len++] = '1'; + else if (len > 0 || i == 0) + buf[len++] = '0'; + if (len > 0 && ((i-1) % 8) == 7) + buf[len++] = ','; + } + buf[len] = '\0'; + return buf; +} + + +/** + * Print all of a program's parameters/fields to given file. + */ +static void +_mesa_fprint_program_parameters(FILE *f, + GLcontext *ctx, + const struct gl_program *prog) +{ + GLuint i; + + fprintf(f, "InputsRead: 0x%x (0b%s)\n", + prog->InputsRead, binary(prog->InputsRead)); + fprintf(f, "OutputsWritten: 0x%llx (0b%s)\n", + prog->OutputsWritten, binary(prog->OutputsWritten)); + fprintf(f, "NumInstructions=%d\n", prog->NumInstructions); + fprintf(f, "NumTemporaries=%d\n", prog->NumTemporaries); + fprintf(f, "NumParameters=%d\n", prog->NumParameters); + fprintf(f, "NumAttributes=%d\n", prog->NumAttributes); + fprintf(f, "NumAddressRegs=%d\n", prog->NumAddressRegs); + fprintf(f, "SamplersUsed: 0x%x (0b%s)\n", + prog->SamplersUsed, binary(prog->SamplersUsed)); + fprintf(f, "Samplers=[ "); + for (i = 0; i < MAX_SAMPLERS; i++) { + fprintf(f, "%d ", prog->SamplerUnits[i]); + } + fprintf(f, "]\n"); + + _mesa_load_state_parameters(ctx, prog->Parameters); + +#if 0 + fprintf(f, "Local Params:\n"); + for (i = 0; i < MAX_PROGRAM_LOCAL_PARAMS; i++){ + const GLfloat *p = prog->LocalParams[i]; + fprintf(f, "%2d: %f, %f, %f, %f\n", i, p[0], p[1], p[2], p[3]); + } +#endif + _mesa_print_parameter_list(prog->Parameters); +} + + +/** + * Print all of a program's parameters/fields to stderr. + */ +void +_mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog) +{ + _mesa_fprint_program_parameters(stderr, ctx, prog); +} + + +/** + * Print a program parameter list to given file. + */ +static void +_mesa_fprint_parameter_list(FILE *f, + const struct gl_program_parameter_list *list) +{ + const gl_prog_print_mode mode = PROG_PRINT_DEBUG; + GLuint i; + + if (!list) + return; + + if (0) + fprintf(f, "param list %p\n", (void *) list); + fprintf(f, "dirty state flags: 0x%x\n", list->StateFlags); + for (i = 0; i < list->NumParameters; i++){ + struct gl_program_parameter *param = list->Parameters + i; + const GLfloat *v = list->ParameterValues[i]; + fprintf(f, "param[%d] sz=%d %s %s = {%.3g, %.3g, %.3g, %.3g}", + i, param->Size, + file_string(list->Parameters[i].Type, mode), + param->Name, v[0], v[1], v[2], v[3]); + if (param->Flags & PROG_PARAM_BIT_CENTROID) + fprintf(f, " Centroid"); + if (param->Flags & PROG_PARAM_BIT_INVARIANT) + fprintf(f, " Invariant"); + if (param->Flags & PROG_PARAM_BIT_FLAT) + fprintf(f, " Flat"); + if (param->Flags & PROG_PARAM_BIT_LINEAR) + fprintf(f, " Linear"); + fprintf(f, "\n"); + } +} + + +/** + * Print a program parameter list to stderr. + */ +void +_mesa_print_parameter_list(const struct gl_program_parameter_list *list) +{ + _mesa_fprint_parameter_list(stderr, list); +} + + +/** + * Write shader and associated info to a file. + */ +void +_mesa_write_shader_to_file(const struct gl_shader *shader) +{ + const char *type; + char filename[100]; + FILE *f; + + if (shader->Type == GL_FRAGMENT_SHADER) + type = "frag"; + else + type = "vert"; + + _mesa_snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type); + f = fopen(filename, "w"); + if (!f) { + fprintf(stderr, "Unable to open %s for writing\n", filename); + return; + } + + fprintf(f, "/* Shader %u source, checksum %u */\n", shader->Name, shader->SourceChecksum); + fputs(shader->Source, f); + fprintf(f, "\n"); + + fprintf(f, "/* Compile status: %s */\n", + shader->CompileStatus ? "ok" : "fail"); + if (!shader->CompileStatus) { + fprintf(f, "/* Log Info: */\n"); + fputs(shader->InfoLog, f); + } + else { + fprintf(f, "/* GPU code */\n"); + fprintf(f, "/*\n"); + _mesa_fprint_program_opt(f, shader->Program, PROG_PRINT_DEBUG, GL_TRUE); + fprintf(f, "*/\n"); + fprintf(f, "/* Parameters / constants */\n"); + fprintf(f, "/*\n"); + _mesa_fprint_parameter_list(f, shader->Program->Parameters); + fprintf(f, "*/\n"); + } + + fclose(f); +} + + +/** + * Append the shader's uniform info/values to the shader log file. + * The log file will typically have been created by the + * _mesa_write_shader_to_file function. + */ +void +_mesa_append_uniforms_to_file(const struct gl_shader *shader, + const struct gl_program *prog) +{ + const char *type; + char filename[100]; + FILE *f; + + if (shader->Type == GL_FRAGMENT_SHADER) + type = "frag"; + else + type = "vert"; + + _mesa_snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type); + f = fopen(filename, "a"); /* append */ + if (!f) { + fprintf(stderr, "Unable to open %s for appending\n", filename); + return; + } + + fprintf(f, "/* First-draw parameters / constants */\n"); + fprintf(f, "/*\n"); + _mesa_fprint_parameter_list(f, prog->Parameters); + fprintf(f, "*/\n"); + + fclose(f); +} diff --git a/src/mesa/program/prog_print.h b/src/mesa/program/prog_print.h new file mode 100644 index 0000000000..9ab7456016 --- /dev/null +++ b/src/mesa/program/prog_print.h @@ -0,0 +1,100 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef PROG_PRINT_H +#define PROG_PRINT_H + + +/** + * The output style to use when printing programs. + */ +typedef enum { + PROG_PRINT_ARB, + PROG_PRINT_NV, + PROG_PRINT_DEBUG +} gl_prog_print_mode; + + +extern void +_mesa_print_vp_inputs(GLbitfield inputs); + +extern void +_mesa_print_fp_inputs(GLbitfield inputs); + +extern const char * +_mesa_condcode_string(GLuint condcode); + +extern const char * +_mesa_swizzle_string(GLuint swizzle, GLuint negateBase, GLboolean extended); + +const char * +_mesa_writemask_string(GLuint writeMask); + +extern void +_mesa_print_swizzle(GLuint swizzle); + +extern void +_mesa_print_alu_instruction(const struct prog_instruction *inst, + const char *opcode_string, GLuint numRegs); + +extern void +_mesa_print_instruction(const struct prog_instruction *inst); + +extern GLint +_mesa_fprint_instruction_opt(FILE *f, + const struct prog_instruction *inst, + GLint indent, + gl_prog_print_mode mode, + const struct gl_program *prog); + +extern GLint +_mesa_print_instruction_opt(const struct prog_instruction *inst, GLint indent, + gl_prog_print_mode mode, + const struct gl_program *prog); + +extern void +_mesa_print_program(const struct gl_program *prog); + +extern void +_mesa_fprint_program_opt(FILE *f, + const struct gl_program *prog, gl_prog_print_mode mode, + GLboolean lineNumbers); + +extern void +_mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog); + +extern void +_mesa_print_parameter_list(const struct gl_program_parameter_list *list); + + +extern void +_mesa_write_shader_to_file(const struct gl_shader *shader); + +extern void +_mesa_append_uniforms_to_file(const struct gl_shader *shader, + const struct gl_program *prog); + + +#endif /* PROG_PRINT_H */ diff --git a/src/mesa/program/prog_statevars.c b/src/mesa/program/prog_statevars.c new file mode 100644 index 0000000000..ead3ece95d --- /dev/null +++ b/src/mesa/program/prog_statevars.c @@ -0,0 +1,1187 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file prog_statevars.c + * Program state variable management. + * \author Brian Paul + */ + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/imports.h" +#include "main/macros.h" +#include "main/mtypes.h" +#include "prog_statevars.h" +#include "prog_parameter.h" + + +/** + * Use the list of tokens in the state[] array to find global GL state + * and return it in . Usually, four values are returned in + * but matrix queries may return as many as 16 values. + * This function is used for ARB vertex/fragment programs. + * The program parser will produce the state[] values. + */ +static void +_mesa_fetch_state(GLcontext *ctx, const gl_state_index state[], + GLfloat *value) +{ + switch (state[0]) { + case STATE_MATERIAL: + { + /* state[1] is either 0=front or 1=back side */ + const GLuint face = (GLuint) state[1]; + const struct gl_material *mat = &ctx->Light.Material; + ASSERT(face == 0 || face == 1); + /* we rely on tokens numbered so that _BACK_ == _FRONT_+ 1 */ + ASSERT(MAT_ATTRIB_FRONT_AMBIENT + 1 == MAT_ATTRIB_BACK_AMBIENT); + /* XXX we could get rid of this switch entirely with a little + * work in arbprogparse.c's parse_state_single_item(). + */ + /* state[2] is the material attribute */ + switch (state[2]) { + case STATE_AMBIENT: + COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_AMBIENT + face]); + return; + case STATE_DIFFUSE: + COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_DIFFUSE + face]); + return; + case STATE_SPECULAR: + COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_SPECULAR + face]); + return; + case STATE_EMISSION: + COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_EMISSION + face]); + return; + case STATE_SHININESS: + value[0] = mat->Attrib[MAT_ATTRIB_FRONT_SHININESS + face][0]; + value[1] = 0.0F; + value[2] = 0.0F; + value[3] = 1.0F; + return; + default: + _mesa_problem(ctx, "Invalid material state in fetch_state"); + return; + } + } + case STATE_LIGHT: + { + /* state[1] is the light number */ + const GLuint ln = (GLuint) state[1]; + /* state[2] is the light attribute */ + switch (state[2]) { + case STATE_AMBIENT: + COPY_4V(value, ctx->Light.Light[ln].Ambient); + return; + case STATE_DIFFUSE: + COPY_4V(value, ctx->Light.Light[ln].Diffuse); + return; + case STATE_SPECULAR: + COPY_4V(value, ctx->Light.Light[ln].Specular); + return; + case STATE_POSITION: + COPY_4V(value, ctx->Light.Light[ln].EyePosition); + return; + case STATE_ATTENUATION: + value[0] = ctx->Light.Light[ln].ConstantAttenuation; + value[1] = ctx->Light.Light[ln].LinearAttenuation; + value[2] = ctx->Light.Light[ln].QuadraticAttenuation; + value[3] = ctx->Light.Light[ln].SpotExponent; + return; + case STATE_SPOT_DIRECTION: + COPY_3V(value, ctx->Light.Light[ln].SpotDirection); + value[3] = ctx->Light.Light[ln]._CosCutoff; + return; + case STATE_SPOT_CUTOFF: + value[0] = ctx->Light.Light[ln].SpotCutoff; + return; + case STATE_HALF_VECTOR: + { + static const GLfloat eye_z[] = {0, 0, 1}; + GLfloat p[3]; + /* Compute infinite half angle vector: + * halfVector = normalize(normalize(lightPos) + (0, 0, 1)) + * light.EyePosition.w should be 0 for infinite lights. + */ + COPY_3V(p, ctx->Light.Light[ln].EyePosition); + NORMALIZE_3FV(p); + ADD_3V(value, p, eye_z); + NORMALIZE_3FV(value); + value[3] = 1.0; + } + return; + default: + _mesa_problem(ctx, "Invalid light state in fetch_state"); + return; + } + } + case STATE_LIGHTMODEL_AMBIENT: + COPY_4V(value, ctx->Light.Model.Ambient); + return; + case STATE_LIGHTMODEL_SCENECOLOR: + if (state[1] == 0) { + /* front */ + GLint i; + for (i = 0; i < 3; i++) { + value[i] = ctx->Light.Model.Ambient[i] + * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT][i] + + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION][i]; + } + value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3]; + } + else { + /* back */ + GLint i; + for (i = 0; i < 3; i++) { + value[i] = ctx->Light.Model.Ambient[i] + * ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT][i] + + ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION][i]; + } + value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3]; + } + return; + case STATE_LIGHTPROD: + { + const GLuint ln = (GLuint) state[1]; + const GLuint face = (GLuint) state[2]; + GLint i; + ASSERT(face == 0 || face == 1); + switch (state[3]) { + case STATE_AMBIENT: + for (i = 0; i < 3; i++) { + value[i] = ctx->Light.Light[ln].Ambient[i] * + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][i]; + } + /* [3] = material alpha */ + value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][3]; + return; + case STATE_DIFFUSE: + for (i = 0; i < 3; i++) { + value[i] = ctx->Light.Light[ln].Diffuse[i] * + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][i]; + } + /* [3] = material alpha */ + value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3]; + return; + case STATE_SPECULAR: + for (i = 0; i < 3; i++) { + value[i] = ctx->Light.Light[ln].Specular[i] * + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][i]; + } + /* [3] = material alpha */ + value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][3]; + return; + default: + _mesa_problem(ctx, "Invalid lightprod state in fetch_state"); + return; + } + } + case STATE_TEXGEN: + { + /* state[1] is the texture unit */ + const GLuint unit = (GLuint) state[1]; + /* state[2] is the texgen attribute */ + switch (state[2]) { + case STATE_TEXGEN_EYE_S: + COPY_4V(value, ctx->Texture.Unit[unit].GenS.EyePlane); + return; + case STATE_TEXGEN_EYE_T: + COPY_4V(value, ctx->Texture.Unit[unit].GenT.EyePlane); + return; + case STATE_TEXGEN_EYE_R: + COPY_4V(value, ctx->Texture.Unit[unit].GenR.EyePlane); + return; + case STATE_TEXGEN_EYE_Q: + COPY_4V(value, ctx->Texture.Unit[unit].GenQ.EyePlane); + return; + case STATE_TEXGEN_OBJECT_S: + COPY_4V(value, ctx->Texture.Unit[unit].GenS.ObjectPlane); + return; + case STATE_TEXGEN_OBJECT_T: + COPY_4V(value, ctx->Texture.Unit[unit].GenT.ObjectPlane); + return; + case STATE_TEXGEN_OBJECT_R: + COPY_4V(value, ctx->Texture.Unit[unit].GenR.ObjectPlane); + return; + case STATE_TEXGEN_OBJECT_Q: + COPY_4V(value, ctx->Texture.Unit[unit].GenQ.ObjectPlane); + return; + default: + _mesa_problem(ctx, "Invalid texgen state in fetch_state"); + return; + } + } + case STATE_TEXENV_COLOR: + { + /* state[1] is the texture unit */ + const GLuint unit = (GLuint) state[1]; + COPY_4V(value, ctx->Texture.Unit[unit].EnvColor); + } + return; + case STATE_FOG_COLOR: + COPY_4V(value, ctx->Fog.Color); + return; + case STATE_FOG_PARAMS: + value[0] = ctx->Fog.Density; + value[1] = ctx->Fog.Start; + value[2] = ctx->Fog.End; + value[3] = (ctx->Fog.End == ctx->Fog.Start) + ? 1.0f : (GLfloat)(1.0 / (ctx->Fog.End - ctx->Fog.Start)); + return; + case STATE_CLIPPLANE: + { + const GLuint plane = (GLuint) state[1]; + COPY_4V(value, ctx->Transform.EyeUserPlane[plane]); + } + return; + case STATE_POINT_SIZE: + value[0] = ctx->Point.Size; + value[1] = ctx->Point.MinSize; + value[2] = ctx->Point.MaxSize; + value[3] = ctx->Point.Threshold; + return; + case STATE_POINT_ATTENUATION: + value[0] = ctx->Point.Params[0]; + value[1] = ctx->Point.Params[1]; + value[2] = ctx->Point.Params[2]; + value[3] = 1.0F; + return; + case STATE_MODELVIEW_MATRIX: + case STATE_PROJECTION_MATRIX: + case STATE_MVP_MATRIX: + case STATE_TEXTURE_MATRIX: + case STATE_PROGRAM_MATRIX: + case STATE_COLOR_MATRIX: + { + /* state[0] = modelview, projection, texture, etc. */ + /* state[1] = which texture matrix or program matrix */ + /* state[2] = first row to fetch */ + /* state[3] = last row to fetch */ + /* state[4] = transpose, inverse or invtrans */ + const GLmatrix *matrix; + const gl_state_index mat = state[0]; + const GLuint index = (GLuint) state[1]; + const GLuint firstRow = (GLuint) state[2]; + const GLuint lastRow = (GLuint) state[3]; + const gl_state_index modifier = state[4]; + const GLfloat *m; + GLuint row, i; + ASSERT(firstRow >= 0); + ASSERT(firstRow < 4); + ASSERT(lastRow >= 0); + ASSERT(lastRow < 4); + if (mat == STATE_MODELVIEW_MATRIX) { + matrix = ctx->ModelviewMatrixStack.Top; + } + else if (mat == STATE_PROJECTION_MATRIX) { + matrix = ctx->ProjectionMatrixStack.Top; + } + else if (mat == STATE_MVP_MATRIX) { + matrix = &ctx->_ModelProjectMatrix; + } + else if (mat == STATE_TEXTURE_MATRIX) { + ASSERT(index < Elements(ctx->TextureMatrixStack)); + matrix = ctx->TextureMatrixStack[index].Top; + } + else if (mat == STATE_PROGRAM_MATRIX) { + ASSERT(index < Elements(ctx->ProgramMatrixStack)); + matrix = ctx->ProgramMatrixStack[index].Top; + } + else if (mat == STATE_COLOR_MATRIX) { + matrix = ctx->ColorMatrixStack.Top; + } + else { + _mesa_problem(ctx, "Bad matrix name in _mesa_fetch_state()"); + return; + } + if (modifier == STATE_MATRIX_INVERSE || + modifier == STATE_MATRIX_INVTRANS) { + /* Be sure inverse is up to date: + */ + _math_matrix_alloc_inv( (GLmatrix *) matrix ); + _math_matrix_analyse( (GLmatrix*) matrix ); + m = matrix->inv; + } + else { + m = matrix->m; + } + if (modifier == STATE_MATRIX_TRANSPOSE || + modifier == STATE_MATRIX_INVTRANS) { + for (i = 0, row = firstRow; row <= lastRow; row++) { + value[i++] = m[row * 4 + 0]; + value[i++] = m[row * 4 + 1]; + value[i++] = m[row * 4 + 2]; + value[i++] = m[row * 4 + 3]; + } + } + else { + for (i = 0, row = firstRow; row <= lastRow; row++) { + value[i++] = m[row + 0]; + value[i++] = m[row + 4]; + value[i++] = m[row + 8]; + value[i++] = m[row + 12]; + } + } + } + return; + case STATE_DEPTH_RANGE: + value[0] = ctx->Viewport.Near; /* near */ + value[1] = ctx->Viewport.Far; /* far */ + value[2] = ctx->Viewport.Far - ctx->Viewport.Near; /* far - near */ + value[3] = 1.0; + return; + case STATE_FRAGMENT_PROGRAM: + { + /* state[1] = {STATE_ENV, STATE_LOCAL} */ + /* state[2] = parameter index */ + const int idx = (int) state[2]; + switch (state[1]) { + case STATE_ENV: + COPY_4V(value, ctx->FragmentProgram.Parameters[idx]); + return; + case STATE_LOCAL: + COPY_4V(value, ctx->FragmentProgram.Current->Base.LocalParams[idx]); + return; + default: + _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()"); + return; + } + } + return; + + case STATE_VERTEX_PROGRAM: + { + /* state[1] = {STATE_ENV, STATE_LOCAL} */ + /* state[2] = parameter index */ + const int idx = (int) state[2]; + switch (state[1]) { + case STATE_ENV: + COPY_4V(value, ctx->VertexProgram.Parameters[idx]); + return; + case STATE_LOCAL: + COPY_4V(value, ctx->VertexProgram.Current->Base.LocalParams[idx]); + return; + default: + _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()"); + return; + } + } + return; + + case STATE_NORMAL_SCALE: + ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1); + return; + + case STATE_INTERNAL: + switch (state[1]) { + case STATE_CURRENT_ATTRIB: + { + const GLuint idx = (GLuint) state[2]; + COPY_4V(value, ctx->Current.Attrib[idx]); + } + return; + + case STATE_NORMAL_SCALE: + ASSIGN_4V(value, + ctx->_ModelViewInvScale, + ctx->_ModelViewInvScale, + ctx->_ModelViewInvScale, + 1); + return; + + case STATE_TEXRECT_SCALE: + /* Value = { 1/texWidth, 1/texHeight, 0, 1 }. + * Used to convert unnormalized texcoords to normalized texcoords. + */ + { + const int unit = (int) state[2]; + const struct gl_texture_object *texObj + = ctx->Texture.Unit[unit]._Current; + if (texObj) { + struct gl_texture_image *texImage = texObj->Image[0][0]; + ASSIGN_4V(value, + (GLfloat) (1.0 / texImage->Width), + (GLfloat) (1.0 / texImage->Height), + 0.0f, 1.0f); + } + } + return; + + case STATE_FOG_PARAMS_OPTIMIZED: + /* for simpler per-vertex/pixel fog calcs. POW (for EXP/EXP2 fog) + * might be more expensive than EX2 on some hw, plus it needs + * another constant (e) anyway. Linear fog can now be done with a + * single MAD. + * linear: fogcoord * -1/(end-start) + end/(end-start) + * exp: 2^-(density/ln(2) * fogcoord) + * exp2: 2^-((density/(ln(2)^2) * fogcoord)^2) + */ + value[0] = (ctx->Fog.End == ctx->Fog.Start) + ? 1.0f : (GLfloat)(-1.0F / (ctx->Fog.End - ctx->Fog.Start)); + value[1] = ctx->Fog.End * -value[0]; + value[2] = (GLfloat)(ctx->Fog.Density * ONE_DIV_LN2); + value[3] = (GLfloat)(ctx->Fog.Density * ONE_DIV_SQRT_LN2); + return; + + case STATE_POINT_SIZE_CLAMPED: + { + /* this includes implementation dependent limits, to avoid + * another potentially necessary clamp. + * Note: for sprites, point smooth (point AA) is ignored + * and we'll clamp to MinPointSizeAA and MaxPointSize, because we + * expect drivers will want to say their minimum for AA size is 0.0 + * but for non-AA it's 1.0 (because normal points with size below 1.0 + * need to get rounded up to 1.0, hence never disappear). GL does + * not specify max clamp size for sprites, other than it needs to be + * at least as large as max AA size, hence use non-AA size there. + */ + GLfloat minImplSize; + GLfloat maxImplSize; + if (ctx->Point.PointSprite) { + minImplSize = ctx->Const.MinPointSizeAA; + maxImplSize = ctx->Const.MaxPointSize; + } + else if (ctx->Point.SmoothFlag || ctx->Multisample._Enabled) { + minImplSize = ctx->Const.MinPointSizeAA; + maxImplSize = ctx->Const.MaxPointSizeAA; + } + else { + minImplSize = ctx->Const.MinPointSize; + maxImplSize = ctx->Const.MaxPointSize; + } + value[0] = ctx->Point.Size; + value[1] = ctx->Point.MinSize >= minImplSize ? ctx->Point.MinSize : minImplSize; + value[2] = ctx->Point.MaxSize <= maxImplSize ? ctx->Point.MaxSize : maxImplSize; + value[3] = ctx->Point.Threshold; + } + return; + case STATE_POINT_SIZE_IMPL_CLAMP: + { + /* for implementation clamp only in vs */ + GLfloat minImplSize; + GLfloat maxImplSize; + if (ctx->Point.PointSprite) { + minImplSize = ctx->Const.MinPointSizeAA; + maxImplSize = ctx->Const.MaxPointSize; + } + else if (ctx->Point.SmoothFlag || ctx->Multisample._Enabled) { + minImplSize = ctx->Const.MinPointSizeAA; + maxImplSize = ctx->Const.MaxPointSizeAA; + } + else { + minImplSize = ctx->Const.MinPointSize; + maxImplSize = ctx->Const.MaxPointSize; + } + value[0] = ctx->Point.Size; + value[1] = minImplSize; + value[2] = maxImplSize; + value[3] = ctx->Point.Threshold; + } + return; + case STATE_LIGHT_SPOT_DIR_NORMALIZED: + { + /* here, state[2] is the light number */ + /* pre-normalize spot dir */ + const GLuint ln = (GLuint) state[2]; + COPY_3V(value, ctx->Light.Light[ln]._NormSpotDirection); + value[3] = ctx->Light.Light[ln]._CosCutoff; + } + return; + + case STATE_LIGHT_POSITION: + { + const GLuint ln = (GLuint) state[2]; + COPY_4V(value, ctx->Light.Light[ln]._Position); + } + return; + + case STATE_LIGHT_POSITION_NORMALIZED: + { + const GLuint ln = (GLuint) state[2]; + COPY_4V(value, ctx->Light.Light[ln]._Position); + NORMALIZE_3FV( value ); + } + return; + + case STATE_LIGHT_HALF_VECTOR: + { + const GLuint ln = (GLuint) state[2]; + GLfloat p[3]; + /* Compute infinite half angle vector: + * halfVector = normalize(normalize(lightPos) + (0, 0, 1)) + * light.EyePosition.w should be 0 for infinite lights. + */ + COPY_3V(p, ctx->Light.Light[ln]._Position); + NORMALIZE_3FV(p); + ADD_3V(value, p, ctx->_EyeZDir); + NORMALIZE_3FV(value); + value[3] = 1.0; + } + return; + + case STATE_PT_SCALE: + value[0] = ctx->Pixel.RedScale; + value[1] = ctx->Pixel.GreenScale; + value[2] = ctx->Pixel.BlueScale; + value[3] = ctx->Pixel.AlphaScale; + return; + + case STATE_PT_BIAS: + value[0] = ctx->Pixel.RedBias; + value[1] = ctx->Pixel.GreenBias; + value[2] = ctx->Pixel.BlueBias; + value[3] = ctx->Pixel.AlphaBias; + return; + + case STATE_PCM_SCALE: + COPY_4V(value, ctx->Pixel.PostColorMatrixScale); + return; + + case STATE_PCM_BIAS: + COPY_4V(value, ctx->Pixel.PostColorMatrixBias); + return; + + case STATE_SHADOW_AMBIENT: + { + const int unit = (int) state[2]; + const struct gl_texture_object *texObj + = ctx->Texture.Unit[unit]._Current; + if (texObj) { + value[0] = + value[1] = + value[2] = + value[3] = texObj->CompareFailValue; + } + } + return; + + case STATE_FB_SIZE: + value[0] = (GLfloat) (ctx->DrawBuffer->Width - 1); + value[1] = (GLfloat) (ctx->DrawBuffer->Height - 1); + value[2] = 0.0F; + value[3] = 0.0F; + return; + + case STATE_ROT_MATRIX_0: + { + const int unit = (int) state[2]; + GLfloat *rotMat22 = ctx->Texture.Unit[unit].RotMatrix; + value[0] = rotMat22[0]; + value[1] = rotMat22[2]; + value[2] = 0.0; + value[3] = 0.0; + } + return; + + case STATE_ROT_MATRIX_1: + { + const int unit = (int) state[2]; + GLfloat *rotMat22 = ctx->Texture.Unit[unit].RotMatrix; + value[0] = rotMat22[1]; + value[1] = rotMat22[3]; + value[2] = 0.0; + value[3] = 0.0; + } + return; + + /* XXX: make sure new tokens added here are also handled in the + * _mesa_program_state_flags() switch, below. + */ + default: + /* Unknown state indexes are silently ignored here. + * Drivers may do something special. + */ + return; + } + return; + + default: + _mesa_problem(ctx, "Invalid state in _mesa_fetch_state"); + return; + } +} + + +/** + * Return a bitmask of the Mesa state flags (_NEW_* values) which would + * indicate that the given context state may have changed. + * The bitmask is used during validation to determine if we need to update + * vertex/fragment program parameters (like "state.material.color") when + * some GL state has changed. + */ +GLbitfield +_mesa_program_state_flags(const gl_state_index state[STATE_LENGTH]) +{ + switch (state[0]) { + case STATE_MATERIAL: + case STATE_LIGHT: + case STATE_LIGHTMODEL_AMBIENT: + case STATE_LIGHTMODEL_SCENECOLOR: + case STATE_LIGHTPROD: + return _NEW_LIGHT; + + case STATE_TEXGEN: + case STATE_TEXENV_COLOR: + return _NEW_TEXTURE; + + case STATE_FOG_COLOR: + case STATE_FOG_PARAMS: + return _NEW_FOG; + + case STATE_CLIPPLANE: + return _NEW_TRANSFORM; + + case STATE_POINT_SIZE: + case STATE_POINT_ATTENUATION: + return _NEW_POINT; + + case STATE_MODELVIEW_MATRIX: + return _NEW_MODELVIEW; + case STATE_PROJECTION_MATRIX: + return _NEW_PROJECTION; + case STATE_MVP_MATRIX: + return _NEW_MODELVIEW | _NEW_PROJECTION; + case STATE_TEXTURE_MATRIX: + return _NEW_TEXTURE_MATRIX; + case STATE_PROGRAM_MATRIX: + return _NEW_TRACK_MATRIX; + case STATE_COLOR_MATRIX: + return _NEW_COLOR_MATRIX; + + case STATE_DEPTH_RANGE: + return _NEW_VIEWPORT; + + case STATE_FRAGMENT_PROGRAM: + case STATE_VERTEX_PROGRAM: + return _NEW_PROGRAM; + + case STATE_NORMAL_SCALE: + return _NEW_MODELVIEW; + + case STATE_INTERNAL: + switch (state[1]) { + case STATE_CURRENT_ATTRIB: + return _NEW_CURRENT_ATTRIB; + + case STATE_NORMAL_SCALE: + return _NEW_MODELVIEW; + + case STATE_TEXRECT_SCALE: + case STATE_SHADOW_AMBIENT: + case STATE_ROT_MATRIX_0: + case STATE_ROT_MATRIX_1: + return _NEW_TEXTURE; + case STATE_FOG_PARAMS_OPTIMIZED: + return _NEW_FOG; + case STATE_POINT_SIZE_CLAMPED: + case STATE_POINT_SIZE_IMPL_CLAMP: + return _NEW_POINT | _NEW_MULTISAMPLE; + case STATE_LIGHT_SPOT_DIR_NORMALIZED: + case STATE_LIGHT_POSITION: + case STATE_LIGHT_POSITION_NORMALIZED: + case STATE_LIGHT_HALF_VECTOR: + return _NEW_LIGHT; + + case STATE_PT_SCALE: + case STATE_PT_BIAS: + case STATE_PCM_SCALE: + case STATE_PCM_BIAS: + return _NEW_PIXEL; + + case STATE_FB_SIZE: + return _NEW_BUFFERS; + + default: + /* unknown state indexes are silently ignored and + * no flag set, since it is handled by the driver. + */ + return 0; + } + + default: + _mesa_problem(NULL, "unexpected state[0] in make_state_flags()"); + return 0; + } +} + + +static void +append(char *dst, const char *src) +{ + while (*dst) + dst++; + while (*src) + *dst++ = *src++; + *dst = 0; +} + + +/** + * Convert token 'k' to a string, append it onto 'dst' string. + */ +static void +append_token(char *dst, gl_state_index k) +{ + switch (k) { + case STATE_MATERIAL: + append(dst, "material"); + break; + case STATE_LIGHT: + append(dst, "light"); + break; + case STATE_LIGHTMODEL_AMBIENT: + append(dst, "lightmodel.ambient"); + break; + case STATE_LIGHTMODEL_SCENECOLOR: + break; + case STATE_LIGHTPROD: + append(dst, "lightprod"); + break; + case STATE_TEXGEN: + append(dst, "texgen"); + break; + case STATE_FOG_COLOR: + append(dst, "fog.color"); + break; + case STATE_FOG_PARAMS: + append(dst, "fog.params"); + break; + case STATE_CLIPPLANE: + append(dst, "clip"); + break; + case STATE_POINT_SIZE: + append(dst, "point.size"); + break; + case STATE_POINT_ATTENUATION: + append(dst, "point.attenuation"); + break; + case STATE_MODELVIEW_MATRIX: + append(dst, "matrix.modelview"); + break; + case STATE_PROJECTION_MATRIX: + append(dst, "matrix.projection"); + break; + case STATE_MVP_MATRIX: + append(dst, "matrix.mvp"); + break; + case STATE_TEXTURE_MATRIX: + append(dst, "matrix.texture"); + break; + case STATE_PROGRAM_MATRIX: + append(dst, "matrix.program"); + break; + case STATE_COLOR_MATRIX: + append(dst, "matrix.color"); + break; + case STATE_MATRIX_INVERSE: + append(dst, ".inverse"); + break; + case STATE_MATRIX_TRANSPOSE: + append(dst, ".transpose"); + break; + case STATE_MATRIX_INVTRANS: + append(dst, ".invtrans"); + break; + case STATE_AMBIENT: + append(dst, ".ambient"); + break; + case STATE_DIFFUSE: + append(dst, ".diffuse"); + break; + case STATE_SPECULAR: + append(dst, ".specular"); + break; + case STATE_EMISSION: + append(dst, ".emission"); + break; + case STATE_SHININESS: + append(dst, "lshininess"); + break; + case STATE_HALF_VECTOR: + append(dst, ".half"); + break; + case STATE_POSITION: + append(dst, ".position"); + break; + case STATE_ATTENUATION: + append(dst, ".attenuation"); + break; + case STATE_SPOT_DIRECTION: + append(dst, ".spot.direction"); + break; + case STATE_SPOT_CUTOFF: + append(dst, ".spot.cutoff"); + break; + case STATE_TEXGEN_EYE_S: + append(dst, ".eye.s"); + break; + case STATE_TEXGEN_EYE_T: + append(dst, ".eye.t"); + break; + case STATE_TEXGEN_EYE_R: + append(dst, ".eye.r"); + break; + case STATE_TEXGEN_EYE_Q: + append(dst, ".eye.q"); + break; + case STATE_TEXGEN_OBJECT_S: + append(dst, ".object.s"); + break; + case STATE_TEXGEN_OBJECT_T: + append(dst, ".object.t"); + break; + case STATE_TEXGEN_OBJECT_R: + append(dst, ".object.r"); + break; + case STATE_TEXGEN_OBJECT_Q: + append(dst, ".object.q"); + break; + case STATE_TEXENV_COLOR: + append(dst, "texenv"); + break; + case STATE_DEPTH_RANGE: + append(dst, "depth.range"); + break; + case STATE_VERTEX_PROGRAM: + case STATE_FRAGMENT_PROGRAM: + break; + case STATE_ENV: + append(dst, "env"); + break; + case STATE_LOCAL: + append(dst, "local"); + break; + /* BEGIN internal state vars */ + case STATE_INTERNAL: + append(dst, ".internal."); + break; + case STATE_CURRENT_ATTRIB: + append(dst, "current"); + break; + case STATE_NORMAL_SCALE: + append(dst, "normalScale"); + break; + case STATE_TEXRECT_SCALE: + append(dst, "texrectScale"); + break; + case STATE_FOG_PARAMS_OPTIMIZED: + append(dst, "fogParamsOptimized"); + break; + case STATE_POINT_SIZE_CLAMPED: + append(dst, "pointSizeClamped"); + break; + case STATE_POINT_SIZE_IMPL_CLAMP: + append(dst, "pointSizeImplClamp"); + break; + case STATE_LIGHT_SPOT_DIR_NORMALIZED: + append(dst, "lightSpotDirNormalized"); + break; + case STATE_LIGHT_POSITION: + append(dst, "lightPosition"); + break; + case STATE_LIGHT_POSITION_NORMALIZED: + append(dst, "light.position.normalized"); + break; + case STATE_LIGHT_HALF_VECTOR: + append(dst, "lightHalfVector"); + break; + case STATE_PT_SCALE: + append(dst, "PTscale"); + break; + case STATE_PT_BIAS: + append(dst, "PTbias"); + break; + case STATE_PCM_SCALE: + append(dst, "PCMscale"); + break; + case STATE_PCM_BIAS: + append(dst, "PCMbias"); + break; + case STATE_SHADOW_AMBIENT: + append(dst, "CompareFailValue"); + break; + case STATE_FB_SIZE: + append(dst, "FbSize"); + break; + case STATE_ROT_MATRIX_0: + append(dst, "rotMatrixRow0"); + break; + case STATE_ROT_MATRIX_1: + append(dst, "rotMatrixRow1"); + break; + default: + /* probably STATE_INTERNAL_DRIVER+i (driver private state) */ + append(dst, "driverState"); + } +} + +static void +append_face(char *dst, GLint face) +{ + if (face == 0) + append(dst, "front."); + else + append(dst, "back."); +} + +static void +append_index(char *dst, GLint index) +{ + char s[20]; + sprintf(s, "[%d]", index); + append(dst, s); +} + +/** + * Make a string from the given state vector. + * For example, return "state.matrix.texture[2].inverse". + * Use free() to deallocate the string. + */ +char * +_mesa_program_state_string(const gl_state_index state[STATE_LENGTH]) +{ + char str[1000] = ""; + char tmp[30]; + + append(str, "state."); + append_token(str, state[0]); + + switch (state[0]) { + case STATE_MATERIAL: + append_face(str, state[1]); + append_token(str, state[2]); + break; + case STATE_LIGHT: + append_index(str, state[1]); /* light number [i]. */ + append_token(str, state[2]); /* coefficients */ + break; + case STATE_LIGHTMODEL_AMBIENT: + append(str, "lightmodel.ambient"); + break; + case STATE_LIGHTMODEL_SCENECOLOR: + if (state[1] == 0) { + append(str, "lightmodel.front.scenecolor"); + } + else { + append(str, "lightmodel.back.scenecolor"); + } + break; + case STATE_LIGHTPROD: + append_index(str, state[1]); /* light number [i]. */ + append_face(str, state[2]); + append_token(str, state[3]); + break; + case STATE_TEXGEN: + append_index(str, state[1]); /* tex unit [i] */ + append_token(str, state[2]); /* plane coef */ + break; + case STATE_TEXENV_COLOR: + append_index(str, state[1]); /* tex unit [i] */ + append(str, "color"); + break; + case STATE_CLIPPLANE: + append_index(str, state[1]); /* plane [i] */ + append(str, ".plane"); + break; + case STATE_MODELVIEW_MATRIX: + case STATE_PROJECTION_MATRIX: + case STATE_MVP_MATRIX: + case STATE_TEXTURE_MATRIX: + case STATE_PROGRAM_MATRIX: + case STATE_COLOR_MATRIX: + { + /* state[0] = modelview, projection, texture, etc. */ + /* state[1] = which texture matrix or program matrix */ + /* state[2] = first row to fetch */ + /* state[3] = last row to fetch */ + /* state[4] = transpose, inverse or invtrans */ + const gl_state_index mat = state[0]; + const GLuint index = (GLuint) state[1]; + const GLuint firstRow = (GLuint) state[2]; + const GLuint lastRow = (GLuint) state[3]; + const gl_state_index modifier = state[4]; + if (index || + mat == STATE_TEXTURE_MATRIX || + mat == STATE_PROGRAM_MATRIX) + append_index(str, index); + if (modifier) + append_token(str, modifier); + if (firstRow == lastRow) + sprintf(tmp, ".row[%d]", firstRow); + else + sprintf(tmp, ".row[%d..%d]", firstRow, lastRow); + append(str, tmp); + } + break; + case STATE_POINT_SIZE: + break; + case STATE_POINT_ATTENUATION: + break; + case STATE_FOG_PARAMS: + break; + case STATE_FOG_COLOR: + break; + case STATE_DEPTH_RANGE: + break; + case STATE_FRAGMENT_PROGRAM: + case STATE_VERTEX_PROGRAM: + /* state[1] = {STATE_ENV, STATE_LOCAL} */ + /* state[2] = parameter index */ + append_token(str, state[1]); + append_index(str, state[2]); + break; + case STATE_INTERNAL: + append_token(str, state[1]); + if (state[1] == STATE_CURRENT_ATTRIB) + append_index(str, state[2]); + break; + default: + _mesa_problem(NULL, "Invalid state in _mesa_program_state_string"); + break; + } + + return _mesa_strdup(str); +} + + +/** + * Loop over all the parameters in a parameter list. If the parameter + * is a GL state reference, look up the current value of that state + * variable and put it into the parameter's Value[4] array. + * This would be called at glBegin time when using a fragment program. + */ +void +_mesa_load_state_parameters(GLcontext *ctx, + struct gl_program_parameter_list *paramList) +{ + GLuint i; + + if (!paramList) + return; + + /*assert(ctx->Driver.NeedFlush == 0);*/ + + for (i = 0; i < paramList->NumParameters; i++) { + if (paramList->Parameters[i].Type == PROGRAM_STATE_VAR) { + _mesa_fetch_state(ctx, + (gl_state_index *) paramList->Parameters[i].StateIndexes, + paramList->ParameterValues[i]); + } + } +} + + +/** + * Copy the 16 elements of a matrix into four consecutive program + * registers starting at 'pos'. + */ +static void +load_matrix(GLfloat registers[][4], GLuint pos, const GLfloat mat[16]) +{ + GLuint i; + for (i = 0; i < 4; i++) { + registers[pos + i][0] = mat[0 + i]; + registers[pos + i][1] = mat[4 + i]; + registers[pos + i][2] = mat[8 + i]; + registers[pos + i][3] = mat[12 + i]; + } +} + + +/** + * As above, but transpose the matrix. + */ +static void +load_transpose_matrix(GLfloat registers[][4], GLuint pos, + const GLfloat mat[16]) +{ + memcpy(registers[pos], mat, 16 * sizeof(GLfloat)); +} + + +/** + * Load current vertex program's parameter registers with tracked + * matrices (if NV program). This only needs to be done per + * glBegin/glEnd, not per-vertex. + */ +void +_mesa_load_tracked_matrices(GLcontext *ctx) +{ + GLuint i; + + for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) { + /* point 'mat' at source matrix */ + GLmatrix *mat; + if (ctx->VertexProgram.TrackMatrix[i] == GL_MODELVIEW) { + mat = ctx->ModelviewMatrixStack.Top; + } + else if (ctx->VertexProgram.TrackMatrix[i] == GL_PROJECTION) { + mat = ctx->ProjectionMatrixStack.Top; + } + else if (ctx->VertexProgram.TrackMatrix[i] == GL_TEXTURE) { + GLuint unit = MIN2(ctx->Texture.CurrentUnit, + Elements(ctx->TextureMatrixStack) - 1); + mat = ctx->TextureMatrixStack[unit].Top; + } + else if (ctx->VertexProgram.TrackMatrix[i] == GL_COLOR) { + mat = ctx->ColorMatrixStack.Top; + } + else if (ctx->VertexProgram.TrackMatrix[i]==GL_MODELVIEW_PROJECTION_NV) { + /* XXX verify the combined matrix is up to date */ + mat = &ctx->_ModelProjectMatrix; + } + else if (ctx->VertexProgram.TrackMatrix[i] >= GL_MATRIX0_NV && + ctx->VertexProgram.TrackMatrix[i] <= GL_MATRIX7_NV) { + GLuint n = ctx->VertexProgram.TrackMatrix[i] - GL_MATRIX0_NV; + ASSERT(n < Elements(ctx->ProgramMatrixStack)); + mat = ctx->ProgramMatrixStack[n].Top; + } + else { + /* no matrix is tracked, but we leave the register values as-is */ + assert(ctx->VertexProgram.TrackMatrix[i] == GL_NONE); + continue; + } + + /* load the matrix values into sequential registers */ + if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_IDENTITY_NV) { + load_matrix(ctx->VertexProgram.Parameters, i*4, mat->m); + } + else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_INVERSE_NV) { + _math_matrix_analyse(mat); /* update the inverse */ + ASSERT(!_math_matrix_is_dirty(mat)); + load_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv); + } + else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_TRANSPOSE_NV) { + load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->m); + } + else { + assert(ctx->VertexProgram.TrackMatrixTransform[i] + == GL_INVERSE_TRANSPOSE_NV); + _math_matrix_analyse(mat); /* update the inverse */ + ASSERT(!_math_matrix_is_dirty(mat)); + load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv); + } + } +} diff --git a/src/mesa/program/prog_statevars.h b/src/mesa/program/prog_statevars.h new file mode 100644 index 0000000000..1753471ffb --- /dev/null +++ b/src/mesa/program/prog_statevars.h @@ -0,0 +1,147 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef PROG_STATEVARS_H +#define PROG_STATEVARS_H + +#include "main/mtypes.h" + + +/** + * Number of STATE_* values we need to address any GL state. + * Used to dimension arrays. + */ +#define STATE_LENGTH 5 + + +/** + * Used for describing GL state referenced from inside ARB vertex and + * fragment programs. + * A string such as "state.light[0].ambient" gets translated into a + * sequence of tokens such as [ STATE_LIGHT, 0, STATE_AMBIENT ]. + * + * For state that's an array, like STATE_CLIPPLANE, the 2nd token [1] should + * always be the array index. + */ +typedef enum gl_state_index_ { + STATE_MATERIAL = 100, /* start at 100 so small ints are seen as ints */ + + STATE_LIGHT, + STATE_LIGHTMODEL_AMBIENT, + STATE_LIGHTMODEL_SCENECOLOR, + STATE_LIGHTPROD, + + STATE_TEXGEN, + + STATE_FOG_COLOR, + STATE_FOG_PARAMS, + + STATE_CLIPPLANE, + + STATE_POINT_SIZE, + STATE_POINT_ATTENUATION, + + STATE_MODELVIEW_MATRIX, + STATE_PROJECTION_MATRIX, + STATE_MVP_MATRIX, + STATE_TEXTURE_MATRIX, + STATE_PROGRAM_MATRIX, + STATE_COLOR_MATRIX, + STATE_MATRIX_INVERSE, + STATE_MATRIX_TRANSPOSE, + STATE_MATRIX_INVTRANS, + + STATE_AMBIENT, + STATE_DIFFUSE, + STATE_SPECULAR, + STATE_EMISSION, + STATE_SHININESS, + STATE_HALF_VECTOR, + + STATE_POSITION, /**< xyzw = position */ + STATE_ATTENUATION, /**< xyz = attenuation, w = spot exponent */ + STATE_SPOT_DIRECTION, /**< xyz = direction, w = cos(cutoff) */ + STATE_SPOT_CUTOFF, /**< x = cutoff, yzw = undefined */ + + STATE_TEXGEN_EYE_S, + STATE_TEXGEN_EYE_T, + STATE_TEXGEN_EYE_R, + STATE_TEXGEN_EYE_Q, + STATE_TEXGEN_OBJECT_S, + STATE_TEXGEN_OBJECT_T, + STATE_TEXGEN_OBJECT_R, + STATE_TEXGEN_OBJECT_Q, + + STATE_TEXENV_COLOR, + + STATE_DEPTH_RANGE, + + STATE_VERTEX_PROGRAM, + STATE_FRAGMENT_PROGRAM, + + STATE_ENV, + STATE_LOCAL, + + STATE_INTERNAL, /* Mesa additions */ + STATE_CURRENT_ATTRIB, /* ctx->Current vertex attrib value */ + STATE_NORMAL_SCALE, + STATE_TEXRECT_SCALE, + STATE_FOG_PARAMS_OPTIMIZED, /* for faster fog calc */ + STATE_POINT_SIZE_CLAMPED, /* includes implementation dependent size clamp */ + STATE_POINT_SIZE_IMPL_CLAMP, /* for implementation clamp only in vs */ + STATE_LIGHT_SPOT_DIR_NORMALIZED, /* pre-normalized spot dir */ + STATE_LIGHT_POSITION, /* object vs eye space */ + STATE_LIGHT_POSITION_NORMALIZED, /* object vs eye space */ + STATE_LIGHT_HALF_VECTOR, /* object vs eye space */ + STATE_PT_SCALE, /**< Pixel transfer RGBA scale */ + STATE_PT_BIAS, /**< Pixel transfer RGBA bias */ + STATE_PCM_SCALE, /**< Post color matrix RGBA scale */ + STATE_PCM_BIAS, /**< Post color matrix RGBA bias */ + STATE_SHADOW_AMBIENT, /**< ARB_shadow_ambient fail value; token[2] is texture unit index */ + STATE_FB_SIZE, /**< (width-1, height-1, 0, 0) */ + STATE_ROT_MATRIX_0, /**< ATI_envmap_bumpmap, rot matrix row 0 */ + STATE_ROT_MATRIX_1, /**< ATI_envmap_bumpmap, rot matrix row 1 */ + STATE_INTERNAL_DRIVER /* first available state index for drivers (must be last) */ +} gl_state_index; + + + +extern void +_mesa_load_state_parameters(GLcontext *ctx, + struct gl_program_parameter_list *paramList); + + +extern GLbitfield +_mesa_program_state_flags(const gl_state_index state[STATE_LENGTH]); + + +extern char * +_mesa_program_state_string(const gl_state_index state[STATE_LENGTH]); + + +extern void +_mesa_load_tracked_matrices(GLcontext *ctx); + + +#endif /* PROG_STATEVARS_H */ diff --git a/src/mesa/program/prog_uniform.c b/src/mesa/program/prog_uniform.c new file mode 100644 index 0000000000..c408a8492c --- /dev/null +++ b/src/mesa/program/prog_uniform.c @@ -0,0 +1,165 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file prog_uniform.c + * Shader uniform functions. + * \author Brian Paul + */ + +#include "main/imports.h" +#include "main/mtypes.h" +#include "prog_uniform.h" + + +struct gl_uniform_list * +_mesa_new_uniform_list(void) +{ + return CALLOC_STRUCT(gl_uniform_list); +} + + +void +_mesa_free_uniform_list(struct gl_uniform_list *list) +{ + GLuint i; + for (i = 0; i < list->NumUniforms; i++) { + free((void *) list->Uniforms[i].Name); + } + free(list->Uniforms); + free(list); +} + + +struct gl_uniform * +_mesa_append_uniform(struct gl_uniform_list *list, + const char *name, GLenum target, GLuint progPos) +{ + const GLuint oldNum = list->NumUniforms; + struct gl_uniform *uniform; + GLint index; + + assert(target == GL_VERTEX_PROGRAM_ARB || + target == GL_FRAGMENT_PROGRAM_ARB); + + index = _mesa_lookup_uniform(list, name); + if (index < 0) { + /* not found - append to list */ + + if (oldNum + 1 > list->Size) { + /* Need to grow the list array (alloc some extra) */ + list->Size += 4; + + /* realloc arrays */ + list->Uniforms = (struct gl_uniform *) + _mesa_realloc(list->Uniforms, + oldNum * sizeof(struct gl_uniform), + list->Size * sizeof(struct gl_uniform)); + } + + if (!list->Uniforms) { + /* out of memory */ + list->NumUniforms = 0; + list->Size = 0; + return GL_FALSE; + } + + uniform = list->Uniforms + oldNum; + + uniform->Name = _mesa_strdup(name); + uniform->VertPos = -1; + uniform->FragPos = -1; + uniform->Initialized = GL_FALSE; + + list->NumUniforms++; + } + else { + /* found */ + uniform = list->Uniforms + index; + } + + /* update position for the vertex or fragment program */ + if (target == GL_VERTEX_PROGRAM_ARB) { + if (uniform->VertPos != -1) { + /* this uniform is already in the list - that shouldn't happen */ + return GL_FALSE; + } + uniform->VertPos = progPos; + } + else { + if (uniform->FragPos != -1) { + /* this uniform is already in the list - that shouldn't happen */ + return GL_FALSE; + } + uniform->FragPos = progPos; + } + + return uniform; +} + + +/** + * Return the location/index of the named uniform in the uniform list, + * or -1 if not found. + */ +GLint +_mesa_lookup_uniform(const struct gl_uniform_list *list, const char *name) +{ + GLuint i; + for (i = 0; list && i < list->NumUniforms; i++) { + if (!strcmp(list->Uniforms[i].Name, name)) { + return i; + } + } + return -1; +} + + +GLint +_mesa_longest_uniform_name(const struct gl_uniform_list *list) +{ + GLint max = 0; + GLuint i; + for (i = 0; list && i < list->NumUniforms; i++) { + GLint len = (GLint) strlen(list->Uniforms[i].Name); + if (len > max) + max = len; + } + return max; +} + + +void +_mesa_print_uniforms(const struct gl_uniform_list *list) +{ + GLuint i; + printf("Uniform list %p:\n", (void *) list); + for (i = 0; i < list->NumUniforms; i++) { + printf("%d: %s %d %d\n", + i, + list->Uniforms[i].Name, + list->Uniforms[i].VertPos, + list->Uniforms[i].FragPos); + } +} diff --git a/src/mesa/program/prog_uniform.h b/src/mesa/program/prog_uniform.h new file mode 100644 index 0000000000..22a2bfd970 --- /dev/null +++ b/src/mesa/program/prog_uniform.h @@ -0,0 +1,92 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file prog_uniform.c + * Shader uniform functions. + * \author Brian Paul + */ + +#ifndef PROG_UNIFORM_H +#define PROG_UNIFORM_H + +#include "main/mtypes.h" +#include "prog_statevars.h" + + +/** + * Shader program uniform variable. + * The glGetUniformLocation() and glUniform() commands will use this + * information. + * Note that a uniform such as "binormal" might be used in both the + * vertex shader and the fragment shader. When glUniform() is called to + * set the uniform's value, it must be updated in both the vertex and + * fragment shaders. The uniform may be in different locations in the + * two shaders so we keep track of that here. + */ +struct gl_uniform +{ + const char *Name; /**< Null-terminated string */ + GLint VertPos; + GLint FragPos; + GLboolean Initialized; /**< For debug. Has this uniform been set? */ +#if 0 + GLenum DataType; /**< GL_FLOAT, GL_FLOAT_VEC2, etc */ + GLuint Size; /**< Number of components (1..4) */ +#endif +}; + + +/** + * List of gl_uniforms + */ +struct gl_uniform_list +{ + GLuint Size; /**< allocated size of Uniforms array */ + GLuint NumUniforms; /**< number of uniforms in the array */ + struct gl_uniform *Uniforms; /**< Array [Size] */ +}; + + +extern struct gl_uniform_list * +_mesa_new_uniform_list(void); + +extern void +_mesa_free_uniform_list(struct gl_uniform_list *list); + +extern struct gl_uniform * +_mesa_append_uniform(struct gl_uniform_list *list, + const char *name, GLenum target, GLuint progPos); + +extern GLint +_mesa_lookup_uniform(const struct gl_uniform_list *list, const char *name); + +extern GLint +_mesa_longest_uniform_name(const struct gl_uniform_list *list); + +extern void +_mesa_print_uniforms(const struct gl_uniform_list *list); + + +#endif /* PROG_UNIFORM_H */ diff --git a/src/mesa/program/program.c b/src/mesa/program/program.c new file mode 100644 index 0000000000..a6ada8a048 --- /dev/null +++ b/src/mesa/program/program.c @@ -0,0 +1,913 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file program.c + * Vertex and fragment program support functions. + * \author Brian Paul + */ + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/hash.h" +#include "program.h" +#include "prog_cache.h" +#include "prog_parameter.h" +#include "prog_instruction.h" + + +/** + * A pointer to this dummy program is put into the hash table when + * glGenPrograms is called. + */ +struct gl_program _mesa_DummyProgram; + + +/** + * Init context's vertex/fragment program state + */ +void +_mesa_init_program(GLcontext *ctx) +{ + GLuint i; + + /* + * If this assertion fails, we need to increase the field + * size for register indexes. + */ + ASSERT(ctx->Const.VertexProgram.MaxUniformComponents / 4 + <= (1 << INST_INDEX_BITS)); + ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents / 4 + <= (1 << INST_INDEX_BITS)); + + /* If this fails, increase prog_instruction::TexSrcUnit size */ + ASSERT(MAX_TEXTURE_UNITS < (1 << 5)); + + /* If this fails, increase prog_instruction::TexSrcTarget size */ + ASSERT(NUM_TEXTURE_TARGETS < (1 << 3)); + + ctx->Program.ErrorPos = -1; + ctx->Program.ErrorString = _mesa_strdup(""); + +#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program + ctx->VertexProgram.Enabled = GL_FALSE; +#if FEATURE_es2_glsl + ctx->VertexProgram.PointSizeEnabled = + (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE; +#else + ctx->VertexProgram.PointSizeEnabled = GL_FALSE; +#endif + ctx->VertexProgram.TwoSideEnabled = GL_FALSE; + _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, + ctx->Shared->DefaultVertexProgram); + assert(ctx->VertexProgram.Current); + for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) { + ctx->VertexProgram.TrackMatrix[i] = GL_NONE; + ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV; + } + ctx->VertexProgram.Cache = _mesa_new_program_cache(); +#endif + +#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program + ctx->FragmentProgram.Enabled = GL_FALSE; + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, + ctx->Shared->DefaultFragmentProgram); + assert(ctx->FragmentProgram.Current); + ctx->FragmentProgram.Cache = _mesa_new_program_cache(); +#endif + + + /* XXX probably move this stuff */ +#if FEATURE_ATI_fragment_shader + ctx->ATIFragmentShader.Enabled = GL_FALSE; + ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader; + assert(ctx->ATIFragmentShader.Current); + ctx->ATIFragmentShader.Current->RefCount++; +#endif +} + + +/** + * Free a context's vertex/fragment program state + */ +void +_mesa_free_program_data(GLcontext *ctx) +{ +#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program + _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL); + _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache); +#endif +#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL); + _mesa_delete_program_cache(ctx, ctx->FragmentProgram.Cache); +#endif + /* XXX probably move this stuff */ +#if FEATURE_ATI_fragment_shader + if (ctx->ATIFragmentShader.Current) { + ctx->ATIFragmentShader.Current->RefCount--; + if (ctx->ATIFragmentShader.Current->RefCount <= 0) { + free(ctx->ATIFragmentShader.Current); + } + } +#endif + free((void *) ctx->Program.ErrorString); +} + + +/** + * Update the default program objects in the given context to reference those + * specified in the shared state and release those referencing the old + * shared state. + */ +void +_mesa_update_default_objects_program(GLcontext *ctx) +{ +#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program + _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, + (struct gl_vertex_program *) + ctx->Shared->DefaultVertexProgram); + assert(ctx->VertexProgram.Current); +#endif + +#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, + (struct gl_fragment_program *) + ctx->Shared->DefaultFragmentProgram); + assert(ctx->FragmentProgram.Current); +#endif + + /* XXX probably move this stuff */ +#if FEATURE_ATI_fragment_shader + if (ctx->ATIFragmentShader.Current) { + ctx->ATIFragmentShader.Current->RefCount--; + if (ctx->ATIFragmentShader.Current->RefCount <= 0) { + free(ctx->ATIFragmentShader.Current); + } + } + ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader; + assert(ctx->ATIFragmentShader.Current); + ctx->ATIFragmentShader.Current->RefCount++; +#endif +} + + +/** + * Set the vertex/fragment program error state (position and error string). + * This is generally called from within the parsers. + */ +void +_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string) +{ + ctx->Program.ErrorPos = pos; + free((void *) ctx->Program.ErrorString); + if (!string) + string = ""; + ctx->Program.ErrorString = _mesa_strdup(string); +} + + +/** + * Find the line number and column for 'pos' within 'string'. + * Return a copy of the line which contains 'pos'. Free the line with + * free(). + * \param string the program string + * \param pos the position within the string + * \param line returns the line number corresponding to 'pos'. + * \param col returns the column number corresponding to 'pos'. + * \return copy of the line containing 'pos'. + */ +const GLubyte * +_mesa_find_line_column(const GLubyte *string, const GLubyte *pos, + GLint *line, GLint *col) +{ + const GLubyte *lineStart = string; + const GLubyte *p = string; + GLubyte *s; + int len; + + *line = 1; + + while (p != pos) { + if (*p == (GLubyte) '\n') { + (*line)++; + lineStart = p + 1; + } + p++; + } + + *col = (pos - lineStart) + 1; + + /* return copy of this line */ + while (*p != 0 && *p != '\n') + p++; + len = p - lineStart; + s = (GLubyte *) malloc(len + 1); + memcpy(s, lineStart, len); + s[len] = 0; + + return s; +} + + +/** + * Initialize a new vertex/fragment program object. + */ +static struct gl_program * +_mesa_init_program_struct( GLcontext *ctx, struct gl_program *prog, + GLenum target, GLuint id) +{ + (void) ctx; + if (prog) { + GLuint i; + memset(prog, 0, sizeof(*prog)); + prog->Id = id; + prog->Target = target; + prog->Resident = GL_TRUE; + prog->RefCount = 1; + prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB; + + /* default mapping from samplers to texture units */ + for (i = 0; i < MAX_SAMPLERS; i++) + prog->SamplerUnits[i] = i; + } + + return prog; +} + + +/** + * Initialize a new fragment program object. + */ +struct gl_program * +_mesa_init_fragment_program( GLcontext *ctx, struct gl_fragment_program *prog, + GLenum target, GLuint id) +{ + if (prog) + return _mesa_init_program_struct( ctx, &prog->Base, target, id ); + else + return NULL; +} + + +/** + * Initialize a new vertex program object. + */ +struct gl_program * +_mesa_init_vertex_program( GLcontext *ctx, struct gl_vertex_program *prog, + GLenum target, GLuint id) +{ + if (prog) + return _mesa_init_program_struct( ctx, &prog->Base, target, id ); + else + return NULL; +} + + +/** + * Allocate and initialize a new fragment/vertex program object but + * don't put it into the program hash table. Called via + * ctx->Driver.NewProgram. May be overridden (ie. replaced) by a + * device driver function to implement OO deriviation with additional + * types not understood by this function. + * + * \param ctx context + * \param id program id/number + * \param target program target/type + * \return pointer to new program object + */ +struct gl_program * +_mesa_new_program(GLcontext *ctx, GLenum target, GLuint id) +{ + struct gl_program *prog; + switch (target) { + case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */ + case GL_VERTEX_STATE_PROGRAM_NV: + prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program), + target, id ); + break; + case GL_FRAGMENT_PROGRAM_NV: + case GL_FRAGMENT_PROGRAM_ARB: + prog =_mesa_init_fragment_program(ctx, + CALLOC_STRUCT(gl_fragment_program), + target, id ); + break; + default: + _mesa_problem(ctx, "bad target in _mesa_new_program"); + prog = NULL; + } + return prog; +} + + +/** + * Delete a program and remove it from the hash table, ignoring the + * reference count. + * Called via ctx->Driver.DeleteProgram. May be wrapped (OO deriviation) + * by a device driver function. + */ +void +_mesa_delete_program(GLcontext *ctx, struct gl_program *prog) +{ + (void) ctx; + ASSERT(prog); + ASSERT(prog->RefCount==0); + + if (prog == &_mesa_DummyProgram) + return; + + if (prog->String) + free(prog->String); + + _mesa_free_instructions(prog->Instructions, prog->NumInstructions); + + if (prog->Parameters) { + _mesa_free_parameter_list(prog->Parameters); + } + if (prog->Varying) { + _mesa_free_parameter_list(prog->Varying); + } + if (prog->Attributes) { + _mesa_free_parameter_list(prog->Attributes); + } + + free(prog); +} + + +/** + * Return the gl_program object for a given ID. + * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of + * casts elsewhere. + */ +struct gl_program * +_mesa_lookup_program(GLcontext *ctx, GLuint id) +{ + if (id) + return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id); + else + return NULL; +} + + +/** + * Reference counting for vertex/fragment programs + */ +void +_mesa_reference_program(GLcontext *ctx, + struct gl_program **ptr, + struct gl_program *prog) +{ + assert(ptr); + if (*ptr && prog) { + /* sanity check */ + if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB) + ASSERT(prog->Target == GL_VERTEX_PROGRAM_ARB); + else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB) + ASSERT(prog->Target == GL_FRAGMENT_PROGRAM_ARB || + prog->Target == GL_FRAGMENT_PROGRAM_NV); + } + if (*ptr == prog) { + return; /* no change */ + } + if (*ptr) { + GLboolean deleteFlag; + + /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/ +#if 0 + printf("Program %p ID=%u Target=%s Refcount-- to %d\n", + *ptr, (*ptr)->Id, + ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : "FP"), + (*ptr)->RefCount - 1); +#endif + ASSERT((*ptr)->RefCount > 0); + (*ptr)->RefCount--; + + deleteFlag = ((*ptr)->RefCount == 0); + /*_glthread_UNLOCK_MUTEX((*ptr)->Mutex);*/ + + if (deleteFlag) { + ASSERT(ctx); + ctx->Driver.DeleteProgram(ctx, *ptr); + } + + *ptr = NULL; + } + + assert(!*ptr); + if (prog) { + /*_glthread_LOCK_MUTEX(prog->Mutex);*/ + prog->RefCount++; +#if 0 + printf("Program %p ID=%u Target=%s Refcount++ to %d\n", + prog, prog->Id, + (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : "FP"), + prog->RefCount); +#endif + /*_glthread_UNLOCK_MUTEX(prog->Mutex);*/ + } + + *ptr = prog; +} + + +/** + * Return a copy of a program. + * XXX Problem here if the program object is actually OO-derivation + * made by a device driver. + */ +struct gl_program * +_mesa_clone_program(GLcontext *ctx, const struct gl_program *prog) +{ + struct gl_program *clone; + + clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id); + if (!clone) + return NULL; + + assert(clone->Target == prog->Target); + assert(clone->RefCount == 1); + + clone->String = (GLubyte *) _mesa_strdup((char *) prog->String); + clone->Format = prog->Format; + clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions); + if (!clone->Instructions) { + _mesa_reference_program(ctx, &clone, NULL); + return NULL; + } + _mesa_copy_instructions(clone->Instructions, prog->Instructions, + prog->NumInstructions); + clone->InputsRead = prog->InputsRead; + clone->OutputsWritten = prog->OutputsWritten; + clone->SamplersUsed = prog->SamplersUsed; + clone->ShadowSamplers = prog->ShadowSamplers; + memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed)); + + if (prog->Parameters) + clone->Parameters = _mesa_clone_parameter_list(prog->Parameters); + memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); + if (prog->Varying) + clone->Varying = _mesa_clone_parameter_list(prog->Varying); + if (prog->Attributes) + clone->Attributes = _mesa_clone_parameter_list(prog->Attributes); + memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); + clone->NumInstructions = prog->NumInstructions; + clone->NumTemporaries = prog->NumTemporaries; + clone->NumParameters = prog->NumParameters; + clone->NumAttributes = prog->NumAttributes; + clone->NumAddressRegs = prog->NumAddressRegs; + clone->NumNativeInstructions = prog->NumNativeInstructions; + clone->NumNativeTemporaries = prog->NumNativeTemporaries; + clone->NumNativeParameters = prog->NumNativeParameters; + clone->NumNativeAttributes = prog->NumNativeAttributes; + clone->NumNativeAddressRegs = prog->NumNativeAddressRegs; + clone->NumAluInstructions = prog->NumAluInstructions; + clone->NumTexInstructions = prog->NumTexInstructions; + clone->NumTexIndirections = prog->NumTexIndirections; + clone->NumNativeAluInstructions = prog->NumNativeAluInstructions; + clone->NumNativeTexInstructions = prog->NumNativeTexInstructions; + clone->NumNativeTexIndirections = prog->NumNativeTexIndirections; + + switch (prog->Target) { + case GL_VERTEX_PROGRAM_ARB: + { + const struct gl_vertex_program *vp + = (const struct gl_vertex_program *) prog; + struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone; + vpc->IsPositionInvariant = vp->IsPositionInvariant; + vpc->IsNVProgram = vp->IsNVProgram; + } + break; + case GL_FRAGMENT_PROGRAM_ARB: + { + const struct gl_fragment_program *fp + = (const struct gl_fragment_program *) prog; + struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone; + fpc->FogOption = fp->FogOption; + fpc->UsesKill = fp->UsesKill; + fpc->OriginUpperLeft = fp->OriginUpperLeft; + fpc->PixelCenterInteger = fp->PixelCenterInteger; + } + break; + default: + _mesa_problem(NULL, "Unexpected target in _mesa_clone_program"); + } + + return clone; +} + + +/** + * Insert 'count' NOP instructions at 'start' in the given program. + * Adjust branch targets accordingly. + */ +GLboolean +_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count) +{ + const GLuint origLen = prog->NumInstructions; + const GLuint newLen = origLen + count; + struct prog_instruction *newInst; + GLuint i; + + /* adjust branches */ + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + if (inst->BranchTarget > 0) { + if ((GLuint)inst->BranchTarget >= start) { + inst->BranchTarget += count; + } + } + } + + /* Alloc storage for new instructions */ + newInst = _mesa_alloc_instructions(newLen); + if (!newInst) { + return GL_FALSE; + } + + /* Copy 'start' instructions into new instruction buffer */ + _mesa_copy_instructions(newInst, prog->Instructions, start); + + /* init the new instructions */ + _mesa_init_instructions(newInst + start, count); + + /* Copy the remaining/tail instructions to new inst buffer */ + _mesa_copy_instructions(newInst + start + count, + prog->Instructions + start, + origLen - start); + + /* free old instructions */ + _mesa_free_instructions(prog->Instructions, origLen); + + /* install new instructions */ + prog->Instructions = newInst; + prog->NumInstructions = newLen; + + return GL_TRUE; +} + +/** + * Delete 'count' instructions at 'start' in the given program. + * Adjust branch targets accordingly. + */ +GLboolean +_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count) +{ + const GLuint origLen = prog->NumInstructions; + const GLuint newLen = origLen - count; + struct prog_instruction *newInst; + GLuint i; + + /* adjust branches */ + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + if (inst->BranchTarget > 0) { + if (inst->BranchTarget > (GLint) start) { + inst->BranchTarget -= count; + } + } + } + + /* Alloc storage for new instructions */ + newInst = _mesa_alloc_instructions(newLen); + if (!newInst) { + return GL_FALSE; + } + + /* Copy 'start' instructions into new instruction buffer */ + _mesa_copy_instructions(newInst, prog->Instructions, start); + + /* Copy the remaining/tail instructions to new inst buffer */ + _mesa_copy_instructions(newInst + start, + prog->Instructions + start + count, + newLen - start); + + /* free old instructions */ + _mesa_free_instructions(prog->Instructions, origLen); + + /* install new instructions */ + prog->Instructions = newInst; + prog->NumInstructions = newLen; + + return GL_TRUE; +} + + +/** + * Search instructions for registers that match (oldFile, oldIndex), + * replacing them with (newFile, newIndex). + */ +static void +replace_registers(struct prog_instruction *inst, GLuint numInst, + GLuint oldFile, GLuint oldIndex, + GLuint newFile, GLuint newIndex) +{ + GLuint i, j; + for (i = 0; i < numInst; i++) { + /* src regs */ + for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) { + if (inst[i].SrcReg[j].File == oldFile && + inst[i].SrcReg[j].Index == oldIndex) { + inst[i].SrcReg[j].File = newFile; + inst[i].SrcReg[j].Index = newIndex; + } + } + /* dst reg */ + if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) { + inst[i].DstReg.File = newFile; + inst[i].DstReg.Index = newIndex; + } + } +} + + +/** + * Search instructions for references to program parameters. When found, + * increment the parameter index by 'offset'. + * Used when combining programs. + */ +static void +adjust_param_indexes(struct prog_instruction *inst, GLuint numInst, + GLuint offset) +{ + GLuint i, j; + for (i = 0; i < numInst; i++) { + for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) { + GLuint f = inst[i].SrcReg[j].File; + if (f == PROGRAM_CONSTANT || + f == PROGRAM_UNIFORM || + f == PROGRAM_STATE_VAR) { + inst[i].SrcReg[j].Index += offset; + } + } + } +} + + +/** + * Combine two programs into one. Fix instructions so the outputs of + * the first program go to the inputs of the second program. + */ +struct gl_program * +_mesa_combine_programs(GLcontext *ctx, + const struct gl_program *progA, + const struct gl_program *progB) +{ + struct prog_instruction *newInst; + struct gl_program *newProg; + const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */ + const GLuint lenB = progB->NumInstructions; + const GLuint numParamsA = _mesa_num_parameters(progA->Parameters); + const GLuint newLength = lenA + lenB; + GLboolean usedTemps[MAX_PROGRAM_TEMPS]; + GLuint firstTemp = 0; + GLbitfield inputsB; + GLuint i; + + ASSERT(progA->Target == progB->Target); + + newInst = _mesa_alloc_instructions(newLength); + if (!newInst) + return GL_FALSE; + + _mesa_copy_instructions(newInst, progA->Instructions, lenA); + _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB); + + /* adjust branch / instruction addresses for B's instructions */ + for (i = 0; i < lenB; i++) { + newInst[lenA + i].BranchTarget += lenA; + } + + newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0); + newProg->Instructions = newInst; + newProg->NumInstructions = newLength; + + /* find used temp regs (we may need new temps below) */ + _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY, + usedTemps, MAX_PROGRAM_TEMPS); + + if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) { + struct gl_fragment_program *fprogA, *fprogB, *newFprog; + GLbitfield progB_inputsRead = progB->InputsRead; + GLint progB_colorFile, progB_colorIndex; + + fprogA = (struct gl_fragment_program *) progA; + fprogB = (struct gl_fragment_program *) progB; + newFprog = (struct gl_fragment_program *) newProg; + + newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill; + + /* We'll do a search and replace for instances + * of progB_colorFile/progB_colorIndex below... + */ + progB_colorFile = PROGRAM_INPUT; + progB_colorIndex = FRAG_ATTRIB_COL0; + + /* + * The fragment program may get color from a state var rather than + * a fragment input (vertex output) if it's constant. + * See the texenvprogram.c code. + * So, search the program's parameter list now to see if the program + * gets color from a state var instead of a conventional fragment + * input register. + */ + for (i = 0; i < progB->Parameters->NumParameters; i++) { + struct gl_program_parameter *p = &progB->Parameters->Parameters[i]; + if (p->Type == PROGRAM_STATE_VAR && + p->StateIndexes[0] == STATE_INTERNAL && + p->StateIndexes[1] == STATE_CURRENT_ATTRIB && + p->StateIndexes[2] == VERT_ATTRIB_COLOR0) { + progB_inputsRead |= FRAG_BIT_COL0; + progB_colorFile = PROGRAM_STATE_VAR; + progB_colorIndex = i; + break; + } + } + + /* Connect color outputs of fprogA to color inputs of fprogB, via a + * new temporary register. + */ + if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) && + (progB_inputsRead & FRAG_BIT_COL0)) { + GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS, + firstTemp); + if (tempReg < 0) { + _mesa_problem(ctx, "No free temp regs found in " + "_mesa_combine_programs(), using 31"); + tempReg = 31; + } + firstTemp = tempReg + 1; + + /* replace writes to result.color[0] with tempReg */ + replace_registers(newInst, lenA, + PROGRAM_OUTPUT, FRAG_RESULT_COLOR, + PROGRAM_TEMPORARY, tempReg); + /* replace reads from the input color with tempReg */ + replace_registers(newInst + lenA, lenB, + progB_colorFile, progB_colorIndex, /* search for */ + PROGRAM_TEMPORARY, tempReg /* replace with */ ); + } + + /* compute combined program's InputsRead */ + inputsB = progB_inputsRead; + if (progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) { + inputsB &= ~(1 << FRAG_ATTRIB_COL0); + } + newProg->InputsRead = progA->InputsRead | inputsB; + newProg->OutputsWritten = progB->OutputsWritten; + newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed; + } + else { + /* vertex program */ + assert(0); /* XXX todo */ + } + + /* + * Merge parameters (uniforms, constants, etc) + */ + newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters, + progB->Parameters); + + adjust_param_indexes(newInst + lenA, lenB, numParamsA); + + + return newProg; +} + + +/** + * Populate the 'used' array with flags indicating which registers (TEMPs, + * INPUTs, OUTPUTs, etc, are used by the given program. + * \param file type of register to scan for + * \param used returns true/false flags for in use / free + * \param usedSize size of the 'used' array + */ +void +_mesa_find_used_registers(const struct gl_program *prog, + gl_register_file file, + GLboolean used[], GLuint usedSize) +{ + GLuint i, j; + + memset(used, 0, usedSize); + + for (i = 0; i < prog->NumInstructions; i++) { + const struct prog_instruction *inst = prog->Instructions + i; + const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); + + if (inst->DstReg.File == file) { + used[inst->DstReg.Index] = GL_TRUE; + } + + for (j = 0; j < n; j++) { + if (inst->SrcReg[j].File == file) { + used[inst->SrcReg[j].Index] = GL_TRUE; + } + } + } +} + + +/** + * Scan the given 'used' register flag array for the first entry + * that's >= firstReg. + * \param used vector of flags indicating registers in use (as returned + * by _mesa_find_used_registers()) + * \param usedSize size of the 'used' array + * \param firstReg first register to start searching at + * \return index of unused register, or -1 if none. + */ +GLint +_mesa_find_free_register(const GLboolean used[], + GLuint usedSize, GLuint firstReg) +{ + GLuint i; + + assert(firstReg < usedSize); + + for (i = firstReg; i < usedSize; i++) + if (!used[i]) + return i; + + return -1; +} + + +/** + * "Post-process" a GPU program. This is intended to be used for debugging. + * Example actions include no-op'ing instructions or changing instruction + * behaviour. + */ +void +_mesa_postprocess_program(GLcontext *ctx, struct gl_program *prog) +{ + static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 }; + GLuint i; + GLuint whiteSwizzle; + GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters, + white, 4, &whiteSwizzle); + + (void) whiteIndex; + + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); + + (void) n; + + if (_mesa_is_tex_instruction(inst->Opcode)) { +#if 0 + /* replace TEX/TXP/TXB with MOV */ + inst->Opcode = OPCODE_MOV; + inst->DstReg.WriteMask = WRITEMASK_XYZW; + inst->SrcReg[0].Swizzle = SWIZZLE_XYZW; + inst->SrcReg[0].Negate = NEGATE_NONE; +#endif + +#if 0 + /* disable shadow texture mode */ + inst->TexShadow = 0; +#endif + } + + if (inst->Opcode == OPCODE_TXP) { +#if 0 + inst->Opcode = OPCODE_MOV; + inst->DstReg.WriteMask = WRITEMASK_XYZW; + inst->SrcReg[0].File = PROGRAM_CONSTANT; + inst->SrcReg[0].Index = whiteIndex; + inst->SrcReg[0].Swizzle = SWIZZLE_XYZW; + inst->SrcReg[0].Negate = NEGATE_NONE; +#endif +#if 0 + inst->TexShadow = 0; +#endif +#if 0 + inst->Opcode = OPCODE_TEX; + inst->TexShadow = 0; +#endif + } + + } +} diff --git a/src/mesa/program/program.h b/src/mesa/program/program.h new file mode 100644 index 0000000000..af9f4170d1 --- /dev/null +++ b/src/mesa/program/program.h @@ -0,0 +1,151 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file program.c + * Vertex and fragment program support functions. + * \author Brian Paul + */ + + +/** + * \mainpage Mesa vertex and fragment program module + * + * This module or directory contains most of the code for vertex and + * fragment programs and shaders, including state management, parsers, + * and (some) software routines for executing programs + */ + +#ifndef PROGRAM_H +#define PROGRAM_H + +#include "main/mtypes.h" + + +extern struct gl_program _mesa_DummyProgram; + + +extern void +_mesa_init_program(GLcontext *ctx); + +extern void +_mesa_free_program_data(GLcontext *ctx); + +extern void +_mesa_update_default_objects_program(GLcontext *ctx); + +extern void +_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string); + +extern const GLubyte * +_mesa_find_line_column(const GLubyte *string, const GLubyte *pos, + GLint *line, GLint *col); + + +extern struct gl_program * +_mesa_init_vertex_program(GLcontext *ctx, + struct gl_vertex_program *prog, + GLenum target, GLuint id); + +extern struct gl_program * +_mesa_init_fragment_program(GLcontext *ctx, + struct gl_fragment_program *prog, + GLenum target, GLuint id); + +extern struct gl_program * +_mesa_new_program(GLcontext *ctx, GLenum target, GLuint id); + +extern void +_mesa_delete_program(GLcontext *ctx, struct gl_program *prog); + +extern struct gl_program * +_mesa_lookup_program(GLcontext *ctx, GLuint id); + +extern void +_mesa_reference_program(GLcontext *ctx, + struct gl_program **ptr, + struct gl_program *prog); + +static INLINE void +_mesa_reference_vertprog(GLcontext *ctx, + struct gl_vertex_program **ptr, + struct gl_vertex_program *prog) +{ + _mesa_reference_program(ctx, (struct gl_program **) ptr, + (struct gl_program *) prog); +} + +static INLINE void +_mesa_reference_fragprog(GLcontext *ctx, + struct gl_fragment_program **ptr, + struct gl_fragment_program *prog) +{ + _mesa_reference_program(ctx, (struct gl_program **) ptr, + (struct gl_program *) prog); +} + +extern struct gl_program * +_mesa_clone_program(GLcontext *ctx, const struct gl_program *prog); + +static INLINE struct gl_vertex_program * +_mesa_clone_vertex_program(GLcontext *ctx, + const struct gl_vertex_program *prog) +{ + return (struct gl_vertex_program *) _mesa_clone_program(ctx, &prog->Base); +} + + +static INLINE struct gl_fragment_program * +_mesa_clone_fragment_program(GLcontext *ctx, + const struct gl_fragment_program *prog) +{ + return (struct gl_fragment_program *) _mesa_clone_program(ctx, &prog->Base); +} + + +extern GLboolean +_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count); + +extern GLboolean +_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count); + +extern struct gl_program * +_mesa_combine_programs(GLcontext *ctx, + const struct gl_program *progA, + const struct gl_program *progB); + +extern void +_mesa_find_used_registers(const struct gl_program *prog, + gl_register_file file, + GLboolean used[], GLuint usedSize); + +extern GLint +_mesa_find_free_register(const GLboolean used[], + GLuint maxRegs, GLuint firstReg); + +extern void +_mesa_postprocess_program(GLcontext *ctx, struct gl_program *prog); + + +#endif /* PROGRAM_H */ diff --git a/src/mesa/program/program_lexer.l b/src/mesa/program/program_lexer.l new file mode 100644 index 0000000000..5730c6d761 --- /dev/null +++ b/src/mesa/program/program_lexer.l @@ -0,0 +1,494 @@ +%{ +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "main/glheader.h" +#include "main/imports.h" +#include "program/prog_instruction.h" +#include "program/prog_statevars.h" +#include "program/symbol_table.h" +#include "program/program_parser.h" +#include "program/program_parse.tab.h" + +#define require_ARB_vp (yyextra->mode == ARB_vertex) +#define require_ARB_fp (yyextra->mode == ARB_fragment) +#define require_NV_fp (yyextra->option.NV_fragment) +#define require_shadow (yyextra->option.Shadow) +#define require_rect (yyextra->option.TexRect) +#define require_texarray (yyextra->option.TexArray) + +#ifndef HAVE_UNISTD_H +#define YY_NO_UNISTD_H +#endif + +#define return_token_or_IDENTIFIER(condition, token) \ + do { \ + if (condition) { \ + return token; \ + } else { \ + return handle_ident(yyextra, yytext, yylval); \ + } \ + } while (0) + +#define return_token_or_DOT(condition, token) \ + do { \ + if (condition) { \ + return token; \ + } else { \ + yyless(1); \ + return DOT; \ + } \ + } while (0) + + +#define return_opcode(condition, token, opcode, len) \ + do { \ + if (condition && \ + _mesa_parse_instruction_suffix(yyextra, \ + yytext + len, \ + & yylval->temp_inst)) { \ + yylval->temp_inst.Opcode = OPCODE_ ## opcode; \ + return token; \ + } else { \ + return handle_ident(yyextra, yytext, yylval); \ + } \ + } while (0) + +#define SWIZZLE_INVAL MAKE_SWIZZLE4(SWIZZLE_NIL, SWIZZLE_NIL, \ + SWIZZLE_NIL, SWIZZLE_NIL) + +static unsigned +mask_from_char(char c) +{ + switch (c) { + case 'x': + case 'r': + return WRITEMASK_X; + case 'y': + case 'g': + return WRITEMASK_Y; + case 'z': + case 'b': + return WRITEMASK_Z; + case 'w': + case 'a': + return WRITEMASK_W; + } + + return 0; +} + +static unsigned +swiz_from_char(char c) +{ + switch (c) { + case 'x': + case 'r': + return SWIZZLE_X; + case 'y': + case 'g': + return SWIZZLE_Y; + case 'z': + case 'b': + return SWIZZLE_Z; + case 'w': + case 'a': + return SWIZZLE_W; + } + + return 0; +} + +static int +handle_ident(struct asm_parser_state *state, const char *text, YYSTYPE *lval) +{ + lval->string = strdup(text); + + return (_mesa_symbol_table_find_symbol(state->st, 0, text) == NULL) + ? IDENTIFIER : USED_IDENTIFIER; +} + +#define YY_USER_ACTION \ + do { \ + yylloc->first_column = yylloc->last_column; \ + yylloc->last_column += yyleng; \ + if ((yylloc->first_line == 1) \ + && (yylloc->first_column == 1)) { \ + yylloc->position = 1; \ + } else { \ + yylloc->position += yylloc->last_column - yylloc->first_column; \ + } \ + } while(0); + +#define YY_EXTRA_TYPE struct asm_parser_state * +%} + +num [0-9]+ +exp [Ee][-+]?[0-9]+ +frac "."[0-9]+ +dot "."[ \t]* + +sz [HRX]? +szf [HR]? +cc C? +sat (_SAT)? + +%option bison-bridge bison-locations reentrant noyywrap +%% + +"!!ARBvp1.0" { return ARBvp_10; } +"!!ARBfp1.0" { return ARBfp_10; } +ADDRESS { + yylval->integer = at_address; + return_token_or_IDENTIFIER(require_ARB_vp, ADDRESS); +} +ALIAS { return ALIAS; } +ATTRIB { return ATTRIB; } +END { return END; } +OPTION { return OPTION; } +OUTPUT { return OUTPUT; } +PARAM { return PARAM; } +TEMP { yylval->integer = at_temp; return TEMP; } + +ABS{sz}{cc}{sat} { return_opcode( 1, VECTOR_OP, ABS, 3); } +ADD{sz}{cc}{sat} { return_opcode( 1, BIN_OP, ADD, 3); } +ARL { return_opcode(require_ARB_vp, ARL, ARL, 3); } + +CMP{sat} { return_opcode(require_ARB_fp, TRI_OP, CMP, 3); } +COS{szf}{cc}{sat} { return_opcode(require_ARB_fp, SCALAR_OP, COS, 3); } + +DDX{szf}{cc}{sat} { return_opcode(require_NV_fp, VECTOR_OP, DDX, 3); } +DDY{szf}{cc}{sat} { return_opcode(require_NV_fp, VECTOR_OP, DDY, 3); } +DP3{sz}{cc}{sat} { return_opcode( 1, BIN_OP, DP3, 3); } +DP4{sz}{cc}{sat} { return_opcode( 1, BIN_OP, DP4, 3); } +DPH{sz}{cc}{sat} { return_opcode( 1, BIN_OP, DPH, 3); } +DST{szf}{cc}{sat} { return_opcode( 1, BIN_OP, DST, 3); } + +EX2{szf}{cc}{sat} { return_opcode( 1, SCALAR_OP, EX2, 3); } +EXP { return_opcode(require_ARB_vp, SCALAR_OP, EXP, 3); } + +FLR{sz}{cc}{sat} { return_opcode( 1, VECTOR_OP, FLR, 3); } +FRC{sz}{cc}{sat} { return_opcode( 1, VECTOR_OP, FRC, 3); } + +KIL { return_opcode(require_ARB_fp, KIL, KIL, 3); } + +LIT{szf}{cc}{sat} { return_opcode( 1, VECTOR_OP, LIT, 3); } +LG2{szf}{cc}{sat} { return_opcode( 1, SCALAR_OP, LG2, 3); } +LOG { return_opcode(require_ARB_vp, SCALAR_OP, LOG, 3); } +LRP{sz}{cc}{sat} { return_opcode(require_ARB_fp, TRI_OP, LRP, 3); } + +MAD{sz}{cc}{sat} { return_opcode( 1, TRI_OP, MAD, 3); } +MAX{sz}{cc}{sat} { return_opcode( 1, BIN_OP, MAX, 3); } +MIN{sz}{cc}{sat} { return_opcode( 1, BIN_OP, MIN, 3); } +MOV{sz}{cc}{sat} { return_opcode( 1, VECTOR_OP, MOV, 3); } +MUL{sz}{cc}{sat} { return_opcode( 1, BIN_OP, MUL, 3); } + +PK2H { return_opcode(require_NV_fp, VECTOR_OP, PK2H, 4); } +PK2US { return_opcode(require_NV_fp, VECTOR_OP, PK2US, 5); } +PK4B { return_opcode(require_NV_fp, VECTOR_OP, PK4B, 4); } +PK4UB { return_opcode(require_NV_fp, VECTOR_OP, PK4UB, 5); } +POW{szf}{cc}{sat} { return_opcode( 1, BINSC_OP, POW, 3); } + +RCP{szf}{cc}{sat} { return_opcode( 1, SCALAR_OP, RCP, 3); } +RFL{szf}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, RFL, 3); } +RSQ{szf}{cc}{sat} { return_opcode( 1, SCALAR_OP, RSQ, 3); } + +SCS{sat} { return_opcode(require_ARB_fp, SCALAR_OP, SCS, 3); } +SEQ{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SEQ, 3); } +SFL{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SFL, 3); } +SGE{sz}{cc}{sat} { return_opcode( 1, BIN_OP, SGE, 3); } +SGT{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SGT, 3); } +SIN{szf}{cc}{sat} { return_opcode(require_ARB_fp, SCALAR_OP, SIN, 3); } +SLE{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SLE, 3); } +SLT{sz}{cc}{sat} { return_opcode( 1, BIN_OP, SLT, 3); } +SNE{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SNE, 3); } +STR{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, STR, 3); } +SUB{sz}{cc}{sat} { return_opcode( 1, BIN_OP, SUB, 3); } +SWZ{sat} { return_opcode( 1, SWZ, SWZ, 3); } + +TEX{cc}{sat} { return_opcode(require_ARB_fp, SAMPLE_OP, TEX, 3); } +TXB{cc}{sat} { return_opcode(require_ARB_fp, SAMPLE_OP, TXB, 3); } +TXD{cc}{sat} { return_opcode(require_NV_fp, TXD_OP, TXD, 3); } +TXP{cc}{sat} { return_opcode(require_ARB_fp, SAMPLE_OP, TXP, 3); } + +UP2H{cc}{sat} { return_opcode(require_NV_fp, SCALAR_OP, UP2H, 4); } +UP2US{cc}{sat} { return_opcode(require_NV_fp, SCALAR_OP, UP2US, 5); } +UP4B{cc}{sat} { return_opcode(require_NV_fp, SCALAR_OP, UP4B, 4); } +UP4UB{cc}{sat} { return_opcode(require_NV_fp, SCALAR_OP, UP4UB, 5); } + +X2D{szf}{cc}{sat} { return_opcode(require_NV_fp, TRI_OP, X2D, 3); } +XPD{sat} { return_opcode( 1, BIN_OP, XPD, 3); } + +vertex { return_token_or_IDENTIFIER(require_ARB_vp, VERTEX); } +fragment { return_token_or_IDENTIFIER(require_ARB_fp, FRAGMENT); } +program { return PROGRAM; } +state { return STATE; } +result { return RESULT; } + +{dot}ambient { return AMBIENT; } +{dot}attenuation { return ATTENUATION; } +{dot}back { return BACK; } +{dot}clip { return_token_or_DOT(require_ARB_vp, CLIP); } +{dot}color { return COLOR; } +{dot}depth { return_token_or_DOT(require_ARB_fp, DEPTH); } +{dot}diffuse { return DIFFUSE; } +{dot}direction { return DIRECTION; } +{dot}emission { return EMISSION; } +{dot}env { return ENV; } +{dot}eye { return EYE; } +{dot}fogcoord { return FOGCOORD; } +{dot}fog { return FOG; } +{dot}front { return FRONT; } +{dot}half { return HALF; } +{dot}inverse { return INVERSE; } +{dot}invtrans { return INVTRANS; } +{dot}light { return LIGHT; } +{dot}lightmodel { return LIGHTMODEL; } +{dot}lightprod { return LIGHTPROD; } +{dot}local { return LOCAL; } +{dot}material { return MATERIAL; } +{dot}program { return MAT_PROGRAM; } +{dot}matrix { return MATRIX; } +{dot}matrixindex { return_token_or_DOT(require_ARB_vp, MATRIXINDEX); } +{dot}modelview { return MODELVIEW; } +{dot}mvp { return MVP; } +{dot}normal { return_token_or_DOT(require_ARB_vp, NORMAL); } +{dot}object { return OBJECT; } +{dot}palette { return PALETTE; } +{dot}params { return PARAMS; } +{dot}plane { return PLANE; } +{dot}point { return_token_or_DOT(require_ARB_vp, POINT_TOK); } +{dot}pointsize { return_token_or_DOT(require_ARB_vp, POINTSIZE); } +{dot}position { return POSITION; } +{dot}primary { return PRIMARY; } +{dot}projection { return PROJECTION; } +{dot}range { return_token_or_DOT(require_ARB_fp, RANGE); } +{dot}row { return ROW; } +{dot}scenecolor { return SCENECOLOR; } +{dot}secondary { return SECONDARY; } +{dot}shininess { return SHININESS; } +{dot}size { return_token_or_DOT(require_ARB_vp, SIZE_TOK); } +{dot}specular { return SPECULAR; } +{dot}spot { return SPOT; } +{dot}texcoord { return TEXCOORD; } +{dot}texenv { return_token_or_DOT(require_ARB_fp, TEXENV); } +{dot}texgen { return_token_or_DOT(require_ARB_vp, TEXGEN); } +{dot}q { return_token_or_DOT(require_ARB_vp, TEXGEN_Q); } +{dot}s { return_token_or_DOT(require_ARB_vp, TEXGEN_S); } +{dot}t { return_token_or_DOT(require_ARB_vp, TEXGEN_T); } +{dot}texture { return TEXTURE; } +{dot}transpose { return TRANSPOSE; } +{dot}attrib { return_token_or_DOT(require_ARB_vp, VTXATTRIB); } +{dot}weight { return_token_or_DOT(require_ARB_vp, WEIGHT); } + +texture { return_token_or_IDENTIFIER(require_ARB_fp, TEXTURE_UNIT); } +1D { return_token_or_IDENTIFIER(require_ARB_fp, TEX_1D); } +2D { return_token_or_IDENTIFIER(require_ARB_fp, TEX_2D); } +3D { return_token_or_IDENTIFIER(require_ARB_fp, TEX_3D); } +CUBE { return_token_or_IDENTIFIER(require_ARB_fp, TEX_CUBE); } +RECT { return_token_or_IDENTIFIER(require_ARB_fp && require_rect, TEX_RECT); } +SHADOW1D { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow, TEX_SHADOW1D); } +SHADOW2D { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow, TEX_SHADOW2D); } +SHADOWRECT { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_rect, TEX_SHADOWRECT); } +ARRAY1D { return_token_or_IDENTIFIER(require_ARB_fp && require_texarray, TEX_ARRAY1D); } +ARRAY2D { return_token_or_IDENTIFIER(require_ARB_fp && require_texarray, TEX_ARRAY2D); } +ARRAYSHADOW1D { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_texarray, TEX_ARRAYSHADOW1D); } +ARRAYSHADOW2D { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_texarray, TEX_ARRAYSHADOW2D); } + +[_a-zA-Z$][_a-zA-Z0-9$]* { return handle_ident(yyextra, yytext, yylval); } + +".." { return DOT_DOT; } + +{num} { + yylval->integer = strtol(yytext, NULL, 10); + return INTEGER; +} +{num}?{frac}{exp}? { + yylval->real = _mesa_strtof(yytext, NULL); + return REAL; +} +{num}"."/[^.] { + yylval->real = _mesa_strtof(yytext, NULL); + return REAL; +} +{num}{exp} { + yylval->real = _mesa_strtof(yytext, NULL); + return REAL; +} +{num}"."{exp} { + yylval->real = _mesa_strtof(yytext, NULL); + return REAL; +} + +".xyzw" { + yylval->swiz_mask.swizzle = SWIZZLE_NOOP; + yylval->swiz_mask.mask = WRITEMASK_XYZW; + return MASK4; +} + +".xy"[zw] { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XY + | mask_from_char(yytext[3]); + return MASK3; +} +".xzw" { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XZW; + return MASK3; +} +".yzw" { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_YZW; + return MASK3; +} + +".x"[yzw] { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_X + | mask_from_char(yytext[2]); + return MASK2; +} +".y"[zw] { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_Y + | mask_from_char(yytext[2]); + return MASK2; +} +".zw" { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_ZW; + return MASK2; +} + +"."[xyzw] { + const unsigned s = swiz_from_char(yytext[1]); + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(s, s, s, s); + yylval->swiz_mask.mask = mask_from_char(yytext[1]); + return MASK1; +} + +"."[xyzw]{4} { + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(swiz_from_char(yytext[1]), + swiz_from_char(yytext[2]), + swiz_from_char(yytext[3]), + swiz_from_char(yytext[4])); + yylval->swiz_mask.mask = 0; + return SWIZZLE; +} + +".rgba" { + yylval->swiz_mask.swizzle = SWIZZLE_NOOP; + yylval->swiz_mask.mask = WRITEMASK_XYZW; + return_token_or_DOT(require_ARB_fp, MASK4); +} + +".rg"[ba] { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XY + | mask_from_char(yytext[3]); + return_token_or_DOT(require_ARB_fp, MASK3); +} +".rba" { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XZW; + return_token_or_DOT(require_ARB_fp, MASK3); +} +".gba" { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_YZW; + return_token_or_DOT(require_ARB_fp, MASK3); +} + +".r"[gba] { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_X + | mask_from_char(yytext[2]); + return_token_or_DOT(require_ARB_fp, MASK2); +} +".g"[ba] { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_Y + | mask_from_char(yytext[2]); + return_token_or_DOT(require_ARB_fp, MASK2); +} +".ba" { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_ZW; + return_token_or_DOT(require_ARB_fp, MASK2); +} + +"."[gba] { + const unsigned s = swiz_from_char(yytext[1]); + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(s, s, s, s); + yylval->swiz_mask.mask = mask_from_char(yytext[1]); + return_token_or_DOT(require_ARB_fp, MASK1); +} + + +".r" { + if (require_ARB_vp) { + return TEXGEN_R; + } else { + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, + SWIZZLE_X, SWIZZLE_X); + yylval->swiz_mask.mask = WRITEMASK_X; + return MASK1; + } +} + +"."[rgba]{4} { + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(swiz_from_char(yytext[1]), + swiz_from_char(yytext[2]), + swiz_from_char(yytext[3]), + swiz_from_char(yytext[4])); + yylval->swiz_mask.mask = 0; + return_token_or_DOT(require_ARB_fp, SWIZZLE); +} + +"." { return DOT; } + +\n { + yylloc->first_line++; + yylloc->first_column = 1; + yylloc->last_line++; + yylloc->last_column = 1; + yylloc->position++; +} +[ \t\r]+ /* eat whitespace */ ; +#.*$ /* eat comments */ ; +. { return yytext[0]; } +%% + +void +_mesa_program_lexer_ctor(void **scanner, struct asm_parser_state *state, + const char *string, size_t len) +{ + yylex_init_extra(state, scanner); + yy_scan_bytes(string, len, *scanner); +} + +void +_mesa_program_lexer_dtor(void *scanner) +{ + yylex_destroy(scanner); +} diff --git a/src/mesa/program/program_parse.tab.c b/src/mesa/program/program_parse.tab.c new file mode 100644 index 0000000000..6421d1f58a --- /dev/null +++ b/src/mesa/program/program_parse.tab.c @@ -0,0 +1,5729 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 1 + + + +/* Copy the first part of user declarations. */ + +/* Line 189 of yacc.c */ +#line 1 "program_parse.y" + +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include +#include +#include + +#include "main/mtypes.h" +#include "main/imports.h" +#include "program/program.h" +#include "program/prog_parameter.h" +#include "program/prog_parameter_layout.h" +#include "program/prog_statevars.h" +#include "program/prog_instruction.h" + +#include "program/symbol_table.h" +#include "program/program_parser.h" + +extern void *yy_scan_string(char *); +extern void yy_delete_buffer(void *); + +static struct asm_symbol *declare_variable(struct asm_parser_state *state, + char *name, enum asm_type t, struct YYLTYPE *locp); + +static int add_state_reference(struct gl_program_parameter_list *param_list, + const gl_state_index tokens[STATE_LENGTH]); + +static int initialize_symbol_from_state(struct gl_program *prog, + struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]); + +static int initialize_symbol_from_param(struct gl_program *prog, + struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]); + +static int initialize_symbol_from_const(struct gl_program *prog, + struct asm_symbol *param_var, const struct asm_vector *vec, + GLboolean allowSwizzle); + +static int yyparse(struct asm_parser_state *state); + +static char *make_error_string(const char *fmt, ...); + +static void yyerror(struct YYLTYPE *locp, struct asm_parser_state *state, + const char *s); + +static int validate_inputs(struct YYLTYPE *locp, + struct asm_parser_state *state); + +static void init_dst_reg(struct prog_dst_register *r); + +static void set_dst_reg(struct prog_dst_register *r, + gl_register_file file, GLint index); + +static void init_src_reg(struct asm_src_register *r); + +static void set_src_reg(struct asm_src_register *r, + gl_register_file file, GLint index); + +static void set_src_reg_swz(struct asm_src_register *r, + gl_register_file file, GLint index, GLuint swizzle); + +static void asm_instruction_set_operands(struct asm_instruction *inst, + const struct prog_dst_register *dst, const struct asm_src_register *src0, + const struct asm_src_register *src1, const struct asm_src_register *src2); + +static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op, + const struct prog_dst_register *dst, const struct asm_src_register *src0, + const struct asm_src_register *src1, const struct asm_src_register *src2); + +static struct asm_instruction *asm_instruction_copy_ctor( + const struct prog_instruction *base, const struct prog_dst_register *dst, + const struct asm_src_register *src0, const struct asm_src_register *src1, + const struct asm_src_register *src2); + +#ifndef FALSE +#define FALSE 0 +#define TRUE (!FALSE) +#endif + +#define YYLLOC_DEFAULT(Current, Rhs, N) \ + do { \ + if (YYID(N)) { \ + (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ + (Current).position = YYRHSLOC(Rhs, 1).position; \ + (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC(Rhs, N).last_column; \ + } else { \ + (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \ + (Current).last_line = (Current).first_line; \ + (Current).first_column = YYRHSLOC(Rhs, 0).last_column; \ + (Current).last_column = (Current).first_column; \ + (Current).position = YYRHSLOC(Rhs, 0).position \ + + (Current).first_column; \ + } \ + } while(YYID(0)) + +#define YYLEX_PARAM state->scanner + + +/* Line 189 of yacc.c */ +#line 193 "program_parse.tab.c" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 1 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + ARBvp_10 = 258, + ARBfp_10 = 259, + ADDRESS = 260, + ALIAS = 261, + ATTRIB = 262, + OPTION = 263, + OUTPUT = 264, + PARAM = 265, + TEMP = 266, + END = 267, + BIN_OP = 268, + BINSC_OP = 269, + SAMPLE_OP = 270, + SCALAR_OP = 271, + TRI_OP = 272, + VECTOR_OP = 273, + ARL = 274, + KIL = 275, + SWZ = 276, + TXD_OP = 277, + INTEGER = 278, + REAL = 279, + AMBIENT = 280, + ATTENUATION = 281, + BACK = 282, + CLIP = 283, + COLOR = 284, + DEPTH = 285, + DIFFUSE = 286, + DIRECTION = 287, + EMISSION = 288, + ENV = 289, + EYE = 290, + FOG = 291, + FOGCOORD = 292, + FRAGMENT = 293, + FRONT = 294, + HALF = 295, + INVERSE = 296, + INVTRANS = 297, + LIGHT = 298, + LIGHTMODEL = 299, + LIGHTPROD = 300, + LOCAL = 301, + MATERIAL = 302, + MAT_PROGRAM = 303, + MATRIX = 304, + MATRIXINDEX = 305, + MODELVIEW = 306, + MVP = 307, + NORMAL = 308, + OBJECT = 309, + PALETTE = 310, + PARAMS = 311, + PLANE = 312, + POINT_TOK = 313, + POINTSIZE = 314, + POSITION = 315, + PRIMARY = 316, + PROGRAM = 317, + PROJECTION = 318, + RANGE = 319, + RESULT = 320, + ROW = 321, + SCENECOLOR = 322, + SECONDARY = 323, + SHININESS = 324, + SIZE_TOK = 325, + SPECULAR = 326, + SPOT = 327, + STATE = 328, + TEXCOORD = 329, + TEXENV = 330, + TEXGEN = 331, + TEXGEN_Q = 332, + TEXGEN_R = 333, + TEXGEN_S = 334, + TEXGEN_T = 335, + TEXTURE = 336, + TRANSPOSE = 337, + TEXTURE_UNIT = 338, + TEX_1D = 339, + TEX_2D = 340, + TEX_3D = 341, + TEX_CUBE = 342, + TEX_RECT = 343, + TEX_SHADOW1D = 344, + TEX_SHADOW2D = 345, + TEX_SHADOWRECT = 346, + TEX_ARRAY1D = 347, + TEX_ARRAY2D = 348, + TEX_ARRAYSHADOW1D = 349, + TEX_ARRAYSHADOW2D = 350, + VERTEX = 351, + VTXATTRIB = 352, + WEIGHT = 353, + IDENTIFIER = 354, + USED_IDENTIFIER = 355, + MASK4 = 356, + MASK3 = 357, + MASK2 = 358, + MASK1 = 359, + SWIZZLE = 360, + DOT_DOT = 361, + DOT = 362 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 214 of yacc.c */ +#line 126 "program_parse.y" + + struct asm_instruction *inst; + struct asm_symbol *sym; + struct asm_symbol temp_sym; + struct asm_swizzle_mask swiz_mask; + struct asm_src_register src_reg; + struct prog_dst_register dst_reg; + struct prog_instruction temp_inst; + char *string; + unsigned result; + unsigned attrib; + int integer; + float real; + gl_state_index state[STATE_LENGTH]; + int negate; + struct asm_vector vector; + gl_inst_opcode opcode; + + struct { + unsigned swz; + unsigned rgba_valid:1; + unsigned xyzw_valid:1; + unsigned negate:1; + } ext_swizzle; + + + +/* Line 214 of yacc.c */ +#line 364 "program_parse.tab.c" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + +/* Copy the second part of user declarations. */ + +/* Line 264 of yacc.c */ +#line 271 "program_parse.y" + +extern int yylex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param, + void *yyscanner); + + +/* Line 264 of yacc.c */ +#line 395 "program_parse.tab.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; + YYLTYPE yyls_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 5 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 396 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 120 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 143 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 282 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 475 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 362 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 115, 116, 2, 113, 109, 114, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 108, + 2, 117, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 111, 2, 112, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 118, 110, 119, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 8, 10, 12, 15, 16, 20, 23, + 24, 27, 30, 32, 34, 36, 38, 40, 42, 44, + 46, 48, 50, 52, 54, 59, 64, 69, 76, 83, + 92, 101, 104, 107, 120, 123, 125, 127, 129, 131, + 133, 135, 137, 139, 141, 143, 145, 147, 154, 157, + 162, 165, 167, 171, 177, 181, 184, 192, 195, 197, + 199, 201, 203, 208, 210, 212, 214, 216, 218, 220, + 222, 226, 227, 230, 233, 235, 237, 239, 241, 243, + 245, 247, 249, 251, 252, 254, 256, 258, 260, 261, + 265, 269, 270, 273, 276, 278, 280, 282, 284, 286, + 288, 290, 292, 297, 300, 303, 305, 308, 310, 313, + 315, 318, 323, 328, 330, 331, 335, 337, 339, 342, + 344, 347, 349, 351, 355, 362, 363, 365, 368, 373, + 375, 379, 381, 383, 385, 387, 389, 391, 393, 395, + 397, 399, 402, 405, 408, 411, 414, 417, 420, 423, + 426, 429, 432, 435, 439, 441, 443, 445, 451, 453, + 455, 457, 460, 462, 464, 467, 469, 472, 479, 481, + 485, 487, 489, 491, 493, 495, 500, 502, 504, 506, + 508, 510, 512, 515, 517, 519, 525, 527, 530, 532, + 534, 540, 543, 544, 551, 555, 556, 558, 560, 562, + 564, 566, 569, 571, 573, 576, 581, 586, 587, 591, + 593, 595, 597, 600, 602, 604, 606, 608, 614, 616, + 620, 626, 632, 634, 638, 644, 646, 648, 650, 652, + 654, 656, 658, 660, 662, 666, 672, 680, 690, 693, + 696, 698, 700, 701, 702, 707, 709, 710, 711, 715, + 719, 721, 727, 730, 733, 736, 739, 743, 746, 750, + 751, 753, 755, 756, 758, 760, 761, 763, 765, 766, + 768, 770, 771, 775, 776, 780, 781, 785, 787, 789, + 791, 796, 798 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int16 yyrhs[] = +{ + 121, 0, -1, 122, 123, 125, 12, -1, 3, -1, + 4, -1, 123, 124, -1, -1, 8, 262, 108, -1, + 125, 126, -1, -1, 127, 108, -1, 170, 108, -1, + 128, -1, 129, -1, 130, -1, 131, -1, 132, -1, + 133, -1, 134, -1, 135, -1, 141, -1, 136, -1, + 137, -1, 138, -1, 19, 146, 109, 142, -1, 18, + 145, 109, 144, -1, 16, 145, 109, 142, -1, 14, + 145, 109, 142, 109, 142, -1, 13, 145, 109, 144, + 109, 144, -1, 17, 145, 109, 144, 109, 144, 109, + 144, -1, 15, 145, 109, 144, 109, 139, 109, 140, + -1, 20, 144, -1, 20, 166, -1, 22, 145, 109, + 144, 109, 144, 109, 144, 109, 139, 109, 140, -1, + 83, 256, -1, 84, -1, 85, -1, 86, -1, 87, + -1, 88, -1, 89, -1, 90, -1, 91, -1, 92, + -1, 93, -1, 94, -1, 95, -1, 21, 145, 109, + 150, 109, 147, -1, 241, 143, -1, 241, 110, 143, + 110, -1, 150, 162, -1, 238, -1, 241, 150, 163, + -1, 241, 110, 150, 163, 110, -1, 151, 164, 165, + -1, 159, 161, -1, 148, 109, 148, 109, 148, 109, + 148, -1, 241, 149, -1, 23, -1, 262, -1, 100, + -1, 172, -1, 152, 111, 153, 112, -1, 186, -1, + 249, -1, 100, -1, 100, -1, 154, -1, 155, -1, + 23, -1, 159, 160, 156, -1, -1, 113, 157, -1, + 114, 158, -1, 23, -1, 23, -1, 100, -1, 104, + -1, 104, -1, 104, -1, 104, -1, 101, -1, 105, + -1, -1, 101, -1, 102, -1, 103, -1, 104, -1, + -1, 115, 166, 116, -1, 115, 167, 116, -1, -1, + 168, 163, -1, 169, 163, -1, 99, -1, 100, -1, + 171, -1, 178, -1, 242, -1, 245, -1, 248, -1, + 261, -1, 7, 99, 117, 172, -1, 96, 173, -1, + 38, 177, -1, 60, -1, 98, 175, -1, 53, -1, + 29, 254, -1, 37, -1, 74, 255, -1, 50, 111, + 176, 112, -1, 97, 111, 174, 112, -1, 23, -1, + -1, 111, 176, 112, -1, 23, -1, 60, -1, 29, + 254, -1, 37, -1, 74, 255, -1, 179, -1, 180, + -1, 10, 99, 182, -1, 10, 99, 111, 181, 112, + 183, -1, -1, 23, -1, 117, 185, -1, 117, 118, + 184, 119, -1, 187, -1, 184, 109, 187, -1, 189, + -1, 225, -1, 235, -1, 189, -1, 225, -1, 236, + -1, 188, -1, 226, -1, 235, -1, 189, -1, 73, + 213, -1, 73, 190, -1, 73, 192, -1, 73, 195, + -1, 73, 197, -1, 73, 203, -1, 73, 199, -1, + 73, 206, -1, 73, 208, -1, 73, 210, -1, 73, + 212, -1, 73, 224, -1, 47, 253, 191, -1, 201, + -1, 33, -1, 69, -1, 43, 111, 202, 112, 193, + -1, 201, -1, 60, -1, 26, -1, 72, 194, -1, + 40, -1, 32, -1, 44, 196, -1, 25, -1, 253, + 67, -1, 45, 111, 202, 112, 253, 198, -1, 201, + -1, 75, 257, 200, -1, 29, -1, 25, -1, 31, + -1, 71, -1, 23, -1, 76, 255, 204, 205, -1, + 35, -1, 54, -1, 79, -1, 80, -1, 78, -1, + 77, -1, 36, 207, -1, 29, -1, 56, -1, 28, + 111, 209, 112, 57, -1, 23, -1, 58, 211, -1, + 70, -1, 26, -1, 215, 66, 111, 218, 112, -1, + 215, 214, -1, -1, 66, 111, 218, 106, 218, 112, + -1, 49, 219, 216, -1, -1, 217, -1, 41, -1, + 82, -1, 42, -1, 23, -1, 51, 220, -1, 63, + -1, 52, -1, 81, 255, -1, 55, 111, 222, 112, + -1, 48, 111, 223, 112, -1, -1, 111, 221, 112, + -1, 23, -1, 23, -1, 23, -1, 30, 64, -1, + 229, -1, 232, -1, 227, -1, 230, -1, 62, 34, + 111, 228, 112, -1, 233, -1, 233, 106, 233, -1, + 62, 34, 111, 233, 112, -1, 62, 46, 111, 231, + 112, -1, 234, -1, 234, 106, 234, -1, 62, 46, + 111, 234, 112, -1, 23, -1, 23, -1, 237, -1, + 239, -1, 238, -1, 239, -1, 240, -1, 24, -1, + 23, -1, 118, 240, 119, -1, 118, 240, 109, 240, + 119, -1, 118, 240, 109, 240, 109, 240, 119, -1, + 118, 240, 109, 240, 109, 240, 109, 240, 119, -1, + 241, 24, -1, 241, 23, -1, 113, -1, 114, -1, + -1, -1, 244, 11, 243, 247, -1, 262, -1, -1, + -1, 5, 246, 247, -1, 247, 109, 99, -1, 99, + -1, 244, 9, 99, 117, 249, -1, 65, 60, -1, + 65, 37, -1, 65, 250, -1, 65, 59, -1, 65, + 74, 255, -1, 65, 30, -1, 29, 251, 252, -1, + -1, 39, -1, 27, -1, -1, 61, -1, 68, -1, + -1, 39, -1, 27, -1, -1, 61, -1, 68, -1, + -1, 111, 258, 112, -1, -1, 111, 259, 112, -1, + -1, 111, 260, 112, -1, 23, -1, 23, -1, 23, + -1, 6, 99, 117, 100, -1, 99, -1, 100, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 278, 278, 281, 289, 301, 302, 305, 329, 330, + 333, 348, 351, 356, 363, 364, 365, 366, 367, 368, + 369, 372, 373, 374, 377, 383, 389, 395, 402, 408, + 415, 459, 464, 474, 518, 524, 525, 526, 527, 528, + 529, 530, 531, 532, 533, 534, 535, 538, 550, 558, + 575, 582, 601, 612, 632, 657, 664, 697, 704, 719, + 774, 817, 826, 847, 857, 861, 890, 909, 909, 911, + 918, 930, 931, 932, 935, 949, 963, 983, 994, 1006, + 1008, 1009, 1010, 1011, 1014, 1014, 1014, 1014, 1015, 1018, + 1022, 1027, 1034, 1041, 1048, 1071, 1094, 1095, 1096, 1097, + 1098, 1099, 1102, 1121, 1125, 1131, 1135, 1139, 1143, 1152, + 1161, 1165, 1170, 1176, 1187, 1187, 1188, 1190, 1194, 1198, + 1202, 1208, 1208, 1210, 1228, 1254, 1257, 1268, 1274, 1280, + 1281, 1288, 1294, 1300, 1308, 1314, 1320, 1328, 1334, 1340, + 1348, 1349, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, + 1360, 1361, 1362, 1365, 1374, 1378, 1382, 1388, 1397, 1401, + 1405, 1414, 1418, 1424, 1430, 1437, 1442, 1450, 1460, 1462, + 1470, 1476, 1480, 1484, 1490, 1501, 1510, 1514, 1519, 1523, + 1527, 1531, 1537, 1544, 1548, 1554, 1562, 1573, 1580, 1584, + 1590, 1600, 1611, 1615, 1633, 1642, 1645, 1651, 1655, 1659, + 1665, 1676, 1681, 1686, 1691, 1696, 1701, 1709, 1712, 1717, + 1730, 1738, 1749, 1757, 1757, 1759, 1759, 1761, 1771, 1776, + 1783, 1793, 1802, 1807, 1814, 1824, 1834, 1846, 1846, 1847, + 1847, 1849, 1859, 1867, 1877, 1885, 1893, 1902, 1913, 1917, + 1923, 1924, 1925, 1928, 1928, 1931, 1966, 1970, 1970, 1973, + 1980, 1989, 2003, 2012, 2021, 2025, 2034, 2043, 2054, 2061, + 2066, 2075, 2087, 2090, 2099, 2110, 2111, 2112, 2115, 2116, + 2117, 2120, 2121, 2124, 2125, 2128, 2129, 2132, 2143, 2154, + 2165, 2191, 2192 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "ARBvp_10", "ARBfp_10", "ADDRESS", + "ALIAS", "ATTRIB", "OPTION", "OUTPUT", "PARAM", "TEMP", "END", "BIN_OP", + "BINSC_OP", "SAMPLE_OP", "SCALAR_OP", "TRI_OP", "VECTOR_OP", "ARL", + "KIL", "SWZ", "TXD_OP", "INTEGER", "REAL", "AMBIENT", "ATTENUATION", + "BACK", "CLIP", "COLOR", "DEPTH", "DIFFUSE", "DIRECTION", "EMISSION", + "ENV", "EYE", "FOG", "FOGCOORD", "FRAGMENT", "FRONT", "HALF", "INVERSE", + "INVTRANS", "LIGHT", "LIGHTMODEL", "LIGHTPROD", "LOCAL", "MATERIAL", + "MAT_PROGRAM", "MATRIX", "MATRIXINDEX", "MODELVIEW", "MVP", "NORMAL", + "OBJECT", "PALETTE", "PARAMS", "PLANE", "POINT_TOK", "POINTSIZE", + "POSITION", "PRIMARY", "PROGRAM", "PROJECTION", "RANGE", "RESULT", "ROW", + "SCENECOLOR", "SECONDARY", "SHININESS", "SIZE_TOK", "SPECULAR", "SPOT", + "STATE", "TEXCOORD", "TEXENV", "TEXGEN", "TEXGEN_Q", "TEXGEN_R", + "TEXGEN_S", "TEXGEN_T", "TEXTURE", "TRANSPOSE", "TEXTURE_UNIT", "TEX_1D", + "TEX_2D", "TEX_3D", "TEX_CUBE", "TEX_RECT", "TEX_SHADOW1D", + "TEX_SHADOW2D", "TEX_SHADOWRECT", "TEX_ARRAY1D", "TEX_ARRAY2D", + "TEX_ARRAYSHADOW1D", "TEX_ARRAYSHADOW2D", "VERTEX", "VTXATTRIB", + "WEIGHT", "IDENTIFIER", "USED_IDENTIFIER", "MASK4", "MASK3", "MASK2", + "MASK1", "SWIZZLE", "DOT_DOT", "DOT", "';'", "','", "'|'", "'['", "']'", + "'+'", "'-'", "'('", "')'", "'='", "'{'", "'}'", "$accept", "program", + "language", "optionSequence", "option", "statementSequence", "statement", + "instruction", "ALU_instruction", "TexInstruction", "ARL_instruction", + "VECTORop_instruction", "SCALARop_instruction", "BINSCop_instruction", + "BINop_instruction", "TRIop_instruction", "SAMPLE_instruction", + "KIL_instruction", "TXD_instruction", "texImageUnit", "texTarget", + "SWZ_instruction", "scalarSrcReg", "scalarUse", "swizzleSrcReg", + "maskedDstReg", "maskedAddrReg", "extendedSwizzle", "extSwizComp", + "extSwizSel", "srcReg", "dstReg", "progParamArray", "progParamArrayMem", + "progParamArrayAbs", "progParamArrayRel", "addrRegRelOffset", + "addrRegPosOffset", "addrRegNegOffset", "addrReg", "addrComponent", + "addrWriteMask", "scalarSuffix", "swizzleSuffix", "optionalMask", + "optionalCcMask", "ccTest", "ccTest2", "ccMaskRule", "ccMaskRule2", + "namingStatement", "ATTRIB_statement", "attribBinding", "vtxAttribItem", + "vtxAttribNum", "vtxOptWeightNum", "vtxWeightNum", "fragAttribItem", + "PARAM_statement", "PARAM_singleStmt", "PARAM_multipleStmt", + "optArraySize", "paramSingleInit", "paramMultipleInit", + "paramMultInitList", "paramSingleItemDecl", "paramSingleItemUse", + "paramMultipleItem", "stateMultipleItem", "stateSingleItem", + "stateMaterialItem", "stateMatProperty", "stateLightItem", + "stateLightProperty", "stateSpotProperty", "stateLightModelItem", + "stateLModProperty", "stateLightProdItem", "stateLProdProperty", + "stateTexEnvItem", "stateTexEnvProperty", "ambDiffSpecProperty", + "stateLightNumber", "stateTexGenItem", "stateTexGenType", + "stateTexGenCoord", "stateFogItem", "stateFogProperty", + "stateClipPlaneItem", "stateClipPlaneNum", "statePointItem", + "statePointProperty", "stateMatrixRow", "stateMatrixRows", + "optMatrixRows", "stateMatrixItem", "stateOptMatModifier", + "stateMatModifier", "stateMatrixRowNum", "stateMatrixName", + "stateOptModMatNum", "stateModMatNum", "statePaletteMatNum", + "stateProgramMatNum", "stateDepthItem", "programSingleItem", + "programMultipleItem", "progEnvParams", "progEnvParamNums", + "progEnvParam", "progLocalParams", "progLocalParamNums", + "progLocalParam", "progEnvParamNum", "progLocalParamNum", + "paramConstDecl", "paramConstUse", "paramConstScalarDecl", + "paramConstScalarUse", "paramConstVector", "signedFloatConstant", + "optionalSign", "TEMP_statement", "@1", "optVarSize", + "ADDRESS_statement", "@2", "varNameList", "OUTPUT_statement", + "resultBinding", "resultColBinding", "optResultFaceType", + "optResultColorType", "optFaceType", "optColorType", + "optTexCoordUnitNum", "optTexImageUnitNum", "optLegacyTexUnitNum", + "texCoordUnitNum", "texImageUnitNum", "legacyTexUnitNum", + "ALIAS_statement", "string", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 59, 44, + 124, 91, 93, 43, 45, 40, 41, 61, 123, 125 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint16 yyr1[] = +{ + 0, 120, 121, 122, 122, 123, 123, 124, 125, 125, + 126, 126, 127, 127, 128, 128, 128, 128, 128, 128, + 128, 129, 129, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 137, 138, 139, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 141, 142, 142, + 143, 143, 144, 144, 145, 146, 147, 148, 149, 149, + 150, 150, 150, 150, 151, 151, 152, 153, 153, 154, + 155, 156, 156, 156, 157, 158, 159, 160, 161, 162, + 163, 163, 163, 163, 164, 164, 164, 164, 164, 165, + 165, 165, 166, 167, 168, 169, 170, 170, 170, 170, + 170, 170, 171, 172, 172, 173, 173, 173, 173, 173, + 173, 173, 173, 174, 175, 175, 176, 177, 177, 177, + 177, 178, 178, 179, 180, 181, 181, 182, 183, 184, + 184, 185, 185, 185, 186, 186, 186, 187, 187, 187, + 188, 188, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 190, 191, 191, 191, 192, 193, 193, + 193, 193, 193, 194, 195, 196, 196, 197, 198, 199, + 200, 201, 201, 201, 202, 203, 204, 204, 205, 205, + 205, 205, 206, 207, 207, 208, 209, 210, 211, 211, + 212, 213, 214, 214, 215, 216, 216, 217, 217, 217, + 218, 219, 219, 219, 219, 219, 219, 220, 220, 221, + 222, 223, 224, 225, 225, 226, 226, 227, 228, 228, + 229, 230, 231, 231, 232, 233, 234, 235, 235, 236, + 236, 237, 238, 238, 239, 239, 239, 239, 240, 240, + 241, 241, 241, 243, 242, 244, 244, 246, 245, 247, + 247, 248, 249, 249, 249, 249, 249, 249, 250, 251, + 251, 251, 252, 252, 252, 253, 253, 253, 254, 254, + 254, 255, 255, 256, 256, 257, 257, 258, 259, 260, + 261, 262, 262 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 4, 1, 1, 2, 0, 3, 2, 0, + 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 4, 4, 4, 6, 6, 8, + 8, 2, 2, 12, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 6, 2, 4, + 2, 1, 3, 5, 3, 2, 7, 2, 1, 1, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 3, 0, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 1, 1, 1, 0, 3, + 3, 0, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 4, 2, 2, 1, 2, 1, 2, 1, + 2, 4, 4, 1, 0, 3, 1, 1, 2, 1, + 2, 1, 1, 3, 6, 0, 1, 2, 4, 1, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 3, 1, 1, 1, 5, 1, 1, + 1, 2, 1, 1, 2, 1, 2, 6, 1, 3, + 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, + 1, 1, 2, 1, 1, 5, 1, 2, 1, 1, + 5, 2, 0, 6, 3, 0, 1, 1, 1, 1, + 1, 2, 1, 1, 2, 4, 4, 0, 3, 1, + 1, 1, 2, 1, 1, 1, 1, 5, 1, 3, + 5, 5, 1, 3, 5, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 5, 7, 9, 2, 2, + 1, 1, 0, 0, 4, 1, 0, 0, 3, 3, + 1, 5, 2, 2, 2, 2, 3, 2, 3, 0, + 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, + 1, 0, 3, 0, 3, 0, 3, 1, 1, 1, + 4, 1, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint16 yydefact[] = +{ + 0, 3, 4, 0, 6, 1, 9, 0, 5, 246, + 281, 282, 0, 247, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 242, 0, 0, 8, 0, + 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, + 23, 20, 0, 96, 97, 121, 122, 98, 0, 99, + 100, 101, 245, 7, 0, 0, 0, 0, 0, 65, + 0, 88, 64, 0, 0, 0, 0, 0, 76, 0, + 0, 94, 240, 241, 31, 32, 83, 0, 0, 0, + 10, 11, 0, 243, 250, 248, 0, 0, 125, 242, + 123, 259, 257, 253, 255, 252, 271, 254, 242, 84, + 85, 86, 87, 91, 242, 242, 242, 242, 242, 242, + 78, 55, 81, 80, 82, 92, 233, 232, 0, 0, + 0, 0, 60, 0, 242, 83, 0, 61, 63, 134, + 135, 213, 214, 136, 229, 230, 0, 242, 0, 0, + 0, 280, 102, 126, 0, 127, 131, 132, 133, 227, + 228, 231, 0, 261, 260, 262, 0, 256, 0, 0, + 54, 0, 0, 0, 26, 0, 25, 24, 268, 119, + 117, 271, 104, 0, 0, 0, 0, 0, 0, 265, + 0, 265, 0, 0, 275, 271, 142, 143, 144, 145, + 147, 146, 148, 149, 150, 151, 0, 152, 268, 109, + 0, 107, 105, 271, 0, 114, 103, 83, 0, 52, + 0, 0, 0, 0, 244, 249, 0, 239, 238, 263, + 264, 258, 277, 0, 242, 95, 0, 0, 83, 242, + 0, 48, 0, 51, 0, 242, 269, 270, 118, 120, + 0, 0, 0, 212, 183, 184, 182, 0, 165, 267, + 266, 164, 0, 0, 0, 0, 207, 203, 0, 202, + 271, 195, 189, 188, 187, 0, 0, 0, 0, 108, + 0, 110, 0, 0, 106, 0, 242, 234, 69, 0, + 67, 68, 0, 242, 242, 251, 0, 124, 272, 28, + 89, 90, 93, 27, 0, 79, 50, 273, 0, 0, + 225, 0, 226, 0, 186, 0, 174, 0, 166, 0, + 171, 172, 155, 156, 173, 153, 154, 0, 0, 201, + 0, 204, 197, 199, 198, 194, 196, 279, 0, 170, + 169, 176, 177, 0, 0, 116, 0, 113, 0, 0, + 53, 0, 62, 77, 71, 47, 0, 0, 0, 242, + 49, 0, 34, 0, 242, 220, 224, 0, 0, 265, + 211, 0, 209, 0, 210, 0, 276, 181, 180, 178, + 179, 175, 200, 0, 111, 112, 115, 242, 235, 0, + 0, 70, 242, 58, 57, 59, 242, 0, 0, 0, + 129, 137, 140, 138, 215, 216, 139, 278, 0, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 30, 29, 185, 160, 162, 159, 0, 157, 158, + 0, 206, 208, 205, 190, 0, 74, 72, 75, 73, + 0, 0, 0, 0, 141, 192, 242, 128, 274, 163, + 161, 167, 168, 242, 236, 242, 0, 0, 0, 0, + 191, 130, 0, 0, 0, 0, 218, 0, 222, 0, + 237, 242, 0, 217, 0, 221, 0, 0, 56, 33, + 219, 223, 0, 0, 193 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 3, 4, 6, 8, 9, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 298, + 411, 41, 161, 231, 74, 60, 69, 345, 346, 384, + 232, 61, 126, 279, 280, 281, 381, 427, 429, 70, + 344, 111, 296, 115, 103, 160, 75, 227, 76, 228, + 42, 43, 127, 206, 338, 274, 336, 172, 44, 45, + 46, 144, 90, 287, 389, 145, 128, 390, 391, 129, + 186, 315, 187, 418, 440, 188, 251, 189, 441, 190, + 330, 316, 307, 191, 333, 371, 192, 246, 193, 305, + 194, 264, 195, 434, 450, 196, 325, 326, 373, 261, + 319, 363, 365, 361, 197, 130, 393, 394, 455, 131, + 395, 457, 132, 301, 303, 396, 133, 149, 134, 135, + 151, 77, 47, 139, 48, 49, 54, 85, 50, 62, + 97, 155, 221, 252, 238, 157, 352, 266, 223, 398, + 328, 51, 12 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -401 +static const yytype_int16 yypact[] = +{ + 193, -401, -401, 27, -401, -401, 62, 143, -401, 24, + -401, -401, -30, -401, -18, 12, 83, -401, 15, 15, + 15, 15, 15, 15, 67, 61, 15, 15, -401, 127, + -401, -401, -401, -401, -401, -401, -401, -401, -401, -401, + -401, -401, 144, -401, -401, -401, -401, -401, 204, -401, + -401, -401, -401, -401, 155, 136, 138, 34, 140, -401, + 147, 108, -401, 150, 156, 157, 158, 160, -401, 162, + 159, -401, -401, -401, -401, -401, 102, -13, 163, 164, + -401, -401, 165, -401, -401, 166, 170, 10, 235, 0, + -401, 141, -401, -401, -401, -401, 167, -401, 131, -401, + -401, -401, -401, 168, 131, 131, 131, 131, 131, 131, + -401, -401, -401, -401, -401, -401, -401, -401, 104, 97, + 114, 38, 169, 30, 131, 102, 171, -401, -401, -401, + -401, -401, -401, -401, -401, -401, 30, 131, 172, 155, + 175, -401, -401, -401, 173, -401, -401, -401, -401, -401, + -401, -401, 223, -401, -401, 123, 253, -401, 177, 149, + -401, 178, -10, 181, -401, 182, -401, -401, 134, -401, + -401, 167, -401, 183, 184, 185, 213, 99, 186, 154, + 187, 146, 153, 7, 188, 167, -401, -401, -401, -401, + -401, -401, -401, -401, -401, -401, 215, -401, 134, -401, + 190, -401, -401, 167, 191, 192, -401, 102, -48, -401, + 1, 195, 196, 214, 166, -401, 189, -401, -401, -401, + -401, -401, -401, 180, 131, -401, 194, 197, 102, 131, + 30, -401, 203, 205, 201, 131, -401, -401, -401, -401, + 285, 288, 289, -401, -401, -401, -401, 291, -401, -401, + -401, -401, 248, 291, 33, 206, 207, -401, 208, -401, + 167, 14, -401, -401, -401, 293, 292, 92, 209, -401, + 299, -401, 301, 299, -401, 216, 131, -401, -401, 217, + -401, -401, 221, 131, 131, -401, 212, -401, -401, -401, + -401, -401, -401, -401, 218, -401, -401, 220, 224, 225, + -401, 226, -401, 227, -401, 228, -401, 230, -401, 231, + -401, -401, -401, -401, -401, -401, -401, 304, 309, -401, + 312, -401, -401, -401, -401, -401, -401, -401, 232, -401, + -401, -401, -401, 161, 313, -401, 233, -401, 234, 238, + -401, 13, -401, -401, 137, -401, 242, -15, 243, 3, + -401, 314, -401, 133, 131, -401, -401, 296, 94, 146, + -401, 245, -401, 246, -401, 247, -401, -401, -401, -401, + -401, -401, -401, 249, -401, -401, -401, 131, -401, 332, + 337, -401, 131, -401, -401, -401, 131, 142, 114, 28, + -401, -401, -401, -401, -401, -401, -401, -401, 250, -401, + -401, -401, -401, -401, -401, -401, -401, -401, -401, -401, + -401, -401, -401, -401, -401, -401, -401, 331, -401, -401, + 68, -401, -401, -401, -401, 43, -401, -401, -401, -401, + 255, 256, 257, 258, -401, 300, 3, -401, -401, -401, + -401, -401, -401, 131, -401, 131, 201, 285, 288, 259, + -401, -401, 252, 264, 265, 263, 261, 266, 270, 313, + -401, 131, 133, -401, 285, -401, 288, 80, -401, -401, + -401, -401, 313, 267, -401 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -401, -401, -401, -401, -401, -401, -401, -401, -401, -401, + -401, -401, -401, -401, -401, -401, -401, -401, -401, -69, + -82, -401, -100, 151, -86, 210, -401, -401, -366, -401, + -54, -401, -401, -401, -401, -401, -401, -401, -401, 174, + -401, -401, -401, -118, -401, -401, 229, -401, -401, -401, + -401, -401, 295, -401, -401, -401, 110, -401, -401, -401, + -401, -401, -401, -401, -401, -401, -401, -51, -401, -88, + -401, -401, -401, -401, -401, -401, -401, -401, -401, -401, + -401, -311, 139, -401, -401, -401, -401, -401, -401, -401, + -401, -401, -401, -401, -401, -2, -401, -401, -400, -401, + -401, -401, -401, -401, -401, 298, -401, -401, -401, -401, + -401, -401, -401, -390, -295, 302, -401, -401, -136, -87, + -120, -89, -401, -401, -401, -401, -401, 251, -401, 176, + -401, -401, -401, -176, 198, -153, -401, -401, -401, -401, + -401, -401, -6 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -230 +static const yytype_int16 yytable[] = +{ + 152, 146, 150, 52, 208, 254, 164, 209, 383, 167, + 116, 117, 158, 116, 117, 162, 430, 162, 239, 163, + 162, 165, 166, 125, 278, 118, 233, 5, 118, 13, + 14, 15, 267, 262, 16, 152, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 419, 118, 119, + 271, 212, 119, 116, 117, 322, 323, 456, 310, 467, + 120, 276, 119, 120, 311, 387, 312, 198, 118, 207, + 7, 277, 473, 120, 470, 199, 388, 263, 53, 453, + 58, 55, 211, 121, 10, 11, 121, 122, 200, 275, + 122, 201, 119, 310, 233, 468, 324, 123, 202, 311, + 230, 68, 313, 120, 314, 124, 121, 321, 124, 442, + 292, 56, 203, 72, 73, 59, 72, 73, 124, 310, + 414, 124, 377, 10, 11, 311, 121, 331, 244, 293, + 122, 173, 378, 168, 415, 204, 205, 436, 289, 314, + 162, 169, 175, 174, 176, 88, 332, 437, 124, 299, + 177, 89, 443, 458, 416, 245, 341, 178, 179, 180, + 71, 181, 444, 182, 170, 314, 417, 68, 153, 91, + 92, 471, 183, 249, 72, 73, 432, 93, 171, 248, + 154, 249, 57, 420, 219, 250, 472, 152, 433, 184, + 185, 220, 424, 250, 347, 236, 1, 2, 348, 94, + 95, 255, 237, 112, 256, 257, 113, 114, 258, 99, + 100, 101, 102, 82, 96, 83, 259, 399, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 63, + 64, 65, 66, 67, 260, 80, 78, 79, 367, 368, + 369, 370, 10, 11, 72, 73, 217, 218, 71, 225, + 379, 380, 81, 86, 84, 87, 98, 425, 143, 104, + 152, 392, 150, 110, 138, 105, 106, 107, 412, 108, + 141, 109, 136, 137, 215, 140, 222, 243, 156, 58, + -66, 268, 210, 159, 297, 216, 224, 229, 152, 213, + 234, 235, 288, 347, 240, 241, 242, 247, 253, 265, + 431, 270, 272, 273, 283, 284, 286, 295, 300, -229, + 290, 302, 304, 291, 306, 308, 327, 317, 318, 320, + 334, 329, 335, 452, 337, 343, 340, 360, 350, 342, + 349, 351, 362, 353, 354, 364, 372, 397, 355, 356, + 357, 385, 358, 359, 366, 374, 375, 152, 392, 150, + 376, 382, 386, 413, 152, 426, 347, 421, 422, 423, + 428, 424, 438, 439, 445, 446, 449, 464, 447, 448, + 459, 460, 347, 461, 462, 463, 466, 454, 465, 474, + 469, 294, 142, 339, 282, 451, 435, 147, 226, 285, + 214, 148, 309, 0, 0, 0, 269 +}; + +static const yytype_int16 yycheck[] = +{ + 89, 89, 89, 9, 124, 181, 106, 125, 23, 109, + 23, 24, 98, 23, 24, 104, 382, 106, 171, 105, + 109, 107, 108, 77, 23, 38, 162, 0, 38, 5, + 6, 7, 185, 26, 10, 124, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 358, 38, 62, + 203, 137, 62, 23, 24, 41, 42, 447, 25, 459, + 73, 109, 62, 73, 31, 62, 33, 29, 38, 123, + 8, 119, 472, 73, 464, 37, 73, 70, 108, 445, + 65, 99, 136, 96, 99, 100, 96, 100, 50, 207, + 100, 53, 62, 25, 230, 461, 82, 110, 60, 31, + 110, 100, 69, 73, 71, 118, 96, 260, 118, 420, + 228, 99, 74, 113, 114, 100, 113, 114, 118, 25, + 26, 118, 109, 99, 100, 31, 96, 35, 29, 229, + 100, 34, 119, 29, 40, 97, 98, 109, 224, 71, + 229, 37, 28, 46, 30, 111, 54, 119, 118, 235, + 36, 117, 109, 448, 60, 56, 276, 43, 44, 45, + 99, 47, 119, 49, 60, 71, 72, 100, 27, 29, + 30, 466, 58, 27, 113, 114, 34, 37, 74, 25, + 39, 27, 99, 359, 61, 39, 106, 276, 46, 75, + 76, 68, 112, 39, 283, 61, 3, 4, 284, 59, + 60, 48, 68, 101, 51, 52, 104, 105, 55, 101, + 102, 103, 104, 9, 74, 11, 63, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 19, + 20, 21, 22, 23, 81, 108, 26, 27, 77, 78, + 79, 80, 99, 100, 113, 114, 23, 24, 99, 100, + 113, 114, 108, 117, 99, 117, 109, 377, 23, 109, + 349, 349, 349, 104, 99, 109, 109, 109, 354, 109, + 100, 109, 109, 109, 99, 109, 23, 64, 111, 65, + 111, 66, 111, 115, 83, 112, 109, 109, 377, 117, + 109, 109, 112, 382, 111, 111, 111, 111, 111, 111, + 386, 111, 111, 111, 109, 109, 117, 104, 23, 104, + 116, 23, 23, 116, 23, 67, 23, 111, 111, 111, + 111, 29, 23, 443, 23, 104, 110, 23, 110, 112, + 118, 111, 23, 109, 109, 23, 23, 23, 112, 112, + 112, 347, 112, 112, 112, 112, 112, 436, 436, 436, + 112, 109, 109, 57, 443, 23, 445, 112, 112, 112, + 23, 112, 112, 32, 109, 109, 66, 106, 111, 111, + 111, 119, 461, 109, 109, 112, 106, 446, 112, 112, + 462, 230, 87, 273, 210, 436, 388, 89, 159, 213, + 139, 89, 253, -1, -1, -1, 198 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint16 yystos[] = +{ + 0, 3, 4, 121, 122, 0, 123, 8, 124, 125, + 99, 100, 262, 5, 6, 7, 10, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 141, 170, 171, 178, 179, 180, 242, 244, 245, + 248, 261, 262, 108, 246, 99, 99, 99, 65, 100, + 145, 151, 249, 145, 145, 145, 145, 145, 100, 146, + 159, 99, 113, 114, 144, 166, 168, 241, 145, 145, + 108, 108, 9, 11, 99, 247, 117, 117, 111, 117, + 182, 29, 30, 37, 59, 60, 74, 250, 109, 101, + 102, 103, 104, 164, 109, 109, 109, 109, 109, 109, + 104, 161, 101, 104, 105, 163, 23, 24, 38, 62, + 73, 96, 100, 110, 118, 150, 152, 172, 186, 189, + 225, 229, 232, 236, 238, 239, 109, 109, 99, 243, + 109, 100, 172, 23, 181, 185, 189, 225, 235, 237, + 239, 240, 241, 27, 39, 251, 111, 255, 144, 115, + 165, 142, 241, 144, 142, 144, 144, 142, 29, 37, + 60, 74, 177, 34, 46, 28, 30, 36, 43, 44, + 45, 47, 49, 58, 75, 76, 190, 192, 195, 197, + 199, 203, 206, 208, 210, 212, 215, 224, 29, 37, + 50, 53, 60, 74, 97, 98, 173, 150, 240, 163, + 111, 150, 144, 117, 247, 99, 112, 23, 24, 61, + 68, 252, 23, 258, 109, 100, 166, 167, 169, 109, + 110, 143, 150, 238, 109, 109, 61, 68, 254, 255, + 111, 111, 111, 64, 29, 56, 207, 111, 25, 27, + 39, 196, 253, 111, 253, 48, 51, 52, 55, 63, + 81, 219, 26, 70, 211, 111, 257, 255, 66, 254, + 111, 255, 111, 111, 175, 163, 109, 119, 23, 153, + 154, 155, 159, 109, 109, 249, 117, 183, 112, 144, + 116, 116, 163, 142, 143, 104, 162, 83, 139, 144, + 23, 233, 23, 234, 23, 209, 23, 202, 67, 202, + 25, 31, 33, 69, 71, 191, 201, 111, 111, 220, + 111, 255, 41, 42, 82, 216, 217, 23, 260, 29, + 200, 35, 54, 204, 111, 23, 176, 23, 174, 176, + 110, 240, 112, 104, 160, 147, 148, 241, 144, 118, + 110, 111, 256, 109, 109, 112, 112, 112, 112, 112, + 23, 223, 23, 221, 23, 222, 112, 77, 78, 79, + 80, 205, 23, 218, 112, 112, 112, 109, 119, 113, + 114, 156, 109, 23, 149, 262, 109, 62, 73, 184, + 187, 188, 189, 226, 227, 230, 235, 23, 259, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 140, 144, 57, 26, 40, 60, 72, 193, 201, + 253, 112, 112, 112, 112, 240, 23, 157, 23, 158, + 148, 144, 34, 46, 213, 215, 109, 119, 112, 32, + 194, 198, 201, 109, 119, 109, 109, 111, 111, 66, + 214, 187, 240, 148, 139, 228, 233, 231, 234, 111, + 119, 109, 109, 112, 106, 112, 106, 218, 148, 140, + 233, 234, 106, 218, 112 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (&yylloc, state, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval, &yylloc, scanner) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, Location, state); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct asm_parser_state *state) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, state) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + struct asm_parser_state *state; +#endif +{ + if (!yyvaluep) + return; + YYUSE (yylocationp); + YYUSE (state); +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct asm_parser_state *state) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, state) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + struct asm_parser_state *state; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + YY_LOCATION_PRINT (yyoutput, *yylocationp); + YYFPRINTF (yyoutput, ": "); + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, state); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, struct asm_parser_state *state) +#else +static void +yy_reduce_print (yyvsp, yylsp, yyrule, state) + YYSTYPE *yyvsp; + YYLTYPE *yylsp; + int yyrule; + struct asm_parser_state *state; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , &(yylsp[(yyi + 1) - (yynrhs)]) , state); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, yylsp, Rule, state); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, struct asm_parser_state *state) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, yylocationp, state) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; + YYLTYPE *yylocationp; + struct asm_parser_state *state; +#endif +{ + YYUSE (yyvaluep); + YYUSE (yylocationp); + YYUSE (state); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (struct asm_parser_state *state); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (struct asm_parser_state *state) +#else +int +yyparse (state) + struct asm_parser_state *state; +#endif +#endif +{ +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Location data for the lookahead symbol. */ +YYLTYPE yylloc; + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls; + YYLTYPE *yylsp; + + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[2]; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + YYLTYPE yyloc; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yyls = yylsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + yylsp = yyls; + +#if YYLTYPE_IS_TRIVIAL + /* Initialize the default location before parsing starts. */ + yylloc.first_line = yylloc.last_line = 1; + yylloc.first_column = yylloc.last_column = 1; +#endif + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + + yyls = yyls1; + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + yylsp = yyls + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + *++yylsp = yylloc; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 3: + +/* Line 1455 of yacc.c */ +#line 282 "program_parse.y" + { + if (state->prog->Target != GL_VERTEX_PROGRAM_ARB) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid fragment program header"); + + } + state->mode = ARB_vertex; + ;} + break; + + case 4: + +/* Line 1455 of yacc.c */ +#line 290 "program_parse.y" + { + if (state->prog->Target != GL_FRAGMENT_PROGRAM_ARB) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid vertex program header"); + } + state->mode = ARB_fragment; + + state->option.TexRect = + (state->ctx->Extensions.NV_texture_rectangle != GL_FALSE); + ;} + break; + + case 7: + +/* Line 1455 of yacc.c */ +#line 306 "program_parse.y" + { + int valid = 0; + + if (state->mode == ARB_vertex) { + valid = _mesa_ARBvp_parse_option(state, (yyvsp[(2) - (3)].string)); + } else if (state->mode == ARB_fragment) { + valid = _mesa_ARBfp_parse_option(state, (yyvsp[(2) - (3)].string)); + } + + + free((yyvsp[(2) - (3)].string)); + + if (!valid) { + const char *const err_str = (state->mode == ARB_vertex) + ? "invalid ARB vertex program option" + : "invalid ARB fragment program option"; + + yyerror(& (yylsp[(2) - (3)]), state, err_str); + YYERROR; + } + ;} + break; + + case 10: + +/* Line 1455 of yacc.c */ +#line 334 "program_parse.y" + { + if ((yyvsp[(1) - (2)].inst) != NULL) { + if (state->inst_tail == NULL) { + state->inst_head = (yyvsp[(1) - (2)].inst); + } else { + state->inst_tail->next = (yyvsp[(1) - (2)].inst); + } + + state->inst_tail = (yyvsp[(1) - (2)].inst); + (yyvsp[(1) - (2)].inst)->next = NULL; + + state->prog->NumInstructions++; + } + ;} + break; + + case 12: + +/* Line 1455 of yacc.c */ +#line 352 "program_parse.y" + { + (yyval.inst) = (yyvsp[(1) - (1)].inst); + state->prog->NumAluInstructions++; + ;} + break; + + case 13: + +/* Line 1455 of yacc.c */ +#line 357 "program_parse.y" + { + (yyval.inst) = (yyvsp[(1) - (1)].inst); + state->prog->NumTexInstructions++; + ;} + break; + + case 24: + +/* Line 1455 of yacc.c */ +#line 378 "program_parse.y" + { + (yyval.inst) = asm_instruction_ctor(OPCODE_ARL, & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL); + ;} + break; + + case 25: + +/* Line 1455 of yacc.c */ +#line 384 "program_parse.y" + { + (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (4)].temp_inst), & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL); + ;} + break; + + case 26: + +/* Line 1455 of yacc.c */ +#line 390 "program_parse.y" + { + (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (4)].temp_inst), & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL); + ;} + break; + + case 27: + +/* Line 1455 of yacc.c */ +#line 396 "program_parse.y" + { + (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (6)].temp_inst), & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), & (yyvsp[(6) - (6)].src_reg), NULL); + ;} + break; + + case 28: + +/* Line 1455 of yacc.c */ +#line 403 "program_parse.y" + { + (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (6)].temp_inst), & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), & (yyvsp[(6) - (6)].src_reg), NULL); + ;} + break; + + case 29: + +/* Line 1455 of yacc.c */ +#line 410 "program_parse.y" + { + (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (8)].temp_inst), & (yyvsp[(2) - (8)].dst_reg), & (yyvsp[(4) - (8)].src_reg), & (yyvsp[(6) - (8)].src_reg), & (yyvsp[(8) - (8)].src_reg)); + ;} + break; + + case 30: + +/* Line 1455 of yacc.c */ +#line 416 "program_parse.y" + { + (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (8)].temp_inst), & (yyvsp[(2) - (8)].dst_reg), & (yyvsp[(4) - (8)].src_reg), NULL, NULL); + if ((yyval.inst) != NULL) { + const GLbitfield tex_mask = (1U << (yyvsp[(6) - (8)].integer)); + GLbitfield shadow_tex = 0; + GLbitfield target_mask = 0; + + + (yyval.inst)->Base.TexSrcUnit = (yyvsp[(6) - (8)].integer); + + if ((yyvsp[(8) - (8)].integer) < 0) { + shadow_tex = tex_mask; + + (yyval.inst)->Base.TexSrcTarget = -(yyvsp[(8) - (8)].integer); + (yyval.inst)->Base.TexShadow = 1; + } else { + (yyval.inst)->Base.TexSrcTarget = (yyvsp[(8) - (8)].integer); + } + + target_mask = (1U << (yyval.inst)->Base.TexSrcTarget); + + /* If this texture unit was previously accessed and that access + * had a different texture target, generate an error. + * + * If this texture unit was previously accessed and that access + * had a different shadow mode, generate an error. + */ + if ((state->prog->TexturesUsed[(yyvsp[(6) - (8)].integer)] != 0) + && ((state->prog->TexturesUsed[(yyvsp[(6) - (8)].integer)] != target_mask) + || ((state->prog->ShadowSamplers & tex_mask) + != shadow_tex))) { + yyerror(& (yylsp[(8) - (8)]), state, + "multiple targets used on one texture image unit"); + YYERROR; + } + + + state->prog->TexturesUsed[(yyvsp[(6) - (8)].integer)] |= target_mask; + state->prog->ShadowSamplers |= shadow_tex; + } + ;} + break; + + case 31: + +/* Line 1455 of yacc.c */ +#line 460 "program_parse.y" + { + (yyval.inst) = asm_instruction_ctor(OPCODE_KIL, NULL, & (yyvsp[(2) - (2)].src_reg), NULL, NULL); + state->fragment.UsesKill = 1; + ;} + break; + + case 32: + +/* Line 1455 of yacc.c */ +#line 465 "program_parse.y" + { + (yyval.inst) = asm_instruction_ctor(OPCODE_KIL_NV, NULL, NULL, NULL, NULL); + (yyval.inst)->Base.DstReg.CondMask = (yyvsp[(2) - (2)].dst_reg).CondMask; + (yyval.inst)->Base.DstReg.CondSwizzle = (yyvsp[(2) - (2)].dst_reg).CondSwizzle; + (yyval.inst)->Base.DstReg.CondSrc = (yyvsp[(2) - (2)].dst_reg).CondSrc; + state->fragment.UsesKill = 1; + ;} + break; + + case 33: + +/* Line 1455 of yacc.c */ +#line 475 "program_parse.y" + { + (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (12)].temp_inst), & (yyvsp[(2) - (12)].dst_reg), & (yyvsp[(4) - (12)].src_reg), & (yyvsp[(6) - (12)].src_reg), & (yyvsp[(8) - (12)].src_reg)); + if ((yyval.inst) != NULL) { + const GLbitfield tex_mask = (1U << (yyvsp[(10) - (12)].integer)); + GLbitfield shadow_tex = 0; + GLbitfield target_mask = 0; + + + (yyval.inst)->Base.TexSrcUnit = (yyvsp[(10) - (12)].integer); + + if ((yyvsp[(12) - (12)].integer) < 0) { + shadow_tex = tex_mask; + + (yyval.inst)->Base.TexSrcTarget = -(yyvsp[(12) - (12)].integer); + (yyval.inst)->Base.TexShadow = 1; + } else { + (yyval.inst)->Base.TexSrcTarget = (yyvsp[(12) - (12)].integer); + } + + target_mask = (1U << (yyval.inst)->Base.TexSrcTarget); + + /* If this texture unit was previously accessed and that access + * had a different texture target, generate an error. + * + * If this texture unit was previously accessed and that access + * had a different shadow mode, generate an error. + */ + if ((state->prog->TexturesUsed[(yyvsp[(10) - (12)].integer)] != 0) + && ((state->prog->TexturesUsed[(yyvsp[(10) - (12)].integer)] != target_mask) + || ((state->prog->ShadowSamplers & tex_mask) + != shadow_tex))) { + yyerror(& (yylsp[(12) - (12)]), state, + "multiple targets used on one texture image unit"); + YYERROR; + } + + + state->prog->TexturesUsed[(yyvsp[(10) - (12)].integer)] |= target_mask; + state->prog->ShadowSamplers |= shadow_tex; + } + ;} + break; + + case 34: + +/* Line 1455 of yacc.c */ +#line 519 "program_parse.y" + { + (yyval.integer) = (yyvsp[(2) - (2)].integer); + ;} + break; + + case 35: + +/* Line 1455 of yacc.c */ +#line 524 "program_parse.y" + { (yyval.integer) = TEXTURE_1D_INDEX; ;} + break; + + case 36: + +/* Line 1455 of yacc.c */ +#line 525 "program_parse.y" + { (yyval.integer) = TEXTURE_2D_INDEX; ;} + break; + + case 37: + +/* Line 1455 of yacc.c */ +#line 526 "program_parse.y" + { (yyval.integer) = TEXTURE_3D_INDEX; ;} + break; + + case 38: + +/* Line 1455 of yacc.c */ +#line 527 "program_parse.y" + { (yyval.integer) = TEXTURE_CUBE_INDEX; ;} + break; + + case 39: + +/* Line 1455 of yacc.c */ +#line 528 "program_parse.y" + { (yyval.integer) = TEXTURE_RECT_INDEX; ;} + break; + + case 40: + +/* Line 1455 of yacc.c */ +#line 529 "program_parse.y" + { (yyval.integer) = -TEXTURE_1D_INDEX; ;} + break; + + case 41: + +/* Line 1455 of yacc.c */ +#line 530 "program_parse.y" + { (yyval.integer) = -TEXTURE_2D_INDEX; ;} + break; + + case 42: + +/* Line 1455 of yacc.c */ +#line 531 "program_parse.y" + { (yyval.integer) = -TEXTURE_RECT_INDEX; ;} + break; + + case 43: + +/* Line 1455 of yacc.c */ +#line 532 "program_parse.y" + { (yyval.integer) = TEXTURE_1D_ARRAY_INDEX; ;} + break; + + case 44: + +/* Line 1455 of yacc.c */ +#line 533 "program_parse.y" + { (yyval.integer) = TEXTURE_2D_ARRAY_INDEX; ;} + break; + + case 45: + +/* Line 1455 of yacc.c */ +#line 534 "program_parse.y" + { (yyval.integer) = -TEXTURE_1D_ARRAY_INDEX; ;} + break; + + case 46: + +/* Line 1455 of yacc.c */ +#line 535 "program_parse.y" + { (yyval.integer) = -TEXTURE_2D_ARRAY_INDEX; ;} + break; + + case 47: + +/* Line 1455 of yacc.c */ +#line 539 "program_parse.y" + { + /* FIXME: Is this correct? Should the extenedSwizzle be applied + * FIXME: to the existing swizzle? + */ + (yyvsp[(4) - (6)].src_reg).Base.Swizzle = (yyvsp[(6) - (6)].swiz_mask).swizzle; + (yyvsp[(4) - (6)].src_reg).Base.Negate = (yyvsp[(6) - (6)].swiz_mask).mask; + + (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (6)].temp_inst), & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), NULL, NULL); + ;} + break; + + case 48: + +/* Line 1455 of yacc.c */ +#line 551 "program_parse.y" + { + (yyval.src_reg) = (yyvsp[(2) - (2)].src_reg); + + if ((yyvsp[(1) - (2)].negate)) { + (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate; + } + ;} + break; + + case 49: + +/* Line 1455 of yacc.c */ +#line 559 "program_parse.y" + { + (yyval.src_reg) = (yyvsp[(3) - (4)].src_reg); + + if (!state->option.NV_fragment) { + yyerror(& (yylsp[(2) - (4)]), state, "unexpected character '|'"); + YYERROR; + } + + if ((yyvsp[(1) - (4)].negate)) { + (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate; + } + + (yyval.src_reg).Base.Abs = 1; + ;} + break; + + case 50: + +/* Line 1455 of yacc.c */ +#line 576 "program_parse.y" + { + (yyval.src_reg) = (yyvsp[(1) - (2)].src_reg); + + (yyval.src_reg).Base.Swizzle = _mesa_combine_swizzles((yyval.src_reg).Base.Swizzle, + (yyvsp[(2) - (2)].swiz_mask).swizzle); + ;} + break; + + case 51: + +/* Line 1455 of yacc.c */ +#line 583 "program_parse.y" + { + struct asm_symbol temp_sym; + + if (!state->option.NV_fragment) { + yyerror(& (yylsp[(1) - (1)]), state, "expected scalar suffix"); + YYERROR; + } + + memset(& temp_sym, 0, sizeof(temp_sym)); + temp_sym.param_binding_begin = ~0; + initialize_symbol_from_const(state->prog, & temp_sym, & (yyvsp[(1) - (1)].vector), GL_TRUE); + + set_src_reg_swz(& (yyval.src_reg), PROGRAM_CONSTANT, + temp_sym.param_binding_begin, + temp_sym.param_binding_swizzle); + ;} + break; + + case 52: + +/* Line 1455 of yacc.c */ +#line 602 "program_parse.y" + { + (yyval.src_reg) = (yyvsp[(2) - (3)].src_reg); + + if ((yyvsp[(1) - (3)].negate)) { + (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate; + } + + (yyval.src_reg).Base.Swizzle = _mesa_combine_swizzles((yyval.src_reg).Base.Swizzle, + (yyvsp[(3) - (3)].swiz_mask).swizzle); + ;} + break; + + case 53: + +/* Line 1455 of yacc.c */ +#line 613 "program_parse.y" + { + (yyval.src_reg) = (yyvsp[(3) - (5)].src_reg); + + if (!state->option.NV_fragment) { + yyerror(& (yylsp[(2) - (5)]), state, "unexpected character '|'"); + YYERROR; + } + + if ((yyvsp[(1) - (5)].negate)) { + (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate; + } + + (yyval.src_reg).Base.Abs = 1; + (yyval.src_reg).Base.Swizzle = _mesa_combine_swizzles((yyval.src_reg).Base.Swizzle, + (yyvsp[(4) - (5)].swiz_mask).swizzle); + ;} + break; + + case 54: + +/* Line 1455 of yacc.c */ +#line 633 "program_parse.y" + { + (yyval.dst_reg) = (yyvsp[(1) - (3)].dst_reg); + (yyval.dst_reg).WriteMask = (yyvsp[(2) - (3)].swiz_mask).mask; + (yyval.dst_reg).CondMask = (yyvsp[(3) - (3)].dst_reg).CondMask; + (yyval.dst_reg).CondSwizzle = (yyvsp[(3) - (3)].dst_reg).CondSwizzle; + (yyval.dst_reg).CondSrc = (yyvsp[(3) - (3)].dst_reg).CondSrc; + + if ((yyval.dst_reg).File == PROGRAM_OUTPUT) { + /* Technically speaking, this should check that it is in + * vertex program mode. However, PositionInvariant can never be + * set in fragment program mode, so it is somewhat irrelevant. + */ + if (state->option.PositionInvariant + && ((yyval.dst_reg).Index == VERT_RESULT_HPOS)) { + yyerror(& (yylsp[(1) - (3)]), state, "position-invariant programs cannot " + "write position"); + YYERROR; + } + + state->prog->OutputsWritten |= BITFIELD64_BIT((yyval.dst_reg).Index); + } + ;} + break; + + case 55: + +/* Line 1455 of yacc.c */ +#line 658 "program_parse.y" + { + set_dst_reg(& (yyval.dst_reg), PROGRAM_ADDRESS, 0); + (yyval.dst_reg).WriteMask = (yyvsp[(2) - (2)].swiz_mask).mask; + ;} + break; + + case 56: + +/* Line 1455 of yacc.c */ +#line 665 "program_parse.y" + { + const unsigned xyzw_valid = + ((yyvsp[(1) - (7)].ext_swizzle).xyzw_valid << 0) + | ((yyvsp[(3) - (7)].ext_swizzle).xyzw_valid << 1) + | ((yyvsp[(5) - (7)].ext_swizzle).xyzw_valid << 2) + | ((yyvsp[(7) - (7)].ext_swizzle).xyzw_valid << 3); + const unsigned rgba_valid = + ((yyvsp[(1) - (7)].ext_swizzle).rgba_valid << 0) + | ((yyvsp[(3) - (7)].ext_swizzle).rgba_valid << 1) + | ((yyvsp[(5) - (7)].ext_swizzle).rgba_valid << 2) + | ((yyvsp[(7) - (7)].ext_swizzle).rgba_valid << 3); + + /* All of the swizzle components have to be valid in either RGBA + * or XYZW. Note that 0 and 1 are valid in both, so both masks + * can have some bits set. + * + * We somewhat deviate from the spec here. It would be really hard + * to figure out which component is the error, and there probably + * isn't a lot of benefit. + */ + if ((rgba_valid != 0x0f) && (xyzw_valid != 0x0f)) { + yyerror(& (yylsp[(1) - (7)]), state, "cannot combine RGBA and XYZW swizzle " + "components"); + YYERROR; + } + + (yyval.swiz_mask).swizzle = MAKE_SWIZZLE4((yyvsp[(1) - (7)].ext_swizzle).swz, (yyvsp[(3) - (7)].ext_swizzle).swz, (yyvsp[(5) - (7)].ext_swizzle).swz, (yyvsp[(7) - (7)].ext_swizzle).swz); + (yyval.swiz_mask).mask = ((yyvsp[(1) - (7)].ext_swizzle).negate) | ((yyvsp[(3) - (7)].ext_swizzle).negate << 1) | ((yyvsp[(5) - (7)].ext_swizzle).negate << 2) + | ((yyvsp[(7) - (7)].ext_swizzle).negate << 3); + ;} + break; + + case 57: + +/* Line 1455 of yacc.c */ +#line 698 "program_parse.y" + { + (yyval.ext_swizzle) = (yyvsp[(2) - (2)].ext_swizzle); + (yyval.ext_swizzle).negate = ((yyvsp[(1) - (2)].negate)) ? 1 : 0; + ;} + break; + + case 58: + +/* Line 1455 of yacc.c */ +#line 705 "program_parse.y" + { + if (((yyvsp[(1) - (1)].integer) != 0) && ((yyvsp[(1) - (1)].integer) != 1)) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid extended swizzle selector"); + YYERROR; + } + + (yyval.ext_swizzle).swz = ((yyvsp[(1) - (1)].integer) == 0) ? SWIZZLE_ZERO : SWIZZLE_ONE; + + /* 0 and 1 are valid for both RGBA swizzle names and XYZW + * swizzle names. + */ + (yyval.ext_swizzle).xyzw_valid = 1; + (yyval.ext_swizzle).rgba_valid = 1; + ;} + break; + + case 59: + +/* Line 1455 of yacc.c */ +#line 720 "program_parse.y" + { + char s; + + if (strlen((yyvsp[(1) - (1)].string)) > 1) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid extended swizzle selector"); + YYERROR; + } + + s = (yyvsp[(1) - (1)].string)[0]; + free((yyvsp[(1) - (1)].string)); + + switch (s) { + case 'x': + (yyval.ext_swizzle).swz = SWIZZLE_X; + (yyval.ext_swizzle).xyzw_valid = 1; + break; + case 'y': + (yyval.ext_swizzle).swz = SWIZZLE_Y; + (yyval.ext_swizzle).xyzw_valid = 1; + break; + case 'z': + (yyval.ext_swizzle).swz = SWIZZLE_Z; + (yyval.ext_swizzle).xyzw_valid = 1; + break; + case 'w': + (yyval.ext_swizzle).swz = SWIZZLE_W; + (yyval.ext_swizzle).xyzw_valid = 1; + break; + + case 'r': + (yyval.ext_swizzle).swz = SWIZZLE_X; + (yyval.ext_swizzle).rgba_valid = 1; + break; + case 'g': + (yyval.ext_swizzle).swz = SWIZZLE_Y; + (yyval.ext_swizzle).rgba_valid = 1; + break; + case 'b': + (yyval.ext_swizzle).swz = SWIZZLE_Z; + (yyval.ext_swizzle).rgba_valid = 1; + break; + case 'a': + (yyval.ext_swizzle).swz = SWIZZLE_W; + (yyval.ext_swizzle).rgba_valid = 1; + break; + + default: + yyerror(& (yylsp[(1) - (1)]), state, "invalid extended swizzle selector"); + YYERROR; + break; + } + ;} + break; + + case 60: + +/* Line 1455 of yacc.c */ +#line 775 "program_parse.y" + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string)); + + free((yyvsp[(1) - (1)].string)); + + if (s == NULL) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable"); + YYERROR; + } else if ((s->type != at_param) && (s->type != at_temp) + && (s->type != at_attrib)) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable"); + YYERROR; + } else if ((s->type == at_param) && s->param_is_array) { + yyerror(& (yylsp[(1) - (1)]), state, "non-array access to array PARAM"); + YYERROR; + } + + init_src_reg(& (yyval.src_reg)); + switch (s->type) { + case at_temp: + set_src_reg(& (yyval.src_reg), PROGRAM_TEMPORARY, s->temp_binding); + break; + case at_param: + set_src_reg_swz(& (yyval.src_reg), s->param_binding_type, + s->param_binding_begin, + s->param_binding_swizzle); + break; + case at_attrib: + set_src_reg(& (yyval.src_reg), PROGRAM_INPUT, s->attrib_binding); + state->prog->InputsRead |= (1U << (yyval.src_reg).Base.Index); + + if (!validate_inputs(& (yylsp[(1) - (1)]), state)) { + YYERROR; + } + break; + + default: + YYERROR; + break; + } + ;} + break; + + case 61: + +/* Line 1455 of yacc.c */ +#line 818 "program_parse.y" + { + set_src_reg(& (yyval.src_reg), PROGRAM_INPUT, (yyvsp[(1) - (1)].attrib)); + state->prog->InputsRead |= (1U << (yyval.src_reg).Base.Index); + + if (!validate_inputs(& (yylsp[(1) - (1)]), state)) { + YYERROR; + } + ;} + break; + + case 62: + +/* Line 1455 of yacc.c */ +#line 827 "program_parse.y" + { + if (! (yyvsp[(3) - (4)].src_reg).Base.RelAddr + && ((unsigned) (yyvsp[(3) - (4)].src_reg).Base.Index >= (yyvsp[(1) - (4)].sym)->param_binding_length)) { + yyerror(& (yylsp[(3) - (4)]), state, "out of bounds array access"); + YYERROR; + } + + init_src_reg(& (yyval.src_reg)); + (yyval.src_reg).Base.File = (yyvsp[(1) - (4)].sym)->param_binding_type; + + if ((yyvsp[(3) - (4)].src_reg).Base.RelAddr) { + (yyvsp[(1) - (4)].sym)->param_accessed_indirectly = 1; + + (yyval.src_reg).Base.RelAddr = 1; + (yyval.src_reg).Base.Index = (yyvsp[(3) - (4)].src_reg).Base.Index; + (yyval.src_reg).Symbol = (yyvsp[(1) - (4)].sym); + } else { + (yyval.src_reg).Base.Index = (yyvsp[(1) - (4)].sym)->param_binding_begin + (yyvsp[(3) - (4)].src_reg).Base.Index; + } + ;} + break; + + case 63: + +/* Line 1455 of yacc.c */ +#line 848 "program_parse.y" + { + gl_register_file file = ((yyvsp[(1) - (1)].temp_sym).name != NULL) + ? (yyvsp[(1) - (1)].temp_sym).param_binding_type + : PROGRAM_CONSTANT; + set_src_reg_swz(& (yyval.src_reg), file, (yyvsp[(1) - (1)].temp_sym).param_binding_begin, + (yyvsp[(1) - (1)].temp_sym).param_binding_swizzle); + ;} + break; + + case 64: + +/* Line 1455 of yacc.c */ +#line 858 "program_parse.y" + { + set_dst_reg(& (yyval.dst_reg), PROGRAM_OUTPUT, (yyvsp[(1) - (1)].result)); + ;} + break; + + case 65: + +/* Line 1455 of yacc.c */ +#line 862 "program_parse.y" + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string)); + + free((yyvsp[(1) - (1)].string)); + + if (s == NULL) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable"); + YYERROR; + } else if ((s->type != at_output) && (s->type != at_temp)) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable"); + YYERROR; + } + + switch (s->type) { + case at_temp: + set_dst_reg(& (yyval.dst_reg), PROGRAM_TEMPORARY, s->temp_binding); + break; + case at_output: + set_dst_reg(& (yyval.dst_reg), PROGRAM_OUTPUT, s->output_binding); + break; + default: + set_dst_reg(& (yyval.dst_reg), s->param_binding_type, s->param_binding_begin); + break; + } + ;} + break; + + case 66: + +/* Line 1455 of yacc.c */ +#line 891 "program_parse.y" + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string)); + + free((yyvsp[(1) - (1)].string)); + + if (s == NULL) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable"); + YYERROR; + } else if ((s->type != at_param) || !s->param_is_array) { + yyerror(& (yylsp[(1) - (1)]), state, "array access to non-PARAM variable"); + YYERROR; + } else { + (yyval.sym) = s; + } + ;} + break; + + case 69: + +/* Line 1455 of yacc.c */ +#line 912 "program_parse.y" + { + init_src_reg(& (yyval.src_reg)); + (yyval.src_reg).Base.Index = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 70: + +/* Line 1455 of yacc.c */ +#line 919 "program_parse.y" + { + /* FINISHME: Add support for multiple address registers. + */ + /* FINISHME: Add support for 4-component address registers. + */ + init_src_reg(& (yyval.src_reg)); + (yyval.src_reg).Base.RelAddr = 1; + (yyval.src_reg).Base.Index = (yyvsp[(3) - (3)].integer); + ;} + break; + + case 71: + +/* Line 1455 of yacc.c */ +#line 930 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 72: + +/* Line 1455 of yacc.c */ +#line 931 "program_parse.y" + { (yyval.integer) = (yyvsp[(2) - (2)].integer); ;} + break; + + case 73: + +/* Line 1455 of yacc.c */ +#line 932 "program_parse.y" + { (yyval.integer) = -(yyvsp[(2) - (2)].integer); ;} + break; + + case 74: + +/* Line 1455 of yacc.c */ +#line 936 "program_parse.y" + { + if (((yyvsp[(1) - (1)].integer) < 0) || ((yyvsp[(1) - (1)].integer) > 63)) { + char s[100]; + _mesa_snprintf(s, sizeof(s), + "relative address offset too large (%d)", (yyvsp[(1) - (1)].integer)); + yyerror(& (yylsp[(1) - (1)]), state, s); + YYERROR; + } else { + (yyval.integer) = (yyvsp[(1) - (1)].integer); + } + ;} + break; + + case 75: + +/* Line 1455 of yacc.c */ +#line 950 "program_parse.y" + { + if (((yyvsp[(1) - (1)].integer) < 0) || ((yyvsp[(1) - (1)].integer) > 64)) { + char s[100]; + _mesa_snprintf(s, sizeof(s), + "relative address offset too large (%d)", (yyvsp[(1) - (1)].integer)); + yyerror(& (yylsp[(1) - (1)]), state, s); + YYERROR; + } else { + (yyval.integer) = (yyvsp[(1) - (1)].integer); + } + ;} + break; + + case 76: + +/* Line 1455 of yacc.c */ +#line 964 "program_parse.y" + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string)); + + free((yyvsp[(1) - (1)].string)); + + if (s == NULL) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid array member"); + YYERROR; + } else if (s->type != at_address) { + yyerror(& (yylsp[(1) - (1)]), state, + "invalid variable for indexed array access"); + YYERROR; + } else { + (yyval.sym) = s; + } + ;} + break; + + case 77: + +/* Line 1455 of yacc.c */ +#line 984 "program_parse.y" + { + if ((yyvsp[(1) - (1)].swiz_mask).mask != WRITEMASK_X) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid address component selector"); + YYERROR; + } else { + (yyval.swiz_mask) = (yyvsp[(1) - (1)].swiz_mask); + } + ;} + break; + + case 78: + +/* Line 1455 of yacc.c */ +#line 995 "program_parse.y" + { + if ((yyvsp[(1) - (1)].swiz_mask).mask != WRITEMASK_X) { + yyerror(& (yylsp[(1) - (1)]), state, + "address register write mask must be \".x\""); + YYERROR; + } else { + (yyval.swiz_mask) = (yyvsp[(1) - (1)].swiz_mask); + } + ;} + break; + + case 83: + +/* Line 1455 of yacc.c */ +#line 1011 "program_parse.y" + { (yyval.swiz_mask).swizzle = SWIZZLE_NOOP; (yyval.swiz_mask).mask = WRITEMASK_XYZW; ;} + break; + + case 88: + +/* Line 1455 of yacc.c */ +#line 1015 "program_parse.y" + { (yyval.swiz_mask).swizzle = SWIZZLE_NOOP; (yyval.swiz_mask).mask = WRITEMASK_XYZW; ;} + break; + + case 89: + +/* Line 1455 of yacc.c */ +#line 1019 "program_parse.y" + { + (yyval.dst_reg) = (yyvsp[(2) - (3)].dst_reg); + ;} + break; + + case 90: + +/* Line 1455 of yacc.c */ +#line 1023 "program_parse.y" + { + (yyval.dst_reg) = (yyvsp[(2) - (3)].dst_reg); + ;} + break; + + case 91: + +/* Line 1455 of yacc.c */ +#line 1027 "program_parse.y" + { + (yyval.dst_reg).CondMask = COND_TR; + (yyval.dst_reg).CondSwizzle = SWIZZLE_NOOP; + (yyval.dst_reg).CondSrc = 0; + ;} + break; + + case 92: + +/* Line 1455 of yacc.c */ +#line 1035 "program_parse.y" + { + (yyval.dst_reg) = (yyvsp[(1) - (2)].dst_reg); + (yyval.dst_reg).CondSwizzle = (yyvsp[(2) - (2)].swiz_mask).swizzle; + ;} + break; + + case 93: + +/* Line 1455 of yacc.c */ +#line 1042 "program_parse.y" + { + (yyval.dst_reg) = (yyvsp[(1) - (2)].dst_reg); + (yyval.dst_reg).CondSwizzle = (yyvsp[(2) - (2)].swiz_mask).swizzle; + ;} + break; + + case 94: + +/* Line 1455 of yacc.c */ +#line 1049 "program_parse.y" + { + const int cond = _mesa_parse_cc((yyvsp[(1) - (1)].string)); + if ((cond == 0) || ((yyvsp[(1) - (1)].string)[2] != '\0')) { + char *const err_str = + make_error_string("invalid condition code \"%s\"", (yyvsp[(1) - (1)].string)); + + yyerror(& (yylsp[(1) - (1)]), state, (err_str != NULL) + ? err_str : "invalid condition code"); + + if (err_str != NULL) { + free(err_str); + } + + YYERROR; + } + + (yyval.dst_reg).CondMask = cond; + (yyval.dst_reg).CondSwizzle = SWIZZLE_NOOP; + (yyval.dst_reg).CondSrc = 0; + ;} + break; + + case 95: + +/* Line 1455 of yacc.c */ +#line 1072 "program_parse.y" + { + const int cond = _mesa_parse_cc((yyvsp[(1) - (1)].string)); + if ((cond == 0) || ((yyvsp[(1) - (1)].string)[2] != '\0')) { + char *const err_str = + make_error_string("invalid condition code \"%s\"", (yyvsp[(1) - (1)].string)); + + yyerror(& (yylsp[(1) - (1)]), state, (err_str != NULL) + ? err_str : "invalid condition code"); + + if (err_str != NULL) { + free(err_str); + } + + YYERROR; + } + + (yyval.dst_reg).CondMask = cond; + (yyval.dst_reg).CondSwizzle = SWIZZLE_NOOP; + (yyval.dst_reg).CondSrc = 0; + ;} + break; + + case 102: + +/* Line 1455 of yacc.c */ +#line 1103 "program_parse.y" + { + struct asm_symbol *const s = + declare_variable(state, (yyvsp[(2) - (4)].string), at_attrib, & (yylsp[(2) - (4)])); + + if (s == NULL) { + free((yyvsp[(2) - (4)].string)); + YYERROR; + } else { + s->attrib_binding = (yyvsp[(4) - (4)].attrib); + state->InputsBound |= (1U << s->attrib_binding); + + if (!validate_inputs(& (yylsp[(4) - (4)]), state)) { + YYERROR; + } + } + ;} + break; + + case 103: + +/* Line 1455 of yacc.c */ +#line 1122 "program_parse.y" + { + (yyval.attrib) = (yyvsp[(2) - (2)].attrib); + ;} + break; + + case 104: + +/* Line 1455 of yacc.c */ +#line 1126 "program_parse.y" + { + (yyval.attrib) = (yyvsp[(2) - (2)].attrib); + ;} + break; + + case 105: + +/* Line 1455 of yacc.c */ +#line 1132 "program_parse.y" + { + (yyval.attrib) = VERT_ATTRIB_POS; + ;} + break; + + case 106: + +/* Line 1455 of yacc.c */ +#line 1136 "program_parse.y" + { + (yyval.attrib) = VERT_ATTRIB_WEIGHT; + ;} + break; + + case 107: + +/* Line 1455 of yacc.c */ +#line 1140 "program_parse.y" + { + (yyval.attrib) = VERT_ATTRIB_NORMAL; + ;} + break; + + case 108: + +/* Line 1455 of yacc.c */ +#line 1144 "program_parse.y" + { + if (!state->ctx->Extensions.EXT_secondary_color) { + yyerror(& (yylsp[(2) - (2)]), state, "GL_EXT_secondary_color not supported"); + YYERROR; + } + + (yyval.attrib) = VERT_ATTRIB_COLOR0 + (yyvsp[(2) - (2)].integer); + ;} + break; + + case 109: + +/* Line 1455 of yacc.c */ +#line 1153 "program_parse.y" + { + if (!state->ctx->Extensions.EXT_fog_coord) { + yyerror(& (yylsp[(1) - (1)]), state, "GL_EXT_fog_coord not supported"); + YYERROR; + } + + (yyval.attrib) = VERT_ATTRIB_FOG; + ;} + break; + + case 110: + +/* Line 1455 of yacc.c */ +#line 1162 "program_parse.y" + { + (yyval.attrib) = VERT_ATTRIB_TEX0 + (yyvsp[(2) - (2)].integer); + ;} + break; + + case 111: + +/* Line 1455 of yacc.c */ +#line 1166 "program_parse.y" + { + yyerror(& (yylsp[(1) - (4)]), state, "GL_ARB_matrix_palette not supported"); + YYERROR; + ;} + break; + + case 112: + +/* Line 1455 of yacc.c */ +#line 1171 "program_parse.y" + { + (yyval.attrib) = VERT_ATTRIB_GENERIC0 + (yyvsp[(3) - (4)].integer); + ;} + break; + + case 113: + +/* Line 1455 of yacc.c */ +#line 1177 "program_parse.y" + { + if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->limits->MaxAttribs) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid vertex attribute reference"); + YYERROR; + } + + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 117: + +/* Line 1455 of yacc.c */ +#line 1191 "program_parse.y" + { + (yyval.attrib) = FRAG_ATTRIB_WPOS; + ;} + break; + + case 118: + +/* Line 1455 of yacc.c */ +#line 1195 "program_parse.y" + { + (yyval.attrib) = FRAG_ATTRIB_COL0 + (yyvsp[(2) - (2)].integer); + ;} + break; + + case 119: + +/* Line 1455 of yacc.c */ +#line 1199 "program_parse.y" + { + (yyval.attrib) = FRAG_ATTRIB_FOGC; + ;} + break; + + case 120: + +/* Line 1455 of yacc.c */ +#line 1203 "program_parse.y" + { + (yyval.attrib) = FRAG_ATTRIB_TEX0 + (yyvsp[(2) - (2)].integer); + ;} + break; + + case 123: + +/* Line 1455 of yacc.c */ +#line 1211 "program_parse.y" + { + struct asm_symbol *const s = + declare_variable(state, (yyvsp[(2) - (3)].string), at_param, & (yylsp[(2) - (3)])); + + if (s == NULL) { + free((yyvsp[(2) - (3)].string)); + YYERROR; + } else { + s->param_binding_type = (yyvsp[(3) - (3)].temp_sym).param_binding_type; + s->param_binding_begin = (yyvsp[(3) - (3)].temp_sym).param_binding_begin; + s->param_binding_length = (yyvsp[(3) - (3)].temp_sym).param_binding_length; + s->param_binding_swizzle = (yyvsp[(3) - (3)].temp_sym).param_binding_swizzle; + s->param_is_array = 0; + } + ;} + break; + + case 124: + +/* Line 1455 of yacc.c */ +#line 1229 "program_parse.y" + { + if (((yyvsp[(4) - (6)].integer) != 0) && ((unsigned) (yyvsp[(4) - (6)].integer) != (yyvsp[(6) - (6)].temp_sym).param_binding_length)) { + free((yyvsp[(2) - (6)].string)); + yyerror(& (yylsp[(4) - (6)]), state, + "parameter array size and number of bindings must match"); + YYERROR; + } else { + struct asm_symbol *const s = + declare_variable(state, (yyvsp[(2) - (6)].string), (yyvsp[(6) - (6)].temp_sym).type, & (yylsp[(2) - (6)])); + + if (s == NULL) { + free((yyvsp[(2) - (6)].string)); + YYERROR; + } else { + s->param_binding_type = (yyvsp[(6) - (6)].temp_sym).param_binding_type; + s->param_binding_begin = (yyvsp[(6) - (6)].temp_sym).param_binding_begin; + s->param_binding_length = (yyvsp[(6) - (6)].temp_sym).param_binding_length; + s->param_binding_swizzle = SWIZZLE_XYZW; + s->param_is_array = 1; + } + } + ;} + break; + + case 125: + +/* Line 1455 of yacc.c */ +#line 1254 "program_parse.y" + { + (yyval.integer) = 0; + ;} + break; + + case 126: + +/* Line 1455 of yacc.c */ +#line 1258 "program_parse.y" + { + if (((yyvsp[(1) - (1)].integer) < 1) || ((unsigned) (yyvsp[(1) - (1)].integer) > state->limits->MaxParameters)) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid parameter array size"); + YYERROR; + } else { + (yyval.integer) = (yyvsp[(1) - (1)].integer); + } + ;} + break; + + case 127: + +/* Line 1455 of yacc.c */ +#line 1269 "program_parse.y" + { + (yyval.temp_sym) = (yyvsp[(2) - (2)].temp_sym); + ;} + break; + + case 128: + +/* Line 1455 of yacc.c */ +#line 1275 "program_parse.y" + { + (yyval.temp_sym) = (yyvsp[(3) - (4)].temp_sym); + ;} + break; + + case 130: + +/* Line 1455 of yacc.c */ +#line 1282 "program_parse.y" + { + (yyvsp[(1) - (3)].temp_sym).param_binding_length += (yyvsp[(3) - (3)].temp_sym).param_binding_length; + (yyval.temp_sym) = (yyvsp[(1) - (3)].temp_sym); + ;} + break; + + case 131: + +/* Line 1455 of yacc.c */ +#line 1289 "program_parse.y" + { + memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); + (yyval.temp_sym).param_binding_begin = ~0; + initialize_symbol_from_state(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state)); + ;} + break; + + case 132: + +/* Line 1455 of yacc.c */ +#line 1295 "program_parse.y" + { + memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); + (yyval.temp_sym).param_binding_begin = ~0; + initialize_symbol_from_param(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state)); + ;} + break; + + case 133: + +/* Line 1455 of yacc.c */ +#line 1301 "program_parse.y" + { + memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); + (yyval.temp_sym).param_binding_begin = ~0; + initialize_symbol_from_const(state->prog, & (yyval.temp_sym), & (yyvsp[(1) - (1)].vector), GL_TRUE); + ;} + break; + + case 134: + +/* Line 1455 of yacc.c */ +#line 1309 "program_parse.y" + { + memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); + (yyval.temp_sym).param_binding_begin = ~0; + initialize_symbol_from_state(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state)); + ;} + break; + + case 135: + +/* Line 1455 of yacc.c */ +#line 1315 "program_parse.y" + { + memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); + (yyval.temp_sym).param_binding_begin = ~0; + initialize_symbol_from_param(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state)); + ;} + break; + + case 136: + +/* Line 1455 of yacc.c */ +#line 1321 "program_parse.y" + { + memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); + (yyval.temp_sym).param_binding_begin = ~0; + initialize_symbol_from_const(state->prog, & (yyval.temp_sym), & (yyvsp[(1) - (1)].vector), GL_TRUE); + ;} + break; + + case 137: + +/* Line 1455 of yacc.c */ +#line 1329 "program_parse.y" + { + memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); + (yyval.temp_sym).param_binding_begin = ~0; + initialize_symbol_from_state(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state)); + ;} + break; + + case 138: + +/* Line 1455 of yacc.c */ +#line 1335 "program_parse.y" + { + memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); + (yyval.temp_sym).param_binding_begin = ~0; + initialize_symbol_from_param(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state)); + ;} + break; + + case 139: + +/* Line 1455 of yacc.c */ +#line 1341 "program_parse.y" + { + memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); + (yyval.temp_sym).param_binding_begin = ~0; + initialize_symbol_from_const(state->prog, & (yyval.temp_sym), & (yyvsp[(1) - (1)].vector), GL_FALSE); + ;} + break; + + case 140: + +/* Line 1455 of yacc.c */ +#line 1348 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(1) - (1)].state), sizeof((yyval.state))); ;} + break; + + case 141: + +/* Line 1455 of yacc.c */ +#line 1349 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 142: + +/* Line 1455 of yacc.c */ +#line 1352 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 143: + +/* Line 1455 of yacc.c */ +#line 1353 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 144: + +/* Line 1455 of yacc.c */ +#line 1354 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 145: + +/* Line 1455 of yacc.c */ +#line 1355 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 146: + +/* Line 1455 of yacc.c */ +#line 1356 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 147: + +/* Line 1455 of yacc.c */ +#line 1357 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 148: + +/* Line 1455 of yacc.c */ +#line 1358 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 149: + +/* Line 1455 of yacc.c */ +#line 1359 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 150: + +/* Line 1455 of yacc.c */ +#line 1360 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 151: + +/* Line 1455 of yacc.c */ +#line 1361 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 152: + +/* Line 1455 of yacc.c */ +#line 1362 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 153: + +/* Line 1455 of yacc.c */ +#line 1366 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = STATE_MATERIAL; + (yyval.state)[1] = (yyvsp[(2) - (3)].integer); + (yyval.state)[2] = (yyvsp[(3) - (3)].integer); + ;} + break; + + case 154: + +/* Line 1455 of yacc.c */ +#line 1375 "program_parse.y" + { + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 155: + +/* Line 1455 of yacc.c */ +#line 1379 "program_parse.y" + { + (yyval.integer) = STATE_EMISSION; + ;} + break; + + case 156: + +/* Line 1455 of yacc.c */ +#line 1383 "program_parse.y" + { + (yyval.integer) = STATE_SHININESS; + ;} + break; + + case 157: + +/* Line 1455 of yacc.c */ +#line 1389 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = STATE_LIGHT; + (yyval.state)[1] = (yyvsp[(3) - (5)].integer); + (yyval.state)[2] = (yyvsp[(5) - (5)].integer); + ;} + break; + + case 158: + +/* Line 1455 of yacc.c */ +#line 1398 "program_parse.y" + { + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 159: + +/* Line 1455 of yacc.c */ +#line 1402 "program_parse.y" + { + (yyval.integer) = STATE_POSITION; + ;} + break; + + case 160: + +/* Line 1455 of yacc.c */ +#line 1406 "program_parse.y" + { + if (!state->ctx->Extensions.EXT_point_parameters) { + yyerror(& (yylsp[(1) - (1)]), state, "GL_ARB_point_parameters not supported"); + YYERROR; + } + + (yyval.integer) = STATE_ATTENUATION; + ;} + break; + + case 161: + +/* Line 1455 of yacc.c */ +#line 1415 "program_parse.y" + { + (yyval.integer) = (yyvsp[(2) - (2)].integer); + ;} + break; + + case 162: + +/* Line 1455 of yacc.c */ +#line 1419 "program_parse.y" + { + (yyval.integer) = STATE_HALF_VECTOR; + ;} + break; + + case 163: + +/* Line 1455 of yacc.c */ +#line 1425 "program_parse.y" + { + (yyval.integer) = STATE_SPOT_DIRECTION; + ;} + break; + + case 164: + +/* Line 1455 of yacc.c */ +#line 1431 "program_parse.y" + { + (yyval.state)[0] = (yyvsp[(2) - (2)].state)[0]; + (yyval.state)[1] = (yyvsp[(2) - (2)].state)[1]; + ;} + break; + + case 165: + +/* Line 1455 of yacc.c */ +#line 1438 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = STATE_LIGHTMODEL_AMBIENT; + ;} + break; + + case 166: + +/* Line 1455 of yacc.c */ +#line 1443 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = STATE_LIGHTMODEL_SCENECOLOR; + (yyval.state)[1] = (yyvsp[(1) - (2)].integer); + ;} + break; + + case 167: + +/* Line 1455 of yacc.c */ +#line 1451 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = STATE_LIGHTPROD; + (yyval.state)[1] = (yyvsp[(3) - (6)].integer); + (yyval.state)[2] = (yyvsp[(5) - (6)].integer); + (yyval.state)[3] = (yyvsp[(6) - (6)].integer); + ;} + break; + + case 169: + +/* Line 1455 of yacc.c */ +#line 1463 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = (yyvsp[(3) - (3)].integer); + (yyval.state)[1] = (yyvsp[(2) - (3)].integer); + ;} + break; + + case 170: + +/* Line 1455 of yacc.c */ +#line 1471 "program_parse.y" + { + (yyval.integer) = STATE_TEXENV_COLOR; + ;} + break; + + case 171: + +/* Line 1455 of yacc.c */ +#line 1477 "program_parse.y" + { + (yyval.integer) = STATE_AMBIENT; + ;} + break; + + case 172: + +/* Line 1455 of yacc.c */ +#line 1481 "program_parse.y" + { + (yyval.integer) = STATE_DIFFUSE; + ;} + break; + + case 173: + +/* Line 1455 of yacc.c */ +#line 1485 "program_parse.y" + { + (yyval.integer) = STATE_SPECULAR; + ;} + break; + + case 174: + +/* Line 1455 of yacc.c */ +#line 1491 "program_parse.y" + { + if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxLights) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid light selector"); + YYERROR; + } + + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 175: + +/* Line 1455 of yacc.c */ +#line 1502 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = STATE_TEXGEN; + (yyval.state)[1] = (yyvsp[(2) - (4)].integer); + (yyval.state)[2] = (yyvsp[(3) - (4)].integer) + (yyvsp[(4) - (4)].integer); + ;} + break; + + case 176: + +/* Line 1455 of yacc.c */ +#line 1511 "program_parse.y" + { + (yyval.integer) = STATE_TEXGEN_EYE_S; + ;} + break; + + case 177: + +/* Line 1455 of yacc.c */ +#line 1515 "program_parse.y" + { + (yyval.integer) = STATE_TEXGEN_OBJECT_S; + ;} + break; + + case 178: + +/* Line 1455 of yacc.c */ +#line 1520 "program_parse.y" + { + (yyval.integer) = STATE_TEXGEN_EYE_S - STATE_TEXGEN_EYE_S; + ;} + break; + + case 179: + +/* Line 1455 of yacc.c */ +#line 1524 "program_parse.y" + { + (yyval.integer) = STATE_TEXGEN_EYE_T - STATE_TEXGEN_EYE_S; + ;} + break; + + case 180: + +/* Line 1455 of yacc.c */ +#line 1528 "program_parse.y" + { + (yyval.integer) = STATE_TEXGEN_EYE_R - STATE_TEXGEN_EYE_S; + ;} + break; + + case 181: + +/* Line 1455 of yacc.c */ +#line 1532 "program_parse.y" + { + (yyval.integer) = STATE_TEXGEN_EYE_Q - STATE_TEXGEN_EYE_S; + ;} + break; + + case 182: + +/* Line 1455 of yacc.c */ +#line 1538 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = (yyvsp[(2) - (2)].integer); + ;} + break; + + case 183: + +/* Line 1455 of yacc.c */ +#line 1545 "program_parse.y" + { + (yyval.integer) = STATE_FOG_COLOR; + ;} + break; + + case 184: + +/* Line 1455 of yacc.c */ +#line 1549 "program_parse.y" + { + (yyval.integer) = STATE_FOG_PARAMS; + ;} + break; + + case 185: + +/* Line 1455 of yacc.c */ +#line 1555 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = STATE_CLIPPLANE; + (yyval.state)[1] = (yyvsp[(3) - (5)].integer); + ;} + break; + + case 186: + +/* Line 1455 of yacc.c */ +#line 1563 "program_parse.y" + { + if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxClipPlanes) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid clip plane selector"); + YYERROR; + } + + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 187: + +/* Line 1455 of yacc.c */ +#line 1574 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = (yyvsp[(2) - (2)].integer); + ;} + break; + + case 188: + +/* Line 1455 of yacc.c */ +#line 1581 "program_parse.y" + { + (yyval.integer) = STATE_POINT_SIZE; + ;} + break; + + case 189: + +/* Line 1455 of yacc.c */ +#line 1585 "program_parse.y" + { + (yyval.integer) = STATE_POINT_ATTENUATION; + ;} + break; + + case 190: + +/* Line 1455 of yacc.c */ +#line 1591 "program_parse.y" + { + (yyval.state)[0] = (yyvsp[(1) - (5)].state)[0]; + (yyval.state)[1] = (yyvsp[(1) - (5)].state)[1]; + (yyval.state)[2] = (yyvsp[(4) - (5)].integer); + (yyval.state)[3] = (yyvsp[(4) - (5)].integer); + (yyval.state)[4] = (yyvsp[(1) - (5)].state)[2]; + ;} + break; + + case 191: + +/* Line 1455 of yacc.c */ +#line 1601 "program_parse.y" + { + (yyval.state)[0] = (yyvsp[(1) - (2)].state)[0]; + (yyval.state)[1] = (yyvsp[(1) - (2)].state)[1]; + (yyval.state)[2] = (yyvsp[(2) - (2)].state)[2]; + (yyval.state)[3] = (yyvsp[(2) - (2)].state)[3]; + (yyval.state)[4] = (yyvsp[(1) - (2)].state)[2]; + ;} + break; + + case 192: + +/* Line 1455 of yacc.c */ +#line 1611 "program_parse.y" + { + (yyval.state)[2] = 0; + (yyval.state)[3] = 3; + ;} + break; + + case 193: + +/* Line 1455 of yacc.c */ +#line 1616 "program_parse.y" + { + /* It seems logical that the matrix row range specifier would have + * to specify a range or more than one row (i.e., $5 > $3). + * However, the ARB_vertex_program spec says "a program will fail + * to load if is greater than ." This means that $3 == $5 + * is valid. + */ + if ((yyvsp[(3) - (6)].integer) > (yyvsp[(5) - (6)].integer)) { + yyerror(& (yylsp[(3) - (6)]), state, "invalid matrix row range"); + YYERROR; + } + + (yyval.state)[2] = (yyvsp[(3) - (6)].integer); + (yyval.state)[3] = (yyvsp[(5) - (6)].integer); + ;} + break; + + case 194: + +/* Line 1455 of yacc.c */ +#line 1634 "program_parse.y" + { + (yyval.state)[0] = (yyvsp[(2) - (3)].state)[0]; + (yyval.state)[1] = (yyvsp[(2) - (3)].state)[1]; + (yyval.state)[2] = (yyvsp[(3) - (3)].integer); + ;} + break; + + case 195: + +/* Line 1455 of yacc.c */ +#line 1642 "program_parse.y" + { + (yyval.integer) = 0; + ;} + break; + + case 196: + +/* Line 1455 of yacc.c */ +#line 1646 "program_parse.y" + { + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 197: + +/* Line 1455 of yacc.c */ +#line 1652 "program_parse.y" + { + (yyval.integer) = STATE_MATRIX_INVERSE; + ;} + break; + + case 198: + +/* Line 1455 of yacc.c */ +#line 1656 "program_parse.y" + { + (yyval.integer) = STATE_MATRIX_TRANSPOSE; + ;} + break; + + case 199: + +/* Line 1455 of yacc.c */ +#line 1660 "program_parse.y" + { + (yyval.integer) = STATE_MATRIX_INVTRANS; + ;} + break; + + case 200: + +/* Line 1455 of yacc.c */ +#line 1666 "program_parse.y" + { + if ((yyvsp[(1) - (1)].integer) > 3) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid matrix row reference"); + YYERROR; + } + + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 201: + +/* Line 1455 of yacc.c */ +#line 1677 "program_parse.y" + { + (yyval.state)[0] = STATE_MODELVIEW_MATRIX; + (yyval.state)[1] = (yyvsp[(2) - (2)].integer); + ;} + break; + + case 202: + +/* Line 1455 of yacc.c */ +#line 1682 "program_parse.y" + { + (yyval.state)[0] = STATE_PROJECTION_MATRIX; + (yyval.state)[1] = 0; + ;} + break; + + case 203: + +/* Line 1455 of yacc.c */ +#line 1687 "program_parse.y" + { + (yyval.state)[0] = STATE_MVP_MATRIX; + (yyval.state)[1] = 0; + ;} + break; + + case 204: + +/* Line 1455 of yacc.c */ +#line 1692 "program_parse.y" + { + (yyval.state)[0] = STATE_TEXTURE_MATRIX; + (yyval.state)[1] = (yyvsp[(2) - (2)].integer); + ;} + break; + + case 205: + +/* Line 1455 of yacc.c */ +#line 1697 "program_parse.y" + { + yyerror(& (yylsp[(1) - (4)]), state, "GL_ARB_matrix_palette not supported"); + YYERROR; + ;} + break; + + case 206: + +/* Line 1455 of yacc.c */ +#line 1702 "program_parse.y" + { + (yyval.state)[0] = STATE_PROGRAM_MATRIX; + (yyval.state)[1] = (yyvsp[(3) - (4)].integer); + ;} + break; + + case 207: + +/* Line 1455 of yacc.c */ +#line 1709 "program_parse.y" + { + (yyval.integer) = 0; + ;} + break; + + case 208: + +/* Line 1455 of yacc.c */ +#line 1713 "program_parse.y" + { + (yyval.integer) = (yyvsp[(2) - (3)].integer); + ;} + break; + + case 209: + +/* Line 1455 of yacc.c */ +#line 1718 "program_parse.y" + { + /* Since GL_ARB_vertex_blend isn't supported, only modelview matrix + * zero is valid. + */ + if ((yyvsp[(1) - (1)].integer) != 0) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid modelview matrix index"); + YYERROR; + } + + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 210: + +/* Line 1455 of yacc.c */ +#line 1731 "program_parse.y" + { + /* Since GL_ARB_matrix_palette isn't supported, just let any value + * through here. The error will be generated later. + */ + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 211: + +/* Line 1455 of yacc.c */ +#line 1739 "program_parse.y" + { + if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxProgramMatrices) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid program matrix selector"); + YYERROR; + } + + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 212: + +/* Line 1455 of yacc.c */ +#line 1750 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = STATE_DEPTH_RANGE; + ;} + break; + + case 217: + +/* Line 1455 of yacc.c */ +#line 1762 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = state->state_param_enum; + (yyval.state)[1] = STATE_ENV; + (yyval.state)[2] = (yyvsp[(4) - (5)].state)[0]; + (yyval.state)[3] = (yyvsp[(4) - (5)].state)[1]; + ;} + break; + + case 218: + +/* Line 1455 of yacc.c */ +#line 1772 "program_parse.y" + { + (yyval.state)[0] = (yyvsp[(1) - (1)].integer); + (yyval.state)[1] = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 219: + +/* Line 1455 of yacc.c */ +#line 1777 "program_parse.y" + { + (yyval.state)[0] = (yyvsp[(1) - (3)].integer); + (yyval.state)[1] = (yyvsp[(3) - (3)].integer); + ;} + break; + + case 220: + +/* Line 1455 of yacc.c */ +#line 1784 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = state->state_param_enum; + (yyval.state)[1] = STATE_ENV; + (yyval.state)[2] = (yyvsp[(4) - (5)].integer); + (yyval.state)[3] = (yyvsp[(4) - (5)].integer); + ;} + break; + + case 221: + +/* Line 1455 of yacc.c */ +#line 1794 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = state->state_param_enum; + (yyval.state)[1] = STATE_LOCAL; + (yyval.state)[2] = (yyvsp[(4) - (5)].state)[0]; + (yyval.state)[3] = (yyvsp[(4) - (5)].state)[1]; + ;} + break; + + case 222: + +/* Line 1455 of yacc.c */ +#line 1803 "program_parse.y" + { + (yyval.state)[0] = (yyvsp[(1) - (1)].integer); + (yyval.state)[1] = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 223: + +/* Line 1455 of yacc.c */ +#line 1808 "program_parse.y" + { + (yyval.state)[0] = (yyvsp[(1) - (3)].integer); + (yyval.state)[1] = (yyvsp[(3) - (3)].integer); + ;} + break; + + case 224: + +/* Line 1455 of yacc.c */ +#line 1815 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = state->state_param_enum; + (yyval.state)[1] = STATE_LOCAL; + (yyval.state)[2] = (yyvsp[(4) - (5)].integer); + (yyval.state)[3] = (yyvsp[(4) - (5)].integer); + ;} + break; + + case 225: + +/* Line 1455 of yacc.c */ +#line 1825 "program_parse.y" + { + if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->limits->MaxEnvParams) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid environment parameter reference"); + YYERROR; + } + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 226: + +/* Line 1455 of yacc.c */ +#line 1835 "program_parse.y" + { + if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->limits->MaxLocalParams) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid local parameter reference"); + YYERROR; + } + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 231: + +/* Line 1455 of yacc.c */ +#line 1850 "program_parse.y" + { + (yyval.vector).count = 4; + (yyval.vector).data[0] = (yyvsp[(1) - (1)].real); + (yyval.vector).data[1] = (yyvsp[(1) - (1)].real); + (yyval.vector).data[2] = (yyvsp[(1) - (1)].real); + (yyval.vector).data[3] = (yyvsp[(1) - (1)].real); + ;} + break; + + case 232: + +/* Line 1455 of yacc.c */ +#line 1860 "program_parse.y" + { + (yyval.vector).count = 1; + (yyval.vector).data[0] = (yyvsp[(1) - (1)].real); + (yyval.vector).data[1] = (yyvsp[(1) - (1)].real); + (yyval.vector).data[2] = (yyvsp[(1) - (1)].real); + (yyval.vector).data[3] = (yyvsp[(1) - (1)].real); + ;} + break; + + case 233: + +/* Line 1455 of yacc.c */ +#line 1868 "program_parse.y" + { + (yyval.vector).count = 1; + (yyval.vector).data[0] = (float) (yyvsp[(1) - (1)].integer); + (yyval.vector).data[1] = (float) (yyvsp[(1) - (1)].integer); + (yyval.vector).data[2] = (float) (yyvsp[(1) - (1)].integer); + (yyval.vector).data[3] = (float) (yyvsp[(1) - (1)].integer); + ;} + break; + + case 234: + +/* Line 1455 of yacc.c */ +#line 1878 "program_parse.y" + { + (yyval.vector).count = 4; + (yyval.vector).data[0] = (yyvsp[(2) - (3)].real); + (yyval.vector).data[1] = 0.0f; + (yyval.vector).data[2] = 0.0f; + (yyval.vector).data[3] = 1.0f; + ;} + break; + + case 235: + +/* Line 1455 of yacc.c */ +#line 1886 "program_parse.y" + { + (yyval.vector).count = 4; + (yyval.vector).data[0] = (yyvsp[(2) - (5)].real); + (yyval.vector).data[1] = (yyvsp[(4) - (5)].real); + (yyval.vector).data[2] = 0.0f; + (yyval.vector).data[3] = 1.0f; + ;} + break; + + case 236: + +/* Line 1455 of yacc.c */ +#line 1895 "program_parse.y" + { + (yyval.vector).count = 4; + (yyval.vector).data[0] = (yyvsp[(2) - (7)].real); + (yyval.vector).data[1] = (yyvsp[(4) - (7)].real); + (yyval.vector).data[2] = (yyvsp[(6) - (7)].real); + (yyval.vector).data[3] = 1.0f; + ;} + break; + + case 237: + +/* Line 1455 of yacc.c */ +#line 1904 "program_parse.y" + { + (yyval.vector).count = 4; + (yyval.vector).data[0] = (yyvsp[(2) - (9)].real); + (yyval.vector).data[1] = (yyvsp[(4) - (9)].real); + (yyval.vector).data[2] = (yyvsp[(6) - (9)].real); + (yyval.vector).data[3] = (yyvsp[(8) - (9)].real); + ;} + break; + + case 238: + +/* Line 1455 of yacc.c */ +#line 1914 "program_parse.y" + { + (yyval.real) = ((yyvsp[(1) - (2)].negate)) ? -(yyvsp[(2) - (2)].real) : (yyvsp[(2) - (2)].real); + ;} + break; + + case 239: + +/* Line 1455 of yacc.c */ +#line 1918 "program_parse.y" + { + (yyval.real) = (float)(((yyvsp[(1) - (2)].negate)) ? -(yyvsp[(2) - (2)].integer) : (yyvsp[(2) - (2)].integer)); + ;} + break; + + case 240: + +/* Line 1455 of yacc.c */ +#line 1923 "program_parse.y" + { (yyval.negate) = FALSE; ;} + break; + + case 241: + +/* Line 1455 of yacc.c */ +#line 1924 "program_parse.y" + { (yyval.negate) = TRUE; ;} + break; + + case 242: + +/* Line 1455 of yacc.c */ +#line 1925 "program_parse.y" + { (yyval.negate) = FALSE; ;} + break; + + case 243: + +/* Line 1455 of yacc.c */ +#line 1928 "program_parse.y" + { (yyval.integer) = (yyvsp[(2) - (2)].integer); ;} + break; + + case 245: + +/* Line 1455 of yacc.c */ +#line 1932 "program_parse.y" + { + /* NV_fragment_program_option defines the size qualifiers in a + * fairly broken way. "SHORT" or "LONG" can optionally be used + * before TEMP or OUTPUT. However, neither is a reserved word! + * This means that we have to parse it as an identifier, then check + * to make sure it's one of the valid values. *sigh* + * + * In addition, the grammar in the extension spec does *not* allow + * the size specifier to be optional, but all known implementations + * do. + */ + if (!state->option.NV_fragment) { + yyerror(& (yylsp[(1) - (1)]), state, "unexpected IDENTIFIER"); + YYERROR; + } + + if (strcmp("SHORT", (yyvsp[(1) - (1)].string)) == 0) { + } else if (strcmp("LONG", (yyvsp[(1) - (1)].string)) == 0) { + } else { + char *const err_str = + make_error_string("invalid storage size specifier \"%s\"", + (yyvsp[(1) - (1)].string)); + + yyerror(& (yylsp[(1) - (1)]), state, (err_str != NULL) + ? err_str : "invalid storage size specifier"); + + if (err_str != NULL) { + free(err_str); + } + + YYERROR; + } + ;} + break; + + case 246: + +/* Line 1455 of yacc.c */ +#line 1966 "program_parse.y" + { + ;} + break; + + case 247: + +/* Line 1455 of yacc.c */ +#line 1970 "program_parse.y" + { (yyval.integer) = (yyvsp[(1) - (1)].integer); ;} + break; + + case 249: + +/* Line 1455 of yacc.c */ +#line 1974 "program_parse.y" + { + if (!declare_variable(state, (yyvsp[(3) - (3)].string), (yyvsp[(0) - (3)].integer), & (yylsp[(3) - (3)]))) { + free((yyvsp[(3) - (3)].string)); + YYERROR; + } + ;} + break; + + case 250: + +/* Line 1455 of yacc.c */ +#line 1981 "program_parse.y" + { + if (!declare_variable(state, (yyvsp[(1) - (1)].string), (yyvsp[(0) - (1)].integer), & (yylsp[(1) - (1)]))) { + free((yyvsp[(1) - (1)].string)); + YYERROR; + } + ;} + break; + + case 251: + +/* Line 1455 of yacc.c */ +#line 1990 "program_parse.y" + { + struct asm_symbol *const s = + declare_variable(state, (yyvsp[(3) - (5)].string), at_output, & (yylsp[(3) - (5)])); + + if (s == NULL) { + free((yyvsp[(3) - (5)].string)); + YYERROR; + } else { + s->output_binding = (yyvsp[(5) - (5)].result); + } + ;} + break; + + case 252: + +/* Line 1455 of yacc.c */ +#line 2004 "program_parse.y" + { + if (state->mode == ARB_vertex) { + (yyval.result) = VERT_RESULT_HPOS; + } else { + yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name"); + YYERROR; + } + ;} + break; + + case 253: + +/* Line 1455 of yacc.c */ +#line 2013 "program_parse.y" + { + if (state->mode == ARB_vertex) { + (yyval.result) = VERT_RESULT_FOGC; + } else { + yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name"); + YYERROR; + } + ;} + break; + + case 254: + +/* Line 1455 of yacc.c */ +#line 2022 "program_parse.y" + { + (yyval.result) = (yyvsp[(2) - (2)].result); + ;} + break; + + case 255: + +/* Line 1455 of yacc.c */ +#line 2026 "program_parse.y" + { + if (state->mode == ARB_vertex) { + (yyval.result) = VERT_RESULT_PSIZ; + } else { + yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name"); + YYERROR; + } + ;} + break; + + case 256: + +/* Line 1455 of yacc.c */ +#line 2035 "program_parse.y" + { + if (state->mode == ARB_vertex) { + (yyval.result) = VERT_RESULT_TEX0 + (yyvsp[(3) - (3)].integer); + } else { + yyerror(& (yylsp[(2) - (3)]), state, "invalid program result name"); + YYERROR; + } + ;} + break; + + case 257: + +/* Line 1455 of yacc.c */ +#line 2044 "program_parse.y" + { + if (state->mode == ARB_fragment) { + (yyval.result) = FRAG_RESULT_DEPTH; + } else { + yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name"); + YYERROR; + } + ;} + break; + + case 258: + +/* Line 1455 of yacc.c */ +#line 2055 "program_parse.y" + { + (yyval.result) = (yyvsp[(2) - (3)].integer) + (yyvsp[(3) - (3)].integer); + ;} + break; + + case 259: + +/* Line 1455 of yacc.c */ +#line 2061 "program_parse.y" + { + (yyval.integer) = (state->mode == ARB_vertex) + ? VERT_RESULT_COL0 + : FRAG_RESULT_COLOR; + ;} + break; + + case 260: + +/* Line 1455 of yacc.c */ +#line 2067 "program_parse.y" + { + if (state->mode == ARB_vertex) { + (yyval.integer) = VERT_RESULT_COL0; + } else { + yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name"); + YYERROR; + } + ;} + break; + + case 261: + +/* Line 1455 of yacc.c */ +#line 2076 "program_parse.y" + { + if (state->mode == ARB_vertex) { + (yyval.integer) = VERT_RESULT_BFC0; + } else { + yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name"); + YYERROR; + } + ;} + break; + + case 262: + +/* Line 1455 of yacc.c */ +#line 2087 "program_parse.y" + { + (yyval.integer) = 0; + ;} + break; + + case 263: + +/* Line 1455 of yacc.c */ +#line 2091 "program_parse.y" + { + if (state->mode == ARB_vertex) { + (yyval.integer) = 0; + } else { + yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name"); + YYERROR; + } + ;} + break; + + case 264: + +/* Line 1455 of yacc.c */ +#line 2100 "program_parse.y" + { + if (state->mode == ARB_vertex) { + (yyval.integer) = 1; + } else { + yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name"); + YYERROR; + } + ;} + break; + + case 265: + +/* Line 1455 of yacc.c */ +#line 2110 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 266: + +/* Line 1455 of yacc.c */ +#line 2111 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 267: + +/* Line 1455 of yacc.c */ +#line 2112 "program_parse.y" + { (yyval.integer) = 1; ;} + break; + + case 268: + +/* Line 1455 of yacc.c */ +#line 2115 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 269: + +/* Line 1455 of yacc.c */ +#line 2116 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 270: + +/* Line 1455 of yacc.c */ +#line 2117 "program_parse.y" + { (yyval.integer) = 1; ;} + break; + + case 271: + +/* Line 1455 of yacc.c */ +#line 2120 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 272: + +/* Line 1455 of yacc.c */ +#line 2121 "program_parse.y" + { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;} + break; + + case 273: + +/* Line 1455 of yacc.c */ +#line 2124 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 274: + +/* Line 1455 of yacc.c */ +#line 2125 "program_parse.y" + { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;} + break; + + case 275: + +/* Line 1455 of yacc.c */ +#line 2128 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 276: + +/* Line 1455 of yacc.c */ +#line 2129 "program_parse.y" + { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;} + break; + + case 277: + +/* Line 1455 of yacc.c */ +#line 2133 "program_parse.y" + { + if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxTextureCoordUnits) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid texture coordinate unit selector"); + YYERROR; + } + + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 278: + +/* Line 1455 of yacc.c */ +#line 2144 "program_parse.y" + { + if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxTextureImageUnits) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid texture image unit selector"); + YYERROR; + } + + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 279: + +/* Line 1455 of yacc.c */ +#line 2155 "program_parse.y" + { + if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxTextureUnits) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid texture unit selector"); + YYERROR; + } + + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 280: + +/* Line 1455 of yacc.c */ +#line 2166 "program_parse.y" + { + struct asm_symbol *exist = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(2) - (4)].string)); + struct asm_symbol *target = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(4) - (4)].string)); + + free((yyvsp[(4) - (4)].string)); + + if (exist != NULL) { + char m[1000]; + _mesa_snprintf(m, sizeof(m), "redeclared identifier: %s", (yyvsp[(2) - (4)].string)); + free((yyvsp[(2) - (4)].string)); + yyerror(& (yylsp[(2) - (4)]), state, m); + YYERROR; + } else if (target == NULL) { + free((yyvsp[(2) - (4)].string)); + yyerror(& (yylsp[(4) - (4)]), state, + "undefined variable binding in ALIAS statement"); + YYERROR; + } else { + _mesa_symbol_table_add_symbol(state->st, 0, (yyvsp[(2) - (4)].string), target); + } + ;} + break; + + + +/* Line 1455 of yacc.c */ +#line 4937 "program_parse.tab.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + *++yylsp = yyloc; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (&yylloc, state, YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (&yylloc, state, yymsg); + } + else + { + yyerror (&yylloc, state, YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + yyerror_range[0] = yylloc; + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc, state); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + yyerror_range[0] = yylsp[1-yylen]; + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yyerror_range[0] = *yylsp; + yydestruct ("Error: popping", + yystos[yystate], yyvsp, yylsp, state); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + yyerror_range[1] = yylloc; + /* Using YYLLOC is tempting, but would change the location of + the lookahead. YYLOC is available though. */ + YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); + *++yylsp = yyloc; + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (&yylloc, state, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc, state); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yylsp, state); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + +/* Line 1675 of yacc.c */ +#line 2195 "program_parse.y" + + +void +asm_instruction_set_operands(struct asm_instruction *inst, + const struct prog_dst_register *dst, + const struct asm_src_register *src0, + const struct asm_src_register *src1, + const struct asm_src_register *src2) +{ + /* In the core ARB extensions only the KIL instruction doesn't have a + * destination register. + */ + if (dst == NULL) { + init_dst_reg(& inst->Base.DstReg); + } else { + inst->Base.DstReg = *dst; + } + + /* The only instruction that doesn't have any source registers is the + * condition-code based KIL instruction added by NV_fragment_program_option. + */ + if (src0 != NULL) { + inst->Base.SrcReg[0] = src0->Base; + inst->SrcReg[0] = *src0; + } else { + init_src_reg(& inst->SrcReg[0]); + } + + if (src1 != NULL) { + inst->Base.SrcReg[1] = src1->Base; + inst->SrcReg[1] = *src1; + } else { + init_src_reg(& inst->SrcReg[1]); + } + + if (src2 != NULL) { + inst->Base.SrcReg[2] = src2->Base; + inst->SrcReg[2] = *src2; + } else { + init_src_reg(& inst->SrcReg[2]); + } +} + + +struct asm_instruction * +asm_instruction_ctor(gl_inst_opcode op, + const struct prog_dst_register *dst, + const struct asm_src_register *src0, + const struct asm_src_register *src1, + const struct asm_src_register *src2) +{ + struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction); + + if (inst) { + _mesa_init_instructions(& inst->Base, 1); + inst->Base.Opcode = op; + + asm_instruction_set_operands(inst, dst, src0, src1, src2); + } + + return inst; +} + + +struct asm_instruction * +asm_instruction_copy_ctor(const struct prog_instruction *base, + const struct prog_dst_register *dst, + const struct asm_src_register *src0, + const struct asm_src_register *src1, + const struct asm_src_register *src2) +{ + struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction); + + if (inst) { + _mesa_init_instructions(& inst->Base, 1); + inst->Base.Opcode = base->Opcode; + inst->Base.CondUpdate = base->CondUpdate; + inst->Base.CondDst = base->CondDst; + inst->Base.SaturateMode = base->SaturateMode; + inst->Base.Precision = base->Precision; + + asm_instruction_set_operands(inst, dst, src0, src1, src2); + } + + return inst; +} + + +void +init_dst_reg(struct prog_dst_register *r) +{ + memset(r, 0, sizeof(*r)); + r->File = PROGRAM_UNDEFINED; + r->WriteMask = WRITEMASK_XYZW; + r->CondMask = COND_TR; + r->CondSwizzle = SWIZZLE_NOOP; +} + + +/** Like init_dst_reg() but set the File and Index fields. */ +void +set_dst_reg(struct prog_dst_register *r, gl_register_file file, GLint index) +{ + const GLint maxIndex = 1 << INST_INDEX_BITS; + const GLint minIndex = 0; + ASSERT(index >= minIndex); + (void) minIndex; + ASSERT(index <= maxIndex); + (void) maxIndex; + ASSERT(file == PROGRAM_TEMPORARY || + file == PROGRAM_ADDRESS || + file == PROGRAM_OUTPUT); + memset(r, 0, sizeof(*r)); + r->File = file; + r->Index = index; + r->WriteMask = WRITEMASK_XYZW; + r->CondMask = COND_TR; + r->CondSwizzle = SWIZZLE_NOOP; +} + + +void +init_src_reg(struct asm_src_register *r) +{ + memset(r, 0, sizeof(*r)); + r->Base.File = PROGRAM_UNDEFINED; + r->Base.Swizzle = SWIZZLE_NOOP; + r->Symbol = NULL; +} + + +/** Like init_src_reg() but set the File and Index fields. + * \return GL_TRUE if a valid src register, GL_FALSE otherwise + */ +void +set_src_reg(struct asm_src_register *r, gl_register_file file, GLint index) +{ + set_src_reg_swz(r, file, index, SWIZZLE_XYZW); +} + + +void +set_src_reg_swz(struct asm_src_register *r, gl_register_file file, GLint index, + GLuint swizzle) +{ + const GLint maxIndex = (1 << INST_INDEX_BITS) - 1; + const GLint minIndex = -(1 << INST_INDEX_BITS); + ASSERT(file < PROGRAM_FILE_MAX); + ASSERT(index >= minIndex); + (void) minIndex; + ASSERT(index <= maxIndex); + (void) maxIndex; + memset(r, 0, sizeof(*r)); + r->Base.File = file; + r->Base.Index = index; + r->Base.Swizzle = swizzle; + r->Symbol = NULL; +} + + +/** + * Validate the set of inputs used by a program + * + * Validates that legal sets of inputs are used by the program. In this case + * "used" included both reading the input or binding the input to a name using + * the \c ATTRIB command. + * + * \return + * \c TRUE if the combination of inputs used is valid, \c FALSE otherwise. + */ +int +validate_inputs(struct YYLTYPE *locp, struct asm_parser_state *state) +{ + const int inputs = state->prog->InputsRead | state->InputsBound; + + if (((inputs & 0x0ffff) & (inputs >> 16)) != 0) { + yyerror(locp, state, "illegal use of generic attribute and name attribute"); + return 0; + } + + return 1; +} + + +struct asm_symbol * +declare_variable(struct asm_parser_state *state, char *name, enum asm_type t, + struct YYLTYPE *locp) +{ + struct asm_symbol *s = NULL; + struct asm_symbol *exist = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, name); + + + if (exist != NULL) { + yyerror(locp, state, "redeclared identifier"); + } else { + s = calloc(1, sizeof(struct asm_symbol)); + s->name = name; + s->type = t; + + switch (t) { + case at_temp: + if (state->prog->NumTemporaries >= state->limits->MaxTemps) { + yyerror(locp, state, "too many temporaries declared"); + free(s); + return NULL; + } + + s->temp_binding = state->prog->NumTemporaries; + state->prog->NumTemporaries++; + break; + + case at_address: + if (state->prog->NumAddressRegs >= state->limits->MaxAddressRegs) { + yyerror(locp, state, "too many address registers declared"); + free(s); + return NULL; + } + + /* FINISHME: Add support for multiple address registers. + */ + state->prog->NumAddressRegs++; + break; + + default: + break; + } + + _mesa_symbol_table_add_symbol(state->st, 0, s->name, s); + s->next = state->sym; + state->sym = s; + } + + return s; +} + + +int add_state_reference(struct gl_program_parameter_list *param_list, + const gl_state_index tokens[STATE_LENGTH]) +{ + const GLuint size = 4; /* XXX fix */ + char *name; + GLint index; + + name = _mesa_program_state_string(tokens); + index = _mesa_add_parameter(param_list, PROGRAM_STATE_VAR, name, + size, GL_NONE, NULL, tokens, 0x0); + param_list->StateFlags |= _mesa_program_state_flags(tokens); + + /* free name string here since we duplicated it in add_parameter() */ + free(name); + + return index; +} + + +int +initialize_symbol_from_state(struct gl_program *prog, + struct asm_symbol *param_var, + const gl_state_index tokens[STATE_LENGTH]) +{ + int idx = -1; + gl_state_index state_tokens[STATE_LENGTH]; + + + memcpy(state_tokens, tokens, sizeof(state_tokens)); + + param_var->type = at_param; + param_var->param_binding_type = PROGRAM_STATE_VAR; + + /* If we are adding a STATE_MATRIX that has multiple rows, we need to + * unroll it and call add_state_reference() for each row + */ + if ((state_tokens[0] == STATE_MODELVIEW_MATRIX || + state_tokens[0] == STATE_PROJECTION_MATRIX || + state_tokens[0] == STATE_MVP_MATRIX || + state_tokens[0] == STATE_TEXTURE_MATRIX || + state_tokens[0] == STATE_PROGRAM_MATRIX) + && (state_tokens[2] != state_tokens[3])) { + int row; + const int first_row = state_tokens[2]; + const int last_row = state_tokens[3]; + + for (row = first_row; row <= last_row; row++) { + state_tokens[2] = state_tokens[3] = row; + + idx = add_state_reference(prog->Parameters, state_tokens); + if (param_var->param_binding_begin == ~0U) { + param_var->param_binding_begin = idx; + param_var->param_binding_swizzle = SWIZZLE_XYZW; + } + + param_var->param_binding_length++; + } + } + else { + idx = add_state_reference(prog->Parameters, state_tokens); + if (param_var->param_binding_begin == ~0U) { + param_var->param_binding_begin = idx; + param_var->param_binding_swizzle = SWIZZLE_XYZW; + } + param_var->param_binding_length++; + } + + return idx; +} + + +int +initialize_symbol_from_param(struct gl_program *prog, + struct asm_symbol *param_var, + const gl_state_index tokens[STATE_LENGTH]) +{ + int idx = -1; + gl_state_index state_tokens[STATE_LENGTH]; + + + memcpy(state_tokens, tokens, sizeof(state_tokens)); + + assert((state_tokens[0] == STATE_VERTEX_PROGRAM) + || (state_tokens[0] == STATE_FRAGMENT_PROGRAM)); + assert((state_tokens[1] == STATE_ENV) + || (state_tokens[1] == STATE_LOCAL)); + + /* + * The param type is STATE_VAR. The program parameter entry will + * effectively be a pointer into the LOCAL or ENV parameter array. + */ + param_var->type = at_param; + param_var->param_binding_type = PROGRAM_STATE_VAR; + + /* If we are adding a STATE_ENV or STATE_LOCAL that has multiple elements, + * we need to unroll it and call add_state_reference() for each row + */ + if (state_tokens[2] != state_tokens[3]) { + int row; + const int first_row = state_tokens[2]; + const int last_row = state_tokens[3]; + + for (row = first_row; row <= last_row; row++) { + state_tokens[2] = state_tokens[3] = row; + + idx = add_state_reference(prog->Parameters, state_tokens); + if (param_var->param_binding_begin == ~0U) { + param_var->param_binding_begin = idx; + param_var->param_binding_swizzle = SWIZZLE_XYZW; + } + param_var->param_binding_length++; + } + } + else { + idx = add_state_reference(prog->Parameters, state_tokens); + if (param_var->param_binding_begin == ~0U) { + param_var->param_binding_begin = idx; + param_var->param_binding_swizzle = SWIZZLE_XYZW; + } + param_var->param_binding_length++; + } + + return idx; +} + + +/** + * Put a float/vector constant/literal into the parameter list. + * \param param_var returns info about the parameter/constant's location, + * binding, type, etc. + * \param vec the vector/constant to add + * \param allowSwizzle if true, try to consolidate constants which only differ + * by a swizzle. We don't want to do this when building + * arrays of constants that may be indexed indirectly. + * \return index of the constant in the parameter list. + */ +int +initialize_symbol_from_const(struct gl_program *prog, + struct asm_symbol *param_var, + const struct asm_vector *vec, + GLboolean allowSwizzle) +{ + unsigned swizzle; + const int idx = _mesa_add_unnamed_constant(prog->Parameters, + vec->data, vec->count, + allowSwizzle ? &swizzle : NULL); + + param_var->type = at_param; + param_var->param_binding_type = PROGRAM_CONSTANT; + + if (param_var->param_binding_begin == ~0U) { + param_var->param_binding_begin = idx; + param_var->param_binding_swizzle = allowSwizzle ? swizzle : SWIZZLE_XYZW; + } + param_var->param_binding_length++; + + return idx; +} + + +char * +make_error_string(const char *fmt, ...) +{ + int length; + char *str; + va_list args; + + + /* Call vsnprintf once to determine how large the final string is. Call it + * again to do the actual formatting. from the vsnprintf manual page: + * + * Upon successful return, these functions return the number of + * characters printed (not including the trailing '\0' used to end + * output to strings). + */ + va_start(args, fmt); + length = 1 + vsnprintf(NULL, 0, fmt, args); + va_end(args); + + str = malloc(length); + if (str) { + va_start(args, fmt); + vsnprintf(str, length, fmt, args); + va_end(args); + } + + return str; +} + + +void +yyerror(YYLTYPE *locp, struct asm_parser_state *state, const char *s) +{ + char *err_str; + + + err_str = make_error_string("glProgramStringARB(%s)\n", s); + if (err_str) { + _mesa_error(state->ctx, GL_INVALID_OPERATION, err_str); + free(err_str); + } + + err_str = make_error_string("line %u, char %u: error: %s\n", + locp->first_line, locp->first_column, s); + _mesa_set_program_error(state->ctx, locp->position, err_str); + + if (err_str) { + free(err_str); + } +} + + +GLboolean +_mesa_parse_arb_program(GLcontext *ctx, GLenum target, const GLubyte *str, + GLsizei len, struct asm_parser_state *state) +{ + struct asm_instruction *inst; + unsigned i; + GLubyte *strz; + GLboolean result = GL_FALSE; + void *temp; + struct asm_symbol *sym; + + state->ctx = ctx; + state->prog->Target = target; + state->prog->Parameters = _mesa_new_parameter_list(); + + /* Make a copy of the program string and force it to be NUL-terminated. + */ + strz = (GLubyte *) malloc(len + 1); + if (strz == NULL) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramStringARB"); + return GL_FALSE; + } + memcpy (strz, str, len); + strz[len] = '\0'; + + state->prog->String = strz; + + state->st = _mesa_symbol_table_ctor(); + + state->limits = (target == GL_VERTEX_PROGRAM_ARB) + ? & ctx->Const.VertexProgram + : & ctx->Const.FragmentProgram; + + state->MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits; + state->MaxTextureCoordUnits = ctx->Const.MaxTextureCoordUnits; + state->MaxTextureUnits = ctx->Const.MaxTextureUnits; + state->MaxClipPlanes = ctx->Const.MaxClipPlanes; + state->MaxLights = ctx->Const.MaxLights; + state->MaxProgramMatrices = ctx->Const.MaxProgramMatrices; + + state->state_param_enum = (target == GL_VERTEX_PROGRAM_ARB) + ? STATE_VERTEX_PROGRAM : STATE_FRAGMENT_PROGRAM; + + _mesa_set_program_error(ctx, -1, NULL); + + _mesa_program_lexer_ctor(& state->scanner, state, (const char *) str, len); + yyparse(state); + _mesa_program_lexer_dtor(state->scanner); + + + if (ctx->Program.ErrorPos != -1) { + goto error; + } + + if (! _mesa_layout_parameters(state)) { + struct YYLTYPE loc; + + loc.first_line = 0; + loc.first_column = 0; + loc.position = len; + + yyerror(& loc, state, "invalid PARAM usage"); + goto error; + } + + + + /* Add one instruction to store the "END" instruction. + */ + state->prog->Instructions = + _mesa_alloc_instructions(state->prog->NumInstructions + 1); + inst = state->inst_head; + for (i = 0; i < state->prog->NumInstructions; i++) { + struct asm_instruction *const temp = inst->next; + + state->prog->Instructions[i] = inst->Base; + inst = temp; + } + + /* Finally, tag on an OPCODE_END instruction */ + { + const GLuint numInst = state->prog->NumInstructions; + _mesa_init_instructions(state->prog->Instructions + numInst, 1); + state->prog->Instructions[numInst].Opcode = OPCODE_END; + } + state->prog->NumInstructions++; + + state->prog->NumParameters = state->prog->Parameters->NumParameters; + state->prog->NumAttributes = _mesa_bitcount(state->prog->InputsRead); + + /* + * Initialize native counts to logical counts. The device driver may + * change them if program is translated into a hardware program. + */ + state->prog->NumNativeInstructions = state->prog->NumInstructions; + state->prog->NumNativeTemporaries = state->prog->NumTemporaries; + state->prog->NumNativeParameters = state->prog->NumParameters; + state->prog->NumNativeAttributes = state->prog->NumAttributes; + state->prog->NumNativeAddressRegs = state->prog->NumAddressRegs; + + result = GL_TRUE; + +error: + for (inst = state->inst_head; inst != NULL; inst = temp) { + temp = inst->next; + free(inst); + } + + state->inst_head = NULL; + state->inst_tail = NULL; + + for (sym = state->sym; sym != NULL; sym = temp) { + temp = sym->next; + + free((void *) sym->name); + free(sym); + } + state->sym = NULL; + + _mesa_symbol_table_dtor(state->st); + state->st = NULL; + + return result; +} + diff --git a/src/mesa/program/program_parse.tab.h b/src/mesa/program/program_parse.tab.h new file mode 100644 index 0000000000..045241d9e7 --- /dev/null +++ b/src/mesa/program/program_parse.tab.h @@ -0,0 +1,209 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + ARBvp_10 = 258, + ARBfp_10 = 259, + ADDRESS = 260, + ALIAS = 261, + ATTRIB = 262, + OPTION = 263, + OUTPUT = 264, + PARAM = 265, + TEMP = 266, + END = 267, + BIN_OP = 268, + BINSC_OP = 269, + SAMPLE_OP = 270, + SCALAR_OP = 271, + TRI_OP = 272, + VECTOR_OP = 273, + ARL = 274, + KIL = 275, + SWZ = 276, + TXD_OP = 277, + INTEGER = 278, + REAL = 279, + AMBIENT = 280, + ATTENUATION = 281, + BACK = 282, + CLIP = 283, + COLOR = 284, + DEPTH = 285, + DIFFUSE = 286, + DIRECTION = 287, + EMISSION = 288, + ENV = 289, + EYE = 290, + FOG = 291, + FOGCOORD = 292, + FRAGMENT = 293, + FRONT = 294, + HALF = 295, + INVERSE = 296, + INVTRANS = 297, + LIGHT = 298, + LIGHTMODEL = 299, + LIGHTPROD = 300, + LOCAL = 301, + MATERIAL = 302, + MAT_PROGRAM = 303, + MATRIX = 304, + MATRIXINDEX = 305, + MODELVIEW = 306, + MVP = 307, + NORMAL = 308, + OBJECT = 309, + PALETTE = 310, + PARAMS = 311, + PLANE = 312, + POINT_TOK = 313, + POINTSIZE = 314, + POSITION = 315, + PRIMARY = 316, + PROGRAM = 317, + PROJECTION = 318, + RANGE = 319, + RESULT = 320, + ROW = 321, + SCENECOLOR = 322, + SECONDARY = 323, + SHININESS = 324, + SIZE_TOK = 325, + SPECULAR = 326, + SPOT = 327, + STATE = 328, + TEXCOORD = 329, + TEXENV = 330, + TEXGEN = 331, + TEXGEN_Q = 332, + TEXGEN_R = 333, + TEXGEN_S = 334, + TEXGEN_T = 335, + TEXTURE = 336, + TRANSPOSE = 337, + TEXTURE_UNIT = 338, + TEX_1D = 339, + TEX_2D = 340, + TEX_3D = 341, + TEX_CUBE = 342, + TEX_RECT = 343, + TEX_SHADOW1D = 344, + TEX_SHADOW2D = 345, + TEX_SHADOWRECT = 346, + TEX_ARRAY1D = 347, + TEX_ARRAY2D = 348, + TEX_ARRAYSHADOW1D = 349, + TEX_ARRAYSHADOW2D = 350, + VERTEX = 351, + VTXATTRIB = 352, + WEIGHT = 353, + IDENTIFIER = 354, + USED_IDENTIFIER = 355, + MASK4 = 356, + MASK3 = 357, + MASK2 = 358, + MASK1 = 359, + SWIZZLE = 360, + DOT_DOT = 361, + DOT = 362 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 1676 of yacc.c */ +#line 126 "program_parse.y" + + struct asm_instruction *inst; + struct asm_symbol *sym; + struct asm_symbol temp_sym; + struct asm_swizzle_mask swiz_mask; + struct asm_src_register src_reg; + struct prog_dst_register dst_reg; + struct prog_instruction temp_inst; + char *string; + unsigned result; + unsigned attrib; + int integer; + float real; + gl_state_index state[STATE_LENGTH]; + int negate; + struct asm_vector vector; + gl_inst_opcode opcode; + + struct { + unsigned swz; + unsigned rgba_valid:1; + unsigned xyzw_valid:1; + unsigned negate:1; + } ext_swizzle; + + + +/* Line 1676 of yacc.c */ +#line 187 "program_parse.tab.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + + diff --git a/src/mesa/program/program_parse.y b/src/mesa/program/program_parse.y new file mode 100644 index 0000000000..861927c744 --- /dev/null +++ b/src/mesa/program/program_parse.y @@ -0,0 +1,2767 @@ +%{ +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include +#include +#include + +#include "main/mtypes.h" +#include "main/imports.h" +#include "program/program.h" +#include "program/prog_parameter.h" +#include "program/prog_parameter_layout.h" +#include "program/prog_statevars.h" +#include "program/prog_instruction.h" + +#include "program/symbol_table.h" +#include "program/program_parser.h" + +extern void *yy_scan_string(char *); +extern void yy_delete_buffer(void *); + +static struct asm_symbol *declare_variable(struct asm_parser_state *state, + char *name, enum asm_type t, struct YYLTYPE *locp); + +static int add_state_reference(struct gl_program_parameter_list *param_list, + const gl_state_index tokens[STATE_LENGTH]); + +static int initialize_symbol_from_state(struct gl_program *prog, + struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]); + +static int initialize_symbol_from_param(struct gl_program *prog, + struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]); + +static int initialize_symbol_from_const(struct gl_program *prog, + struct asm_symbol *param_var, const struct asm_vector *vec, + GLboolean allowSwizzle); + +static int yyparse(struct asm_parser_state *state); + +static char *make_error_string(const char *fmt, ...); + +static void yyerror(struct YYLTYPE *locp, struct asm_parser_state *state, + const char *s); + +static int validate_inputs(struct YYLTYPE *locp, + struct asm_parser_state *state); + +static void init_dst_reg(struct prog_dst_register *r); + +static void set_dst_reg(struct prog_dst_register *r, + gl_register_file file, GLint index); + +static void init_src_reg(struct asm_src_register *r); + +static void set_src_reg(struct asm_src_register *r, + gl_register_file file, GLint index); + +static void set_src_reg_swz(struct asm_src_register *r, + gl_register_file file, GLint index, GLuint swizzle); + +static void asm_instruction_set_operands(struct asm_instruction *inst, + const struct prog_dst_register *dst, const struct asm_src_register *src0, + const struct asm_src_register *src1, const struct asm_src_register *src2); + +static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op, + const struct prog_dst_register *dst, const struct asm_src_register *src0, + const struct asm_src_register *src1, const struct asm_src_register *src2); + +static struct asm_instruction *asm_instruction_copy_ctor( + const struct prog_instruction *base, const struct prog_dst_register *dst, + const struct asm_src_register *src0, const struct asm_src_register *src1, + const struct asm_src_register *src2); + +#ifndef FALSE +#define FALSE 0 +#define TRUE (!FALSE) +#endif + +#define YYLLOC_DEFAULT(Current, Rhs, N) \ + do { \ + if (YYID(N)) { \ + (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ + (Current).position = YYRHSLOC(Rhs, 1).position; \ + (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC(Rhs, N).last_column; \ + } else { \ + (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \ + (Current).last_line = (Current).first_line; \ + (Current).first_column = YYRHSLOC(Rhs, 0).last_column; \ + (Current).last_column = (Current).first_column; \ + (Current).position = YYRHSLOC(Rhs, 0).position \ + + (Current).first_column; \ + } \ + } while(YYID(0)) + +#define YYLEX_PARAM state->scanner +%} + +%pure-parser +%locations +%parse-param { struct asm_parser_state *state } +%error-verbose +%lex-param { void *scanner } + +%union { + struct asm_instruction *inst; + struct asm_symbol *sym; + struct asm_symbol temp_sym; + struct asm_swizzle_mask swiz_mask; + struct asm_src_register src_reg; + struct prog_dst_register dst_reg; + struct prog_instruction temp_inst; + char *string; + unsigned result; + unsigned attrib; + int integer; + float real; + gl_state_index state[STATE_LENGTH]; + int negate; + struct asm_vector vector; + gl_inst_opcode opcode; + + struct { + unsigned swz; + unsigned rgba_valid:1; + unsigned xyzw_valid:1; + unsigned negate:1; + } ext_swizzle; +} + +%token ARBvp_10 ARBfp_10 + +/* Tokens for assembler pseudo-ops */ +%token ADDRESS +%token ALIAS ATTRIB +%token OPTION OUTPUT +%token PARAM +%token TEMP +%token END + + /* Tokens for instructions */ +%token BIN_OP BINSC_OP SAMPLE_OP SCALAR_OP TRI_OP VECTOR_OP +%token ARL KIL SWZ TXD_OP + +%token INTEGER +%token REAL + +%token AMBIENT ATTENUATION +%token BACK +%token CLIP COLOR +%token DEPTH DIFFUSE DIRECTION +%token EMISSION ENV EYE +%token FOG FOGCOORD FRAGMENT FRONT +%token HALF +%token INVERSE INVTRANS +%token LIGHT LIGHTMODEL LIGHTPROD LOCAL +%token MATERIAL MAT_PROGRAM MATRIX MATRIXINDEX MODELVIEW MVP +%token NORMAL +%token OBJECT +%token PALETTE PARAMS PLANE POINT_TOK POINTSIZE POSITION PRIMARY PROGRAM PROJECTION +%token RANGE RESULT ROW +%token SCENECOLOR SECONDARY SHININESS SIZE_TOK SPECULAR SPOT STATE +%token TEXCOORD TEXENV TEXGEN TEXGEN_Q TEXGEN_R TEXGEN_S TEXGEN_T TEXTURE TRANSPOSE +%token TEXTURE_UNIT TEX_1D TEX_2D TEX_3D TEX_CUBE TEX_RECT +%token TEX_SHADOW1D TEX_SHADOW2D TEX_SHADOWRECT +%token TEX_ARRAY1D TEX_ARRAY2D TEX_ARRAYSHADOW1D TEX_ARRAYSHADOW2D +%token VERTEX VTXATTRIB +%token WEIGHT + +%token IDENTIFIER USED_IDENTIFIER +%type string +%token MASK4 MASK3 MASK2 MASK1 SWIZZLE +%token DOT_DOT +%token DOT + +%type instruction ALU_instruction TexInstruction +%type ARL_instruction VECTORop_instruction +%type SCALARop_instruction BINSCop_instruction BINop_instruction +%type TRIop_instruction TXD_instruction SWZ_instruction SAMPLE_instruction +%type KIL_instruction + +%type dstReg maskedDstReg maskedAddrReg +%type srcReg scalarUse scalarSrcReg swizzleSrcReg +%type scalarSuffix swizzleSuffix extendedSwizzle +%type extSwizComp extSwizSel +%type optionalMask + +%type progParamArray +%type addrRegRelOffset addrRegPosOffset addrRegNegOffset +%type progParamArrayMem progParamArrayAbs progParamArrayRel +%type addrReg +%type addrComponent addrWriteMask + +%type ccMaskRule ccTest ccMaskRule2 ccTest2 optionalCcMask + +%type resultBinding resultColBinding +%type optFaceType optColorType +%type optResultFaceType optResultColorType + +%type optTexImageUnitNum texImageUnitNum +%type optTexCoordUnitNum texCoordUnitNum +%type optLegacyTexUnitNum legacyTexUnitNum +%type texImageUnit texTarget +%type vtxAttribNum + +%type attribBinding vtxAttribItem fragAttribItem + +%type paramSingleInit paramSingleItemDecl +%type optArraySize + +%type stateSingleItem stateMultipleItem +%type stateMaterialItem +%type stateLightItem stateLightModelItem stateLightProdItem +%type stateTexGenItem stateFogItem stateClipPlaneItem statePointItem +%type stateMatrixItem stateMatrixRow stateMatrixRows +%type stateTexEnvItem stateDepthItem + +%type stateLModProperty +%type stateMatrixName optMatrixRows + +%type stateMatProperty +%type stateLightProperty stateSpotProperty +%type stateLightNumber stateLProdProperty +%type stateTexGenType stateTexGenCoord +%type stateTexEnvProperty +%type stateFogProperty +%type stateClipPlaneNum +%type statePointProperty + +%type stateOptMatModifier stateMatModifier stateMatrixRowNum +%type stateOptModMatNum stateModMatNum statePaletteMatNum +%type stateProgramMatNum + +%type ambDiffSpecProperty + +%type programSingleItem progEnvParam progLocalParam +%type programMultipleItem progEnvParams progLocalParams + +%type paramMultipleInit paramMultInitList paramMultipleItem +%type paramSingleItemUse + +%type progEnvParamNum progLocalParamNum +%type progEnvParamNums progLocalParamNums + +%type paramConstDecl paramConstUse +%type paramConstScalarDecl paramConstScalarUse paramConstVector +%type signedFloatConstant +%type optionalSign + +%{ +extern int yylex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param, + void *yyscanner); +%} + +%% + +program: language optionSequence statementSequence END + ; + +language: ARBvp_10 + { + if (state->prog->Target != GL_VERTEX_PROGRAM_ARB) { + yyerror(& @1, state, "invalid fragment program header"); + + } + state->mode = ARB_vertex; + } + | ARBfp_10 + { + if (state->prog->Target != GL_FRAGMENT_PROGRAM_ARB) { + yyerror(& @1, state, "invalid vertex program header"); + } + state->mode = ARB_fragment; + + state->option.TexRect = + (state->ctx->Extensions.NV_texture_rectangle != GL_FALSE); + } + ; + +optionSequence: optionSequence option + | + ; + +option: OPTION string ';' + { + int valid = 0; + + if (state->mode == ARB_vertex) { + valid = _mesa_ARBvp_parse_option(state, $2); + } else if (state->mode == ARB_fragment) { + valid = _mesa_ARBfp_parse_option(state, $2); + } + + + free($2); + + if (!valid) { + const char *const err_str = (state->mode == ARB_vertex) + ? "invalid ARB vertex program option" + : "invalid ARB fragment program option"; + + yyerror(& @2, state, err_str); + YYERROR; + } + } + ; + +statementSequence: statementSequence statement + | + ; + +statement: instruction ';' + { + if ($1 != NULL) { + if (state->inst_tail == NULL) { + state->inst_head = $1; + } else { + state->inst_tail->next = $1; + } + + state->inst_tail = $1; + $1->next = NULL; + + state->prog->NumInstructions++; + } + } + | namingStatement ';' + ; + +instruction: ALU_instruction + { + $$ = $1; + state->prog->NumAluInstructions++; + } + | TexInstruction + { + $$ = $1; + state->prog->NumTexInstructions++; + } + ; + +ALU_instruction: ARL_instruction + | VECTORop_instruction + | SCALARop_instruction + | BINSCop_instruction + | BINop_instruction + | TRIop_instruction + | SWZ_instruction + ; + +TexInstruction: SAMPLE_instruction + | KIL_instruction + | TXD_instruction + ; + +ARL_instruction: ARL maskedAddrReg ',' scalarSrcReg + { + $$ = asm_instruction_ctor(OPCODE_ARL, & $2, & $4, NULL, NULL); + } + ; + +VECTORop_instruction: VECTOR_OP maskedDstReg ',' swizzleSrcReg + { + $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL); + } + ; + +SCALARop_instruction: SCALAR_OP maskedDstReg ',' scalarSrcReg + { + $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL); + } + ; + +BINSCop_instruction: BINSC_OP maskedDstReg ',' scalarSrcReg ',' scalarSrcReg + { + $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL); + } + ; + + +BINop_instruction: BIN_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg + { + $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL); + } + ; + +TRIop_instruction: TRI_OP maskedDstReg ',' + swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg + { + $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8); + } + ; + +SAMPLE_instruction: SAMPLE_OP maskedDstReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget + { + $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL); + if ($$ != NULL) { + const GLbitfield tex_mask = (1U << $6); + GLbitfield shadow_tex = 0; + GLbitfield target_mask = 0; + + + $$->Base.TexSrcUnit = $6; + + if ($8 < 0) { + shadow_tex = tex_mask; + + $$->Base.TexSrcTarget = -$8; + $$->Base.TexShadow = 1; + } else { + $$->Base.TexSrcTarget = $8; + } + + target_mask = (1U << $$->Base.TexSrcTarget); + + /* If this texture unit was previously accessed and that access + * had a different texture target, generate an error. + * + * If this texture unit was previously accessed and that access + * had a different shadow mode, generate an error. + */ + if ((state->prog->TexturesUsed[$6] != 0) + && ((state->prog->TexturesUsed[$6] != target_mask) + || ((state->prog->ShadowSamplers & tex_mask) + != shadow_tex))) { + yyerror(& @8, state, + "multiple targets used on one texture image unit"); + YYERROR; + } + + + state->prog->TexturesUsed[$6] |= target_mask; + state->prog->ShadowSamplers |= shadow_tex; + } + } + ; + +KIL_instruction: KIL swizzleSrcReg + { + $$ = asm_instruction_ctor(OPCODE_KIL, NULL, & $2, NULL, NULL); + state->fragment.UsesKill = 1; + } + | KIL ccTest + { + $$ = asm_instruction_ctor(OPCODE_KIL_NV, NULL, NULL, NULL, NULL); + $$->Base.DstReg.CondMask = $2.CondMask; + $$->Base.DstReg.CondSwizzle = $2.CondSwizzle; + $$->Base.DstReg.CondSrc = $2.CondSrc; + state->fragment.UsesKill = 1; + } + ; + +TXD_instruction: TXD_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget + { + $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8); + if ($$ != NULL) { + const GLbitfield tex_mask = (1U << $10); + GLbitfield shadow_tex = 0; + GLbitfield target_mask = 0; + + + $$->Base.TexSrcUnit = $10; + + if ($12 < 0) { + shadow_tex = tex_mask; + + $$->Base.TexSrcTarget = -$12; + $$->Base.TexShadow = 1; + } else { + $$->Base.TexSrcTarget = $12; + } + + target_mask = (1U << $$->Base.TexSrcTarget); + + /* If this texture unit was previously accessed and that access + * had a different texture target, generate an error. + * + * If this texture unit was previously accessed and that access + * had a different shadow mode, generate an error. + */ + if ((state->prog->TexturesUsed[$10] != 0) + && ((state->prog->TexturesUsed[$10] != target_mask) + || ((state->prog->ShadowSamplers & tex_mask) + != shadow_tex))) { + yyerror(& @12, state, + "multiple targets used on one texture image unit"); + YYERROR; + } + + + state->prog->TexturesUsed[$10] |= target_mask; + state->prog->ShadowSamplers |= shadow_tex; + } + } + ; + +texImageUnit: TEXTURE_UNIT optTexImageUnitNum + { + $$ = $2; + } + ; + +texTarget: TEX_1D { $$ = TEXTURE_1D_INDEX; } + | TEX_2D { $$ = TEXTURE_2D_INDEX; } + | TEX_3D { $$ = TEXTURE_3D_INDEX; } + | TEX_CUBE { $$ = TEXTURE_CUBE_INDEX; } + | TEX_RECT { $$ = TEXTURE_RECT_INDEX; } + | TEX_SHADOW1D { $$ = -TEXTURE_1D_INDEX; } + | TEX_SHADOW2D { $$ = -TEXTURE_2D_INDEX; } + | TEX_SHADOWRECT { $$ = -TEXTURE_RECT_INDEX; } + | TEX_ARRAY1D { $$ = TEXTURE_1D_ARRAY_INDEX; } + | TEX_ARRAY2D { $$ = TEXTURE_2D_ARRAY_INDEX; } + | TEX_ARRAYSHADOW1D { $$ = -TEXTURE_1D_ARRAY_INDEX; } + | TEX_ARRAYSHADOW2D { $$ = -TEXTURE_2D_ARRAY_INDEX; } + ; + +SWZ_instruction: SWZ maskedDstReg ',' srcReg ',' extendedSwizzle + { + /* FIXME: Is this correct? Should the extenedSwizzle be applied + * FIXME: to the existing swizzle? + */ + $4.Base.Swizzle = $6.swizzle; + $4.Base.Negate = $6.mask; + + $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL); + } + ; + +scalarSrcReg: optionalSign scalarUse + { + $$ = $2; + + if ($1) { + $$.Base.Negate = ~$$.Base.Negate; + } + } + | optionalSign '|' scalarUse '|' + { + $$ = $3; + + if (!state->option.NV_fragment) { + yyerror(& @2, state, "unexpected character '|'"); + YYERROR; + } + + if ($1) { + $$.Base.Negate = ~$$.Base.Negate; + } + + $$.Base.Abs = 1; + } + ; + +scalarUse: srcReg scalarSuffix + { + $$ = $1; + + $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle, + $2.swizzle); + } + | paramConstScalarUse + { + struct asm_symbol temp_sym; + + if (!state->option.NV_fragment) { + yyerror(& @1, state, "expected scalar suffix"); + YYERROR; + } + + memset(& temp_sym, 0, sizeof(temp_sym)); + temp_sym.param_binding_begin = ~0; + initialize_symbol_from_const(state->prog, & temp_sym, & $1, GL_TRUE); + + set_src_reg_swz(& $$, PROGRAM_CONSTANT, + temp_sym.param_binding_begin, + temp_sym.param_binding_swizzle); + } + ; + +swizzleSrcReg: optionalSign srcReg swizzleSuffix + { + $$ = $2; + + if ($1) { + $$.Base.Negate = ~$$.Base.Negate; + } + + $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle, + $3.swizzle); + } + | optionalSign '|' srcReg swizzleSuffix '|' + { + $$ = $3; + + if (!state->option.NV_fragment) { + yyerror(& @2, state, "unexpected character '|'"); + YYERROR; + } + + if ($1) { + $$.Base.Negate = ~$$.Base.Negate; + } + + $$.Base.Abs = 1; + $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle, + $4.swizzle); + } + + ; + +maskedDstReg: dstReg optionalMask optionalCcMask + { + $$ = $1; + $$.WriteMask = $2.mask; + $$.CondMask = $3.CondMask; + $$.CondSwizzle = $3.CondSwizzle; + $$.CondSrc = $3.CondSrc; + + if ($$.File == PROGRAM_OUTPUT) { + /* Technically speaking, this should check that it is in + * vertex program mode. However, PositionInvariant can never be + * set in fragment program mode, so it is somewhat irrelevant. + */ + if (state->option.PositionInvariant + && ($$.Index == VERT_RESULT_HPOS)) { + yyerror(& @1, state, "position-invariant programs cannot " + "write position"); + YYERROR; + } + + state->prog->OutputsWritten |= BITFIELD64_BIT($$.Index); + } + } + ; + +maskedAddrReg: addrReg addrWriteMask + { + set_dst_reg(& $$, PROGRAM_ADDRESS, 0); + $$.WriteMask = $2.mask; + } + ; + +extendedSwizzle: extSwizComp ',' extSwizComp ',' extSwizComp ',' extSwizComp + { + const unsigned xyzw_valid = + ($1.xyzw_valid << 0) + | ($3.xyzw_valid << 1) + | ($5.xyzw_valid << 2) + | ($7.xyzw_valid << 3); + const unsigned rgba_valid = + ($1.rgba_valid << 0) + | ($3.rgba_valid << 1) + | ($5.rgba_valid << 2) + | ($7.rgba_valid << 3); + + /* All of the swizzle components have to be valid in either RGBA + * or XYZW. Note that 0 and 1 are valid in both, so both masks + * can have some bits set. + * + * We somewhat deviate from the spec here. It would be really hard + * to figure out which component is the error, and there probably + * isn't a lot of benefit. + */ + if ((rgba_valid != 0x0f) && (xyzw_valid != 0x0f)) { + yyerror(& @1, state, "cannot combine RGBA and XYZW swizzle " + "components"); + YYERROR; + } + + $$.swizzle = MAKE_SWIZZLE4($1.swz, $3.swz, $5.swz, $7.swz); + $$.mask = ($1.negate) | ($3.negate << 1) | ($5.negate << 2) + | ($7.negate << 3); + } + ; + +extSwizComp: optionalSign extSwizSel + { + $$ = $2; + $$.negate = ($1) ? 1 : 0; + } + ; + +extSwizSel: INTEGER + { + if (($1 != 0) && ($1 != 1)) { + yyerror(& @1, state, "invalid extended swizzle selector"); + YYERROR; + } + + $$.swz = ($1 == 0) ? SWIZZLE_ZERO : SWIZZLE_ONE; + + /* 0 and 1 are valid for both RGBA swizzle names and XYZW + * swizzle names. + */ + $$.xyzw_valid = 1; + $$.rgba_valid = 1; + } + | string + { + char s; + + if (strlen($1) > 1) { + yyerror(& @1, state, "invalid extended swizzle selector"); + YYERROR; + } + + s = $1[0]; + free($1); + + switch (s) { + case 'x': + $$.swz = SWIZZLE_X; + $$.xyzw_valid = 1; + break; + case 'y': + $$.swz = SWIZZLE_Y; + $$.xyzw_valid = 1; + break; + case 'z': + $$.swz = SWIZZLE_Z; + $$.xyzw_valid = 1; + break; + case 'w': + $$.swz = SWIZZLE_W; + $$.xyzw_valid = 1; + break; + + case 'r': + $$.swz = SWIZZLE_X; + $$.rgba_valid = 1; + break; + case 'g': + $$.swz = SWIZZLE_Y; + $$.rgba_valid = 1; + break; + case 'b': + $$.swz = SWIZZLE_Z; + $$.rgba_valid = 1; + break; + case 'a': + $$.swz = SWIZZLE_W; + $$.rgba_valid = 1; + break; + + default: + yyerror(& @1, state, "invalid extended swizzle selector"); + YYERROR; + break; + } + } + ; + +srcReg: USED_IDENTIFIER /* temporaryReg | progParamSingle */ + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, $1); + + free($1); + + if (s == NULL) { + yyerror(& @1, state, "invalid operand variable"); + YYERROR; + } else if ((s->type != at_param) && (s->type != at_temp) + && (s->type != at_attrib)) { + yyerror(& @1, state, "invalid operand variable"); + YYERROR; + } else if ((s->type == at_param) && s->param_is_array) { + yyerror(& @1, state, "non-array access to array PARAM"); + YYERROR; + } + + init_src_reg(& $$); + switch (s->type) { + case at_temp: + set_src_reg(& $$, PROGRAM_TEMPORARY, s->temp_binding); + break; + case at_param: + set_src_reg_swz(& $$, s->param_binding_type, + s->param_binding_begin, + s->param_binding_swizzle); + break; + case at_attrib: + set_src_reg(& $$, PROGRAM_INPUT, s->attrib_binding); + state->prog->InputsRead |= (1U << $$.Base.Index); + + if (!validate_inputs(& @1, state)) { + YYERROR; + } + break; + + default: + YYERROR; + break; + } + } + | attribBinding + { + set_src_reg(& $$, PROGRAM_INPUT, $1); + state->prog->InputsRead |= (1U << $$.Base.Index); + + if (!validate_inputs(& @1, state)) { + YYERROR; + } + } + | progParamArray '[' progParamArrayMem ']' + { + if (! $3.Base.RelAddr + && ((unsigned) $3.Base.Index >= $1->param_binding_length)) { + yyerror(& @3, state, "out of bounds array access"); + YYERROR; + } + + init_src_reg(& $$); + $$.Base.File = $1->param_binding_type; + + if ($3.Base.RelAddr) { + $1->param_accessed_indirectly = 1; + + $$.Base.RelAddr = 1; + $$.Base.Index = $3.Base.Index; + $$.Symbol = $1; + } else { + $$.Base.Index = $1->param_binding_begin + $3.Base.Index; + } + } + | paramSingleItemUse + { + gl_register_file file = ($1.name != NULL) + ? $1.param_binding_type + : PROGRAM_CONSTANT; + set_src_reg_swz(& $$, file, $1.param_binding_begin, + $1.param_binding_swizzle); + } + ; + +dstReg: resultBinding + { + set_dst_reg(& $$, PROGRAM_OUTPUT, $1); + } + | USED_IDENTIFIER /* temporaryReg | vertexResultReg */ + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, $1); + + free($1); + + if (s == NULL) { + yyerror(& @1, state, "invalid operand variable"); + YYERROR; + } else if ((s->type != at_output) && (s->type != at_temp)) { + yyerror(& @1, state, "invalid operand variable"); + YYERROR; + } + + switch (s->type) { + case at_temp: + set_dst_reg(& $$, PROGRAM_TEMPORARY, s->temp_binding); + break; + case at_output: + set_dst_reg(& $$, PROGRAM_OUTPUT, s->output_binding); + break; + default: + set_dst_reg(& $$, s->param_binding_type, s->param_binding_begin); + break; + } + } + ; + +progParamArray: USED_IDENTIFIER + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, $1); + + free($1); + + if (s == NULL) { + yyerror(& @1, state, "invalid operand variable"); + YYERROR; + } else if ((s->type != at_param) || !s->param_is_array) { + yyerror(& @1, state, "array access to non-PARAM variable"); + YYERROR; + } else { + $$ = s; + } + } + ; + +progParamArrayMem: progParamArrayAbs | progParamArrayRel; + +progParamArrayAbs: INTEGER + { + init_src_reg(& $$); + $$.Base.Index = $1; + } + ; + +progParamArrayRel: addrReg addrComponent addrRegRelOffset + { + /* FINISHME: Add support for multiple address registers. + */ + /* FINISHME: Add support for 4-component address registers. + */ + init_src_reg(& $$); + $$.Base.RelAddr = 1; + $$.Base.Index = $3; + } + ; + +addrRegRelOffset: { $$ = 0; } + | '+' addrRegPosOffset { $$ = $2; } + | '-' addrRegNegOffset { $$ = -$2; } + ; + +addrRegPosOffset: INTEGER + { + if (($1 < 0) || ($1 > 63)) { + char s[100]; + _mesa_snprintf(s, sizeof(s), + "relative address offset too large (%d)", $1); + yyerror(& @1, state, s); + YYERROR; + } else { + $$ = $1; + } + } + ; + +addrRegNegOffset: INTEGER + { + if (($1 < 0) || ($1 > 64)) { + char s[100]; + _mesa_snprintf(s, sizeof(s), + "relative address offset too large (%d)", $1); + yyerror(& @1, state, s); + YYERROR; + } else { + $$ = $1; + } + } + ; + +addrReg: USED_IDENTIFIER + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, $1); + + free($1); + + if (s == NULL) { + yyerror(& @1, state, "invalid array member"); + YYERROR; + } else if (s->type != at_address) { + yyerror(& @1, state, + "invalid variable for indexed array access"); + YYERROR; + } else { + $$ = s; + } + } + ; + +addrComponent: MASK1 + { + if ($1.mask != WRITEMASK_X) { + yyerror(& @1, state, "invalid address component selector"); + YYERROR; + } else { + $$ = $1; + } + } + ; + +addrWriteMask: MASK1 + { + if ($1.mask != WRITEMASK_X) { + yyerror(& @1, state, + "address register write mask must be \".x\""); + YYERROR; + } else { + $$ = $1; + } + } + ; + +scalarSuffix: MASK1; + +swizzleSuffix: MASK1 + | MASK4 + | SWIZZLE + | { $$.swizzle = SWIZZLE_NOOP; $$.mask = WRITEMASK_XYZW; } + ; + +optionalMask: MASK4 | MASK3 | MASK2 | MASK1 + | { $$.swizzle = SWIZZLE_NOOP; $$.mask = WRITEMASK_XYZW; } + ; + +optionalCcMask: '(' ccTest ')' + { + $$ = $2; + } + | '(' ccTest2 ')' + { + $$ = $2; + } + | + { + $$.CondMask = COND_TR; + $$.CondSwizzle = SWIZZLE_NOOP; + $$.CondSrc = 0; + } + ; + +ccTest: ccMaskRule swizzleSuffix + { + $$ = $1; + $$.CondSwizzle = $2.swizzle; + } + ; + +ccTest2: ccMaskRule2 swizzleSuffix + { + $$ = $1; + $$.CondSwizzle = $2.swizzle; + } + ; + +ccMaskRule: IDENTIFIER + { + const int cond = _mesa_parse_cc($1); + if ((cond == 0) || ($1[2] != '\0')) { + char *const err_str = + make_error_string("invalid condition code \"%s\"", $1); + + yyerror(& @1, state, (err_str != NULL) + ? err_str : "invalid condition code"); + + if (err_str != NULL) { + free(err_str); + } + + YYERROR; + } + + $$.CondMask = cond; + $$.CondSwizzle = SWIZZLE_NOOP; + $$.CondSrc = 0; + } + ; + +ccMaskRule2: USED_IDENTIFIER + { + const int cond = _mesa_parse_cc($1); + if ((cond == 0) || ($1[2] != '\0')) { + char *const err_str = + make_error_string("invalid condition code \"%s\"", $1); + + yyerror(& @1, state, (err_str != NULL) + ? err_str : "invalid condition code"); + + if (err_str != NULL) { + free(err_str); + } + + YYERROR; + } + + $$.CondMask = cond; + $$.CondSwizzle = SWIZZLE_NOOP; + $$.CondSrc = 0; + } + ; + +namingStatement: ATTRIB_statement + | PARAM_statement + | TEMP_statement + | ADDRESS_statement + | OUTPUT_statement + | ALIAS_statement + ; + +ATTRIB_statement: ATTRIB IDENTIFIER '=' attribBinding + { + struct asm_symbol *const s = + declare_variable(state, $2, at_attrib, & @2); + + if (s == NULL) { + free($2); + YYERROR; + } else { + s->attrib_binding = $4; + state->InputsBound |= (1U << s->attrib_binding); + + if (!validate_inputs(& @4, state)) { + YYERROR; + } + } + } + ; + +attribBinding: VERTEX vtxAttribItem + { + $$ = $2; + } + | FRAGMENT fragAttribItem + { + $$ = $2; + } + ; + +vtxAttribItem: POSITION + { + $$ = VERT_ATTRIB_POS; + } + | WEIGHT vtxOptWeightNum + { + $$ = VERT_ATTRIB_WEIGHT; + } + | NORMAL + { + $$ = VERT_ATTRIB_NORMAL; + } + | COLOR optColorType + { + if (!state->ctx->Extensions.EXT_secondary_color) { + yyerror(& @2, state, "GL_EXT_secondary_color not supported"); + YYERROR; + } + + $$ = VERT_ATTRIB_COLOR0 + $2; + } + | FOGCOORD + { + if (!state->ctx->Extensions.EXT_fog_coord) { + yyerror(& @1, state, "GL_EXT_fog_coord not supported"); + YYERROR; + } + + $$ = VERT_ATTRIB_FOG; + } + | TEXCOORD optTexCoordUnitNum + { + $$ = VERT_ATTRIB_TEX0 + $2; + } + | MATRIXINDEX '[' vtxWeightNum ']' + { + yyerror(& @1, state, "GL_ARB_matrix_palette not supported"); + YYERROR; + } + | VTXATTRIB '[' vtxAttribNum ']' + { + $$ = VERT_ATTRIB_GENERIC0 + $3; + } + ; + +vtxAttribNum: INTEGER + { + if ((unsigned) $1 >= state->limits->MaxAttribs) { + yyerror(& @1, state, "invalid vertex attribute reference"); + YYERROR; + } + + $$ = $1; + } + ; + +vtxOptWeightNum: | '[' vtxWeightNum ']'; +vtxWeightNum: INTEGER; + +fragAttribItem: POSITION + { + $$ = FRAG_ATTRIB_WPOS; + } + | COLOR optColorType + { + $$ = FRAG_ATTRIB_COL0 + $2; + } + | FOGCOORD + { + $$ = FRAG_ATTRIB_FOGC; + } + | TEXCOORD optTexCoordUnitNum + { + $$ = FRAG_ATTRIB_TEX0 + $2; + } + ; + +PARAM_statement: PARAM_singleStmt | PARAM_multipleStmt; + +PARAM_singleStmt: PARAM IDENTIFIER paramSingleInit + { + struct asm_symbol *const s = + declare_variable(state, $2, at_param, & @2); + + if (s == NULL) { + free($2); + YYERROR; + } else { + s->param_binding_type = $3.param_binding_type; + s->param_binding_begin = $3.param_binding_begin; + s->param_binding_length = $3.param_binding_length; + s->param_binding_swizzle = $3.param_binding_swizzle; + s->param_is_array = 0; + } + } + ; + +PARAM_multipleStmt: PARAM IDENTIFIER '[' optArraySize ']' paramMultipleInit + { + if (($4 != 0) && ((unsigned) $4 != $6.param_binding_length)) { + free($2); + yyerror(& @4, state, + "parameter array size and number of bindings must match"); + YYERROR; + } else { + struct asm_symbol *const s = + declare_variable(state, $2, $6.type, & @2); + + if (s == NULL) { + free($2); + YYERROR; + } else { + s->param_binding_type = $6.param_binding_type; + s->param_binding_begin = $6.param_binding_begin; + s->param_binding_length = $6.param_binding_length; + s->param_binding_swizzle = SWIZZLE_XYZW; + s->param_is_array = 1; + } + } + } + ; + +optArraySize: + { + $$ = 0; + } + | INTEGER + { + if (($1 < 1) || ((unsigned) $1 > state->limits->MaxParameters)) { + yyerror(& @1, state, "invalid parameter array size"); + YYERROR; + } else { + $$ = $1; + } + } + ; + +paramSingleInit: '=' paramSingleItemDecl + { + $$ = $2; + } + ; + +paramMultipleInit: '=' '{' paramMultInitList '}' + { + $$ = $3; + } + ; + +paramMultInitList: paramMultipleItem + | paramMultInitList ',' paramMultipleItem + { + $1.param_binding_length += $3.param_binding_length; + $$ = $1; + } + ; + +paramSingleItemDecl: stateSingleItem + { + memset(& $$, 0, sizeof($$)); + $$.param_binding_begin = ~0; + initialize_symbol_from_state(state->prog, & $$, $1); + } + | programSingleItem + { + memset(& $$, 0, sizeof($$)); + $$.param_binding_begin = ~0; + initialize_symbol_from_param(state->prog, & $$, $1); + } + | paramConstDecl + { + memset(& $$, 0, sizeof($$)); + $$.param_binding_begin = ~0; + initialize_symbol_from_const(state->prog, & $$, & $1, GL_TRUE); + } + ; + +paramSingleItemUse: stateSingleItem + { + memset(& $$, 0, sizeof($$)); + $$.param_binding_begin = ~0; + initialize_symbol_from_state(state->prog, & $$, $1); + } + | programSingleItem + { + memset(& $$, 0, sizeof($$)); + $$.param_binding_begin = ~0; + initialize_symbol_from_param(state->prog, & $$, $1); + } + | paramConstUse + { + memset(& $$, 0, sizeof($$)); + $$.param_binding_begin = ~0; + initialize_symbol_from_const(state->prog, & $$, & $1, GL_TRUE); + } + ; + +paramMultipleItem: stateMultipleItem + { + memset(& $$, 0, sizeof($$)); + $$.param_binding_begin = ~0; + initialize_symbol_from_state(state->prog, & $$, $1); + } + | programMultipleItem + { + memset(& $$, 0, sizeof($$)); + $$.param_binding_begin = ~0; + initialize_symbol_from_param(state->prog, & $$, $1); + } + | paramConstDecl + { + memset(& $$, 0, sizeof($$)); + $$.param_binding_begin = ~0; + initialize_symbol_from_const(state->prog, & $$, & $1, GL_FALSE); + } + ; + +stateMultipleItem: stateSingleItem { memcpy($$, $1, sizeof($$)); } + | STATE stateMatrixRows { memcpy($$, $2, sizeof($$)); } + ; + +stateSingleItem: STATE stateMaterialItem { memcpy($$, $2, sizeof($$)); } + | STATE stateLightItem { memcpy($$, $2, sizeof($$)); } + | STATE stateLightModelItem { memcpy($$, $2, sizeof($$)); } + | STATE stateLightProdItem { memcpy($$, $2, sizeof($$)); } + | STATE stateTexGenItem { memcpy($$, $2, sizeof($$)); } + | STATE stateTexEnvItem { memcpy($$, $2, sizeof($$)); } + | STATE stateFogItem { memcpy($$, $2, sizeof($$)); } + | STATE stateClipPlaneItem { memcpy($$, $2, sizeof($$)); } + | STATE statePointItem { memcpy($$, $2, sizeof($$)); } + | STATE stateMatrixRow { memcpy($$, $2, sizeof($$)); } + | STATE stateDepthItem { memcpy($$, $2, sizeof($$)); } + ; + +stateMaterialItem: MATERIAL optFaceType stateMatProperty + { + memset($$, 0, sizeof($$)); + $$[0] = STATE_MATERIAL; + $$[1] = $2; + $$[2] = $3; + } + ; + +stateMatProperty: ambDiffSpecProperty + { + $$ = $1; + } + | EMISSION + { + $$ = STATE_EMISSION; + } + | SHININESS + { + $$ = STATE_SHININESS; + } + ; + +stateLightItem: LIGHT '[' stateLightNumber ']' stateLightProperty + { + memset($$, 0, sizeof($$)); + $$[0] = STATE_LIGHT; + $$[1] = $3; + $$[2] = $5; + } + ; + +stateLightProperty: ambDiffSpecProperty + { + $$ = $1; + } + | POSITION + { + $$ = STATE_POSITION; + } + | ATTENUATION + { + if (!state->ctx->Extensions.EXT_point_parameters) { + yyerror(& @1, state, "GL_ARB_point_parameters not supported"); + YYERROR; + } + + $$ = STATE_ATTENUATION; + } + | SPOT stateSpotProperty + { + $$ = $2; + } + | HALF + { + $$ = STATE_HALF_VECTOR; + } + ; + +stateSpotProperty: DIRECTION + { + $$ = STATE_SPOT_DIRECTION; + } + ; + +stateLightModelItem: LIGHTMODEL stateLModProperty + { + $$[0] = $2[0]; + $$[1] = $2[1]; + } + ; + +stateLModProperty: AMBIENT + { + memset($$, 0, sizeof($$)); + $$[0] = STATE_LIGHTMODEL_AMBIENT; + } + | optFaceType SCENECOLOR + { + memset($$, 0, sizeof($$)); + $$[0] = STATE_LIGHTMODEL_SCENECOLOR; + $$[1] = $1; + } + ; + +stateLightProdItem: LIGHTPROD '[' stateLightNumber ']' optFaceType stateLProdProperty + { + memset($$, 0, sizeof($$)); + $$[0] = STATE_LIGHTPROD; + $$[1] = $3; + $$[2] = $5; + $$[3] = $6; + } + ; + +stateLProdProperty: ambDiffSpecProperty; + +stateTexEnvItem: TEXENV optLegacyTexUnitNum stateTexEnvProperty + { + memset($$, 0, sizeof($$)); + $$[0] = $3; + $$[1] = $2; + } + ; + +stateTexEnvProperty: COLOR + { + $$ = STATE_TEXENV_COLOR; + } + ; + +ambDiffSpecProperty: AMBIENT + { + $$ = STATE_AMBIENT; + } + | DIFFUSE + { + $$ = STATE_DIFFUSE; + } + | SPECULAR + { + $$ = STATE_SPECULAR; + } + ; + +stateLightNumber: INTEGER + { + if ((unsigned) $1 >= state->MaxLights) { + yyerror(& @1, state, "invalid light selector"); + YYERROR; + } + + $$ = $1; + } + ; + +stateTexGenItem: TEXGEN optTexCoordUnitNum stateTexGenType stateTexGenCoord + { + memset($$, 0, sizeof($$)); + $$[0] = STATE_TEXGEN; + $$[1] = $2; + $$[2] = $3 + $4; + } + ; + +stateTexGenType: EYE + { + $$ = STATE_TEXGEN_EYE_S; + } + | OBJECT + { + $$ = STATE_TEXGEN_OBJECT_S; + } + ; +stateTexGenCoord: TEXGEN_S + { + $$ = STATE_TEXGEN_EYE_S - STATE_TEXGEN_EYE_S; + } + | TEXGEN_T + { + $$ = STATE_TEXGEN_EYE_T - STATE_TEXGEN_EYE_S; + } + | TEXGEN_R + { + $$ = STATE_TEXGEN_EYE_R - STATE_TEXGEN_EYE_S; + } + | TEXGEN_Q + { + $$ = STATE_TEXGEN_EYE_Q - STATE_TEXGEN_EYE_S; + } + ; + +stateFogItem: FOG stateFogProperty + { + memset($$, 0, sizeof($$)); + $$[0] = $2; + } + ; + +stateFogProperty: COLOR + { + $$ = STATE_FOG_COLOR; + } + | PARAMS + { + $$ = STATE_FOG_PARAMS; + } + ; + +stateClipPlaneItem: CLIP '[' stateClipPlaneNum ']' PLANE + { + memset($$, 0, sizeof($$)); + $$[0] = STATE_CLIPPLANE; + $$[1] = $3; + } + ; + +stateClipPlaneNum: INTEGER + { + if ((unsigned) $1 >= state->MaxClipPlanes) { + yyerror(& @1, state, "invalid clip plane selector"); + YYERROR; + } + + $$ = $1; + } + ; + +statePointItem: POINT_TOK statePointProperty + { + memset($$, 0, sizeof($$)); + $$[0] = $2; + } + ; + +statePointProperty: SIZE_TOK + { + $$ = STATE_POINT_SIZE; + } + | ATTENUATION + { + $$ = STATE_POINT_ATTENUATION; + } + ; + +stateMatrixRow: stateMatrixItem ROW '[' stateMatrixRowNum ']' + { + $$[0] = $1[0]; + $$[1] = $1[1]; + $$[2] = $4; + $$[3] = $4; + $$[4] = $1[2]; + } + ; + +stateMatrixRows: stateMatrixItem optMatrixRows + { + $$[0] = $1[0]; + $$[1] = $1[1]; + $$[2] = $2[2]; + $$[3] = $2[3]; + $$[4] = $1[2]; + } + ; + +optMatrixRows: + { + $$[2] = 0; + $$[3] = 3; + } + | ROW '[' stateMatrixRowNum DOT_DOT stateMatrixRowNum ']' + { + /* It seems logical that the matrix row range specifier would have + * to specify a range or more than one row (i.e., $5 > $3). + * However, the ARB_vertex_program spec says "a program will fail + * to load if is greater than ." This means that $3 == $5 + * is valid. + */ + if ($3 > $5) { + yyerror(& @3, state, "invalid matrix row range"); + YYERROR; + } + + $$[2] = $3; + $$[3] = $5; + } + ; + +stateMatrixItem: MATRIX stateMatrixName stateOptMatModifier + { + $$[0] = $2[0]; + $$[1] = $2[1]; + $$[2] = $3; + } + ; + +stateOptMatModifier: + { + $$ = 0; + } + | stateMatModifier + { + $$ = $1; + } + ; + +stateMatModifier: INVERSE + { + $$ = STATE_MATRIX_INVERSE; + } + | TRANSPOSE + { + $$ = STATE_MATRIX_TRANSPOSE; + } + | INVTRANS + { + $$ = STATE_MATRIX_INVTRANS; + } + ; + +stateMatrixRowNum: INTEGER + { + if ($1 > 3) { + yyerror(& @1, state, "invalid matrix row reference"); + YYERROR; + } + + $$ = $1; + } + ; + +stateMatrixName: MODELVIEW stateOptModMatNum + { + $$[0] = STATE_MODELVIEW_MATRIX; + $$[1] = $2; + } + | PROJECTION + { + $$[0] = STATE_PROJECTION_MATRIX; + $$[1] = 0; + } + | MVP + { + $$[0] = STATE_MVP_MATRIX; + $$[1] = 0; + } + | TEXTURE optTexCoordUnitNum + { + $$[0] = STATE_TEXTURE_MATRIX; + $$[1] = $2; + } + | PALETTE '[' statePaletteMatNum ']' + { + yyerror(& @1, state, "GL_ARB_matrix_palette not supported"); + YYERROR; + } + | MAT_PROGRAM '[' stateProgramMatNum ']' + { + $$[0] = STATE_PROGRAM_MATRIX; + $$[1] = $3; + } + ; + +stateOptModMatNum: + { + $$ = 0; + } + | '[' stateModMatNum ']' + { + $$ = $2; + } + ; +stateModMatNum: INTEGER + { + /* Since GL_ARB_vertex_blend isn't supported, only modelview matrix + * zero is valid. + */ + if ($1 != 0) { + yyerror(& @1, state, "invalid modelview matrix index"); + YYERROR; + } + + $$ = $1; + } + ; +statePaletteMatNum: INTEGER + { + /* Since GL_ARB_matrix_palette isn't supported, just let any value + * through here. The error will be generated later. + */ + $$ = $1; + } + ; +stateProgramMatNum: INTEGER + { + if ((unsigned) $1 >= state->MaxProgramMatrices) { + yyerror(& @1, state, "invalid program matrix selector"); + YYERROR; + } + + $$ = $1; + } + ; + +stateDepthItem: DEPTH RANGE + { + memset($$, 0, sizeof($$)); + $$[0] = STATE_DEPTH_RANGE; + } + ; + + +programSingleItem: progEnvParam | progLocalParam; + +programMultipleItem: progEnvParams | progLocalParams; + +progEnvParams: PROGRAM ENV '[' progEnvParamNums ']' + { + memset($$, 0, sizeof($$)); + $$[0] = state->state_param_enum; + $$[1] = STATE_ENV; + $$[2] = $4[0]; + $$[3] = $4[1]; + } + ; + +progEnvParamNums: progEnvParamNum + { + $$[0] = $1; + $$[1] = $1; + } + | progEnvParamNum DOT_DOT progEnvParamNum + { + $$[0] = $1; + $$[1] = $3; + } + ; + +progEnvParam: PROGRAM ENV '[' progEnvParamNum ']' + { + memset($$, 0, sizeof($$)); + $$[0] = state->state_param_enum; + $$[1] = STATE_ENV; + $$[2] = $4; + $$[3] = $4; + } + ; + +progLocalParams: PROGRAM LOCAL '[' progLocalParamNums ']' + { + memset($$, 0, sizeof($$)); + $$[0] = state->state_param_enum; + $$[1] = STATE_LOCAL; + $$[2] = $4[0]; + $$[3] = $4[1]; + } + +progLocalParamNums: progLocalParamNum + { + $$[0] = $1; + $$[1] = $1; + } + | progLocalParamNum DOT_DOT progLocalParamNum + { + $$[0] = $1; + $$[1] = $3; + } + ; + +progLocalParam: PROGRAM LOCAL '[' progLocalParamNum ']' + { + memset($$, 0, sizeof($$)); + $$[0] = state->state_param_enum; + $$[1] = STATE_LOCAL; + $$[2] = $4; + $$[3] = $4; + } + ; + +progEnvParamNum: INTEGER + { + if ((unsigned) $1 >= state->limits->MaxEnvParams) { + yyerror(& @1, state, "invalid environment parameter reference"); + YYERROR; + } + $$ = $1; + } + ; + +progLocalParamNum: INTEGER + { + if ((unsigned) $1 >= state->limits->MaxLocalParams) { + yyerror(& @1, state, "invalid local parameter reference"); + YYERROR; + } + $$ = $1; + } + ; + + + +paramConstDecl: paramConstScalarDecl | paramConstVector; +paramConstUse: paramConstScalarUse | paramConstVector; + +paramConstScalarDecl: signedFloatConstant + { + $$.count = 4; + $$.data[0] = $1; + $$.data[1] = $1; + $$.data[2] = $1; + $$.data[3] = $1; + } + ; + +paramConstScalarUse: REAL + { + $$.count = 1; + $$.data[0] = $1; + $$.data[1] = $1; + $$.data[2] = $1; + $$.data[3] = $1; + } + | INTEGER + { + $$.count = 1; + $$.data[0] = (float) $1; + $$.data[1] = (float) $1; + $$.data[2] = (float) $1; + $$.data[3] = (float) $1; + } + ; + +paramConstVector: '{' signedFloatConstant '}' + { + $$.count = 4; + $$.data[0] = $2; + $$.data[1] = 0.0f; + $$.data[2] = 0.0f; + $$.data[3] = 1.0f; + } + | '{' signedFloatConstant ',' signedFloatConstant '}' + { + $$.count = 4; + $$.data[0] = $2; + $$.data[1] = $4; + $$.data[2] = 0.0f; + $$.data[3] = 1.0f; + } + | '{' signedFloatConstant ',' signedFloatConstant ',' + signedFloatConstant '}' + { + $$.count = 4; + $$.data[0] = $2; + $$.data[1] = $4; + $$.data[2] = $6; + $$.data[3] = 1.0f; + } + | '{' signedFloatConstant ',' signedFloatConstant ',' + signedFloatConstant ',' signedFloatConstant '}' + { + $$.count = 4; + $$.data[0] = $2; + $$.data[1] = $4; + $$.data[2] = $6; + $$.data[3] = $8; + } + ; + +signedFloatConstant: optionalSign REAL + { + $$ = ($1) ? -$2 : $2; + } + | optionalSign INTEGER + { + $$ = (float)(($1) ? -$2 : $2); + } + ; + +optionalSign: '+' { $$ = FALSE; } + | '-' { $$ = TRUE; } + | { $$ = FALSE; } + ; + +TEMP_statement: optVarSize TEMP { $$ = $2; } varNameList + ; + +optVarSize: string + { + /* NV_fragment_program_option defines the size qualifiers in a + * fairly broken way. "SHORT" or "LONG" can optionally be used + * before TEMP or OUTPUT. However, neither is a reserved word! + * This means that we have to parse it as an identifier, then check + * to make sure it's one of the valid values. *sigh* + * + * In addition, the grammar in the extension spec does *not* allow + * the size specifier to be optional, but all known implementations + * do. + */ + if (!state->option.NV_fragment) { + yyerror(& @1, state, "unexpected IDENTIFIER"); + YYERROR; + } + + if (strcmp("SHORT", $1) == 0) { + } else if (strcmp("LONG", $1) == 0) { + } else { + char *const err_str = + make_error_string("invalid storage size specifier \"%s\"", + $1); + + yyerror(& @1, state, (err_str != NULL) + ? err_str : "invalid storage size specifier"); + + if (err_str != NULL) { + free(err_str); + } + + YYERROR; + } + } + | + { + } + ; + +ADDRESS_statement: ADDRESS { $$ = $1; } varNameList + ; + +varNameList: varNameList ',' IDENTIFIER + { + if (!declare_variable(state, $3, $0, & @3)) { + free($3); + YYERROR; + } + } + | IDENTIFIER + { + if (!declare_variable(state, $1, $0, & @1)) { + free($1); + YYERROR; + } + } + ; + +OUTPUT_statement: optVarSize OUTPUT IDENTIFIER '=' resultBinding + { + struct asm_symbol *const s = + declare_variable(state, $3, at_output, & @3); + + if (s == NULL) { + free($3); + YYERROR; + } else { + s->output_binding = $5; + } + } + ; + +resultBinding: RESULT POSITION + { + if (state->mode == ARB_vertex) { + $$ = VERT_RESULT_HPOS; + } else { + yyerror(& @2, state, "invalid program result name"); + YYERROR; + } + } + | RESULT FOGCOORD + { + if (state->mode == ARB_vertex) { + $$ = VERT_RESULT_FOGC; + } else { + yyerror(& @2, state, "invalid program result name"); + YYERROR; + } + } + | RESULT resultColBinding + { + $$ = $2; + } + | RESULT POINTSIZE + { + if (state->mode == ARB_vertex) { + $$ = VERT_RESULT_PSIZ; + } else { + yyerror(& @2, state, "invalid program result name"); + YYERROR; + } + } + | RESULT TEXCOORD optTexCoordUnitNum + { + if (state->mode == ARB_vertex) { + $$ = VERT_RESULT_TEX0 + $3; + } else { + yyerror(& @2, state, "invalid program result name"); + YYERROR; + } + } + | RESULT DEPTH + { + if (state->mode == ARB_fragment) { + $$ = FRAG_RESULT_DEPTH; + } else { + yyerror(& @2, state, "invalid program result name"); + YYERROR; + } + } + ; + +resultColBinding: COLOR optResultFaceType optResultColorType + { + $$ = $2 + $3; + } + ; + +optResultFaceType: + { + $$ = (state->mode == ARB_vertex) + ? VERT_RESULT_COL0 + : FRAG_RESULT_COLOR; + } + | FRONT + { + if (state->mode == ARB_vertex) { + $$ = VERT_RESULT_COL0; + } else { + yyerror(& @1, state, "invalid program result name"); + YYERROR; + } + } + | BACK + { + if (state->mode == ARB_vertex) { + $$ = VERT_RESULT_BFC0; + } else { + yyerror(& @1, state, "invalid program result name"); + YYERROR; + } + } + ; + +optResultColorType: + { + $$ = 0; + } + | PRIMARY + { + if (state->mode == ARB_vertex) { + $$ = 0; + } else { + yyerror(& @1, state, "invalid program result name"); + YYERROR; + } + } + | SECONDARY + { + if (state->mode == ARB_vertex) { + $$ = 1; + } else { + yyerror(& @1, state, "invalid program result name"); + YYERROR; + } + } + ; + +optFaceType: { $$ = 0; } + | FRONT { $$ = 0; } + | BACK { $$ = 1; } + ; + +optColorType: { $$ = 0; } + | PRIMARY { $$ = 0; } + | SECONDARY { $$ = 1; } + ; + +optTexCoordUnitNum: { $$ = 0; } + | '[' texCoordUnitNum ']' { $$ = $2; } + ; + +optTexImageUnitNum: { $$ = 0; } + | '[' texImageUnitNum ']' { $$ = $2; } + ; + +optLegacyTexUnitNum: { $$ = 0; } + | '[' legacyTexUnitNum ']' { $$ = $2; } + ; + +texCoordUnitNum: INTEGER + { + if ((unsigned) $1 >= state->MaxTextureCoordUnits) { + yyerror(& @1, state, "invalid texture coordinate unit selector"); + YYERROR; + } + + $$ = $1; + } + ; + +texImageUnitNum: INTEGER + { + if ((unsigned) $1 >= state->MaxTextureImageUnits) { + yyerror(& @1, state, "invalid texture image unit selector"); + YYERROR; + } + + $$ = $1; + } + ; + +legacyTexUnitNum: INTEGER + { + if ((unsigned) $1 >= state->MaxTextureUnits) { + yyerror(& @1, state, "invalid texture unit selector"); + YYERROR; + } + + $$ = $1; + } + ; + +ALIAS_statement: ALIAS IDENTIFIER '=' USED_IDENTIFIER + { + struct asm_symbol *exist = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, $2); + struct asm_symbol *target = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, $4); + + free($4); + + if (exist != NULL) { + char m[1000]; + _mesa_snprintf(m, sizeof(m), "redeclared identifier: %s", $2); + free($2); + yyerror(& @2, state, m); + YYERROR; + } else if (target == NULL) { + free($2); + yyerror(& @4, state, + "undefined variable binding in ALIAS statement"); + YYERROR; + } else { + _mesa_symbol_table_add_symbol(state->st, 0, $2, target); + } + } + ; + +string: IDENTIFIER + | USED_IDENTIFIER + ; + +%% + +void +asm_instruction_set_operands(struct asm_instruction *inst, + const struct prog_dst_register *dst, + const struct asm_src_register *src0, + const struct asm_src_register *src1, + const struct asm_src_register *src2) +{ + /* In the core ARB extensions only the KIL instruction doesn't have a + * destination register. + */ + if (dst == NULL) { + init_dst_reg(& inst->Base.DstReg); + } else { + inst->Base.DstReg = *dst; + } + + /* The only instruction that doesn't have any source registers is the + * condition-code based KIL instruction added by NV_fragment_program_option. + */ + if (src0 != NULL) { + inst->Base.SrcReg[0] = src0->Base; + inst->SrcReg[0] = *src0; + } else { + init_src_reg(& inst->SrcReg[0]); + } + + if (src1 != NULL) { + inst->Base.SrcReg[1] = src1->Base; + inst->SrcReg[1] = *src1; + } else { + init_src_reg(& inst->SrcReg[1]); + } + + if (src2 != NULL) { + inst->Base.SrcReg[2] = src2->Base; + inst->SrcReg[2] = *src2; + } else { + init_src_reg(& inst->SrcReg[2]); + } +} + + +struct asm_instruction * +asm_instruction_ctor(gl_inst_opcode op, + const struct prog_dst_register *dst, + const struct asm_src_register *src0, + const struct asm_src_register *src1, + const struct asm_src_register *src2) +{ + struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction); + + if (inst) { + _mesa_init_instructions(& inst->Base, 1); + inst->Base.Opcode = op; + + asm_instruction_set_operands(inst, dst, src0, src1, src2); + } + + return inst; +} + + +struct asm_instruction * +asm_instruction_copy_ctor(const struct prog_instruction *base, + const struct prog_dst_register *dst, + const struct asm_src_register *src0, + const struct asm_src_register *src1, + const struct asm_src_register *src2) +{ + struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction); + + if (inst) { + _mesa_init_instructions(& inst->Base, 1); + inst->Base.Opcode = base->Opcode; + inst->Base.CondUpdate = base->CondUpdate; + inst->Base.CondDst = base->CondDst; + inst->Base.SaturateMode = base->SaturateMode; + inst->Base.Precision = base->Precision; + + asm_instruction_set_operands(inst, dst, src0, src1, src2); + } + + return inst; +} + + +void +init_dst_reg(struct prog_dst_register *r) +{ + memset(r, 0, sizeof(*r)); + r->File = PROGRAM_UNDEFINED; + r->WriteMask = WRITEMASK_XYZW; + r->CondMask = COND_TR; + r->CondSwizzle = SWIZZLE_NOOP; +} + + +/** Like init_dst_reg() but set the File and Index fields. */ +void +set_dst_reg(struct prog_dst_register *r, gl_register_file file, GLint index) +{ + const GLint maxIndex = 1 << INST_INDEX_BITS; + const GLint minIndex = 0; + ASSERT(index >= minIndex); + (void) minIndex; + ASSERT(index <= maxIndex); + (void) maxIndex; + ASSERT(file == PROGRAM_TEMPORARY || + file == PROGRAM_ADDRESS || + file == PROGRAM_OUTPUT); + memset(r, 0, sizeof(*r)); + r->File = file; + r->Index = index; + r->WriteMask = WRITEMASK_XYZW; + r->CondMask = COND_TR; + r->CondSwizzle = SWIZZLE_NOOP; +} + + +void +init_src_reg(struct asm_src_register *r) +{ + memset(r, 0, sizeof(*r)); + r->Base.File = PROGRAM_UNDEFINED; + r->Base.Swizzle = SWIZZLE_NOOP; + r->Symbol = NULL; +} + + +/** Like init_src_reg() but set the File and Index fields. + * \return GL_TRUE if a valid src register, GL_FALSE otherwise + */ +void +set_src_reg(struct asm_src_register *r, gl_register_file file, GLint index) +{ + set_src_reg_swz(r, file, index, SWIZZLE_XYZW); +} + + +void +set_src_reg_swz(struct asm_src_register *r, gl_register_file file, GLint index, + GLuint swizzle) +{ + const GLint maxIndex = (1 << INST_INDEX_BITS) - 1; + const GLint minIndex = -(1 << INST_INDEX_BITS); + ASSERT(file < PROGRAM_FILE_MAX); + ASSERT(index >= minIndex); + (void) minIndex; + ASSERT(index <= maxIndex); + (void) maxIndex; + memset(r, 0, sizeof(*r)); + r->Base.File = file; + r->Base.Index = index; + r->Base.Swizzle = swizzle; + r->Symbol = NULL; +} + + +/** + * Validate the set of inputs used by a program + * + * Validates that legal sets of inputs are used by the program. In this case + * "used" included both reading the input or binding the input to a name using + * the \c ATTRIB command. + * + * \return + * \c TRUE if the combination of inputs used is valid, \c FALSE otherwise. + */ +int +validate_inputs(struct YYLTYPE *locp, struct asm_parser_state *state) +{ + const int inputs = state->prog->InputsRead | state->InputsBound; + + if (((inputs & 0x0ffff) & (inputs >> 16)) != 0) { + yyerror(locp, state, "illegal use of generic attribute and name attribute"); + return 0; + } + + return 1; +} + + +struct asm_symbol * +declare_variable(struct asm_parser_state *state, char *name, enum asm_type t, + struct YYLTYPE *locp) +{ + struct asm_symbol *s = NULL; + struct asm_symbol *exist = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, name); + + + if (exist != NULL) { + yyerror(locp, state, "redeclared identifier"); + } else { + s = calloc(1, sizeof(struct asm_symbol)); + s->name = name; + s->type = t; + + switch (t) { + case at_temp: + if (state->prog->NumTemporaries >= state->limits->MaxTemps) { + yyerror(locp, state, "too many temporaries declared"); + free(s); + return NULL; + } + + s->temp_binding = state->prog->NumTemporaries; + state->prog->NumTemporaries++; + break; + + case at_address: + if (state->prog->NumAddressRegs >= state->limits->MaxAddressRegs) { + yyerror(locp, state, "too many address registers declared"); + free(s); + return NULL; + } + + /* FINISHME: Add support for multiple address registers. + */ + state->prog->NumAddressRegs++; + break; + + default: + break; + } + + _mesa_symbol_table_add_symbol(state->st, 0, s->name, s); + s->next = state->sym; + state->sym = s; + } + + return s; +} + + +int add_state_reference(struct gl_program_parameter_list *param_list, + const gl_state_index tokens[STATE_LENGTH]) +{ + const GLuint size = 4; /* XXX fix */ + char *name; + GLint index; + + name = _mesa_program_state_string(tokens); + index = _mesa_add_parameter(param_list, PROGRAM_STATE_VAR, name, + size, GL_NONE, NULL, tokens, 0x0); + param_list->StateFlags |= _mesa_program_state_flags(tokens); + + /* free name string here since we duplicated it in add_parameter() */ + free(name); + + return index; +} + + +int +initialize_symbol_from_state(struct gl_program *prog, + struct asm_symbol *param_var, + const gl_state_index tokens[STATE_LENGTH]) +{ + int idx = -1; + gl_state_index state_tokens[STATE_LENGTH]; + + + memcpy(state_tokens, tokens, sizeof(state_tokens)); + + param_var->type = at_param; + param_var->param_binding_type = PROGRAM_STATE_VAR; + + /* If we are adding a STATE_MATRIX that has multiple rows, we need to + * unroll it and call add_state_reference() for each row + */ + if ((state_tokens[0] == STATE_MODELVIEW_MATRIX || + state_tokens[0] == STATE_PROJECTION_MATRIX || + state_tokens[0] == STATE_MVP_MATRIX || + state_tokens[0] == STATE_TEXTURE_MATRIX || + state_tokens[0] == STATE_PROGRAM_MATRIX) + && (state_tokens[2] != state_tokens[3])) { + int row; + const int first_row = state_tokens[2]; + const int last_row = state_tokens[3]; + + for (row = first_row; row <= last_row; row++) { + state_tokens[2] = state_tokens[3] = row; + + idx = add_state_reference(prog->Parameters, state_tokens); + if (param_var->param_binding_begin == ~0U) { + param_var->param_binding_begin = idx; + param_var->param_binding_swizzle = SWIZZLE_XYZW; + } + + param_var->param_binding_length++; + } + } + else { + idx = add_state_reference(prog->Parameters, state_tokens); + if (param_var->param_binding_begin == ~0U) { + param_var->param_binding_begin = idx; + param_var->param_binding_swizzle = SWIZZLE_XYZW; + } + param_var->param_binding_length++; + } + + return idx; +} + + +int +initialize_symbol_from_param(struct gl_program *prog, + struct asm_symbol *param_var, + const gl_state_index tokens[STATE_LENGTH]) +{ + int idx = -1; + gl_state_index state_tokens[STATE_LENGTH]; + + + memcpy(state_tokens, tokens, sizeof(state_tokens)); + + assert((state_tokens[0] == STATE_VERTEX_PROGRAM) + || (state_tokens[0] == STATE_FRAGMENT_PROGRAM)); + assert((state_tokens[1] == STATE_ENV) + || (state_tokens[1] == STATE_LOCAL)); + + /* + * The param type is STATE_VAR. The program parameter entry will + * effectively be a pointer into the LOCAL or ENV parameter array. + */ + param_var->type = at_param; + param_var->param_binding_type = PROGRAM_STATE_VAR; + + /* If we are adding a STATE_ENV or STATE_LOCAL that has multiple elements, + * we need to unroll it and call add_state_reference() for each row + */ + if (state_tokens[2] != state_tokens[3]) { + int row; + const int first_row = state_tokens[2]; + const int last_row = state_tokens[3]; + + for (row = first_row; row <= last_row; row++) { + state_tokens[2] = state_tokens[3] = row; + + idx = add_state_reference(prog->Parameters, state_tokens); + if (param_var->param_binding_begin == ~0U) { + param_var->param_binding_begin = idx; + param_var->param_binding_swizzle = SWIZZLE_XYZW; + } + param_var->param_binding_length++; + } + } + else { + idx = add_state_reference(prog->Parameters, state_tokens); + if (param_var->param_binding_begin == ~0U) { + param_var->param_binding_begin = idx; + param_var->param_binding_swizzle = SWIZZLE_XYZW; + } + param_var->param_binding_length++; + } + + return idx; +} + + +/** + * Put a float/vector constant/literal into the parameter list. + * \param param_var returns info about the parameter/constant's location, + * binding, type, etc. + * \param vec the vector/constant to add + * \param allowSwizzle if true, try to consolidate constants which only differ + * by a swizzle. We don't want to do this when building + * arrays of constants that may be indexed indirectly. + * \return index of the constant in the parameter list. + */ +int +initialize_symbol_from_const(struct gl_program *prog, + struct asm_symbol *param_var, + const struct asm_vector *vec, + GLboolean allowSwizzle) +{ + unsigned swizzle; + const int idx = _mesa_add_unnamed_constant(prog->Parameters, + vec->data, vec->count, + allowSwizzle ? &swizzle : NULL); + + param_var->type = at_param; + param_var->param_binding_type = PROGRAM_CONSTANT; + + if (param_var->param_binding_begin == ~0U) { + param_var->param_binding_begin = idx; + param_var->param_binding_swizzle = allowSwizzle ? swizzle : SWIZZLE_XYZW; + } + param_var->param_binding_length++; + + return idx; +} + + +char * +make_error_string(const char *fmt, ...) +{ + int length; + char *str; + va_list args; + + + /* Call vsnprintf once to determine how large the final string is. Call it + * again to do the actual formatting. from the vsnprintf manual page: + * + * Upon successful return, these functions return the number of + * characters printed (not including the trailing '\0' used to end + * output to strings). + */ + va_start(args, fmt); + length = 1 + vsnprintf(NULL, 0, fmt, args); + va_end(args); + + str = malloc(length); + if (str) { + va_start(args, fmt); + vsnprintf(str, length, fmt, args); + va_end(args); + } + + return str; +} + + +void +yyerror(YYLTYPE *locp, struct asm_parser_state *state, const char *s) +{ + char *err_str; + + + err_str = make_error_string("glProgramStringARB(%s)\n", s); + if (err_str) { + _mesa_error(state->ctx, GL_INVALID_OPERATION, err_str); + free(err_str); + } + + err_str = make_error_string("line %u, char %u: error: %s\n", + locp->first_line, locp->first_column, s); + _mesa_set_program_error(state->ctx, locp->position, err_str); + + if (err_str) { + free(err_str); + } +} + + +GLboolean +_mesa_parse_arb_program(GLcontext *ctx, GLenum target, const GLubyte *str, + GLsizei len, struct asm_parser_state *state) +{ + struct asm_instruction *inst; + unsigned i; + GLubyte *strz; + GLboolean result = GL_FALSE; + void *temp; + struct asm_symbol *sym; + + state->ctx = ctx; + state->prog->Target = target; + state->prog->Parameters = _mesa_new_parameter_list(); + + /* Make a copy of the program string and force it to be NUL-terminated. + */ + strz = (GLubyte *) malloc(len + 1); + if (strz == NULL) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramStringARB"); + return GL_FALSE; + } + memcpy (strz, str, len); + strz[len] = '\0'; + + state->prog->String = strz; + + state->st = _mesa_symbol_table_ctor(); + + state->limits = (target == GL_VERTEX_PROGRAM_ARB) + ? & ctx->Const.VertexProgram + : & ctx->Const.FragmentProgram; + + state->MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits; + state->MaxTextureCoordUnits = ctx->Const.MaxTextureCoordUnits; + state->MaxTextureUnits = ctx->Const.MaxTextureUnits; + state->MaxClipPlanes = ctx->Const.MaxClipPlanes; + state->MaxLights = ctx->Const.MaxLights; + state->MaxProgramMatrices = ctx->Const.MaxProgramMatrices; + + state->state_param_enum = (target == GL_VERTEX_PROGRAM_ARB) + ? STATE_VERTEX_PROGRAM : STATE_FRAGMENT_PROGRAM; + + _mesa_set_program_error(ctx, -1, NULL); + + _mesa_program_lexer_ctor(& state->scanner, state, (const char *) str, len); + yyparse(state); + _mesa_program_lexer_dtor(state->scanner); + + + if (ctx->Program.ErrorPos != -1) { + goto error; + } + + if (! _mesa_layout_parameters(state)) { + struct YYLTYPE loc; + + loc.first_line = 0; + loc.first_column = 0; + loc.position = len; + + yyerror(& loc, state, "invalid PARAM usage"); + goto error; + } + + + + /* Add one instruction to store the "END" instruction. + */ + state->prog->Instructions = + _mesa_alloc_instructions(state->prog->NumInstructions + 1); + inst = state->inst_head; + for (i = 0; i < state->prog->NumInstructions; i++) { + struct asm_instruction *const temp = inst->next; + + state->prog->Instructions[i] = inst->Base; + inst = temp; + } + + /* Finally, tag on an OPCODE_END instruction */ + { + const GLuint numInst = state->prog->NumInstructions; + _mesa_init_instructions(state->prog->Instructions + numInst, 1); + state->prog->Instructions[numInst].Opcode = OPCODE_END; + } + state->prog->NumInstructions++; + + state->prog->NumParameters = state->prog->Parameters->NumParameters; + state->prog->NumAttributes = _mesa_bitcount(state->prog->InputsRead); + + /* + * Initialize native counts to logical counts. The device driver may + * change them if program is translated into a hardware program. + */ + state->prog->NumNativeInstructions = state->prog->NumInstructions; + state->prog->NumNativeTemporaries = state->prog->NumTemporaries; + state->prog->NumNativeParameters = state->prog->NumParameters; + state->prog->NumNativeAttributes = state->prog->NumAttributes; + state->prog->NumNativeAddressRegs = state->prog->NumAddressRegs; + + result = GL_TRUE; + +error: + for (inst = state->inst_head; inst != NULL; inst = temp) { + temp = inst->next; + free(inst); + } + + state->inst_head = NULL; + state->inst_tail = NULL; + + for (sym = state->sym; sym != NULL; sym = temp) { + temp = sym->next; + + free((void *) sym->name); + free(sym); + } + state->sym = NULL; + + _mesa_symbol_table_dtor(state->st); + state->st = NULL; + + return result; +} diff --git a/src/mesa/program/program_parse_extra.c b/src/mesa/program/program_parse_extra.c new file mode 100644 index 0000000000..ae98b782b7 --- /dev/null +++ b/src/mesa/program/program_parse_extra.c @@ -0,0 +1,255 @@ +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include "main/mtypes.h" +#include "prog_instruction.h" +#include "program_parser.h" + + +/** + * Extra assembly-level parser routines + * + * \author Ian Romanick + */ + +int +_mesa_parse_instruction_suffix(const struct asm_parser_state *state, + const char *suffix, + struct prog_instruction *inst) +{ + inst->CondUpdate = 0; + inst->CondDst = 0; + inst->SaturateMode = SATURATE_OFF; + inst->Precision = FLOAT32; + + + /* The first possible suffix element is the precision specifier from + * NV_fragment_program_option. + */ + if (state->option.NV_fragment) { + switch (suffix[0]) { + case 'H': + inst->Precision = FLOAT16; + suffix++; + break; + case 'R': + inst->Precision = FLOAT32; + suffix++; + break; + case 'X': + inst->Precision = FIXED12; + suffix++; + break; + default: + break; + } + } + + /* The next possible suffix element is the condition code modifier selection + * from NV_fragment_program_option. + */ + if (state->option.NV_fragment) { + if (suffix[0] == 'C') { + inst->CondUpdate = 1; + suffix++; + } + } + + + /* The final possible suffix element is the saturation selector from + * ARB_fragment_program. + */ + if (state->mode == ARB_fragment) { + if (strcmp(suffix, "_SAT") == 0) { + inst->SaturateMode = SATURATE_ZERO_ONE; + suffix += 4; + } + } + + + /* It is an error for all of the suffix string not to be consumed. + */ + return suffix[0] == '\0'; +} + + +int +_mesa_parse_cc(const char *s) +{ + int cond = 0; + + switch (s[0]) { + case 'E': + if (s[1] == 'Q') { + cond = COND_EQ; + } + break; + + case 'F': + if (s[1] == 'L') { + cond = COND_FL; + } + break; + + case 'G': + if (s[1] == 'E') { + cond = COND_GE; + } else if (s[1] == 'T') { + cond = COND_GT; + } + break; + + case 'L': + if (s[1] == 'E') { + cond = COND_LE; + } else if (s[1] == 'T') { + cond = COND_LT; + } + break; + + case 'N': + if (s[1] == 'E') { + cond = COND_NE; + } + break; + + case 'T': + if (s[1] == 'R') { + cond = COND_TR; + } + break; + + default: + break; + } + + return ((cond == 0) || (s[2] != '\0')) ? 0 : cond; +} + + +int +_mesa_ARBvp_parse_option(struct asm_parser_state *state, const char *option) +{ + if (strcmp(option, "ARB_position_invariant") == 0) { + state->option.PositionInvariant = 1; + return 1; + } + + return 0; +} + + +int +_mesa_ARBfp_parse_option(struct asm_parser_state *state, const char *option) +{ + /* All of the options currently supported start with "ARB_". The code is + * currently structured with nested if-statements because eventually options + * that start with "NV_" will be supported. This structure will result in + * less churn when those options are added. + */ + if (strncmp(option, "ARB_", 4) == 0) { + /* Advance the pointer past the "ARB_" prefix. + */ + option += 4; + + + if (strncmp(option, "fog_", 4) == 0) { + option += 4; + + if (state->option.Fog == OPTION_NONE) { + if (strcmp(option, "exp") == 0) { + state->option.Fog = OPTION_FOG_EXP; + return 1; + } else if (strcmp(option, "exp2") == 0) { + state->option.Fog = OPTION_FOG_EXP2; + return 1; + } else if (strcmp(option, "linear") == 0) { + state->option.Fog = OPTION_FOG_LINEAR; + return 1; + } + } + + return 0; + } else if (strncmp(option, "precision_hint_", 15) == 0) { + option += 15; + + if (state->option.PrecisionHint == OPTION_NONE) { + if (strcmp(option, "nicest") == 0) { + state->option.PrecisionHint = OPTION_NICEST; + return 1; + } else if (strcmp(option, "fastest") == 0) { + state->option.PrecisionHint = OPTION_FASTEST; + return 1; + } + } + + return 0; + } else if (strcmp(option, "draw_buffers") == 0) { + /* Don't need to check extension availability because all Mesa-based + * drivers support GL_ARB_draw_buffers. + */ + state->option.DrawBuffers = 1; + return 1; + } else if (strcmp(option, "fragment_program_shadow") == 0) { + if (state->ctx->Extensions.ARB_fragment_program_shadow) { + state->option.Shadow = 1; + return 1; + } + } else if (strncmp(option, "fragment_coord_", 15) == 0) { + option += 15; + if (state->ctx->Extensions.ARB_fragment_coord_conventions) { + if (strcmp(option, "origin_upper_left") == 0) { + state->option.OriginUpperLeft = 1; + return 1; + } + else if (strcmp(option, "pixel_center_integer") == 0) { + state->option.PixelCenterInteger = 1; + return 1; + } + } + } + } else if (strncmp(option, "NV_fragment_program", 19) == 0) { + option += 19; + + /* Other NV_fragment_program strings may be supported later. + */ + if (option[0] == '\0') { + if (state->ctx->Extensions.NV_fragment_program_option) { + state->option.NV_fragment = 1; + return 1; + } + } + } else if (strncmp(option, "MESA_", 5) == 0) { + option += 5; + + if (strcmp(option, "texture_array") == 0) { + if (state->ctx->Extensions.MESA_texture_array) { + state->option.TexArray = 1; + return 1; + } + } + } + + return 0; +} diff --git a/src/mesa/program/program_parser.h b/src/mesa/program/program_parser.h new file mode 100644 index 0000000000..be952d4b9c --- /dev/null +++ b/src/mesa/program/program_parser.h @@ -0,0 +1,302 @@ +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include "main/config.h" + +#ifndef MTYPES_H +struct __GLcontextRec; +typedef struct __GLcontextRec GLcontext; +#endif + +enum asm_type { + at_none, + at_address, + at_attrib, + at_param, + at_temp, + at_output +}; + +struct asm_symbol { + struct asm_symbol *next; /**< List linkage for freeing. */ + const char *name; + enum asm_type type; + unsigned attrib_binding; + unsigned output_binding; /**< Output / result register number. */ + + /** + * One of PROGRAM_STATE_VAR, PROGRAM_LOCAL_PARAM, or PROGRAM_ENV_PARAM. + */ + unsigned param_binding_type; + + /** + * Offset into the program_parameter_list where the tokens representing our + * bound state (or constants) start. + */ + unsigned param_binding_begin; + + /** + * Constants put into the parameter list may be swizzled. This + * field contain's the symbol's swizzle. (SWIZZLE_X/Y/Z/W) + */ + unsigned param_binding_swizzle; + + /* This is how many entries in the program_parameter_list we take up + * with our state tokens or constants. Note that this is _not_ the same as + * the number of param registers we eventually use. + */ + unsigned param_binding_length; + + /** + * Index of the temp register assigned to this variable. + */ + unsigned temp_binding; + + /** + * Flag whether or not a PARAM is an array + */ + unsigned param_is_array:1; + + + /** + * Flag whether or not a PARAM array is accessed indirectly + */ + unsigned param_accessed_indirectly:1; + + + /** + * \brief Is first pass of parameter layout done with this variable? + * + * The parameter layout routine operates in two passes. This flag tracks + * whether or not the first pass has handled this variable. + * + * \sa _mesa_layout_parameters + */ + unsigned pass1_done:1; +}; + + +struct asm_vector { + unsigned count; + float data[4]; +}; + + +struct asm_swizzle_mask { + unsigned swizzle:12; + unsigned mask:4; +}; + + +struct asm_src_register { + struct prog_src_register Base; + + /** + * Symbol associated with indirect access to parameter arrays. + * + * If \c Base::RelAddr is 1, this will point to the symbol for the parameter + * that is being dereferenced. Further, \c Base::Index will be the offset + * from the address register being used. + */ + struct asm_symbol *Symbol; +}; + + +struct asm_instruction { + struct prog_instruction Base; + struct asm_instruction *next; + struct asm_src_register SrcReg[3]; +}; + + +struct asm_parser_state { + GLcontext *ctx; + struct gl_program *prog; + + /** + * Per-program target limits + */ + struct gl_program_constants *limits; + + struct _mesa_symbol_table *st; + + /** + * Linked list of symbols + * + * This list is \b only used when cleaning up compiler state and freeing + * memory. + */ + struct asm_symbol *sym; + + /** + * State for the lexer. + */ + void *scanner; + + /** + * Linked list of instructions generated during parsing. + */ + /*@{*/ + struct asm_instruction *inst_head; + struct asm_instruction *inst_tail; + /*@}*/ + + + /** + * Selected limits copied from gl_constants + * + * These are limits from the GL context, but various bits in the program + * must be validated against these values. + */ + /*@{*/ + unsigned MaxTextureCoordUnits; + unsigned MaxTextureImageUnits; + unsigned MaxTextureUnits; + unsigned MaxClipPlanes; + unsigned MaxLights; + unsigned MaxProgramMatrices; + /*@}*/ + + /** + * Value to use in state vector accessors for environment and local + * parameters + */ + unsigned state_param_enum; + + + /** + * Input attributes bound to specific names + * + * This is only needed so that errors can be properly produced when + * multiple ATTRIB statements bind illegal combinations of vertex + * attributes. + */ + unsigned InputsBound; + + enum { + invalid_mode = 0, + ARB_vertex, + ARB_fragment + } mode; + + struct { + unsigned PositionInvariant:1; + unsigned Fog:2; + unsigned PrecisionHint:2; + unsigned DrawBuffers:1; + unsigned Shadow:1; + unsigned TexRect:1; + unsigned TexArray:1; + unsigned NV_fragment:1; + unsigned OriginUpperLeft:1; + unsigned PixelCenterInteger:1; + } option; + + struct { + unsigned UsesKill:1; + } fragment; +}; + +#define OPTION_NONE 0 +#define OPTION_FOG_EXP 1 +#define OPTION_FOG_EXP2 2 +#define OPTION_FOG_LINEAR 3 +#define OPTION_NICEST 1 +#define OPTION_FASTEST 2 + +typedef struct YYLTYPE { + int first_line; + int first_column; + int last_line; + int last_column; + int position; +} YYLTYPE; + +#define YYLTYPE_IS_DECLARED 1 +#define YYLTYPE_IS_TRIVIAL 1 + + +extern GLboolean _mesa_parse_arb_program(GLcontext *ctx, GLenum target, + const GLubyte *str, GLsizei len, struct asm_parser_state *state); + + + +/* From program_lexer.l. */ +extern void _mesa_program_lexer_dtor(void *scanner); + +extern void _mesa_program_lexer_ctor(void **scanner, + struct asm_parser_state *state, const char *string, size_t len); + + +/** + *\name From program_parse_extra.c + */ +/*@{*/ + +/** + * Parses and processes an option string to an ARB vertex program + * + * \return + * Non-zero on success, zero on failure. + */ +extern int _mesa_ARBvp_parse_option(struct asm_parser_state *state, + const char *option); + +/** + * Parses and processes an option string to an ARB fragment program + * + * \return + * Non-zero on success, zero on failure. + */ +extern int _mesa_ARBfp_parse_option(struct asm_parser_state *state, + const char *option); + +/** + * Parses and processes instruction suffixes + * + * Instruction suffixes, such as \c _SAT, are processed. The relevant bits + * are set in \c inst. If suffixes are encountered that are either not known + * or not supported by the modes and options set in \c state, zero will be + * returned. + * + * \return + * Non-zero on success, zero on failure. + */ +extern int _mesa_parse_instruction_suffix(const struct asm_parser_state *state, + const char *suffix, struct prog_instruction *inst); + +/** + * Parses a condition code name + * + * The condition code names (e.g., \c LT, \c GT, \c NE) were added to assembly + * shaders with the \c GL_NV_fragment_program_option extension. This function + * converts a string representation into one of the \c COND_ macros. + * + * \return + * One of the \c COND_ macros defined in prog_instruction.h on success or zero + * on failure. + */ +extern int _mesa_parse_cc(const char *s); + +/*@}*/ diff --git a/src/mesa/program/programopt.c b/src/mesa/program/programopt.c new file mode 100644 index 0000000000..fb2ebe6338 --- /dev/null +++ b/src/mesa/program/programopt.c @@ -0,0 +1,669 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file programopt.c + * Vertex/Fragment program optimizations and transformations for program + * options, etc. + * + * \author Brian Paul + */ + + +#include "main/glheader.h" +#include "main/context.h" +#include "prog_parameter.h" +#include "prog_statevars.h" +#include "program.h" +#include "programopt.h" +#include "prog_instruction.h" + + +/** + * This function inserts instructions for coordinate modelview * projection + * into a vertex program. + * May be used to implement the position_invariant option. + */ +static void +_mesa_insert_mvp_dp4_code(GLcontext *ctx, struct gl_vertex_program *vprog) +{ + struct prog_instruction *newInst; + const GLuint origLen = vprog->Base.NumInstructions; + const GLuint newLen = origLen + 4; + GLuint i; + + /* + * Setup state references for the modelview/projection matrix. + * XXX we should check if these state vars are already declared. + */ + static const gl_state_index mvpState[4][STATE_LENGTH] = { + { STATE_MVP_MATRIX, 0, 0, 0, 0 }, /* state.matrix.mvp.row[0] */ + { STATE_MVP_MATRIX, 0, 1, 1, 0 }, /* state.matrix.mvp.row[1] */ + { STATE_MVP_MATRIX, 0, 2, 2, 0 }, /* state.matrix.mvp.row[2] */ + { STATE_MVP_MATRIX, 0, 3, 3, 0 }, /* state.matrix.mvp.row[3] */ + }; + GLint mvpRef[4]; + + for (i = 0; i < 4; i++) { + mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters, + mvpState[i]); + } + + /* Alloc storage for new instructions */ + newInst = _mesa_alloc_instructions(newLen); + if (!newInst) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "glProgramString(inserting position_invariant code)"); + return; + } + + /* + * Generated instructions: + * newInst[0] = DP4 result.position.x, mvp.row[0], vertex.position; + * newInst[1] = DP4 result.position.y, mvp.row[1], vertex.position; + * newInst[2] = DP4 result.position.z, mvp.row[2], vertex.position; + * newInst[3] = DP4 result.position.w, mvp.row[3], vertex.position; + */ + _mesa_init_instructions(newInst, 4); + for (i = 0; i < 4; i++) { + newInst[i].Opcode = OPCODE_DP4; + newInst[i].DstReg.File = PROGRAM_OUTPUT; + newInst[i].DstReg.Index = VERT_RESULT_HPOS; + newInst[i].DstReg.WriteMask = (WRITEMASK_X << i); + newInst[i].SrcReg[0].File = PROGRAM_STATE_VAR; + newInst[i].SrcReg[0].Index = mvpRef[i]; + newInst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP; + newInst[i].SrcReg[1].File = PROGRAM_INPUT; + newInst[i].SrcReg[1].Index = VERT_ATTRIB_POS; + newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; + } + + /* Append original instructions after new instructions */ + _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen); + + /* free old instructions */ + _mesa_free_instructions(vprog->Base.Instructions, origLen); + + /* install new instructions */ + vprog->Base.Instructions = newInst; + vprog->Base.NumInstructions = newLen; + vprog->Base.InputsRead |= VERT_BIT_POS; + vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS); +} + + +static void +_mesa_insert_mvp_mad_code(GLcontext *ctx, struct gl_vertex_program *vprog) +{ + struct prog_instruction *newInst; + const GLuint origLen = vprog->Base.NumInstructions; + const GLuint newLen = origLen + 4; + GLuint hposTemp; + GLuint i; + + /* + * Setup state references for the modelview/projection matrix. + * XXX we should check if these state vars are already declared. + */ + static const gl_state_index mvpState[4][STATE_LENGTH] = { + { STATE_MVP_MATRIX, 0, 0, 0, STATE_MATRIX_TRANSPOSE }, + { STATE_MVP_MATRIX, 0, 1, 1, STATE_MATRIX_TRANSPOSE }, + { STATE_MVP_MATRIX, 0, 2, 2, STATE_MATRIX_TRANSPOSE }, + { STATE_MVP_MATRIX, 0, 3, 3, STATE_MATRIX_TRANSPOSE }, + }; + GLint mvpRef[4]; + + for (i = 0; i < 4; i++) { + mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters, + mvpState[i]); + } + + /* Alloc storage for new instructions */ + newInst = _mesa_alloc_instructions(newLen); + if (!newInst) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "glProgramString(inserting position_invariant code)"); + return; + } + + /* TEMP hposTemp; */ + hposTemp = vprog->Base.NumTemporaries++; + + /* + * Generated instructions: + * emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]); + * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp); + * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp); + * emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp); + */ + _mesa_init_instructions(newInst, 4); + + newInst[0].Opcode = OPCODE_MUL; + newInst[0].DstReg.File = PROGRAM_TEMPORARY; + newInst[0].DstReg.Index = hposTemp; + newInst[0].DstReg.WriteMask = WRITEMASK_XYZW; + newInst[0].SrcReg[0].File = PROGRAM_INPUT; + newInst[0].SrcReg[0].Index = VERT_ATTRIB_POS; + newInst[0].SrcReg[0].Swizzle = SWIZZLE_XXXX; + newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR; + newInst[0].SrcReg[1].Index = mvpRef[0]; + newInst[0].SrcReg[1].Swizzle = SWIZZLE_NOOP; + + for (i = 1; i <= 2; i++) { + newInst[i].Opcode = OPCODE_MAD; + newInst[i].DstReg.File = PROGRAM_TEMPORARY; + newInst[i].DstReg.Index = hposTemp; + newInst[i].DstReg.WriteMask = WRITEMASK_XYZW; + newInst[i].SrcReg[0].File = PROGRAM_INPUT; + newInst[i].SrcReg[0].Index = VERT_ATTRIB_POS; + newInst[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(i,i,i,i); + newInst[i].SrcReg[1].File = PROGRAM_STATE_VAR; + newInst[i].SrcReg[1].Index = mvpRef[i]; + newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; + newInst[i].SrcReg[2].File = PROGRAM_TEMPORARY; + newInst[i].SrcReg[2].Index = hposTemp; + newInst[1].SrcReg[2].Swizzle = SWIZZLE_NOOP; + } + + newInst[3].Opcode = OPCODE_MAD; + newInst[3].DstReg.File = PROGRAM_OUTPUT; + newInst[3].DstReg.Index = VERT_RESULT_HPOS; + newInst[3].DstReg.WriteMask = WRITEMASK_XYZW; + newInst[3].SrcReg[0].File = PROGRAM_INPUT; + newInst[3].SrcReg[0].Index = VERT_ATTRIB_POS; + newInst[3].SrcReg[0].Swizzle = SWIZZLE_WWWW; + newInst[3].SrcReg[1].File = PROGRAM_STATE_VAR; + newInst[3].SrcReg[1].Index = mvpRef[3]; + newInst[3].SrcReg[1].Swizzle = SWIZZLE_NOOP; + newInst[3].SrcReg[2].File = PROGRAM_TEMPORARY; + newInst[3].SrcReg[2].Index = hposTemp; + newInst[3].SrcReg[2].Swizzle = SWIZZLE_NOOP; + + + /* Append original instructions after new instructions */ + _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen); + + /* free old instructions */ + _mesa_free_instructions(vprog->Base.Instructions, origLen); + + /* install new instructions */ + vprog->Base.Instructions = newInst; + vprog->Base.NumInstructions = newLen; + vprog->Base.InputsRead |= VERT_BIT_POS; + vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS); +} + + +void +_mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog) +{ + if (ctx->mvp_with_dp4) + _mesa_insert_mvp_dp4_code( ctx, vprog ); + else + _mesa_insert_mvp_mad_code( ctx, vprog ); +} + + + + + + +/** + * Append extra instructions onto the given fragment program to implement + * the fog mode specified by fprog->FogOption. + * The fragment.fogcoord input is used to compute the fog blend factor. + * + * XXX with a little work, this function could be adapted to add fog code + * to vertex programs too. + */ +void +_mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog) +{ + static const gl_state_index fogPStateOpt[STATE_LENGTH] + = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 }; + static const gl_state_index fogColorState[STATE_LENGTH] + = { STATE_FOG_COLOR, 0, 0, 0, 0}; + struct prog_instruction *newInst, *inst; + const GLuint origLen = fprog->Base.NumInstructions; + const GLuint newLen = origLen + 5; + GLuint i; + GLint fogPRefOpt, fogColorRef; /* state references */ + GLuint colorTemp, fogFactorTemp; /* temporary registerss */ + + if (fprog->FogOption == GL_NONE) { + _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program" + " with FogOption == GL_NONE"); + return; + } + + /* Alloc storage for new instructions */ + newInst = _mesa_alloc_instructions(newLen); + if (!newInst) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "glProgramString(inserting fog_option code)"); + return; + } + + /* Copy orig instructions into new instruction buffer */ + _mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen); + + /* PARAM fogParamsRefOpt = internal optimized fog params; */ + fogPRefOpt + = _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt); + /* PARAM fogColorRef = state.fog.color; */ + fogColorRef + = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState); + + /* TEMP colorTemp; */ + colorTemp = fprog->Base.NumTemporaries++; + /* TEMP fogFactorTemp; */ + fogFactorTemp = fprog->Base.NumTemporaries++; + + /* Scan program to find where result.color is written */ + inst = newInst; + for (i = 0; i < fprog->Base.NumInstructions; i++) { + if (inst->Opcode == OPCODE_END) + break; + if (inst->DstReg.File == PROGRAM_OUTPUT && + inst->DstReg.Index == FRAG_RESULT_COLOR) { + /* change the instruction to write to colorTemp w/ clamping */ + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = colorTemp; + inst->SaturateMode = SATURATE_ZERO_ONE; + /* don't break (may be several writes to result.color) */ + } + inst++; + } + assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */ + + _mesa_init_instructions(inst, 5); + + /* emit instructions to compute fog blending factor */ + if (fprog->FogOption == GL_LINEAR) { + /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */ + inst->Opcode = OPCODE_MAD; + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = fogFactorTemp; + inst->DstReg.WriteMask = WRITEMASK_X; + inst->SrcReg[0].File = PROGRAM_INPUT; + inst->SrcReg[0].Index = FRAG_ATTRIB_FOGC; + inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; + inst->SrcReg[1].File = PROGRAM_STATE_VAR; + inst->SrcReg[1].Index = fogPRefOpt; + inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; + inst->SrcReg[2].File = PROGRAM_STATE_VAR; + inst->SrcReg[2].Index = fogPRefOpt; + inst->SrcReg[2].Swizzle = SWIZZLE_YYYY; + inst->SaturateMode = SATURATE_ZERO_ONE; + inst++; + } + else { + ASSERT(fprog->FogOption == GL_EXP || fprog->FogOption == GL_EXP2); + /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */ + /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */ + /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */ + inst->Opcode = OPCODE_MUL; + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = fogFactorTemp; + inst->DstReg.WriteMask = WRITEMASK_X; + inst->SrcReg[0].File = PROGRAM_STATE_VAR; + inst->SrcReg[0].Index = fogPRefOpt; + inst->SrcReg[0].Swizzle + = (fprog->FogOption == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW; + inst->SrcReg[1].File = PROGRAM_INPUT; + inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC; + inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; + inst++; + if (fprog->FogOption == GL_EXP2) { + /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */ + inst->Opcode = OPCODE_MUL; + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = fogFactorTemp; + inst->DstReg.WriteMask = WRITEMASK_X; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = fogFactorTemp; + inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; + inst->SrcReg[1].File = PROGRAM_TEMPORARY; + inst->SrcReg[1].Index = fogFactorTemp; + inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; + inst++; + } + /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */ + inst->Opcode = OPCODE_EX2; + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = fogFactorTemp; + inst->DstReg.WriteMask = WRITEMASK_X; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = fogFactorTemp; + inst->SrcReg[0].Negate = NEGATE_XYZW; + inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; + inst->SaturateMode = SATURATE_ZERO_ONE; + inst++; + } + /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */ + inst->Opcode = OPCODE_LRP; + inst->DstReg.File = PROGRAM_OUTPUT; + inst->DstReg.Index = FRAG_RESULT_COLOR; + inst->DstReg.WriteMask = WRITEMASK_XYZ; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = fogFactorTemp; + inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; + inst->SrcReg[1].File = PROGRAM_TEMPORARY; + inst->SrcReg[1].Index = colorTemp; + inst->SrcReg[1].Swizzle = SWIZZLE_NOOP; + inst->SrcReg[2].File = PROGRAM_STATE_VAR; + inst->SrcReg[2].Index = fogColorRef; + inst->SrcReg[2].Swizzle = SWIZZLE_NOOP; + inst++; + /* MOV result.color.w, colorTemp.x; # copy alpha */ + inst->Opcode = OPCODE_MOV; + inst->DstReg.File = PROGRAM_OUTPUT; + inst->DstReg.Index = FRAG_RESULT_COLOR; + inst->DstReg.WriteMask = WRITEMASK_W; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = colorTemp; + inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; + inst++; + /* END; */ + inst->Opcode = OPCODE_END; + inst++; + + /* free old instructions */ + _mesa_free_instructions(fprog->Base.Instructions, origLen); + + /* install new instructions */ + fprog->Base.Instructions = newInst; + fprog->Base.NumInstructions = inst - newInst; + fprog->Base.InputsRead |= FRAG_BIT_FOGC; + /* XXX do this? fprog->FogOption = GL_NONE; */ +} + + + +static GLboolean +is_texture_instruction(const struct prog_instruction *inst) +{ + switch (inst->Opcode) { + case OPCODE_TEX: + case OPCODE_TXB: + case OPCODE_TXD: + case OPCODE_TXL: + case OPCODE_TXP: + case OPCODE_TXP_NV: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Count the number of texure indirections in the given program. + * The program's NumTexIndirections field will be updated. + * See the GL_ARB_fragment_program spec (issue 24) for details. + * XXX we count texture indirections in texenvprogram.c (maybe use this code + * instead and elsewhere). + */ +void +_mesa_count_texture_indirections(struct gl_program *prog) +{ + GLuint indirections = 1; + GLbitfield tempsOutput = 0x0; + GLbitfield aluTemps = 0x0; + GLuint i; + + for (i = 0; i < prog->NumInstructions; i++) { + const struct prog_instruction *inst = prog->Instructions + i; + + if (is_texture_instruction(inst)) { + if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) && + (tempsOutput & (1 << inst->SrcReg[0].Index))) || + ((inst->Opcode != OPCODE_KIL) && + (inst->DstReg.File == PROGRAM_TEMPORARY) && + (aluTemps & (1 << inst->DstReg.Index)))) + { + indirections++; + tempsOutput = 0x0; + aluTemps = 0x0; + } + } + else { + GLuint j; + for (j = 0; j < 3; j++) { + if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) + aluTemps |= (1 << inst->SrcReg[j].Index); + } + if (inst->DstReg.File == PROGRAM_TEMPORARY) + aluTemps |= (1 << inst->DstReg.Index); + } + + if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY)) + tempsOutput |= (1 << inst->DstReg.Index); + } + + prog->NumTexIndirections = indirections; +} + + +/** + * Count number of texture instructions in given program and update the + * program's NumTexInstructions field. + */ +void +_mesa_count_texture_instructions(struct gl_program *prog) +{ + GLuint i; + prog->NumTexInstructions = 0; + for (i = 0; i < prog->NumInstructions; i++) { + prog->NumTexInstructions += is_texture_instruction(prog->Instructions + i); + } +} + + +/** + * Scan/rewrite program to remove reads of custom (output) registers. + * The passed type has to be either PROGRAM_OUTPUT or PROGRAM_VARYING + * (for vertex shaders). + * In GLSL shaders, varying vars can be read and written. + * On some hardware, trying to read an output register causes trouble. + * So, rewrite the program to use a temporary register in this case. + */ +void +_mesa_remove_output_reads(struct gl_program *prog, gl_register_file type) +{ + GLuint i; + GLint outputMap[VERT_RESULT_MAX]; + GLuint numVaryingReads = 0; + GLboolean usedTemps[MAX_PROGRAM_TEMPS]; + GLuint firstTemp = 0; + + _mesa_find_used_registers(prog, PROGRAM_TEMPORARY, + usedTemps, MAX_PROGRAM_TEMPS); + + assert(type == PROGRAM_VARYING || type == PROGRAM_OUTPUT); + assert(prog->Target == GL_VERTEX_PROGRAM_ARB || type != PROGRAM_VARYING); + + for (i = 0; i < VERT_RESULT_MAX; i++) + outputMap[i] = -1; + + /* look for instructions which read from varying vars */ + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); + GLuint j; + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == type) { + /* replace the read with a temp reg */ + const GLuint var = inst->SrcReg[j].Index; + if (outputMap[var] == -1) { + numVaryingReads++; + outputMap[var] = _mesa_find_free_register(usedTemps, + MAX_PROGRAM_TEMPS, + firstTemp); + firstTemp = outputMap[var] + 1; + } + inst->SrcReg[j].File = PROGRAM_TEMPORARY; + inst->SrcReg[j].Index = outputMap[var]; + } + } + } + + if (numVaryingReads == 0) + return; /* nothing to be done */ + + /* look for instructions which write to the varying vars identified above */ + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + if (inst->DstReg.File == type && + outputMap[inst->DstReg.Index] >= 0) { + /* change inst to write to the temp reg, instead of the varying */ + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = outputMap[inst->DstReg.Index]; + } + } + + /* insert new instructions to copy the temp vars to the varying vars */ + { + struct prog_instruction *inst; + GLint endPos, var; + + /* Look for END instruction and insert the new varying writes */ + endPos = -1; + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + if (inst->Opcode == OPCODE_END) { + endPos = i; + _mesa_insert_instructions(prog, i, numVaryingReads); + break; + } + } + + assert(endPos >= 0); + + /* insert new MOV instructions here */ + inst = prog->Instructions + endPos; + for (var = 0; var < VERT_RESULT_MAX; var++) { + if (outputMap[var] >= 0) { + /* MOV VAR[var], TEMP[tmp]; */ + inst->Opcode = OPCODE_MOV; + inst->DstReg.File = type; + inst->DstReg.Index = var; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = outputMap[var]; + inst++; + } + } + } +} + + +/** + * Make the given fragment program into a "no-op" shader. + * Actually, just copy the incoming fragment color (or texcoord) + * to the output color. + * This is for debug/test purposes. + */ +void +_mesa_nop_fragment_program(GLcontext *ctx, struct gl_fragment_program *prog) +{ + struct prog_instruction *inst; + GLuint inputAttr; + + inst = _mesa_alloc_instructions(2); + if (!inst) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_fragment_program"); + return; + } + + _mesa_init_instructions(inst, 2); + + inst[0].Opcode = OPCODE_MOV; + inst[0].DstReg.File = PROGRAM_OUTPUT; + inst[0].DstReg.Index = FRAG_RESULT_COLOR; + inst[0].SrcReg[0].File = PROGRAM_INPUT; + if (prog->Base.InputsRead & FRAG_BIT_COL0) + inputAttr = FRAG_ATTRIB_COL0; + else + inputAttr = FRAG_ATTRIB_TEX0; + inst[0].SrcReg[0].Index = inputAttr; + + inst[1].Opcode = OPCODE_END; + + _mesa_free_instructions(prog->Base.Instructions, + prog->Base.NumInstructions); + + prog->Base.Instructions = inst; + prog->Base.NumInstructions = 2; + prog->Base.InputsRead = 1 << inputAttr; + prog->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR); +} + + +/** + * \sa _mesa_nop_fragment_program + * Replace the given vertex program with a "no-op" program that just + * transforms vertex position and emits color. + */ +void +_mesa_nop_vertex_program(GLcontext *ctx, struct gl_vertex_program *prog) +{ + struct prog_instruction *inst; + GLuint inputAttr; + + /* + * Start with a simple vertex program that emits color. + */ + inst = _mesa_alloc_instructions(2); + if (!inst) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_vertex_program"); + return; + } + + _mesa_init_instructions(inst, 2); + + inst[0].Opcode = OPCODE_MOV; + inst[0].DstReg.File = PROGRAM_OUTPUT; + inst[0].DstReg.Index = VERT_RESULT_COL0; + inst[0].SrcReg[0].File = PROGRAM_INPUT; + if (prog->Base.InputsRead & VERT_BIT_COLOR0) + inputAttr = VERT_ATTRIB_COLOR0; + else + inputAttr = VERT_ATTRIB_TEX0; + inst[0].SrcReg[0].Index = inputAttr; + + inst[1].Opcode = OPCODE_END; + + _mesa_free_instructions(prog->Base.Instructions, + prog->Base.NumInstructions); + + prog->Base.Instructions = inst; + prog->Base.NumInstructions = 2; + prog->Base.InputsRead = 1 << inputAttr; + prog->Base.OutputsWritten = BITFIELD64_BIT(VERT_RESULT_COL0); + + /* + * Now insert code to do standard modelview/projection transformation. + */ + _mesa_insert_mvp_code(ctx, prog); +} diff --git a/src/mesa/program/programopt.h b/src/mesa/program/programopt.h new file mode 100644 index 0000000000..21fac07849 --- /dev/null +++ b/src/mesa/program/programopt.h @@ -0,0 +1,52 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef PROGRAMOPT_H +#define PROGRAMOPT_H 1 + + +extern void +_mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog); + +extern void +_mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog); + +extern void +_mesa_count_texture_indirections(struct gl_program *prog); + +extern void +_mesa_count_texture_instructions(struct gl_program *prog); + +extern void +_mesa_remove_output_reads(struct gl_program *prog, gl_register_file type); + +extern void +_mesa_nop_fragment_program(GLcontext *ctx, struct gl_fragment_program *prog); + +extern void +_mesa_nop_vertex_program(GLcontext *ctx, struct gl_vertex_program *prog); + + +#endif /* PROGRAMOPT_H */ diff --git a/src/mesa/program/symbol_table.c b/src/mesa/program/symbol_table.c new file mode 100644 index 0000000000..6a5d686897 --- /dev/null +++ b/src/mesa/program/symbol_table.c @@ -0,0 +1,362 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "main/imports.h" +#include "symbol_table.h" +#include "hash_table.h" + +struct symbol { + /** + * Link to the next symbol in the table with the same name + * + * The linked list of symbols with the same name is ordered by scope + * from inner-most to outer-most. + */ + struct symbol *next_with_same_name; + + + /** + * Link to the next symbol in the table with the same scope + * + * The linked list of symbols with the same scope is unordered. Symbols + * in this list my have unique names. + */ + struct symbol *next_with_same_scope; + + + /** + * Header information for the list of symbols with the same name. + */ + struct symbol_header *hdr; + + + /** + * Name space of the symbol + * + * Name space are arbitrary user assigned integers. No two symbols can + * exist in the same name space at the same scope level. + */ + int name_space; + + + /** + * Arbitrary user supplied data. + */ + void *data; +}; + + +/** + */ +struct symbol_header { + /** Linkage in list of all headers in a given symbol table. */ + struct symbol_header *next; + + /** Symbol name. */ + const char *name; + + /** Linked list of symbols with the same name. */ + struct symbol *symbols; +}; + + +/** + * Element of the scope stack. + */ +struct scope_level { + /** Link to next (inner) scope level. */ + struct scope_level *next; + + /** Linked list of symbols with the same scope. */ + struct symbol *symbols; +}; + + +/** + * + */ +struct _mesa_symbol_table { + /** Hash table containing all symbols in the symbol table. */ + struct hash_table *ht; + + /** Top of scope stack. */ + struct scope_level *current_scope; + + /** List of all symbol headers in the table. */ + struct symbol_header *hdr; +}; + + +struct _mesa_symbol_table_iterator { + /** + * Name space of symbols returned by this iterator. + */ + int name_space; + + + /** + * Currently iterated symbol + * + * The next call to \c _mesa_symbol_table_iterator_get will return this + * value. It will also update this value to the value that should be + * returned by the next call. + */ + struct symbol *curr; +}; + + +static void +check_symbol_table(struct _mesa_symbol_table *table) +{ +#if 1 + struct scope_level *scope; + + for (scope = table->current_scope; scope != NULL; scope = scope->next) { + struct symbol *sym; + + for (sym = scope->symbols + ; sym != NULL + ; sym = sym->next_with_same_name) { + const struct symbol_header *const hdr = sym->hdr; + struct symbol *sym2; + + for (sym2 = hdr->symbols + ; sym2 != NULL + ; sym2 = sym2->next_with_same_name) { + assert(sym2->hdr == hdr); + } + } + } +#endif +} + +void +_mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table) +{ + struct scope_level *const scope = table->current_scope; + struct symbol *sym = scope->symbols; + + table->current_scope = scope->next; + + free(scope); + + while (sym != NULL) { + struct symbol *const next = sym->next_with_same_scope; + struct symbol_header *const hdr = sym->hdr; + + assert(hdr->symbols == sym); + + hdr->symbols = sym->next_with_same_name; + + free(sym); + + sym = next; + } + + check_symbol_table(table); +} + + +void +_mesa_symbol_table_push_scope(struct _mesa_symbol_table *table) +{ + struct scope_level *const scope = calloc(1, sizeof(*scope)); + + scope->next = table->current_scope; + table->current_scope = scope; +} + + +static struct symbol_header * +find_symbol(struct _mesa_symbol_table *table, const char *name) +{ + return (struct symbol_header *) hash_table_find(table->ht, name); +} + + +struct _mesa_symbol_table_iterator * +_mesa_symbol_table_iterator_ctor(struct _mesa_symbol_table *table, + int name_space, const char *name) +{ + struct _mesa_symbol_table_iterator *iter = calloc(1, sizeof(*iter)); + struct symbol_header *const hdr = find_symbol(table, name); + + iter->name_space = name_space; + + if (hdr != NULL) { + struct symbol *sym; + + for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) { + assert(sym->hdr == hdr); + + if ((name_space == -1) || (sym->name_space == name_space)) { + iter->curr = sym; + break; + } + } + } + + return iter; +} + + +void +_mesa_symbol_table_iterator_dtor(struct _mesa_symbol_table_iterator *iter) +{ + free(iter); +} + + +void * +_mesa_symbol_table_iterator_get(struct _mesa_symbol_table_iterator *iter) +{ + return (iter->curr == NULL) ? NULL : iter->curr->data; +} + + +int +_mesa_symbol_table_iterator_next(struct _mesa_symbol_table_iterator *iter) +{ + struct symbol_header *hdr; + + if (iter->curr == NULL) { + return 0; + } + + hdr = iter->curr->hdr; + iter->curr = iter->curr->next_with_same_name; + + while (iter->curr != NULL) { + assert(iter->curr->hdr == hdr); + + if ((iter->name_space == -1) + || (iter->curr->name_space == iter->name_space)) { + return 1; + } + + iter->curr = iter->curr->next_with_same_name; + } + + return 0; +} + + +void * +_mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table, + int name_space, const char *name) +{ + struct symbol_header *const hdr = find_symbol(table, name); + + if (hdr != NULL) { + struct symbol *sym; + + + for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) { + assert(sym->hdr == hdr); + + if ((name_space == -1) || (sym->name_space == name_space)) { + return sym->data; + } + } + } + + return NULL; +} + + +int +_mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table, + int name_space, const char *name, + void *declaration) +{ + struct symbol_header *hdr; + struct symbol *sym; + + check_symbol_table(table); + + hdr = find_symbol(table, name); + + check_symbol_table(table); + + if (hdr == NULL) { + hdr = calloc(1, sizeof(*hdr)); + hdr->name = name; + + hash_table_insert(table->ht, hdr, name); + hdr->next = table->hdr; + table->hdr = hdr; + } + + check_symbol_table(table); + + sym = calloc(1, sizeof(*sym)); + sym->next_with_same_name = hdr->symbols; + sym->next_with_same_scope = table->current_scope->symbols; + sym->hdr = hdr; + sym->name_space = name_space; + sym->data = declaration; + + assert(sym->hdr == hdr); + + hdr->symbols = sym; + table->current_scope->symbols = sym; + + check_symbol_table(table); + return 0; +} + + +struct _mesa_symbol_table * +_mesa_symbol_table_ctor(void) +{ + struct _mesa_symbol_table *table = calloc(1, sizeof(*table)); + + if (table != NULL) { + table->ht = hash_table_ctor(32, hash_table_string_hash, + hash_table_string_compare); + + _mesa_symbol_table_push_scope(table); + } + + return table; +} + + +void +_mesa_symbol_table_dtor(struct _mesa_symbol_table *table) +{ + struct symbol_header *hdr; + struct symbol_header *next; + + while (table->current_scope != NULL) { + _mesa_symbol_table_pop_scope(table); + } + + for (hdr = table->hdr; hdr != NULL; hdr = next) { + next = hdr->next; + free(hdr); + } + + hash_table_dtor(table->ht); + free(table); +} diff --git a/src/mesa/program/symbol_table.h b/src/mesa/program/symbol_table.h new file mode 100644 index 0000000000..0c054ef139 --- /dev/null +++ b/src/mesa/program/symbol_table.h @@ -0,0 +1,55 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#ifndef MESA_SYMBOL_TABLE_H +#define MESA_SYMBOL_TABLE_H + +struct _mesa_symbol_table; +struct _mesa_symbol_table_iterator; + +extern void _mesa_symbol_table_push_scope(struct _mesa_symbol_table *table); + +extern void _mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table); + +extern int _mesa_symbol_table_add_symbol(struct _mesa_symbol_table *symtab, + int name_space, const char *name, void *declaration); + +extern void *_mesa_symbol_table_find_symbol( + struct _mesa_symbol_table *symtab, int name_space, const char *name); + +extern struct _mesa_symbol_table *_mesa_symbol_table_ctor(void); + +extern void _mesa_symbol_table_dtor(struct _mesa_symbol_table *); + +extern struct _mesa_symbol_table_iterator *_mesa_symbol_table_iterator_ctor( + struct _mesa_symbol_table *table, int name_space, const char *name); + +extern void _mesa_symbol_table_iterator_dtor( + struct _mesa_symbol_table_iterator *); + +extern void *_mesa_symbol_table_iterator_get( + struct _mesa_symbol_table_iterator *iter); + +extern int _mesa_symbol_table_iterator_next( + struct _mesa_symbol_table_iterator *iter); + +#endif /* MESA_SYMBOL_TABLE_H */ diff --git a/src/mesa/shader/.gitignore b/src/mesa/shader/.gitignore deleted file mode 100644 index 086fd9a705..0000000000 --- a/src/mesa/shader/.gitignore +++ /dev/null @@ -1 +0,0 @@ -program_parse.output diff --git a/src/mesa/shader/Makefile b/src/mesa/shader/Makefile deleted file mode 100644 index 400a543bda..0000000000 --- a/src/mesa/shader/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: program_parse.tab.c lex.yy.c - -program_parse.tab.c program_parse.tab.h: program_parse.y - bison -v -d $< - -lex.yy.c: program_lexer.l - flex --never-interactive $< diff --git a/src/mesa/shader/arbprogparse.c b/src/mesa/shader/arbprogparse.c deleted file mode 100644 index 6373529e4e..0000000000 --- a/src/mesa/shader/arbprogparse.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#define DEBUG_PARSING 0 - -/** - * \file arbprogparse.c - * ARB_*_program parser core - * \author Karl Rasche - */ - -/** -Notes on program parameters, etc. - -The instructions we emit will use six kinds of source registers: - - PROGRAM_INPUT - input registers - PROGRAM_TEMPORARY - temp registers - PROGRAM_ADDRESS - address/indirect register - PROGRAM_SAMPLER - texture sampler - PROGRAM_CONSTANT - indexes into program->Parameters, a known constant/literal - PROGRAM_STATE_VAR - indexes into program->Parameters, and may actually be: - + a state variable, like "state.fog.color", or - + a pointer to a "program.local[k]" parameter, or - + a pointer to a "program.env[k]" parameter - -Basically, all the program.local[] and program.env[] values will get mapped -into the unified gl_program->Parameters array. This solves the problem of -having three separate program parameter arrays. -*/ - - -#include "main/glheader.h" -#include "main/imports.h" -#include "main/context.h" -#include "main/mtypes.h" -#include "arbprogparse.h" -#include "programopt.h" -#include "prog_parameter.h" -#include "prog_statevars.h" -#include "prog_instruction.h" -#include "program_parser.h" - - -void -_mesa_parse_arb_fragment_program(GLcontext* ctx, GLenum target, - const GLvoid *str, GLsizei len, - struct gl_fragment_program *program) -{ - struct gl_program prog; - struct asm_parser_state state; - GLuint i; - - ASSERT(target == GL_FRAGMENT_PROGRAM_ARB); - - memset(&prog, 0, sizeof(prog)); - memset(&state, 0, sizeof(state)); - state.prog = &prog; - - if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len, - &state)) { - /* Error in the program. Just return. */ - return; - } - - if (program->Base.String != NULL) - free(program->Base.String); - - /* Copy the relevant contents of the arb_program struct into the - * fragment_program struct. - */ - program->Base.String = prog.String; - program->Base.NumInstructions = prog.NumInstructions; - program->Base.NumTemporaries = prog.NumTemporaries; - program->Base.NumParameters = prog.NumParameters; - program->Base.NumAttributes = prog.NumAttributes; - program->Base.NumAddressRegs = prog.NumAddressRegs; - program->Base.NumNativeInstructions = prog.NumNativeInstructions; - program->Base.NumNativeTemporaries = prog.NumNativeTemporaries; - program->Base.NumNativeParameters = prog.NumNativeParameters; - program->Base.NumNativeAttributes = prog.NumNativeAttributes; - program->Base.NumNativeAddressRegs = prog.NumNativeAddressRegs; - program->Base.NumAluInstructions = prog.NumAluInstructions; - program->Base.NumTexInstructions = prog.NumTexInstructions; - program->Base.NumTexIndirections = prog.NumTexIndirections; - program->Base.NumNativeAluInstructions = prog.NumAluInstructions; - program->Base.NumNativeTexInstructions = prog.NumTexInstructions; - program->Base.NumNativeTexIndirections = prog.NumTexIndirections; - program->Base.InputsRead = prog.InputsRead; - program->Base.OutputsWritten = prog.OutputsWritten; - for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++) { - program->Base.TexturesUsed[i] = prog.TexturesUsed[i]; - if (prog.TexturesUsed[i]) - program->Base.SamplersUsed |= (1 << i); - } - program->Base.ShadowSamplers = prog.ShadowSamplers; - switch (state.option.Fog) { - case OPTION_FOG_EXP: program->FogOption = GL_EXP; break; - case OPTION_FOG_EXP2: program->FogOption = GL_EXP2; break; - case OPTION_FOG_LINEAR: program->FogOption = GL_LINEAR; break; - default: program->FogOption = GL_NONE; break; - } - program->OriginUpperLeft = state.option.OriginUpperLeft; - program->PixelCenterInteger = state.option.PixelCenterInteger; - - program->UsesKill = state.fragment.UsesKill; - - if (program->FogOption) - program->Base.InputsRead |= FRAG_BIT_FOGC; - - if (program->Base.Instructions) - free(program->Base.Instructions); - program->Base.Instructions = prog.Instructions; - - if (program->Base.Parameters) - _mesa_free_parameter_list(program->Base.Parameters); - program->Base.Parameters = prog.Parameters; - - /* Append fog instructions now if the program has "OPTION ARB_fog_exp" - * or similar. We used to leave this up to drivers, but it appears - * there's no hardware that wants to do fog in a discrete stage separate - * from the fragment shader. - */ - if (program->FogOption != GL_NONE) { - _mesa_append_fog_code(ctx, program); - program->FogOption = GL_NONE; - } - -#if DEBUG_FP - printf("____________Fragment program %u ________\n", program->Base.Id); - _mesa_print_program(&program->Base); -#endif -} - - - -/** - * Parse the vertex program string. If success, update the given - * vertex_program object with the new program. Else, leave the vertex_program - * object unchanged. - */ -void -_mesa_parse_arb_vertex_program(GLcontext *ctx, GLenum target, - const GLvoid *str, GLsizei len, - struct gl_vertex_program *program) -{ - struct gl_program prog; - struct asm_parser_state state; - - ASSERT(target == GL_VERTEX_PROGRAM_ARB); - - memset(&prog, 0, sizeof(prog)); - memset(&state, 0, sizeof(state)); - state.prog = &prog; - - if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len, - &state)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramString(bad program)"); - return; - } - - if (program->Base.String != NULL) - free(program->Base.String); - - /* Copy the relevant contents of the arb_program struct into the - * vertex_program struct. - */ - program->Base.String = prog.String; - program->Base.NumInstructions = prog.NumInstructions; - program->Base.NumTemporaries = prog.NumTemporaries; - program->Base.NumParameters = prog.NumParameters; - program->Base.NumAttributes = prog.NumAttributes; - program->Base.NumAddressRegs = prog.NumAddressRegs; - program->Base.NumNativeInstructions = prog.NumNativeInstructions; - program->Base.NumNativeTemporaries = prog.NumNativeTemporaries; - program->Base.NumNativeParameters = prog.NumNativeParameters; - program->Base.NumNativeAttributes = prog.NumNativeAttributes; - program->Base.NumNativeAddressRegs = prog.NumNativeAddressRegs; - program->Base.InputsRead = prog.InputsRead; - program->Base.OutputsWritten = prog.OutputsWritten; - program->IsPositionInvariant = (state.option.PositionInvariant) - ? GL_TRUE : GL_FALSE; - - if (program->Base.Instructions) - free(program->Base.Instructions); - program->Base.Instructions = prog.Instructions; - - if (program->Base.Parameters) - _mesa_free_parameter_list(program->Base.Parameters); - program->Base.Parameters = prog.Parameters; - -#if DEBUG_VP - printf("____________Vertex program %u __________\n", program->Base.Id); - _mesa_print_program(&program->Base); -#endif -} diff --git a/src/mesa/shader/arbprogparse.h b/src/mesa/shader/arbprogparse.h deleted file mode 100644 index 980d39fb9f..0000000000 --- a/src/mesa/shader/arbprogparse.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#ifndef ARBPROGPARSE_H -#define ARBPROGPARSE_H - -#include "main/mtypes.h" - -extern void -_mesa_parse_arb_vertex_program(GLcontext *ctx, GLenum target, - const GLvoid *str, GLsizei len, - struct gl_vertex_program *program); - -extern void -_mesa_parse_arb_fragment_program(GLcontext *ctx, GLenum target, - const GLvoid *str, GLsizei len, - struct gl_fragment_program *program); - -#endif diff --git a/src/mesa/shader/descrip.mms b/src/mesa/shader/descrip.mms deleted file mode 100644 index 59730020d0..0000000000 --- a/src/mesa/shader/descrip.mms +++ /dev/null @@ -1,93 +0,0 @@ -# Makefile for core library for VMS -# contributed by Jouk Jansen joukj@hrem.nano.tudelft.nl -# Last revision : 29 September 2008 -.first - define gl [---.include.gl] - define math [-.math] - define swrast [-.swrast] - define array_cache [-.array_cache] - define glapi [-.glapi] - define main [-.main] - define shader [-.shader] - -.include [---]mms-config. - -##### MACROS ##### - -VPATH = RCS - -INCDIR = [---.include],[-.main],[-.glapi],[.slang] -LIBDIR = [---.lib] -CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1,"__extension__=")/name=(as_is,short)/float=ieee/ieee=denorm - -SOURCES = \ - atifragshader.c \ - arbprogparse.c \ - arbprogram.c \ - nvfragparse.c \ - nvprogram.c \ - nvvertparse.c \ - program.c \ - programopt.c \ - prog_debug.c \ - prog_execute.c \ - prog_instruction.c \ - prog_parameter.c \ - prog_print.c \ - prog_cache.c \ - prog_statevars.c \ - shader_api.c prog_uniform.c - -OBJECTS = \ - atifragshader.obj,\ - arbprogparse.obj,\ - arbprogram.obj,\ - nvfragparse.obj,\ - nvprogram.obj,\ - nvvertparse.obj,\ - program.obj,\ - programopt.obj,\ - prog_debug.obj,\ - prog_execute.obj,\ - prog_instruction.obj,\ - prog_parameter.obj,\ - prog_print.obj,\ - prog_statevars.obj,\ - shader_api.obj,prog_uniform.obj,prog_cache.obj - -##### RULES ##### - -VERSION=Mesa V3.4 - -##### TARGETS ##### -all : - $(MMS)$(MMSQUALIFIERS) $(LIBDIR)$(GL_LIB) - set def [.slang] - $(MMS)$(MMSQUALIFIERS) - set def [-] - -# Make the library -$(LIBDIR)$(GL_LIB) : $(OBJECTS) - @ library $(LIBDIR)$(GL_LIB) $(OBJECTS) - -clean : - purge - delete *.obj;* - -atifragshader.obj : atifragshader.c -arbprogparse.obj : arbprogparse.c -arbprogram.obj : arbprogram.c -nvfragparse.obj : nvfragparse.c -nvprogram.obj : nvprogram.c -nvvertparse.obj : nvvertparse.c -program.obj : program.c -programopt. obj : programopt.c -prog_debug.obj : prog_debug.c -prog_execute.obj : prog_execute.c -prog_instruction.obj : prog_instruction.c -prog_parameter.obj : prog_parameter.c -prog_print.obj : prog_print.c -prog_statevars.obj : prog_statevars.c -shader_api.obj : shader_api.c -prog_uniform.obj : prog_uniform.c -prog_cache.obj : prog_cache.c diff --git a/src/mesa/shader/hash_table.c b/src/mesa/shader/hash_table.c deleted file mode 100644 index fa6ba2bfdf..0000000000 --- a/src/mesa/shader/hash_table.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright © 2008 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/** - * \file hash_table.c - * \brief Implementation of a generic, opaque hash table data type. - * - * \author Ian Romanick - */ - -#include "main/imports.h" -#include "main/simple_list.h" -#include "hash_table.h" - -struct node { - struct node *next; - struct node *prev; -}; - -struct hash_table { - hash_func_t hash; - hash_compare_func_t compare; - - unsigned num_buckets; - struct node buckets[1]; -}; - - -struct hash_node { - struct node link; - const void *key; - void *data; -}; - - -struct hash_table * -hash_table_ctor(unsigned num_buckets, hash_func_t hash, - hash_compare_func_t compare) -{ - struct hash_table *ht; - unsigned i; - - - if (num_buckets < 16) { - num_buckets = 16; - } - - ht = malloc(sizeof(*ht) + ((num_buckets - 1) - * sizeof(ht->buckets[0]))); - if (ht != NULL) { - ht->hash = hash; - ht->compare = compare; - ht->num_buckets = num_buckets; - - for (i = 0; i < num_buckets; i++) { - make_empty_list(& ht->buckets[i]); - } - } - - return ht; -} - - -void -hash_table_dtor(struct hash_table *ht) -{ - hash_table_clear(ht); - free(ht); -} - - -void -hash_table_clear(struct hash_table *ht) -{ - struct node *node; - struct node *temp; - unsigned i; - - - for (i = 0; i < ht->num_buckets; i++) { - foreach_s(node, temp, & ht->buckets[i]) { - remove_from_list(node); - free(node); - } - - assert(is_empty_list(& ht->buckets[i])); - } -} - - -void * -hash_table_find(struct hash_table *ht, const void *key) -{ - const unsigned hash_value = (*ht->hash)(key); - const unsigned bucket = hash_value % ht->num_buckets; - struct node *node; - - foreach(node, & ht->buckets[bucket]) { - struct hash_node *hn = (struct hash_node *) node; - - if ((*ht->compare)(hn->key, key) == 0) { - return hn->data; - } - } - - return NULL; -} - - -void -hash_table_insert(struct hash_table *ht, void *data, const void *key) -{ - const unsigned hash_value = (*ht->hash)(key); - const unsigned bucket = hash_value % ht->num_buckets; - struct hash_node *node; - - node = calloc(1, sizeof(*node)); - - node->data = data; - node->key = key; - - insert_at_head(& ht->buckets[bucket], & node->link); -} - - -unsigned -hash_table_string_hash(const void *key) -{ - const char *str = (const char *) key; - unsigned hash = 5381; - - - while (*str != '\0') { - hash = (hash * 33) + *str; - str++; - } - - return hash; -} diff --git a/src/mesa/shader/hash_table.h b/src/mesa/shader/hash_table.h deleted file mode 100644 index 7b302f5dbe..0000000000 --- a/src/mesa/shader/hash_table.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright © 2008 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/** - * \file hash_table.h - * \brief Implementation of a generic, opaque hash table data type. - * - * \author Ian Romanick - */ - -#ifndef HASH_TABLE_H -#define HASH_TABLE_H - -#include - -struct hash_table; - -typedef unsigned (*hash_func_t)(const void *key); -typedef int (*hash_compare_func_t)(const void *key1, const void *key2); - -/** - * Hash table constructor - * - * Creates a hash table with the specified number of buckets. The supplied - * \c hash and \c compare routines are used when adding elements to the table - * and when searching for elements in the table. - * - * \param num_buckets Number of buckets (bins) in the hash table. - * \param hash Function used to compute hash value of input keys. - * \param compare Function used to compare keys. - */ -extern struct hash_table *hash_table_ctor(unsigned num_buckets, - hash_func_t hash, hash_compare_func_t compare); - - -/** - * Release all memory associated with a hash table - * - * \warning - * This function cannot release memory occupied either by keys or data. - */ -extern void hash_table_dtor(struct hash_table *ht); - - -/** - * Flush all entries from a hash table - * - * \param ht Table to be cleared of its entries. - */ -extern void hash_table_clear(struct hash_table *ht); - - -/** - * Search a hash table for a specific element - * - * \param ht Table to be searched - * \param key Key of the desired element - * - * \return - * The \c data value supplied to \c hash_table_insert when the element with - * the matching key was added. If no matching key exists in the table, - * \c NULL is returned. - */ -extern void *hash_table_find(struct hash_table *ht, const void *key); - - -/** - * Add an element to a hash table - */ -extern void hash_table_insert(struct hash_table *ht, void *data, - const void *key); - - -/** - * Compute hash value of a string - * - * Computes the hash value of a string using the DJB2 algorithm developed by - * Professor Daniel J. Bernstein. It was published on comp.lang.c once upon - * a time. I was unable to find the original posting in the archives. - * - * \param key Pointer to a NUL terminated string to be hashed. - * - * \sa hash_table_string_compare - */ -extern unsigned hash_table_string_hash(const void *key); - - -/** - * Compare two strings used as keys - * - * This is just a macro wrapper around \c strcmp. - * - * \sa hash_table_string_hash - */ -#define hash_table_string_compare ((hash_compare_func_t) strcmp) - -#endif /* HASH_TABLE_H */ diff --git a/src/mesa/shader/lex.yy.c b/src/mesa/shader/lex.yy.c deleted file mode 100644 index 4c5c644a6e..0000000000 --- a/src/mesa/shader/lex.yy.c +++ /dev/null @@ -1,3655 +0,0 @@ - -#line 3 "lex.yy.c" - -#define YY_INT_ALIGNED short int - -/* A lexical scanner generated by flex */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 35 -#if YY_FLEX_SUBMINOR_VERSION > 0 -#define FLEX_BETA -#endif - -/* First, we deal with platform-specific or compiler-specific issues. */ - -/* begin standard C headers. */ -#include -#include -#include -#include - -/* end standard C headers. */ - -/* flex integer type definitions */ - -#ifndef FLEXINT_H -#define FLEXINT_H - -/* C99 systems have . Non-C99 systems may or may not. */ - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - -/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, - * if you want the limit (max/min) macros for int types. - */ -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS 1 -#endif - -#include -typedef int8_t flex_int8_t; -typedef uint8_t flex_uint8_t; -typedef int16_t flex_int16_t; -typedef uint16_t flex_uint16_t; -typedef int32_t flex_int32_t; -typedef uint32_t flex_uint32_t; -#else -typedef signed char flex_int8_t; -typedef short int flex_int16_t; -typedef int flex_int32_t; -typedef unsigned char flex_uint8_t; -typedef unsigned short int flex_uint16_t; -typedef unsigned int flex_uint32_t; -#endif /* ! C99 */ - -/* Limits of integral types. */ -#ifndef INT8_MIN -#define INT8_MIN (-128) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-32767-1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#ifndef INT8_MAX -#define INT8_MAX (127) -#endif -#ifndef INT16_MAX -#define INT16_MAX (32767) -#endif -#ifndef INT32_MAX -#define INT32_MAX (2147483647) -#endif -#ifndef UINT8_MAX -#define UINT8_MAX (255U) -#endif -#ifndef UINT16_MAX -#define UINT16_MAX (65535U) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - -#endif /* ! FLEXINT_H */ - -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -/* C99 requires __STDC__ to be defined as 1. */ -#if defined (__STDC__) - -#define YY_USE_CONST - -#endif /* defined (__STDC__) */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - -/* Returned upon end-of-file. */ -#define YY_NULL 0 - -/* Promotes a possibly negative, possibly signed char to an unsigned - * integer for use as an array index. If the signed char is negative, - * we want to instead treat it as an 8-bit unsigned char, hence the - * double cast. - */ -#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) - -/* An opaque pointer. */ -#ifndef YY_TYPEDEF_YY_SCANNER_T -#define YY_TYPEDEF_YY_SCANNER_T -typedef void* yyscan_t; -#endif - -/* For convenience, these vars (plus the bison vars far below) - are macros in the reentrant scanner. */ -#define yyin yyg->yyin_r -#define yyout yyg->yyout_r -#define yyextra yyg->yyextra_r -#define yyleng yyg->yyleng_r -#define yytext yyg->yytext_r -#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) -#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) -#define yy_flex_debug yyg->yy_flex_debug_r - -/* Enter a start condition. This macro really ought to take a parameter, - * but we do it the disgusting crufty way forced on us by the ()-less - * definition of BEGIN. - */ -#define BEGIN yyg->yy_start = 1 + 2 * - -/* Translate the current start state into a value that can be later handed - * to BEGIN to return to the state. The YYSTATE alias is for lex - * compatibility. - */ -#define YY_START ((yyg->yy_start - 1) / 2) -#define YYSTATE YY_START - -/* Action number for EOF rule of a given start state. */ -#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) - -/* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE yyrestart(yyin ,yyscanner ) - -#define YY_END_OF_BUFFER_CHAR 0 - -/* Size of default input buffer. */ -#ifndef YY_BUF_SIZE -#define YY_BUF_SIZE 16384 -#endif - -/* The state buf must be large enough to hold one state per character in the main buffer. - */ -#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) - -#ifndef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -typedef struct yy_buffer_state *YY_BUFFER_STATE; -#endif - -#define EOB_ACT_CONTINUE_SCAN 0 -#define EOB_ACT_END_OF_FILE 1 -#define EOB_ACT_LAST_MATCH 2 - - #define YY_LESS_LINENO(n) - -/* Return all but the first "n" matched characters back to the input stream. */ -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - *yy_cp = yyg->yy_hold_char; \ - YY_RESTORE_YY_MORE_OFFSET \ - yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ - } \ - while ( 0 ) - -#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) - -#ifndef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -typedef size_t yy_size_t; -#endif - -#ifndef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - int yy_bs_lineno; /**< The line count. */ - int yy_bs_column; /**< The column count. */ - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; - -#define YY_BUFFER_NEW 0 -#define YY_BUFFER_NORMAL 1 - /* When an EOF's been seen but there's still some text to process - * then we mark the buffer as YY_EOF_PENDING, to indicate that we - * shouldn't try reading from the input source any more. We might - * still have a bunch of tokens to match, though, because of - * possible backing-up. - * - * When we actually see the EOF, we change the status to "new" - * (via yyrestart()), so that the user can continue scanning by - * just pointing yyin at a new input file. - */ -#define YY_BUFFER_EOF_PENDING 2 - - }; -#endif /* !YY_STRUCT_YY_BUFFER_STATE */ - -/* We provide macros for accessing buffer states in case in the - * future we want to put the buffer states in a more general - * "scanner state". - * - * Returns the top of the stack, or NULL. - */ -#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ - ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ - : NULL) - -/* Same as previous macro, but useful when we know that the buffer stack is not - * NULL or when we need an lvalue. For internal use only. - */ -#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] - -void yyrestart (FILE *input_file ,yyscan_t yyscanner ); -void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); -void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -void yypop_buffer_state (yyscan_t yyscanner ); - -static void yyensure_buffer_stack (yyscan_t yyscanner ); -static void yy_load_buffer_state (yyscan_t yyscanner ); -static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); - -#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) - -YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); - -void *yyalloc (yy_size_t ,yyscan_t yyscanner ); -void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); -void yyfree (void * ,yyscan_t yyscanner ); - -#define yy_new_buffer yy_create_buffer - -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! YY_CURRENT_BUFFER ){ \ - yyensure_buffer_stack (yyscanner); \ - YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ - } - -#define yy_set_bol(at_bol) \ - { \ - if ( ! YY_CURRENT_BUFFER ){\ - yyensure_buffer_stack (yyscanner); \ - YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ - } - -#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) - -/* Begin user sect3 */ - -#define yywrap(n) 1 -#define YY_SKIP_YYWRAP - -typedef unsigned char YY_CHAR; - -typedef int yy_state_type; - -#define yytext_ptr yytext_r - -static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); -static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); -static int yy_get_next_buffer (yyscan_t yyscanner ); -static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); - -/* Done after the current pattern has been matched and before the - * corresponding action - sets up yytext. - */ -#define YY_DO_BEFORE_ACTION \ - yyg->yytext_ptr = yy_bp; \ - yyleng = (size_t) (yy_cp - yy_bp); \ - yyg->yy_hold_char = *yy_cp; \ - *yy_cp = '\0'; \ - yyg->yy_c_buf_p = yy_cp; - -#define YY_NUM_RULES 170 -#define YY_END_OF_BUFFER 171 -/* This struct is not used in this scanner, - but its presence is necessary. */ -struct yy_trans_info - { - flex_int32_t yy_verify; - flex_int32_t yy_nxt; - }; -static yyconst flex_int16_t yy_accept[850] = - { 0, - 0, 0, 171, 169, 167, 166, 169, 169, 139, 165, - 141, 141, 141, 141, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 167, 0, 0, 168, 139, - 0, 140, 142, 162, 162, 0, 0, 0, 0, 162, - 0, 0, 0, 0, 0, 0, 0, 119, 163, 120, - 121, 153, 153, 153, 153, 0, 141, 0, 127, 128, - 129, 139, 139, 139, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, - - 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 139, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 161, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 160, 160, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 159, 159, 159, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 150, 150, 150, 151, 151, 152, 143, - 142, 143, 0, 144, 11, 12, 139, 13, 139, 139, - 14, 15, 139, 16, 17, 18, 19, 20, 21, 6, - - 22, 23, 24, 25, 26, 28, 27, 29, 30, 31, - 32, 33, 34, 35, 139, 139, 139, 139, 139, 40, - 41, 139, 42, 43, 44, 45, 46, 47, 48, 139, - 49, 50, 51, 52, 53, 54, 55, 139, 56, 57, - 58, 59, 139, 139, 64, 65, 139, 139, 139, 139, - 139, 139, 0, 0, 0, 0, 142, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 80, 81, 83, - 0, 158, 0, 0, 0, 0, 0, 0, 97, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, - 156, 156, 109, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 147, 147, 148, 149, 0, 145, 11, - 11, 139, 12, 12, 12, 139, 139, 139, 139, 139, - 15, 15, 139, 130, 16, 16, 139, 17, 17, 139, - 18, 18, 139, 19, 19, 139, 20, 20, 139, 21, - 21, 139, 22, 22, 139, 24, 24, 139, 25, 25, - 139, 28, 28, 139, 27, 27, 139, 30, 30, 139, - 31, 31, 139, 32, 32, 139, 33, 33, 139, 34, - 34, 139, 35, 35, 139, 139, 139, 139, 36, 139, - 38, 139, 40, 40, 139, 41, 41, 139, 131, 42, - 42, 139, 43, 43, 139, 139, 45, 45, 139, 46, - - 46, 139, 47, 47, 139, 48, 48, 139, 139, 49, - 49, 139, 50, 50, 139, 51, 51, 139, 52, 52, - 139, 53, 53, 139, 54, 54, 139, 139, 10, 56, - 139, 57, 139, 58, 139, 59, 139, 60, 139, 62, - 139, 64, 64, 139, 139, 139, 139, 139, 139, 139, - 139, 0, 164, 0, 0, 0, 73, 74, 0, 0, - 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 155, 0, 0, 0, 113, 0, - 115, 0, 0, 0, 0, 0, 0, 154, 146, 139, - - 139, 139, 4, 139, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 139, 9, 37, 39, 139, - 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, - 60, 139, 61, 62, 139, 63, 139, 139, 139, 139, - 139, 69, 139, 139, 0, 0, 0, 0, 0, 75, - 76, 0, 0, 0, 0, 84, 0, 0, 88, 91, - 0, 0, 0, 0, 0, 0, 0, 102, 103, 0, - 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 139, 139, 139, 139, 139, 139, - 5, 139, 139, 139, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, - 7, 8, 139, 139, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 61, 139, 139, 63, 139, 139, - 139, 139, 139, 70, 139, 66, 0, 0, 0, 0, - 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 94, 0, 98, 99, 0, 101, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 117, 118, 0, 0, - - 125, 11, 3, 12, 135, 136, 139, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 24, 25, 28, 27, - 30, 31, 32, 33, 34, 35, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 139, 139, 139, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, 59, 139, - 139, 139, 139, 64, 65, 139, 68, 126, 0, 0, - 71, 0, 77, 0, 0, 0, 86, 0, 0, 0, - 0, 0, 0, 100, 0, 0, 106, 93, 0, 0, - 0, 0, 0, 0, 122, 0, 139, 132, 133, 139, - 60, 139, 62, 139, 67, 0, 0, 0, 0, 79, - - 82, 87, 0, 0, 92, 0, 0, 0, 105, 0, - 0, 0, 0, 114, 116, 0, 139, 139, 61, 63, - 2, 1, 0, 78, 0, 90, 0, 96, 104, 0, - 0, 111, 112, 123, 139, 134, 0, 89, 0, 107, - 110, 139, 72, 95, 139, 139, 137, 138, 0 - } ; - -static yyconst flex_int32_t yy_ec[256] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, - 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 5, 1, 6, 7, 1, 1, 1, 1, - 1, 1, 8, 1, 8, 9, 1, 10, 11, 12, - 13, 14, 15, 15, 15, 15, 15, 1, 1, 1, - 1, 1, 1, 1, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 7, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 1, 1, 1, 1, 41, 1, 42, 43, 44, 45, - - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 - } ; - -static yyconst flex_int32_t yy_meta[68] = - { 0, - 1, 1, 1, 1, 1, 1, 2, 1, 3, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2 - } ; - -static yyconst flex_int16_t yy_base[853] = - { 0, - 0, 0, 1299, 1300, 66, 1300, 1293, 1294, 0, 69, - 85, 128, 140, 152, 151, 58, 56, 63, 76, 1272, - 158, 160, 39, 163, 173, 189, 52, 1265, 76, 1235, - 1234, 1246, 1230, 1244, 1243, 105, 1272, 1284, 1300, 0, - 225, 1300, 218, 160, 157, 20, 123, 66, 119, 192, - 1244, 1230, 54, 162, 1228, 1240, 194, 1300, 200, 195, - 98, 227, 196, 231, 235, 293, 305, 316, 1300, 1300, - 1300, 1249, 1262, 1256, 223, 1245, 1248, 1244, 1259, 107, - 298, 1241, 1255, 246, 1241, 1254, 1245, 1258, 1235, 1246, - 1237, 182, 1238, 1229, 1238, 1229, 1228, 1229, 144, 1223, - - 1229, 1240, 1231, 1225, 1222, 1223, 1227, 289, 1236, 1223, - 302, 1230, 1217, 1231, 1207, 65, 315, 276, 1227, 1226, - 1202, 1187, 1182, 1199, 1175, 1180, 1206, 279, 1195, 293, - 1190, 342, 299, 1192, 1173, 317, 1183, 1179, 1174, 207, - 1180, 1166, 1182, 1179, 1170, 320, 324, 1172, 1161, 1175, - 1178, 1160, 1175, 1162, 1159, 1166, 284, 1174, 227, 288, - 327, 342, 345, 1151, 1168, 1169, 1162, 1144, 318, 1145, - 1167, 1158, 330, 341, 345, 349, 353, 357, 361, 1300, - 419, 430, 436, 442, 440, 441, 1191, 0, 1190, 1173, - 1163, 443, 1183, 444, 451, 468, 470, 472, 471, 0, - - 496, 0, 497, 498, 0, 499, 500, 0, 524, 525, - 526, 536, 537, 553, 1178, 1171, 1184, 354, 356, 561, - 563, 1165, 564, 565, 1157, 580, 590, 591, 592, 1178, - 593, 617, 618, 619, 629, 630, 1155, 1165, 330, 362, - 419, 483, 445, 364, 646, 1153, 1145, 1144, 1129, 1129, - 1128, 1127, 1170, 1142, 1130, 662, 669, 643, 1134, 487, - 1131, 1125, 1125, 1119, 1132, 1132, 1117, 1300, 1300, 1132, - 1120, 646, 1127, 135, 1124, 1130, 561, 1125, 1300, 1116, - 1123, 1122, 1125, 1111, 1110, 1114, 1109, 448, 1114, 650, - 653, 665, 1300, 1106, 1104, 1104, 1112, 1113, 1095, 670, - - 1100, 1106, 486, 579, 655, 661, 668, 726, 732, 1112, - 682, 1119, 1110, 688, 730, 1117, 1116, 1109, 1123, 1113, - 1104, 712, 1111, 0, 1102, 731, 1109, 1100, 733, 1107, - 1098, 734, 1105, 1096, 736, 1103, 1094, 737, 1101, 1092, - 738, 1099, 1090, 739, 1097, 1088, 740, 1095, 1086, 741, - 1093, 1084, 742, 1091, 1082, 743, 1089, 1080, 744, 1087, - 1078, 745, 1085, 1076, 746, 1083, 1074, 747, 1081, 1072, - 748, 1079, 1070, 749, 1077, 1080, 1073, 1080, 0, 1073, - 0, 1088, 1063, 750, 1070, 1061, 751, 1068, 0, 1059, - 752, 1066, 1057, 755, 1064, 1063, 1054, 758, 1061, 1052, - - 776, 1059, 1050, 777, 1057, 1048, 779, 1055, 1058, 1045, - 780, 1052, 1043, 782, 1050, 1041, 783, 1048, 1039, 784, - 1046, 1037, 785, 1044, 1035, 786, 1042, 1041, 0, 1032, - 1039, 1030, 1037, 1028, 1035, 1026, 1033, 787, 1032, 788, - 1047, 1022, 789, 1029, 1028, 1006, 1000, 1005, 1011, 994, - 1009, 424, 1300, 1008, 998, 1002, 1300, 1300, 992, 1001, - 987, 1004, 987, 990, 984, 1300, 985, 984, 981, 988, - 981, 989, 985, 995, 992, 974, 980, 987, 971, 970, - 988, 970, 982, 981, 1300, 980, 970, 974, 1300, 961, - 1300, 966, 966, 974, 957, 958, 968, 1300, 1300, 1000, - - 982, 998, 0, 798, 996, 996, 995, 994, 993, 992, - 991, 990, 989, 988, 987, 986, 985, 984, 983, 982, - 981, 980, 979, 978, 965, 958, 0, 0, 0, 975, - 974, 973, 972, 971, 970, 969, 968, 967, 945, 965, - 964, 963, 962, 961, 960, 959, 958, 957, 956, 955, - 929, 936, 793, 927, 934, 794, 950, 949, 918, 921, - 901, 0, 902, 895, 902, 901, 902, 894, 912, 1300, - 1300, 894, 892, 902, 895, 1300, 890, 907, 516, 1300, - 898, 882, 883, 892, 883, 882, 882, 1300, 881, 890, - 880, 896, 893, 1300, 892, 890, 879, 880, 876, 868, - - 875, 870, 871, 866, 892, 892, 890, 904, 903, 898, - 0, 886, 885, 884, 883, 882, 881, 880, 879, 878, - 877, 876, 875, 874, 873, 872, 871, 870, 869, 868, - 0, 0, 867, 866, 865, 864, 863, 862, 861, 860, - 859, 804, 858, 857, 856, 855, 854, 853, 852, 851, - 850, 849, 848, 865, 839, 846, 862, 836, 843, 841, - 840, 818, 818, 0, 825, 0, 859, 858, 807, 825, - 1300, 820, 815, 808, 804, 816, 806, 804, 800, 816, - 807, 806, 1300, 1300, 809, 1300, 804, 797, 786, 797, - 789, 793, 806, 801, 804, 786, 1300, 1300, 798, 787, - - 1300, 0, 0, 0, 0, 0, 826, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 814, 813, 802, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 785, - 798, 779, 792, 0, 0, 656, 0, 0, 706, 702, - 1300, 649, 1300, 648, 648, 654, 1300, 637, 645, 610, - 612, 608, 608, 1300, 572, 583, 1300, 1300, 577, 573, - 560, 557, 542, 555, 1300, 539, 573, 0, 0, 572, - 0, 555, 0, 546, 0, 562, 551, 495, 479, 1300, - - 1300, 1300, 481, 481, 1300, 480, 443, 31, 1300, 141, - 166, 171, 186, 1300, 1300, 211, 236, 276, 0, 0, - 1300, 1300, 290, 1300, 325, 1300, 346, 1300, 1300, 343, - 341, 1300, 1300, 1300, 365, 0, 380, 1300, 371, 1300, - 1300, 486, 1300, 1300, 451, 458, 0, 0, 1300, 836, - 503, 839 - } ; - -static yyconst flex_int16_t yy_def[853] = - { 0, - 849, 1, 849, 849, 849, 849, 849, 850, 851, 849, - 849, 849, 849, 849, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 849, 849, 850, 849, 851, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 852, 849, 849, 849, 849, - 849, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - - 849, 849, 849, 849, 849, 849, 849, 849, 849, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 851, - - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - - 849, 849, 849, 849, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - - 849, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 851, 851, 851, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 851, 851, 851, 851, - 851, 851, 851, 851, 851, 849, 849, 849, 849, 849, - - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 851, 851, 851, 851, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 851, 851, 849, 849, 849, 849, - 849, 851, 849, 849, 851, 851, 851, 851, 0, 849, - 849, 849 - } ; - -static yyconst flex_int16_t yy_nxt[1368] = - { 0, - 4, 5, 6, 5, 7, 8, 9, 4, 10, 11, - 12, 13, 14, 11, 11, 15, 9, 16, 17, 18, - 19, 9, 9, 9, 20, 21, 22, 9, 23, 24, - 9, 25, 26, 27, 28, 9, 9, 29, 9, 9, - 9, 9, 9, 9, 9, 9, 30, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 31, 9, 32, 33, - 34, 9, 35, 9, 9, 9, 9, 36, 96, 36, - 41, 116, 137, 97, 80, 138, 829, 42, 43, 43, - 43, 43, 43, 43, 77, 81, 78, 119, 82, 117, - 83, 238, 79, 66, 67, 67, 67, 67, 67, 67, - - 84, 85, 239, 150, 68, 120, 36, 86, 36, 151, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 141, - 142, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 68, 143, 62, 63, 64, 65, 66, 67, 67, 67, - 67, 67, 67, 170, 194, 195, 69, 68, 66, 67, - 67, 67, 67, 67, 67, 218, 171, 219, 70, 68, - 66, 67, 67, 67, 67, 67, 67, 72, 139, 73, - 71, 68, 140, 68, 144, 92, 74, 145, 98, 88, - 467, 89, 75, 93, 76, 68, 90, 99, 94, 91, - 101, 100, 102, 103, 95, 468, 830, 68, 136, 133, - - 210, 133, 133, 152, 133, 104, 105, 133, 106, 107, - 108, 109, 110, 134, 111, 133, 112, 153, 133, 211, - 135, 831, 113, 114, 154, 115, 41, 43, 43, 43, - 43, 43, 43, 146, 147, 157, 832, 132, 165, 133, - 166, 161, 162, 167, 168, 833, 158, 163, 188, 159, - 133, 169, 160, 265, 189, 164, 834, 201, 133, 174, - 173, 175, 176, 132, 835, 266, 128, 129, 46, 47, - 48, 49, 172, 51, 52, 202, 285, 53, 54, 55, - 56, 57, 58, 130, 60, 61, 286, 243, 131, 244, - 173, 173, 173, 173, 177, 173, 173, 178, 179, 173, - - 173, 173, 181, 181, 181, 181, 181, 181, 228, 836, - 196, 197, 182, 66, 67, 67, 67, 67, 67, 67, - 198, 232, 229, 183, 68, 184, 184, 184, 184, 184, - 184, 240, 134, 241, 255, 233, 282, 287, 182, 135, - 258, 258, 283, 288, 242, 837, 258, 430, 164, 256, - 68, 257, 257, 257, 257, 257, 257, 258, 258, 258, - 261, 258, 258, 298, 258, 272, 258, 258, 258, 258, - 431, 258, 381, 299, 258, 258, 379, 838, 258, 432, - 440, 289, 258, 290, 258, 258, 291, 292, 380, 258, - 382, 839, 258, 303, 303, 303, 303, 840, 441, 841, - - 258, 842, 433, 258, 303, 303, 303, 303, 304, 303, - 303, 305, 306, 303, 303, 303, 303, 303, 303, 303, - 307, 303, 303, 303, 303, 303, 303, 303, 43, 43, - 43, 43, 43, 43, 843, 844, 434, 308, 132, 309, - 309, 309, 309, 309, 309, 184, 184, 184, 184, 184, - 184, 184, 184, 184, 184, 184, 184, 310, 313, 435, - 321, 325, 311, 314, 132, 322, 326, 438, 328, 847, - 565, 311, 315, 329, 322, 326, 848, 311, 314, 439, - 312, 316, 329, 323, 327, 331, 566, 334, 340, 337, - 332, 330, 335, 341, 338, 482, 845, 846, 483, 332, - - 436, 335, 341, 338, 40, 332, 828, 335, 333, 338, - 336, 342, 339, 343, 346, 349, 352, 355, 344, 347, - 350, 353, 356, 437, 827, 826, 825, 344, 347, 350, - 353, 356, 455, 824, 347, 350, 345, 348, 351, 354, - 357, 358, 361, 364, 823, 456, 359, 362, 365, 498, - 498, 498, 498, 367, 370, 359, 362, 365, 368, 371, - 822, 359, 362, 365, 360, 363, 366, 368, 371, 678, - 373, 821, 679, 368, 371, 374, 369, 372, 383, 820, - 386, 390, 393, 384, 374, 387, 391, 394, 819, 818, - 374, 817, 384, 375, 387, 391, 394, 397, 816, 815, - - 814, 385, 398, 388, 392, 395, 471, 400, 403, 406, - 410, 398, 401, 404, 407, 411, 813, 398, 812, 472, - 399, 401, 404, 407, 411, 811, 810, 401, 404, 407, - 402, 405, 408, 412, 413, 416, 419, 809, 808, 414, - 417, 420, 498, 498, 498, 498, 422, 425, 414, 417, - 420, 423, 426, 807, 414, 417, 420, 415, 418, 421, - 423, 426, 806, 442, 805, 804, 423, 426, 443, 424, - 427, 257, 257, 257, 257, 257, 257, 443, 257, 257, - 257, 257, 257, 257, 453, 453, 444, 453, 453, 803, - 453, 453, 453, 453, 453, 453, 802, 453, 801, 310, - - 453, 453, 800, 799, 453, 313, 485, 453, 453, 798, - 797, 453, 453, 492, 796, 493, 795, 494, 499, 498, - 498, 498, 312, 453, 498, 498, 498, 498, 316, 321, - 495, 498, 498, 498, 498, 309, 309, 309, 309, 309, - 309, 309, 309, 309, 309, 309, 309, 313, 325, 501, - 328, 331, 323, 334, 337, 340, 343, 346, 349, 352, - 355, 358, 361, 364, 367, 370, 373, 383, 386, 390, - 316, 327, 393, 330, 333, 397, 336, 339, 342, 345, - 348, 351, 354, 357, 360, 363, 366, 369, 372, 375, - 385, 388, 392, 400, 403, 395, 406, 410, 399, 413, - - 416, 419, 422, 425, 551, 554, 442, 794, 608, 609, - 655, 658, 793, 792, 736, 737, 402, 405, 791, 408, - 412, 790, 415, 418, 421, 424, 427, 552, 555, 444, - 610, 789, 788, 656, 659, 738, 38, 38, 38, 180, - 180, 787, 786, 785, 784, 783, 782, 781, 780, 779, - 778, 777, 776, 775, 774, 773, 772, 771, 770, 769, - 768, 767, 766, 765, 764, 763, 762, 761, 760, 759, - 758, 757, 756, 755, 754, 753, 659, 752, 751, 656, - 750, 749, 748, 747, 746, 745, 744, 743, 742, 741, - 740, 739, 735, 734, 733, 732, 731, 730, 729, 728, - - 727, 726, 725, 724, 723, 722, 721, 720, 719, 718, - 717, 716, 715, 714, 713, 712, 711, 710, 709, 708, - 707, 706, 705, 704, 703, 702, 701, 700, 699, 698, - 697, 696, 695, 694, 693, 692, 691, 690, 689, 688, - 687, 686, 685, 684, 683, 682, 681, 680, 677, 676, - 675, 674, 673, 672, 671, 670, 669, 668, 667, 666, - 665, 664, 663, 662, 661, 660, 657, 555, 654, 552, - 653, 652, 651, 650, 649, 648, 647, 646, 645, 644, - 643, 642, 641, 640, 639, 638, 637, 636, 635, 634, - 633, 632, 631, 630, 629, 628, 627, 626, 625, 624, - - 623, 622, 621, 620, 619, 618, 617, 616, 615, 614, - 613, 612, 611, 607, 606, 605, 604, 603, 602, 601, - 600, 599, 598, 597, 596, 595, 594, 593, 592, 591, - 590, 589, 588, 587, 586, 585, 584, 583, 582, 581, - 580, 579, 578, 577, 576, 575, 574, 573, 572, 571, - 570, 569, 568, 567, 564, 563, 562, 561, 560, 559, - 558, 557, 444, 556, 553, 550, 437, 549, 435, 548, - 433, 547, 431, 546, 545, 427, 544, 424, 543, 421, - 542, 418, 541, 415, 540, 412, 539, 538, 408, 537, - 405, 536, 402, 535, 399, 534, 533, 395, 532, 392, - - 531, 388, 530, 385, 529, 528, 527, 526, 525, 524, - 375, 523, 372, 522, 369, 521, 366, 520, 363, 519, - 360, 518, 357, 517, 354, 516, 351, 515, 348, 514, - 345, 513, 342, 512, 339, 511, 336, 510, 333, 509, - 330, 508, 327, 507, 323, 506, 505, 504, 503, 502, - 316, 500, 312, 497, 496, 491, 490, 489, 488, 487, - 486, 484, 481, 480, 479, 478, 477, 476, 475, 474, - 473, 470, 469, 466, 465, 464, 463, 462, 461, 460, - 459, 458, 457, 454, 289, 261, 452, 451, 450, 449, - 448, 447, 446, 445, 429, 428, 409, 396, 389, 378, - - 377, 376, 324, 320, 319, 318, 317, 302, 301, 300, - 297, 296, 295, 294, 293, 284, 281, 280, 279, 278, - 277, 276, 275, 274, 273, 271, 270, 269, 268, 267, - 264, 263, 262, 260, 259, 172, 254, 253, 252, 251, - 250, 249, 248, 247, 246, 245, 237, 236, 235, 234, - 231, 230, 227, 226, 225, 224, 223, 222, 221, 220, - 217, 216, 215, 214, 213, 212, 209, 208, 207, 206, - 205, 204, 203, 200, 199, 193, 192, 191, 190, 187, - 186, 185, 156, 155, 149, 148, 39, 127, 126, 125, - 124, 123, 122, 121, 118, 87, 39, 37, 849, 3, - - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849 - } ; - -static yyconst flex_int16_t yy_chk[1368] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 5, 23, 5, - 10, 27, 46, 23, 17, 46, 808, 10, 10, 10, - 10, 10, 10, 10, 16, 17, 16, 29, 17, 27, - 18, 116, 16, 11, 11, 11, 11, 11, 11, 11, - - 18, 19, 116, 53, 11, 29, 36, 19, 36, 53, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 48, - 48, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 11, 48, 10, 10, 10, 10, 12, 12, 12, 12, - 12, 12, 12, 61, 80, 80, 12, 12, 13, 13, - 13, 13, 13, 13, 13, 99, 61, 99, 13, 13, - 14, 14, 14, 14, 14, 14, 14, 15, 47, 15, - 14, 14, 47, 12, 49, 22, 15, 49, 24, 21, - 274, 21, 15, 22, 15, 13, 21, 24, 22, 21, - 25, 24, 25, 25, 22, 274, 810, 14, 45, 45, - - 92, 44, 44, 54, 45, 25, 26, 44, 26, 26, - 26, 26, 26, 44, 26, 45, 26, 54, 44, 92, - 44, 811, 26, 26, 54, 26, 41, 43, 43, 43, - 43, 43, 43, 50, 50, 57, 812, 43, 60, 50, - 60, 59, 59, 60, 60, 813, 57, 59, 75, 57, - 50, 60, 57, 140, 75, 59, 816, 84, 59, 63, - 63, 63, 63, 43, 817, 140, 41, 41, 41, 41, - 41, 41, 62, 41, 41, 84, 159, 41, 41, 41, - 41, 41, 41, 41, 41, 41, 159, 118, 41, 118, - 62, 62, 62, 62, 64, 64, 64, 64, 65, 65, - - 65, 65, 66, 66, 66, 66, 66, 66, 108, 818, - 81, 81, 66, 67, 67, 67, 67, 67, 67, 67, - 81, 111, 108, 68, 67, 68, 68, 68, 68, 68, - 68, 117, 128, 117, 130, 111, 157, 160, 66, 128, - 133, 133, 157, 160, 117, 823, 133, 239, 130, 132, - 67, 132, 132, 132, 132, 132, 132, 133, 136, 136, - 136, 146, 146, 169, 136, 147, 147, 146, 161, 161, - 239, 147, 219, 169, 161, 136, 218, 825, 146, 240, - 244, 161, 147, 162, 162, 161, 163, 163, 218, 162, - 219, 827, 163, 173, 173, 173, 173, 830, 244, 831, - - 162, 835, 240, 163, 174, 174, 174, 174, 175, 175, - 175, 175, 176, 176, 176, 176, 177, 177, 177, 177, - 178, 178, 178, 178, 179, 179, 179, 179, 181, 181, - 181, 181, 181, 181, 837, 839, 241, 182, 181, 182, - 182, 182, 182, 182, 182, 183, 183, 183, 183, 183, - 183, 184, 184, 184, 184, 184, 184, 185, 186, 241, - 192, 194, 185, 186, 181, 192, 194, 243, 195, 845, - 452, 185, 186, 195, 192, 194, 846, 185, 186, 243, - 185, 186, 195, 192, 194, 196, 452, 197, 199, 198, - 196, 195, 197, 199, 198, 288, 842, 842, 288, 196, - - 242, 197, 199, 198, 851, 196, 807, 197, 196, 198, - 197, 199, 198, 201, 203, 204, 206, 207, 201, 203, - 204, 206, 207, 242, 806, 804, 803, 201, 203, 204, - 206, 207, 260, 799, 203, 204, 201, 203, 204, 206, - 207, 209, 210, 211, 798, 260, 209, 210, 211, 303, - 303, 303, 303, 212, 213, 209, 210, 211, 212, 213, - 797, 209, 210, 211, 209, 210, 211, 212, 213, 579, - 214, 796, 579, 212, 213, 214, 212, 213, 220, 794, - 221, 223, 224, 220, 214, 221, 223, 224, 792, 790, - 214, 787, 220, 214, 221, 223, 224, 226, 786, 784, - - 783, 220, 226, 221, 223, 224, 277, 227, 228, 229, - 231, 226, 227, 228, 229, 231, 782, 226, 781, 277, - 226, 227, 228, 229, 231, 780, 779, 227, 228, 229, - 227, 228, 229, 231, 232, 233, 234, 776, 775, 232, - 233, 234, 304, 304, 304, 304, 235, 236, 232, 233, - 234, 235, 236, 773, 232, 233, 234, 232, 233, 234, - 235, 236, 772, 245, 771, 770, 235, 236, 245, 235, - 236, 256, 256, 256, 256, 256, 256, 245, 257, 257, - 257, 257, 257, 257, 258, 258, 245, 272, 272, 769, - 258, 290, 290, 272, 291, 291, 768, 290, 766, 311, - - 291, 258, 765, 764, 272, 314, 292, 292, 290, 762, - 760, 291, 292, 300, 759, 300, 756, 300, 305, 305, - 305, 305, 311, 292, 306, 306, 306, 306, 314, 322, - 300, 307, 307, 307, 307, 308, 308, 308, 308, 308, - 308, 309, 309, 309, 309, 309, 309, 315, 326, 315, - 329, 332, 322, 335, 338, 341, 344, 347, 350, 353, - 356, 359, 362, 365, 368, 371, 374, 384, 387, 391, - 315, 326, 394, 329, 332, 398, 335, 338, 341, 344, - 347, 350, 353, 356, 359, 362, 365, 368, 371, 374, - 384, 387, 391, 401, 404, 394, 407, 411, 398, 414, - - 417, 420, 423, 426, 438, 440, 443, 753, 504, 504, - 553, 556, 752, 751, 642, 642, 401, 404, 750, 407, - 411, 738, 414, 417, 420, 423, 426, 438, 440, 443, - 504, 737, 736, 553, 556, 642, 850, 850, 850, 852, - 852, 707, 700, 699, 696, 695, 694, 693, 692, 691, - 690, 689, 688, 687, 685, 682, 681, 680, 679, 678, - 677, 676, 675, 674, 673, 672, 670, 669, 668, 667, - 665, 663, 662, 661, 660, 659, 658, 657, 656, 655, - 654, 653, 652, 651, 650, 649, 648, 647, 646, 645, - 644, 643, 641, 640, 639, 638, 637, 636, 635, 634, - - 633, 630, 629, 628, 627, 626, 625, 624, 623, 622, - 621, 620, 619, 618, 617, 616, 615, 614, 613, 612, - 610, 609, 608, 607, 606, 605, 604, 603, 602, 601, - 600, 599, 598, 597, 596, 595, 593, 592, 591, 590, - 589, 587, 586, 585, 584, 583, 582, 581, 578, 577, - 575, 574, 573, 572, 569, 568, 567, 566, 565, 564, - 563, 561, 560, 559, 558, 557, 555, 554, 552, 551, - 550, 549, 548, 547, 546, 545, 544, 543, 542, 541, - 540, 539, 538, 537, 536, 535, 534, 533, 532, 531, - 530, 526, 525, 524, 523, 522, 521, 520, 519, 518, - - 517, 516, 515, 514, 513, 512, 511, 510, 509, 508, - 507, 506, 505, 502, 501, 500, 497, 496, 495, 494, - 493, 492, 490, 488, 487, 486, 484, 483, 482, 481, - 480, 479, 478, 477, 476, 475, 474, 473, 472, 471, - 470, 469, 468, 467, 465, 464, 463, 462, 461, 460, - 459, 456, 455, 454, 451, 450, 449, 448, 447, 446, - 445, 444, 442, 441, 439, 437, 436, 435, 434, 433, - 432, 431, 430, 428, 427, 425, 424, 422, 421, 419, - 418, 416, 415, 413, 412, 410, 409, 408, 406, 405, - 403, 402, 400, 399, 397, 396, 395, 393, 392, 390, - - 388, 386, 385, 383, 382, 380, 378, 377, 376, 375, - 373, 372, 370, 369, 367, 366, 364, 363, 361, 360, - 358, 357, 355, 354, 352, 351, 349, 348, 346, 345, - 343, 342, 340, 339, 337, 336, 334, 333, 331, 330, - 328, 327, 325, 323, 321, 320, 319, 318, 317, 316, - 313, 312, 310, 302, 301, 299, 298, 297, 296, 295, - 294, 289, 287, 286, 285, 284, 283, 282, 281, 280, - 278, 276, 275, 273, 271, 270, 267, 266, 265, 264, - 263, 262, 261, 259, 255, 254, 253, 252, 251, 250, - 249, 248, 247, 246, 238, 237, 230, 225, 222, 217, - - 216, 215, 193, 191, 190, 189, 187, 172, 171, 170, - 168, 167, 166, 165, 164, 158, 156, 155, 154, 153, - 152, 151, 150, 149, 148, 145, 144, 143, 142, 141, - 139, 138, 137, 135, 134, 131, 129, 127, 126, 125, - 124, 123, 122, 121, 120, 119, 115, 114, 113, 112, - 110, 109, 107, 106, 105, 104, 103, 102, 101, 100, - 98, 97, 96, 95, 94, 93, 91, 90, 89, 88, - 87, 86, 85, 83, 82, 79, 78, 77, 76, 74, - 73, 72, 56, 55, 52, 51, 38, 37, 35, 34, - 33, 32, 31, 30, 28, 20, 8, 7, 3, 849, - - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, - 849, 849, 849, 849, 849, 849, 849 - } ; - -/* The intent behind this definition is that it'll catch - * any uses of REJECT which flex missed. - */ -#define REJECT reject_used_but_not_detected -#define yymore() yymore_used_but_not_detected -#define YY_MORE_ADJ 0 -#define YY_RESTORE_YY_MORE_OFFSET -#line 1 "program_lexer.l" -#line 2 "program_lexer.l" -/* - * Copyright © 2009 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#include "main/glheader.h" -#include "main/imports.h" -#include "shader/prog_instruction.h" -#include "shader/prog_statevars.h" - -#include "shader/symbol_table.h" -#include "shader/program_parser.h" -#include "shader/program_parse.tab.h" - -#define require_ARB_vp (yyextra->mode == ARB_vertex) -#define require_ARB_fp (yyextra->mode == ARB_fragment) -#define require_NV_fp (yyextra->option.NV_fragment) -#define require_shadow (yyextra->option.Shadow) -#define require_rect (yyextra->option.TexRect) -#define require_texarray (yyextra->option.TexArray) - -#ifndef HAVE_UNISTD_H -#define YY_NO_UNISTD_H -#endif - -#define return_token_or_IDENTIFIER(condition, token) \ - do { \ - if (condition) { \ - return token; \ - } else { \ - return handle_ident(yyextra, yytext, yylval); \ - } \ - } while (0) - -#define return_token_or_DOT(condition, token) \ - do { \ - if (condition) { \ - return token; \ - } else { \ - yyless(1); \ - return DOT; \ - } \ - } while (0) - - -#define return_opcode(condition, token, opcode, len) \ - do { \ - if (condition && \ - _mesa_parse_instruction_suffix(yyextra, \ - yytext + len, \ - & yylval->temp_inst)) { \ - yylval->temp_inst.Opcode = OPCODE_ ## opcode; \ - return token; \ - } else { \ - return handle_ident(yyextra, yytext, yylval); \ - } \ - } while (0) - -#define SWIZZLE_INVAL MAKE_SWIZZLE4(SWIZZLE_NIL, SWIZZLE_NIL, \ - SWIZZLE_NIL, SWIZZLE_NIL) - -static unsigned -mask_from_char(char c) -{ - switch (c) { - case 'x': - case 'r': - return WRITEMASK_X; - case 'y': - case 'g': - return WRITEMASK_Y; - case 'z': - case 'b': - return WRITEMASK_Z; - case 'w': - case 'a': - return WRITEMASK_W; - } - - return 0; -} - -static unsigned -swiz_from_char(char c) -{ - switch (c) { - case 'x': - case 'r': - return SWIZZLE_X; - case 'y': - case 'g': - return SWIZZLE_Y; - case 'z': - case 'b': - return SWIZZLE_Z; - case 'w': - case 'a': - return SWIZZLE_W; - } - - return 0; -} - -static int -handle_ident(struct asm_parser_state *state, const char *text, YYSTYPE *lval) -{ - lval->string = strdup(text); - - return (_mesa_symbol_table_find_symbol(state->st, 0, text) == NULL) - ? IDENTIFIER : USED_IDENTIFIER; -} - -#define YY_USER_ACTION \ - do { \ - yylloc->first_column = yylloc->last_column; \ - yylloc->last_column += yyleng; \ - if ((yylloc->first_line == 1) \ - && (yylloc->first_column == 1)) { \ - yylloc->position = 1; \ - } else { \ - yylloc->position += yylloc->last_column - yylloc->first_column; \ - } \ - } while(0); - -#define YY_EXTRA_TYPE struct asm_parser_state * -#line 1156 "lex.yy.c" - -#define INITIAL 0 - -#ifndef YY_NO_UNISTD_H -/* Special case for "unistd.h", since it is non-ANSI. We include it way - * down here because we want the user's section 1 to have been scanned first. - * The user has a chance to override it with an option. - */ -#include -#endif - -#ifndef YY_EXTRA_TYPE -#define YY_EXTRA_TYPE void * -#endif - -/* Holds the entire state of the reentrant scanner. */ -struct yyguts_t - { - - /* User-defined. Not touched by flex. */ - YY_EXTRA_TYPE yyextra_r; - - /* The rest are the same as the globals declared in the non-reentrant scanner. */ - FILE *yyin_r, *yyout_r; - size_t yy_buffer_stack_top; /**< index of top of stack. */ - size_t yy_buffer_stack_max; /**< capacity of stack. */ - YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ - char yy_hold_char; - int yy_n_chars; - int yyleng_r; - char *yy_c_buf_p; - int yy_init; - int yy_start; - int yy_did_buffer_switch_on_eof; - int yy_start_stack_ptr; - int yy_start_stack_depth; - int *yy_start_stack; - yy_state_type yy_last_accepting_state; - char* yy_last_accepting_cpos; - - int yylineno_r; - int yy_flex_debug_r; - - char *yytext_r; - int yy_more_flag; - int yy_more_len; - - YYSTYPE * yylval_r; - - YYLTYPE * yylloc_r; - - }; /* end struct yyguts_t */ - -static int yy_init_globals (yyscan_t yyscanner ); - - /* This must go here because YYSTYPE and YYLTYPE are included - * from bison output in section 1.*/ - # define yylval yyg->yylval_r - - # define yylloc yyg->yylloc_r - -int yylex_init (yyscan_t* scanner); - -int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); - -/* Accessor methods to globals. - These are made visible to non-reentrant scanners for convenience. */ - -int yylex_destroy (yyscan_t yyscanner ); - -int yyget_debug (yyscan_t yyscanner ); - -void yyset_debug (int debug_flag ,yyscan_t yyscanner ); - -YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); - -void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); - -FILE *yyget_in (yyscan_t yyscanner ); - -void yyset_in (FILE * in_str ,yyscan_t yyscanner ); - -FILE *yyget_out (yyscan_t yyscanner ); - -void yyset_out (FILE * out_str ,yyscan_t yyscanner ); - -int yyget_leng (yyscan_t yyscanner ); - -char *yyget_text (yyscan_t yyscanner ); - -int yyget_lineno (yyscan_t yyscanner ); - -void yyset_lineno (int line_number ,yyscan_t yyscanner ); - -YYSTYPE * yyget_lval (yyscan_t yyscanner ); - -void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); - - YYLTYPE *yyget_lloc (yyscan_t yyscanner ); - - void yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int yywrap (yyscan_t yyscanner ); -#else -extern int yywrap (yyscan_t yyscanner ); -#endif -#endif - - static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner); - -#ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); -#endif - -#ifndef YY_NO_INPUT - -#ifdef __cplusplus -static int yyinput (yyscan_t yyscanner ); -#else -static int input (yyscan_t yyscanner ); -#endif - -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#endif - -/* Copy whatever the last rule matched to the standard output. */ -#ifndef ECHO -/* This used to be an fputs(), but since the string might contain NUL's, - * we now use fwrite(). - */ -#define ECHO fwrite( yytext, yyleng, 1, yyout ) -#endif - -/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, - * is returned in "result". - */ -#ifndef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ - { \ - int c = '*'; \ - unsigned n; \ - for ( n = 0; n < max_size && \ - (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ - buf[n] = (char) c; \ - if ( c == '\n' ) \ - buf[n++] = (char) c; \ - if ( c == EOF && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - result = n; \ - } \ - else \ - { \ - errno=0; \ - while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ - { \ - if( errno != EINTR) \ - { \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - break; \ - } \ - errno=0; \ - clearerr(yyin); \ - } \ - }\ -\ - -#endif - -/* No semi-colon after return; correct usage is to write "yyterminate();" - - * we don't want an extra ';' after the "return" because that will cause - * some compilers to complain about unreachable statements. - */ -#ifndef yyterminate -#define yyterminate() return YY_NULL -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Report a fatal error. */ -#ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) -#endif - -/* end tables serialization structures and prototypes */ - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL_IS_OURS 1 - -extern int yylex \ - (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); - -#define YY_DECL int yylex \ - (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) -#endif /* !YY_DECL */ - -/* Code executed at the beginning of each rule, after yytext and yyleng - * have been set up. - */ -#ifndef YY_USER_ACTION -#define YY_USER_ACTION -#endif - -/* Code executed at the end of each rule. */ -#ifndef YY_BREAK -#define YY_BREAK break; -#endif - -#define YY_RULE_SETUP \ - YY_USER_ACTION - -/** The main scanner function which does all the work. - */ -YY_DECL -{ - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - -#line 157 "program_lexer.l" - - -#line 1400 "lex.yy.c" - - yylval = yylval_param; - - yylloc = yylloc_param; - - if ( !yyg->yy_init ) - { - yyg->yy_init = 1; - -#ifdef YY_USER_INIT - YY_USER_INIT; -#endif - - if ( ! yyg->yy_start ) - yyg->yy_start = 1; /* first start state */ - - if ( ! yyin ) - yyin = stdin; - - if ( ! yyout ) - yyout = stdout; - - if ( ! YY_CURRENT_BUFFER ) { - yyensure_buffer_stack (yyscanner); - YY_CURRENT_BUFFER_LVALUE = - yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); - } - - yy_load_buffer_state(yyscanner ); - } - - while ( 1 ) /* loops until end-of-file is reached */ - { - yy_cp = yyg->yy_c_buf_p; - - /* Support of yytext. */ - *yy_cp = yyg->yy_hold_char; - - /* yy_bp points to the position in yy_ch_buf of the start of - * the current run. - */ - yy_bp = yy_cp; - - yy_current_state = yyg->yy_start; -yy_match: - do - { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; - if ( yy_accept[yy_current_state] ) - { - yyg->yy_last_accepting_state = yy_current_state; - yyg->yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 850 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - ++yy_cp; - } - while ( yy_base[yy_current_state] != 1300 ); - -yy_find_action: - yy_act = yy_accept[yy_current_state]; - if ( yy_act == 0 ) - { /* have to back up */ - yy_cp = yyg->yy_last_accepting_cpos; - yy_current_state = yyg->yy_last_accepting_state; - yy_act = yy_accept[yy_current_state]; - } - - YY_DO_BEFORE_ACTION; - -do_action: /* This label is used only to access EOF actions. */ - - switch ( yy_act ) - { /* beginning of action switch */ - case 0: /* must back up */ - /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = yyg->yy_hold_char; - yy_cp = yyg->yy_last_accepting_cpos; - yy_current_state = yyg->yy_last_accepting_state; - goto yy_find_action; - -case 1: -YY_RULE_SETUP -#line 159 "program_lexer.l" -{ return ARBvp_10; } - YY_BREAK -case 2: -YY_RULE_SETUP -#line 160 "program_lexer.l" -{ return ARBfp_10; } - YY_BREAK -case 3: -YY_RULE_SETUP -#line 161 "program_lexer.l" -{ - yylval->integer = at_address; - return_token_or_IDENTIFIER(require_ARB_vp, ADDRESS); -} - YY_BREAK -case 4: -YY_RULE_SETUP -#line 165 "program_lexer.l" -{ return ALIAS; } - YY_BREAK -case 5: -YY_RULE_SETUP -#line 166 "program_lexer.l" -{ return ATTRIB; } - YY_BREAK -case 6: -YY_RULE_SETUP -#line 167 "program_lexer.l" -{ return END; } - YY_BREAK -case 7: -YY_RULE_SETUP -#line 168 "program_lexer.l" -{ return OPTION; } - YY_BREAK -case 8: -YY_RULE_SETUP -#line 169 "program_lexer.l" -{ return OUTPUT; } - YY_BREAK -case 9: -YY_RULE_SETUP -#line 170 "program_lexer.l" -{ return PARAM; } - YY_BREAK -case 10: -YY_RULE_SETUP -#line 171 "program_lexer.l" -{ yylval->integer = at_temp; return TEMP; } - YY_BREAK -case 11: -YY_RULE_SETUP -#line 173 "program_lexer.l" -{ return_opcode( 1, VECTOR_OP, ABS, 3); } - YY_BREAK -case 12: -YY_RULE_SETUP -#line 174 "program_lexer.l" -{ return_opcode( 1, BIN_OP, ADD, 3); } - YY_BREAK -case 13: -YY_RULE_SETUP -#line 175 "program_lexer.l" -{ return_opcode(require_ARB_vp, ARL, ARL, 3); } - YY_BREAK -case 14: -YY_RULE_SETUP -#line 177 "program_lexer.l" -{ return_opcode(require_ARB_fp, TRI_OP, CMP, 3); } - YY_BREAK -case 15: -YY_RULE_SETUP -#line 178 "program_lexer.l" -{ return_opcode(require_ARB_fp, SCALAR_OP, COS, 3); } - YY_BREAK -case 16: -YY_RULE_SETUP -#line 180 "program_lexer.l" -{ return_opcode(require_NV_fp, VECTOR_OP, DDX, 3); } - YY_BREAK -case 17: -YY_RULE_SETUP -#line 181 "program_lexer.l" -{ return_opcode(require_NV_fp, VECTOR_OP, DDY, 3); } - YY_BREAK -case 18: -YY_RULE_SETUP -#line 182 "program_lexer.l" -{ return_opcode( 1, BIN_OP, DP3, 3); } - YY_BREAK -case 19: -YY_RULE_SETUP -#line 183 "program_lexer.l" -{ return_opcode( 1, BIN_OP, DP4, 3); } - YY_BREAK -case 20: -YY_RULE_SETUP -#line 184 "program_lexer.l" -{ return_opcode( 1, BIN_OP, DPH, 3); } - YY_BREAK -case 21: -YY_RULE_SETUP -#line 185 "program_lexer.l" -{ return_opcode( 1, BIN_OP, DST, 3); } - YY_BREAK -case 22: -YY_RULE_SETUP -#line 187 "program_lexer.l" -{ return_opcode( 1, SCALAR_OP, EX2, 3); } - YY_BREAK -case 23: -YY_RULE_SETUP -#line 188 "program_lexer.l" -{ return_opcode(require_ARB_vp, SCALAR_OP, EXP, 3); } - YY_BREAK -case 24: -YY_RULE_SETUP -#line 190 "program_lexer.l" -{ return_opcode( 1, VECTOR_OP, FLR, 3); } - YY_BREAK -case 25: -YY_RULE_SETUP -#line 191 "program_lexer.l" -{ return_opcode( 1, VECTOR_OP, FRC, 3); } - YY_BREAK -case 26: -YY_RULE_SETUP -#line 193 "program_lexer.l" -{ return_opcode(require_ARB_fp, KIL, KIL, 3); } - YY_BREAK -case 27: -YY_RULE_SETUP -#line 195 "program_lexer.l" -{ return_opcode( 1, VECTOR_OP, LIT, 3); } - YY_BREAK -case 28: -YY_RULE_SETUP -#line 196 "program_lexer.l" -{ return_opcode( 1, SCALAR_OP, LG2, 3); } - YY_BREAK -case 29: -YY_RULE_SETUP -#line 197 "program_lexer.l" -{ return_opcode(require_ARB_vp, SCALAR_OP, LOG, 3); } - YY_BREAK -case 30: -YY_RULE_SETUP -#line 198 "program_lexer.l" -{ return_opcode(require_ARB_fp, TRI_OP, LRP, 3); } - YY_BREAK -case 31: -YY_RULE_SETUP -#line 200 "program_lexer.l" -{ return_opcode( 1, TRI_OP, MAD, 3); } - YY_BREAK -case 32: -YY_RULE_SETUP -#line 201 "program_lexer.l" -{ return_opcode( 1, BIN_OP, MAX, 3); } - YY_BREAK -case 33: -YY_RULE_SETUP -#line 202 "program_lexer.l" -{ return_opcode( 1, BIN_OP, MIN, 3); } - YY_BREAK -case 34: -YY_RULE_SETUP -#line 203 "program_lexer.l" -{ return_opcode( 1, VECTOR_OP, MOV, 3); } - YY_BREAK -case 35: -YY_RULE_SETUP -#line 204 "program_lexer.l" -{ return_opcode( 1, BIN_OP, MUL, 3); } - YY_BREAK -case 36: -YY_RULE_SETUP -#line 206 "program_lexer.l" -{ return_opcode(require_NV_fp, VECTOR_OP, PK2H, 4); } - YY_BREAK -case 37: -YY_RULE_SETUP -#line 207 "program_lexer.l" -{ return_opcode(require_NV_fp, VECTOR_OP, PK2US, 5); } - YY_BREAK -case 38: -YY_RULE_SETUP -#line 208 "program_lexer.l" -{ return_opcode(require_NV_fp, VECTOR_OP, PK4B, 4); } - YY_BREAK -case 39: -YY_RULE_SETUP -#line 209 "program_lexer.l" -{ return_opcode(require_NV_fp, VECTOR_OP, PK4UB, 5); } - YY_BREAK -case 40: -YY_RULE_SETUP -#line 210 "program_lexer.l" -{ return_opcode( 1, BINSC_OP, POW, 3); } - YY_BREAK -case 41: -YY_RULE_SETUP -#line 212 "program_lexer.l" -{ return_opcode( 1, SCALAR_OP, RCP, 3); } - YY_BREAK -case 42: -YY_RULE_SETUP -#line 213 "program_lexer.l" -{ return_opcode(require_NV_fp, BIN_OP, RFL, 3); } - YY_BREAK -case 43: -YY_RULE_SETUP -#line 214 "program_lexer.l" -{ return_opcode( 1, SCALAR_OP, RSQ, 3); } - YY_BREAK -case 44: -YY_RULE_SETUP -#line 216 "program_lexer.l" -{ return_opcode(require_ARB_fp, SCALAR_OP, SCS, 3); } - YY_BREAK -case 45: -YY_RULE_SETUP -#line 217 "program_lexer.l" -{ return_opcode(require_NV_fp, BIN_OP, SEQ, 3); } - YY_BREAK -case 46: -YY_RULE_SETUP -#line 218 "program_lexer.l" -{ return_opcode(require_NV_fp, BIN_OP, SFL, 3); } - YY_BREAK -case 47: -YY_RULE_SETUP -#line 219 "program_lexer.l" -{ return_opcode( 1, BIN_OP, SGE, 3); } - YY_BREAK -case 48: -YY_RULE_SETUP -#line 220 "program_lexer.l" -{ return_opcode(require_NV_fp, BIN_OP, SGT, 3); } - YY_BREAK -case 49: -YY_RULE_SETUP -#line 221 "program_lexer.l" -{ return_opcode(require_ARB_fp, SCALAR_OP, SIN, 3); } - YY_BREAK -case 50: -YY_RULE_SETUP -#line 222 "program_lexer.l" -{ return_opcode(require_NV_fp, BIN_OP, SLE, 3); } - YY_BREAK -case 51: -YY_RULE_SETUP -#line 223 "program_lexer.l" -{ return_opcode( 1, BIN_OP, SLT, 3); } - YY_BREAK -case 52: -YY_RULE_SETUP -#line 224 "program_lexer.l" -{ return_opcode(require_NV_fp, BIN_OP, SNE, 3); } - YY_BREAK -case 53: -YY_RULE_SETUP -#line 225 "program_lexer.l" -{ return_opcode(require_NV_fp, BIN_OP, STR, 3); } - YY_BREAK -case 54: -YY_RULE_SETUP -#line 226 "program_lexer.l" -{ return_opcode( 1, BIN_OP, SUB, 3); } - YY_BREAK -case 55: -YY_RULE_SETUP -#line 227 "program_lexer.l" -{ return_opcode( 1, SWZ, SWZ, 3); } - YY_BREAK -case 56: -YY_RULE_SETUP -#line 229 "program_lexer.l" -{ return_opcode(require_ARB_fp, SAMPLE_OP, TEX, 3); } - YY_BREAK -case 57: -YY_RULE_SETUP -#line 230 "program_lexer.l" -{ return_opcode(require_ARB_fp, SAMPLE_OP, TXB, 3); } - YY_BREAK -case 58: -YY_RULE_SETUP -#line 231 "program_lexer.l" -{ return_opcode(require_NV_fp, TXD_OP, TXD, 3); } - YY_BREAK -case 59: -YY_RULE_SETUP -#line 232 "program_lexer.l" -{ return_opcode(require_ARB_fp, SAMPLE_OP, TXP, 3); } - YY_BREAK -case 60: -YY_RULE_SETUP -#line 234 "program_lexer.l" -{ return_opcode(require_NV_fp, SCALAR_OP, UP2H, 4); } - YY_BREAK -case 61: -YY_RULE_SETUP -#line 235 "program_lexer.l" -{ return_opcode(require_NV_fp, SCALAR_OP, UP2US, 5); } - YY_BREAK -case 62: -YY_RULE_SETUP -#line 236 "program_lexer.l" -{ return_opcode(require_NV_fp, SCALAR_OP, UP4B, 4); } - YY_BREAK -case 63: -YY_RULE_SETUP -#line 237 "program_lexer.l" -{ return_opcode(require_NV_fp, SCALAR_OP, UP4UB, 5); } - YY_BREAK -case 64: -YY_RULE_SETUP -#line 239 "program_lexer.l" -{ return_opcode(require_NV_fp, TRI_OP, X2D, 3); } - YY_BREAK -case 65: -YY_RULE_SETUP -#line 240 "program_lexer.l" -{ return_opcode( 1, BIN_OP, XPD, 3); } - YY_BREAK -case 66: -YY_RULE_SETUP -#line 242 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_vp, VERTEX); } - YY_BREAK -case 67: -YY_RULE_SETUP -#line 243 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp, FRAGMENT); } - YY_BREAK -case 68: -YY_RULE_SETUP -#line 244 "program_lexer.l" -{ return PROGRAM; } - YY_BREAK -case 69: -YY_RULE_SETUP -#line 245 "program_lexer.l" -{ return STATE; } - YY_BREAK -case 70: -YY_RULE_SETUP -#line 246 "program_lexer.l" -{ return RESULT; } - YY_BREAK -case 71: -YY_RULE_SETUP -#line 248 "program_lexer.l" -{ return AMBIENT; } - YY_BREAK -case 72: -YY_RULE_SETUP -#line 249 "program_lexer.l" -{ return ATTENUATION; } - YY_BREAK -case 73: -YY_RULE_SETUP -#line 250 "program_lexer.l" -{ return BACK; } - YY_BREAK -case 74: -YY_RULE_SETUP -#line 251 "program_lexer.l" -{ return_token_or_DOT(require_ARB_vp, CLIP); } - YY_BREAK -case 75: -YY_RULE_SETUP -#line 252 "program_lexer.l" -{ return COLOR; } - YY_BREAK -case 76: -YY_RULE_SETUP -#line 253 "program_lexer.l" -{ return_token_or_DOT(require_ARB_fp, DEPTH); } - YY_BREAK -case 77: -YY_RULE_SETUP -#line 254 "program_lexer.l" -{ return DIFFUSE; } - YY_BREAK -case 78: -YY_RULE_SETUP -#line 255 "program_lexer.l" -{ return DIRECTION; } - YY_BREAK -case 79: -YY_RULE_SETUP -#line 256 "program_lexer.l" -{ return EMISSION; } - YY_BREAK -case 80: -YY_RULE_SETUP -#line 257 "program_lexer.l" -{ return ENV; } - YY_BREAK -case 81: -YY_RULE_SETUP -#line 258 "program_lexer.l" -{ return EYE; } - YY_BREAK -case 82: -YY_RULE_SETUP -#line 259 "program_lexer.l" -{ return FOGCOORD; } - YY_BREAK -case 83: -YY_RULE_SETUP -#line 260 "program_lexer.l" -{ return FOG; } - YY_BREAK -case 84: -YY_RULE_SETUP -#line 261 "program_lexer.l" -{ return FRONT; } - YY_BREAK -case 85: -YY_RULE_SETUP -#line 262 "program_lexer.l" -{ return HALF; } - YY_BREAK -case 86: -YY_RULE_SETUP -#line 263 "program_lexer.l" -{ return INVERSE; } - YY_BREAK -case 87: -YY_RULE_SETUP -#line 264 "program_lexer.l" -{ return INVTRANS; } - YY_BREAK -case 88: -YY_RULE_SETUP -#line 265 "program_lexer.l" -{ return LIGHT; } - YY_BREAK -case 89: -YY_RULE_SETUP -#line 266 "program_lexer.l" -{ return LIGHTMODEL; } - YY_BREAK -case 90: -YY_RULE_SETUP -#line 267 "program_lexer.l" -{ return LIGHTPROD; } - YY_BREAK -case 91: -YY_RULE_SETUP -#line 268 "program_lexer.l" -{ return LOCAL; } - YY_BREAK -case 92: -YY_RULE_SETUP -#line 269 "program_lexer.l" -{ return MATERIAL; } - YY_BREAK -case 93: -YY_RULE_SETUP -#line 270 "program_lexer.l" -{ return MAT_PROGRAM; } - YY_BREAK -case 94: -YY_RULE_SETUP -#line 271 "program_lexer.l" -{ return MATRIX; } - YY_BREAK -case 95: -YY_RULE_SETUP -#line 272 "program_lexer.l" -{ return_token_or_DOT(require_ARB_vp, MATRIXINDEX); } - YY_BREAK -case 96: -YY_RULE_SETUP -#line 273 "program_lexer.l" -{ return MODELVIEW; } - YY_BREAK -case 97: -YY_RULE_SETUP -#line 274 "program_lexer.l" -{ return MVP; } - YY_BREAK -case 98: -YY_RULE_SETUP -#line 275 "program_lexer.l" -{ return_token_or_DOT(require_ARB_vp, NORMAL); } - YY_BREAK -case 99: -YY_RULE_SETUP -#line 276 "program_lexer.l" -{ return OBJECT; } - YY_BREAK -case 100: -YY_RULE_SETUP -#line 277 "program_lexer.l" -{ return PALETTE; } - YY_BREAK -case 101: -YY_RULE_SETUP -#line 278 "program_lexer.l" -{ return PARAMS; } - YY_BREAK -case 102: -YY_RULE_SETUP -#line 279 "program_lexer.l" -{ return PLANE; } - YY_BREAK -case 103: -YY_RULE_SETUP -#line 280 "program_lexer.l" -{ return_token_or_DOT(require_ARB_vp, POINT_TOK); } - YY_BREAK -case 104: -YY_RULE_SETUP -#line 281 "program_lexer.l" -{ return_token_or_DOT(require_ARB_vp, POINTSIZE); } - YY_BREAK -case 105: -YY_RULE_SETUP -#line 282 "program_lexer.l" -{ return POSITION; } - YY_BREAK -case 106: -YY_RULE_SETUP -#line 283 "program_lexer.l" -{ return PRIMARY; } - YY_BREAK -case 107: -YY_RULE_SETUP -#line 284 "program_lexer.l" -{ return PROJECTION; } - YY_BREAK -case 108: -YY_RULE_SETUP -#line 285 "program_lexer.l" -{ return_token_or_DOT(require_ARB_fp, RANGE); } - YY_BREAK -case 109: -YY_RULE_SETUP -#line 286 "program_lexer.l" -{ return ROW; } - YY_BREAK -case 110: -YY_RULE_SETUP -#line 287 "program_lexer.l" -{ return SCENECOLOR; } - YY_BREAK -case 111: -YY_RULE_SETUP -#line 288 "program_lexer.l" -{ return SECONDARY; } - YY_BREAK -case 112: -YY_RULE_SETUP -#line 289 "program_lexer.l" -{ return SHININESS; } - YY_BREAK -case 113: -YY_RULE_SETUP -#line 290 "program_lexer.l" -{ return_token_or_DOT(require_ARB_vp, SIZE_TOK); } - YY_BREAK -case 114: -YY_RULE_SETUP -#line 291 "program_lexer.l" -{ return SPECULAR; } - YY_BREAK -case 115: -YY_RULE_SETUP -#line 292 "program_lexer.l" -{ return SPOT; } - YY_BREAK -case 116: -YY_RULE_SETUP -#line 293 "program_lexer.l" -{ return TEXCOORD; } - YY_BREAK -case 117: -YY_RULE_SETUP -#line 294 "program_lexer.l" -{ return_token_or_DOT(require_ARB_fp, TEXENV); } - YY_BREAK -case 118: -YY_RULE_SETUP -#line 295 "program_lexer.l" -{ return_token_or_DOT(require_ARB_vp, TEXGEN); } - YY_BREAK -case 119: -YY_RULE_SETUP -#line 296 "program_lexer.l" -{ return_token_or_DOT(require_ARB_vp, TEXGEN_Q); } - YY_BREAK -case 120: -YY_RULE_SETUP -#line 297 "program_lexer.l" -{ return_token_or_DOT(require_ARB_vp, TEXGEN_S); } - YY_BREAK -case 121: -YY_RULE_SETUP -#line 298 "program_lexer.l" -{ return_token_or_DOT(require_ARB_vp, TEXGEN_T); } - YY_BREAK -case 122: -YY_RULE_SETUP -#line 299 "program_lexer.l" -{ return TEXTURE; } - YY_BREAK -case 123: -YY_RULE_SETUP -#line 300 "program_lexer.l" -{ return TRANSPOSE; } - YY_BREAK -case 124: -YY_RULE_SETUP -#line 301 "program_lexer.l" -{ return_token_or_DOT(require_ARB_vp, VTXATTRIB); } - YY_BREAK -case 125: -YY_RULE_SETUP -#line 302 "program_lexer.l" -{ return_token_or_DOT(require_ARB_vp, WEIGHT); } - YY_BREAK -case 126: -YY_RULE_SETUP -#line 304 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp, TEXTURE_UNIT); } - YY_BREAK -case 127: -YY_RULE_SETUP -#line 305 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp, TEX_1D); } - YY_BREAK -case 128: -YY_RULE_SETUP -#line 306 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp, TEX_2D); } - YY_BREAK -case 129: -YY_RULE_SETUP -#line 307 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp, TEX_3D); } - YY_BREAK -case 130: -YY_RULE_SETUP -#line 308 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp, TEX_CUBE); } - YY_BREAK -case 131: -YY_RULE_SETUP -#line 309 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp && require_rect, TEX_RECT); } - YY_BREAK -case 132: -YY_RULE_SETUP -#line 310 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow, TEX_SHADOW1D); } - YY_BREAK -case 133: -YY_RULE_SETUP -#line 311 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow, TEX_SHADOW2D); } - YY_BREAK -case 134: -YY_RULE_SETUP -#line 312 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_rect, TEX_SHADOWRECT); } - YY_BREAK -case 135: -YY_RULE_SETUP -#line 313 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp && require_texarray, TEX_ARRAY1D); } - YY_BREAK -case 136: -YY_RULE_SETUP -#line 314 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp && require_texarray, TEX_ARRAY2D); } - YY_BREAK -case 137: -YY_RULE_SETUP -#line 315 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_texarray, TEX_ARRAYSHADOW1D); } - YY_BREAK -case 138: -YY_RULE_SETUP -#line 316 "program_lexer.l" -{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_texarray, TEX_ARRAYSHADOW2D); } - YY_BREAK -case 139: -YY_RULE_SETUP -#line 318 "program_lexer.l" -{ return handle_ident(yyextra, yytext, yylval); } - YY_BREAK -case 140: -YY_RULE_SETUP -#line 320 "program_lexer.l" -{ return DOT_DOT; } - YY_BREAK -case 141: -YY_RULE_SETUP -#line 322 "program_lexer.l" -{ - yylval->integer = strtol(yytext, NULL, 10); - return INTEGER; -} - YY_BREAK -case 142: -YY_RULE_SETUP -#line 326 "program_lexer.l" -{ - yylval->real = _mesa_strtof(yytext, NULL); - return REAL; -} - YY_BREAK -case 143: -/* rule 143 can match eol */ -*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ -yyg->yy_c_buf_p = yy_cp -= 1; -YY_DO_BEFORE_ACTION; /* set up yytext again */ -YY_RULE_SETUP -#line 330 "program_lexer.l" -{ - yylval->real = _mesa_strtof(yytext, NULL); - return REAL; -} - YY_BREAK -case 144: -YY_RULE_SETUP -#line 334 "program_lexer.l" -{ - yylval->real = _mesa_strtof(yytext, NULL); - return REAL; -} - YY_BREAK -case 145: -YY_RULE_SETUP -#line 338 "program_lexer.l" -{ - yylval->real = _mesa_strtof(yytext, NULL); - return REAL; -} - YY_BREAK -case 146: -YY_RULE_SETUP -#line 343 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_NOOP; - yylval->swiz_mask.mask = WRITEMASK_XYZW; - return MASK4; -} - YY_BREAK -case 147: -YY_RULE_SETUP -#line 349 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_XY - | mask_from_char(yytext[3]); - return MASK3; -} - YY_BREAK -case 148: -YY_RULE_SETUP -#line 355 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_XZW; - return MASK3; -} - YY_BREAK -case 149: -YY_RULE_SETUP -#line 360 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_YZW; - return MASK3; -} - YY_BREAK -case 150: -YY_RULE_SETUP -#line 366 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_X - | mask_from_char(yytext[2]); - return MASK2; -} - YY_BREAK -case 151: -YY_RULE_SETUP -#line 372 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_Y - | mask_from_char(yytext[2]); - return MASK2; -} - YY_BREAK -case 152: -YY_RULE_SETUP -#line 378 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_ZW; - return MASK2; -} - YY_BREAK -case 153: -YY_RULE_SETUP -#line 384 "program_lexer.l" -{ - const unsigned s = swiz_from_char(yytext[1]); - yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(s, s, s, s); - yylval->swiz_mask.mask = mask_from_char(yytext[1]); - return MASK1; -} - YY_BREAK -case 154: -YY_RULE_SETUP -#line 391 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(swiz_from_char(yytext[1]), - swiz_from_char(yytext[2]), - swiz_from_char(yytext[3]), - swiz_from_char(yytext[4])); - yylval->swiz_mask.mask = 0; - return SWIZZLE; -} - YY_BREAK -case 155: -YY_RULE_SETUP -#line 400 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_NOOP; - yylval->swiz_mask.mask = WRITEMASK_XYZW; - return_token_or_DOT(require_ARB_fp, MASK4); -} - YY_BREAK -case 156: -YY_RULE_SETUP -#line 406 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_XY - | mask_from_char(yytext[3]); - return_token_or_DOT(require_ARB_fp, MASK3); -} - YY_BREAK -case 157: -YY_RULE_SETUP -#line 412 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_XZW; - return_token_or_DOT(require_ARB_fp, MASK3); -} - YY_BREAK -case 158: -YY_RULE_SETUP -#line 417 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_YZW; - return_token_or_DOT(require_ARB_fp, MASK3); -} - YY_BREAK -case 159: -YY_RULE_SETUP -#line 423 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_X - | mask_from_char(yytext[2]); - return_token_or_DOT(require_ARB_fp, MASK2); -} - YY_BREAK -case 160: -YY_RULE_SETUP -#line 429 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_Y - | mask_from_char(yytext[2]); - return_token_or_DOT(require_ARB_fp, MASK2); -} - YY_BREAK -case 161: -YY_RULE_SETUP -#line 435 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_ZW; - return_token_or_DOT(require_ARB_fp, MASK2); -} - YY_BREAK -case 162: -YY_RULE_SETUP -#line 441 "program_lexer.l" -{ - const unsigned s = swiz_from_char(yytext[1]); - yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(s, s, s, s); - yylval->swiz_mask.mask = mask_from_char(yytext[1]); - return_token_or_DOT(require_ARB_fp, MASK1); -} - YY_BREAK -case 163: -YY_RULE_SETUP -#line 449 "program_lexer.l" -{ - if (require_ARB_vp) { - return TEXGEN_R; - } else { - yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, - SWIZZLE_X, SWIZZLE_X); - yylval->swiz_mask.mask = WRITEMASK_X; - return MASK1; - } -} - YY_BREAK -case 164: -YY_RULE_SETUP -#line 460 "program_lexer.l" -{ - yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(swiz_from_char(yytext[1]), - swiz_from_char(yytext[2]), - swiz_from_char(yytext[3]), - swiz_from_char(yytext[4])); - yylval->swiz_mask.mask = 0; - return_token_or_DOT(require_ARB_fp, SWIZZLE); -} - YY_BREAK -case 165: -YY_RULE_SETUP -#line 469 "program_lexer.l" -{ return DOT; } - YY_BREAK -case 166: -/* rule 166 can match eol */ -YY_RULE_SETUP -#line 471 "program_lexer.l" -{ - yylloc->first_line++; - yylloc->first_column = 1; - yylloc->last_line++; - yylloc->last_column = 1; - yylloc->position++; -} - YY_BREAK -case 167: -YY_RULE_SETUP -#line 478 "program_lexer.l" -/* eat whitespace */ ; - YY_BREAK -case 168: -*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ -yyg->yy_c_buf_p = yy_cp -= 1; -YY_DO_BEFORE_ACTION; /* set up yytext again */ -YY_RULE_SETUP -#line 479 "program_lexer.l" -/* eat comments */ ; - YY_BREAK -case 169: -YY_RULE_SETUP -#line 480 "program_lexer.l" -{ return yytext[0]; } - YY_BREAK -case 170: -YY_RULE_SETUP -#line 481 "program_lexer.l" -ECHO; - YY_BREAK -#line 2464 "lex.yy.c" -case YY_STATE_EOF(INITIAL): - yyterminate(); - - case YY_END_OF_BUFFER: - { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; - - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yyg->yy_hold_char; - YY_RESTORE_YY_MORE_OFFSET - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) - { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed yyin at a new source and called - * yylex(). If so, then we have to assure - * consistency between YY_CURRENT_BUFFER and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; - } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) - { /* This was really a NUL. */ - yy_state_type yy_next_state; - - yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( yyscanner ); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); - - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - - if ( yy_next_state ) - { - /* Consume the NUL. */ - yy_cp = ++yyg->yy_c_buf_p; - yy_current_state = yy_next_state; - goto yy_match; - } - - else - { - yy_cp = yyg->yy_c_buf_p; - goto yy_find_action; - } - } - - else switch ( yy_get_next_buffer( yyscanner ) ) - { - case EOB_ACT_END_OF_FILE: - { - yyg->yy_did_buffer_switch_on_eof = 0; - - if ( yywrap(yyscanner ) ) - { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * yytext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } - - else - { - if ( ! yyg->yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; - } - break; - } - - case EOB_ACT_CONTINUE_SCAN: - yyg->yy_c_buf_p = - yyg->yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( yyscanner ); - - yy_cp = yyg->yy_c_buf_p; - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - goto yy_match; - - case EOB_ACT_LAST_MATCH: - yyg->yy_c_buf_p = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; - - yy_current_state = yy_get_previous_state( yyscanner ); - - yy_cp = yyg->yy_c_buf_p; - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - goto yy_find_action; - } - break; - } - - default: - YY_FATAL_ERROR( - "fatal flex scanner internal error--no action found" ); - } /* end of action switch */ - } /* end of scanning one token */ -} /* end of yylex */ - -/* yy_get_next_buffer - try to read in a new buffer - * - * Returns a code representing an action: - * EOB_ACT_LAST_MATCH - - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position - * EOB_ACT_END_OF_FILE - end of file - */ -static int yy_get_next_buffer (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = yyg->yytext_ptr; - register int number_to_move, i; - int ret_val; - - if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) - { /* Don't try to fill the buffer, so this is an EOF. */ - if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) - { - /* We matched a single character, the EOB, so - * treat this as a final EOF. - */ - return EOB_ACT_END_OF_FILE; - } - - else - { - /* We matched some text prior to the EOB, first - * process it. - */ - return EOB_ACT_LAST_MATCH; - } - } - - /* Try to read more data. */ - - /* First move last chars to start of buffer. */ - number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; - - for ( i = 0; i < number_to_move; ++i ) - *(dest++) = *(source++); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) - /* don't do the read, it's not guaranteed to return an EOF, - * just force an EOF - */ - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; - - else - { - int num_to_read = - YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ - - /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = YY_CURRENT_BUFFER; - - int yy_c_buf_p_offset = - (int) (yyg->yy_c_buf_p - b->yy_ch_buf); - - if ( b->yy_is_our_buffer ) - { - int new_size = b->yy_buf_size * 2; - - if ( new_size <= 0 ) - b->yy_buf_size += b->yy_buf_size / 8; - else - b->yy_buf_size *= 2; - - b->yy_ch_buf = (char *) - /* Include room in for 2 EOB chars. */ - yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); - } - else - /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; - - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( - "fatal error - scanner input buffer overflow" ); - - yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; - - num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - - number_to_move - 1; - - } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), - yyg->yy_n_chars, (size_t) num_to_read ); - - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; - } - - if ( yyg->yy_n_chars == 0 ) - { - if ( number_to_move == YY_MORE_ADJ ) - { - ret_val = EOB_ACT_END_OF_FILE; - yyrestart(yyin ,yyscanner); - } - - else - { - ret_val = EOB_ACT_LAST_MATCH; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = - YY_BUFFER_EOF_PENDING; - } - } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { - /* Extend the array by 50%, plus the number we really need. */ - yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); - if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); - } - - yyg->yy_n_chars += number_to_move; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; - - yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; - - return ret_val; -} - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - - static yy_state_type yy_get_previous_state (yyscan_t yyscanner) -{ - register yy_state_type yy_current_state; - register char *yy_cp; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - yy_current_state = yyg->yy_start; - - for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) - { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); - if ( yy_accept[yy_current_state] ) - { - yyg->yy_last_accepting_state = yy_current_state; - yyg->yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 850 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - } - - return yy_current_state; -} - -/* yy_try_NUL_trans - try to make a transition on the NUL character - * - * synopsis - * next_state = yy_try_NUL_trans( current_state ); - */ - static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) -{ - register int yy_is_jam; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ - register char *yy_cp = yyg->yy_c_buf_p; - - register YY_CHAR yy_c = 1; - if ( yy_accept[yy_current_state] ) - { - yyg->yy_last_accepting_state = yy_current_state; - yyg->yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 850 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 849); - - return yy_is_jam ? 0 : yy_current_state; -} - - static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner) -{ - register char *yy_cp; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - yy_cp = yyg->yy_c_buf_p; - - /* undo effects of setting up yytext */ - *yy_cp = yyg->yy_hold_char; - - if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) - { /* need to shift things up to make room */ - /* +2 for EOB chars. */ - register int number_to_move = yyg->yy_n_chars + 2; - register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ - YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; - register char *source = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; - - while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) - *--dest = *--source; - - yy_cp += (int) (dest - source); - yy_bp += (int) (dest - source); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; - - if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) - YY_FATAL_ERROR( "flex scanner push-back overflow" ); - } - - *--yy_cp = (char) c; - - yyg->yytext_ptr = yy_bp; - yyg->yy_hold_char = *yy_cp; - yyg->yy_c_buf_p = yy_cp; -} - -#ifndef YY_NO_INPUT -#ifdef __cplusplus - static int yyinput (yyscan_t yyscanner) -#else - static int input (yyscan_t yyscanner) -#endif - -{ - int c; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - *yyg->yy_c_buf_p = yyg->yy_hold_char; - - if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) - { - /* yy_c_buf_p now points to the character we want to return. - * If this occurs *before* the EOB characters, then it's a - * valid NUL; if not, then we've hit the end of the buffer. - */ - if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) - /* This was really a NUL. */ - *yyg->yy_c_buf_p = '\0'; - - else - { /* need more input */ - int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; - ++yyg->yy_c_buf_p; - - switch ( yy_get_next_buffer( yyscanner ) ) - { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ - - /* Reset buffer status. */ - yyrestart(yyin ,yyscanner); - - /*FALLTHROUGH*/ - - case EOB_ACT_END_OF_FILE: - { - if ( yywrap(yyscanner ) ) - return EOF; - - if ( ! yyg->yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; -#ifdef __cplusplus - return yyinput(yyscanner); -#else - return input(yyscanner); -#endif - } - - case EOB_ACT_CONTINUE_SCAN: - yyg->yy_c_buf_p = yyg->yytext_ptr + offset; - break; - } - } - } - - c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ - *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ - yyg->yy_hold_char = *++yyg->yy_c_buf_p; - - return c; -} -#endif /* ifndef YY_NO_INPUT */ - -/** Immediately switch to a different input stream. - * @param input_file A readable stream. - * @param yyscanner The scanner object. - * @note This function does not reset the start condition to @c INITIAL . - */ - void yyrestart (FILE * input_file , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if ( ! YY_CURRENT_BUFFER ){ - yyensure_buffer_stack (yyscanner); - YY_CURRENT_BUFFER_LVALUE = - yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); - } - - yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); - yy_load_buffer_state(yyscanner ); -} - -/** Switch to a different input buffer. - * @param new_buffer The new input buffer. - * @param yyscanner The scanner object. - */ - void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* TODO. We should be able to replace this entire function body - * with - * yypop_buffer_state(); - * yypush_buffer_state(new_buffer); - */ - yyensure_buffer_stack (yyscanner); - if ( YY_CURRENT_BUFFER == new_buffer ) - return; - - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *yyg->yy_c_buf_p = yyg->yy_hold_char; - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; - } - - YY_CURRENT_BUFFER_LVALUE = new_buffer; - yy_load_buffer_state(yyscanner ); - - /* We don't actually know whether we did this switch during - * EOF (yywrap()) processing, but the only time this flag - * is looked at is after yywrap() is called, so it's safe - * to go ahead and always set it. - */ - yyg->yy_did_buffer_switch_on_eof = 1; -} - -static void yy_load_buffer_state (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; - yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; - yyg->yy_hold_char = *yyg->yy_c_buf_p; -} - -/** Allocate and initialize an input buffer state. - * @param file A readable stream. - * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. - * @param yyscanner The scanner object. - * @return the allocated buffer state. - */ - YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_buf_size = size; - - /* yy_ch_buf has to be 2 characters longer than the size given because - * we need to put in 2 end-of-buffer characters. - */ - b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner ); - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_is_our_buffer = 1; - - yy_init_buffer(b,file ,yyscanner); - - return b; -} - -/** Destroy the buffer. - * @param b a buffer created with yy_create_buffer() - * @param yyscanner The scanner object. - */ - void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if ( ! b ) - return; - - if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ - YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - yyfree((void *) b->yy_ch_buf ,yyscanner ); - - yyfree((void *) b ,yyscanner ); -} - -/* Initializes or reinitializes a buffer. - * This function is sometimes called more than once on the same buffer, - * such as during a yyrestart() or at EOF. - */ - static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) - -{ - int oerrno = errno; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - yy_flush_buffer(b ,yyscanner); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - - /* If b is the current buffer, then yy_init_buffer was _probably_ - * called from yyrestart() or through yy_get_next_buffer. - * In that case, we don't want to reset the lineno or column. - */ - if (b != YY_CURRENT_BUFFER){ - b->yy_bs_lineno = 1; - b->yy_bs_column = 0; - } - - b->yy_is_interactive = 0; - - errno = oerrno; -} - -/** Discard all buffered characters. On the next scan, YY_INPUT will be called. - * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. - * @param yyscanner The scanner object. - */ - void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if ( ! b ) - return; - - b->yy_n_chars = 0; - - /* We always need two end-of-buffer characters. The first causes - * a transition to the end-of-buffer state. The second causes - * a jam in that state. - */ - b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; - - b->yy_buf_pos = &b->yy_ch_buf[0]; - - b->yy_at_bol = 1; - b->yy_buffer_status = YY_BUFFER_NEW; - - if ( b == YY_CURRENT_BUFFER ) - yy_load_buffer_state(yyscanner ); -} - -/** Pushes the new state onto the stack. The new state becomes - * the current state. This function will allocate the stack - * if necessary. - * @param new_buffer The new state. - * @param yyscanner The scanner object. - */ -void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if (new_buffer == NULL) - return; - - yyensure_buffer_stack(yyscanner); - - /* This block is copied from yy_switch_to_buffer. */ - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *yyg->yy_c_buf_p = yyg->yy_hold_char; - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; - } - - /* Only push if top exists. Otherwise, replace top. */ - if (YY_CURRENT_BUFFER) - yyg->yy_buffer_stack_top++; - YY_CURRENT_BUFFER_LVALUE = new_buffer; - - /* copied from yy_switch_to_buffer. */ - yy_load_buffer_state(yyscanner ); - yyg->yy_did_buffer_switch_on_eof = 1; -} - -/** Removes and deletes the top of the stack, if present. - * The next element becomes the new top. - * @param yyscanner The scanner object. - */ -void yypop_buffer_state (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if (!YY_CURRENT_BUFFER) - return; - - yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); - YY_CURRENT_BUFFER_LVALUE = NULL; - if (yyg->yy_buffer_stack_top > 0) - --yyg->yy_buffer_stack_top; - - if (YY_CURRENT_BUFFER) { - yy_load_buffer_state(yyscanner ); - yyg->yy_did_buffer_switch_on_eof = 1; - } -} - -/* Allocates the stack if it does not exist. - * Guarantees space for at least one push. - */ -static void yyensure_buffer_stack (yyscan_t yyscanner) -{ - int num_to_alloc; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (!yyg->yy_buffer_stack) { - - /* First allocation is just for 2 elements, since we don't know if this - * scanner will even need a stack. We use 2 instead of 1 to avoid an - * immediate realloc on the next call. - */ - num_to_alloc = 1; - yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc - (num_to_alloc * sizeof(struct yy_buffer_state*) - , yyscanner); - if ( ! yyg->yy_buffer_stack ) - YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); - - memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - - yyg->yy_buffer_stack_max = num_to_alloc; - yyg->yy_buffer_stack_top = 0; - return; - } - - if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ - - /* Increase the buffer to prepare for a possible push. */ - int grow_size = 8 /* arbitrary grow size */; - - num_to_alloc = yyg->yy_buffer_stack_max + grow_size; - yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc - (yyg->yy_buffer_stack, - num_to_alloc * sizeof(struct yy_buffer_state*) - , yyscanner); - if ( ! yyg->yy_buffer_stack ) - YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); - - /* zero only the new slots.*/ - memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); - yyg->yy_buffer_stack_max = num_to_alloc; - } -} - -/** Setup the input buffer state to scan directly from a user-specified character buffer. - * @param base the character buffer - * @param size the size in bytes of the character buffer - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - - if ( size < 2 || - base[size-2] != YY_END_OF_BUFFER_CHAR || - base[size-1] != YY_END_OF_BUFFER_CHAR ) - /* They forgot to leave room for the EOB's. */ - return 0; - - b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); - - b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ - b->yy_buf_pos = b->yy_ch_buf = base; - b->yy_is_our_buffer = 0; - b->yy_input_file = 0; - b->yy_n_chars = b->yy_buf_size; - b->yy_is_interactive = 0; - b->yy_at_bol = 1; - b->yy_fill_buffer = 0; - b->yy_buffer_status = YY_BUFFER_NEW; - - yy_switch_to_buffer(b ,yyscanner ); - - return b; -} - -/** Setup the input buffer state to scan a string. The next call to yylex() will - * scan from a @e copy of @a str. - * @param yystr a NUL-terminated string to scan - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - * @note If you want to scan bytes that may contain NUL values, then use - * yy_scan_bytes() instead. - */ -YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) -{ - - return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); -} - -/** Setup the input buffer state to scan the given bytes. The next call to yylex() will - * scan from a @e copy of @a bytes. - * @param bytes the byte buffer to scan - * @param len the number of bytes in the buffer pointed to by @a bytes. - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - int i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = _yybytes_len + 2; - buf = (char *) yyalloc(n ,yyscanner ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - - for ( i = 0; i < _yybytes_len; ++i ) - buf[i] = yybytes[i]; - - buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; - - b = yy_scan_buffer(buf,n ,yyscanner); - if ( ! b ) - YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); - - /* It's okay to grow etc. this buffer, and we should throw it - * away when we're done. - */ - b->yy_is_our_buffer = 1; - - return b; -} - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) -{ - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); -} - -/* Redefine yyless() so it works in section 3 code. */ - -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - yytext[yyleng] = yyg->yy_hold_char; \ - yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ - yyg->yy_hold_char = *yyg->yy_c_buf_p; \ - *yyg->yy_c_buf_p = '\0'; \ - yyleng = yyless_macro_arg; \ - } \ - while ( 0 ) - -/* Accessor methods (get/set functions) to struct members. */ - -/** Get the user-defined data for this scanner. - * @param yyscanner The scanner object. - */ -YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyextra; -} - -/** Get the current line number. - * @param yyscanner The scanner object. - */ -int yyget_lineno (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (! YY_CURRENT_BUFFER) - return 0; - - return yylineno; -} - -/** Get the current column number. - * @param yyscanner The scanner object. - */ -int yyget_column (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (! YY_CURRENT_BUFFER) - return 0; - - return yycolumn; -} - -/** Get the input stream. - * @param yyscanner The scanner object. - */ -FILE *yyget_in (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyin; -} - -/** Get the output stream. - * @param yyscanner The scanner object. - */ -FILE *yyget_out (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyout; -} - -/** Get the length of the current token. - * @param yyscanner The scanner object. - */ -int yyget_leng (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyleng; -} - -/** Get the current token. - * @param yyscanner The scanner object. - */ - -char *yyget_text (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yytext; -} - -/** Set the user-defined data. This data is never touched by the scanner. - * @param user_defined The data to be associated with this scanner. - * @param yyscanner The scanner object. - */ -void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyextra = user_defined ; -} - -/** Set the current line number. - * @param line_number - * @param yyscanner The scanner object. - */ -void yyset_lineno (int line_number , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* lineno is only valid if an input buffer exists. */ - if (! YY_CURRENT_BUFFER ) - yy_fatal_error( "yyset_lineno called with no buffer" , yyscanner); - - yylineno = line_number; -} - -/** Set the current column. - * @param line_number - * @param yyscanner The scanner object. - */ -void yyset_column (int column_no , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* column is only valid if an input buffer exists. */ - if (! YY_CURRENT_BUFFER ) - yy_fatal_error( "yyset_column called with no buffer" , yyscanner); - - yycolumn = column_no; -} - -/** Set the input stream. This does not discard the current - * input buffer. - * @param in_str A readable stream. - * @param yyscanner The scanner object. - * @see yy_switch_to_buffer - */ -void yyset_in (FILE * in_str , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyin = in_str ; -} - -void yyset_out (FILE * out_str , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyout = out_str ; -} - -int yyget_debug (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yy_flex_debug; -} - -void yyset_debug (int bdebug , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yy_flex_debug = bdebug ; -} - -/* Accessor methods for yylval and yylloc */ - -YYSTYPE * yyget_lval (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yylval; -} - -void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yylval = yylval_param; -} - -YYLTYPE *yyget_lloc (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yylloc; -} - -void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yylloc = yylloc_param; -} - -/* User-visible API */ - -/* yylex_init is special because it creates the scanner itself, so it is - * the ONLY reentrant function that doesn't take the scanner as the last argument. - * That's why we explicitly handle the declaration, instead of using our macros. - */ - -int yylex_init(yyscan_t* ptr_yy_globals) - -{ - if (ptr_yy_globals == NULL){ - errno = EINVAL; - return 1; - } - - *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); - - if (*ptr_yy_globals == NULL){ - errno = ENOMEM; - return 1; - } - - /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ - memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); - - return yy_init_globals ( *ptr_yy_globals ); -} - -/* yylex_init_extra has the same functionality as yylex_init, but follows the - * convention of taking the scanner as the last argument. Note however, that - * this is a *pointer* to a scanner, as it will be allocated by this call (and - * is the reason, too, why this function also must handle its own declaration). - * The user defined value in the first argument will be available to yyalloc in - * the yyextra field. - */ - -int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) - -{ - struct yyguts_t dummy_yyguts; - - yyset_extra (yy_user_defined, &dummy_yyguts); - - if (ptr_yy_globals == NULL){ - errno = EINVAL; - return 1; - } - - *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); - - if (*ptr_yy_globals == NULL){ - errno = ENOMEM; - return 1; - } - - /* By setting to 0xAA, we expose bugs in - yy_init_globals. Leave at 0x00 for releases. */ - memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); - - yyset_extra (yy_user_defined, *ptr_yy_globals); - - return yy_init_globals ( *ptr_yy_globals ); -} - -static int yy_init_globals (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - /* Initialization is the same as for the non-reentrant scanner. - * This function is called from yylex_destroy(), so don't allocate here. - */ - - yyg->yy_buffer_stack = 0; - yyg->yy_buffer_stack_top = 0; - yyg->yy_buffer_stack_max = 0; - yyg->yy_c_buf_p = (char *) 0; - yyg->yy_init = 0; - yyg->yy_start = 0; - - yyg->yy_start_stack_ptr = 0; - yyg->yy_start_stack_depth = 0; - yyg->yy_start_stack = NULL; - -/* Defined in main.c */ -#ifdef YY_STDINIT - yyin = stdin; - yyout = stdout; -#else - yyin = (FILE *) 0; - yyout = (FILE *) 0; -#endif - - /* For future reference: Set errno on error, since we are called by - * yylex_init() - */ - return 0; -} - -/* yylex_destroy is for both reentrant and non-reentrant scanners. */ -int yylex_destroy (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* Pop the buffer stack, destroying each element. */ - while(YY_CURRENT_BUFFER){ - yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); - YY_CURRENT_BUFFER_LVALUE = NULL; - yypop_buffer_state(yyscanner); - } - - /* Destroy the stack itself. */ - yyfree(yyg->yy_buffer_stack ,yyscanner); - yyg->yy_buffer_stack = NULL; - - /* Destroy the start condition stack. */ - yyfree(yyg->yy_start_stack ,yyscanner ); - yyg->yy_start_stack = NULL; - - /* Reset the globals. This is important in a non-reentrant scanner so the next time - * yylex() is called, initialization will occur. */ - yy_init_globals( yyscanner); - - /* Destroy the main struct (reentrant only). */ - yyfree ( yyscanner , yyscanner ); - yyscanner = NULL; - return 0; -} - -/* - * Internal utility routines. - */ - -#ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) -{ - register int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; -} -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) -{ - register int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; -} -#endif - -void *yyalloc (yy_size_t size , yyscan_t yyscanner) -{ - return (void *) malloc( size ); -} - -void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) -{ - /* The cast to (char *) in the following accommodates both - * implementations that use char* generic pointers, and those - * that use void* generic pointers. It works with the latter - * because both ANSI C and C++ allow castless assignment from - * any pointer type to void*, and deal with argument conversions - * as though doing an assignment. - */ - return (void *) realloc( (char *) ptr, size ); -} - -void yyfree (void * ptr , yyscan_t yyscanner) -{ - free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ -} - -#define YYTABLES_NAME "yytables" - -#line 481 "program_lexer.l" - - - -void -_mesa_program_lexer_ctor(void **scanner, struct asm_parser_state *state, - const char *string, size_t len) -{ - yylex_init_extra(state,scanner); - yy_scan_bytes(string,len,*scanner); -} - -void -_mesa_program_lexer_dtor(void *scanner) -{ - yylex_destroy(scanner); -} - diff --git a/src/mesa/shader/nvfragparse.c b/src/mesa/shader/nvfragparse.c deleted file mode 100644 index 0de3c5804d..0000000000 --- a/src/mesa/shader/nvfragparse.c +++ /dev/null @@ -1,1588 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file nvfragparse.c - * NVIDIA fragment program parser. - * \author Brian Paul - */ - -/* - * Regarding GL_NV_fragment_program: - * - * Portions of this software may use or implement intellectual - * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims - * any and all warranties with respect to such intellectual property, - * including any use thereof or modifications thereto. - */ - -#include "main/glheader.h" -#include "main/context.h" -#include "main/imports.h" -#include "main/macros.h" -#include "program.h" -#include "prog_parameter.h" -#include "prog_print.h" -#include "prog_instruction.h" -#include "nvfragparse.h" - - -#define INPUT_1V 1 -#define INPUT_2V 2 -#define INPUT_3V 3 -#define INPUT_1S 4 -#define INPUT_2S 5 -#define INPUT_CC 6 -#define INPUT_1V_T 7 /* one source vector, plus textureId */ -#define INPUT_3V_T 8 /* one source vector, plus textureId */ -#define INPUT_NONE 9 -#define INPUT_1V_S 10 /* a string and a vector register */ -#define OUTPUT_V 20 -#define OUTPUT_S 21 -#define OUTPUT_NONE 22 - -/* IRIX defines some of these */ -#undef _R -#undef _H -#undef _X -#undef _C -#undef _S - -/* Optional suffixes */ -#define _R FLOAT32 /* float */ -#define _H FLOAT16 /* half-float */ -#define _X FIXED12 /* fixed */ -#define _C 0x08 /* set cond codes */ -#define _S 0x10 /* saturate, clamp result to [0,1] */ - -struct instruction_pattern { - const char *name; - enum prog_opcode opcode; - GLuint inputs; - GLuint outputs; - GLuint suffixes; -}; - -static const struct instruction_pattern Instructions[] = { - { "ADD", OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "COS", OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, - { "DDX", OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, - { "DDY", OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, - { "DP3", OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S }, - { "DP4", OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S }, - { "DST", OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H | _C | _S }, - { "EX2", OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, - { "FLR", OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "FRC", OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "KIL", OPCODE_KIL_NV, INPUT_CC, OUTPUT_NONE, 0 }, - { "LG2", OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, - { "LIT", OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, - { "LRP", OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "MAD", OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "MAX", OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "MIN", OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "MOV", OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "MUL", OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "PK2H", OPCODE_PK2H, INPUT_1V, OUTPUT_S, 0 }, - { "PK2US", OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0 }, - { "PK4B", OPCODE_PK4B, INPUT_1V, OUTPUT_S, 0 }, - { "PK4UB", OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0 }, - { "POW", OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H | _C | _S }, - { "RCP", OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, - { "RFL", OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H | _C | _S }, - { "RSQ", OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, - { "SEQ", OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "SFL", OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "SGE", OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "SGT", OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "SIN", OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, - { "SLE", OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "SLT", OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "SNE", OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "STR", OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "SUB", OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, - { "TEX", OPCODE_TEX, INPUT_1V_T, OUTPUT_V, _C | _S }, - { "TXD", OPCODE_TXD, INPUT_3V_T, OUTPUT_V, _C | _S }, - { "TXP", OPCODE_TXP_NV, INPUT_1V_T, OUTPUT_V, _C | _S }, - { "UP2H", OPCODE_UP2H, INPUT_1S, OUTPUT_V, _C | _S }, - { "UP2US", OPCODE_UP2US, INPUT_1S, OUTPUT_V, _C | _S }, - { "UP4B", OPCODE_UP4B, INPUT_1S, OUTPUT_V, _C | _S }, - { "UP4UB", OPCODE_UP4UB, INPUT_1S, OUTPUT_V, _C | _S }, - { "X2D", OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H | _C | _S }, - { "PRINT", OPCODE_PRINT, INPUT_1V_S, OUTPUT_NONE, 0 }, - { NULL, (enum prog_opcode) -1, 0, 0, 0 } -}; - - -/* - * Information needed or computed during parsing. - * Remember, we can't modify the target program object until we've - * _successfully_ parsed the program text. - */ -struct parse_state { - GLcontext *ctx; - const GLubyte *start; /* start of program string */ - const GLubyte *pos; /* current position */ - const GLubyte *curLine; - struct gl_fragment_program *program; /* current program */ - - struct gl_program_parameter_list *parameters; - - GLuint numInst; /* number of instructions parsed */ - GLuint inputsRead; /* bitmask of input registers used */ - GLuint outputsWritten; /* bitmask of 1 << FRAG_OUTPUT_* bits */ - GLuint texturesUsed[MAX_TEXTURE_IMAGE_UNITS]; -}; - - - -/* - * Called whenever we find an error during parsing. - */ -static void -record_error(struct parse_state *parseState, const char *msg, int lineNo) -{ -#ifdef DEBUG - GLint line, column; - const GLubyte *lineStr; - lineStr = _mesa_find_line_column(parseState->start, - parseState->pos, &line, &column); - _mesa_debug(parseState->ctx, - "nvfragparse.c(%d): line %d, column %d:%s (%s)\n", - lineNo, line, column, (char *) lineStr, msg); - free((void *) lineStr); -#else - (void) lineNo; -#endif - - /* Check that no error was already recorded. Only record the first one. */ - if (parseState->ctx->Program.ErrorString[0] == 0) { - _mesa_set_program_error(parseState->ctx, - parseState->pos - parseState->start, - msg); - } -} - - -#define RETURN_ERROR \ -do { \ - record_error(parseState, "Unexpected end of input.", __LINE__); \ - return GL_FALSE; \ -} while(0) - -#define RETURN_ERROR1(msg) \ -do { \ - record_error(parseState, msg, __LINE__); \ - return GL_FALSE; \ -} while(0) - -#define RETURN_ERROR2(msg1, msg2) \ -do { \ - char err[1000]; \ - sprintf(err, "%s %s", msg1, msg2); \ - record_error(parseState, err, __LINE__); \ - return GL_FALSE; \ -} while(0) - - - - -/* - * Search a list of instruction structures for a match. - */ -static struct instruction_pattern -MatchInstruction(const GLubyte *token) -{ - const struct instruction_pattern *inst; - struct instruction_pattern result; - - result.name = NULL; - result.opcode = MAX_OPCODE; /* i.e. invalid instruction */ - result.inputs = 0; - result.outputs = 0; - result.suffixes = 0; - - for (inst = Instructions; inst->name; inst++) { - if (strncmp((const char *) token, inst->name, 3) == 0) { - /* matched! */ - int i = 3; - result = *inst; - result.suffixes = 0; - /* look at suffix */ - if (token[i] == 'R') { - result.suffixes |= _R; - i++; - } - else if (token[i] == 'H') { - result.suffixes |= _H; - i++; - } - else if (token[i] == 'X') { - result.suffixes |= _X; - i++; - } - if (token[i] == 'C') { - result.suffixes |= _C; - i++; - } - if (token[i] == '_' && token[i+1] == 'S' && - token[i+2] == 'A' && token[i+3] == 'T') { - result.suffixes |= _S; - } - return result; - } - } - - return result; -} - - - - -/**********************************************************************/ - - -static GLboolean IsLetter(GLubyte b) -{ - return (b >= 'a' && b <= 'z') || - (b >= 'A' && b <= 'Z') || - (b == '_') || - (b == '$'); -} - - -static GLboolean IsDigit(GLubyte b) -{ - return b >= '0' && b <= '9'; -} - - -static GLboolean IsWhitespace(GLubyte b) -{ - return b == ' ' || b == '\t' || b == '\n' || b == '\r'; -} - - -/** - * Starting at 'str' find the next token. A token can be an integer, - * an identifier or punctuation symbol. - * \return <= 0 we found an error, else, return number of characters parsed. - */ -static GLint -GetToken(struct parse_state *parseState, GLubyte *token) -{ - const GLubyte *str = parseState->pos; - GLint i = 0, j = 0; - - token[0] = 0; - - /* skip whitespace and comments */ - while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) { - if (str[i] == '#') { - /* skip comment */ - while (str[i] && (str[i] != '\n' && str[i] != '\r')) { - i++; - } - if (str[i] == '\n' || str[i] == '\r') - parseState->curLine = str + i + 1; - } - else { - /* skip whitespace */ - if (str[i] == '\n' || str[i] == '\r') - parseState->curLine = str + i + 1; - i++; - } - } - - if (str[i] == 0) - return -i; - - /* try matching an integer */ - while (str[i] && IsDigit(str[i])) { - token[j++] = str[i++]; - } - if (j > 0 || !str[i]) { - token[j] = 0; - return i; - } - - /* try matching an identifier */ - if (IsLetter(str[i])) { - while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) { - token[j++] = str[i++]; - } - token[j] = 0; - return i; - } - - /* punctuation character */ - if (str[i]) { - token[0] = str[i++]; - token[1] = 0; - return i; - } - - /* end of input */ - token[0] = 0; - return i; -} - - -/** - * Get next token from input stream and increment stream pointer past token. - */ -static GLboolean -Parse_Token(struct parse_state *parseState, GLubyte *token) -{ - GLint i; - i = GetToken(parseState, token); - if (i <= 0) { - parseState->pos += (-i); - return GL_FALSE; - } - parseState->pos += i; - return GL_TRUE; -} - - -/** - * Get next token from input stream but don't increment stream pointer. - */ -static GLboolean -Peek_Token(struct parse_state *parseState, GLubyte *token) -{ - GLint i, len; - i = GetToken(parseState, token); - if (i <= 0) { - parseState->pos += (-i); - return GL_FALSE; - } - len = (GLint) strlen((const char *) token); - parseState->pos += (i - len); - return GL_TRUE; -} - - -/**********************************************************************/ - -static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = { - "WPOS", "COL0", "COL1", "FOGC", - "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL -}; - - - -/**********************************************************************/ - -/** - * Try to match 'pattern' as the next token after any whitespace/comments. - */ -static GLboolean -Parse_String(struct parse_state *parseState, const char *pattern) -{ - const GLubyte *m; - GLint i; - - /* skip whitespace and comments */ - while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') { - if (*parseState->pos == '#') { - while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) { - parseState->pos += 1; - } - if (*parseState->pos == '\n' || *parseState->pos == '\r') - parseState->curLine = parseState->pos + 1; - } - else { - /* skip whitespace */ - if (*parseState->pos == '\n' || *parseState->pos == '\r') - parseState->curLine = parseState->pos + 1; - parseState->pos += 1; - } - } - - /* Try to match the pattern */ - m = parseState->pos; - for (i = 0; pattern[i]; i++) { - if (*m != (GLubyte) pattern[i]) - return GL_FALSE; - m += 1; - } - parseState->pos = m; - - return GL_TRUE; /* success */ -} - - -static GLboolean -Parse_Identifier(struct parse_state *parseState, GLubyte *ident) -{ - if (!Parse_Token(parseState, ident)) - RETURN_ERROR; - if (IsLetter(ident[0])) - return GL_TRUE; - else - RETURN_ERROR1("Expected an identfier"); -} - - -/** - * Parse a floating point constant, or a defined symbol name. - * [+/-]N[.N[eN]] - * Output: number[0 .. 3] will get the value. - */ -static GLboolean -Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number) -{ - char *end = NULL; - - *number = (GLfloat) _mesa_strtof((const char *) parseState->pos, &end); - - if (end && end > (char *) parseState->pos) { - /* got a number */ - parseState->pos = (GLubyte *) end; - number[1] = *number; - number[2] = *number; - number[3] = *number; - return GL_TRUE; - } - else { - /* should be an identifier */ - GLubyte ident[100]; - const GLfloat *constant; - if (!Parse_Identifier(parseState, ident)) - RETURN_ERROR1("Expected an identifier"); - constant = _mesa_lookup_parameter_value(parseState->parameters, - -1, (const char *) ident); - /* XXX Check that it's a constant and not a parameter */ - if (!constant) { - RETURN_ERROR1("Undefined symbol"); - } - else { - COPY_4V(number, constant); - return GL_TRUE; - } - } -} - - - -/** - * Parse a vector constant, one of: - * { float } - * { float, float } - * { float, float, float } - * { float, float, float, float } - */ -static GLboolean -Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec) -{ - /* "{" was already consumed */ - - ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0); - - if (!Parse_ScalarConstant(parseState, vec+0)) /* X */ - return GL_FALSE; - - if (Parse_String(parseState, "}")) { - return GL_TRUE; - } - - if (!Parse_String(parseState, ",")) - RETURN_ERROR1("Expected comma in vector constant"); - - if (!Parse_ScalarConstant(parseState, vec+1)) /* Y */ - return GL_FALSE; - - if (Parse_String(parseState, "}")) { - return GL_TRUE; - } - - if (!Parse_String(parseState, ",")) - RETURN_ERROR1("Expected comma in vector constant"); - - if (!Parse_ScalarConstant(parseState, vec+2)) /* Z */ - return GL_FALSE; - - if (Parse_String(parseState, "}")) { - return GL_TRUE; - } - - if (!Parse_String(parseState, ",")) - RETURN_ERROR1("Expected comma in vector constant"); - - if (!Parse_ScalarConstant(parseState, vec+3)) /* W */ - return GL_FALSE; - - if (!Parse_String(parseState, "}")) - RETURN_ERROR1("Expected closing brace in vector constant"); - - return GL_TRUE; -} - - -/** - * Parse , or {a, b, c, d}. - * Return number of values in the vector or scalar, or zero if parse error. - */ -static GLuint -Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec) -{ - if (Parse_String(parseState, "{")) { - return Parse_VectorConstant(parseState, vec); - } - else { - GLboolean b = Parse_ScalarConstant(parseState, vec); - if (b) { - vec[1] = vec[2] = vec[3] = vec[0]; - } - return b; - } -} - - -/** - * Parse a texture image source: - * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT] - */ -static GLboolean -Parse_TextureImageId(struct parse_state *parseState, - GLubyte *texUnit, GLubyte *texTargetBit) -{ - GLubyte imageSrc[100]; - GLint unit; - - if (!Parse_Token(parseState, imageSrc)) - RETURN_ERROR; - - if (imageSrc[0] != 'T' || - imageSrc[1] != 'E' || - imageSrc[2] != 'X') { - RETURN_ERROR1("Expected TEX# source"); - } - unit = atoi((const char *) imageSrc + 3); - if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) || - (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) { - RETURN_ERROR1("Invalied TEX# source index"); - } - *texUnit = unit; - - if (!Parse_String(parseState, ",")) - RETURN_ERROR1("Expected ,"); - - if (Parse_String(parseState, "1D")) { - *texTargetBit = TEXTURE_1D_BIT; - } - else if (Parse_String(parseState, "2D")) { - *texTargetBit = TEXTURE_2D_BIT; - } - else if (Parse_String(parseState, "3D")) { - *texTargetBit = TEXTURE_3D_BIT; - } - else if (Parse_String(parseState, "CUBE")) { - *texTargetBit = TEXTURE_CUBE_BIT; - } - else if (Parse_String(parseState, "RECT")) { - *texTargetBit = TEXTURE_RECT_BIT; - } - else { - RETURN_ERROR1("Invalid texture target token"); - } - - /* update record of referenced texture units */ - parseState->texturesUsed[*texUnit] |= *texTargetBit; - if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) { - RETURN_ERROR1("Only one texture target can be used per texture unit."); - } - - return GL_TRUE; -} - - -/** - * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix - * like .wxyz, .xxyy, etc and return the swizzle indexes. - */ -static GLboolean -Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4]) -{ - if (token[1] == 0) { - /* single letter swizzle (scalar) */ - if (token[0] == 'x') - ASSIGN_4V(swizzle, 0, 0, 0, 0); - else if (token[0] == 'y') - ASSIGN_4V(swizzle, 1, 1, 1, 1); - else if (token[0] == 'z') - ASSIGN_4V(swizzle, 2, 2, 2, 2); - else if (token[0] == 'w') - ASSIGN_4V(swizzle, 3, 3, 3, 3); - else - return GL_FALSE; - } - else { - /* 4-component swizzle (vector) */ - GLint k; - for (k = 0; k < 4 && token[k]; k++) { - if (token[k] == 'x') - swizzle[k] = 0; - else if (token[k] == 'y') - swizzle[k] = 1; - else if (token[k] == 'z') - swizzle[k] = 2; - else if (token[k] == 'w') - swizzle[k] = 3; - else - return GL_FALSE; - } - if (k != 4) - return GL_FALSE; - } - return GL_TRUE; -} - - -static GLboolean -Parse_CondCodeMask(struct parse_state *parseState, - struct prog_dst_register *dstReg) -{ - if (Parse_String(parseState, "EQ")) - dstReg->CondMask = COND_EQ; - else if (Parse_String(parseState, "GE")) - dstReg->CondMask = COND_GE; - else if (Parse_String(parseState, "GT")) - dstReg->CondMask = COND_GT; - else if (Parse_String(parseState, "LE")) - dstReg->CondMask = COND_LE; - else if (Parse_String(parseState, "LT")) - dstReg->CondMask = COND_LT; - else if (Parse_String(parseState, "NE")) - dstReg->CondMask = COND_NE; - else if (Parse_String(parseState, "TR")) - dstReg->CondMask = COND_TR; - else if (Parse_String(parseState, "FL")) - dstReg->CondMask = COND_FL; - else - RETURN_ERROR1("Invalid condition code mask"); - - /* look for optional .xyzw swizzle */ - if (Parse_String(parseState, ".")) { - GLubyte token[100]; - GLuint swz[4]; - - if (!Parse_Token(parseState, token)) /* get xyzw suffix */ - RETURN_ERROR; - - if (!Parse_SwizzleSuffix(token, swz)) - RETURN_ERROR1("Invalid swizzle suffix"); - - dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]); - } - - return GL_TRUE; -} - - -/** - * Parse a temporary register: Rnn or Hnn - */ -static GLboolean -Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum) -{ - GLubyte token[100]; - - /* Should be 'R##' or 'H##' */ - if (!Parse_Token(parseState, token)) - RETURN_ERROR; - if (token[0] != 'R' && token[0] != 'H') - RETURN_ERROR1("Expected R## or H##"); - - if (IsDigit(token[1])) { - GLint reg = atoi((const char *) (token + 1)); - if (token[0] == 'H') - reg += 32; - if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS) - RETURN_ERROR1("Invalid temporary register name"); - *tempRegNum = reg; - } - else { - RETURN_ERROR1("Invalid temporary register name"); - } - - return GL_TRUE; -} - - -/** - * Parse a write-only dummy register: RC or HC. - */ -static GLboolean -Parse_DummyReg(struct parse_state *parseState, GLint *regNum) -{ - if (Parse_String(parseState, "RC")) { - *regNum = 0; - } - else if (Parse_String(parseState, "HC")) { - *regNum = 1; - } - else { - RETURN_ERROR1("Invalid write-only register name"); - } - - return GL_TRUE; -} - - -/** - * Parse a program local parameter register "p[##]" - */ -static GLboolean -Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum) -{ - GLubyte token[100]; - - if (!Parse_String(parseState, "p[")) - RETURN_ERROR1("Expected p["); - - if (!Parse_Token(parseState, token)) - RETURN_ERROR; - - if (IsDigit(token[0])) { - /* a numbered program parameter register */ - GLint reg = atoi((const char *) token); - if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS) - RETURN_ERROR1("Invalid constant program number"); - *regNum = reg; - } - else { - RETURN_ERROR; - } - - if (!Parse_String(parseState, "]")) - RETURN_ERROR1("Expected ]"); - - return GL_TRUE; -} - - -/** - * Parse f[name] - fragment input register - */ -static GLboolean -Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum) -{ - GLubyte token[100]; - GLint j; - - /* Match 'f[' */ - if (!Parse_String(parseState, "f[")) - RETURN_ERROR1("Expected f["); - - /* get and look for match */ - if (!Parse_Token(parseState, token)) { - RETURN_ERROR; - } - for (j = 0; InputRegisters[j]; j++) { - if (strcmp((const char *) token, InputRegisters[j]) == 0) { - *tempRegNum = j; - parseState->inputsRead |= (1 << j); - break; - } - } - if (!InputRegisters[j]) { - /* unknown input register label */ - RETURN_ERROR2("Invalid register name", token); - } - - /* Match '[' */ - if (!Parse_String(parseState, "]")) - RETURN_ERROR1("Expected ]"); - - return GL_TRUE; -} - - -static GLboolean -Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum) -{ - GLubyte token[100]; - - /* Match "o[" */ - if (!Parse_String(parseState, "o[")) - RETURN_ERROR1("Expected o["); - - /* Get output reg name */ - if (!Parse_Token(parseState, token)) - RETURN_ERROR; - - /* try to match an output register name */ - if (strcmp((char *) token, "COLR") == 0 || - strcmp((char *) token, "COLH") == 0) { - /* note that we don't distinguish between COLR and COLH */ - *outputRegNum = FRAG_RESULT_COLOR; - parseState->outputsWritten |= (1 << FRAG_RESULT_COLOR); - } - else if (strcmp((char *) token, "DEPR") == 0) { - *outputRegNum = FRAG_RESULT_DEPTH; - parseState->outputsWritten |= (1 << FRAG_RESULT_DEPTH); - } - else { - RETURN_ERROR1("Invalid output register name"); - } - - /* Match ']' */ - if (!Parse_String(parseState, "]")) - RETURN_ERROR1("Expected ]"); - - return GL_TRUE; -} - - -static GLboolean -Parse_MaskedDstReg(struct parse_state *parseState, - struct prog_dst_register *dstReg) -{ - GLubyte token[100]; - GLint idx; - - /* Dst reg can be R, H, o[n], RC or HC */ - if (!Peek_Token(parseState, token)) - RETURN_ERROR; - - if (strcmp((const char *) token, "RC") == 0 || - strcmp((const char *) token, "HC") == 0) { - /* a write-only register */ - dstReg->File = PROGRAM_WRITE_ONLY; - if (!Parse_DummyReg(parseState, &idx)) - RETURN_ERROR; - dstReg->Index = idx; - } - else if (token[0] == 'R' || token[0] == 'H') { - /* a temporary register */ - dstReg->File = PROGRAM_TEMPORARY; - if (!Parse_TempReg(parseState, &idx)) - RETURN_ERROR; - dstReg->Index = idx; - } - else if (token[0] == 'o') { - /* an output register */ - dstReg->File = PROGRAM_OUTPUT; - if (!Parse_OutputReg(parseState, &idx)) - RETURN_ERROR; - dstReg->Index = idx; - } - else { - RETURN_ERROR1("Invalid destination register name"); - } - - /* Parse optional write mask */ - if (Parse_String(parseState, ".")) { - /* got a mask */ - GLint k = 0; - - if (!Parse_Token(parseState, token)) /* get xyzw writemask */ - RETURN_ERROR; - - dstReg->WriteMask = 0; - - if (token[k] == 'x') { - dstReg->WriteMask |= WRITEMASK_X; - k++; - } - if (token[k] == 'y') { - dstReg->WriteMask |= WRITEMASK_Y; - k++; - } - if (token[k] == 'z') { - dstReg->WriteMask |= WRITEMASK_Z; - k++; - } - if (token[k] == 'w') { - dstReg->WriteMask |= WRITEMASK_W; - k++; - } - if (k == 0) { - RETURN_ERROR1("Invalid writemask character"); - } - - } - else { - dstReg->WriteMask = WRITEMASK_XYZW; - } - - /* optional condition code mask */ - if (Parse_String(parseState, "(")) { - /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */ - /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */ - if (!Parse_CondCodeMask(parseState, dstReg)) - RETURN_ERROR; - - if (!Parse_String(parseState, ")")) /* consume ")" */ - RETURN_ERROR1("Expected )"); - - return GL_TRUE; - } - else { - /* no cond code mask */ - dstReg->CondMask = COND_TR; - dstReg->CondSwizzle = SWIZZLE_NOOP; - return GL_TRUE; - } -} - - -/** - * Parse a vector source (register, constant, etc): - * ::= - * | - * ::= "|" "|" - */ -static GLboolean -Parse_VectorSrc(struct parse_state *parseState, - struct prog_src_register *srcReg) -{ - GLfloat sign = 1.0F; - GLubyte token[100]; - GLint idx; - GLuint negateBase, negateAbs; - - /* - * First, take care of +/- and absolute value stuff. - */ - if (Parse_String(parseState, "-")) - sign = -1.0F; - else if (Parse_String(parseState, "+")) - sign = +1.0F; - - if (Parse_String(parseState, "|")) { - srcReg->Abs = GL_TRUE; - negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; - - if (Parse_String(parseState, "-")) - negateBase = NEGATE_XYZW; - else if (Parse_String(parseState, "+")) - negateBase = NEGATE_NONE; - else - negateBase = NEGATE_NONE; - } - else { - srcReg->Abs = GL_FALSE; - negateAbs = NEGATE_NONE; - negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; - } - - srcReg->Negate = srcReg->Abs ? negateAbs : negateBase; - - /* This should be the real src vector/register name */ - if (!Peek_Token(parseState, token)) - RETURN_ERROR; - - /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar - * literal or vector literal. - */ - if (token[0] == 'R' || token[0] == 'H') { - srcReg->File = PROGRAM_TEMPORARY; - if (!Parse_TempReg(parseState, &idx)) - RETURN_ERROR; - srcReg->Index = idx; - } - else if (token[0] == 'f') { - /* XXX this might be an identifier! */ - srcReg->File = PROGRAM_INPUT; - if (!Parse_FragReg(parseState, &idx)) - RETURN_ERROR; - srcReg->Index = idx; - } - else if (token[0] == 'p') { - /* XXX this might be an identifier! */ - srcReg->File = PROGRAM_LOCAL_PARAM; - if (!Parse_ProgramParamReg(parseState, &idx)) - RETURN_ERROR; - srcReg->Index = idx; - } - else if (IsLetter(token[0])){ - GLubyte ident[100]; - GLint paramIndex; - if (!Parse_Identifier(parseState, ident)) - RETURN_ERROR; - paramIndex = _mesa_lookup_parameter_index(parseState->parameters, - -1, (const char *) ident); - if (paramIndex < 0) { - RETURN_ERROR2("Undefined constant or parameter: ", ident); - } - srcReg->File = PROGRAM_NAMED_PARAM; - srcReg->Index = paramIndex; - } - else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){ - /* literal scalar constant */ - GLfloat values[4]; - GLuint paramIndex; - if (!Parse_ScalarConstant(parseState, values)) - RETURN_ERROR; - paramIndex = _mesa_add_unnamed_constant(parseState->parameters, - values, 4, NULL); - srcReg->File = PROGRAM_NAMED_PARAM; - srcReg->Index = paramIndex; - } - else if (token[0] == '{'){ - /* literal vector constant */ - GLfloat values[4]; - GLuint paramIndex; - (void) Parse_String(parseState, "{"); - if (!Parse_VectorConstant(parseState, values)) - RETURN_ERROR; - paramIndex = _mesa_add_unnamed_constant(parseState->parameters, - values, 4, NULL); - srcReg->File = PROGRAM_NAMED_PARAM; - srcReg->Index = paramIndex; - } - else { - RETURN_ERROR2("Invalid source register name", token); - } - - /* init swizzle fields */ - srcReg->Swizzle = SWIZZLE_NOOP; - - /* Look for optional swizzle suffix */ - if (Parse_String(parseState, ".")) { - GLuint swz[4]; - - if (!Parse_Token(parseState, token)) - RETURN_ERROR; - - if (!Parse_SwizzleSuffix(token, swz)) - RETURN_ERROR1("Invalid swizzle suffix"); - - srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]); - } - - /* Finish absolute value */ - if (srcReg->Abs && !Parse_String(parseState, "|")) { - RETURN_ERROR1("Expected |"); - } - - return GL_TRUE; -} - - -static GLboolean -Parse_ScalarSrcReg(struct parse_state *parseState, - struct prog_src_register *srcReg) -{ - GLubyte token[100]; - GLfloat sign = 1.0F; - GLboolean needSuffix = GL_TRUE; - GLint idx; - GLuint negateBase, negateAbs; - - /* - * First, take care of +/- and absolute value stuff. - */ - if (Parse_String(parseState, "-")) - sign = -1.0F; - else if (Parse_String(parseState, "+")) - sign = +1.0F; - - if (Parse_String(parseState, "|")) { - srcReg->Abs = GL_TRUE; - negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; - - if (Parse_String(parseState, "-")) - negateBase = NEGATE_XYZW; - else if (Parse_String(parseState, "+")) - negateBase = NEGATE_NONE; - else - negateBase = NEGATE_NONE; - } - else { - srcReg->Abs = GL_FALSE; - negateAbs = NEGATE_NONE; - negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; - } - - srcReg->Negate = srcReg->Abs ? negateAbs : negateBase; - - if (!Peek_Token(parseState, token)) - RETURN_ERROR; - - /* Src reg can be R, H or a named fragment attrib */ - if (token[0] == 'R' || token[0] == 'H') { - srcReg->File = PROGRAM_TEMPORARY; - if (!Parse_TempReg(parseState, &idx)) - RETURN_ERROR; - srcReg->Index = idx; - } - else if (token[0] == 'f') { - srcReg->File = PROGRAM_INPUT; - if (!Parse_FragReg(parseState, &idx)) - RETURN_ERROR; - srcReg->Index = idx; - } - else if (token[0] == '{') { - /* vector literal */ - GLfloat values[4]; - GLuint paramIndex; - (void) Parse_String(parseState, "{"); - if (!Parse_VectorConstant(parseState, values)) - RETURN_ERROR; - paramIndex = _mesa_add_unnamed_constant(parseState->parameters, - values, 4, NULL); - srcReg->File = PROGRAM_NAMED_PARAM; - srcReg->Index = paramIndex; - } - else if (IsLetter(token[0])){ - /* named param/constant */ - GLubyte ident[100]; - GLint paramIndex; - if (!Parse_Identifier(parseState, ident)) - RETURN_ERROR; - paramIndex = _mesa_lookup_parameter_index(parseState->parameters, - -1, (const char *) ident); - if (paramIndex < 0) { - RETURN_ERROR2("Undefined constant or parameter: ", ident); - } - srcReg->File = PROGRAM_NAMED_PARAM; - srcReg->Index = paramIndex; - } - else if (IsDigit(token[0])) { - /* scalar literal */ - GLfloat values[4]; - GLuint paramIndex; - if (!Parse_ScalarConstant(parseState, values)) - RETURN_ERROR; - paramIndex = _mesa_add_unnamed_constant(parseState->parameters, - values, 4, NULL); - srcReg->Index = paramIndex; - srcReg->File = PROGRAM_NAMED_PARAM; - needSuffix = GL_FALSE; - } - else { - RETURN_ERROR2("Invalid scalar source argument", token); - } - - srcReg->Swizzle = 0; - if (needSuffix) { - /* parse .[xyzw] suffix */ - if (!Parse_String(parseState, ".")) - RETURN_ERROR1("Expected ."); - - if (!Parse_Token(parseState, token)) - RETURN_ERROR; - - if (token[0] == 'x' && token[1] == 0) { - srcReg->Swizzle = 0; - } - else if (token[0] == 'y' && token[1] == 0) { - srcReg->Swizzle = 1; - } - else if (token[0] == 'z' && token[1] == 0) { - srcReg->Swizzle = 2; - } - else if (token[0] == 'w' && token[1] == 0) { - srcReg->Swizzle = 3; - } - else { - RETURN_ERROR1("Invalid scalar source suffix"); - } - } - - /* Finish absolute value */ - if (srcReg->Abs && !Parse_String(parseState, "|")) { - RETURN_ERROR1("Expected |"); - } - - return GL_TRUE; -} - - -static GLboolean -Parse_PrintInstruction(struct parse_state *parseState, - struct prog_instruction *inst) -{ - const GLubyte *str; - GLubyte *msg; - GLuint len; - GLint idx; - - /* The first argument is a literal string 'just like this' */ - if (!Parse_String(parseState, "'")) - RETURN_ERROR1("Expected '"); - - str = parseState->pos; - for (len = 0; str[len] != '\''; len++) /* find closing quote */ - ; - parseState->pos += len + 1; - msg = (GLubyte*) malloc(len + 1); - - memcpy(msg, str, len); - msg[len] = 0; - inst->Data = msg; - - if (Parse_String(parseState, ",")) { - /* got an optional register to print */ - GLubyte token[100]; - GetToken(parseState, token); - if (token[0] == 'o') { - /* dst reg */ - if (!Parse_OutputReg(parseState, &idx)) - RETURN_ERROR; - inst->SrcReg[0].Index = idx; - inst->SrcReg[0].File = PROGRAM_OUTPUT; - } - else { - /* src reg */ - if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) - RETURN_ERROR; - } - } - else { - inst->SrcReg[0].File = PROGRAM_UNDEFINED; - } - - inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; - inst->SrcReg[0].Abs = GL_FALSE; - inst->SrcReg[0].Negate = NEGATE_NONE; - - return GL_TRUE; -} - - -static GLboolean -Parse_InstructionSequence(struct parse_state *parseState, - struct prog_instruction program[]) -{ - while (1) { - struct prog_instruction *inst = program + parseState->numInst; - struct instruction_pattern instMatch; - GLubyte token[100]; - - /* Initialize the instruction */ - _mesa_init_instructions(inst, 1); - - /* special instructions */ - if (Parse_String(parseState, "DEFINE")) { - GLubyte id[100]; - GLfloat value[7]; /* yes, 7 to be safe */ - if (!Parse_Identifier(parseState, id)) - RETURN_ERROR; - /* XXX make sure id is not a reserved identifer, like R9 */ - if (!Parse_String(parseState, "=")) - RETURN_ERROR1("Expected ="); - if (!Parse_VectorOrScalarConstant(parseState, value)) - RETURN_ERROR; - if (!Parse_String(parseState, ";")) - RETURN_ERROR1("Expected ;"); - if (_mesa_lookup_parameter_index(parseState->parameters, - -1, (const char *) id) >= 0) { - RETURN_ERROR2(id, "already defined"); - } - _mesa_add_named_parameter(parseState->parameters, - (const char *) id, value); - } - else if (Parse_String(parseState, "DECLARE")) { - GLubyte id[100]; - GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */ - if (!Parse_Identifier(parseState, id)) - RETURN_ERROR; - /* XXX make sure id is not a reserved identifer, like R9 */ - if (Parse_String(parseState, "=")) { - if (!Parse_VectorOrScalarConstant(parseState, value)) - RETURN_ERROR; - } - if (!Parse_String(parseState, ";")) - RETURN_ERROR1("Expected ;"); - if (_mesa_lookup_parameter_index(parseState->parameters, - -1, (const char *) id) >= 0) { - RETURN_ERROR2(id, "already declared"); - } - _mesa_add_named_parameter(parseState->parameters, - (const char *) id, value); - } - else if (Parse_String(parseState, "END")) { - inst->Opcode = OPCODE_END; - parseState->numInst++; - if (Parse_Token(parseState, token)) { - RETURN_ERROR1("Code after END opcode."); - } - break; - } - else { - /* general/arithmetic instruction */ - - /* get token */ - if (!Parse_Token(parseState, token)) { - RETURN_ERROR1("Missing END instruction."); - } - - /* try to find matching instuction */ - instMatch = MatchInstruction(token); - if (instMatch.opcode >= MAX_OPCODE) { - /* bad instruction name */ - RETURN_ERROR2("Unexpected token: ", token); - } - - inst->Opcode = instMatch.opcode; - inst->Precision = instMatch.suffixes & (_R | _H | _X); - inst->SaturateMode = (instMatch.suffixes & (_S)) - ? SATURATE_ZERO_ONE : SATURATE_OFF; - inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE; - - /* - * parse the input and output operands - */ - if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) { - if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) - RETURN_ERROR; - if (!Parse_String(parseState, ",")) - RETURN_ERROR1("Expected ,"); - } - else if (instMatch.outputs == OUTPUT_NONE) { - if (instMatch.opcode == OPCODE_KIL_NV) { - /* This is a little weird, the cond code info is in - * the dest register. - */ - if (!Parse_CondCodeMask(parseState, &inst->DstReg)) - RETURN_ERROR; - } - else { - ASSERT(instMatch.opcode == OPCODE_PRINT); - } - } - - if (instMatch.inputs == INPUT_1V) { - if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) - RETURN_ERROR; - } - else if (instMatch.inputs == INPUT_2V) { - if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) - RETURN_ERROR; - if (!Parse_String(parseState, ",")) - RETURN_ERROR1("Expected ,"); - if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) - RETURN_ERROR; - } - else if (instMatch.inputs == INPUT_3V) { - if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) - RETURN_ERROR; - if (!Parse_String(parseState, ",")) - RETURN_ERROR1("Expected ,"); - if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) - RETURN_ERROR; - if (!Parse_String(parseState, ",")) - RETURN_ERROR1("Expected ,"); - if (!Parse_VectorSrc(parseState, &inst->SrcReg[2])) - RETURN_ERROR; - } - else if (instMatch.inputs == INPUT_1S) { - if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) - RETURN_ERROR; - } - else if (instMatch.inputs == INPUT_2S) { - if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) - RETURN_ERROR; - if (!Parse_String(parseState, ",")) - RETURN_ERROR1("Expected ,"); - if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1])) - RETURN_ERROR; - } - else if (instMatch.inputs == INPUT_CC) { - /* XXX to-do */ - } - else if (instMatch.inputs == INPUT_1V_T) { - GLubyte unit, idx; - if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) - RETURN_ERROR; - if (!Parse_String(parseState, ",")) - RETURN_ERROR1("Expected ,"); - if (!Parse_TextureImageId(parseState, &unit, &idx)) - RETURN_ERROR; - inst->TexSrcUnit = unit; - inst->TexSrcTarget = idx; - } - else if (instMatch.inputs == INPUT_3V_T) { - GLubyte unit, idx; - if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) - RETURN_ERROR; - if (!Parse_String(parseState, ",")) - RETURN_ERROR1("Expected ,"); - if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) - RETURN_ERROR; - if (!Parse_String(parseState, ",")) - RETURN_ERROR1("Expected ,"); - if (!Parse_VectorSrc(parseState, &inst->SrcReg[2])) - RETURN_ERROR; - if (!Parse_String(parseState, ",")) - RETURN_ERROR1("Expected ,"); - if (!Parse_TextureImageId(parseState, &unit, &idx)) - RETURN_ERROR; - inst->TexSrcUnit = unit; - inst->TexSrcTarget = idx; - } - else if (instMatch.inputs == INPUT_1V_S) { - if (!Parse_PrintInstruction(parseState, inst)) - RETURN_ERROR; - } - - /* end of statement semicolon */ - if (!Parse_String(parseState, ";")) - RETURN_ERROR1("Expected ;"); - - parseState->numInst++; - - if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS) - RETURN_ERROR1("Program too long"); - } - } - return GL_TRUE; -} - - - -/** - * Parse/compile the 'str' returning the compiled 'program'. - * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos - * indicates the position of the error in 'str'. - */ -void -_mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget, - const GLubyte *str, GLsizei len, - struct gl_fragment_program *program) -{ - struct parse_state parseState; - struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS]; - struct prog_instruction *newInst; - GLenum target; - GLubyte *programString; - - /* Make a null-terminated copy of the program string */ - programString = (GLubyte *) MALLOC(len + 1); - if (!programString) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); - return; - } - memcpy(programString, str, len); - programString[len] = 0; - - /* Get ready to parse */ - memset(&parseState, 0, sizeof(struct parse_state)); - parseState.ctx = ctx; - parseState.start = programString; - parseState.program = program; - parseState.numInst = 0; - parseState.curLine = programString; - parseState.parameters = _mesa_new_parameter_list(); - - /* Reset error state */ - _mesa_set_program_error(ctx, -1, NULL); - - /* check the program header */ - if (strncmp((const char *) programString, "!!FP1.0", 7) == 0) { - target = GL_FRAGMENT_PROGRAM_NV; - parseState.pos = programString + 7; - } - else if (strncmp((const char *) programString, "!!FCP1.0", 8) == 0) { - /* fragment / register combiner program - not supported */ - _mesa_set_program_error(ctx, 0, "Invalid fragment program header"); - _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); - return; - } - else { - /* invalid header */ - _mesa_set_program_error(ctx, 0, "Invalid fragment program header"); - _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); - return; - } - - /* make sure target and header match */ - if (target != dstTarget) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glLoadProgramNV(target mismatch 0x%x != 0x%x)", - target, dstTarget); - return; - } - - if (Parse_InstructionSequence(&parseState, instBuffer)) { - GLuint u; - /* successful parse! */ - - if (parseState.outputsWritten == 0) { - /* must write at least one output! */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "Invalid fragment program - no outputs written."); - return; - } - - /* copy the compiled instructions */ - assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS); - newInst = _mesa_alloc_instructions(parseState.numInst); - if (!newInst) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); - return; /* out of memory */ - } - _mesa_copy_instructions(newInst, instBuffer, parseState.numInst); - - /* install the program */ - program->Base.Target = target; - if (program->Base.String) { - FREE(program->Base.String); - } - program->Base.String = programString; - program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB; - if (program->Base.Instructions) { - free(program->Base.Instructions); - } - program->Base.Instructions = newInst; - program->Base.NumInstructions = parseState.numInst; - program->Base.InputsRead = parseState.inputsRead; - program->Base.OutputsWritten = parseState.outputsWritten; - for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++) - program->Base.TexturesUsed[u] = parseState.texturesUsed[u]; - - /* save program parameters */ - program->Base.Parameters = parseState.parameters; - - /* allocate registers for declared program parameters */ -#if 00 - _mesa_assign_program_registers(&(program->SymbolTable)); -#endif - -#ifdef DEBUG_foo - printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id); - _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0); - printf("----------------------------------\n"); -#endif - } - else { - /* Error! */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV"); - /* NOTE: _mesa_set_program_error would have been called already */ - } -} - - -const char * -_mesa_nv_fragment_input_register_name(GLuint i) -{ - ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS); - return InputRegisters[i]; -} - diff --git a/src/mesa/shader/nvfragparse.h b/src/mesa/shader/nvfragparse.h deleted file mode 100644 index 544ab80c56..0000000000 --- a/src/mesa/shader/nvfragparse.h +++ /dev/null @@ -1,43 +0,0 @@ - -/* - * Mesa 3-D graphics library - * Version: 5.1 - * - * Copyright (C) 1999-2002 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Brian Paul - */ - - -#ifndef NVFRAGPARSE_H -#define NVFRAGPARSE_H - - -extern void -_mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum target, - const GLubyte *str, GLsizei len, - struct gl_fragment_program *program); - - -extern const char * -_mesa_nv_fragment_input_register_name(GLuint i); - -#endif diff --git a/src/mesa/shader/nvvertparse.c b/src/mesa/shader/nvvertparse.c deleted file mode 100644 index e2afcfd4ce..0000000000 --- a/src/mesa/shader/nvvertparse.c +++ /dev/null @@ -1,1454 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.2 - * - * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file nvvertparse.c - * NVIDIA vertex program parser. - * \author Brian Paul - */ - -/* - * Regarding GL_NV_vertex_program, GL_NV_vertex_program1_1: - * - * Portions of this software may use or implement intellectual - * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims - * any and all warranties with respect to such intellectual property, - * including any use thereof or modifications thereto. - */ - -#include "main/glheader.h" -#include "main/context.h" -#include "main/imports.h" -#include "main/nvprogram.h" -#include "nvvertparse.h" -#include "prog_instruction.h" -#include "prog_parameter.h" -#include "prog_print.h" -#include "program.h" - - -/** - * Current parsing state. This structure is passed among the parsing - * functions and keeps track of the current parser position and various - * program attributes. - */ -struct parse_state { - GLcontext *ctx; - const GLubyte *start; - const GLubyte *pos; - const GLubyte *curLine; - GLboolean isStateProgram; - GLboolean isPositionInvariant; - GLboolean isVersion1_1; - GLbitfield inputsRead; - GLbitfield outputsWritten; - GLboolean anyProgRegsWritten; - GLuint numInst; /* number of instructions parsed */ -}; - - -/* - * Called whenever we find an error during parsing. - */ -static void -record_error(struct parse_state *parseState, const char *msg, int lineNo) -{ -#ifdef DEBUG - GLint line, column; - const GLubyte *lineStr; - lineStr = _mesa_find_line_column(parseState->start, - parseState->pos, &line, &column); - _mesa_debug(parseState->ctx, - "nvfragparse.c(%d): line %d, column %d:%s (%s)\n", - lineNo, line, column, (char *) lineStr, msg); - free((void *) lineStr); -#else - (void) lineNo; -#endif - - /* Check that no error was already recorded. Only record the first one. */ - if (parseState->ctx->Program.ErrorString[0] == 0) { - _mesa_set_program_error(parseState->ctx, - parseState->pos - parseState->start, - msg); - } -} - - -#define RETURN_ERROR \ -do { \ - record_error(parseState, "Unexpected end of input.", __LINE__); \ - return GL_FALSE; \ -} while(0) - -#define RETURN_ERROR1(msg) \ -do { \ - record_error(parseState, msg, __LINE__); \ - return GL_FALSE; \ -} while(0) - -#define RETURN_ERROR2(msg1, msg2) \ -do { \ - char err[1000]; \ - sprintf(err, "%s %s", msg1, msg2); \ - record_error(parseState, err, __LINE__); \ - return GL_FALSE; \ -} while(0) - - - - - -static GLboolean IsLetter(GLubyte b) -{ - return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z'); -} - - -static GLboolean IsDigit(GLubyte b) -{ - return b >= '0' && b <= '9'; -} - - -static GLboolean IsWhitespace(GLubyte b) -{ - return b == ' ' || b == '\t' || b == '\n' || b == '\r'; -} - - -/** - * Starting at 'str' find the next token. A token can be an integer, - * an identifier or punctuation symbol. - * \return <= 0 we found an error, else, return number of characters parsed. - */ -static GLint -GetToken(struct parse_state *parseState, GLubyte *token) -{ - const GLubyte *str = parseState->pos; - GLint i = 0, j = 0; - - token[0] = 0; - - /* skip whitespace and comments */ - while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) { - if (str[i] == '#') { - /* skip comment */ - while (str[i] && (str[i] != '\n' && str[i] != '\r')) { - i++; - } - if (str[i] == '\n' || str[i] == '\r') - parseState->curLine = str + i + 1; - } - else { - /* skip whitespace */ - if (str[i] == '\n' || str[i] == '\r') - parseState->curLine = str + i + 1; - i++; - } - } - - if (str[i] == 0) - return -i; - - /* try matching an integer */ - while (str[i] && IsDigit(str[i])) { - token[j++] = str[i++]; - } - if (j > 0 || !str[i]) { - token[j] = 0; - return i; - } - - /* try matching an identifier */ - if (IsLetter(str[i])) { - while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) { - token[j++] = str[i++]; - } - token[j] = 0; - return i; - } - - /* punctuation character */ - if (str[i]) { - token[0] = str[i++]; - token[1] = 0; - return i; - } - - /* end of input */ - token[0] = 0; - return i; -} - - -/** - * Get next token from input stream and increment stream pointer past token. - */ -static GLboolean -Parse_Token(struct parse_state *parseState, GLubyte *token) -{ - GLint i; - i = GetToken(parseState, token); - if (i <= 0) { - parseState->pos += (-i); - return GL_FALSE; - } - parseState->pos += i; - return GL_TRUE; -} - - -/** - * Get next token from input stream but don't increment stream pointer. - */ -static GLboolean -Peek_Token(struct parse_state *parseState, GLubyte *token) -{ - GLint i, len; - i = GetToken(parseState, token); - if (i <= 0) { - parseState->pos += (-i); - return GL_FALSE; - } - len = (GLint) strlen((const char *) token); - parseState->pos += (i - len); - return GL_TRUE; -} - - -/** - * Try to match 'pattern' as the next token after any whitespace/comments. - * Advance the current parsing position only if we match the pattern. - * \return GL_TRUE if pattern is matched, GL_FALSE otherwise. - */ -static GLboolean -Parse_String(struct parse_state *parseState, const char *pattern) -{ - const GLubyte *m; - GLint i; - - /* skip whitespace and comments */ - while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') { - if (*parseState->pos == '#') { - while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) { - parseState->pos += 1; - } - if (*parseState->pos == '\n' || *parseState->pos == '\r') - parseState->curLine = parseState->pos + 1; - } - else { - /* skip whitespace */ - if (*parseState->pos == '\n' || *parseState->pos == '\r') - parseState->curLine = parseState->pos + 1; - parseState->pos += 1; - } - } - - /* Try to match the pattern */ - m = parseState->pos; - for (i = 0; pattern[i]; i++) { - if (*m != (GLubyte) pattern[i]) - return GL_FALSE; - m += 1; - } - parseState->pos = m; - - return GL_TRUE; /* success */ -} - - -/**********************************************************************/ - -static const char *InputRegisters[MAX_NV_VERTEX_PROGRAM_INPUTS + 1] = { - "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7", - "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL -}; - -static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = { - "HPOS", "COL0", "COL1", "FOGC", - "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", - "PSIZ", "BFC0", "BFC1", NULL -}; - - - -/** - * Parse a temporary register: Rnn - */ -static GLboolean -Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum) -{ - GLubyte token[100]; - - /* Should be 'R##' */ - if (!Parse_Token(parseState, token)) - RETURN_ERROR; - if (token[0] != 'R') - RETURN_ERROR1("Expected R##"); - - if (IsDigit(token[1])) { - GLint reg = atoi((char *) (token + 1)); - if (reg >= MAX_NV_VERTEX_PROGRAM_TEMPS) - RETURN_ERROR1("Bad temporary register name"); - *tempRegNum = reg; - } - else { - RETURN_ERROR1("Bad temporary register name"); - } - - return GL_TRUE; -} - - -/** - * Parse address register "A0.x" - */ -static GLboolean -Parse_AddrReg(struct parse_state *parseState) -{ - /* match 'A0' */ - if (!Parse_String(parseState, "A0")) - RETURN_ERROR; - - /* match '.' */ - if (!Parse_String(parseState, ".")) - RETURN_ERROR; - - /* match 'x' */ - if (!Parse_String(parseState, "x")) - RETURN_ERROR; - - return GL_TRUE; -} - - -/** - * Parse absolute program parameter register "c[##]" - */ -static GLboolean -Parse_AbsParamReg(struct parse_state *parseState, GLint *regNum) -{ - GLubyte token[100]; - - if (!Parse_String(parseState, "c")) - RETURN_ERROR; - - if (!Parse_String(parseState, "[")) - RETURN_ERROR; - - if (!Parse_Token(parseState, token)) - RETURN_ERROR; - - if (IsDigit(token[0])) { - /* a numbered program parameter register */ - GLint reg = atoi((char *) token); - if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS) - RETURN_ERROR1("Bad program parameter number"); - *regNum = reg; - } - else { - RETURN_ERROR; - } - - if (!Parse_String(parseState, "]")) - RETURN_ERROR; - - return GL_TRUE; -} - - -static GLboolean -Parse_ParamReg(struct parse_state *parseState, struct prog_src_register *srcReg) -{ - GLubyte token[100]; - - if (!Parse_String(parseState, "c")) - RETURN_ERROR; - - if (!Parse_String(parseState, "[")) - RETURN_ERROR; - - if (!Peek_Token(parseState, token)) - RETURN_ERROR; - - if (IsDigit(token[0])) { - /* a numbered program parameter register */ - GLint reg; - (void) Parse_Token(parseState, token); - reg = atoi((char *) token); - if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS) - RETURN_ERROR1("Bad program parameter number"); - srcReg->File = PROGRAM_ENV_PARAM; - srcReg->Index = reg; - } - else if (strcmp((const char *) token, "A0") == 0) { - /* address register "A0.x" */ - if (!Parse_AddrReg(parseState)) - RETURN_ERROR; - - srcReg->RelAddr = GL_TRUE; - srcReg->File = PROGRAM_ENV_PARAM; - /* Look for +/-N offset */ - if (!Peek_Token(parseState, token)) - RETURN_ERROR; - - if (token[0] == '-' || token[0] == '+') { - const GLubyte sign = token[0]; - (void) Parse_Token(parseState, token); /* consume +/- */ - - /* an integer should be next */ - if (!Parse_Token(parseState, token)) - RETURN_ERROR; - - if (IsDigit(token[0])) { - const GLint k = atoi((char *) token); - if (sign == '-') { - if (k > 64) - RETURN_ERROR1("Bad address offset"); - srcReg->Index = -k; - } - else { - if (k > 63) - RETURN_ERROR1("Bad address offset"); - srcReg->Index = k; - } - } - else { - RETURN_ERROR; - } - } - else { - /* probably got a ']', catch it below */ - } - } - else { - RETURN_ERROR; - } - - /* Match closing ']' */ - if (!Parse_String(parseState, "]")) - RETURN_ERROR; - - return GL_TRUE; -} - - -/** - * Parse v[#] or v[] - */ -static GLboolean -Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum) -{ - GLubyte token[100]; - GLint j; - - /* Match 'v' */ - if (!Parse_String(parseState, "v")) - RETURN_ERROR; - - /* Match '[' */ - if (!Parse_String(parseState, "[")) - RETURN_ERROR; - - /* match number or named register */ - if (!Parse_Token(parseState, token)) - RETURN_ERROR; - - if (parseState->isStateProgram && token[0] != '0') - RETURN_ERROR1("Only v[0] accessible in vertex state programs"); - - if (IsDigit(token[0])) { - GLint reg = atoi((char *) token); - if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS) - RETURN_ERROR1("Bad vertex attribute register name"); - *tempRegNum = reg; - } - else { - for (j = 0; InputRegisters[j]; j++) { - if (strcmp((const char *) token, InputRegisters[j]) == 0) { - *tempRegNum = j; - break; - } - } - if (!InputRegisters[j]) { - /* unknown input register label */ - RETURN_ERROR2("Bad register name", token); - } - } - - /* Match '[' */ - if (!Parse_String(parseState, "]")) - RETURN_ERROR; - - return GL_TRUE; -} - - -static GLboolean -Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum) -{ - GLubyte token[100]; - GLint start, j; - - /* Match 'o' */ - if (!Parse_String(parseState, "o")) - RETURN_ERROR; - - /* Match '[' */ - if (!Parse_String(parseState, "[")) - RETURN_ERROR; - - /* Get output reg name */ - if (!Parse_Token(parseState, token)) - RETURN_ERROR; - - if (parseState->isPositionInvariant) - start = 1; /* skip HPOS register name */ - else - start = 0; - - /* try to match an output register name */ - for (j = start; OutputRegisters[j]; j++) { - if (strcmp((const char *) token, OutputRegisters[j]) == 0) { - *outputRegNum = j; - break; - } - } - if (!OutputRegisters[j]) - RETURN_ERROR1("Unrecognized output register name"); - - /* Match ']' */ - if (!Parse_String(parseState, "]")) - RETURN_ERROR1("Expected ]"); - - return GL_TRUE; -} - - -static GLboolean -Parse_MaskedDstReg(struct parse_state *parseState, struct prog_dst_register *dstReg) -{ - GLubyte token[100]; - GLint idx; - - /* Dst reg can be R or o[n] */ - if (!Peek_Token(parseState, token)) - RETURN_ERROR; - - if (token[0] == 'R') { - /* a temporary register */ - dstReg->File = PROGRAM_TEMPORARY; - if (!Parse_TempReg(parseState, &idx)) - RETURN_ERROR; - dstReg->Index = idx; - } - else if (!parseState->isStateProgram && token[0] == 'o') { - /* an output register */ - dstReg->File = PROGRAM_OUTPUT; - if (!Parse_OutputReg(parseState, &idx)) - RETURN_ERROR; - dstReg->Index = idx; - } - else if (parseState->isStateProgram && token[0] == 'c' && - parseState->isStateProgram) { - /* absolute program parameter register */ - /* Only valid for vertex state programs */ - dstReg->File = PROGRAM_ENV_PARAM; - if (!Parse_AbsParamReg(parseState, &idx)) - RETURN_ERROR; - dstReg->Index = idx; - } - else { - RETURN_ERROR1("Bad destination register name"); - } - - /* Parse optional write mask */ - if (!Peek_Token(parseState, token)) - RETURN_ERROR; - - if (token[0] == '.') { - /* got a mask */ - GLint k = 0; - - if (!Parse_String(parseState, ".")) - RETURN_ERROR; - - if (!Parse_Token(parseState, token)) - RETURN_ERROR; - - dstReg->WriteMask = 0; - - if (token[k] == 'x') { - dstReg->WriteMask |= WRITEMASK_X; - k++; - } - if (token[k] == 'y') { - dstReg->WriteMask |= WRITEMASK_Y; - k++; - } - if (token[k] == 'z') { - dstReg->WriteMask |= WRITEMASK_Z; - k++; - } - if (token[k] == 'w') { - dstReg->WriteMask |= WRITEMASK_W; - k++; - } - if (k == 0) { - RETURN_ERROR1("Bad writemask character"); - } - return GL_TRUE; - } - else { - dstReg->WriteMask = WRITEMASK_XYZW; - return GL_TRUE; - } -} - - -static GLboolean -Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg) -{ - GLubyte token[100]; - GLint idx; - - srcReg->RelAddr = GL_FALSE; - - /* check for '-' */ - if (!Peek_Token(parseState, token)) - RETURN_ERROR; - if (token[0] == '-') { - (void) Parse_String(parseState, "-"); - srcReg->Negate = NEGATE_XYZW; - if (!Peek_Token(parseState, token)) - RETURN_ERROR; - } - else { - srcReg->Negate = NEGATE_NONE; - } - - /* Src reg can be R, c[n], c[n +/- offset], or a named vertex attrib */ - if (token[0] == 'R') { - srcReg->File = PROGRAM_TEMPORARY; - if (!Parse_TempReg(parseState, &idx)) - RETURN_ERROR; - srcReg->Index = idx; - } - else if (token[0] == 'c') { - if (!Parse_ParamReg(parseState, srcReg)) - RETURN_ERROR; - } - else if (token[0] == 'v') { - srcReg->File = PROGRAM_INPUT; - if (!Parse_AttribReg(parseState, &idx)) - RETURN_ERROR; - srcReg->Index = idx; - } - else { - RETURN_ERROR2("Bad source register name", token); - } - - /* init swizzle fields */ - srcReg->Swizzle = SWIZZLE_NOOP; - - /* Look for optional swizzle suffix */ - if (!Peek_Token(parseState, token)) - RETURN_ERROR; - if (token[0] == '.') { - (void) Parse_String(parseState, "."); /* consume . */ - - if (!Parse_Token(parseState, token)) - RETURN_ERROR; - - if (token[1] == 0) { - /* single letter swizzle */ - if (token[0] == 'x') - srcReg->Swizzle = SWIZZLE_XXXX; - else if (token[0] == 'y') - srcReg->Swizzle = SWIZZLE_YYYY; - else if (token[0] == 'z') - srcReg->Swizzle = SWIZZLE_ZZZZ; - else if (token[0] == 'w') - srcReg->Swizzle = SWIZZLE_WWWW; - else - RETURN_ERROR1("Expected x, y, z, or w"); - } - else { - /* 2, 3 or 4-component swizzle */ - GLint k; - - srcReg->Swizzle = 0; - - for (k = 0; token[k] && k < 5; k++) { - if (token[k] == 'x') - srcReg->Swizzle |= 0 << (k*3); - else if (token[k] == 'y') - srcReg->Swizzle |= 1 << (k*3); - else if (token[k] == 'z') - srcReg->Swizzle |= 2 << (k*3); - else if (token[k] == 'w') - srcReg->Swizzle |= 3 << (k*3); - else - RETURN_ERROR; - } - if (k >= 5) - RETURN_ERROR; - } - } - - return GL_TRUE; -} - - -static GLboolean -Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg) -{ - GLubyte token[100]; - GLint idx; - - srcReg->RelAddr = GL_FALSE; - - /* check for '-' */ - if (!Peek_Token(parseState, token)) - RETURN_ERROR; - if (token[0] == '-') { - srcReg->Negate = NEGATE_XYZW; - (void) Parse_String(parseState, "-"); /* consume '-' */ - if (!Peek_Token(parseState, token)) - RETURN_ERROR; - } - else { - srcReg->Negate = NEGATE_NONE; - } - - /* Src reg can be R, c[n], c[n +/- offset], or a named vertex attrib */ - if (token[0] == 'R') { - srcReg->File = PROGRAM_TEMPORARY; - if (!Parse_TempReg(parseState, &idx)) - RETURN_ERROR; - srcReg->Index = idx; - } - else if (token[0] == 'c') { - if (!Parse_ParamReg(parseState, srcReg)) - RETURN_ERROR; - } - else if (token[0] == 'v') { - srcReg->File = PROGRAM_INPUT; - if (!Parse_AttribReg(parseState, &idx)) - RETURN_ERROR; - srcReg->Index = idx; - } - else { - RETURN_ERROR2("Bad source register name", token); - } - - /* Look for .[xyzw] suffix */ - if (!Parse_String(parseState, ".")) - RETURN_ERROR; - - if (!Parse_Token(parseState, token)) - RETURN_ERROR; - - if (token[0] == 'x' && token[1] == 0) { - srcReg->Swizzle = 0; - } - else if (token[0] == 'y' && token[1] == 0) { - srcReg->Swizzle = 1; - } - else if (token[0] == 'z' && token[1] == 0) { - srcReg->Swizzle = 2; - } - else if (token[0] == 'w' && token[1] == 0) { - srcReg->Swizzle = 3; - } - else { - RETURN_ERROR1("Bad scalar source suffix"); - } - - return GL_TRUE; -} - - -static GLint -Parse_UnaryOpInstruction(struct parse_state *parseState, - struct prog_instruction *inst, - enum prog_opcode opcode) -{ - if (opcode == OPCODE_ABS && !parseState->isVersion1_1) - RETURN_ERROR1("ABS illegal for vertex program 1.0"); - - inst->Opcode = opcode; - - /* dest reg */ - if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) - RETURN_ERROR; - - /* comma */ - if (!Parse_String(parseState, ",")) - RETURN_ERROR; - - /* src arg */ - if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0])) - RETURN_ERROR; - - /* semicolon */ - if (!Parse_String(parseState, ";")) - RETURN_ERROR; - - return GL_TRUE; -} - - -static GLboolean -Parse_BiOpInstruction(struct parse_state *parseState, - struct prog_instruction *inst, - enum prog_opcode opcode) -{ - if (opcode == OPCODE_DPH && !parseState->isVersion1_1) - RETURN_ERROR1("DPH illegal for vertex program 1.0"); - if (opcode == OPCODE_SUB && !parseState->isVersion1_1) - RETURN_ERROR1("SUB illegal for vertex program 1.0"); - - inst->Opcode = opcode; - - /* dest reg */ - if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) - RETURN_ERROR; - - /* comma */ - if (!Parse_String(parseState, ",")) - RETURN_ERROR; - - /* first src arg */ - if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0])) - RETURN_ERROR; - - /* comma */ - if (!Parse_String(parseState, ",")) - RETURN_ERROR; - - /* second src arg */ - if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1])) - RETURN_ERROR; - - /* semicolon */ - if (!Parse_String(parseState, ";")) - RETURN_ERROR; - - /* make sure we don't reference more than one program parameter register */ - if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM && - inst->SrcReg[1].File == PROGRAM_ENV_PARAM && - inst->SrcReg[0].Index != inst->SrcReg[1].Index) - RETURN_ERROR1("Can't reference two program parameter registers"); - - /* make sure we don't reference more than one vertex attribute register */ - if (inst->SrcReg[0].File == PROGRAM_INPUT && - inst->SrcReg[1].File == PROGRAM_INPUT && - inst->SrcReg[0].Index != inst->SrcReg[1].Index) - RETURN_ERROR1("Can't reference two vertex attribute registers"); - - return GL_TRUE; -} - - -static GLboolean -Parse_TriOpInstruction(struct parse_state *parseState, - struct prog_instruction *inst, - enum prog_opcode opcode) -{ - inst->Opcode = opcode; - - /* dest reg */ - if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) - RETURN_ERROR; - - /* comma */ - if (!Parse_String(parseState, ",")) - RETURN_ERROR; - - /* first src arg */ - if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0])) - RETURN_ERROR; - - /* comma */ - if (!Parse_String(parseState, ",")) - RETURN_ERROR; - - /* second src arg */ - if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1])) - RETURN_ERROR; - - /* comma */ - if (!Parse_String(parseState, ",")) - RETURN_ERROR; - - /* third src arg */ - if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2])) - RETURN_ERROR; - - /* semicolon */ - if (!Parse_String(parseState, ";")) - RETURN_ERROR; - - /* make sure we don't reference more than one program parameter register */ - if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM && - inst->SrcReg[1].File == PROGRAM_ENV_PARAM && - inst->SrcReg[0].Index != inst->SrcReg[1].Index) || - (inst->SrcReg[0].File == PROGRAM_ENV_PARAM && - inst->SrcReg[2].File == PROGRAM_ENV_PARAM && - inst->SrcReg[0].Index != inst->SrcReg[2].Index) || - (inst->SrcReg[1].File == PROGRAM_ENV_PARAM && - inst->SrcReg[2].File == PROGRAM_ENV_PARAM && - inst->SrcReg[1].Index != inst->SrcReg[2].Index)) - RETURN_ERROR1("Can only reference one program register"); - - /* make sure we don't reference more than one vertex attribute register */ - if ((inst->SrcReg[0].File == PROGRAM_INPUT && - inst->SrcReg[1].File == PROGRAM_INPUT && - inst->SrcReg[0].Index != inst->SrcReg[1].Index) || - (inst->SrcReg[0].File == PROGRAM_INPUT && - inst->SrcReg[2].File == PROGRAM_INPUT && - inst->SrcReg[0].Index != inst->SrcReg[2].Index) || - (inst->SrcReg[1].File == PROGRAM_INPUT && - inst->SrcReg[2].File == PROGRAM_INPUT && - inst->SrcReg[1].Index != inst->SrcReg[2].Index)) - RETURN_ERROR1("Can only reference one input register"); - - return GL_TRUE; -} - - -static GLboolean -Parse_ScalarInstruction(struct parse_state *parseState, - struct prog_instruction *inst, - enum prog_opcode opcode) -{ - if (opcode == OPCODE_RCC && !parseState->isVersion1_1) - RETURN_ERROR1("RCC illegal for vertex program 1.0"); - - inst->Opcode = opcode; - - /* dest reg */ - if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) - RETURN_ERROR; - - /* comma */ - if (!Parse_String(parseState, ",")) - RETURN_ERROR; - - /* first src arg */ - if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) - RETURN_ERROR; - - /* semicolon */ - if (!Parse_String(parseState, ";")) - RETURN_ERROR; - - return GL_TRUE; -} - - -static GLboolean -Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst) -{ - inst->Opcode = OPCODE_ARL; - - /* Make ARB_vp backends happy */ - inst->DstReg.File = PROGRAM_ADDRESS; - inst->DstReg.WriteMask = WRITEMASK_X; - inst->DstReg.Index = 0; - - /* dest A0 reg */ - if (!Parse_AddrReg(parseState)) - RETURN_ERROR; - - /* comma */ - if (!Parse_String(parseState, ",")) - RETURN_ERROR; - - /* parse src reg */ - if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) - RETURN_ERROR; - - /* semicolon */ - if (!Parse_String(parseState, ";")) - RETURN_ERROR; - - return GL_TRUE; -} - - -static GLboolean -Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *inst) -{ - GLubyte token[100]; - - inst->Opcode = OPCODE_END; - - /* this should fail! */ - if (Parse_Token(parseState, token)) - RETURN_ERROR2("Unexpected token after END:", token); - else - return GL_TRUE; -} - - -/** - * The PRINT instruction is Mesa-specific and is meant as a debugging aid for - * the vertex program developer. - * The NV_vertex_program extension grammar is modified as follows: - * - * ::= - * | ... - * | - * - * ::= "PRINT" - * | "PRINT" "," - * | "PRINT" "," - */ -static GLboolean -Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *inst) -{ - const GLubyte *str; - GLubyte *msg; - GLuint len; - GLubyte token[100]; - struct prog_src_register *srcReg = &inst->SrcReg[0]; - GLint idx; - - inst->Opcode = OPCODE_PRINT; - - /* The first argument is a literal string 'just like this' */ - if (!Parse_String(parseState, "'")) - RETURN_ERROR; - - str = parseState->pos; - for (len = 0; str[len] != '\''; len++) /* find closing quote */ - ; - parseState->pos += len + 1; - msg = (GLubyte*) malloc(len + 1); - - memcpy(msg, str, len); - msg[len] = 0; - inst->Data = msg; - - /* comma */ - if (Parse_String(parseState, ",")) { - - /* The second argument is a register name */ - if (!Peek_Token(parseState, token)) - RETURN_ERROR; - - srcReg->RelAddr = GL_FALSE; - srcReg->Negate = NEGATE_NONE; - srcReg->Swizzle = SWIZZLE_NOOP; - - /* Register can be R, c[n], c[n +/- offset], a named vertex attrib, - * or an o[n] output register. - */ - if (token[0] == 'R') { - srcReg->File = PROGRAM_TEMPORARY; - if (!Parse_TempReg(parseState, &idx)) - RETURN_ERROR; - srcReg->Index = idx; - } - else if (token[0] == 'c') { - srcReg->File = PROGRAM_ENV_PARAM; - if (!Parse_ParamReg(parseState, srcReg)) - RETURN_ERROR; - } - else if (token[0] == 'v') { - srcReg->File = PROGRAM_INPUT; - if (!Parse_AttribReg(parseState, &idx)) - RETURN_ERROR; - srcReg->Index = idx; - } - else if (token[0] == 'o') { - srcReg->File = PROGRAM_OUTPUT; - if (!Parse_OutputReg(parseState, &idx)) - RETURN_ERROR; - srcReg->Index = idx; - } - else { - RETURN_ERROR2("Bad source register name", token); - } - } - else { - srcReg->File = PROGRAM_UNDEFINED; - } - - /* semicolon */ - if (!Parse_String(parseState, ";")) - RETURN_ERROR; - - return GL_TRUE; -} - - -static GLboolean -Parse_OptionSequence(struct parse_state *parseState, - struct prog_instruction program[]) -{ - (void) program; - while (1) { - if (!Parse_String(parseState, "OPTION")) - return GL_TRUE; /* ok, not an OPTION statement */ - if (Parse_String(parseState, "NV_position_invariant")) { - parseState->isPositionInvariant = GL_TRUE; - } - else { - RETURN_ERROR1("unexpected OPTION statement"); - } - if (!Parse_String(parseState, ";")) - return GL_FALSE; - } -} - - -static GLboolean -Parse_InstructionSequence(struct parse_state *parseState, - struct prog_instruction program[]) -{ - while (1) { - struct prog_instruction *inst = program + parseState->numInst; - - /* Initialize the instruction */ - _mesa_init_instructions(inst, 1); - - if (Parse_String(parseState, "MOV")) { - if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_MOV)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "LIT")) { - if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_LIT)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "ABS")) { - if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_ABS)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "MUL")) { - if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MUL)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "ADD")) { - if (!Parse_BiOpInstruction(parseState, inst, OPCODE_ADD)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "DP3")) { - if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP3)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "DP4")) { - if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP4)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "DST")) { - if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DST)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "MIN")) { - if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MIN)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "MAX")) { - if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MAX)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "SLT")) { - if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SLT)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "SGE")) { - if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SGE)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "DPH")) { - if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DPH)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "SUB")) { - if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SUB)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "MAD")) { - if (!Parse_TriOpInstruction(parseState, inst, OPCODE_MAD)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "RCP")) { - if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCP)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "RSQ")) { - if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RSQ)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "EXP")) { - if (!Parse_ScalarInstruction(parseState, inst, OPCODE_EXP)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "LOG")) { - if (!Parse_ScalarInstruction(parseState, inst, OPCODE_LOG)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "RCC")) { - if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCC)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "ARL")) { - if (!Parse_AddressInstruction(parseState, inst)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "PRINT")) { - if (!Parse_PrintInstruction(parseState, inst)) - RETURN_ERROR; - } - else if (Parse_String(parseState, "END")) { - if (!Parse_EndInstruction(parseState, inst)) - RETURN_ERROR; - else { - parseState->numInst++; - return GL_TRUE; /* all done */ - } - } - else { - /* bad instruction name */ - RETURN_ERROR1("Unexpected token"); - } - - /* examine input/output registers */ - if (inst->DstReg.File == PROGRAM_OUTPUT) - parseState->outputsWritten |= (1 << inst->DstReg.Index); - else if (inst->DstReg.File == PROGRAM_ENV_PARAM) - parseState->anyProgRegsWritten = GL_TRUE; - - if (inst->SrcReg[0].File == PROGRAM_INPUT) - parseState->inputsRead |= (1 << inst->SrcReg[0].Index); - if (inst->SrcReg[1].File == PROGRAM_INPUT) - parseState->inputsRead |= (1 << inst->SrcReg[1].Index); - if (inst->SrcReg[2].File == PROGRAM_INPUT) - parseState->inputsRead |= (1 << inst->SrcReg[2].Index); - - parseState->numInst++; - - if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS) - RETURN_ERROR1("Program too long"); - } - - RETURN_ERROR; -} - - -static GLboolean -Parse_Program(struct parse_state *parseState, - struct prog_instruction instBuffer[]) -{ - if (parseState->isVersion1_1) { - if (!Parse_OptionSequence(parseState, instBuffer)) { - return GL_FALSE; - } - } - return Parse_InstructionSequence(parseState, instBuffer); -} - - -/** - * Parse/compile the 'str' returning the compiled 'program'. - * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos - * indicates the position of the error in 'str'. - */ -void -_mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget, - const GLubyte *str, GLsizei len, - struct gl_vertex_program *program) -{ - struct parse_state parseState; - struct prog_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS]; - struct prog_instruction *newInst; - GLenum target; - GLubyte *programString; - - /* Make a null-terminated copy of the program string */ - programString = (GLubyte *) MALLOC(len + 1); - if (!programString) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); - return; - } - memcpy(programString, str, len); - programString[len] = 0; - - /* Get ready to parse */ - parseState.ctx = ctx; - parseState.start = programString; - parseState.isPositionInvariant = GL_FALSE; - parseState.isVersion1_1 = GL_FALSE; - parseState.numInst = 0; - parseState.inputsRead = 0; - parseState.outputsWritten = 0; - parseState.anyProgRegsWritten = GL_FALSE; - - /* Reset error state */ - _mesa_set_program_error(ctx, -1, NULL); - - /* check the program header */ - if (strncmp((const char *) programString, "!!VP1.0", 7) == 0) { - target = GL_VERTEX_PROGRAM_NV; - parseState.pos = programString + 7; - parseState.isStateProgram = GL_FALSE; - } - else if (strncmp((const char *) programString, "!!VP1.1", 7) == 0) { - target = GL_VERTEX_PROGRAM_NV; - parseState.pos = programString + 7; - parseState.isStateProgram = GL_FALSE; - parseState.isVersion1_1 = GL_TRUE; - } - else if (strncmp((const char *) programString, "!!VSP1.0", 8) == 0) { - target = GL_VERTEX_STATE_PROGRAM_NV; - parseState.pos = programString + 8; - parseState.isStateProgram = GL_TRUE; - } - else { - /* invalid header */ - ctx->Program.ErrorPos = 0; - _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); - return; - } - - /* make sure target and header match */ - if (target != dstTarget) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glLoadProgramNV(target mismatch)"); - return; - } - - - if (Parse_Program(&parseState, instBuffer)) { - gl_state_index state_tokens[STATE_LENGTH] = {0, 0, 0, 0, 0}; - int i; - - /* successful parse! */ - - if (parseState.isStateProgram) { - if (!parseState.anyProgRegsWritten) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glLoadProgramNV(c[#] not written)"); - return; - } - } - else { - if (!parseState.isPositionInvariant && - !(parseState.outputsWritten & (1 << VERT_RESULT_HPOS))) { - /* bit 1 = HPOS register */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glLoadProgramNV(HPOS not written)"); - return; - } - } - - /* copy the compiled instructions */ - assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS); - newInst = _mesa_alloc_instructions(parseState.numInst); - if (!newInst) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); - free(programString); - return; /* out of memory */ - } - _mesa_copy_instructions(newInst, instBuffer, parseState.numInst); - - /* install the program */ - program->Base.Target = target; - if (program->Base.String) { - free(program->Base.String); - } - program->Base.String = programString; - program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB; - if (program->Base.Instructions) { - free(program->Base.Instructions); - } - program->Base.Instructions = newInst; - program->Base.InputsRead = parseState.inputsRead; - if (parseState.isPositionInvariant) - program->Base.InputsRead |= VERT_BIT_POS; - program->Base.NumInstructions = parseState.numInst; - program->Base.OutputsWritten = parseState.outputsWritten; - program->IsPositionInvariant = parseState.isPositionInvariant; - program->IsNVProgram = GL_TRUE; - -#ifdef DEBUG_foo - printf("--- glLoadProgramNV result ---\n"); - _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0); - printf("------------------------------\n"); -#endif - - if (program->Base.Parameters) - _mesa_free_parameter_list(program->Base.Parameters); - - program->Base.Parameters = _mesa_new_parameter_list (); - program->Base.NumParameters = 0; - - state_tokens[0] = STATE_VERTEX_PROGRAM; - state_tokens[1] = STATE_ENV; - /* Add refs to all of the potential params, in order. If we want to not - * upload everything, _mesa_layout_parameters is the answer. - */ - for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS; i++) { - GLint index; - state_tokens[2] = i; - index = _mesa_add_state_reference(program->Base.Parameters, - state_tokens); - assert(index == i); - } - program->Base.NumParameters = program->Base.Parameters->NumParameters; - - _mesa_setup_nv_temporary_count(ctx, &program->Base); - _mesa_emit_nv_temp_initialization(ctx, &program->Base); - } - else { - /* Error! */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV"); - /* NOTE: _mesa_set_program_error would have been called already */ - /* GL_NV_vertex_program isn't supposed to set the error string - * so we reset it here. - */ - _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL); - } -} - - -const char * -_mesa_nv_vertex_input_register_name(GLuint i) -{ - ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS); - return InputRegisters[i]; -} - - -const char * -_mesa_nv_vertex_output_register_name(GLuint i) -{ - ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS); - return OutputRegisters[i]; -} - diff --git a/src/mesa/shader/nvvertparse.h b/src/mesa/shader/nvvertparse.h deleted file mode 100644 index 9919e22388..0000000000 --- a/src/mesa/shader/nvvertparse.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 5.1 - * - * Copyright (C) 1999-2003 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Brian Paul - */ - - -#ifndef NVVERTPARSE_H -#define NVVERTPARSE_H - - -extern void -_mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum target, - const GLubyte *str, GLsizei len, - struct gl_vertex_program *program); - - -extern const char * -_mesa_nv_vertex_input_register_name(GLuint i); - -extern const char * -_mesa_nv_vertex_output_register_name(GLuint i); - -#endif diff --git a/src/mesa/shader/prog_cache.c b/src/mesa/shader/prog_cache.c deleted file mode 100644 index e5b602fc09..0000000000 --- a/src/mesa/shader/prog_cache.c +++ /dev/null @@ -1,206 +0,0 @@ -/************************************************************************** - * - * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - - -#include "main/glheader.h" -#include "main/mtypes.h" -#include "main/imports.h" -#include "shader/prog_cache.h" -#include "shader/program.h" - - -struct cache_item -{ - GLuint hash; - void *key; - struct gl_program *program; - struct cache_item *next; -}; - -struct gl_program_cache -{ - struct cache_item **items; - struct cache_item *last; - GLuint size, n_items; -}; - - - -/** - * Compute hash index from state key. - */ -static GLuint -hash_key(const void *key, GLuint key_size) -{ - const GLuint *ikey = (const GLuint *) key; - GLuint hash = 0, i; - - assert(key_size >= 4); - - /* Make a slightly better attempt at a hash function: - */ - for (i = 0; i < key_size / sizeof(*ikey); i++) - { - hash += ikey[i]; - hash += (hash << 10); - hash ^= (hash >> 6); - } - - return hash; -} - - -/** - * Rebuild/expand the hash table to accomodate more entries - */ -static void -rehash(struct gl_program_cache *cache) -{ - struct cache_item **items; - struct cache_item *c, *next; - GLuint size, i; - - cache->last = NULL; - - size = cache->size * 3; - items = (struct cache_item**) malloc(size * sizeof(*items)); - memset(items, 0, size * sizeof(*items)); - - for (i = 0; i < cache->size; i++) - for (c = cache->items[i]; c; c = next) { - next = c->next; - c->next = items[c->hash % size]; - items[c->hash % size] = c; - } - - free(cache->items); - cache->items = items; - cache->size = size; -} - - -static void -clear_cache(GLcontext *ctx, struct gl_program_cache *cache) -{ - struct cache_item *c, *next; - GLuint i; - - cache->last = NULL; - - for (i = 0; i < cache->size; i++) { - for (c = cache->items[i]; c; c = next) { - next = c->next; - free(c->key); - _mesa_reference_program(ctx, &c->program, NULL); - free(c); - } - cache->items[i] = NULL; - } - - - cache->n_items = 0; -} - - - -struct gl_program_cache * -_mesa_new_program_cache(void) -{ - struct gl_program_cache *cache = CALLOC_STRUCT(gl_program_cache); - if (cache) { - cache->size = 17; - cache->items = (struct cache_item **) - calloc(1, cache->size * sizeof(struct cache_item)); - if (!cache->items) { - free(cache); - return NULL; - } - } - return cache; -} - - -void -_mesa_delete_program_cache(GLcontext *ctx, struct gl_program_cache *cache) -{ - clear_cache(ctx, cache); - free(cache->items); - free(cache); -} - - -struct gl_program * -_mesa_search_program_cache(struct gl_program_cache *cache, - const void *key, GLuint keysize) -{ - if (cache->last && - memcmp(cache->last->key, key, keysize) == 0) { - return cache->last->program; - } - else { - const GLuint hash = hash_key(key, keysize); - struct cache_item *c; - - for (c = cache->items[hash % cache->size]; c; c = c->next) { - if (c->hash == hash && memcmp(c->key, key, keysize) == 0) { - cache->last = c; - return c->program; - } - } - - return NULL; - } -} - - -void -_mesa_program_cache_insert(GLcontext *ctx, - struct gl_program_cache *cache, - const void *key, GLuint keysize, - struct gl_program *program) -{ - const GLuint hash = hash_key(key, keysize); - struct cache_item *c = CALLOC_STRUCT(cache_item); - - c->hash = hash; - - c->key = malloc(keysize); - memcpy(c->key, key, keysize); - - c->program = program; /* no refcount change */ - - if (cache->n_items > cache->size * 1.5) { - if (cache->size < 1000) - rehash(cache); - else - clear_cache(ctx, cache); - } - - cache->n_items++; - c->next = cache->items[hash % cache->size]; - cache->items[hash % cache->size] = c; -} diff --git a/src/mesa/shader/prog_cache.h b/src/mesa/shader/prog_cache.h deleted file mode 100644 index 4e1ccac03f..0000000000 --- a/src/mesa/shader/prog_cache.h +++ /dev/null @@ -1,55 +0,0 @@ -/************************************************************************** - * - * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - - -#ifndef PROG_CACHE_H -#define PROG_CACHE_H - - -/** Opaque type */ -struct gl_program_cache; - - -extern struct gl_program_cache * -_mesa_new_program_cache(void); - -extern void -_mesa_delete_program_cache(GLcontext *ctx, struct gl_program_cache *pc); - - -extern struct gl_program * -_mesa_search_program_cache(struct gl_program_cache *cache, - const void *key, GLuint keysize); - -extern void -_mesa_program_cache_insert(GLcontext *ctx, - struct gl_program_cache *cache, - const void *key, GLuint keysize, - struct gl_program *program); - - -#endif /* PROG_CACHE_H */ diff --git a/src/mesa/shader/prog_execute.c b/src/mesa/shader/prog_execute.c deleted file mode 100644 index f85c6513f3..0000000000 --- a/src/mesa/shader/prog_execute.c +++ /dev/null @@ -1,1798 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.3 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file prog_execute.c - * Software interpreter for vertex/fragment programs. - * \author Brian Paul - */ - -/* - * NOTE: we do everything in single-precision floating point; we don't - * currently observe the single/half/fixed-precision qualifiers. - * - */ - - -#include "main/glheader.h" -#include "main/colormac.h" -#include "main/context.h" -#include "prog_execute.h" -#include "prog_instruction.h" -#include "prog_parameter.h" -#include "prog_print.h" -#include "prog_noise.h" - - -/* debug predicate */ -#define DEBUG_PROG 0 - - -/** - * Set x to positive or negative infinity. - */ -#if defined(USE_IEEE) || defined(_WIN32) -#define SET_POS_INFINITY(x) \ - do { \ - fi_type fi; \ - fi.i = 0x7F800000; \ - x = fi.f; \ - } while (0) -#define SET_NEG_INFINITY(x) \ - do { \ - fi_type fi; \ - fi.i = 0xFF800000; \ - x = fi.f; \ - } while (0) -#elif defined(VMS) -#define SET_POS_INFINITY(x) x = __MAXFLOAT -#define SET_NEG_INFINITY(x) x = -__MAXFLOAT -#else -#define SET_POS_INFINITY(x) x = (GLfloat) HUGE_VAL -#define SET_NEG_INFINITY(x) x = (GLfloat) -HUGE_VAL -#endif - -#define SET_FLOAT_BITS(x, bits) ((fi_type *) (void *) &(x))->i = bits - - -static const GLfloat ZeroVec[4] = { 0.0F, 0.0F, 0.0F, 0.0F }; - - - -/** - * Return a pointer to the 4-element float vector specified by the given - * source register. - */ -static INLINE const GLfloat * -get_src_register_pointer(const struct prog_src_register *source, - const struct gl_program_machine *machine) -{ - const struct gl_program *prog = machine->CurProgram; - GLint reg = source->Index; - - if (source->RelAddr) { - /* add address register value to src index/offset */ - reg += machine->AddressReg[0][0]; - if (reg < 0) { - return ZeroVec; - } - } - - switch (source->File) { - case PROGRAM_TEMPORARY: - if (reg >= MAX_PROGRAM_TEMPS) - return ZeroVec; - return machine->Temporaries[reg]; - - case PROGRAM_INPUT: - if (prog->Target == GL_VERTEX_PROGRAM_ARB) { - if (reg >= VERT_ATTRIB_MAX) - return ZeroVec; - return machine->VertAttribs[reg]; - } - else { - if (reg >= FRAG_ATTRIB_MAX) - return ZeroVec; - return machine->Attribs[reg][machine->CurElement]; - } - - case PROGRAM_OUTPUT: - if (reg >= MAX_PROGRAM_OUTPUTS) - return ZeroVec; - return machine->Outputs[reg]; - - case PROGRAM_LOCAL_PARAM: - if (reg >= MAX_PROGRAM_LOCAL_PARAMS) - return ZeroVec; - return machine->CurProgram->LocalParams[reg]; - - case PROGRAM_ENV_PARAM: - if (reg >= MAX_PROGRAM_ENV_PARAMS) - return ZeroVec; - return machine->EnvParams[reg]; - - case PROGRAM_STATE_VAR: - /* Fallthrough */ - case PROGRAM_CONSTANT: - /* Fallthrough */ - case PROGRAM_UNIFORM: - /* Fallthrough */ - case PROGRAM_NAMED_PARAM: - if (reg >= (GLint) prog->Parameters->NumParameters) - return ZeroVec; - return prog->Parameters->ParameterValues[reg]; - - default: - _mesa_problem(NULL, - "Invalid src register file %d in get_src_register_pointer()", - source->File); - return NULL; - } -} - - -/** - * Return a pointer to the 4-element float vector specified by the given - * destination register. - */ -static INLINE GLfloat * -get_dst_register_pointer(const struct prog_dst_register *dest, - struct gl_program_machine *machine) -{ - static GLfloat dummyReg[4]; - GLint reg = dest->Index; - - if (dest->RelAddr) { - /* add address register value to src index/offset */ - reg += machine->AddressReg[0][0]; - if (reg < 0) { - return dummyReg; - } - } - - switch (dest->File) { - case PROGRAM_TEMPORARY: - if (reg >= MAX_PROGRAM_TEMPS) - return dummyReg; - return machine->Temporaries[reg]; - - case PROGRAM_OUTPUT: - if (reg >= MAX_PROGRAM_OUTPUTS) - return dummyReg; - return machine->Outputs[reg]; - - case PROGRAM_WRITE_ONLY: - return dummyReg; - - default: - _mesa_problem(NULL, - "Invalid dest register file %d in get_dst_register_pointer()", - dest->File); - return NULL; - } -} - - - -/** - * Fetch a 4-element float vector from the given source register. - * Apply swizzling and negating as needed. - */ -static void -fetch_vector4(const struct prog_src_register *source, - const struct gl_program_machine *machine, GLfloat result[4]) -{ - const GLfloat *src = get_src_register_pointer(source, machine); - ASSERT(src); - - if (source->Swizzle == SWIZZLE_NOOP) { - /* no swizzling */ - COPY_4V(result, src); - } - else { - ASSERT(GET_SWZ(source->Swizzle, 0) <= 3); - ASSERT(GET_SWZ(source->Swizzle, 1) <= 3); - ASSERT(GET_SWZ(source->Swizzle, 2) <= 3); - ASSERT(GET_SWZ(source->Swizzle, 3) <= 3); - result[0] = src[GET_SWZ(source->Swizzle, 0)]; - result[1] = src[GET_SWZ(source->Swizzle, 1)]; - result[2] = src[GET_SWZ(source->Swizzle, 2)]; - result[3] = src[GET_SWZ(source->Swizzle, 3)]; - } - - if (source->Abs) { - result[0] = FABSF(result[0]); - result[1] = FABSF(result[1]); - result[2] = FABSF(result[2]); - result[3] = FABSF(result[3]); - } - if (source->Negate) { - ASSERT(source->Negate == NEGATE_XYZW); - result[0] = -result[0]; - result[1] = -result[1]; - result[2] = -result[2]; - result[3] = -result[3]; - } - -#ifdef NAN_CHECK - assert(!IS_INF_OR_NAN(result[0])); - assert(!IS_INF_OR_NAN(result[0])); - assert(!IS_INF_OR_NAN(result[0])); - assert(!IS_INF_OR_NAN(result[0])); -#endif -} - - -/** - * Fetch a 4-element uint vector from the given source register. - * Apply swizzling but not negation/abs. - */ -static void -fetch_vector4ui(const struct prog_src_register *source, - const struct gl_program_machine *machine, GLuint result[4]) -{ - const GLuint *src = (GLuint *) get_src_register_pointer(source, machine); - ASSERT(src); - - if (source->Swizzle == SWIZZLE_NOOP) { - /* no swizzling */ - COPY_4V(result, src); - } - else { - ASSERT(GET_SWZ(source->Swizzle, 0) <= 3); - ASSERT(GET_SWZ(source->Swizzle, 1) <= 3); - ASSERT(GET_SWZ(source->Swizzle, 2) <= 3); - ASSERT(GET_SWZ(source->Swizzle, 3) <= 3); - result[0] = src[GET_SWZ(source->Swizzle, 0)]; - result[1] = src[GET_SWZ(source->Swizzle, 1)]; - result[2] = src[GET_SWZ(source->Swizzle, 2)]; - result[3] = src[GET_SWZ(source->Swizzle, 3)]; - } - - /* Note: no Negate or Abs here */ -} - - - -/** - * Fetch the derivative with respect to X or Y for the given register. - * XXX this currently only works for fragment program input attribs. - */ -static void -fetch_vector4_deriv(GLcontext * ctx, - const struct prog_src_register *source, - const struct gl_program_machine *machine, - char xOrY, GLfloat result[4]) -{ - if (source->File == PROGRAM_INPUT && - source->Index < (GLint) machine->NumDeriv) { - const GLint col = machine->CurElement; - const GLfloat w = machine->Attribs[FRAG_ATTRIB_WPOS][col][3]; - const GLfloat invQ = 1.0f / w; - GLfloat deriv[4]; - - if (xOrY == 'X') { - deriv[0] = machine->DerivX[source->Index][0] * invQ; - deriv[1] = machine->DerivX[source->Index][1] * invQ; - deriv[2] = machine->DerivX[source->Index][2] * invQ; - deriv[3] = machine->DerivX[source->Index][3] * invQ; - } - else { - deriv[0] = machine->DerivY[source->Index][0] * invQ; - deriv[1] = machine->DerivY[source->Index][1] * invQ; - deriv[2] = machine->DerivY[source->Index][2] * invQ; - deriv[3] = machine->DerivY[source->Index][3] * invQ; - } - - result[0] = deriv[GET_SWZ(source->Swizzle, 0)]; - result[1] = deriv[GET_SWZ(source->Swizzle, 1)]; - result[2] = deriv[GET_SWZ(source->Swizzle, 2)]; - result[3] = deriv[GET_SWZ(source->Swizzle, 3)]; - - if (source->Abs) { - result[0] = FABSF(result[0]); - result[1] = FABSF(result[1]); - result[2] = FABSF(result[2]); - result[3] = FABSF(result[3]); - } - if (source->Negate) { - ASSERT(source->Negate == NEGATE_XYZW); - result[0] = -result[0]; - result[1] = -result[1]; - result[2] = -result[2]; - result[3] = -result[3]; - } - } - else { - ASSIGN_4V(result, 0.0, 0.0, 0.0, 0.0); - } -} - - -/** - * As above, but only return result[0] element. - */ -static void -fetch_vector1(const struct prog_src_register *source, - const struct gl_program_machine *machine, GLfloat result[4]) -{ - const GLfloat *src = get_src_register_pointer(source, machine); - ASSERT(src); - - result[0] = src[GET_SWZ(source->Swizzle, 0)]; - - if (source->Abs) { - result[0] = FABSF(result[0]); - } - if (source->Negate) { - result[0] = -result[0]; - } -} - - -static GLuint -fetch_vector1ui(const struct prog_src_register *source, - const struct gl_program_machine *machine) -{ - const GLuint *src = (GLuint *) get_src_register_pointer(source, machine); - return src[GET_SWZ(source->Swizzle, 0)]; -} - - -/** - * Fetch texel from texture. Use partial derivatives when possible. - */ -static INLINE void -fetch_texel(GLcontext *ctx, - const struct gl_program_machine *machine, - const struct prog_instruction *inst, - const GLfloat texcoord[4], GLfloat lodBias, - GLfloat color[4]) -{ - const GLuint unit = machine->Samplers[inst->TexSrcUnit]; - - /* Note: we only have the right derivatives for fragment input attribs. - */ - if (machine->NumDeriv > 0 && - inst->SrcReg[0].File == PROGRAM_INPUT && - inst->SrcReg[0].Index == FRAG_ATTRIB_TEX0 + inst->TexSrcUnit) { - /* simple texture fetch for which we should have derivatives */ - GLuint attr = inst->SrcReg[0].Index; - machine->FetchTexelDeriv(ctx, texcoord, - machine->DerivX[attr], - machine->DerivY[attr], - lodBias, unit, color); - } - else { - machine->FetchTexelLod(ctx, texcoord, lodBias, unit, color); - } -} - - -/** - * Test value against zero and return GT, LT, EQ or UN if NaN. - */ -static INLINE GLuint -generate_cc(float value) -{ - if (value != value) - return COND_UN; /* NaN */ - if (value > 0.0F) - return COND_GT; - if (value < 0.0F) - return COND_LT; - return COND_EQ; -} - - -/** - * Test if the ccMaskRule is satisfied by the given condition code. - * Used to mask destination writes according to the current condition code. - */ -static INLINE GLboolean -test_cc(GLuint condCode, GLuint ccMaskRule) -{ - switch (ccMaskRule) { - case COND_EQ: return (condCode == COND_EQ); - case COND_NE: return (condCode != COND_EQ); - case COND_LT: return (condCode == COND_LT); - case COND_GE: return (condCode == COND_GT || condCode == COND_EQ); - case COND_LE: return (condCode == COND_LT || condCode == COND_EQ); - case COND_GT: return (condCode == COND_GT); - case COND_TR: return GL_TRUE; - case COND_FL: return GL_FALSE; - default: return GL_TRUE; - } -} - - -/** - * Evaluate the 4 condition codes against a predicate and return GL_TRUE - * or GL_FALSE to indicate result. - */ -static INLINE GLboolean -eval_condition(const struct gl_program_machine *machine, - const struct prog_instruction *inst) -{ - const GLuint swizzle = inst->DstReg.CondSwizzle; - const GLuint condMask = inst->DstReg.CondMask; - if (test_cc(machine->CondCodes[GET_SWZ(swizzle, 0)], condMask) || - test_cc(machine->CondCodes[GET_SWZ(swizzle, 1)], condMask) || - test_cc(machine->CondCodes[GET_SWZ(swizzle, 2)], condMask) || - test_cc(machine->CondCodes[GET_SWZ(swizzle, 3)], condMask)) { - return GL_TRUE; - } - else { - return GL_FALSE; - } -} - - - -/** - * Store 4 floats into a register. Observe the instructions saturate and - * set-condition-code flags. - */ -static void -store_vector4(const struct prog_instruction *inst, - struct gl_program_machine *machine, const GLfloat value[4]) -{ - const struct prog_dst_register *dstReg = &(inst->DstReg); - const GLboolean clamp = inst->SaturateMode == SATURATE_ZERO_ONE; - GLuint writeMask = dstReg->WriteMask; - GLfloat clampedValue[4]; - GLfloat *dst = get_dst_register_pointer(dstReg, machine); - -#if 0 - if (value[0] > 1.0e10 || - IS_INF_OR_NAN(value[0]) || - IS_INF_OR_NAN(value[1]) || - IS_INF_OR_NAN(value[2]) || IS_INF_OR_NAN(value[3])) - printf("store %g %g %g %g\n", value[0], value[1], value[2], value[3]); -#endif - - if (clamp) { - clampedValue[0] = CLAMP(value[0], 0.0F, 1.0F); - clampedValue[1] = CLAMP(value[1], 0.0F, 1.0F); - clampedValue[2] = CLAMP(value[2], 0.0F, 1.0F); - clampedValue[3] = CLAMP(value[3], 0.0F, 1.0F); - value = clampedValue; - } - - if (dstReg->CondMask != COND_TR) { - /* condition codes may turn off some writes */ - if (writeMask & WRITEMASK_X) { - if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 0)], - dstReg->CondMask)) - writeMask &= ~WRITEMASK_X; - } - if (writeMask & WRITEMASK_Y) { - if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 1)], - dstReg->CondMask)) - writeMask &= ~WRITEMASK_Y; - } - if (writeMask & WRITEMASK_Z) { - if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 2)], - dstReg->CondMask)) - writeMask &= ~WRITEMASK_Z; - } - if (writeMask & WRITEMASK_W) { - if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 3)], - dstReg->CondMask)) - writeMask &= ~WRITEMASK_W; - } - } - -#ifdef NAN_CHECK - assert(!IS_INF_OR_NAN(value[0])); - assert(!IS_INF_OR_NAN(value[0])); - assert(!IS_INF_OR_NAN(value[0])); - assert(!IS_INF_OR_NAN(value[0])); -#endif - - if (writeMask & WRITEMASK_X) - dst[0] = value[0]; - if (writeMask & WRITEMASK_Y) - dst[1] = value[1]; - if (writeMask & WRITEMASK_Z) - dst[2] = value[2]; - if (writeMask & WRITEMASK_W) - dst[3] = value[3]; - - if (inst->CondUpdate) { - if (writeMask & WRITEMASK_X) - machine->CondCodes[0] = generate_cc(value[0]); - if (writeMask & WRITEMASK_Y) - machine->CondCodes[1] = generate_cc(value[1]); - if (writeMask & WRITEMASK_Z) - machine->CondCodes[2] = generate_cc(value[2]); - if (writeMask & WRITEMASK_W) - machine->CondCodes[3] = generate_cc(value[3]); -#if DEBUG_PROG - printf("CondCodes=(%s,%s,%s,%s) for:\n", - _mesa_condcode_string(machine->CondCodes[0]), - _mesa_condcode_string(machine->CondCodes[1]), - _mesa_condcode_string(machine->CondCodes[2]), - _mesa_condcode_string(machine->CondCodes[3])); -#endif - } -} - - -/** - * Store 4 uints into a register. Observe the set-condition-code flags. - */ -static void -store_vector4ui(const struct prog_instruction *inst, - struct gl_program_machine *machine, const GLuint value[4]) -{ - const struct prog_dst_register *dstReg = &(inst->DstReg); - GLuint writeMask = dstReg->WriteMask; - GLuint *dst = (GLuint *) get_dst_register_pointer(dstReg, machine); - - if (dstReg->CondMask != COND_TR) { - /* condition codes may turn off some writes */ - if (writeMask & WRITEMASK_X) { - if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 0)], - dstReg->CondMask)) - writeMask &= ~WRITEMASK_X; - } - if (writeMask & WRITEMASK_Y) { - if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 1)], - dstReg->CondMask)) - writeMask &= ~WRITEMASK_Y; - } - if (writeMask & WRITEMASK_Z) { - if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 2)], - dstReg->CondMask)) - writeMask &= ~WRITEMASK_Z; - } - if (writeMask & WRITEMASK_W) { - if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 3)], - dstReg->CondMask)) - writeMask &= ~WRITEMASK_W; - } - } - - if (writeMask & WRITEMASK_X) - dst[0] = value[0]; - if (writeMask & WRITEMASK_Y) - dst[1] = value[1]; - if (writeMask & WRITEMASK_Z) - dst[2] = value[2]; - if (writeMask & WRITEMASK_W) - dst[3] = value[3]; - - if (inst->CondUpdate) { - if (writeMask & WRITEMASK_X) - machine->CondCodes[0] = generate_cc((float)value[0]); - if (writeMask & WRITEMASK_Y) - machine->CondCodes[1] = generate_cc((float)value[1]); - if (writeMask & WRITEMASK_Z) - machine->CondCodes[2] = generate_cc((float)value[2]); - if (writeMask & WRITEMASK_W) - machine->CondCodes[3] = generate_cc((float)value[3]); -#if DEBUG_PROG - printf("CondCodes=(%s,%s,%s,%s) for:\n", - _mesa_condcode_string(machine->CondCodes[0]), - _mesa_condcode_string(machine->CondCodes[1]), - _mesa_condcode_string(machine->CondCodes[2]), - _mesa_condcode_string(machine->CondCodes[3])); -#endif - } -} - - - -/** - * Execute the given vertex/fragment program. - * - * \param ctx rendering context - * \param program the program to execute - * \param machine machine state (must be initialized) - * \return GL_TRUE if program completed or GL_FALSE if program executed KIL. - */ -GLboolean -_mesa_execute_program(GLcontext * ctx, - const struct gl_program *program, - struct gl_program_machine *machine) -{ - const GLuint numInst = program->NumInstructions; - const GLuint maxExec = 10000; - GLuint pc, numExec = 0; - - machine->CurProgram = program; - - if (DEBUG_PROG) { - printf("execute program %u --------------------\n", program->Id); - } - - if (program->Target == GL_VERTEX_PROGRAM_ARB) { - machine->EnvParams = ctx->VertexProgram.Parameters; - } - else { - machine->EnvParams = ctx->FragmentProgram.Parameters; - } - - for (pc = 0; pc < numInst; pc++) { - const struct prog_instruction *inst = program->Instructions + pc; - - if (DEBUG_PROG) { - _mesa_print_instruction(inst); - } - - switch (inst->Opcode) { - case OPCODE_ABS: - { - GLfloat a[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - result[0] = FABSF(a[0]); - result[1] = FABSF(a[1]); - result[2] = FABSF(a[2]); - result[3] = FABSF(a[3]); - store_vector4(inst, machine, result); - } - break; - case OPCODE_ADD: - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = a[0] + b[0]; - result[1] = a[1] + b[1]; - result[2] = a[2] + b[2]; - result[3] = a[3] + b[3]; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("ADD (%g %g %g %g) = (%g %g %g %g) + (%g %g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]); - } - } - break; - case OPCODE_AND: /* bitwise AND */ - { - GLuint a[4], b[4], result[4]; - fetch_vector4ui(&inst->SrcReg[0], machine, a); - fetch_vector4ui(&inst->SrcReg[1], machine, b); - result[0] = a[0] & b[0]; - result[1] = a[1] & b[1]; - result[2] = a[2] & b[2]; - result[3] = a[3] & b[3]; - store_vector4ui(inst, machine, result); - } - break; - case OPCODE_ARL: - { - GLfloat t[4]; - fetch_vector4(&inst->SrcReg[0], machine, t); - machine->AddressReg[0][0] = IFLOOR(t[0]); - if (DEBUG_PROG) { - printf("ARL %d\n", machine->AddressReg[0][0]); - } - } - break; - case OPCODE_BGNLOOP: - /* no-op */ - ASSERT(program->Instructions[inst->BranchTarget].Opcode - == OPCODE_ENDLOOP); - break; - case OPCODE_ENDLOOP: - /* subtract 1 here since pc is incremented by for(pc) loop */ - ASSERT(program->Instructions[inst->BranchTarget].Opcode - == OPCODE_BGNLOOP); - pc = inst->BranchTarget - 1; /* go to matching BNGLOOP */ - break; - case OPCODE_BGNSUB: /* begin subroutine */ - break; - case OPCODE_ENDSUB: /* end subroutine */ - break; - case OPCODE_BRA: /* branch (conditional) */ - if (eval_condition(machine, inst)) { - /* take branch */ - /* Subtract 1 here since we'll do pc++ below */ - pc = inst->BranchTarget - 1; - } - break; - case OPCODE_BRK: /* break out of loop (conditional) */ - ASSERT(program->Instructions[inst->BranchTarget].Opcode - == OPCODE_ENDLOOP); - if (eval_condition(machine, inst)) { - /* break out of loop */ - /* pc++ at end of for-loop will put us after the ENDLOOP inst */ - pc = inst->BranchTarget; - } - break; - case OPCODE_CONT: /* continue loop (conditional) */ - ASSERT(program->Instructions[inst->BranchTarget].Opcode - == OPCODE_ENDLOOP); - if (eval_condition(machine, inst)) { - /* continue at ENDLOOP */ - /* Subtract 1 here since we'll do pc++ at end of for-loop */ - pc = inst->BranchTarget - 1; - } - break; - case OPCODE_CAL: /* Call subroutine (conditional) */ - if (eval_condition(machine, inst)) { - /* call the subroutine */ - if (machine->StackDepth >= MAX_PROGRAM_CALL_DEPTH) { - return GL_TRUE; /* Per GL_NV_vertex_program2 spec */ - } - machine->CallStack[machine->StackDepth++] = pc + 1; /* next inst */ - /* Subtract 1 here since we'll do pc++ at end of for-loop */ - pc = inst->BranchTarget - 1; - } - break; - case OPCODE_CMP: - { - GLfloat a[4], b[4], c[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - fetch_vector4(&inst->SrcReg[2], machine, c); - result[0] = a[0] < 0.0F ? b[0] : c[0]; - result[1] = a[1] < 0.0F ? b[1] : c[1]; - result[2] = a[2] < 0.0F ? b[2] : c[2]; - result[3] = a[3] < 0.0F ? b[3] : c[3]; - store_vector4(inst, machine, result); - } - break; - case OPCODE_COS: - { - GLfloat a[4], result[4]; - fetch_vector1(&inst->SrcReg[0], machine, a); - result[0] = result[1] = result[2] = result[3] - = (GLfloat) cos(a[0]); - store_vector4(inst, machine, result); - } - break; - case OPCODE_DDX: /* Partial derivative with respect to X */ - { - GLfloat result[4]; - fetch_vector4_deriv(ctx, &inst->SrcReg[0], machine, - 'X', result); - store_vector4(inst, machine, result); - } - break; - case OPCODE_DDY: /* Partial derivative with respect to Y */ - { - GLfloat result[4]; - fetch_vector4_deriv(ctx, &inst->SrcReg[0], machine, - 'Y', result); - store_vector4(inst, machine, result); - } - break; - case OPCODE_DP2: - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = result[1] = result[2] = result[3] = DOT2(a, b); - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("DP2 %g = (%g %g) . (%g %g)\n", - result[0], a[0], a[1], b[0], b[1]); - } - } - break; - case OPCODE_DP2A: - { - GLfloat a[4], b[4], c, result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - fetch_vector1(&inst->SrcReg[1], machine, &c); - result[0] = result[1] = result[2] = result[3] = DOT2(a, b) + c; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("DP2A %g = (%g %g) . (%g %g) + %g\n", - result[0], a[0], a[1], b[0], b[1], c); - } - } - break; - case OPCODE_DP3: - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = result[1] = result[2] = result[3] = DOT3(a, b); - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("DP3 %g = (%g %g %g) . (%g %g %g)\n", - result[0], a[0], a[1], a[2], b[0], b[1], b[2]); - } - } - break; - case OPCODE_DP4: - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = result[1] = result[2] = result[3] = DOT4(a, b); - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("DP4 %g = (%g, %g %g %g) . (%g, %g %g %g)\n", - result[0], a[0], a[1], a[2], a[3], - b[0], b[1], b[2], b[3]); - } - } - break; - case OPCODE_DPH: - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = result[1] = result[2] = result[3] = DOT3(a, b) + b[3]; - store_vector4(inst, machine, result); - } - break; - case OPCODE_DST: /* Distance vector */ - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = 1.0F; - result[1] = a[1] * b[1]; - result[2] = a[2]; - result[3] = b[3]; - store_vector4(inst, machine, result); - } - break; - case OPCODE_EXP: - { - GLfloat t[4], q[4], floor_t0; - fetch_vector1(&inst->SrcReg[0], machine, t); - floor_t0 = FLOORF(t[0]); - if (floor_t0 > FLT_MAX_EXP) { - SET_POS_INFINITY(q[0]); - SET_POS_INFINITY(q[2]); - } - else if (floor_t0 < FLT_MIN_EXP) { - q[0] = 0.0F; - q[2] = 0.0F; - } - else { - q[0] = LDEXPF(1.0, (int) floor_t0); - /* Note: GL_NV_vertex_program expects - * result.z = result.x * APPX(result.y) - * We do what the ARB extension says. - */ - q[2] = (GLfloat) pow(2.0, t[0]); - } - q[1] = t[0] - floor_t0; - q[3] = 1.0F; - store_vector4( inst, machine, q ); - } - break; - case OPCODE_EX2: /* Exponential base 2 */ - { - GLfloat a[4], result[4], val; - fetch_vector1(&inst->SrcReg[0], machine, a); - val = (GLfloat) pow(2.0, a[0]); - /* - if (IS_INF_OR_NAN(val)) - val = 1.0e10; - */ - result[0] = result[1] = result[2] = result[3] = val; - store_vector4(inst, machine, result); - } - break; - case OPCODE_FLR: - { - GLfloat a[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - result[0] = FLOORF(a[0]); - result[1] = FLOORF(a[1]); - result[2] = FLOORF(a[2]); - result[3] = FLOORF(a[3]); - store_vector4(inst, machine, result); - } - break; - case OPCODE_FRC: - { - GLfloat a[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - result[0] = a[0] - FLOORF(a[0]); - result[1] = a[1] - FLOORF(a[1]); - result[2] = a[2] - FLOORF(a[2]); - result[3] = a[3] - FLOORF(a[3]); - store_vector4(inst, machine, result); - } - break; - case OPCODE_IF: - { - GLboolean cond; - ASSERT(program->Instructions[inst->BranchTarget].Opcode - == OPCODE_ELSE || - program->Instructions[inst->BranchTarget].Opcode - == OPCODE_ENDIF); - /* eval condition */ - if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { - GLfloat a[4]; - fetch_vector1(&inst->SrcReg[0], machine, a); - cond = (a[0] != 0.0); - } - else { - cond = eval_condition(machine, inst); - } - if (DEBUG_PROG) { - printf("IF: %d\n", cond); - } - /* do if/else */ - if (cond) { - /* do if-clause (just continue execution) */ - } - else { - /* go to the instruction after ELSE or ENDIF */ - assert(inst->BranchTarget >= 0); - pc = inst->BranchTarget; - } - } - break; - case OPCODE_ELSE: - /* goto ENDIF */ - ASSERT(program->Instructions[inst->BranchTarget].Opcode - == OPCODE_ENDIF); - assert(inst->BranchTarget >= 0); - pc = inst->BranchTarget; - break; - case OPCODE_ENDIF: - /* nothing */ - break; - case OPCODE_KIL_NV: /* NV_f_p only (conditional) */ - if (eval_condition(machine, inst)) { - return GL_FALSE; - } - break; - case OPCODE_KIL: /* ARB_f_p only */ - { - GLfloat a[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - if (DEBUG_PROG) { - printf("KIL if (%g %g %g %g) <= 0.0\n", - a[0], a[1], a[2], a[3]); - } - - if (a[0] < 0.0F || a[1] < 0.0F || a[2] < 0.0F || a[3] < 0.0F) { - return GL_FALSE; - } - } - break; - case OPCODE_LG2: /* log base 2 */ - { - GLfloat a[4], result[4], val; - fetch_vector1(&inst->SrcReg[0], machine, a); - /* The fast LOG2 macro doesn't meet the precision requirements. - */ - if (a[0] == 0.0F) { - val = -FLT_MAX; - } - else { - val = (float)(log(a[0]) * 1.442695F); - } - result[0] = result[1] = result[2] = result[3] = val; - store_vector4(inst, machine, result); - } - break; - case OPCODE_LIT: - { - const GLfloat epsilon = 1.0F / 256.0F; /* from NV VP spec */ - GLfloat a[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - a[0] = MAX2(a[0], 0.0F); - a[1] = MAX2(a[1], 0.0F); - /* XXX ARB version clamps a[3], NV version doesn't */ - a[3] = CLAMP(a[3], -(128.0F - epsilon), (128.0F - epsilon)); - result[0] = 1.0F; - result[1] = a[0]; - /* XXX we could probably just use pow() here */ - if (a[0] > 0.0F) { - if (a[1] == 0.0 && a[3] == 0.0) - result[2] = 1.0F; - else - result[2] = (GLfloat) pow(a[1], a[3]); - } - else { - result[2] = 0.0F; - } - result[3] = 1.0F; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("LIT (%g %g %g %g) : (%g %g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], a[3]); - } - } - break; - case OPCODE_LOG: - { - GLfloat t[4], q[4], abs_t0; - fetch_vector1(&inst->SrcReg[0], machine, t); - abs_t0 = FABSF(t[0]); - if (abs_t0 != 0.0F) { - /* Since we really can't handle infinite values on VMS - * like other OSes we'll use __MAXFLOAT to represent - * infinity. This may need some tweaking. - */ -#ifdef VMS - if (abs_t0 == __MAXFLOAT) -#else - if (IS_INF_OR_NAN(abs_t0)) -#endif - { - SET_POS_INFINITY(q[0]); - q[1] = 1.0F; - SET_POS_INFINITY(q[2]); - } - else { - int exponent; - GLfloat mantissa = FREXPF(t[0], &exponent); - q[0] = (GLfloat) (exponent - 1); - q[1] = (GLfloat) (2.0 * mantissa); /* map [.5, 1) -> [1, 2) */ - - /* The fast LOG2 macro doesn't meet the precision - * requirements. - */ - q[2] = (float)(log(t[0]) * 1.442695F); - } - } - else { - SET_NEG_INFINITY(q[0]); - q[1] = 1.0F; - SET_NEG_INFINITY(q[2]); - } - q[3] = 1.0; - store_vector4(inst, machine, q); - } - break; - case OPCODE_LRP: - { - GLfloat a[4], b[4], c[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - fetch_vector4(&inst->SrcReg[2], machine, c); - result[0] = a[0] * b[0] + (1.0F - a[0]) * c[0]; - result[1] = a[1] * b[1] + (1.0F - a[1]) * c[1]; - result[2] = a[2] * b[2] + (1.0F - a[2]) * c[2]; - result[3] = a[3] * b[3] + (1.0F - a[3]) * c[3]; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("LRP (%g %g %g %g) = (%g %g %g %g), " - "(%g %g %g %g), (%g %g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], a[3], - b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]); - } - } - break; - case OPCODE_MAD: - { - GLfloat a[4], b[4], c[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - fetch_vector4(&inst->SrcReg[2], machine, c); - result[0] = a[0] * b[0] + c[0]; - result[1] = a[1] * b[1] + c[1]; - result[2] = a[2] * b[2] + c[2]; - result[3] = a[3] * b[3] + c[3]; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("MAD (%g %g %g %g) = (%g %g %g %g) * " - "(%g %g %g %g) + (%g %g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], a[3], - b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]); - } - } - break; - case OPCODE_MAX: - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = MAX2(a[0], b[0]); - result[1] = MAX2(a[1], b[1]); - result[2] = MAX2(a[2], b[2]); - result[3] = MAX2(a[3], b[3]); - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("MAX (%g %g %g %g) = (%g %g %g %g), (%g %g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]); - } - } - break; - case OPCODE_MIN: - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = MIN2(a[0], b[0]); - result[1] = MIN2(a[1], b[1]); - result[2] = MIN2(a[2], b[2]); - result[3] = MIN2(a[3], b[3]); - store_vector4(inst, machine, result); - } - break; - case OPCODE_MOV: - { - GLfloat result[4]; - fetch_vector4(&inst->SrcReg[0], machine, result); - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("MOV (%g %g %g %g)\n", - result[0], result[1], result[2], result[3]); - } - } - break; - case OPCODE_MUL: - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = a[0] * b[0]; - result[1] = a[1] * b[1]; - result[2] = a[2] * b[2]; - result[3] = a[3] * b[3]; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("MUL (%g %g %g %g) = (%g %g %g %g) * (%g %g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]); - } - } - break; - case OPCODE_NOISE1: - { - GLfloat a[4], result[4]; - fetch_vector1(&inst->SrcReg[0], machine, a); - result[0] = - result[1] = - result[2] = - result[3] = _mesa_noise1(a[0]); - store_vector4(inst, machine, result); - } - break; - case OPCODE_NOISE2: - { - GLfloat a[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - result[0] = - result[1] = - result[2] = result[3] = _mesa_noise2(a[0], a[1]); - store_vector4(inst, machine, result); - } - break; - case OPCODE_NOISE3: - { - GLfloat a[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - result[0] = - result[1] = - result[2] = - result[3] = _mesa_noise3(a[0], a[1], a[2]); - store_vector4(inst, machine, result); - } - break; - case OPCODE_NOISE4: - { - GLfloat a[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - result[0] = - result[1] = - result[2] = - result[3] = _mesa_noise4(a[0], a[1], a[2], a[3]); - store_vector4(inst, machine, result); - } - break; - case OPCODE_NOP: - break; - case OPCODE_NOT: /* bitwise NOT */ - { - GLuint a[4], result[4]; - fetch_vector4ui(&inst->SrcReg[0], machine, a); - result[0] = ~a[0]; - result[1] = ~a[1]; - result[2] = ~a[2]; - result[3] = ~a[3]; - store_vector4ui(inst, machine, result); - } - break; - case OPCODE_NRM3: /* 3-component normalization */ - { - GLfloat a[4], result[4]; - GLfloat tmp; - fetch_vector4(&inst->SrcReg[0], machine, a); - tmp = a[0] * a[0] + a[1] * a[1] + a[2] * a[2]; - if (tmp != 0.0F) - tmp = INV_SQRTF(tmp); - result[0] = tmp * a[0]; - result[1] = tmp * a[1]; - result[2] = tmp * a[2]; - result[3] = 0.0; /* undefined, but prevent valgrind warnings */ - store_vector4(inst, machine, result); - } - break; - case OPCODE_NRM4: /* 4-component normalization */ - { - GLfloat a[4], result[4]; - GLfloat tmp; - fetch_vector4(&inst->SrcReg[0], machine, a); - tmp = a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3]; - if (tmp != 0.0F) - tmp = INV_SQRTF(tmp); - result[0] = tmp * a[0]; - result[1] = tmp * a[1]; - result[2] = tmp * a[2]; - result[3] = tmp * a[3]; - store_vector4(inst, machine, result); - } - break; - case OPCODE_OR: /* bitwise OR */ - { - GLuint a[4], b[4], result[4]; - fetch_vector4ui(&inst->SrcReg[0], machine, a); - fetch_vector4ui(&inst->SrcReg[1], machine, b); - result[0] = a[0] | b[0]; - result[1] = a[1] | b[1]; - result[2] = a[2] | b[2]; - result[3] = a[3] | b[3]; - store_vector4ui(inst, machine, result); - } - break; - case OPCODE_PK2H: /* pack two 16-bit floats in one 32-bit float */ - { - GLfloat a[4]; - GLuint result[4]; - GLhalfNV hx, hy; - fetch_vector4(&inst->SrcReg[0], machine, a); - hx = _mesa_float_to_half(a[0]); - hy = _mesa_float_to_half(a[1]); - result[0] = - result[1] = - result[2] = - result[3] = hx | (hy << 16); - store_vector4ui(inst, machine, result); - } - break; - case OPCODE_PK2US: /* pack two GLushorts into one 32-bit float */ - { - GLfloat a[4]; - GLuint result[4], usx, usy; - fetch_vector4(&inst->SrcReg[0], machine, a); - a[0] = CLAMP(a[0], 0.0F, 1.0F); - a[1] = CLAMP(a[1], 0.0F, 1.0F); - usx = IROUND(a[0] * 65535.0F); - usy = IROUND(a[1] * 65535.0F); - result[0] = - result[1] = - result[2] = - result[3] = usx | (usy << 16); - store_vector4ui(inst, machine, result); - } - break; - case OPCODE_PK4B: /* pack four GLbytes into one 32-bit float */ - { - GLfloat a[4]; - GLuint result[4], ubx, uby, ubz, ubw; - fetch_vector4(&inst->SrcReg[0], machine, a); - a[0] = CLAMP(a[0], -128.0F / 127.0F, 1.0F); - a[1] = CLAMP(a[1], -128.0F / 127.0F, 1.0F); - a[2] = CLAMP(a[2], -128.0F / 127.0F, 1.0F); - a[3] = CLAMP(a[3], -128.0F / 127.0F, 1.0F); - ubx = IROUND(127.0F * a[0] + 128.0F); - uby = IROUND(127.0F * a[1] + 128.0F); - ubz = IROUND(127.0F * a[2] + 128.0F); - ubw = IROUND(127.0F * a[3] + 128.0F); - result[0] = - result[1] = - result[2] = - result[3] = ubx | (uby << 8) | (ubz << 16) | (ubw << 24); - store_vector4ui(inst, machine, result); - } - break; - case OPCODE_PK4UB: /* pack four GLubytes into one 32-bit float */ - { - GLfloat a[4]; - GLuint result[4], ubx, uby, ubz, ubw; - fetch_vector4(&inst->SrcReg[0], machine, a); - a[0] = CLAMP(a[0], 0.0F, 1.0F); - a[1] = CLAMP(a[1], 0.0F, 1.0F); - a[2] = CLAMP(a[2], 0.0F, 1.0F); - a[3] = CLAMP(a[3], 0.0F, 1.0F); - ubx = IROUND(255.0F * a[0]); - uby = IROUND(255.0F * a[1]); - ubz = IROUND(255.0F * a[2]); - ubw = IROUND(255.0F * a[3]); - result[0] = - result[1] = - result[2] = - result[3] = ubx | (uby << 8) | (ubz << 16) | (ubw << 24); - store_vector4ui(inst, machine, result); - } - break; - case OPCODE_POW: - { - GLfloat a[4], b[4], result[4]; - fetch_vector1(&inst->SrcReg[0], machine, a); - fetch_vector1(&inst->SrcReg[1], machine, b); - result[0] = result[1] = result[2] = result[3] - = (GLfloat) pow(a[0], b[0]); - store_vector4(inst, machine, result); - } - break; - case OPCODE_RCP: - { - GLfloat a[4], result[4]; - fetch_vector1(&inst->SrcReg[0], machine, a); - if (DEBUG_PROG) { - if (a[0] == 0) - printf("RCP(0)\n"); - else if (IS_INF_OR_NAN(a[0])) - printf("RCP(inf)\n"); - } - result[0] = result[1] = result[2] = result[3] = 1.0F / a[0]; - store_vector4(inst, machine, result); - } - break; - case OPCODE_RET: /* return from subroutine (conditional) */ - if (eval_condition(machine, inst)) { - if (machine->StackDepth == 0) { - return GL_TRUE; /* Per GL_NV_vertex_program2 spec */ - } - /* subtract one because of pc++ in the for loop */ - pc = machine->CallStack[--machine->StackDepth] - 1; - } - break; - case OPCODE_RFL: /* reflection vector */ - { - GLfloat axis[4], dir[4], result[4], tmpX, tmpW; - fetch_vector4(&inst->SrcReg[0], machine, axis); - fetch_vector4(&inst->SrcReg[1], machine, dir); - tmpW = DOT3(axis, axis); - tmpX = (2.0F * DOT3(axis, dir)) / tmpW; - result[0] = tmpX * axis[0] - dir[0]; - result[1] = tmpX * axis[1] - dir[1]; - result[2] = tmpX * axis[2] - dir[2]; - /* result[3] is never written! XXX enforce in parser! */ - store_vector4(inst, machine, result); - } - break; - case OPCODE_RSQ: /* 1 / sqrt() */ - { - GLfloat a[4], result[4]; - fetch_vector1(&inst->SrcReg[0], machine, a); - a[0] = FABSF(a[0]); - result[0] = result[1] = result[2] = result[3] = INV_SQRTF(a[0]); - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("RSQ %g = 1/sqrt(|%g|)\n", result[0], a[0]); - } - } - break; - case OPCODE_SCS: /* sine and cos */ - { - GLfloat a[4], result[4]; - fetch_vector1(&inst->SrcReg[0], machine, a); - result[0] = (GLfloat) cos(a[0]); - result[1] = (GLfloat) sin(a[0]); - result[2] = 0.0; /* undefined! */ - result[3] = 0.0; /* undefined! */ - store_vector4(inst, machine, result); - } - break; - case OPCODE_SEQ: /* set on equal */ - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = (a[0] == b[0]) ? 1.0F : 0.0F; - result[1] = (a[1] == b[1]) ? 1.0F : 0.0F; - result[2] = (a[2] == b[2]) ? 1.0F : 0.0F; - result[3] = (a[3] == b[3]) ? 1.0F : 0.0F; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("SEQ (%g %g %g %g) = (%g %g %g %g) == (%g %g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], a[3], - b[0], b[1], b[2], b[3]); - } - } - break; - case OPCODE_SFL: /* set false, operands ignored */ - { - static const GLfloat result[4] = { 0.0F, 0.0F, 0.0F, 0.0F }; - store_vector4(inst, machine, result); - } - break; - case OPCODE_SGE: /* set on greater or equal */ - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = (a[0] >= b[0]) ? 1.0F : 0.0F; - result[1] = (a[1] >= b[1]) ? 1.0F : 0.0F; - result[2] = (a[2] >= b[2]) ? 1.0F : 0.0F; - result[3] = (a[3] >= b[3]) ? 1.0F : 0.0F; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("SGE (%g %g %g %g) = (%g %g %g %g) >= (%g %g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], a[3], - b[0], b[1], b[2], b[3]); - } - } - break; - case OPCODE_SGT: /* set on greater */ - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = (a[0] > b[0]) ? 1.0F : 0.0F; - result[1] = (a[1] > b[1]) ? 1.0F : 0.0F; - result[2] = (a[2] > b[2]) ? 1.0F : 0.0F; - result[3] = (a[3] > b[3]) ? 1.0F : 0.0F; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("SGT (%g %g %g %g) = (%g %g %g %g) > (%g %g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], a[3], - b[0], b[1], b[2], b[3]); - } - } - break; - case OPCODE_SIN: - { - GLfloat a[4], result[4]; - fetch_vector1(&inst->SrcReg[0], machine, a); - result[0] = result[1] = result[2] = result[3] - = (GLfloat) sin(a[0]); - store_vector4(inst, machine, result); - } - break; - case OPCODE_SLE: /* set on less or equal */ - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = (a[0] <= b[0]) ? 1.0F : 0.0F; - result[1] = (a[1] <= b[1]) ? 1.0F : 0.0F; - result[2] = (a[2] <= b[2]) ? 1.0F : 0.0F; - result[3] = (a[3] <= b[3]) ? 1.0F : 0.0F; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("SLE (%g %g %g %g) = (%g %g %g %g) <= (%g %g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], a[3], - b[0], b[1], b[2], b[3]); - } - } - break; - case OPCODE_SLT: /* set on less */ - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = (a[0] < b[0]) ? 1.0F : 0.0F; - result[1] = (a[1] < b[1]) ? 1.0F : 0.0F; - result[2] = (a[2] < b[2]) ? 1.0F : 0.0F; - result[3] = (a[3] < b[3]) ? 1.0F : 0.0F; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("SLT (%g %g %g %g) = (%g %g %g %g) < (%g %g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], a[3], - b[0], b[1], b[2], b[3]); - } - } - break; - case OPCODE_SNE: /* set on not equal */ - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = (a[0] != b[0]) ? 1.0F : 0.0F; - result[1] = (a[1] != b[1]) ? 1.0F : 0.0F; - result[2] = (a[2] != b[2]) ? 1.0F : 0.0F; - result[3] = (a[3] != b[3]) ? 1.0F : 0.0F; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("SNE (%g %g %g %g) = (%g %g %g %g) != (%g %g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], a[3], - b[0], b[1], b[2], b[3]); - } - } - break; - case OPCODE_SSG: /* set sign (-1, 0 or +1) */ - { - GLfloat a[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - result[0] = (GLfloat) ((a[0] > 0.0F) - (a[0] < 0.0F)); - result[1] = (GLfloat) ((a[1] > 0.0F) - (a[1] < 0.0F)); - result[2] = (GLfloat) ((a[2] > 0.0F) - (a[2] < 0.0F)); - result[3] = (GLfloat) ((a[3] > 0.0F) - (a[3] < 0.0F)); - store_vector4(inst, machine, result); - } - break; - case OPCODE_STR: /* set true, operands ignored */ - { - static const GLfloat result[4] = { 1.0F, 1.0F, 1.0F, 1.0F }; - store_vector4(inst, machine, result); - } - break; - case OPCODE_SUB: - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = a[0] - b[0]; - result[1] = a[1] - b[1]; - result[2] = a[2] - b[2]; - result[3] = a[3] - b[3]; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("SUB (%g %g %g %g) = (%g %g %g %g) - (%g %g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]); - } - } - break; - case OPCODE_SWZ: /* extended swizzle */ - { - const struct prog_src_register *source = &inst->SrcReg[0]; - const GLfloat *src = get_src_register_pointer(source, machine); - GLfloat result[4]; - GLuint i; - for (i = 0; i < 4; i++) { - const GLuint swz = GET_SWZ(source->Swizzle, i); - if (swz == SWIZZLE_ZERO) - result[i] = 0.0; - else if (swz == SWIZZLE_ONE) - result[i] = 1.0; - else { - ASSERT(swz >= 0); - ASSERT(swz <= 3); - result[i] = src[swz]; - } - if (source->Negate & (1 << i)) - result[i] = -result[i]; - } - store_vector4(inst, machine, result); - } - break; - case OPCODE_TEX: /* Both ARB and NV frag prog */ - /* Simple texel lookup */ - { - GLfloat texcoord[4], color[4]; - fetch_vector4(&inst->SrcReg[0], machine, texcoord); - - fetch_texel(ctx, machine, inst, texcoord, 0.0, color); - - if (DEBUG_PROG) { - printf("TEX (%g, %g, %g, %g) = texture[%d][%g, %g, %g, %g]\n", - color[0], color[1], color[2], color[3], - inst->TexSrcUnit, - texcoord[0], texcoord[1], texcoord[2], texcoord[3]); - } - store_vector4(inst, machine, color); - } - break; - case OPCODE_TXB: /* GL_ARB_fragment_program only */ - /* Texel lookup with LOD bias */ - { - GLfloat texcoord[4], color[4], lodBias; - - fetch_vector4(&inst->SrcReg[0], machine, texcoord); - - /* texcoord[3] is the bias to add to lambda */ - lodBias = texcoord[3]; - - fetch_texel(ctx, machine, inst, texcoord, lodBias, color); - - store_vector4(inst, machine, color); - } - break; - case OPCODE_TXD: /* GL_NV_fragment_program only */ - /* Texture lookup w/ partial derivatives for LOD */ - { - GLfloat texcoord[4], dtdx[4], dtdy[4], color[4]; - fetch_vector4(&inst->SrcReg[0], machine, texcoord); - fetch_vector4(&inst->SrcReg[1], machine, dtdx); - fetch_vector4(&inst->SrcReg[2], machine, dtdy); - machine->FetchTexelDeriv(ctx, texcoord, dtdx, dtdy, - 0.0, /* lodBias */ - inst->TexSrcUnit, color); - store_vector4(inst, machine, color); - } - break; - case OPCODE_TXP: /* GL_ARB_fragment_program only */ - /* Texture lookup w/ projective divide */ - { - GLfloat texcoord[4], color[4]; - - fetch_vector4(&inst->SrcReg[0], machine, texcoord); - /* Not so sure about this test - if texcoord[3] is - * zero, we'd probably be fine except for an ASSERT in - * IROUND_POS() which gets triggered by the inf values created. - */ - if (texcoord[3] != 0.0) { - texcoord[0] /= texcoord[3]; - texcoord[1] /= texcoord[3]; - texcoord[2] /= texcoord[3]; - } - - fetch_texel(ctx, machine, inst, texcoord, 0.0, color); - - store_vector4(inst, machine, color); - } - break; - case OPCODE_TXP_NV: /* GL_NV_fragment_program only */ - /* Texture lookup w/ projective divide, as above, but do not - * do the divide by w if sampling from a cube map. - */ - { - GLfloat texcoord[4], color[4]; - - fetch_vector4(&inst->SrcReg[0], machine, texcoord); - if (inst->TexSrcTarget != TEXTURE_CUBE_INDEX && - texcoord[3] != 0.0) { - texcoord[0] /= texcoord[3]; - texcoord[1] /= texcoord[3]; - texcoord[2] /= texcoord[3]; - } - - fetch_texel(ctx, machine, inst, texcoord, 0.0, color); - - store_vector4(inst, machine, color); - } - break; - case OPCODE_TRUNC: /* truncate toward zero */ - { - GLfloat a[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - result[0] = (GLfloat) (GLint) a[0]; - result[1] = (GLfloat) (GLint) a[1]; - result[2] = (GLfloat) (GLint) a[2]; - result[3] = (GLfloat) (GLint) a[3]; - store_vector4(inst, machine, result); - } - break; - case OPCODE_UP2H: /* unpack two 16-bit floats */ - { - const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine); - GLfloat result[4]; - GLushort hx, hy; - hx = raw & 0xffff; - hy = raw >> 16; - result[0] = result[2] = _mesa_half_to_float(hx); - result[1] = result[3] = _mesa_half_to_float(hy); - store_vector4(inst, machine, result); - } - break; - case OPCODE_UP2US: /* unpack two GLushorts */ - { - const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine); - GLfloat result[4]; - GLushort usx, usy; - usx = raw & 0xffff; - usy = raw >> 16; - result[0] = result[2] = usx * (1.0f / 65535.0f); - result[1] = result[3] = usy * (1.0f / 65535.0f); - store_vector4(inst, machine, result); - } - break; - case OPCODE_UP4B: /* unpack four GLbytes */ - { - const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine); - GLfloat result[4]; - result[0] = (((raw >> 0) & 0xff) - 128) / 127.0F; - result[1] = (((raw >> 8) & 0xff) - 128) / 127.0F; - result[2] = (((raw >> 16) & 0xff) - 128) / 127.0F; - result[3] = (((raw >> 24) & 0xff) - 128) / 127.0F; - store_vector4(inst, machine, result); - } - break; - case OPCODE_UP4UB: /* unpack four GLubytes */ - { - const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine); - GLfloat result[4]; - result[0] = ((raw >> 0) & 0xff) / 255.0F; - result[1] = ((raw >> 8) & 0xff) / 255.0F; - result[2] = ((raw >> 16) & 0xff) / 255.0F; - result[3] = ((raw >> 24) & 0xff) / 255.0F; - store_vector4(inst, machine, result); - } - break; - case OPCODE_XOR: /* bitwise XOR */ - { - GLuint a[4], b[4], result[4]; - fetch_vector4ui(&inst->SrcReg[0], machine, a); - fetch_vector4ui(&inst->SrcReg[1], machine, b); - result[0] = a[0] ^ b[0]; - result[1] = a[1] ^ b[1]; - result[2] = a[2] ^ b[2]; - result[3] = a[3] ^ b[3]; - store_vector4ui(inst, machine, result); - } - break; - case OPCODE_XPD: /* cross product */ - { - GLfloat a[4], b[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - result[0] = a[1] * b[2] - a[2] * b[1]; - result[1] = a[2] * b[0] - a[0] * b[2]; - result[2] = a[0] * b[1] - a[1] * b[0]; - result[3] = 1.0; - store_vector4(inst, machine, result); - if (DEBUG_PROG) { - printf("XPD (%g %g %g %g) = (%g %g %g) X (%g %g %g)\n", - result[0], result[1], result[2], result[3], - a[0], a[1], a[2], b[0], b[1], b[2]); - } - } - break; - case OPCODE_X2D: /* 2-D matrix transform */ - { - GLfloat a[4], b[4], c[4], result[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - fetch_vector4(&inst->SrcReg[1], machine, b); - fetch_vector4(&inst->SrcReg[2], machine, c); - result[0] = a[0] + b[0] * c[0] + b[1] * c[1]; - result[1] = a[1] + b[0] * c[2] + b[1] * c[3]; - result[2] = a[2] + b[0] * c[0] + b[1] * c[1]; - result[3] = a[3] + b[0] * c[2] + b[1] * c[3]; - store_vector4(inst, machine, result); - } - break; - case OPCODE_PRINT: - { - if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { - GLfloat a[4]; - fetch_vector4(&inst->SrcReg[0], machine, a); - printf("%s%g, %g, %g, %g\n", (const char *) inst->Data, - a[0], a[1], a[2], a[3]); - } - else { - printf("%s\n", (const char *) inst->Data); - } - } - break; - case OPCODE_END: - return GL_TRUE; - default: - _mesa_problem(ctx, "Bad opcode %d in _mesa_execute_program", - inst->Opcode); - return GL_TRUE; /* return value doesn't matter */ - } - - numExec++; - if (numExec > maxExec) { - _mesa_problem(ctx, "Infinite loop detected in fragment program"); - return GL_TRUE; - } - - } /* for pc */ - - return GL_TRUE; -} diff --git a/src/mesa/shader/prog_execute.h b/src/mesa/shader/prog_execute.h deleted file mode 100644 index adefc5439d..0000000000 --- a/src/mesa/shader/prog_execute.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.0.3 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef PROG_EXECUTE_H -#define PROG_EXECUTE_H - -#include "main/config.h" - - -typedef void (*FetchTexelLodFunc)(GLcontext *ctx, const GLfloat texcoord[4], - GLfloat lambda, GLuint unit, GLfloat color[4]); - -typedef void (*FetchTexelDerivFunc)(GLcontext *ctx, const GLfloat texcoord[4], - const GLfloat texdx[4], - const GLfloat texdy[4], - GLfloat lodBias, - GLuint unit, GLfloat color[4]); - - -/** - * Virtual machine state used during execution of vertex/fragment programs. - */ -struct gl_program_machine -{ - const struct gl_program *CurProgram; - - /** Fragment Input attributes */ - GLfloat (*Attribs)[MAX_WIDTH][4]; - GLfloat (*DerivX)[4]; - GLfloat (*DerivY)[4]; - GLuint NumDeriv; /**< Max index into DerivX/Y arrays */ - GLuint CurElement; /**< Index into Attribs arrays */ - - /** Vertex Input attribs */ - GLfloat VertAttribs[VERT_ATTRIB_MAX][4]; - - GLfloat Temporaries[MAX_PROGRAM_TEMPS][4]; - GLfloat Outputs[MAX_PROGRAM_OUTPUTS][4]; - GLfloat (*EnvParams)[4]; /**< Vertex or Fragment env parameters */ - GLuint CondCodes[4]; /**< COND_* value for x/y/z/w */ - GLint AddressReg[MAX_PROGRAM_ADDRESS_REGS][4]; - - const GLubyte *Samplers; /** Array mapping sampler var to tex unit */ - - GLuint CallStack[MAX_PROGRAM_CALL_DEPTH]; /**< For CAL/RET instructions */ - GLuint StackDepth; /**< Index/ptr to top of CallStack[] */ - - /** Texture fetch functions */ - FetchTexelLodFunc FetchTexelLod; - FetchTexelDerivFunc FetchTexelDeriv; -}; - - -extern void -_mesa_get_program_register(GLcontext *ctx, gl_register_file file, - GLuint index, GLfloat val[4]); - -extern GLboolean -_mesa_execute_program(GLcontext *ctx, - const struct gl_program *program, - struct gl_program_machine *machine); - - -#endif /* PROG_EXECUTE_H */ diff --git a/src/mesa/shader/prog_instruction.c b/src/mesa/shader/prog_instruction.c deleted file mode 100644 index 81099cb99c..0000000000 --- a/src/mesa/shader/prog_instruction.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.3 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include "main/glheader.h" -#include "main/imports.h" -#include "main/mtypes.h" -#include "prog_instruction.h" - - -/** - * Initialize program instruction fields to defaults. - * \param inst first instruction to initialize - * \param count number of instructions to initialize - */ -void -_mesa_init_instructions(struct prog_instruction *inst, GLuint count) -{ - GLuint i; - - memset(inst, 0, count * sizeof(struct prog_instruction)); - - for (i = 0; i < count; i++) { - inst[i].SrcReg[0].File = PROGRAM_UNDEFINED; - inst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP; - inst[i].SrcReg[1].File = PROGRAM_UNDEFINED; - inst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; - inst[i].SrcReg[2].File = PROGRAM_UNDEFINED; - inst[i].SrcReg[2].Swizzle = SWIZZLE_NOOP; - - inst[i].DstReg.File = PROGRAM_UNDEFINED; - inst[i].DstReg.WriteMask = WRITEMASK_XYZW; - inst[i].DstReg.CondMask = COND_TR; - inst[i].DstReg.CondSwizzle = SWIZZLE_NOOP; - - inst[i].SaturateMode = SATURATE_OFF; - inst[i].Precision = FLOAT32; - } -} - - -/** - * Allocate an array of program instructions. - * \param numInst number of instructions - * \return pointer to instruction memory - */ -struct prog_instruction * -_mesa_alloc_instructions(GLuint numInst) -{ - return (struct prog_instruction *) - calloc(1, numInst * sizeof(struct prog_instruction)); -} - - -/** - * Reallocate memory storing an array of program instructions. - * This is used when we need to append additional instructions onto an - * program. - * \param oldInst pointer to first of old/src instructions - * \param numOldInst number of instructions at - * \param numNewInst desired size of new instruction array. - * \return pointer to start of new instruction array. - */ -struct prog_instruction * -_mesa_realloc_instructions(struct prog_instruction *oldInst, - GLuint numOldInst, GLuint numNewInst) -{ - struct prog_instruction *newInst; - - newInst = (struct prog_instruction *) - _mesa_realloc(oldInst, - numOldInst * sizeof(struct prog_instruction), - numNewInst * sizeof(struct prog_instruction)); - - return newInst; -} - - -/** - * Copy an array of program instructions. - * \param dest pointer to destination. - * \param src pointer to source. - * \param n number of instructions to copy. - * \return pointer to destination. - */ -struct prog_instruction * -_mesa_copy_instructions(struct prog_instruction *dest, - const struct prog_instruction *src, GLuint n) -{ - GLuint i; - memcpy(dest, src, n * sizeof(struct prog_instruction)); - for (i = 0; i < n; i++) { - if (src[i].Comment) - dest[i].Comment = _mesa_strdup(src[i].Comment); - } - return dest; -} - - -/** - * Free an array of instructions - */ -void -_mesa_free_instructions(struct prog_instruction *inst, GLuint count) -{ - GLuint i; - for (i = 0; i < count; i++) { - if (inst[i].Data) - free(inst[i].Data); - if (inst[i].Comment) - free((char *) inst[i].Comment); - } - free(inst); -} - - -/** - * Basic info about each instruction - */ -struct instruction_info -{ - gl_inst_opcode Opcode; - const char *Name; - GLuint NumSrcRegs; - GLuint NumDstRegs; -}; - -/** - * Instruction info - * \note Opcode should equal array index! - */ -static const struct instruction_info InstInfo[MAX_OPCODE] = { - { OPCODE_NOP, "NOP", 0, 0 }, - { OPCODE_ABS, "ABS", 1, 1 }, - { OPCODE_ADD, "ADD", 2, 1 }, - { OPCODE_AND, "AND", 2, 1 }, - { OPCODE_ARA, "ARA", 1, 1 }, - { OPCODE_ARL, "ARL", 1, 1 }, - { OPCODE_ARL_NV, "ARL_NV", 1, 1 }, - { OPCODE_ARR, "ARL", 1, 1 }, - { OPCODE_BGNLOOP,"BGNLOOP", 0, 0 }, - { OPCODE_BGNSUB, "BGNSUB", 0, 0 }, - { OPCODE_BRA, "BRA", 0, 0 }, - { OPCODE_BRK, "BRK", 0, 0 }, - { OPCODE_CAL, "CAL", 0, 0 }, - { OPCODE_CMP, "CMP", 3, 1 }, - { OPCODE_CONT, "CONT", 0, 0 }, - { OPCODE_COS, "COS", 1, 1 }, - { OPCODE_DDX, "DDX", 1, 1 }, - { OPCODE_DDY, "DDY", 1, 1 }, - { OPCODE_DP2, "DP2", 2, 1 }, - { OPCODE_DP2A, "DP2A", 3, 1 }, - { OPCODE_DP3, "DP3", 2, 1 }, - { OPCODE_DP4, "DP4", 2, 1 }, - { OPCODE_DPH, "DPH", 2, 1 }, - { OPCODE_DST, "DST", 2, 1 }, - { OPCODE_ELSE, "ELSE", 0, 0 }, - { OPCODE_END, "END", 0, 0 }, - { OPCODE_ENDIF, "ENDIF", 0, 0 }, - { OPCODE_ENDLOOP,"ENDLOOP", 0, 0 }, - { OPCODE_ENDSUB, "ENDSUB", 0, 0 }, - { OPCODE_EX2, "EX2", 1, 1 }, - { OPCODE_EXP, "EXP", 1, 1 }, - { OPCODE_FLR, "FLR", 1, 1 }, - { OPCODE_FRC, "FRC", 1, 1 }, - { OPCODE_IF, "IF", 1, 0 }, - { OPCODE_KIL, "KIL", 1, 0 }, - { OPCODE_KIL_NV, "KIL_NV", 0, 0 }, - { OPCODE_LG2, "LG2", 1, 1 }, - { OPCODE_LIT, "LIT", 1, 1 }, - { OPCODE_LOG, "LOG", 1, 1 }, - { OPCODE_LRP, "LRP", 3, 1 }, - { OPCODE_MAD, "MAD", 3, 1 }, - { OPCODE_MAX, "MAX", 2, 1 }, - { OPCODE_MIN, "MIN", 2, 1 }, - { OPCODE_MOV, "MOV", 1, 1 }, - { OPCODE_MUL, "MUL", 2, 1 }, - { OPCODE_NOISE1, "NOISE1", 1, 1 }, - { OPCODE_NOISE2, "NOISE2", 1, 1 }, - { OPCODE_NOISE3, "NOISE3", 1, 1 }, - { OPCODE_NOISE4, "NOISE4", 1, 1 }, - { OPCODE_NOT, "NOT", 1, 1 }, - { OPCODE_NRM3, "NRM3", 1, 1 }, - { OPCODE_NRM4, "NRM4", 1, 1 }, - { OPCODE_OR, "OR", 2, 1 }, - { OPCODE_PK2H, "PK2H", 1, 1 }, - { OPCODE_PK2US, "PK2US", 1, 1 }, - { OPCODE_PK4B, "PK4B", 1, 1 }, - { OPCODE_PK4UB, "PK4UB", 1, 1 }, - { OPCODE_POW, "POW", 2, 1 }, - { OPCODE_POPA, "POPA", 0, 0 }, - { OPCODE_PRINT, "PRINT", 1, 0 }, - { OPCODE_PUSHA, "PUSHA", 0, 0 }, - { OPCODE_RCC, "RCC", 1, 1 }, - { OPCODE_RCP, "RCP", 1, 1 }, - { OPCODE_RET, "RET", 0, 0 }, - { OPCODE_RFL, "RFL", 1, 1 }, - { OPCODE_RSQ, "RSQ", 1, 1 }, - { OPCODE_SCS, "SCS", 1, 1 }, - { OPCODE_SEQ, "SEQ", 2, 1 }, - { OPCODE_SFL, "SFL", 0, 1 }, - { OPCODE_SGE, "SGE", 2, 1 }, - { OPCODE_SGT, "SGT", 2, 1 }, - { OPCODE_SIN, "SIN", 1, 1 }, - { OPCODE_SLE, "SLE", 2, 1 }, - { OPCODE_SLT, "SLT", 2, 1 }, - { OPCODE_SNE, "SNE", 2, 1 }, - { OPCODE_SSG, "SSG", 1, 1 }, - { OPCODE_STR, "STR", 0, 1 }, - { OPCODE_SUB, "SUB", 2, 1 }, - { OPCODE_SWZ, "SWZ", 1, 1 }, - { OPCODE_TEX, "TEX", 1, 1 }, - { OPCODE_TXB, "TXB", 1, 1 }, - { OPCODE_TXD, "TXD", 3, 1 }, - { OPCODE_TXL, "TXL", 1, 1 }, - { OPCODE_TXP, "TXP", 1, 1 }, - { OPCODE_TXP_NV, "TXP_NV", 1, 1 }, - { OPCODE_TRUNC, "TRUNC", 1, 1 }, - { OPCODE_UP2H, "UP2H", 1, 1 }, - { OPCODE_UP2US, "UP2US", 1, 1 }, - { OPCODE_UP4B, "UP4B", 1, 1 }, - { OPCODE_UP4UB, "UP4UB", 1, 1 }, - { OPCODE_X2D, "X2D", 3, 1 }, - { OPCODE_XOR, "XOR", 2, 1 }, - { OPCODE_XPD, "XPD", 2, 1 } -}; - - -/** - * Return the number of src registers for the given instruction/opcode. - */ -GLuint -_mesa_num_inst_src_regs(gl_inst_opcode opcode) -{ - ASSERT(opcode < MAX_OPCODE); - ASSERT(opcode == InstInfo[opcode].Opcode); - ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode); - return InstInfo[opcode].NumSrcRegs; -} - - -/** - * Return the number of dst registers for the given instruction/opcode. - */ -GLuint -_mesa_num_inst_dst_regs(gl_inst_opcode opcode) -{ - ASSERT(opcode < MAX_OPCODE); - ASSERT(opcode == InstInfo[opcode].Opcode); - ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode); - return InstInfo[opcode].NumDstRegs; -} - - -GLboolean -_mesa_is_tex_instruction(gl_inst_opcode opcode) -{ - return (opcode == OPCODE_TEX || - opcode == OPCODE_TXB || - opcode == OPCODE_TXD || - opcode == OPCODE_TXL || - opcode == OPCODE_TXP); -} - - -/** - * Check if there's a potential src/dst register data dependency when - * using SOA execution. - * Example: - * MOV T, T.yxwz; - * This would expand into: - * MOV t0, t1; - * MOV t1, t0; - * MOV t2, t3; - * MOV t3, t2; - * The second instruction will have the wrong value for t0 if executed as-is. - */ -GLboolean -_mesa_check_soa_dependencies(const struct prog_instruction *inst) -{ - GLuint i, chan; - - if (inst->DstReg.WriteMask == WRITEMASK_X || - inst->DstReg.WriteMask == WRITEMASK_Y || - inst->DstReg.WriteMask == WRITEMASK_Z || - inst->DstReg.WriteMask == WRITEMASK_W || - inst->DstReg.WriteMask == 0x0) { - /* no chance of data dependency */ - return GL_FALSE; - } - - /* loop over src regs */ - for (i = 0; i < 3; i++) { - if (inst->SrcReg[i].File == inst->DstReg.File && - inst->SrcReg[i].Index == inst->DstReg.Index) { - /* loop over dest channels */ - GLuint channelsWritten = 0x0; - for (chan = 0; chan < 4; chan++) { - if (inst->DstReg.WriteMask & (1 << chan)) { - /* check if we're reading a channel that's been written */ - GLuint swizzle = GET_SWZ(inst->SrcReg[i].Swizzle, chan); - if (swizzle <= SWIZZLE_W && - (channelsWritten & (1 << swizzle))) { - return GL_TRUE; - } - - channelsWritten |= (1 << chan); - } - } - } - } - return GL_FALSE; -} - - -/** - * Return string name for given program opcode. - */ -const char * -_mesa_opcode_string(gl_inst_opcode opcode) -{ - if (opcode < MAX_OPCODE) - return InstInfo[opcode].Name; - else { - static char s[20]; - _mesa_snprintf(s, sizeof(s), "OP%u", opcode); - return s; - } -} - diff --git a/src/mesa/shader/prog_instruction.h b/src/mesa/shader/prog_instruction.h deleted file mode 100644 index 28c797a4ba..0000000000 --- a/src/mesa/shader/prog_instruction.h +++ /dev/null @@ -1,437 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.3 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -/** - * \file prog_instruction.h - * - * Vertex/fragment program instruction datatypes and constants. - * - * \author Brian Paul - * \author Keith Whitwell - * \author Ian Romanick - */ - - -#ifndef PROG_INSTRUCTION_H -#define PROG_INSTRUCTION_H - - -#include "main/mfeatures.h" - - -/** - * Swizzle indexes. - * Do not change! - */ -/*@{*/ -#define SWIZZLE_X 0 -#define SWIZZLE_Y 1 -#define SWIZZLE_Z 2 -#define SWIZZLE_W 3 -#define SWIZZLE_ZERO 4 /**< For SWZ instruction only */ -#define SWIZZLE_ONE 5 /**< For SWZ instruction only */ -#define SWIZZLE_NIL 7 /**< used during shader code gen (undefined value) */ -/*@}*/ - -#define MAKE_SWIZZLE4(a,b,c,d) (((a)<<0) | ((b)<<3) | ((c)<<6) | ((d)<<9)) -#define SWIZZLE_NOOP MAKE_SWIZZLE4(0,1,2,3) -#define GET_SWZ(swz, idx) (((swz) >> ((idx)*3)) & 0x7) -#define GET_BIT(msk, idx) (((msk) >> (idx)) & 0x1) - -#define SWIZZLE_XYZW MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W) -#define SWIZZLE_XXXX MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X) -#define SWIZZLE_YYYY MAKE_SWIZZLE4(SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y) -#define SWIZZLE_ZZZZ MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z) -#define SWIZZLE_WWWW MAKE_SWIZZLE4(SWIZZLE_W, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W) - - -/** - * Writemask values, 1 bit per component. - */ -/*@{*/ -#define WRITEMASK_X 0x1 -#define WRITEMASK_Y 0x2 -#define WRITEMASK_XY 0x3 -#define WRITEMASK_Z 0x4 -#define WRITEMASK_XZ 0x5 -#define WRITEMASK_YZ 0x6 -#define WRITEMASK_XYZ 0x7 -#define WRITEMASK_W 0x8 -#define WRITEMASK_XW 0x9 -#define WRITEMASK_YW 0xa -#define WRITEMASK_XYW 0xb -#define WRITEMASK_ZW 0xc -#define WRITEMASK_XZW 0xd -#define WRITEMASK_YZW 0xe -#define WRITEMASK_XYZW 0xf -/*@}*/ - - -/** - * Condition codes - */ -/*@{*/ -#define COND_GT 1 /**< greater than zero */ -#define COND_EQ 2 /**< equal to zero */ -#define COND_LT 3 /**< less than zero */ -#define COND_UN 4 /**< unordered (NaN) */ -#define COND_GE 5 /**< greater than or equal to zero */ -#define COND_LE 6 /**< less than or equal to zero */ -#define COND_NE 7 /**< not equal to zero */ -#define COND_TR 8 /**< always true */ -#define COND_FL 9 /**< always false */ -/*@}*/ - - -/** - * Instruction precision for GL_NV_fragment_program - */ -/*@{*/ -#define FLOAT32 0x1 -#define FLOAT16 0x2 -#define FIXED12 0x4 -/*@}*/ - - -/** - * Saturation modes when storing values. - */ -/*@{*/ -#define SATURATE_OFF 0 -#define SATURATE_ZERO_ONE 1 -/*@}*/ - - -/** - * Per-component negation masks - */ -/*@{*/ -#define NEGATE_X 0x1 -#define NEGATE_Y 0x2 -#define NEGATE_Z 0x4 -#define NEGATE_W 0x8 -#define NEGATE_XYZ 0x7 -#define NEGATE_XYZW 0xf -#define NEGATE_NONE 0x0 -/*@}*/ - - -/** - * Program instruction opcodes, for both vertex and fragment programs. - * \note changes to this opcode list must be reflected in t_vb_arbprogram.c - */ -typedef enum prog_opcode { - /* ARB_vp ARB_fp NV_vp NV_fp GLSL */ - /*------------------------------------------*/ - OPCODE_NOP = 0, /* X */ - OPCODE_ABS, /* X X 1.1 X */ - OPCODE_ADD, /* X X X X X */ - OPCODE_AND, /* */ - OPCODE_ARA, /* 2 */ - OPCODE_ARL, /* X X */ - OPCODE_ARL_NV, /* 2 */ - OPCODE_ARR, /* 2 */ - OPCODE_BGNLOOP, /* opt */ - OPCODE_BGNSUB, /* opt */ - OPCODE_BRA, /* 2 X */ - OPCODE_BRK, /* 2 opt */ - OPCODE_CAL, /* 2 2 */ - OPCODE_CMP, /* X */ - OPCODE_CONT, /* opt */ - OPCODE_COS, /* X 2 X X */ - OPCODE_DDX, /* X X */ - OPCODE_DDY, /* X X */ - OPCODE_DP2, /* 2 */ - OPCODE_DP2A, /* 2 */ - OPCODE_DP3, /* X X X X X */ - OPCODE_DP4, /* X X X X X */ - OPCODE_DPH, /* X X 1.1 */ - OPCODE_DST, /* X X X X */ - OPCODE_ELSE, /* X */ - OPCODE_END, /* X X X X opt */ - OPCODE_ENDIF, /* opt */ - OPCODE_ENDLOOP, /* opt */ - OPCODE_ENDSUB, /* opt */ - OPCODE_EX2, /* X X 2 X X */ - OPCODE_EXP, /* X X X */ - OPCODE_FLR, /* X X 2 X X */ - OPCODE_FRC, /* X X 2 X X */ - OPCODE_IF, /* opt */ - OPCODE_KIL, /* X */ - OPCODE_KIL_NV, /* X X */ - OPCODE_LG2, /* X X 2 X X */ - OPCODE_LIT, /* X X X X */ - OPCODE_LOG, /* X X X */ - OPCODE_LRP, /* X X */ - OPCODE_MAD, /* X X X X X */ - OPCODE_MAX, /* X X X X X */ - OPCODE_MIN, /* X X X X X */ - OPCODE_MOV, /* X X X X X */ - OPCODE_MUL, /* X X X X X */ - OPCODE_NOISE1, /* X */ - OPCODE_NOISE2, /* X */ - OPCODE_NOISE3, /* X */ - OPCODE_NOISE4, /* X */ - OPCODE_NOT, /* */ - OPCODE_NRM3, /* */ - OPCODE_NRM4, /* */ - OPCODE_OR, /* */ - OPCODE_PK2H, /* X */ - OPCODE_PK2US, /* X */ - OPCODE_PK4B, /* X */ - OPCODE_PK4UB, /* X */ - OPCODE_POW, /* X X X X */ - OPCODE_POPA, /* 3 */ - OPCODE_PRINT, /* X X */ - OPCODE_PUSHA, /* 3 */ - OPCODE_RCC, /* 1.1 */ - OPCODE_RCP, /* X X X X X */ - OPCODE_RET, /* 2 2 */ - OPCODE_RFL, /* X X */ - OPCODE_RSQ, /* X X X X X */ - OPCODE_SCS, /* X */ - OPCODE_SEQ, /* 2 X X */ - OPCODE_SFL, /* 2 X */ - OPCODE_SGE, /* X X X X X */ - OPCODE_SGT, /* 2 X X */ - OPCODE_SIN, /* X 2 X X */ - OPCODE_SLE, /* 2 X X */ - OPCODE_SLT, /* X X X X X */ - OPCODE_SNE, /* 2 X X */ - OPCODE_SSG, /* 2 */ - OPCODE_STR, /* 2 X */ - OPCODE_SUB, /* X X 1.1 X X */ - OPCODE_SWZ, /* X X */ - OPCODE_TEX, /* X 3 X X */ - OPCODE_TXB, /* X 3 X */ - OPCODE_TXD, /* X X */ - OPCODE_TXL, /* 3 2 X */ - OPCODE_TXP, /* X X */ - OPCODE_TXP_NV, /* 3 X */ - OPCODE_TRUNC, /* X */ - OPCODE_UP2H, /* X */ - OPCODE_UP2US, /* X */ - OPCODE_UP4B, /* X */ - OPCODE_UP4UB, /* X */ - OPCODE_X2D, /* X */ - OPCODE_XOR, /* */ - OPCODE_XPD, /* X X X */ - MAX_OPCODE -} gl_inst_opcode; - - -/** - * Number of bits for the src/dst register Index field. - * This limits the size of temp/uniform register files. - */ -#define INST_INDEX_BITS 10 - - -/** - * Instruction source register. - */ -struct prog_src_register -{ - GLuint File:4; /**< One of the PROGRAM_* register file values. */ - GLint Index:(INST_INDEX_BITS+1); /**< Extra bit here for sign bit. - * May be negative for relative addressing. - */ - GLuint Swizzle:12; - GLuint RelAddr:1; - - /** Take the component-wise absolute value */ - GLuint Abs:1; - - /** - * Post-Abs negation. - * This will either be NEGATE_NONE or NEGATE_XYZW, except for the SWZ - * instruction which allows per-component negation. - */ - GLuint Negate:4; -}; - - -/** - * Instruction destination register. - */ -struct prog_dst_register -{ - GLuint File:4; /**< One of the PROGRAM_* register file values */ - GLuint Index:INST_INDEX_BITS; /**< Unsigned, never negative */ - GLuint WriteMask:4; - GLuint RelAddr:1; - - /** - * \name Conditional destination update control. - * - * \since - * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2, - * NV_vertex_program2_option. - */ - /*@{*/ - /** - * Takes one of the 9 possible condition values (EQ, FL, GT, GE, LE, LT, - * NE, TR, or UN). Dest reg is only written to if the matching - * (swizzled) condition code value passes. When a conditional update mask - * is not specified, this will be \c COND_TR. - */ - GLuint CondMask:4; - - /** - * Condition code swizzle value. - */ - GLuint CondSwizzle:12; - - /** - * Selects the condition code register to use for conditional destination - * update masking. In NV_fragmnet_program or NV_vertex_program2 mode, only - * condition code register 0 is available. In NV_vertex_program3 mode, - * condition code registers 0 and 1 are available. - */ - GLuint CondSrc:1; - /*@}*/ -}; - - -/** - * Vertex/fragment program instruction. - */ -struct prog_instruction -{ - gl_inst_opcode Opcode; - struct prog_src_register SrcReg[3]; - struct prog_dst_register DstReg; - - /** - * Indicates that the instruction should update the condition code - * register. - * - * \since - * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2, - * NV_vertex_program2_option. - */ - GLuint CondUpdate:1; - - /** - * If prog_instruction::CondUpdate is \c GL_TRUE, this value selects the - * condition code register that is to be updated. - * - * In GL_NV_fragment_program or GL_NV_vertex_program2 mode, only condition - * code register 0 is available. In GL_NV_vertex_program3 mode, condition - * code registers 0 and 1 are available. - * - * \since - * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2, - * NV_vertex_program2_option. - */ - GLuint CondDst:1; - - /** - * Saturate each value of the vectored result to the range [0,1] or the - * range [-1,1]. \c SSAT mode (i.e., saturation to the range [-1,1]) is - * only available in NV_fragment_program2 mode. - * Value is one of the SATURATE_* tokens. - * - * \since - * NV_fragment_program, NV_fragment_program_option, NV_vertex_program3. - */ - GLuint SaturateMode:2; - - /** - * Per-instruction selectable precision: FLOAT32, FLOAT16, FIXED12. - * - * \since - * NV_fragment_program, NV_fragment_program_option. - */ - GLuint Precision:3; - - /** - * \name Extra fields for TEX, TXB, TXD, TXL, TXP instructions. - */ - /*@{*/ - /** Source texture unit. */ - GLuint TexSrcUnit:5; - - /** Source texture target, one of TEXTURE_{1D,2D,3D,CUBE,RECT}_INDEX */ - GLuint TexSrcTarget:3; - - /** True if tex instruction should do shadow comparison */ - GLuint TexShadow:1; - /*@}*/ - - /** - * For BRA and CAL instructions, the location to jump to. - * For BGNLOOP, points to ENDLOOP (and vice-versa). - * For BRK, points to BGNLOOP (which points to ENDLOOP). - * For IF, points to ELSE or ENDIF. - * For ELSE, points to ENDIF. - */ - GLint BranchTarget; - - /** for debugging purposes */ - const char *Comment; - - /** Arbitrary data. Used for OPCODE_PRINT and some drivers */ - void *Data; - - /** for driver use (try to remove someday) */ - GLint Aux; -}; - - -extern void -_mesa_init_instructions(struct prog_instruction *inst, GLuint count); - -extern struct prog_instruction * -_mesa_alloc_instructions(GLuint numInst); - -extern struct prog_instruction * -_mesa_realloc_instructions(struct prog_instruction *oldInst, - GLuint numOldInst, GLuint numNewInst); - -extern struct prog_instruction * -_mesa_copy_instructions(struct prog_instruction *dest, - const struct prog_instruction *src, GLuint n); - -extern void -_mesa_free_instructions(struct prog_instruction *inst, GLuint count); - -extern GLuint -_mesa_num_inst_src_regs(gl_inst_opcode opcode); - -extern GLuint -_mesa_num_inst_dst_regs(gl_inst_opcode opcode); - -extern GLboolean -_mesa_is_tex_instruction(gl_inst_opcode opcode); - -extern GLboolean -_mesa_check_soa_dependencies(const struct prog_instruction *inst); - -extern const char * -_mesa_opcode_string(gl_inst_opcode opcode); - - -#endif /* PROG_INSTRUCTION_H */ diff --git a/src/mesa/shader/prog_noise.c b/src/mesa/shader/prog_noise.c deleted file mode 100644 index 1713ddb5f3..0000000000 --- a/src/mesa/shader/prog_noise.c +++ /dev/null @@ -1,638 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * SimplexNoise1234 - * Copyright (c) 2003-2005, Stefan Gustavson - * - * Contact: stegu@itn.liu.se - */ - -/** - * \file - * \brief C implementation of Perlin Simplex Noise over 1, 2, 3 and 4 dims. - * \author Stefan Gustavson (stegu@itn.liu.se) - * - * - * This implementation is "Simplex Noise" as presented by - * Ken Perlin at a relatively obscure and not often cited course - * session "Real-Time Shading" at Siggraph 2001 (before real - * time shading actually took on), under the title "hardware noise". - * The 3D function is numerically equivalent to his Java reference - * code available in the PDF course notes, although I re-implemented - * it from scratch to get more readable code. The 1D, 2D and 4D cases - * were implemented from scratch by me from Ken Perlin's text. - * - * This file has no dependencies on any other file, not even its own - * header file. The header file is made for use by external code only. - */ - - -#include "main/imports.h" -#include "prog_noise.h" - -#define FASTFLOOR(x) ( ((x)>0) ? ((int)x) : (((int)x)-1) ) - -/* - * --------------------------------------------------------------------- - * Static data - */ - -/** - * Permutation table. This is just a random jumble of all numbers 0-255, - * repeated twice to avoid wrapping the index at 255 for each lookup. - * This needs to be exactly the same for all instances on all platforms, - * so it's easiest to just keep it as static explicit data. - * This also removes the need for any initialisation of this class. - * - * Note that making this an int[] instead of a char[] might make the - * code run faster on platforms with a high penalty for unaligned single - * byte addressing. Intel x86 is generally single-byte-friendly, but - * some other CPUs are faster with 4-aligned reads. - * However, a char[] is smaller, which avoids cache trashing, and that - * is probably the most important aspect on most architectures. - * This array is accessed a *lot* by the noise functions. - * A vector-valued noise over 3D accesses it 96 times, and a - * float-valued 4D noise 64 times. We want this to fit in the cache! - */ -unsigned char perm[512] = { 151, 160, 137, 91, 90, 15, - 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, - 99, 37, 240, 21, 10, 23, - 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, - 11, 32, 57, 177, 33, - 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, - 134, 139, 48, 27, 166, - 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, - 55, 46, 245, 40, 244, - 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, - 18, 169, 200, 196, - 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, - 226, 250, 124, 123, - 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, - 17, 182, 189, 28, 42, - 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, - 167, 43, 172, 9, - 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, - 218, 246, 97, 228, - 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, - 249, 14, 239, 107, - 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, - 127, 4, 150, 254, - 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, - 215, 61, 156, 180, - 151, 160, 137, 91, 90, 15, - 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, - 99, 37, 240, 21, 10, 23, - 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, - 11, 32, 57, 177, 33, - 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, - 134, 139, 48, 27, 166, - 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, - 55, 46, 245, 40, 244, - 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, - 18, 169, 200, 196, - 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, - 226, 250, 124, 123, - 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, - 17, 182, 189, 28, 42, - 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, - 167, 43, 172, 9, - 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, - 218, 246, 97, 228, - 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, - 249, 14, 239, 107, - 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, - 127, 4, 150, 254, - 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, - 215, 61, 156, 180 -}; - -/* - * --------------------------------------------------------------------- - */ - -/* - * Helper functions to compute gradients-dot-residualvectors (1D to 4D) - * Note that these generate gradients of more than unit length. To make - * a close match with the value range of classic Perlin noise, the final - * noise values need to be rescaled to fit nicely within [-1,1]. - * (The simplex noise functions as such also have different scaling.) - * Note also that these noise functions are the most practical and useful - * signed version of Perlin noise. To return values according to the - * RenderMan specification from the SL noise() and pnoise() functions, - * the noise values need to be scaled and offset to [0,1], like this: - * float SLnoise = (SimplexNoise1234::noise(x,y,z) + 1.0) * 0.5; - */ - -static float -grad1(int hash, float x) -{ - int h = hash & 15; - float grad = 1.0f + (h & 7); /* Gradient value 1.0, 2.0, ..., 8.0 */ - if (h & 8) - grad = -grad; /* Set a random sign for the gradient */ - return (grad * x); /* Multiply the gradient with the distance */ -} - -static float -grad2(int hash, float x, float y) -{ - int h = hash & 7; /* Convert low 3 bits of hash code */ - float u = h < 4 ? x : y; /* into 8 simple gradient directions, */ - float v = h < 4 ? y : x; /* and compute the dot product with (x,y). */ - return ((h & 1) ? -u : u) + ((h & 2) ? -2.0f * v : 2.0f * v); -} - -static float -grad3(int hash, float x, float y, float z) -{ - int h = hash & 15; /* Convert low 4 bits of hash code into 12 simple */ - float u = h < 8 ? x : y; /* gradient directions, and compute dot product. */ - float v = h < 4 ? y : h == 12 || h == 14 ? x : z; /* Fix repeats at h = 12 to 15 */ - return ((h & 1) ? -u : u) + ((h & 2) ? -v : v); -} - -static float -grad4(int hash, float x, float y, float z, float t) -{ - int h = hash & 31; /* Convert low 5 bits of hash code into 32 simple */ - float u = h < 24 ? x : y; /* gradient directions, and compute dot product. */ - float v = h < 16 ? y : z; - float w = h < 8 ? z : t; - return ((h & 1) ? -u : u) + ((h & 2) ? -v : v) + ((h & 4) ? -w : w); -} - -/** - * A lookup table to traverse the simplex around a given point in 4D. - * Details can be found where this table is used, in the 4D noise method. - * TODO: This should not be required, backport it from Bill's GLSL code! - */ -static unsigned char simplex[64][4] = { - {0, 1, 2, 3}, {0, 1, 3, 2}, {0, 0, 0, 0}, {0, 2, 3, 1}, - {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 2, 3, 0}, - {0, 2, 1, 3}, {0, 0, 0, 0}, {0, 3, 1, 2}, {0, 3, 2, 1}, - {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 3, 2, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, - {1, 2, 0, 3}, {0, 0, 0, 0}, {1, 3, 0, 2}, {0, 0, 0, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, {2, 3, 0, 1}, {2, 3, 1, 0}, - {1, 0, 2, 3}, {1, 0, 3, 2}, {0, 0, 0, 0}, {0, 0, 0, 0}, - {0, 0, 0, 0}, {2, 0, 3, 1}, {0, 0, 0, 0}, {2, 1, 3, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, - {2, 0, 1, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, - {3, 0, 1, 2}, {3, 0, 2, 1}, {0, 0, 0, 0}, {3, 1, 2, 0}, - {2, 1, 0, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, - {3, 1, 0, 2}, {0, 0, 0, 0}, {3, 2, 0, 1}, {3, 2, 1, 0} -}; - - -/** 1D simplex noise */ -GLfloat -_mesa_noise1(GLfloat x) -{ - int i0 = FASTFLOOR(x); - int i1 = i0 + 1; - float x0 = x - i0; - float x1 = x0 - 1.0f; - float t1 = 1.0f - x1 * x1; - float n0, n1; - - float t0 = 1.0f - x0 * x0; -/* if(t0 < 0.0f) t0 = 0.0f; // this never happens for the 1D case */ - t0 *= t0; - n0 = t0 * t0 * grad1(perm[i0 & 0xff], x0); - -/* if(t1 < 0.0f) t1 = 0.0f; // this never happens for the 1D case */ - t1 *= t1; - n1 = t1 * t1 * grad1(perm[i1 & 0xff], x1); - /* The maximum value of this noise is 8*(3/4)^4 = 2.53125 */ - /* A factor of 0.395 would scale to fit exactly within [-1,1], but */ - /* we want to match PRMan's 1D noise, so we scale it down some more. */ - return 0.25f * (n0 + n1); -} - - -/** 2D simplex noise */ -GLfloat -_mesa_noise2(GLfloat x, GLfloat y) -{ -#define F2 0.366025403f /* F2 = 0.5*(sqrt(3.0)-1.0) */ -#define G2 0.211324865f /* G2 = (3.0-Math.sqrt(3.0))/6.0 */ - - float n0, n1, n2; /* Noise contributions from the three corners */ - - /* Skew the input space to determine which simplex cell we're in */ - float s = (x + y) * F2; /* Hairy factor for 2D */ - float xs = x + s; - float ys = y + s; - int i = FASTFLOOR(xs); - int j = FASTFLOOR(ys); - - float t = (float) (i + j) * G2; - float X0 = i - t; /* Unskew the cell origin back to (x,y) space */ - float Y0 = j - t; - float x0 = x - X0; /* The x,y distances from the cell origin */ - float y0 = y - Y0; - - float x1, y1, x2, y2; - int ii, jj; - float t0, t1, t2; - - /* For the 2D case, the simplex shape is an equilateral triangle. */ - /* Determine which simplex we are in. */ - int i1, j1; /* Offsets for second (middle) corner of simplex in (i,j) coords */ - if (x0 > y0) { - i1 = 1; - j1 = 0; - } /* lower triangle, XY order: (0,0)->(1,0)->(1,1) */ - else { - i1 = 0; - j1 = 1; - } /* upper triangle, YX order: (0,0)->(0,1)->(1,1) */ - - /* A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and */ - /* a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where */ - /* c = (3-sqrt(3))/6 */ - - x1 = x0 - i1 + G2; /* Offsets for middle corner in (x,y) unskewed coords */ - y1 = y0 - j1 + G2; - x2 = x0 - 1.0f + 2.0f * G2; /* Offsets for last corner in (x,y) unskewed coords */ - y2 = y0 - 1.0f + 2.0f * G2; - - /* Wrap the integer indices at 256, to avoid indexing perm[] out of bounds */ - ii = i % 256; - jj = j % 256; - - /* Calculate the contribution from the three corners */ - t0 = 0.5f - x0 * x0 - y0 * y0; - if (t0 < 0.0f) - n0 = 0.0f; - else { - t0 *= t0; - n0 = t0 * t0 * grad2(perm[ii + perm[jj]], x0, y0); - } - - t1 = 0.5f - x1 * x1 - y1 * y1; - if (t1 < 0.0f) - n1 = 0.0f; - else { - t1 *= t1; - n1 = t1 * t1 * grad2(perm[ii + i1 + perm[jj + j1]], x1, y1); - } - - t2 = 0.5f - x2 * x2 - y2 * y2; - if (t2 < 0.0f) - n2 = 0.0f; - else { - t2 *= t2; - n2 = t2 * t2 * grad2(perm[ii + 1 + perm[jj + 1]], x2, y2); - } - - /* Add contributions from each corner to get the final noise value. */ - /* The result is scaled to return values in the interval [-1,1]. */ - return 40.0f * (n0 + n1 + n2); /* TODO: The scale factor is preliminary! */ -} - - -/** 3D simplex noise */ -GLfloat -_mesa_noise3(GLfloat x, GLfloat y, GLfloat z) -{ -/* Simple skewing factors for the 3D case */ -#define F3 0.333333333f -#define G3 0.166666667f - - float n0, n1, n2, n3; /* Noise contributions from the four corners */ - - /* Skew the input space to determine which simplex cell we're in */ - float s = (x + y + z) * F3; /* Very nice and simple skew factor for 3D */ - float xs = x + s; - float ys = y + s; - float zs = z + s; - int i = FASTFLOOR(xs); - int j = FASTFLOOR(ys); - int k = FASTFLOOR(zs); - - float t = (float) (i + j + k) * G3; - float X0 = i - t; /* Unskew the cell origin back to (x,y,z) space */ - float Y0 = j - t; - float Z0 = k - t; - float x0 = x - X0; /* The x,y,z distances from the cell origin */ - float y0 = y - Y0; - float z0 = z - Z0; - - float x1, y1, z1, x2, y2, z2, x3, y3, z3; - int ii, jj, kk; - float t0, t1, t2, t3; - - /* For the 3D case, the simplex shape is a slightly irregular tetrahedron. */ - /* Determine which simplex we are in. */ - int i1, j1, k1; /* Offsets for second corner of simplex in (i,j,k) coords */ - int i2, j2, k2; /* Offsets for third corner of simplex in (i,j,k) coords */ - -/* This code would benefit from a backport from the GLSL version! */ - if (x0 >= y0) { - if (y0 >= z0) { - i1 = 1; - j1 = 0; - k1 = 0; - i2 = 1; - j2 = 1; - k2 = 0; - } /* X Y Z order */ - else if (x0 >= z0) { - i1 = 1; - j1 = 0; - k1 = 0; - i2 = 1; - j2 = 0; - k2 = 1; - } /* X Z Y order */ - else { - i1 = 0; - j1 = 0; - k1 = 1; - i2 = 1; - j2 = 0; - k2 = 1; - } /* Z X Y order */ - } - else { /* x0 y0) ? 32 : 0; - int c2 = (x0 > z0) ? 16 : 0; - int c3 = (y0 > z0) ? 8 : 0; - int c4 = (x0 > w0) ? 4 : 0; - int c5 = (y0 > w0) ? 2 : 0; - int c6 = (z0 > w0) ? 1 : 0; - int c = c1 + c2 + c3 + c4 + c5 + c6; - - int i1, j1, k1, l1; /* The integer offsets for the second simplex corner */ - int i2, j2, k2, l2; /* The integer offsets for the third simplex corner */ - int i3, j3, k3, l3; /* The integer offsets for the fourth simplex corner */ - - float x1, y1, z1, w1, x2, y2, z2, w2, x3, y3, z3, w3, x4, y4, z4, w4; - int ii, jj, kk, ll; - float t0, t1, t2, t3, t4; - - /* - * simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some - * order. Many values of c will never occur, since e.g. x>y>z>w - * makes x= 3 ? 1 : 0; - j1 = simplex[c][1] >= 3 ? 1 : 0; - k1 = simplex[c][2] >= 3 ? 1 : 0; - l1 = simplex[c][3] >= 3 ? 1 : 0; - /* The number 2 in the "simplex" array is at the second largest coordinate. */ - i2 = simplex[c][0] >= 2 ? 1 : 0; - j2 = simplex[c][1] >= 2 ? 1 : 0; - k2 = simplex[c][2] >= 2 ? 1 : 0; - l2 = simplex[c][3] >= 2 ? 1 : 0; - /* The number 1 in the "simplex" array is at the second smallest coordinate. */ - i3 = simplex[c][0] >= 1 ? 1 : 0; - j3 = simplex[c][1] >= 1 ? 1 : 0; - k3 = simplex[c][2] >= 1 ? 1 : 0; - l3 = simplex[c][3] >= 1 ? 1 : 0; - /* The fifth corner has all coordinate offsets = 1, so no need to look that up. */ - - x1 = x0 - i1 + G4; /* Offsets for second corner in (x,y,z,w) coords */ - y1 = y0 - j1 + G4; - z1 = z0 - k1 + G4; - w1 = w0 - l1 + G4; - x2 = x0 - i2 + 2.0f * G4; /* Offsets for third corner in (x,y,z,w) coords */ - y2 = y0 - j2 + 2.0f * G4; - z2 = z0 - k2 + 2.0f * G4; - w2 = w0 - l2 + 2.0f * G4; - x3 = x0 - i3 + 3.0f * G4; /* Offsets for fourth corner in (x,y,z,w) coords */ - y3 = y0 - j3 + 3.0f * G4; - z3 = z0 - k3 + 3.0f * G4; - w3 = w0 - l3 + 3.0f * G4; - x4 = x0 - 1.0f + 4.0f * G4; /* Offsets for last corner in (x,y,z,w) coords */ - y4 = y0 - 1.0f + 4.0f * G4; - z4 = z0 - 1.0f + 4.0f * G4; - w4 = w0 - 1.0f + 4.0f * G4; - - /* Wrap the integer indices at 256, to avoid indexing perm[] out of bounds */ - ii = i % 256; - jj = j % 256; - kk = k % 256; - ll = l % 256; - - /* Calculate the contribution from the five corners */ - t0 = 0.6f - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0; - if (t0 < 0.0f) - n0 = 0.0f; - else { - t0 *= t0; - n0 = - t0 * t0 * grad4(perm[ii + perm[jj + perm[kk + perm[ll]]]], x0, y0, - z0, w0); - } - - t1 = 0.6f - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1; - if (t1 < 0.0f) - n1 = 0.0f; - else { - t1 *= t1; - n1 = - t1 * t1 * - grad4(perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]]]], - x1, y1, z1, w1); - } - - t2 = 0.6f - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2; - if (t2 < 0.0f) - n2 = 0.0f; - else { - t2 *= t2; - n2 = - t2 * t2 * - grad4(perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]]]], - x2, y2, z2, w2); - } - - t3 = 0.6f - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3; - if (t3 < 0.0f) - n3 = 0.0f; - else { - t3 *= t3; - n3 = - t3 * t3 * - grad4(perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]]]], - x3, y3, z3, w3); - } - - t4 = 0.6f - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4; - if (t4 < 0.0f) - n4 = 0.0f; - else { - t4 *= t4; - n4 = - t4 * t4 * - grad4(perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]]]], x4, - y4, z4, w4); - } - - /* Sum up and scale the result to cover the range [-1,1] */ - return 27.0f * (n0 + n1 + n2 + n3 + n4); /* TODO: The scale factor is preliminary! */ -} diff --git a/src/mesa/shader/prog_noise.h b/src/mesa/shader/prog_noise.h deleted file mode 100644 index c4779479f9..0000000000 --- a/src/mesa/shader/prog_noise.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef PROG_NOISE -#define PROG_NOISE - -extern GLfloat _mesa_noise1(GLfloat); -extern GLfloat _mesa_noise2(GLfloat, GLfloat); -extern GLfloat _mesa_noise3(GLfloat, GLfloat, GLfloat); -extern GLfloat _mesa_noise4(GLfloat, GLfloat, GLfloat, GLfloat); - -#endif - diff --git a/src/mesa/shader/prog_optimize.c b/src/mesa/shader/prog_optimize.c deleted file mode 100644 index 2941a17da3..0000000000 --- a/src/mesa/shader/prog_optimize.c +++ /dev/null @@ -1,1035 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.5 - * - * Copyright (C) 2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VMWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - - -#include "main/glheader.h" -#include "main/context.h" -#include "main/macros.h" -#include "program.h" -#include "prog_instruction.h" -#include "prog_optimize.h" -#include "prog_print.h" - - -#define MAX_LOOP_NESTING 50 - - -static GLboolean dbg = GL_FALSE; - -/* Returns the mask of channels read from the given srcreg in this instruction. - */ -static GLuint -get_src_arg_mask(const struct prog_instruction *inst, int arg) -{ - int writemask = inst->DstReg.WriteMask; - - if (inst->CondUpdate) - writemask = WRITEMASK_XYZW; - - switch (inst->Opcode) { - case OPCODE_MOV: - case OPCODE_ABS: - case OPCODE_ADD: - case OPCODE_MUL: - case OPCODE_SUB: - return writemask; - case OPCODE_RCP: - case OPCODE_SIN: - case OPCODE_COS: - case OPCODE_RSQ: - case OPCODE_POW: - case OPCODE_EX2: - return WRITEMASK_X; - case OPCODE_DP2: - return WRITEMASK_XY; - case OPCODE_DP3: - case OPCODE_XPD: - return WRITEMASK_XYZ; - default: - return WRITEMASK_XYZW; - } -} - -/** - * In 'prog' remove instruction[i] if removeFlags[i] == TRUE. - * \return number of instructions removed - */ -static GLuint -remove_instructions(struct gl_program *prog, const GLboolean *removeFlags) -{ - GLint i, removeEnd = 0, removeCount = 0; - GLuint totalRemoved = 0; - - /* go backward */ - for (i = prog->NumInstructions - 1; i >= 0; i--) { - if (removeFlags[i]) { - totalRemoved++; - if (removeCount == 0) { - /* begin a run of instructions to remove */ - removeEnd = i; - removeCount = 1; - } - else { - /* extend the run of instructions to remove */ - removeCount++; - } - } - else { - /* don't remove this instruction, but check if the preceeding - * instructions are to be removed. - */ - if (removeCount > 0) { - GLint removeStart = removeEnd - removeCount + 1; - _mesa_delete_instructions(prog, removeStart, removeCount); - removeStart = removeCount = 0; /* reset removal info */ - } - } - } - /* Finish removing if the first instruction was to be removed. */ - if (removeCount > 0) { - GLint removeStart = removeEnd - removeCount + 1; - _mesa_delete_instructions(prog, removeStart, removeCount); - } - return totalRemoved; -} - - -/** - * Remap register indexes according to map. - * \param prog the program to search/replace - * \param file the type of register file to search/replace - * \param map maps old register indexes to new indexes - */ -static void -replace_regs(struct gl_program *prog, gl_register_file file, const GLint map[]) -{ - GLuint i; - - for (i = 0; i < prog->NumInstructions; i++) { - struct prog_instruction *inst = prog->Instructions + i; - const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); - GLuint j; - for (j = 0; j < numSrc; j++) { - if (inst->SrcReg[j].File == file) { - GLuint index = inst->SrcReg[j].Index; - ASSERT(map[index] >= 0); - inst->SrcReg[j].Index = map[index]; - } - } - if (inst->DstReg.File == file) { - const GLuint index = inst->DstReg.Index; - ASSERT(map[index] >= 0); - inst->DstReg.Index = map[index]; - } - } -} - - -/** - * Consolidate temporary registers to use low numbers. For example, if the - * shader only uses temps 4, 5, 8, replace them with 0, 1, 2. - */ -static void -_mesa_consolidate_registers(struct gl_program *prog) -{ - GLboolean tempUsed[MAX_PROGRAM_TEMPS]; - GLint tempMap[MAX_PROGRAM_TEMPS]; - GLuint tempMax = 0, i; - - if (dbg) { - printf("Optimize: Begin register consolidation\n"); - } - - memset(tempUsed, 0, sizeof(tempUsed)); - - for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { - tempMap[i] = -1; - } - - /* set tempUsed[i] if temporary [i] is referenced */ - for (i = 0; i < prog->NumInstructions; i++) { - const struct prog_instruction *inst = prog->Instructions + i; - const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); - GLuint j; - for (j = 0; j < numSrc; j++) { - if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { - const GLuint index = inst->SrcReg[j].Index; - ASSERT(index < MAX_PROGRAM_TEMPS); - tempUsed[index] = GL_TRUE; - tempMax = MAX2(tempMax, index); - break; - } - } - if (inst->DstReg.File == PROGRAM_TEMPORARY) { - const GLuint index = inst->DstReg.Index; - ASSERT(index < MAX_PROGRAM_TEMPS); - tempUsed[index] = GL_TRUE; - tempMax = MAX2(tempMax, index); - } - } - - /* allocate a new index for each temp that's used */ - { - GLuint freeTemp = 0; - for (i = 0; i <= tempMax; i++) { - if (tempUsed[i]) { - tempMap[i] = freeTemp++; - /*printf("replace %u with %u\n", i, tempMap[i]);*/ - } - } - if (freeTemp == tempMax + 1) { - /* no consolidation possible */ - return; - } - if (dbg) { - printf("Replace regs 0..%u with 0..%u\n", tempMax, freeTemp-1); - } - } - - replace_regs(prog, PROGRAM_TEMPORARY, tempMap); - - if (dbg) { - printf("Optimize: End register consolidation\n"); - } -} - - -/** - * Remove dead instructions from the given program. - * This is very primitive for now. Basically look for temp registers - * that are written to but never read. Remove any instructions that - * write to such registers. Be careful with condition code setters. - */ -static void -_mesa_remove_dead_code(struct gl_program *prog) -{ - GLboolean tempRead[MAX_PROGRAM_TEMPS][4]; - GLboolean *removeInst; /* per-instruction removal flag */ - GLuint i, rem = 0, comp; - - memset(tempRead, 0, sizeof(tempRead)); - - if (dbg) { - printf("Optimize: Begin dead code removal\n"); - /*_mesa_print_program(prog);*/ - } - - removeInst = (GLboolean *) - calloc(1, prog->NumInstructions * sizeof(GLboolean)); - - /* Determine which temps are read and written */ - for (i = 0; i < prog->NumInstructions; i++) { - const struct prog_instruction *inst = prog->Instructions + i; - const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); - GLuint j; - - /* check src regs */ - for (j = 0; j < numSrc; j++) { - if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { - const GLuint index = inst->SrcReg[j].Index; - GLuint read_mask; - ASSERT(index < MAX_PROGRAM_TEMPS); - read_mask = get_src_arg_mask(inst, j); - - if (inst->SrcReg[j].RelAddr) { - if (dbg) - printf("abort remove dead code (indirect temp)\n"); - goto done; - } - - for (comp = 0; comp < 4; comp++) { - GLuint swz = (inst->SrcReg[j].Swizzle >> (3 * comp)) & 0x7; - - if ((read_mask & (1 << comp)) == 0) - continue; - - switch (swz) { - case SWIZZLE_X: - tempRead[index][0] = GL_TRUE; - break; - case SWIZZLE_Y: - tempRead[index][1] = GL_TRUE; - break; - case SWIZZLE_Z: - tempRead[index][2] = GL_TRUE; - break; - case SWIZZLE_W: - tempRead[index][3] = GL_TRUE; - break; - } - } - } - } - - /* check dst reg */ - if (inst->DstReg.File == PROGRAM_TEMPORARY) { - const GLuint index = inst->DstReg.Index; - ASSERT(index < MAX_PROGRAM_TEMPS); - - if (inst->DstReg.RelAddr) { - if (dbg) - printf("abort remove dead code (indirect temp)\n"); - goto done; - } - - if (inst->CondUpdate) { - /* If we're writing to this register and setting condition - * codes we cannot remove the instruction. Prevent removal - * by setting the 'read' flag. - */ - tempRead[index][0] = GL_TRUE; - tempRead[index][1] = GL_TRUE; - tempRead[index][2] = GL_TRUE; - tempRead[index][3] = GL_TRUE; - } - } - } - - /* find instructions that write to dead registers, flag for removal */ - for (i = 0; i < prog->NumInstructions; i++) { - struct prog_instruction *inst = prog->Instructions + i; - const GLuint numDst = _mesa_num_inst_dst_regs(inst->Opcode); - - if (numDst != 0 && inst->DstReg.File == PROGRAM_TEMPORARY) { - GLint chan, index = inst->DstReg.Index; - - for (chan = 0; chan < 4; chan++) { - if (!tempRead[index][chan] && - inst->DstReg.WriteMask & (1 << chan)) { - if (dbg) { - printf("Remove writemask on %u.%c\n", i, - chan == 3 ? 'w' : 'x' + chan); - } - inst->DstReg.WriteMask &= ~(1 << chan); - rem++; - } - } - - if (inst->DstReg.WriteMask == 0) { - /* If we cleared all writes, the instruction can be removed. */ - if (dbg) - printf("Remove instruction %u: \n", i); - removeInst[i] = GL_TRUE; - } - } - } - - /* now remove the instructions which aren't needed */ - rem = remove_instructions(prog, removeInst); - - if (dbg) { - printf("Optimize: End dead code removal.\n"); - printf(" %u channel writes removed\n", rem); - printf(" %u instructions removed\n", rem); - /*_mesa_print_program(prog);*/ - } - -done: - free(removeInst); -} - - -enum temp_use -{ - READ, - WRITE, - FLOW, - END -}; - -/** - * Scan forward in program from 'start' for the next occurance of TEMP[index]. - * Return READ, WRITE, FLOW or END to indicate the next usage or an indicator - * that we can't look further. - */ -static enum temp_use -find_next_temp_use(const struct gl_program *prog, GLuint start, GLuint index) -{ - GLuint i; - - for (i = start; i < prog->NumInstructions; i++) { - const struct prog_instruction *inst = prog->Instructions + i; - switch (inst->Opcode) { - case OPCODE_BGNLOOP: - case OPCODE_ENDLOOP: - case OPCODE_BGNSUB: - case OPCODE_ENDSUB: - return FLOW; - default: - { - const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); - GLuint j; - for (j = 0; j < numSrc; j++) { - if (inst->SrcReg[j].File == PROGRAM_TEMPORARY && - inst->SrcReg[j].Index == index) - return READ; - } - if (inst->DstReg.File == PROGRAM_TEMPORARY && - inst->DstReg.Index == index) - return WRITE; - } - } - } - - return END; -} - -static GLboolean _mesa_is_flow_control_opcode(enum prog_opcode opcode) -{ - switch (opcode) { - case OPCODE_BGNLOOP: - case OPCODE_BGNSUB: - case OPCODE_BRA: - case OPCODE_CAL: - case OPCODE_CONT: - case OPCODE_IF: - case OPCODE_ELSE: - case OPCODE_END: - case OPCODE_ENDIF: - case OPCODE_ENDLOOP: - case OPCODE_ENDSUB: - case OPCODE_RET: - return GL_TRUE; - default: - return GL_FALSE; - } -} - -/** - * Try to remove use of extraneous MOV instructions, to free them up for dead - * code removal. - */ -static void -_mesa_remove_extra_move_use(struct gl_program *prog) -{ - GLuint i, j; - - if (dbg) { - printf("Optimize: Begin remove extra move use\n"); - _mesa_print_program(prog); - } - - /* - * Look for sequences such as this: - * MOV tmpX, arg0; - * ... - * FOO tmpY, tmpX, arg1; - * and convert into: - * MOV tmpX, arg0; - * ... - * FOO tmpY, arg0, arg1; - */ - - for (i = 0; i + 1 < prog->NumInstructions; i++) { - const struct prog_instruction *mov = prog->Instructions + i; - - if (mov->Opcode != OPCODE_MOV || - mov->DstReg.File != PROGRAM_TEMPORARY || - mov->DstReg.RelAddr || - mov->DstReg.CondMask != COND_TR || - mov->SaturateMode != SATURATE_OFF || - mov->SrcReg[0].RelAddr) - continue; - - /* Walk through remaining instructions until the or src reg gets - * rewritten or we get into some flow-control, eliminating the use of - * this MOV. - */ - for (j = i + 1; j < prog->NumInstructions; j++) { - struct prog_instruction *inst2 = prog->Instructions + j; - GLuint arg; - - if (_mesa_is_flow_control_opcode(inst2->Opcode)) - break; - - /* First rewrite this instruction's args if appropriate. */ - for (arg = 0; arg < _mesa_num_inst_src_regs(inst2->Opcode); arg++) { - int comp; - int read_mask = get_src_arg_mask(inst2, arg); - - if (inst2->SrcReg[arg].File != mov->DstReg.File || - inst2->SrcReg[arg].Index != mov->DstReg.Index || - inst2->SrcReg[arg].RelAddr || - inst2->SrcReg[arg].Abs) - continue; - - /* Check that all the sources for this arg of inst2 come from inst1 - * or constants. - */ - for (comp = 0; comp < 4; comp++) { - int src_swz = GET_SWZ(inst2->SrcReg[arg].Swizzle, comp); - - /* If the MOV didn't write that channel, can't use it. */ - if ((read_mask & (1 << comp)) && - src_swz <= SWIZZLE_W && - (mov->DstReg.WriteMask & (1 << src_swz)) == 0) - break; - } - if (comp != 4) - continue; - - /* Adjust the swizzles of inst2 to point at MOV's source */ - for (comp = 0; comp < 4; comp++) { - int inst2_swz = GET_SWZ(inst2->SrcReg[arg].Swizzle, comp); - - if (inst2_swz <= SWIZZLE_W) { - GLuint s = GET_SWZ(mov->SrcReg[0].Swizzle, inst2_swz); - inst2->SrcReg[arg].Swizzle &= ~(7 << (3 * comp)); - inst2->SrcReg[arg].Swizzle |= s << (3 * comp); - inst2->SrcReg[arg].Negate ^= (((mov->SrcReg[0].Negate >> - inst2_swz) & 0x1) << comp); - } - } - inst2->SrcReg[arg].File = mov->SrcReg[0].File; - inst2->SrcReg[arg].Index = mov->SrcReg[0].Index; - } - - /* If this instruction overwrote part of the move, our time is up. */ - if ((inst2->DstReg.File == mov->DstReg.File && - (inst2->DstReg.RelAddr || - inst2->DstReg.Index == mov->DstReg.Index)) || - (inst2->DstReg.File == mov->SrcReg[0].File && - (inst2->DstReg.RelAddr || - inst2->DstReg.Index == mov->SrcReg[0].Index))) - break; - } - } - - if (dbg) { - printf("Optimize: End remove extra move use.\n"); - /*_mesa_print_program(prog);*/ - } -} - -/** - * Try to remove extraneous MOV instructions from the given program. - */ -static void -_mesa_remove_extra_moves(struct gl_program *prog) -{ - GLboolean *removeInst; /* per-instruction removal flag */ - GLuint i, rem, loopNesting = 0, subroutineNesting = 0; - - if (dbg) { - printf("Optimize: Begin remove extra moves\n"); - _mesa_print_program(prog); - } - - removeInst = (GLboolean *) - calloc(1, prog->NumInstructions * sizeof(GLboolean)); - - /* - * Look for sequences such as this: - * FOO tmpX, arg0, arg1; - * MOV tmpY, tmpX; - * and convert into: - * FOO tmpY, arg0, arg1; - */ - - for (i = 0; i < prog->NumInstructions; i++) { - const struct prog_instruction *inst = prog->Instructions + i; - - switch (inst->Opcode) { - case OPCODE_BGNLOOP: - loopNesting++; - break; - case OPCODE_ENDLOOP: - loopNesting--; - break; - case OPCODE_BGNSUB: - subroutineNesting++; - break; - case OPCODE_ENDSUB: - subroutineNesting--; - break; - case OPCODE_MOV: - if (i > 0 && - loopNesting == 0 && - subroutineNesting == 0 && - inst->SrcReg[0].File == PROGRAM_TEMPORARY && - inst->SrcReg[0].Swizzle == SWIZZLE_XYZW) { - /* see if this MOV can be removed */ - const GLuint tempIndex = inst->SrcReg[0].Index; - struct prog_instruction *prevInst; - GLuint prevI; - - /* get pointer to previous instruction */ - prevI = i - 1; - while (prevI > 0 && removeInst[prevI]) - prevI--; - prevInst = prog->Instructions + prevI; - - if (prevInst->DstReg.File == PROGRAM_TEMPORARY && - prevInst->DstReg.Index == tempIndex && - prevInst->DstReg.WriteMask == WRITEMASK_XYZW) { - - enum temp_use next_use = - find_next_temp_use(prog, i + 1, tempIndex); - - if (next_use == WRITE || next_use == END) { - /* OK, we can safely remove this MOV instruction. - * Transform: - * prevI: FOO tempIndex, x, y; - * i: MOV z, tempIndex; - * Into: - * prevI: FOO z, x, y; - */ - - /* patch up prev inst */ - prevInst->DstReg.File = inst->DstReg.File; - prevInst->DstReg.Index = inst->DstReg.Index; - - /* flag this instruction for removal */ - removeInst[i] = GL_TRUE; - - if (dbg) { - printf("Remove MOV at %u\n", i); - printf("new prev inst %u: ", prevI); - _mesa_print_instruction(prevInst); - } - } - } - } - break; - default: - ; /* nothing */ - } - } - - /* now remove the instructions which aren't needed */ - rem = remove_instructions(prog, removeInst); - - free(removeInst); - - if (dbg) { - printf("Optimize: End remove extra moves. %u instructions removed\n", rem); - /*_mesa_print_program(prog);*/ - } -} - - -/** A live register interval */ -struct interval -{ - GLuint Reg; /** The temporary register index */ - GLuint Start, End; /** Start/end instruction numbers */ -}; - - -/** A list of register intervals */ -struct interval_list -{ - GLuint Num; - struct interval Intervals[MAX_PROGRAM_TEMPS]; -}; - - -static void -append_interval(struct interval_list *list, const struct interval *inv) -{ - list->Intervals[list->Num++] = *inv; -} - - -/** Insert interval inv into list, sorted by interval end */ -static void -insert_interval_by_end(struct interval_list *list, const struct interval *inv) -{ - /* XXX we could do a binary search insertion here since list is sorted */ - GLint i = list->Num - 1; - while (i >= 0 && list->Intervals[i].End > inv->End) { - list->Intervals[i + 1] = list->Intervals[i]; - i--; - } - list->Intervals[i + 1] = *inv; - list->Num++; - -#ifdef DEBUG - { - GLuint i; - for (i = 0; i + 1 < list->Num; i++) { - ASSERT(list->Intervals[i].End <= list->Intervals[i + 1].End); - } - } -#endif -} - - -/** Remove the given interval from the interval list */ -static void -remove_interval(struct interval_list *list, const struct interval *inv) -{ - /* XXX we could binary search since list is sorted */ - GLuint k; - for (k = 0; k < list->Num; k++) { - if (list->Intervals[k].Reg == inv->Reg) { - /* found, remove it */ - ASSERT(list->Intervals[k].Start == inv->Start); - ASSERT(list->Intervals[k].End == inv->End); - while (k < list->Num - 1) { - list->Intervals[k] = list->Intervals[k + 1]; - k++; - } - list->Num--; - return; - } - } -} - - -/** called by qsort() */ -static int -compare_start(const void *a, const void *b) -{ - const struct interval *ia = (const struct interval *) a; - const struct interval *ib = (const struct interval *) b; - if (ia->Start < ib->Start) - return -1; - else if (ia->Start > ib->Start) - return +1; - else - return 0; -} - -/** sort the interval list according to interval starts */ -static void -sort_interval_list_by_start(struct interval_list *list) -{ - qsort(list->Intervals, list->Num, sizeof(struct interval), compare_start); -#ifdef DEBUG - { - GLuint i; - for (i = 0; i + 1 < list->Num; i++) { - ASSERT(list->Intervals[i].Start <= list->Intervals[i + 1].Start); - } - } -#endif -} - - -/** - * Update the intermediate interval info for register 'index' and - * instruction 'ic'. - */ -static void -update_interval(GLint intBegin[], GLint intEnd[], GLuint index, GLuint ic) -{ - ASSERT(index < MAX_PROGRAM_TEMPS); - if (intBegin[index] == -1) { - ASSERT(intEnd[index] == -1); - intBegin[index] = intEnd[index] = ic; - } - else { - intEnd[index] = ic; - } -} - - -/** - * Find first/last instruction that references each temporary register. - */ -GLboolean -_mesa_find_temp_intervals(const struct prog_instruction *instructions, - GLuint numInstructions, - GLint intBegin[MAX_PROGRAM_TEMPS], - GLint intEnd[MAX_PROGRAM_TEMPS]) -{ - struct loop_info - { - GLuint Start, End; /**< Start, end instructions of loop */ - }; - struct loop_info loopStack[MAX_LOOP_NESTING]; - GLuint loopStackDepth = 0; - GLuint i; - - for (i = 0; i < MAX_PROGRAM_TEMPS; i++){ - intBegin[i] = intEnd[i] = -1; - } - - /* Scan instructions looking for temporary registers */ - for (i = 0; i < numInstructions; i++) { - const struct prog_instruction *inst = instructions + i; - if (inst->Opcode == OPCODE_BGNLOOP) { - loopStack[loopStackDepth].Start = i; - loopStack[loopStackDepth].End = inst->BranchTarget; - loopStackDepth++; - } - else if (inst->Opcode == OPCODE_ENDLOOP) { - loopStackDepth--; - } - else if (inst->Opcode == OPCODE_CAL) { - return GL_FALSE; - } - else { - const GLuint numSrc = 3;/*_mesa_num_inst_src_regs(inst->Opcode);*/ - GLuint j; - for (j = 0; j < numSrc; j++) { - if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { - const GLuint index = inst->SrcReg[j].Index; - if (inst->SrcReg[j].RelAddr) - return GL_FALSE; - update_interval(intBegin, intEnd, index, i); - if (loopStackDepth > 0) { - /* extend temp register's interval to end of loop */ - GLuint loopEnd = loopStack[loopStackDepth - 1].End; - update_interval(intBegin, intEnd, index, loopEnd); - } - } - } - if (inst->DstReg.File == PROGRAM_TEMPORARY) { - const GLuint index = inst->DstReg.Index; - if (inst->DstReg.RelAddr) - return GL_FALSE; - update_interval(intBegin, intEnd, index, i); - if (loopStackDepth > 0) { - /* extend temp register's interval to end of loop */ - GLuint loopEnd = loopStack[loopStackDepth - 1].End; - update_interval(intBegin, intEnd, index, loopEnd); - } - } - } - } - - return GL_TRUE; -} - - -/** - * Find the live intervals for each temporary register in the program. - * For register R, the interval [A,B] indicates that R is referenced - * from instruction A through instruction B. - * Special consideration is needed for loops and subroutines. - * \return GL_TRUE if success, GL_FALSE if we cannot proceed for some reason - */ -static GLboolean -find_live_intervals(struct gl_program *prog, - struct interval_list *liveIntervals) -{ - GLint intBegin[MAX_PROGRAM_TEMPS], intEnd[MAX_PROGRAM_TEMPS]; - GLuint i; - - /* - * Note: we'll return GL_FALSE below if we find relative indexing - * into the TEMP register file. We can't handle that yet. - * We also give up on subroutines for now. - */ - - if (dbg) { - printf("Optimize: Begin find intervals\n"); - } - - /* build intermediate arrays */ - if (!_mesa_find_temp_intervals(prog->Instructions, prog->NumInstructions, - intBegin, intEnd)) - return GL_FALSE; - - /* Build live intervals list from intermediate arrays */ - liveIntervals->Num = 0; - for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { - if (intBegin[i] >= 0) { - struct interval inv; - inv.Reg = i; - inv.Start = intBegin[i]; - inv.End = intEnd[i]; - append_interval(liveIntervals, &inv); - } - } - - /* Sort the list according to interval starts */ - sort_interval_list_by_start(liveIntervals); - - if (dbg) { - /* print interval info */ - for (i = 0; i < liveIntervals->Num; i++) { - const struct interval *inv = liveIntervals->Intervals + i; - printf("Reg[%d] live [%d, %d]:", - inv->Reg, inv->Start, inv->End); - if (1) { - GLuint j; - for (j = 0; j < inv->Start; j++) - printf(" "); - for (j = inv->Start; j <= inv->End; j++) - printf("x"); - } - printf("\n"); - } - } - - return GL_TRUE; -} - - -/** Scan the array of used register flags to find free entry */ -static GLint -alloc_register(GLboolean usedRegs[MAX_PROGRAM_TEMPS]) -{ - GLuint k; - for (k = 0; k < MAX_PROGRAM_TEMPS; k++) { - if (!usedRegs[k]) { - usedRegs[k] = GL_TRUE; - return k; - } - } - return -1; -} - - -/** - * This function implements "Linear Scan Register Allocation" to reduce - * the number of temporary registers used by the program. - * - * We compute the "live interval" for all temporary registers then - * examine the overlap of the intervals to allocate new registers. - * Basically, if two intervals do not overlap, they can use the same register. - */ -static void -_mesa_reallocate_registers(struct gl_program *prog) -{ - struct interval_list liveIntervals; - GLint registerMap[MAX_PROGRAM_TEMPS]; - GLboolean usedRegs[MAX_PROGRAM_TEMPS]; - GLuint i; - GLint maxTemp = -1; - - if (dbg) { - printf("Optimize: Begin live-interval register reallocation\n"); - _mesa_print_program(prog); - } - - for (i = 0; i < MAX_PROGRAM_TEMPS; i++){ - registerMap[i] = -1; - usedRegs[i] = GL_FALSE; - } - - if (!find_live_intervals(prog, &liveIntervals)) { - if (dbg) - printf("Aborting register reallocation\n"); - return; - } - - { - struct interval_list activeIntervals; - activeIntervals.Num = 0; - - /* loop over live intervals, allocating a new register for each */ - for (i = 0; i < liveIntervals.Num; i++) { - const struct interval *live = liveIntervals.Intervals + i; - - if (dbg) - printf("Consider register %u\n", live->Reg); - - /* Expire old intervals. Intervals which have ended with respect - * to the live interval can have their remapped registers freed. - */ - { - GLint j; - for (j = 0; j < (GLint) activeIntervals.Num; j++) { - const struct interval *inv = activeIntervals.Intervals + j; - if (inv->End >= live->Start) { - /* Stop now. Since the activeInterval list is sorted - * we know we don't have to go further. - */ - break; - } - else { - /* Interval 'inv' has expired */ - const GLint regNew = registerMap[inv->Reg]; - ASSERT(regNew >= 0); - - if (dbg) - printf(" expire interval for reg %u\n", inv->Reg); - - /* remove interval j from active list */ - remove_interval(&activeIntervals, inv); - j--; /* counter-act j++ in for-loop above */ - - /* return register regNew to the free pool */ - if (dbg) - printf(" free reg %d\n", regNew); - ASSERT(usedRegs[regNew] == GL_TRUE); - usedRegs[regNew] = GL_FALSE; - } - } - } - - /* find a free register for this live interval */ - { - const GLint k = alloc_register(usedRegs); - if (k < 0) { - /* out of registers, give up */ - return; - } - registerMap[live->Reg] = k; - maxTemp = MAX2(maxTemp, k); - if (dbg) - printf(" remap register %u -> %d\n", live->Reg, k); - } - - /* Insert this live interval into the active list which is sorted - * by increasing end points. - */ - insert_interval_by_end(&activeIntervals, live); - } - } - - if (maxTemp + 1 < (GLint) liveIntervals.Num) { - /* OK, we've reduced the number of registers needed. - * Scan the program and replace all the old temporary register - * indexes with the new indexes. - */ - replace_regs(prog, PROGRAM_TEMPORARY, registerMap); - - prog->NumTemporaries = maxTemp + 1; - } - - if (dbg) { - printf("Optimize: End live-interval register reallocation\n"); - printf("Num temp regs before: %u after: %u\n", - liveIntervals.Num, maxTemp + 1); - _mesa_print_program(prog); - } -} - - -/** - * Apply optimizations to the given program to eliminate unnecessary - * instructions, temp regs, etc. - */ -void -_mesa_optimize_program(GLcontext *ctx, struct gl_program *program) -{ - _mesa_remove_extra_move_use(program); - - if (1) - _mesa_remove_dead_code(program); - - if (0) /* not tested much yet */ - _mesa_remove_extra_moves(program); - - if (0) - _mesa_consolidate_registers(program); - else - _mesa_reallocate_registers(program); -} diff --git a/src/mesa/shader/prog_optimize.h b/src/mesa/shader/prog_optimize.h deleted file mode 100644 index 43894a2723..0000000000 --- a/src/mesa/shader/prog_optimize.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.5 - * - * Copyright (C) 2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VMWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef PROG_OPT_H -#define PROG_OPT_H - - -#include "main/config.h" - - -struct gl_program; -struct prog_instruction; - - -extern GLboolean -_mesa_find_temp_intervals(const struct prog_instruction *instructions, - GLuint numInstructions, - GLint intBegin[MAX_PROGRAM_TEMPS], - GLint intEnd[MAX_PROGRAM_TEMPS]); - -extern void -_mesa_optimize_program(GLcontext *ctx, struct gl_program *program); - -#endif diff --git a/src/mesa/shader/prog_parameter.c b/src/mesa/shader/prog_parameter.c deleted file mode 100644 index aac488c79a..0000000000 --- a/src/mesa/shader/prog_parameter.c +++ /dev/null @@ -1,751 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.3 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file prog_parameter.c - * Program parameter lists and functions. - * \author Brian Paul - */ - - -#include "main/glheader.h" -#include "main/imports.h" -#include "main/macros.h" -#include "prog_instruction.h" -#include "prog_parameter.h" -#include "prog_statevars.h" - - -struct gl_program_parameter_list * -_mesa_new_parameter_list(void) -{ - return CALLOC_STRUCT(gl_program_parameter_list); -} - - -struct gl_program_parameter_list * -_mesa_new_parameter_list_sized(unsigned size) -{ - struct gl_program_parameter_list *p = _mesa_new_parameter_list(); - - if ((p != NULL) && (size != 0)) { - p->Size = size; - - /* alloc arrays */ - p->Parameters = (struct gl_program_parameter *) - calloc(1, size * sizeof(struct gl_program_parameter)); - - p->ParameterValues = (GLfloat (*)[4]) - _mesa_align_malloc(size * 4 *sizeof(GLfloat), 16); - - - if ((p->Parameters == NULL) || (p->ParameterValues == NULL)) { - free(p->Parameters); - _mesa_align_free(p->ParameterValues); - free(p); - p = NULL; - } - } - - return p; -} - - -/** - * Free a parameter list and all its parameters - */ -void -_mesa_free_parameter_list(struct gl_program_parameter_list *paramList) -{ - GLuint i; - for (i = 0; i < paramList->NumParameters; i++) { - if (paramList->Parameters[i].Name) - free((void *) paramList->Parameters[i].Name); - } - free(paramList->Parameters); - if (paramList->ParameterValues) - _mesa_align_free(paramList->ParameterValues); - free(paramList); -} - - -/** - * Add a new parameter to a parameter list. - * Note that parameter values are usually 4-element GLfloat vectors. - * When size > 4 we'll allocate a sequential block of parameters to - * store all the values (in blocks of 4). - * - * \param paramList the list to add the parameter to - * \param type type of parameter, such as - * \param name the parameter name, will be duplicated/copied! - * \param size number of elements in 'values' vector (1..4, or more) - * \param datatype GL_FLOAT, GL_FLOAT_VECx, GL_INT, GL_INT_VECx or GL_NONE. - * \param values initial parameter value, up to 4 GLfloats, or NULL - * \param state state indexes, or NULL - * \return index of new parameter in the list, or -1 if error (out of mem) - */ -GLint -_mesa_add_parameter(struct gl_program_parameter_list *paramList, - gl_register_file type, const char *name, - GLuint size, GLenum datatype, const GLfloat *values, - const gl_state_index state[STATE_LENGTH], - GLbitfield flags) -{ - const GLuint oldNum = paramList->NumParameters; - const GLuint sz4 = (size + 3) / 4; /* no. of new param slots needed */ - - assert(size > 0); - - if (oldNum + sz4 > paramList->Size) { - /* Need to grow the parameter list array (alloc some extra) */ - paramList->Size = paramList->Size + 4 * sz4; - - /* realloc arrays */ - paramList->Parameters = (struct gl_program_parameter *) - _mesa_realloc(paramList->Parameters, - oldNum * sizeof(struct gl_program_parameter), - paramList->Size * sizeof(struct gl_program_parameter)); - - paramList->ParameterValues = (GLfloat (*)[4]) - _mesa_align_realloc(paramList->ParameterValues, /* old buf */ - oldNum * 4 * sizeof(GLfloat), /* old size */ - paramList->Size * 4 *sizeof(GLfloat), /* new sz */ - 16); - } - - if (!paramList->Parameters || - !paramList->ParameterValues) { - /* out of memory */ - paramList->NumParameters = 0; - paramList->Size = 0; - return -1; - } - else { - GLuint i; - - paramList->NumParameters = oldNum + sz4; - - memset(¶mList->Parameters[oldNum], 0, - sz4 * sizeof(struct gl_program_parameter)); - - for (i = 0; i < sz4; i++) { - struct gl_program_parameter *p = paramList->Parameters + oldNum + i; - p->Name = name ? _mesa_strdup(name) : NULL; - p->Type = type; - p->Size = size; - p->DataType = datatype; - p->Flags = flags; - if (values) { - COPY_4V(paramList->ParameterValues[oldNum + i], values); - values += 4; - p->Initialized = GL_TRUE; - } - else { - /* silence valgrind */ - ASSIGN_4V(paramList->ParameterValues[oldNum + i], 0, 0, 0, 0); - } - size -= 4; - } - - if (state) { - for (i = 0; i < STATE_LENGTH; i++) - paramList->Parameters[oldNum].StateIndexes[i] = state[i]; - } - - return (GLint) oldNum; - } -} - - -/** - * Add a new named program parameter (Ex: NV_fragment_program DEFINE statement) - * \return index of the new entry in the parameter list - */ -GLint -_mesa_add_named_parameter(struct gl_program_parameter_list *paramList, - const char *name, const GLfloat values[4]) -{ - return _mesa_add_parameter(paramList, PROGRAM_NAMED_PARAM, name, - 4, GL_NONE, values, NULL, 0x0); - -} - - -/** - * Add a new named constant to the parameter list. - * This will be used when the program contains something like this: - * PARAM myVals = { 0, 1, 2, 3 }; - * - * \param paramList the parameter list - * \param name the name for the constant - * \param values four float values - * \return index/position of the new parameter in the parameter list - */ -GLint -_mesa_add_named_constant(struct gl_program_parameter_list *paramList, - const char *name, const GLfloat values[4], - GLuint size) -{ - /* first check if this is a duplicate constant */ - GLint pos; - for (pos = 0; pos < (GLint)paramList->NumParameters; pos++) { - const GLfloat *pvals = paramList->ParameterValues[pos]; - if (pvals[0] == values[0] && - pvals[1] == values[1] && - pvals[2] == values[2] && - pvals[3] == values[3] && - strcmp(paramList->Parameters[pos].Name, name) == 0) { - /* Same name and value is already in the param list - reuse it */ - return pos; - } - } - /* not found, add new parameter */ - return _mesa_add_parameter(paramList, PROGRAM_CONSTANT, name, - size, GL_NONE, values, NULL, 0x0); -} - - -/** - * Add a new unnamed constant to the parameter list. This will be used - * when a fragment/vertex program contains something like this: - * MOV r, { 0, 1, 2, 3 }; - * If swizzleOut is non-null we'll search the parameter list for an - * existing instance of the constant which matches with a swizzle. - * - * \param paramList the parameter list - * \param values four float values - * \param swizzleOut returns swizzle mask for accessing the constant - * \return index/position of the new parameter in the parameter list. - */ -GLint -_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList, - const GLfloat values[4], GLuint size, - GLuint *swizzleOut) -{ - GLint pos; - ASSERT(size >= 1); - ASSERT(size <= 4); - - if (swizzleOut && - _mesa_lookup_parameter_constant(paramList, values, - size, &pos, swizzleOut)) { - return pos; - } - - /* Look for empty space in an already unnamed constant parameter - * to add this constant. This will only work for single-element - * constants because we rely on smearing (i.e. .yyyy or .zzzz). - */ - if (size == 1 && swizzleOut) { - for (pos = 0; pos < (GLint) paramList->NumParameters; pos++) { - struct gl_program_parameter *p = paramList->Parameters + pos; - if (p->Type == PROGRAM_CONSTANT && p->Size + size <= 4) { - /* ok, found room */ - GLfloat *pVal = paramList->ParameterValues[pos]; - GLuint swz = p->Size; /* 1, 2 or 3 for Y, Z, W */ - pVal[p->Size] = values[0]; - p->Size++; - *swizzleOut = MAKE_SWIZZLE4(swz, swz, swz, swz); - return pos; - } - } - } - - /* add a new parameter to store this constant */ - pos = _mesa_add_parameter(paramList, PROGRAM_CONSTANT, NULL, - size, GL_NONE, values, NULL, 0x0); - if (pos >= 0 && swizzleOut) { - if (size == 1) - *swizzleOut = SWIZZLE_XXXX; - else - *swizzleOut = SWIZZLE_NOOP; - } - return pos; -} - - -/** - * Add a uniform to the parameter list. - * Note that if the uniform is an array, size may be greater than - * what's implied by the datatype. - * \param name uniform's name - * \param size number of floats to allocate - * \param datatype GL_FLOAT_VEC3, GL_FLOAT_MAT4, etc. - */ -GLint -_mesa_add_uniform(struct gl_program_parameter_list *paramList, - const char *name, GLuint size, GLenum datatype, - const GLfloat *values) -{ - GLint i = _mesa_lookup_parameter_index(paramList, -1, name); - ASSERT(datatype != GL_NONE); - if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_UNIFORM) { - ASSERT(paramList->Parameters[i].Size == size); - ASSERT(paramList->Parameters[i].DataType == datatype); - /* already in list */ - return i; - } - else { - i = _mesa_add_parameter(paramList, PROGRAM_UNIFORM, name, - size, datatype, values, NULL, 0x0); - return i; - } -} - - -/** - * Mark the named uniform as 'used'. - */ -void -_mesa_use_uniform(struct gl_program_parameter_list *paramList, - const char *name) -{ - GLuint i; - for (i = 0; i < paramList->NumParameters; i++) { - struct gl_program_parameter *p = paramList->Parameters + i; - if ((p->Type == PROGRAM_UNIFORM || p->Type == PROGRAM_SAMPLER) && - strcmp(p->Name, name) == 0) { - p->Used = GL_TRUE; - /* Note that large uniforms may occupy several slots so we're - * not done searching yet. - */ - } - } -} - - -/** - * Add a sampler to the parameter list. - * \param name uniform's name - * \param datatype GL_SAMPLER_2D, GL_SAMPLER_2D_RECT_ARB, etc. - * \param index the sampler number (as seen in TEX instructions) - * \return sampler index (starting at zero) or -1 if error - */ -GLint -_mesa_add_sampler(struct gl_program_parameter_list *paramList, - const char *name, GLenum datatype) -{ - GLint i = _mesa_lookup_parameter_index(paramList, -1, name); - if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_SAMPLER) { - ASSERT(paramList->Parameters[i].Size == 1); - ASSERT(paramList->Parameters[i].DataType == datatype); - /* already in list */ - return (GLint) paramList->ParameterValues[i][0]; - } - else { - GLuint i; - const GLint size = 1; /* a sampler is basically a texture unit number */ - GLfloat value[4]; - GLint numSamplers = 0; - for (i = 0; i < paramList->NumParameters; i++) { - if (paramList->Parameters[i].Type == PROGRAM_SAMPLER) - numSamplers++; - } - value[0] = (GLfloat) numSamplers; - value[1] = value[2] = value[3] = 0.0F; - (void) _mesa_add_parameter(paramList, PROGRAM_SAMPLER, name, - size, datatype, value, NULL, 0x0); - return numSamplers; - } -} - - -/** - * Add parameter representing a varying variable. - */ -GLint -_mesa_add_varying(struct gl_program_parameter_list *paramList, - const char *name, GLuint size, GLenum datatype, - GLbitfield flags) -{ - GLint i = _mesa_lookup_parameter_index(paramList, -1, name); - if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_VARYING) { - /* already in list */ - return i; - } - else { - /*assert(size == 4);*/ - i = _mesa_add_parameter(paramList, PROGRAM_VARYING, name, - size, datatype, NULL, NULL, flags); - return i; - } -} - - -/** - * Add parameter representing a vertex program attribute. - * \param size size of attribute (in floats), may be -1 if unknown - * \param attrib the attribute index, or -1 if unknown - */ -GLint -_mesa_add_attribute(struct gl_program_parameter_list *paramList, - const char *name, GLint size, GLenum datatype, GLint attrib) -{ - GLint i = _mesa_lookup_parameter_index(paramList, -1, name); - if (i >= 0) { - /* replace */ - if (attrib < 0) - attrib = i; - paramList->Parameters[i].StateIndexes[0] = attrib; - } - else { - /* add */ - gl_state_index state[STATE_LENGTH]; - state[0] = (gl_state_index) attrib; - if (size < 0) - size = 4; - i = _mesa_add_parameter(paramList, PROGRAM_INPUT, name, - size, datatype, NULL, state, 0x0); - } - return i; -} - - - -#if 0 /* not used yet */ -/** - * Returns the number of 4-component registers needed to store a piece - * of GL state. For matrices this may be as many as 4 registers, - * everything else needs - * just 1 register. - */ -static GLuint -sizeof_state_reference(const GLint *stateTokens) -{ - if (stateTokens[0] == STATE_MATRIX) { - GLuint rows = stateTokens[4] - stateTokens[3] + 1; - assert(rows >= 1); - assert(rows <= 4); - return rows; - } - else { - return 1; - } -} -#endif - - -/** - * Add a new state reference to the parameter list. - * This will be used when the program contains something like this: - * PARAM ambient = state.material.front.ambient; - * - * \param paramList the parameter list - * \param stateTokens an array of 5 (STATE_LENGTH) state tokens - * \return index of the new parameter. - */ -GLint -_mesa_add_state_reference(struct gl_program_parameter_list *paramList, - const gl_state_index stateTokens[STATE_LENGTH]) -{ - const GLuint size = 4; /* XXX fix */ - char *name; - GLint index; - - /* Check if the state reference is already in the list */ - for (index = 0; index < (GLint) paramList->NumParameters; index++) { - GLuint i, match = 0; - for (i = 0; i < STATE_LENGTH; i++) { - if (paramList->Parameters[index].StateIndexes[i] == stateTokens[i]) { - match++; - } - else { - break; - } - } - if (match == STATE_LENGTH) { - /* this state reference is already in the parameter list */ - return index; - } - } - - name = _mesa_program_state_string(stateTokens); - index = _mesa_add_parameter(paramList, PROGRAM_STATE_VAR, name, - size, GL_NONE, - NULL, (gl_state_index *) stateTokens, 0x0); - paramList->StateFlags |= _mesa_program_state_flags(stateTokens); - - /* free name string here since we duplicated it in add_parameter() */ - free(name); - - return index; -} - - -/** - * Lookup a parameter value by name in the given parameter list. - * \return pointer to the float[4] values. - */ -GLfloat * -_mesa_lookup_parameter_value(const struct gl_program_parameter_list *paramList, - GLsizei nameLen, const char *name) -{ - GLint i = _mesa_lookup_parameter_index(paramList, nameLen, name); - if (i < 0) - return NULL; - else - return paramList->ParameterValues[i]; -} - - -/** - * Given a program parameter name, find its position in the list of parameters. - * \param paramList the parameter list to search - * \param nameLen length of name (in chars). - * If length is negative, assume that name is null-terminated. - * \param name the name to search for - * \return index of parameter in the list. - */ -GLint -_mesa_lookup_parameter_index(const struct gl_program_parameter_list *paramList, - GLsizei nameLen, const char *name) -{ - GLint i; - - if (!paramList) - return -1; - - if (nameLen == -1) { - /* name is null-terminated */ - for (i = 0; i < (GLint) paramList->NumParameters; i++) { - if (paramList->Parameters[i].Name && - strcmp(paramList->Parameters[i].Name, name) == 0) - return i; - } - } - else { - /* name is not null-terminated, use nameLen */ - for (i = 0; i < (GLint) paramList->NumParameters; i++) { - if (paramList->Parameters[i].Name && - strncmp(paramList->Parameters[i].Name, name, nameLen) == 0 - && strlen(paramList->Parameters[i].Name) == (size_t)nameLen) - return i; - } - } - return -1; -} - - -/** - * Look for a float vector in the given parameter list. The float vector - * may be of length 1, 2, 3 or 4. If swizzleOut is non-null, we'll try - * swizzling to find a match. - * \param list the parameter list to search - * \param v the float vector to search for - * \param vSize number of element in v - * \param posOut returns the position of the constant, if found - * \param swizzleOut returns a swizzle mask describing location of the - * vector elements if found. - * \return GL_TRUE if found, GL_FALSE if not found - */ -GLboolean -_mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list, - const GLfloat v[], GLuint vSize, - GLint *posOut, GLuint *swizzleOut) -{ - GLuint i; - - assert(vSize >= 1); - assert(vSize <= 4); - - if (!list) - return -1; - - for (i = 0; i < list->NumParameters; i++) { - if (list->Parameters[i].Type == PROGRAM_CONSTANT) { - if (!swizzleOut) { - /* swizzle not allowed */ - GLuint j, match = 0; - for (j = 0; j < vSize; j++) { - if (v[j] == list->ParameterValues[i][j]) - match++; - } - if (match == vSize) { - *posOut = i; - return GL_TRUE; - } - } - else { - /* try matching w/ swizzle */ - if (vSize == 1) { - /* look for v[0] anywhere within float[4] value */ - GLuint j; - for (j = 0; j < 4; j++) { - if (list->ParameterValues[i][j] == v[0]) { - /* found it */ - *posOut = i; - *swizzleOut = MAKE_SWIZZLE4(j, j, j, j); - return GL_TRUE; - } - } - } - else if (vSize <= list->Parameters[i].Size) { - /* see if we can match this constant (with a swizzle) */ - GLuint swz[4]; - GLuint match = 0, j, k; - for (j = 0; j < vSize; j++) { - if (v[j] == list->ParameterValues[i][j]) { - swz[j] = j; - match++; - } - else { - for (k = 0; k < list->Parameters[i].Size; k++) { - if (v[j] == list->ParameterValues[i][k]) { - swz[j] = k; - match++; - break; - } - } - } - } - /* smear last value to remaining positions */ - for (; j < 4; j++) - swz[j] = swz[j-1]; - - if (match == vSize) { - *posOut = i; - *swizzleOut = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]); - return GL_TRUE; - } - } - } - } - } - - *posOut = -1; - return GL_FALSE; -} - - -struct gl_program_parameter_list * -_mesa_clone_parameter_list(const struct gl_program_parameter_list *list) -{ - struct gl_program_parameter_list *clone; - GLuint i; - - clone = _mesa_new_parameter_list(); - if (!clone) - return NULL; - - /** Not too efficient, but correct */ - for (i = 0; i < list->NumParameters; i++) { - struct gl_program_parameter *p = list->Parameters + i; - struct gl_program_parameter *pCopy; - GLuint size = MIN2(p->Size, 4); - GLint j = _mesa_add_parameter(clone, p->Type, p->Name, size, p->DataType, - list->ParameterValues[i], NULL, 0x0); - ASSERT(j >= 0); - pCopy = clone->Parameters + j; - pCopy->Used = p->Used; - pCopy->Flags = p->Flags; - /* copy state indexes */ - if (p->Type == PROGRAM_STATE_VAR) { - GLint k; - for (k = 0; k < STATE_LENGTH; k++) { - pCopy->StateIndexes[k] = p->StateIndexes[k]; - } - } - else { - clone->Parameters[j].Size = p->Size; - } - - } - - clone->StateFlags = list->StateFlags; - - return clone; -} - - -/** - * Return a new parameter list which is listA + listB. - */ -struct gl_program_parameter_list * -_mesa_combine_parameter_lists(const struct gl_program_parameter_list *listA, - const struct gl_program_parameter_list *listB) -{ - struct gl_program_parameter_list *list; - - if (listA) { - list = _mesa_clone_parameter_list(listA); - if (list && listB) { - GLuint i; - for (i = 0; i < listB->NumParameters; i++) { - struct gl_program_parameter *param = listB->Parameters + i; - _mesa_add_parameter(list, param->Type, param->Name, param->Size, - param->DataType, - listB->ParameterValues[i], - param->StateIndexes, - param->Flags); - } - } - } - else if (listB) { - list = _mesa_clone_parameter_list(listB); - } - else { - list = NULL; - } - return list; -} - - - -/** - * Find longest name of all uniform parameters in list. - */ -GLuint -_mesa_longest_parameter_name(const struct gl_program_parameter_list *list, - gl_register_file type) -{ - GLuint i, maxLen = 0; - if (!list) - return 0; - for (i = 0; i < list->NumParameters; i++) { - if (list->Parameters[i].Type == type) { - GLuint len = strlen(list->Parameters[i].Name); - if (len > maxLen) - maxLen = len; - } - } - return maxLen; -} - - -/** - * Count the number of parameters in the last that match the given type. - */ -GLuint -_mesa_num_parameters_of_type(const struct gl_program_parameter_list *list, - gl_register_file type) -{ - GLuint i, count = 0; - if (list) { - for (i = 0; i < list->NumParameters; i++) { - if (list->Parameters[i].Type == type) - count++; - } - } - return count; -} diff --git a/src/mesa/shader/prog_parameter.h b/src/mesa/shader/prog_parameter.h deleted file mode 100644 index cc3378ae20..0000000000 --- a/src/mesa/shader/prog_parameter.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.3 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file prog_parameter.c - * Program parameter lists and functions. - * \author Brian Paul - */ - -#ifndef PROG_PARAMETER_H -#define PROG_PARAMETER_H - -#include "main/mtypes.h" -#include "prog_statevars.h" - - -/** - * Program parameter flags - */ -/*@{*/ -#define PROG_PARAM_BIT_CENTROID 0x1 /**< for varying vars (GLSL 1.20) */ -#define PROG_PARAM_BIT_INVARIANT 0x2 /**< for varying vars (GLSL 1.20) */ -#define PROG_PARAM_BIT_FLAT 0x4 /**< for varying vars (GLSL 1.30) */ -#define PROG_PARAM_BIT_LINEAR 0x8 /**< for varying vars (GLSL 1.30) */ -#define PROG_PARAM_BIT_CYL_WRAP 0x10 /**< XXX gallium debug */ -/*@}*/ - - - -/** - * Program parameter. - * Used by shaders/programs for uniforms, constants, varying vars, etc. - */ -struct gl_program_parameter -{ - const char *Name; /**< Null-terminated string */ - gl_register_file Type; /**< PROGRAM_NAMED_PARAM, CONSTANT or STATE_VAR */ - GLenum DataType; /**< GL_FLOAT, GL_FLOAT_VEC2, etc */ - /** - * Number of components (1..4), or more. - * If the number of components is greater than 4, - * this parameter is part of a larger uniform like a GLSL matrix or array. - * The next program parameter's Size will be Size-4 of this parameter. - */ - GLuint Size; - GLboolean Used; /**< Helper flag for GLSL uniform tracking */ - GLboolean Initialized; /**< Has the ParameterValue[] been set? */ - GLbitfield Flags; /**< Bitmask of PROG_PARAM_*_BIT */ - /** - * A sequence of STATE_* tokens and integers to identify GL state. - */ - gl_state_index StateIndexes[STATE_LENGTH]; -}; - - -/** - * List of gl_program_parameter instances. - */ -struct gl_program_parameter_list -{ - GLuint Size; /**< allocated size of Parameters, ParameterValues */ - GLuint NumParameters; /**< number of parameters in arrays */ - struct gl_program_parameter *Parameters; /**< Array [Size] */ - GLfloat (*ParameterValues)[4]; /**< Array [Size] of GLfloat[4] */ - GLbitfield StateFlags; /**< _NEW_* flags indicating which state changes - might invalidate ParameterValues[] */ -}; - - -extern struct gl_program_parameter_list * -_mesa_new_parameter_list(void); - -extern struct gl_program_parameter_list * -_mesa_new_parameter_list_sized(unsigned size); - -extern void -_mesa_free_parameter_list(struct gl_program_parameter_list *paramList); - -extern struct gl_program_parameter_list * -_mesa_clone_parameter_list(const struct gl_program_parameter_list *list); - -extern struct gl_program_parameter_list * -_mesa_combine_parameter_lists(const struct gl_program_parameter_list *a, - const struct gl_program_parameter_list *b); - -static INLINE GLuint -_mesa_num_parameters(const struct gl_program_parameter_list *list) -{ - return list ? list->NumParameters : 0; -} - -extern GLint -_mesa_add_parameter(struct gl_program_parameter_list *paramList, - gl_register_file type, const char *name, - GLuint size, GLenum datatype, const GLfloat *values, - const gl_state_index state[STATE_LENGTH], - GLbitfield flags); - -extern GLint -_mesa_add_named_parameter(struct gl_program_parameter_list *paramList, - const char *name, const GLfloat values[4]); - -extern GLint -_mesa_add_named_constant(struct gl_program_parameter_list *paramList, - const char *name, const GLfloat values[4], - GLuint size); - -extern GLint -_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList, - const GLfloat values[4], GLuint size, - GLuint *swizzleOut); - -extern GLint -_mesa_add_uniform(struct gl_program_parameter_list *paramList, - const char *name, GLuint size, GLenum datatype, - const GLfloat *values); - -extern void -_mesa_use_uniform(struct gl_program_parameter_list *paramList, - const char *name); - -extern GLint -_mesa_add_sampler(struct gl_program_parameter_list *paramList, - const char *name, GLenum datatype); - -extern GLint -_mesa_add_varying(struct gl_program_parameter_list *paramList, - const char *name, GLuint size, GLenum datatype, - GLbitfield flags); - -extern GLint -_mesa_add_attribute(struct gl_program_parameter_list *paramList, - const char *name, GLint size, GLenum datatype, GLint attrib); - -extern GLint -_mesa_add_state_reference(struct gl_program_parameter_list *paramList, - const gl_state_index stateTokens[STATE_LENGTH]); - -extern GLfloat * -_mesa_lookup_parameter_value(const struct gl_program_parameter_list *paramList, - GLsizei nameLen, const char *name); - -extern GLint -_mesa_lookup_parameter_index(const struct gl_program_parameter_list *paramList, - GLsizei nameLen, const char *name); - -extern GLboolean -_mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list, - const GLfloat v[], GLuint vSize, - GLint *posOut, GLuint *swizzleOut); - -extern GLuint -_mesa_longest_parameter_name(const struct gl_program_parameter_list *list, - gl_register_file type); - -extern GLuint -_mesa_num_parameters_of_type(const struct gl_program_parameter_list *list, - gl_register_file type); - - -#endif /* PROG_PARAMETER_H */ diff --git a/src/mesa/shader/prog_parameter_layout.c b/src/mesa/shader/prog_parameter_layout.c deleted file mode 100644 index a888573832..0000000000 --- a/src/mesa/shader/prog_parameter_layout.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright © 2009 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/** - * \file prog_parameter_layout.c - * \brief Helper functions to layout storage for program parameters - * - * \author Ian Romanick - */ - -#include "main/mtypes.h" -#include "prog_parameter.h" -#include "prog_parameter_layout.h" -#include "prog_instruction.h" -#include "program_parser.h" - -unsigned -_mesa_combine_swizzles(unsigned base, unsigned applied) -{ - unsigned swiz = 0; - unsigned i; - - for (i = 0; i < 4; i++) { - const unsigned s = GET_SWZ(applied, i); - - swiz |= ((s <= SWIZZLE_W) ? GET_SWZ(base, s) : s) << (i * 3); - } - - return swiz; -} - - -/** - * Copy indirect access array from one parameter list to another - * - * \param src Parameter array copied from - * \param dst Parameter array copied to - * \param first Index of first element in \c src to copy - * \param count Number of elements to copy - * - * \return - * The location in \c dst of the first element copied from \c src on - * success. -1 on failure. - * - * \warning - * This function assumes that there is already enough space available in - * \c dst to hold all of the elements that will be copied over. - */ -static int -copy_indirect_accessed_array(struct gl_program_parameter_list *src, - struct gl_program_parameter_list *dst, - unsigned first, unsigned count) -{ - const int base = dst->NumParameters; - unsigned i, j; - - for (i = first; i < (first + count); i++) { - struct gl_program_parameter *curr = & src->Parameters[i]; - - if (curr->Type == PROGRAM_CONSTANT) { - j = dst->NumParameters; - } else { - for (j = 0; j < dst->NumParameters; j++) { - if (memcmp(dst->Parameters[j].StateIndexes, curr->StateIndexes, - sizeof(curr->StateIndexes)) == 0) { - return -1; - } - } - } - - assert(j == dst->NumParameters); - - /* copy src parameter [i] to dest parameter [j] */ - memcpy(& dst->Parameters[j], curr, - sizeof(dst->Parameters[j])); - memcpy(dst->ParameterValues[j], src->ParameterValues[i], - sizeof(GLfloat) * 4); - - /* Pointer to the string name was copied. Null-out src param name - * to prevent double free later. - */ - curr->Name = NULL; - - dst->NumParameters++; - } - - return base; -} - - -/** - * XXX description??? - * \return GL_TRUE for success, GL_FALSE for failure - */ -GLboolean -_mesa_layout_parameters(struct asm_parser_state *state) -{ - struct gl_program_parameter_list *layout; - struct asm_instruction *inst; - unsigned i; - - layout = - _mesa_new_parameter_list_sized(state->prog->Parameters->NumParameters); - - /* PASS 1: Move any parameters that are accessed indirectly from the - * original parameter list to the new parameter list. - */ - for (inst = state->inst_head; inst != NULL; inst = inst->next) { - for (i = 0; i < 3; i++) { - if (inst->SrcReg[i].Base.RelAddr) { - /* Only attempt to add the to the new parameter list once. - */ - if (!inst->SrcReg[i].Symbol->pass1_done) { - const int new_begin = - copy_indirect_accessed_array(state->prog->Parameters, layout, - inst->SrcReg[i].Symbol->param_binding_begin, - inst->SrcReg[i].Symbol->param_binding_length); - - if (new_begin < 0) { - return GL_FALSE; - } - - inst->SrcReg[i].Symbol->param_binding_begin = new_begin; - inst->SrcReg[i].Symbol->pass1_done = 1; - } - - /* Previously the Index was just the offset from the parameter - * array. Now that the base of the parameter array is known, the - * index can be updated to its actual value. - */ - inst->Base.SrcReg[i] = inst->SrcReg[i].Base; - inst->Base.SrcReg[i].Index += - inst->SrcReg[i].Symbol->param_binding_begin; - } - } - } - - /* PASS 2: Move any parameters that are not accessed indirectly from the - * original parameter list to the new parameter list. - */ - for (inst = state->inst_head; inst != NULL; inst = inst->next) { - for (i = 0; i < 3; i++) { - const struct gl_program_parameter *p; - const int idx = inst->SrcReg[i].Base.Index; - unsigned swizzle = SWIZZLE_NOOP; - - /* All relative addressed operands were processed on the first - * pass. Just skip them here. - */ - if (inst->SrcReg[i].Base.RelAddr) { - continue; - } - - if ((inst->SrcReg[i].Base.File <= PROGRAM_VARYING ) - || (inst->SrcReg[i].Base.File >= PROGRAM_WRITE_ONLY)) { - continue; - } - - inst->Base.SrcReg[i] = inst->SrcReg[i].Base; - p = & state->prog->Parameters->Parameters[idx]; - - switch (p->Type) { - case PROGRAM_CONSTANT: { - const float *const v = - state->prog->Parameters->ParameterValues[idx]; - - inst->Base.SrcReg[i].Index = - _mesa_add_unnamed_constant(layout, v, p->Size, & swizzle); - - inst->Base.SrcReg[i].Swizzle = - _mesa_combine_swizzles(swizzle, inst->Base.SrcReg[i].Swizzle); - break; - } - - case PROGRAM_STATE_VAR: - inst->Base.SrcReg[i].Index = - _mesa_add_state_reference(layout, p->StateIndexes); - break; - - default: - break; - } - - inst->SrcReg[i].Base.File = p->Type; - inst->Base.SrcReg[i].File = p->Type; - } - } - - _mesa_free_parameter_list(state->prog->Parameters); - state->prog->Parameters = layout; - - return GL_TRUE; -} diff --git a/src/mesa/shader/prog_parameter_layout.h b/src/mesa/shader/prog_parameter_layout.h deleted file mode 100644 index 99a7b6c726..0000000000 --- a/src/mesa/shader/prog_parameter_layout.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright © 2009 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/** - * \file prog_parameter_layout.h - * \brief Helper functions to layout storage for program parameters - * - * \author Ian Romanick - */ - -#pragma once - -#ifndef PROG_PARAMETER_LAYOUT_H -#define PROG_PARAMETER_LAYOUT_H - -extern unsigned _mesa_combine_swizzles(unsigned base, unsigned applied); - -struct asm_parser_state; - -extern GLboolean _mesa_layout_parameters(struct asm_parser_state *state); - -#endif /* PROG_PARAMETER_LAYOUT_H */ diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c deleted file mode 100644 index 05aae83f0c..0000000000 --- a/src/mesa/shader/prog_print.c +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.3 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file prog_print.c - * Print vertex/fragment programs - for debugging. - * \author Brian Paul - */ - -#include "main/glheader.h" -#include "main/context.h" -#include "main/imports.h" -#include "prog_instruction.h" -#include "prog_parameter.h" -#include "prog_print.h" -#include "prog_statevars.h" - - - -/** - * Return string name for given program/register file. - */ -static const char * -file_string(gl_register_file f, gl_prog_print_mode mode) -{ - switch (f) { - case PROGRAM_TEMPORARY: - return "TEMP"; - case PROGRAM_LOCAL_PARAM: - return "LOCAL"; - case PROGRAM_ENV_PARAM: - return "ENV"; - case PROGRAM_STATE_VAR: - return "STATE"; - case PROGRAM_INPUT: - return "INPUT"; - case PROGRAM_OUTPUT: - return "OUTPUT"; - case PROGRAM_NAMED_PARAM: - return "NAMED"; - case PROGRAM_CONSTANT: - return "CONST"; - case PROGRAM_UNIFORM: - return "UNIFORM"; - case PROGRAM_VARYING: - return "VARYING"; - case PROGRAM_WRITE_ONLY: - return "WRITE_ONLY"; - case PROGRAM_ADDRESS: - return "ADDR"; - case PROGRAM_SAMPLER: - return "SAMPLER"; - case PROGRAM_UNDEFINED: - return "UNDEFINED"; - default: - { - static char s[20]; - _mesa_snprintf(s, sizeof(s), "FILE%u", f); - return s; - } - } -} - - -/** - * Return ARB_v/f_prog-style input attrib string. - */ -static const char * -arb_input_attrib_string(GLint index, GLenum progType) -{ - /* - * These strings should match the VERT_ATTRIB_x and FRAG_ATTRIB_x tokens. - */ - const char *vertAttribs[] = { - "vertex.position", - "vertex.weight", - "vertex.normal", - "vertex.color.primary", - "vertex.color.secondary", - "vertex.fogcoord", - "vertex.(six)", - "vertex.(seven)", - "vertex.texcoord[0]", - "vertex.texcoord[1]", - "vertex.texcoord[2]", - "vertex.texcoord[3]", - "vertex.texcoord[4]", - "vertex.texcoord[5]", - "vertex.texcoord[6]", - "vertex.texcoord[7]", - "vertex.attrib[0]", - "vertex.attrib[1]", - "vertex.attrib[2]", - "vertex.attrib[3]", - "vertex.attrib[4]", - "vertex.attrib[5]", - "vertex.attrib[6]", - "vertex.attrib[7]", - "vertex.attrib[8]", - "vertex.attrib[9]", - "vertex.attrib[10]", - "vertex.attrib[11]", - "vertex.attrib[12]", - "vertex.attrib[13]", - "vertex.attrib[14]", - "vertex.attrib[15]" - }; - const char *fragAttribs[] = { - "fragment.position", - "fragment.color.primary", - "fragment.color.secondary", - "fragment.fogcoord", - "fragment.texcoord[0]", - "fragment.texcoord[1]", - "fragment.texcoord[2]", - "fragment.texcoord[3]", - "fragment.texcoord[4]", - "fragment.texcoord[5]", - "fragment.texcoord[6]", - "fragment.texcoord[7]", - "fragment.varying[0]", - "fragment.varying[1]", - "fragment.varying[2]", - "fragment.varying[3]", - "fragment.varying[4]", - "fragment.varying[5]", - "fragment.varying[6]", - "fragment.varying[7]" - }; - - /* sanity checks */ - assert(strcmp(vertAttribs[VERT_ATTRIB_TEX0], "vertex.texcoord[0]") == 0); - assert(strcmp(vertAttribs[VERT_ATTRIB_GENERIC15], "vertex.attrib[15]") == 0); - - if (progType == GL_VERTEX_PROGRAM_ARB) { - assert(index < sizeof(vertAttribs) / sizeof(vertAttribs[0])); - return vertAttribs[index]; - } - else { - assert(index < sizeof(fragAttribs) / sizeof(fragAttribs[0])); - return fragAttribs[index]; - } -} - - -/** - * Print a vertex program's InputsRead field in human-readable format. - * For debugging. - */ -void -_mesa_print_vp_inputs(GLbitfield inputs) -{ - printf("VP Inputs 0x%x: \n", inputs); - while (inputs) { - GLint attr = _mesa_ffs(inputs) - 1; - const char *name = arb_input_attrib_string(attr, - GL_VERTEX_PROGRAM_ARB); - printf(" %d: %s\n", attr, name); - inputs &= ~(1 << attr); - } -} - - -/** - * Print a fragment program's InputsRead field in human-readable format. - * For debugging. - */ -void -_mesa_print_fp_inputs(GLbitfield inputs) -{ - printf("FP Inputs 0x%x: \n", inputs); - while (inputs) { - GLint attr = _mesa_ffs(inputs) - 1; - const char *name = arb_input_attrib_string(attr, - GL_FRAGMENT_PROGRAM_ARB); - printf(" %d: %s\n", attr, name); - inputs &= ~(1 << attr); - } -} - - - -/** - * Return ARB_v/f_prog-style output attrib string. - */ -static const char * -arb_output_attrib_string(GLint index, GLenum progType) -{ - /* - * These strings should match the VERT_RESULT_x and FRAG_RESULT_x tokens. - */ - const char *vertResults[] = { - "result.position", - "result.color.primary", - "result.color.secondary", - "result.fogcoord", - "result.texcoord[0]", - "result.texcoord[1]", - "result.texcoord[2]", - "result.texcoord[3]", - "result.texcoord[4]", - "result.texcoord[5]", - "result.texcoord[6]", - "result.texcoord[7]", - "result.varying[0]", - "result.varying[1]", - "result.varying[2]", - "result.varying[3]", - "result.varying[4]", - "result.varying[5]", - "result.varying[6]", - "result.varying[7]" - }; - const char *fragResults[] = { - "result.color", - "result.color(half)", - "result.depth", - "result.color[0]", - "result.color[1]", - "result.color[2]", - "result.color[3]" - }; - - if (progType == GL_VERTEX_PROGRAM_ARB) { - assert(index < sizeof(vertResults) / sizeof(vertResults[0])); - return vertResults[index]; - } - else { - assert(index < sizeof(fragResults) / sizeof(fragResults[0])); - return fragResults[index]; - } -} - - -/** - * Return string representation of the given register. - * Note that some types of registers (like PROGRAM_UNIFORM) aren't defined - * by the ARB/NV program languages so we've taken some liberties here. - * \param f the register file (PROGRAM_INPUT, PROGRAM_TEMPORARY, etc) - * \param index number of the register in the register file - * \param mode the output format/mode/style - * \param prog pointer to containing program - */ -static const char * -reg_string(gl_register_file f, GLint index, gl_prog_print_mode mode, - GLboolean relAddr, const struct gl_program *prog) -{ - static char str[100]; - const char *addr = relAddr ? "ADDR+" : ""; - - str[0] = 0; - - switch (mode) { - case PROG_PRINT_DEBUG: - sprintf(str, "%s[%s%d]", file_string(f, mode), addr, index); - break; - - case PROG_PRINT_ARB: - switch (f) { - case PROGRAM_INPUT: - sprintf(str, "%s", arb_input_attrib_string(index, prog->Target)); - break; - case PROGRAM_OUTPUT: - sprintf(str, "%s", arb_output_attrib_string(index, prog->Target)); - break; - case PROGRAM_TEMPORARY: - sprintf(str, "temp%d", index); - break; - case PROGRAM_ENV_PARAM: - sprintf(str, "program.env[%s%d]", addr, index); - break; - case PROGRAM_LOCAL_PARAM: - sprintf(str, "program.local[%s%d]", addr, index); - break; - case PROGRAM_VARYING: /* extension */ - sprintf(str, "varying[%s%d]", addr, index); - break; - case PROGRAM_CONSTANT: /* extension */ - sprintf(str, "constant[%s%d]", addr, index); - break; - case PROGRAM_UNIFORM: /* extension */ - sprintf(str, "uniform[%s%d]", addr, index); - break; - case PROGRAM_STATE_VAR: - { - struct gl_program_parameter *param - = prog->Parameters->Parameters + index; - char *state = _mesa_program_state_string(param->StateIndexes); - sprintf(str, "%s", state); - free(state); - } - break; - case PROGRAM_ADDRESS: - sprintf(str, "A%d", index); - break; - default: - _mesa_problem(NULL, "bad file in reg_string()"); - } - break; - - case PROG_PRINT_NV: - switch (f) { - case PROGRAM_INPUT: - if (prog->Target == GL_VERTEX_PROGRAM_ARB) - sprintf(str, "v[%d]", index); - else - sprintf(str, "f[%d]", index); - break; - case PROGRAM_OUTPUT: - sprintf(str, "o[%d]", index); - break; - case PROGRAM_TEMPORARY: - sprintf(str, "R%d", index); - break; - case PROGRAM_ENV_PARAM: - sprintf(str, "c[%d]", index); - break; - case PROGRAM_VARYING: /* extension */ - sprintf(str, "varying[%s%d]", addr, index); - break; - case PROGRAM_UNIFORM: /* extension */ - sprintf(str, "uniform[%s%d]", addr, index); - break; - case PROGRAM_CONSTANT: /* extension */ - sprintf(str, "constant[%s%d]", addr, index); - break; - case PROGRAM_STATE_VAR: /* extension */ - sprintf(str, "state[%s%d]", addr, index); - break; - default: - _mesa_problem(NULL, "bad file in reg_string()"); - } - break; - - default: - _mesa_problem(NULL, "bad mode in reg_string()"); - } - - return str; -} - - -/** - * Return a string representation of the given swizzle word. - * If extended is true, use extended (comma-separated) format. - * \param swizzle the swizzle field - * \param negateBase 4-bit negation vector - * \param extended if true, also allow 0, 1 values - */ -const char * -_mesa_swizzle_string(GLuint swizzle, GLuint negateMask, GLboolean extended) -{ - static const char swz[] = "xyzw01!?"; /* See SWIZZLE_x definitions */ - static char s[20]; - GLuint i = 0; - - if (!extended && swizzle == SWIZZLE_NOOP && negateMask == 0) - return ""; /* no swizzle/negation */ - - if (!extended) - s[i++] = '.'; - - if (negateMask & NEGATE_X) - s[i++] = '-'; - s[i++] = swz[GET_SWZ(swizzle, 0)]; - - if (extended) { - s[i++] = ','; - } - - if (negateMask & NEGATE_Y) - s[i++] = '-'; - s[i++] = swz[GET_SWZ(swizzle, 1)]; - - if (extended) { - s[i++] = ','; - } - - if (negateMask & NEGATE_Z) - s[i++] = '-'; - s[i++] = swz[GET_SWZ(swizzle, 2)]; - - if (extended) { - s[i++] = ','; - } - - if (negateMask & NEGATE_W) - s[i++] = '-'; - s[i++] = swz[GET_SWZ(swizzle, 3)]; - - s[i] = 0; - return s; -} - - -void -_mesa_print_swizzle(GLuint swizzle) -{ - if (swizzle == SWIZZLE_XYZW) { - printf(".xyzw\n"); - } - else { - const char *s = _mesa_swizzle_string(swizzle, 0, 0); - printf("%s\n", s); - } -} - - -const char * -_mesa_writemask_string(GLuint writeMask) -{ - static char s[10]; - GLuint i = 0; - - if (writeMask == WRITEMASK_XYZW) - return ""; - - s[i++] = '.'; - if (writeMask & WRITEMASK_X) - s[i++] = 'x'; - if (writeMask & WRITEMASK_Y) - s[i++] = 'y'; - if (writeMask & WRITEMASK_Z) - s[i++] = 'z'; - if (writeMask & WRITEMASK_W) - s[i++] = 'w'; - - s[i] = 0; - return s; -} - - -const char * -_mesa_condcode_string(GLuint condcode) -{ - switch (condcode) { - case COND_GT: return "GT"; - case COND_EQ: return "EQ"; - case COND_LT: return "LT"; - case COND_UN: return "UN"; - case COND_GE: return "GE"; - case COND_LE: return "LE"; - case COND_NE: return "NE"; - case COND_TR: return "TR"; - case COND_FL: return "FL"; - default: return "cond???"; - } -} - - -static void -fprint_dst_reg(FILE * f, - const struct prog_dst_register *dstReg, - gl_prog_print_mode mode, - const struct gl_program *prog) -{ - fprintf(f, "%s%s", - reg_string((gl_register_file) dstReg->File, - dstReg->Index, mode, dstReg->RelAddr, prog), - _mesa_writemask_string(dstReg->WriteMask)); - - if (dstReg->CondMask != COND_TR) { - fprintf(f, " (%s.%s)", - _mesa_condcode_string(dstReg->CondMask), - _mesa_swizzle_string(dstReg->CondSwizzle, - GL_FALSE, GL_FALSE)); - } - -#if 0 - fprintf(f, "%s[%d]%s", - file_string((gl_register_file) dstReg->File, mode), - dstReg->Index, - _mesa_writemask_string(dstReg->WriteMask)); -#endif -} - - -static void -fprint_src_reg(FILE *f, - const struct prog_src_register *srcReg, - gl_prog_print_mode mode, - const struct gl_program *prog) -{ - const char *abs = srcReg->Abs ? "|" : ""; - - fprintf(f, "%s%s%s%s", - abs, - reg_string((gl_register_file) srcReg->File, - srcReg->Index, mode, srcReg->RelAddr, prog), - _mesa_swizzle_string(srcReg->Swizzle, - srcReg->Negate, GL_FALSE), - abs); -#if 0 - fprintf(f, "%s[%d]%s", - file_string((gl_register_file) srcReg->File, mode), - srcReg->Index, - _mesa_swizzle_string(srcReg->Swizzle, - srcReg->Negate, GL_FALSE)); -#endif -} - - -static void -fprint_comment(FILE *f, const struct prog_instruction *inst) -{ - if (inst->Comment) - fprintf(f, "; # %s\n", inst->Comment); - else - fprintf(f, ";\n"); -} - - -static void -fprint_alu_instruction(FILE *f, - const struct prog_instruction *inst, - const char *opcode_string, GLuint numRegs, - gl_prog_print_mode mode, - const struct gl_program *prog) -{ - GLuint j; - - fprintf(f, "%s", opcode_string); - if (inst->CondUpdate) - fprintf(f, ".C"); - - /* frag prog only */ - if (inst->SaturateMode == SATURATE_ZERO_ONE) - fprintf(f, "_SAT"); - - fprintf(f, " "); - if (inst->DstReg.File != PROGRAM_UNDEFINED) { - fprint_dst_reg(f, &inst->DstReg, mode, prog); - } - else { - fprintf(f, " ???"); - } - - if (numRegs > 0) - fprintf(f, ", "); - - for (j = 0; j < numRegs; j++) { - fprint_src_reg(f, inst->SrcReg + j, mode, prog); - if (j + 1 < numRegs) - fprintf(f, ", "); - } - - fprint_comment(f, inst); -} - - -void -_mesa_print_alu_instruction(const struct prog_instruction *inst, - const char *opcode_string, GLuint numRegs) -{ - fprint_alu_instruction(stderr, inst, opcode_string, - numRegs, PROG_PRINT_DEBUG, NULL); -} - - -/** - * Print a single vertex/fragment program instruction. - */ -GLint -_mesa_fprint_instruction_opt(FILE *f, - const struct prog_instruction *inst, - GLint indent, - gl_prog_print_mode mode, - const struct gl_program *prog) -{ - GLint i; - - if (inst->Opcode == OPCODE_ELSE || - inst->Opcode == OPCODE_ENDIF || - inst->Opcode == OPCODE_ENDLOOP || - inst->Opcode == OPCODE_ENDSUB) { - indent -= 3; - } - for (i = 0; i < indent; i++) { - fprintf(f, " "); - } - - switch (inst->Opcode) { - case OPCODE_PRINT: - fprintf(f, "PRINT '%s'", (char *) inst->Data); - if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { - fprintf(f, ", "); - fprintf(f, "%s[%d]%s", - file_string((gl_register_file) inst->SrcReg[0].File, - mode), - inst->SrcReg[0].Index, - _mesa_swizzle_string(inst->SrcReg[0].Swizzle, - inst->SrcReg[0].Negate, GL_FALSE)); - } - if (inst->Comment) - fprintf(f, " # %s", inst->Comment); - fprint_comment(f, inst); - break; - case OPCODE_SWZ: - fprintf(f, "SWZ"); - if (inst->SaturateMode == SATURATE_ZERO_ONE) - fprintf(f, "_SAT"); - fprintf(f, " "); - fprint_dst_reg(f, &inst->DstReg, mode, prog); - fprintf(f, ", %s[%d], %s", - file_string((gl_register_file) inst->SrcReg[0].File, - mode), - inst->SrcReg[0].Index, - _mesa_swizzle_string(inst->SrcReg[0].Swizzle, - inst->SrcReg[0].Negate, GL_TRUE)); - fprint_comment(f, inst); - break; - case OPCODE_TEX: - case OPCODE_TXP: - case OPCODE_TXL: - case OPCODE_TXB: - fprintf(f, "%s", _mesa_opcode_string(inst->Opcode)); - if (inst->SaturateMode == SATURATE_ZERO_ONE) - fprintf(f, "_SAT"); - fprintf(f, " "); - fprint_dst_reg(f, &inst->DstReg, mode, prog); - fprintf(f, ", "); - fprint_src_reg(f, &inst->SrcReg[0], mode, prog); - fprintf(f, ", texture[%d], ", inst->TexSrcUnit); - switch (inst->TexSrcTarget) { - case TEXTURE_1D_INDEX: fprintf(f, "1D"); break; - case TEXTURE_2D_INDEX: fprintf(f, "2D"); break; - case TEXTURE_3D_INDEX: fprintf(f, "3D"); break; - case TEXTURE_CUBE_INDEX: fprintf(f, "CUBE"); break; - case TEXTURE_RECT_INDEX: fprintf(f, "RECT"); break; - case TEXTURE_1D_ARRAY_INDEX: fprintf(f, "1D_ARRAY"); break; - case TEXTURE_2D_ARRAY_INDEX: fprintf(f, "2D_ARRAY"); break; - default: - ; - } - if (inst->TexShadow) - fprintf(f, " SHADOW"); - fprint_comment(f, inst); - break; - - case OPCODE_KIL: - fprintf(f, "%s", _mesa_opcode_string(inst->Opcode)); - fprintf(f, " "); - fprint_src_reg(f, &inst->SrcReg[0], mode, prog); - fprint_comment(f, inst); - break; - case OPCODE_KIL_NV: - fprintf(f, "%s", _mesa_opcode_string(inst->Opcode)); - fprintf(f, " "); - fprintf(f, "%s.%s", - _mesa_condcode_string(inst->DstReg.CondMask), - _mesa_swizzle_string(inst->DstReg.CondSwizzle, - GL_FALSE, GL_FALSE)); - fprint_comment(f, inst); - break; - - case OPCODE_ARL: - fprintf(f, "ARL "); - fprint_dst_reg(f, &inst->DstReg, mode, prog); - fprintf(f, ", "); - fprint_src_reg(f, &inst->SrcReg[0], mode, prog); - fprint_comment(f, inst); - break; - case OPCODE_BRA: - fprintf(f, "BRA %d (%s%s)", - inst->BranchTarget, - _mesa_condcode_string(inst->DstReg.CondMask), - _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE)); - fprint_comment(f, inst); - break; - case OPCODE_IF: - if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { - /* Use ordinary register */ - fprintf(f, "IF "); - fprint_src_reg(f, &inst->SrcReg[0], mode, prog); - fprintf(f, "; "); - } - else { - /* Use cond codes */ - fprintf(f, "IF (%s%s);", - _mesa_condcode_string(inst->DstReg.CondMask), - _mesa_swizzle_string(inst->DstReg.CondSwizzle, - 0, GL_FALSE)); - } - fprintf(f, " # (if false, goto %d)", inst->BranchTarget); - fprint_comment(f, inst); - return indent + 3; - case OPCODE_ELSE: - fprintf(f, "ELSE; # (goto %d)\n", inst->BranchTarget); - return indent + 3; - case OPCODE_ENDIF: - fprintf(f, "ENDIF;\n"); - break; - case OPCODE_BGNLOOP: - fprintf(f, "BGNLOOP; # (end at %d)\n", inst->BranchTarget); - return indent + 3; - case OPCODE_ENDLOOP: - fprintf(f, "ENDLOOP; # (goto %d)\n", inst->BranchTarget); - break; - case OPCODE_BRK: - case OPCODE_CONT: - fprintf(f, "%s (%s%s); # (goto %d)", - _mesa_opcode_string(inst->Opcode), - _mesa_condcode_string(inst->DstReg.CondMask), - _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE), - inst->BranchTarget); - fprint_comment(f, inst); - break; - - case OPCODE_BGNSUB: - if (mode == PROG_PRINT_NV) { - fprintf(f, "%s:\n", inst->Comment); /* comment is label */ - return indent; - } - else { - fprintf(f, "BGNSUB"); - fprint_comment(f, inst); - return indent + 3; - } - case OPCODE_ENDSUB: - if (mode == PROG_PRINT_DEBUG) { - fprintf(f, "ENDSUB"); - fprint_comment(f, inst); - } - break; - case OPCODE_CAL: - if (mode == PROG_PRINT_NV) { - fprintf(f, "CAL %s; # (goto %d)\n", inst->Comment, inst->BranchTarget); - } - else { - fprintf(f, "CAL %u", inst->BranchTarget); - fprint_comment(f, inst); - } - break; - case OPCODE_RET: - fprintf(f, "RET (%s%s)", - _mesa_condcode_string(inst->DstReg.CondMask), - _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE)); - fprint_comment(f, inst); - break; - - case OPCODE_END: - fprintf(f, "END\n"); - break; - case OPCODE_NOP: - if (mode == PROG_PRINT_DEBUG) { - fprintf(f, "NOP"); - fprint_comment(f, inst); - } - else if (inst->Comment) { - /* ARB/NV extensions don't have NOP instruction */ - fprintf(f, "# %s\n", inst->Comment); - } - break; - /* XXX may need other special-case instructions */ - default: - if (inst->Opcode < MAX_OPCODE) { - /* typical alu instruction */ - fprint_alu_instruction(f, inst, - _mesa_opcode_string(inst->Opcode), - _mesa_num_inst_src_regs(inst->Opcode), - mode, prog); - } - else { - fprint_alu_instruction(f, inst, - _mesa_opcode_string(inst->Opcode), - 3/*_mesa_num_inst_src_regs(inst->Opcode)*/, - mode, prog); - } - break; - } - return indent; -} - - -GLint -_mesa_print_instruction_opt(const struct prog_instruction *inst, - GLint indent, - gl_prog_print_mode mode, - const struct gl_program *prog) -{ - return _mesa_fprint_instruction_opt(stderr, inst, indent, mode, prog); -} - - -void -_mesa_print_instruction(const struct prog_instruction *inst) -{ - /* note: 4th param should be ignored for PROG_PRINT_DEBUG */ - _mesa_fprint_instruction_opt(stderr, inst, 0, PROG_PRINT_DEBUG, NULL); -} - - - -/** - * Print program, with options. - */ -void -_mesa_fprint_program_opt(FILE *f, - const struct gl_program *prog, - gl_prog_print_mode mode, - GLboolean lineNumbers) -{ - GLuint i, indent = 0; - - switch (prog->Target) { - case GL_VERTEX_PROGRAM_ARB: - if (mode == PROG_PRINT_ARB) - fprintf(f, "!!ARBvp1.0\n"); - else if (mode == PROG_PRINT_NV) - fprintf(f, "!!VP1.0\n"); - else - fprintf(f, "# Vertex Program/Shader %u\n", prog->Id); - break; - case GL_FRAGMENT_PROGRAM_ARB: - case GL_FRAGMENT_PROGRAM_NV: - if (mode == PROG_PRINT_ARB) - fprintf(f, "!!ARBfp1.0\n"); - else if (mode == PROG_PRINT_NV) - fprintf(f, "!!FP1.0\n"); - else - fprintf(f, "# Fragment Program/Shader %u\n", prog->Id); - break; - } - - for (i = 0; i < prog->NumInstructions; i++) { - if (lineNumbers) - fprintf(f, "%3d: ", i); - indent = _mesa_fprint_instruction_opt(f, prog->Instructions + i, - indent, mode, prog); - } -} - - -/** - * Print program to stderr, default options. - */ -void -_mesa_print_program(const struct gl_program *prog) -{ - _mesa_fprint_program_opt(stderr, prog, PROG_PRINT_DEBUG, GL_TRUE); -} - - -/** - * Return binary representation of 64-bit value (as a string). - * Insert a comma to separate each group of 8 bits. - * Note we return a pointer to local static storage so this is not - * re-entrant, etc. - * XXX move to imports.[ch] if useful elsewhere. - */ -static const char * -binary(GLbitfield64 val) -{ - static char buf[80]; - GLint i, len = 0; - for (i = 63; i >= 0; --i) { - if (val & (BITFIELD64_BIT(i))) - buf[len++] = '1'; - else if (len > 0 || i == 0) - buf[len++] = '0'; - if (len > 0 && ((i-1) % 8) == 7) - buf[len++] = ','; - } - buf[len] = '\0'; - return buf; -} - - -/** - * Print all of a program's parameters/fields to given file. - */ -static void -_mesa_fprint_program_parameters(FILE *f, - GLcontext *ctx, - const struct gl_program *prog) -{ - GLuint i; - - fprintf(f, "InputsRead: 0x%x (0b%s)\n", - prog->InputsRead, binary(prog->InputsRead)); - fprintf(f, "OutputsWritten: 0x%llx (0b%s)\n", - prog->OutputsWritten, binary(prog->OutputsWritten)); - fprintf(f, "NumInstructions=%d\n", prog->NumInstructions); - fprintf(f, "NumTemporaries=%d\n", prog->NumTemporaries); - fprintf(f, "NumParameters=%d\n", prog->NumParameters); - fprintf(f, "NumAttributes=%d\n", prog->NumAttributes); - fprintf(f, "NumAddressRegs=%d\n", prog->NumAddressRegs); - fprintf(f, "SamplersUsed: 0x%x (0b%s)\n", - prog->SamplersUsed, binary(prog->SamplersUsed)); - fprintf(f, "Samplers=[ "); - for (i = 0; i < MAX_SAMPLERS; i++) { - fprintf(f, "%d ", prog->SamplerUnits[i]); - } - fprintf(f, "]\n"); - - _mesa_load_state_parameters(ctx, prog->Parameters); - -#if 0 - fprintf(f, "Local Params:\n"); - for (i = 0; i < MAX_PROGRAM_LOCAL_PARAMS; i++){ - const GLfloat *p = prog->LocalParams[i]; - fprintf(f, "%2d: %f, %f, %f, %f\n", i, p[0], p[1], p[2], p[3]); - } -#endif - _mesa_print_parameter_list(prog->Parameters); -} - - -/** - * Print all of a program's parameters/fields to stderr. - */ -void -_mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog) -{ - _mesa_fprint_program_parameters(stderr, ctx, prog); -} - - -/** - * Print a program parameter list to given file. - */ -static void -_mesa_fprint_parameter_list(FILE *f, - const struct gl_program_parameter_list *list) -{ - const gl_prog_print_mode mode = PROG_PRINT_DEBUG; - GLuint i; - - if (!list) - return; - - if (0) - fprintf(f, "param list %p\n", (void *) list); - fprintf(f, "dirty state flags: 0x%x\n", list->StateFlags); - for (i = 0; i < list->NumParameters; i++){ - struct gl_program_parameter *param = list->Parameters + i; - const GLfloat *v = list->ParameterValues[i]; - fprintf(f, "param[%d] sz=%d %s %s = {%.3g, %.3g, %.3g, %.3g}", - i, param->Size, - file_string(list->Parameters[i].Type, mode), - param->Name, v[0], v[1], v[2], v[3]); - if (param->Flags & PROG_PARAM_BIT_CENTROID) - fprintf(f, " Centroid"); - if (param->Flags & PROG_PARAM_BIT_INVARIANT) - fprintf(f, " Invariant"); - if (param->Flags & PROG_PARAM_BIT_FLAT) - fprintf(f, " Flat"); - if (param->Flags & PROG_PARAM_BIT_LINEAR) - fprintf(f, " Linear"); - fprintf(f, "\n"); - } -} - - -/** - * Print a program parameter list to stderr. - */ -void -_mesa_print_parameter_list(const struct gl_program_parameter_list *list) -{ - _mesa_fprint_parameter_list(stderr, list); -} - - -/** - * Write shader and associated info to a file. - */ -void -_mesa_write_shader_to_file(const struct gl_shader *shader) -{ - const char *type; - char filename[100]; - FILE *f; - - if (shader->Type == GL_FRAGMENT_SHADER) - type = "frag"; - else - type = "vert"; - - _mesa_snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type); - f = fopen(filename, "w"); - if (!f) { - fprintf(stderr, "Unable to open %s for writing\n", filename); - return; - } - - fprintf(f, "/* Shader %u source, checksum %u */\n", shader->Name, shader->SourceChecksum); - fputs(shader->Source, f); - fprintf(f, "\n"); - - fprintf(f, "/* Compile status: %s */\n", - shader->CompileStatus ? "ok" : "fail"); - if (!shader->CompileStatus) { - fprintf(f, "/* Log Info: */\n"); - fputs(shader->InfoLog, f); - } - else { - fprintf(f, "/* GPU code */\n"); - fprintf(f, "/*\n"); - _mesa_fprint_program_opt(f, shader->Program, PROG_PRINT_DEBUG, GL_TRUE); - fprintf(f, "*/\n"); - fprintf(f, "/* Parameters / constants */\n"); - fprintf(f, "/*\n"); - _mesa_fprint_parameter_list(f, shader->Program->Parameters); - fprintf(f, "*/\n"); - } - - fclose(f); -} - - -/** - * Append the shader's uniform info/values to the shader log file. - * The log file will typically have been created by the - * _mesa_write_shader_to_file function. - */ -void -_mesa_append_uniforms_to_file(const struct gl_shader *shader, - const struct gl_program *prog) -{ - const char *type; - char filename[100]; - FILE *f; - - if (shader->Type == GL_FRAGMENT_SHADER) - type = "frag"; - else - type = "vert"; - - _mesa_snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type); - f = fopen(filename, "a"); /* append */ - if (!f) { - fprintf(stderr, "Unable to open %s for appending\n", filename); - return; - } - - fprintf(f, "/* First-draw parameters / constants */\n"); - fprintf(f, "/*\n"); - _mesa_fprint_parameter_list(f, prog->Parameters); - fprintf(f, "*/\n"); - - fclose(f); -} diff --git a/src/mesa/shader/prog_print.h b/src/mesa/shader/prog_print.h deleted file mode 100644 index 9ab7456016..0000000000 --- a/src/mesa/shader/prog_print.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#ifndef PROG_PRINT_H -#define PROG_PRINT_H - - -/** - * The output style to use when printing programs. - */ -typedef enum { - PROG_PRINT_ARB, - PROG_PRINT_NV, - PROG_PRINT_DEBUG -} gl_prog_print_mode; - - -extern void -_mesa_print_vp_inputs(GLbitfield inputs); - -extern void -_mesa_print_fp_inputs(GLbitfield inputs); - -extern const char * -_mesa_condcode_string(GLuint condcode); - -extern const char * -_mesa_swizzle_string(GLuint swizzle, GLuint negateBase, GLboolean extended); - -const char * -_mesa_writemask_string(GLuint writeMask); - -extern void -_mesa_print_swizzle(GLuint swizzle); - -extern void -_mesa_print_alu_instruction(const struct prog_instruction *inst, - const char *opcode_string, GLuint numRegs); - -extern void -_mesa_print_instruction(const struct prog_instruction *inst); - -extern GLint -_mesa_fprint_instruction_opt(FILE *f, - const struct prog_instruction *inst, - GLint indent, - gl_prog_print_mode mode, - const struct gl_program *prog); - -extern GLint -_mesa_print_instruction_opt(const struct prog_instruction *inst, GLint indent, - gl_prog_print_mode mode, - const struct gl_program *prog); - -extern void -_mesa_print_program(const struct gl_program *prog); - -extern void -_mesa_fprint_program_opt(FILE *f, - const struct gl_program *prog, gl_prog_print_mode mode, - GLboolean lineNumbers); - -extern void -_mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog); - -extern void -_mesa_print_parameter_list(const struct gl_program_parameter_list *list); - - -extern void -_mesa_write_shader_to_file(const struct gl_shader *shader); - -extern void -_mesa_append_uniforms_to_file(const struct gl_shader *shader, - const struct gl_program *prog); - - -#endif /* PROG_PRINT_H */ diff --git a/src/mesa/shader/prog_statevars.c b/src/mesa/shader/prog_statevars.c deleted file mode 100644 index ead3ece95d..0000000000 --- a/src/mesa/shader/prog_statevars.c +++ /dev/null @@ -1,1187 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file prog_statevars.c - * Program state variable management. - * \author Brian Paul - */ - - -#include "main/glheader.h" -#include "main/context.h" -#include "main/imports.h" -#include "main/macros.h" -#include "main/mtypes.h" -#include "prog_statevars.h" -#include "prog_parameter.h" - - -/** - * Use the list of tokens in the state[] array to find global GL state - * and return it in . Usually, four values are returned in - * but matrix queries may return as many as 16 values. - * This function is used for ARB vertex/fragment programs. - * The program parser will produce the state[] values. - */ -static void -_mesa_fetch_state(GLcontext *ctx, const gl_state_index state[], - GLfloat *value) -{ - switch (state[0]) { - case STATE_MATERIAL: - { - /* state[1] is either 0=front or 1=back side */ - const GLuint face = (GLuint) state[1]; - const struct gl_material *mat = &ctx->Light.Material; - ASSERT(face == 0 || face == 1); - /* we rely on tokens numbered so that _BACK_ == _FRONT_+ 1 */ - ASSERT(MAT_ATTRIB_FRONT_AMBIENT + 1 == MAT_ATTRIB_BACK_AMBIENT); - /* XXX we could get rid of this switch entirely with a little - * work in arbprogparse.c's parse_state_single_item(). - */ - /* state[2] is the material attribute */ - switch (state[2]) { - case STATE_AMBIENT: - COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_AMBIENT + face]); - return; - case STATE_DIFFUSE: - COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_DIFFUSE + face]); - return; - case STATE_SPECULAR: - COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_SPECULAR + face]); - return; - case STATE_EMISSION: - COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_EMISSION + face]); - return; - case STATE_SHININESS: - value[0] = mat->Attrib[MAT_ATTRIB_FRONT_SHININESS + face][0]; - value[1] = 0.0F; - value[2] = 0.0F; - value[3] = 1.0F; - return; - default: - _mesa_problem(ctx, "Invalid material state in fetch_state"); - return; - } - } - case STATE_LIGHT: - { - /* state[1] is the light number */ - const GLuint ln = (GLuint) state[1]; - /* state[2] is the light attribute */ - switch (state[2]) { - case STATE_AMBIENT: - COPY_4V(value, ctx->Light.Light[ln].Ambient); - return; - case STATE_DIFFUSE: - COPY_4V(value, ctx->Light.Light[ln].Diffuse); - return; - case STATE_SPECULAR: - COPY_4V(value, ctx->Light.Light[ln].Specular); - return; - case STATE_POSITION: - COPY_4V(value, ctx->Light.Light[ln].EyePosition); - return; - case STATE_ATTENUATION: - value[0] = ctx->Light.Light[ln].ConstantAttenuation; - value[1] = ctx->Light.Light[ln].LinearAttenuation; - value[2] = ctx->Light.Light[ln].QuadraticAttenuation; - value[3] = ctx->Light.Light[ln].SpotExponent; - return; - case STATE_SPOT_DIRECTION: - COPY_3V(value, ctx->Light.Light[ln].SpotDirection); - value[3] = ctx->Light.Light[ln]._CosCutoff; - return; - case STATE_SPOT_CUTOFF: - value[0] = ctx->Light.Light[ln].SpotCutoff; - return; - case STATE_HALF_VECTOR: - { - static const GLfloat eye_z[] = {0, 0, 1}; - GLfloat p[3]; - /* Compute infinite half angle vector: - * halfVector = normalize(normalize(lightPos) + (0, 0, 1)) - * light.EyePosition.w should be 0 for infinite lights. - */ - COPY_3V(p, ctx->Light.Light[ln].EyePosition); - NORMALIZE_3FV(p); - ADD_3V(value, p, eye_z); - NORMALIZE_3FV(value); - value[3] = 1.0; - } - return; - default: - _mesa_problem(ctx, "Invalid light state in fetch_state"); - return; - } - } - case STATE_LIGHTMODEL_AMBIENT: - COPY_4V(value, ctx->Light.Model.Ambient); - return; - case STATE_LIGHTMODEL_SCENECOLOR: - if (state[1] == 0) { - /* front */ - GLint i; - for (i = 0; i < 3; i++) { - value[i] = ctx->Light.Model.Ambient[i] - * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT][i] - + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION][i]; - } - value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3]; - } - else { - /* back */ - GLint i; - for (i = 0; i < 3; i++) { - value[i] = ctx->Light.Model.Ambient[i] - * ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT][i] - + ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION][i]; - } - value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3]; - } - return; - case STATE_LIGHTPROD: - { - const GLuint ln = (GLuint) state[1]; - const GLuint face = (GLuint) state[2]; - GLint i; - ASSERT(face == 0 || face == 1); - switch (state[3]) { - case STATE_AMBIENT: - for (i = 0; i < 3; i++) { - value[i] = ctx->Light.Light[ln].Ambient[i] * - ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][i]; - } - /* [3] = material alpha */ - value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][3]; - return; - case STATE_DIFFUSE: - for (i = 0; i < 3; i++) { - value[i] = ctx->Light.Light[ln].Diffuse[i] * - ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][i]; - } - /* [3] = material alpha */ - value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3]; - return; - case STATE_SPECULAR: - for (i = 0; i < 3; i++) { - value[i] = ctx->Light.Light[ln].Specular[i] * - ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][i]; - } - /* [3] = material alpha */ - value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][3]; - return; - default: - _mesa_problem(ctx, "Invalid lightprod state in fetch_state"); - return; - } - } - case STATE_TEXGEN: - { - /* state[1] is the texture unit */ - const GLuint unit = (GLuint) state[1]; - /* state[2] is the texgen attribute */ - switch (state[2]) { - case STATE_TEXGEN_EYE_S: - COPY_4V(value, ctx->Texture.Unit[unit].GenS.EyePlane); - return; - case STATE_TEXGEN_EYE_T: - COPY_4V(value, ctx->Texture.Unit[unit].GenT.EyePlane); - return; - case STATE_TEXGEN_EYE_R: - COPY_4V(value, ctx->Texture.Unit[unit].GenR.EyePlane); - return; - case STATE_TEXGEN_EYE_Q: - COPY_4V(value, ctx->Texture.Unit[unit].GenQ.EyePlane); - return; - case STATE_TEXGEN_OBJECT_S: - COPY_4V(value, ctx->Texture.Unit[unit].GenS.ObjectPlane); - return; - case STATE_TEXGEN_OBJECT_T: - COPY_4V(value, ctx->Texture.Unit[unit].GenT.ObjectPlane); - return; - case STATE_TEXGEN_OBJECT_R: - COPY_4V(value, ctx->Texture.Unit[unit].GenR.ObjectPlane); - return; - case STATE_TEXGEN_OBJECT_Q: - COPY_4V(value, ctx->Texture.Unit[unit].GenQ.ObjectPlane); - return; - default: - _mesa_problem(ctx, "Invalid texgen state in fetch_state"); - return; - } - } - case STATE_TEXENV_COLOR: - { - /* state[1] is the texture unit */ - const GLuint unit = (GLuint) state[1]; - COPY_4V(value, ctx->Texture.Unit[unit].EnvColor); - } - return; - case STATE_FOG_COLOR: - COPY_4V(value, ctx->Fog.Color); - return; - case STATE_FOG_PARAMS: - value[0] = ctx->Fog.Density; - value[1] = ctx->Fog.Start; - value[2] = ctx->Fog.End; - value[3] = (ctx->Fog.End == ctx->Fog.Start) - ? 1.0f : (GLfloat)(1.0 / (ctx->Fog.End - ctx->Fog.Start)); - return; - case STATE_CLIPPLANE: - { - const GLuint plane = (GLuint) state[1]; - COPY_4V(value, ctx->Transform.EyeUserPlane[plane]); - } - return; - case STATE_POINT_SIZE: - value[0] = ctx->Point.Size; - value[1] = ctx->Point.MinSize; - value[2] = ctx->Point.MaxSize; - value[3] = ctx->Point.Threshold; - return; - case STATE_POINT_ATTENUATION: - value[0] = ctx->Point.Params[0]; - value[1] = ctx->Point.Params[1]; - value[2] = ctx->Point.Params[2]; - value[3] = 1.0F; - return; - case STATE_MODELVIEW_MATRIX: - case STATE_PROJECTION_MATRIX: - case STATE_MVP_MATRIX: - case STATE_TEXTURE_MATRIX: - case STATE_PROGRAM_MATRIX: - case STATE_COLOR_MATRIX: - { - /* state[0] = modelview, projection, texture, etc. */ - /* state[1] = which texture matrix or program matrix */ - /* state[2] = first row to fetch */ - /* state[3] = last row to fetch */ - /* state[4] = transpose, inverse or invtrans */ - const GLmatrix *matrix; - const gl_state_index mat = state[0]; - const GLuint index = (GLuint) state[1]; - const GLuint firstRow = (GLuint) state[2]; - const GLuint lastRow = (GLuint) state[3]; - const gl_state_index modifier = state[4]; - const GLfloat *m; - GLuint row, i; - ASSERT(firstRow >= 0); - ASSERT(firstRow < 4); - ASSERT(lastRow >= 0); - ASSERT(lastRow < 4); - if (mat == STATE_MODELVIEW_MATRIX) { - matrix = ctx->ModelviewMatrixStack.Top; - } - else if (mat == STATE_PROJECTION_MATRIX) { - matrix = ctx->ProjectionMatrixStack.Top; - } - else if (mat == STATE_MVP_MATRIX) { - matrix = &ctx->_ModelProjectMatrix; - } - else if (mat == STATE_TEXTURE_MATRIX) { - ASSERT(index < Elements(ctx->TextureMatrixStack)); - matrix = ctx->TextureMatrixStack[index].Top; - } - else if (mat == STATE_PROGRAM_MATRIX) { - ASSERT(index < Elements(ctx->ProgramMatrixStack)); - matrix = ctx->ProgramMatrixStack[index].Top; - } - else if (mat == STATE_COLOR_MATRIX) { - matrix = ctx->ColorMatrixStack.Top; - } - else { - _mesa_problem(ctx, "Bad matrix name in _mesa_fetch_state()"); - return; - } - if (modifier == STATE_MATRIX_INVERSE || - modifier == STATE_MATRIX_INVTRANS) { - /* Be sure inverse is up to date: - */ - _math_matrix_alloc_inv( (GLmatrix *) matrix ); - _math_matrix_analyse( (GLmatrix*) matrix ); - m = matrix->inv; - } - else { - m = matrix->m; - } - if (modifier == STATE_MATRIX_TRANSPOSE || - modifier == STATE_MATRIX_INVTRANS) { - for (i = 0, row = firstRow; row <= lastRow; row++) { - value[i++] = m[row * 4 + 0]; - value[i++] = m[row * 4 + 1]; - value[i++] = m[row * 4 + 2]; - value[i++] = m[row * 4 + 3]; - } - } - else { - for (i = 0, row = firstRow; row <= lastRow; row++) { - value[i++] = m[row + 0]; - value[i++] = m[row + 4]; - value[i++] = m[row + 8]; - value[i++] = m[row + 12]; - } - } - } - return; - case STATE_DEPTH_RANGE: - value[0] = ctx->Viewport.Near; /* near */ - value[1] = ctx->Viewport.Far; /* far */ - value[2] = ctx->Viewport.Far - ctx->Viewport.Near; /* far - near */ - value[3] = 1.0; - return; - case STATE_FRAGMENT_PROGRAM: - { - /* state[1] = {STATE_ENV, STATE_LOCAL} */ - /* state[2] = parameter index */ - const int idx = (int) state[2]; - switch (state[1]) { - case STATE_ENV: - COPY_4V(value, ctx->FragmentProgram.Parameters[idx]); - return; - case STATE_LOCAL: - COPY_4V(value, ctx->FragmentProgram.Current->Base.LocalParams[idx]); - return; - default: - _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()"); - return; - } - } - return; - - case STATE_VERTEX_PROGRAM: - { - /* state[1] = {STATE_ENV, STATE_LOCAL} */ - /* state[2] = parameter index */ - const int idx = (int) state[2]; - switch (state[1]) { - case STATE_ENV: - COPY_4V(value, ctx->VertexProgram.Parameters[idx]); - return; - case STATE_LOCAL: - COPY_4V(value, ctx->VertexProgram.Current->Base.LocalParams[idx]); - return; - default: - _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()"); - return; - } - } - return; - - case STATE_NORMAL_SCALE: - ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1); - return; - - case STATE_INTERNAL: - switch (state[1]) { - case STATE_CURRENT_ATTRIB: - { - const GLuint idx = (GLuint) state[2]; - COPY_4V(value, ctx->Current.Attrib[idx]); - } - return; - - case STATE_NORMAL_SCALE: - ASSIGN_4V(value, - ctx->_ModelViewInvScale, - ctx->_ModelViewInvScale, - ctx->_ModelViewInvScale, - 1); - return; - - case STATE_TEXRECT_SCALE: - /* Value = { 1/texWidth, 1/texHeight, 0, 1 }. - * Used to convert unnormalized texcoords to normalized texcoords. - */ - { - const int unit = (int) state[2]; - const struct gl_texture_object *texObj - = ctx->Texture.Unit[unit]._Current; - if (texObj) { - struct gl_texture_image *texImage = texObj->Image[0][0]; - ASSIGN_4V(value, - (GLfloat) (1.0 / texImage->Width), - (GLfloat) (1.0 / texImage->Height), - 0.0f, 1.0f); - } - } - return; - - case STATE_FOG_PARAMS_OPTIMIZED: - /* for simpler per-vertex/pixel fog calcs. POW (for EXP/EXP2 fog) - * might be more expensive than EX2 on some hw, plus it needs - * another constant (e) anyway. Linear fog can now be done with a - * single MAD. - * linear: fogcoord * -1/(end-start) + end/(end-start) - * exp: 2^-(density/ln(2) * fogcoord) - * exp2: 2^-((density/(ln(2)^2) * fogcoord)^2) - */ - value[0] = (ctx->Fog.End == ctx->Fog.Start) - ? 1.0f : (GLfloat)(-1.0F / (ctx->Fog.End - ctx->Fog.Start)); - value[1] = ctx->Fog.End * -value[0]; - value[2] = (GLfloat)(ctx->Fog.Density * ONE_DIV_LN2); - value[3] = (GLfloat)(ctx->Fog.Density * ONE_DIV_SQRT_LN2); - return; - - case STATE_POINT_SIZE_CLAMPED: - { - /* this includes implementation dependent limits, to avoid - * another potentially necessary clamp. - * Note: for sprites, point smooth (point AA) is ignored - * and we'll clamp to MinPointSizeAA and MaxPointSize, because we - * expect drivers will want to say their minimum for AA size is 0.0 - * but for non-AA it's 1.0 (because normal points with size below 1.0 - * need to get rounded up to 1.0, hence never disappear). GL does - * not specify max clamp size for sprites, other than it needs to be - * at least as large as max AA size, hence use non-AA size there. - */ - GLfloat minImplSize; - GLfloat maxImplSize; - if (ctx->Point.PointSprite) { - minImplSize = ctx->Const.MinPointSizeAA; - maxImplSize = ctx->Const.MaxPointSize; - } - else if (ctx->Point.SmoothFlag || ctx->Multisample._Enabled) { - minImplSize = ctx->Const.MinPointSizeAA; - maxImplSize = ctx->Const.MaxPointSizeAA; - } - else { - minImplSize = ctx->Const.MinPointSize; - maxImplSize = ctx->Const.MaxPointSize; - } - value[0] = ctx->Point.Size; - value[1] = ctx->Point.MinSize >= minImplSize ? ctx->Point.MinSize : minImplSize; - value[2] = ctx->Point.MaxSize <= maxImplSize ? ctx->Point.MaxSize : maxImplSize; - value[3] = ctx->Point.Threshold; - } - return; - case STATE_POINT_SIZE_IMPL_CLAMP: - { - /* for implementation clamp only in vs */ - GLfloat minImplSize; - GLfloat maxImplSize; - if (ctx->Point.PointSprite) { - minImplSize = ctx->Const.MinPointSizeAA; - maxImplSize = ctx->Const.MaxPointSize; - } - else if (ctx->Point.SmoothFlag || ctx->Multisample._Enabled) { - minImplSize = ctx->Const.MinPointSizeAA; - maxImplSize = ctx->Const.MaxPointSizeAA; - } - else { - minImplSize = ctx->Const.MinPointSize; - maxImplSize = ctx->Const.MaxPointSize; - } - value[0] = ctx->Point.Size; - value[1] = minImplSize; - value[2] = maxImplSize; - value[3] = ctx->Point.Threshold; - } - return; - case STATE_LIGHT_SPOT_DIR_NORMALIZED: - { - /* here, state[2] is the light number */ - /* pre-normalize spot dir */ - const GLuint ln = (GLuint) state[2]; - COPY_3V(value, ctx->Light.Light[ln]._NormSpotDirection); - value[3] = ctx->Light.Light[ln]._CosCutoff; - } - return; - - case STATE_LIGHT_POSITION: - { - const GLuint ln = (GLuint) state[2]; - COPY_4V(value, ctx->Light.Light[ln]._Position); - } - return; - - case STATE_LIGHT_POSITION_NORMALIZED: - { - const GLuint ln = (GLuint) state[2]; - COPY_4V(value, ctx->Light.Light[ln]._Position); - NORMALIZE_3FV( value ); - } - return; - - case STATE_LIGHT_HALF_VECTOR: - { - const GLuint ln = (GLuint) state[2]; - GLfloat p[3]; - /* Compute infinite half angle vector: - * halfVector = normalize(normalize(lightPos) + (0, 0, 1)) - * light.EyePosition.w should be 0 for infinite lights. - */ - COPY_3V(p, ctx->Light.Light[ln]._Position); - NORMALIZE_3FV(p); - ADD_3V(value, p, ctx->_EyeZDir); - NORMALIZE_3FV(value); - value[3] = 1.0; - } - return; - - case STATE_PT_SCALE: - value[0] = ctx->Pixel.RedScale; - value[1] = ctx->Pixel.GreenScale; - value[2] = ctx->Pixel.BlueScale; - value[3] = ctx->Pixel.AlphaScale; - return; - - case STATE_PT_BIAS: - value[0] = ctx->Pixel.RedBias; - value[1] = ctx->Pixel.GreenBias; - value[2] = ctx->Pixel.BlueBias; - value[3] = ctx->Pixel.AlphaBias; - return; - - case STATE_PCM_SCALE: - COPY_4V(value, ctx->Pixel.PostColorMatrixScale); - return; - - case STATE_PCM_BIAS: - COPY_4V(value, ctx->Pixel.PostColorMatrixBias); - return; - - case STATE_SHADOW_AMBIENT: - { - const int unit = (int) state[2]; - const struct gl_texture_object *texObj - = ctx->Texture.Unit[unit]._Current; - if (texObj) { - value[0] = - value[1] = - value[2] = - value[3] = texObj->CompareFailValue; - } - } - return; - - case STATE_FB_SIZE: - value[0] = (GLfloat) (ctx->DrawBuffer->Width - 1); - value[1] = (GLfloat) (ctx->DrawBuffer->Height - 1); - value[2] = 0.0F; - value[3] = 0.0F; - return; - - case STATE_ROT_MATRIX_0: - { - const int unit = (int) state[2]; - GLfloat *rotMat22 = ctx->Texture.Unit[unit].RotMatrix; - value[0] = rotMat22[0]; - value[1] = rotMat22[2]; - value[2] = 0.0; - value[3] = 0.0; - } - return; - - case STATE_ROT_MATRIX_1: - { - const int unit = (int) state[2]; - GLfloat *rotMat22 = ctx->Texture.Unit[unit].RotMatrix; - value[0] = rotMat22[1]; - value[1] = rotMat22[3]; - value[2] = 0.0; - value[3] = 0.0; - } - return; - - /* XXX: make sure new tokens added here are also handled in the - * _mesa_program_state_flags() switch, below. - */ - default: - /* Unknown state indexes are silently ignored here. - * Drivers may do something special. - */ - return; - } - return; - - default: - _mesa_problem(ctx, "Invalid state in _mesa_fetch_state"); - return; - } -} - - -/** - * Return a bitmask of the Mesa state flags (_NEW_* values) which would - * indicate that the given context state may have changed. - * The bitmask is used during validation to determine if we need to update - * vertex/fragment program parameters (like "state.material.color") when - * some GL state has changed. - */ -GLbitfield -_mesa_program_state_flags(const gl_state_index state[STATE_LENGTH]) -{ - switch (state[0]) { - case STATE_MATERIAL: - case STATE_LIGHT: - case STATE_LIGHTMODEL_AMBIENT: - case STATE_LIGHTMODEL_SCENECOLOR: - case STATE_LIGHTPROD: - return _NEW_LIGHT; - - case STATE_TEXGEN: - case STATE_TEXENV_COLOR: - return _NEW_TEXTURE; - - case STATE_FOG_COLOR: - case STATE_FOG_PARAMS: - return _NEW_FOG; - - case STATE_CLIPPLANE: - return _NEW_TRANSFORM; - - case STATE_POINT_SIZE: - case STATE_POINT_ATTENUATION: - return _NEW_POINT; - - case STATE_MODELVIEW_MATRIX: - return _NEW_MODELVIEW; - case STATE_PROJECTION_MATRIX: - return _NEW_PROJECTION; - case STATE_MVP_MATRIX: - return _NEW_MODELVIEW | _NEW_PROJECTION; - case STATE_TEXTURE_MATRIX: - return _NEW_TEXTURE_MATRIX; - case STATE_PROGRAM_MATRIX: - return _NEW_TRACK_MATRIX; - case STATE_COLOR_MATRIX: - return _NEW_COLOR_MATRIX; - - case STATE_DEPTH_RANGE: - return _NEW_VIEWPORT; - - case STATE_FRAGMENT_PROGRAM: - case STATE_VERTEX_PROGRAM: - return _NEW_PROGRAM; - - case STATE_NORMAL_SCALE: - return _NEW_MODELVIEW; - - case STATE_INTERNAL: - switch (state[1]) { - case STATE_CURRENT_ATTRIB: - return _NEW_CURRENT_ATTRIB; - - case STATE_NORMAL_SCALE: - return _NEW_MODELVIEW; - - case STATE_TEXRECT_SCALE: - case STATE_SHADOW_AMBIENT: - case STATE_ROT_MATRIX_0: - case STATE_ROT_MATRIX_1: - return _NEW_TEXTURE; - case STATE_FOG_PARAMS_OPTIMIZED: - return _NEW_FOG; - case STATE_POINT_SIZE_CLAMPED: - case STATE_POINT_SIZE_IMPL_CLAMP: - return _NEW_POINT | _NEW_MULTISAMPLE; - case STATE_LIGHT_SPOT_DIR_NORMALIZED: - case STATE_LIGHT_POSITION: - case STATE_LIGHT_POSITION_NORMALIZED: - case STATE_LIGHT_HALF_VECTOR: - return _NEW_LIGHT; - - case STATE_PT_SCALE: - case STATE_PT_BIAS: - case STATE_PCM_SCALE: - case STATE_PCM_BIAS: - return _NEW_PIXEL; - - case STATE_FB_SIZE: - return _NEW_BUFFERS; - - default: - /* unknown state indexes are silently ignored and - * no flag set, since it is handled by the driver. - */ - return 0; - } - - default: - _mesa_problem(NULL, "unexpected state[0] in make_state_flags()"); - return 0; - } -} - - -static void -append(char *dst, const char *src) -{ - while (*dst) - dst++; - while (*src) - *dst++ = *src++; - *dst = 0; -} - - -/** - * Convert token 'k' to a string, append it onto 'dst' string. - */ -static void -append_token(char *dst, gl_state_index k) -{ - switch (k) { - case STATE_MATERIAL: - append(dst, "material"); - break; - case STATE_LIGHT: - append(dst, "light"); - break; - case STATE_LIGHTMODEL_AMBIENT: - append(dst, "lightmodel.ambient"); - break; - case STATE_LIGHTMODEL_SCENECOLOR: - break; - case STATE_LIGHTPROD: - append(dst, "lightprod"); - break; - case STATE_TEXGEN: - append(dst, "texgen"); - break; - case STATE_FOG_COLOR: - append(dst, "fog.color"); - break; - case STATE_FOG_PARAMS: - append(dst, "fog.params"); - break; - case STATE_CLIPPLANE: - append(dst, "clip"); - break; - case STATE_POINT_SIZE: - append(dst, "point.size"); - break; - case STATE_POINT_ATTENUATION: - append(dst, "point.attenuation"); - break; - case STATE_MODELVIEW_MATRIX: - append(dst, "matrix.modelview"); - break; - case STATE_PROJECTION_MATRIX: - append(dst, "matrix.projection"); - break; - case STATE_MVP_MATRIX: - append(dst, "matrix.mvp"); - break; - case STATE_TEXTURE_MATRIX: - append(dst, "matrix.texture"); - break; - case STATE_PROGRAM_MATRIX: - append(dst, "matrix.program"); - break; - case STATE_COLOR_MATRIX: - append(dst, "matrix.color"); - break; - case STATE_MATRIX_INVERSE: - append(dst, ".inverse"); - break; - case STATE_MATRIX_TRANSPOSE: - append(dst, ".transpose"); - break; - case STATE_MATRIX_INVTRANS: - append(dst, ".invtrans"); - break; - case STATE_AMBIENT: - append(dst, ".ambient"); - break; - case STATE_DIFFUSE: - append(dst, ".diffuse"); - break; - case STATE_SPECULAR: - append(dst, ".specular"); - break; - case STATE_EMISSION: - append(dst, ".emission"); - break; - case STATE_SHININESS: - append(dst, "lshininess"); - break; - case STATE_HALF_VECTOR: - append(dst, ".half"); - break; - case STATE_POSITION: - append(dst, ".position"); - break; - case STATE_ATTENUATION: - append(dst, ".attenuation"); - break; - case STATE_SPOT_DIRECTION: - append(dst, ".spot.direction"); - break; - case STATE_SPOT_CUTOFF: - append(dst, ".spot.cutoff"); - break; - case STATE_TEXGEN_EYE_S: - append(dst, ".eye.s"); - break; - case STATE_TEXGEN_EYE_T: - append(dst, ".eye.t"); - break; - case STATE_TEXGEN_EYE_R: - append(dst, ".eye.r"); - break; - case STATE_TEXGEN_EYE_Q: - append(dst, ".eye.q"); - break; - case STATE_TEXGEN_OBJECT_S: - append(dst, ".object.s"); - break; - case STATE_TEXGEN_OBJECT_T: - append(dst, ".object.t"); - break; - case STATE_TEXGEN_OBJECT_R: - append(dst, ".object.r"); - break; - case STATE_TEXGEN_OBJECT_Q: - append(dst, ".object.q"); - break; - case STATE_TEXENV_COLOR: - append(dst, "texenv"); - break; - case STATE_DEPTH_RANGE: - append(dst, "depth.range"); - break; - case STATE_VERTEX_PROGRAM: - case STATE_FRAGMENT_PROGRAM: - break; - case STATE_ENV: - append(dst, "env"); - break; - case STATE_LOCAL: - append(dst, "local"); - break; - /* BEGIN internal state vars */ - case STATE_INTERNAL: - append(dst, ".internal."); - break; - case STATE_CURRENT_ATTRIB: - append(dst, "current"); - break; - case STATE_NORMAL_SCALE: - append(dst, "normalScale"); - break; - case STATE_TEXRECT_SCALE: - append(dst, "texrectScale"); - break; - case STATE_FOG_PARAMS_OPTIMIZED: - append(dst, "fogParamsOptimized"); - break; - case STATE_POINT_SIZE_CLAMPED: - append(dst, "pointSizeClamped"); - break; - case STATE_POINT_SIZE_IMPL_CLAMP: - append(dst, "pointSizeImplClamp"); - break; - case STATE_LIGHT_SPOT_DIR_NORMALIZED: - append(dst, "lightSpotDirNormalized"); - break; - case STATE_LIGHT_POSITION: - append(dst, "lightPosition"); - break; - case STATE_LIGHT_POSITION_NORMALIZED: - append(dst, "light.position.normalized"); - break; - case STATE_LIGHT_HALF_VECTOR: - append(dst, "lightHalfVector"); - break; - case STATE_PT_SCALE: - append(dst, "PTscale"); - break; - case STATE_PT_BIAS: - append(dst, "PTbias"); - break; - case STATE_PCM_SCALE: - append(dst, "PCMscale"); - break; - case STATE_PCM_BIAS: - append(dst, "PCMbias"); - break; - case STATE_SHADOW_AMBIENT: - append(dst, "CompareFailValue"); - break; - case STATE_FB_SIZE: - append(dst, "FbSize"); - break; - case STATE_ROT_MATRIX_0: - append(dst, "rotMatrixRow0"); - break; - case STATE_ROT_MATRIX_1: - append(dst, "rotMatrixRow1"); - break; - default: - /* probably STATE_INTERNAL_DRIVER+i (driver private state) */ - append(dst, "driverState"); - } -} - -static void -append_face(char *dst, GLint face) -{ - if (face == 0) - append(dst, "front."); - else - append(dst, "back."); -} - -static void -append_index(char *dst, GLint index) -{ - char s[20]; - sprintf(s, "[%d]", index); - append(dst, s); -} - -/** - * Make a string from the given state vector. - * For example, return "state.matrix.texture[2].inverse". - * Use free() to deallocate the string. - */ -char * -_mesa_program_state_string(const gl_state_index state[STATE_LENGTH]) -{ - char str[1000] = ""; - char tmp[30]; - - append(str, "state."); - append_token(str, state[0]); - - switch (state[0]) { - case STATE_MATERIAL: - append_face(str, state[1]); - append_token(str, state[2]); - break; - case STATE_LIGHT: - append_index(str, state[1]); /* light number [i]. */ - append_token(str, state[2]); /* coefficients */ - break; - case STATE_LIGHTMODEL_AMBIENT: - append(str, "lightmodel.ambient"); - break; - case STATE_LIGHTMODEL_SCENECOLOR: - if (state[1] == 0) { - append(str, "lightmodel.front.scenecolor"); - } - else { - append(str, "lightmodel.back.scenecolor"); - } - break; - case STATE_LIGHTPROD: - append_index(str, state[1]); /* light number [i]. */ - append_face(str, state[2]); - append_token(str, state[3]); - break; - case STATE_TEXGEN: - append_index(str, state[1]); /* tex unit [i] */ - append_token(str, state[2]); /* plane coef */ - break; - case STATE_TEXENV_COLOR: - append_index(str, state[1]); /* tex unit [i] */ - append(str, "color"); - break; - case STATE_CLIPPLANE: - append_index(str, state[1]); /* plane [i] */ - append(str, ".plane"); - break; - case STATE_MODELVIEW_MATRIX: - case STATE_PROJECTION_MATRIX: - case STATE_MVP_MATRIX: - case STATE_TEXTURE_MATRIX: - case STATE_PROGRAM_MATRIX: - case STATE_COLOR_MATRIX: - { - /* state[0] = modelview, projection, texture, etc. */ - /* state[1] = which texture matrix or program matrix */ - /* state[2] = first row to fetch */ - /* state[3] = last row to fetch */ - /* state[4] = transpose, inverse or invtrans */ - const gl_state_index mat = state[0]; - const GLuint index = (GLuint) state[1]; - const GLuint firstRow = (GLuint) state[2]; - const GLuint lastRow = (GLuint) state[3]; - const gl_state_index modifier = state[4]; - if (index || - mat == STATE_TEXTURE_MATRIX || - mat == STATE_PROGRAM_MATRIX) - append_index(str, index); - if (modifier) - append_token(str, modifier); - if (firstRow == lastRow) - sprintf(tmp, ".row[%d]", firstRow); - else - sprintf(tmp, ".row[%d..%d]", firstRow, lastRow); - append(str, tmp); - } - break; - case STATE_POINT_SIZE: - break; - case STATE_POINT_ATTENUATION: - break; - case STATE_FOG_PARAMS: - break; - case STATE_FOG_COLOR: - break; - case STATE_DEPTH_RANGE: - break; - case STATE_FRAGMENT_PROGRAM: - case STATE_VERTEX_PROGRAM: - /* state[1] = {STATE_ENV, STATE_LOCAL} */ - /* state[2] = parameter index */ - append_token(str, state[1]); - append_index(str, state[2]); - break; - case STATE_INTERNAL: - append_token(str, state[1]); - if (state[1] == STATE_CURRENT_ATTRIB) - append_index(str, state[2]); - break; - default: - _mesa_problem(NULL, "Invalid state in _mesa_program_state_string"); - break; - } - - return _mesa_strdup(str); -} - - -/** - * Loop over all the parameters in a parameter list. If the parameter - * is a GL state reference, look up the current value of that state - * variable and put it into the parameter's Value[4] array. - * This would be called at glBegin time when using a fragment program. - */ -void -_mesa_load_state_parameters(GLcontext *ctx, - struct gl_program_parameter_list *paramList) -{ - GLuint i; - - if (!paramList) - return; - - /*assert(ctx->Driver.NeedFlush == 0);*/ - - for (i = 0; i < paramList->NumParameters; i++) { - if (paramList->Parameters[i].Type == PROGRAM_STATE_VAR) { - _mesa_fetch_state(ctx, - (gl_state_index *) paramList->Parameters[i].StateIndexes, - paramList->ParameterValues[i]); - } - } -} - - -/** - * Copy the 16 elements of a matrix into four consecutive program - * registers starting at 'pos'. - */ -static void -load_matrix(GLfloat registers[][4], GLuint pos, const GLfloat mat[16]) -{ - GLuint i; - for (i = 0; i < 4; i++) { - registers[pos + i][0] = mat[0 + i]; - registers[pos + i][1] = mat[4 + i]; - registers[pos + i][2] = mat[8 + i]; - registers[pos + i][3] = mat[12 + i]; - } -} - - -/** - * As above, but transpose the matrix. - */ -static void -load_transpose_matrix(GLfloat registers[][4], GLuint pos, - const GLfloat mat[16]) -{ - memcpy(registers[pos], mat, 16 * sizeof(GLfloat)); -} - - -/** - * Load current vertex program's parameter registers with tracked - * matrices (if NV program). This only needs to be done per - * glBegin/glEnd, not per-vertex. - */ -void -_mesa_load_tracked_matrices(GLcontext *ctx) -{ - GLuint i; - - for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) { - /* point 'mat' at source matrix */ - GLmatrix *mat; - if (ctx->VertexProgram.TrackMatrix[i] == GL_MODELVIEW) { - mat = ctx->ModelviewMatrixStack.Top; - } - else if (ctx->VertexProgram.TrackMatrix[i] == GL_PROJECTION) { - mat = ctx->ProjectionMatrixStack.Top; - } - else if (ctx->VertexProgram.TrackMatrix[i] == GL_TEXTURE) { - GLuint unit = MIN2(ctx->Texture.CurrentUnit, - Elements(ctx->TextureMatrixStack) - 1); - mat = ctx->TextureMatrixStack[unit].Top; - } - else if (ctx->VertexProgram.TrackMatrix[i] == GL_COLOR) { - mat = ctx->ColorMatrixStack.Top; - } - else if (ctx->VertexProgram.TrackMatrix[i]==GL_MODELVIEW_PROJECTION_NV) { - /* XXX verify the combined matrix is up to date */ - mat = &ctx->_ModelProjectMatrix; - } - else if (ctx->VertexProgram.TrackMatrix[i] >= GL_MATRIX0_NV && - ctx->VertexProgram.TrackMatrix[i] <= GL_MATRIX7_NV) { - GLuint n = ctx->VertexProgram.TrackMatrix[i] - GL_MATRIX0_NV; - ASSERT(n < Elements(ctx->ProgramMatrixStack)); - mat = ctx->ProgramMatrixStack[n].Top; - } - else { - /* no matrix is tracked, but we leave the register values as-is */ - assert(ctx->VertexProgram.TrackMatrix[i] == GL_NONE); - continue; - } - - /* load the matrix values into sequential registers */ - if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_IDENTITY_NV) { - load_matrix(ctx->VertexProgram.Parameters, i*4, mat->m); - } - else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_INVERSE_NV) { - _math_matrix_analyse(mat); /* update the inverse */ - ASSERT(!_math_matrix_is_dirty(mat)); - load_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv); - } - else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_TRANSPOSE_NV) { - load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->m); - } - else { - assert(ctx->VertexProgram.TrackMatrixTransform[i] - == GL_INVERSE_TRANSPOSE_NV); - _math_matrix_analyse(mat); /* update the inverse */ - ASSERT(!_math_matrix_is_dirty(mat)); - load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv); - } - } -} diff --git a/src/mesa/shader/prog_statevars.h b/src/mesa/shader/prog_statevars.h deleted file mode 100644 index 1753471ffb..0000000000 --- a/src/mesa/shader/prog_statevars.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef PROG_STATEVARS_H -#define PROG_STATEVARS_H - -#include "main/mtypes.h" - - -/** - * Number of STATE_* values we need to address any GL state. - * Used to dimension arrays. - */ -#define STATE_LENGTH 5 - - -/** - * Used for describing GL state referenced from inside ARB vertex and - * fragment programs. - * A string such as "state.light[0].ambient" gets translated into a - * sequence of tokens such as [ STATE_LIGHT, 0, STATE_AMBIENT ]. - * - * For state that's an array, like STATE_CLIPPLANE, the 2nd token [1] should - * always be the array index. - */ -typedef enum gl_state_index_ { - STATE_MATERIAL = 100, /* start at 100 so small ints are seen as ints */ - - STATE_LIGHT, - STATE_LIGHTMODEL_AMBIENT, - STATE_LIGHTMODEL_SCENECOLOR, - STATE_LIGHTPROD, - - STATE_TEXGEN, - - STATE_FOG_COLOR, - STATE_FOG_PARAMS, - - STATE_CLIPPLANE, - - STATE_POINT_SIZE, - STATE_POINT_ATTENUATION, - - STATE_MODELVIEW_MATRIX, - STATE_PROJECTION_MATRIX, - STATE_MVP_MATRIX, - STATE_TEXTURE_MATRIX, - STATE_PROGRAM_MATRIX, - STATE_COLOR_MATRIX, - STATE_MATRIX_INVERSE, - STATE_MATRIX_TRANSPOSE, - STATE_MATRIX_INVTRANS, - - STATE_AMBIENT, - STATE_DIFFUSE, - STATE_SPECULAR, - STATE_EMISSION, - STATE_SHININESS, - STATE_HALF_VECTOR, - - STATE_POSITION, /**< xyzw = position */ - STATE_ATTENUATION, /**< xyz = attenuation, w = spot exponent */ - STATE_SPOT_DIRECTION, /**< xyz = direction, w = cos(cutoff) */ - STATE_SPOT_CUTOFF, /**< x = cutoff, yzw = undefined */ - - STATE_TEXGEN_EYE_S, - STATE_TEXGEN_EYE_T, - STATE_TEXGEN_EYE_R, - STATE_TEXGEN_EYE_Q, - STATE_TEXGEN_OBJECT_S, - STATE_TEXGEN_OBJECT_T, - STATE_TEXGEN_OBJECT_R, - STATE_TEXGEN_OBJECT_Q, - - STATE_TEXENV_COLOR, - - STATE_DEPTH_RANGE, - - STATE_VERTEX_PROGRAM, - STATE_FRAGMENT_PROGRAM, - - STATE_ENV, - STATE_LOCAL, - - STATE_INTERNAL, /* Mesa additions */ - STATE_CURRENT_ATTRIB, /* ctx->Current vertex attrib value */ - STATE_NORMAL_SCALE, - STATE_TEXRECT_SCALE, - STATE_FOG_PARAMS_OPTIMIZED, /* for faster fog calc */ - STATE_POINT_SIZE_CLAMPED, /* includes implementation dependent size clamp */ - STATE_POINT_SIZE_IMPL_CLAMP, /* for implementation clamp only in vs */ - STATE_LIGHT_SPOT_DIR_NORMALIZED, /* pre-normalized spot dir */ - STATE_LIGHT_POSITION, /* object vs eye space */ - STATE_LIGHT_POSITION_NORMALIZED, /* object vs eye space */ - STATE_LIGHT_HALF_VECTOR, /* object vs eye space */ - STATE_PT_SCALE, /**< Pixel transfer RGBA scale */ - STATE_PT_BIAS, /**< Pixel transfer RGBA bias */ - STATE_PCM_SCALE, /**< Post color matrix RGBA scale */ - STATE_PCM_BIAS, /**< Post color matrix RGBA bias */ - STATE_SHADOW_AMBIENT, /**< ARB_shadow_ambient fail value; token[2] is texture unit index */ - STATE_FB_SIZE, /**< (width-1, height-1, 0, 0) */ - STATE_ROT_MATRIX_0, /**< ATI_envmap_bumpmap, rot matrix row 0 */ - STATE_ROT_MATRIX_1, /**< ATI_envmap_bumpmap, rot matrix row 1 */ - STATE_INTERNAL_DRIVER /* first available state index for drivers (must be last) */ -} gl_state_index; - - - -extern void -_mesa_load_state_parameters(GLcontext *ctx, - struct gl_program_parameter_list *paramList); - - -extern GLbitfield -_mesa_program_state_flags(const gl_state_index state[STATE_LENGTH]); - - -extern char * -_mesa_program_state_string(const gl_state_index state[STATE_LENGTH]); - - -extern void -_mesa_load_tracked_matrices(GLcontext *ctx); - - -#endif /* PROG_STATEVARS_H */ diff --git a/src/mesa/shader/prog_uniform.c b/src/mesa/shader/prog_uniform.c deleted file mode 100644 index c408a8492c..0000000000 --- a/src/mesa/shader/prog_uniform.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file prog_uniform.c - * Shader uniform functions. - * \author Brian Paul - */ - -#include "main/imports.h" -#include "main/mtypes.h" -#include "prog_uniform.h" - - -struct gl_uniform_list * -_mesa_new_uniform_list(void) -{ - return CALLOC_STRUCT(gl_uniform_list); -} - - -void -_mesa_free_uniform_list(struct gl_uniform_list *list) -{ - GLuint i; - for (i = 0; i < list->NumUniforms; i++) { - free((void *) list->Uniforms[i].Name); - } - free(list->Uniforms); - free(list); -} - - -struct gl_uniform * -_mesa_append_uniform(struct gl_uniform_list *list, - const char *name, GLenum target, GLuint progPos) -{ - const GLuint oldNum = list->NumUniforms; - struct gl_uniform *uniform; - GLint index; - - assert(target == GL_VERTEX_PROGRAM_ARB || - target == GL_FRAGMENT_PROGRAM_ARB); - - index = _mesa_lookup_uniform(list, name); - if (index < 0) { - /* not found - append to list */ - - if (oldNum + 1 > list->Size) { - /* Need to grow the list array (alloc some extra) */ - list->Size += 4; - - /* realloc arrays */ - list->Uniforms = (struct gl_uniform *) - _mesa_realloc(list->Uniforms, - oldNum * sizeof(struct gl_uniform), - list->Size * sizeof(struct gl_uniform)); - } - - if (!list->Uniforms) { - /* out of memory */ - list->NumUniforms = 0; - list->Size = 0; - return GL_FALSE; - } - - uniform = list->Uniforms + oldNum; - - uniform->Name = _mesa_strdup(name); - uniform->VertPos = -1; - uniform->FragPos = -1; - uniform->Initialized = GL_FALSE; - - list->NumUniforms++; - } - else { - /* found */ - uniform = list->Uniforms + index; - } - - /* update position for the vertex or fragment program */ - if (target == GL_VERTEX_PROGRAM_ARB) { - if (uniform->VertPos != -1) { - /* this uniform is already in the list - that shouldn't happen */ - return GL_FALSE; - } - uniform->VertPos = progPos; - } - else { - if (uniform->FragPos != -1) { - /* this uniform is already in the list - that shouldn't happen */ - return GL_FALSE; - } - uniform->FragPos = progPos; - } - - return uniform; -} - - -/** - * Return the location/index of the named uniform in the uniform list, - * or -1 if not found. - */ -GLint -_mesa_lookup_uniform(const struct gl_uniform_list *list, const char *name) -{ - GLuint i; - for (i = 0; list && i < list->NumUniforms; i++) { - if (!strcmp(list->Uniforms[i].Name, name)) { - return i; - } - } - return -1; -} - - -GLint -_mesa_longest_uniform_name(const struct gl_uniform_list *list) -{ - GLint max = 0; - GLuint i; - for (i = 0; list && i < list->NumUniforms; i++) { - GLint len = (GLint) strlen(list->Uniforms[i].Name); - if (len > max) - max = len; - } - return max; -} - - -void -_mesa_print_uniforms(const struct gl_uniform_list *list) -{ - GLuint i; - printf("Uniform list %p:\n", (void *) list); - for (i = 0; i < list->NumUniforms; i++) { - printf("%d: %s %d %d\n", - i, - list->Uniforms[i].Name, - list->Uniforms[i].VertPos, - list->Uniforms[i].FragPos); - } -} diff --git a/src/mesa/shader/prog_uniform.h b/src/mesa/shader/prog_uniform.h deleted file mode 100644 index 22a2bfd970..0000000000 --- a/src/mesa/shader/prog_uniform.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file prog_uniform.c - * Shader uniform functions. - * \author Brian Paul - */ - -#ifndef PROG_UNIFORM_H -#define PROG_UNIFORM_H - -#include "main/mtypes.h" -#include "prog_statevars.h" - - -/** - * Shader program uniform variable. - * The glGetUniformLocation() and glUniform() commands will use this - * information. - * Note that a uniform such as "binormal" might be used in both the - * vertex shader and the fragment shader. When glUniform() is called to - * set the uniform's value, it must be updated in both the vertex and - * fragment shaders. The uniform may be in different locations in the - * two shaders so we keep track of that here. - */ -struct gl_uniform -{ - const char *Name; /**< Null-terminated string */ - GLint VertPos; - GLint FragPos; - GLboolean Initialized; /**< For debug. Has this uniform been set? */ -#if 0 - GLenum DataType; /**< GL_FLOAT, GL_FLOAT_VEC2, etc */ - GLuint Size; /**< Number of components (1..4) */ -#endif -}; - - -/** - * List of gl_uniforms - */ -struct gl_uniform_list -{ - GLuint Size; /**< allocated size of Uniforms array */ - GLuint NumUniforms; /**< number of uniforms in the array */ - struct gl_uniform *Uniforms; /**< Array [Size] */ -}; - - -extern struct gl_uniform_list * -_mesa_new_uniform_list(void); - -extern void -_mesa_free_uniform_list(struct gl_uniform_list *list); - -extern struct gl_uniform * -_mesa_append_uniform(struct gl_uniform_list *list, - const char *name, GLenum target, GLuint progPos); - -extern GLint -_mesa_lookup_uniform(const struct gl_uniform_list *list, const char *name); - -extern GLint -_mesa_longest_uniform_name(const struct gl_uniform_list *list); - -extern void -_mesa_print_uniforms(const struct gl_uniform_list *list); - - -#endif /* PROG_UNIFORM_H */ diff --git a/src/mesa/shader/program.c b/src/mesa/shader/program.c deleted file mode 100644 index a6ada8a048..0000000000 --- a/src/mesa/shader/program.c +++ /dev/null @@ -1,913 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file program.c - * Vertex and fragment program support functions. - * \author Brian Paul - */ - - -#include "main/glheader.h" -#include "main/context.h" -#include "main/hash.h" -#include "program.h" -#include "prog_cache.h" -#include "prog_parameter.h" -#include "prog_instruction.h" - - -/** - * A pointer to this dummy program is put into the hash table when - * glGenPrograms is called. - */ -struct gl_program _mesa_DummyProgram; - - -/** - * Init context's vertex/fragment program state - */ -void -_mesa_init_program(GLcontext *ctx) -{ - GLuint i; - - /* - * If this assertion fails, we need to increase the field - * size for register indexes. - */ - ASSERT(ctx->Const.VertexProgram.MaxUniformComponents / 4 - <= (1 << INST_INDEX_BITS)); - ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents / 4 - <= (1 << INST_INDEX_BITS)); - - /* If this fails, increase prog_instruction::TexSrcUnit size */ - ASSERT(MAX_TEXTURE_UNITS < (1 << 5)); - - /* If this fails, increase prog_instruction::TexSrcTarget size */ - ASSERT(NUM_TEXTURE_TARGETS < (1 << 3)); - - ctx->Program.ErrorPos = -1; - ctx->Program.ErrorString = _mesa_strdup(""); - -#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program - ctx->VertexProgram.Enabled = GL_FALSE; -#if FEATURE_es2_glsl - ctx->VertexProgram.PointSizeEnabled = - (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE; -#else - ctx->VertexProgram.PointSizeEnabled = GL_FALSE; -#endif - ctx->VertexProgram.TwoSideEnabled = GL_FALSE; - _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, - ctx->Shared->DefaultVertexProgram); - assert(ctx->VertexProgram.Current); - for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) { - ctx->VertexProgram.TrackMatrix[i] = GL_NONE; - ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV; - } - ctx->VertexProgram.Cache = _mesa_new_program_cache(); -#endif - -#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program - ctx->FragmentProgram.Enabled = GL_FALSE; - _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, - ctx->Shared->DefaultFragmentProgram); - assert(ctx->FragmentProgram.Current); - ctx->FragmentProgram.Cache = _mesa_new_program_cache(); -#endif - - - /* XXX probably move this stuff */ -#if FEATURE_ATI_fragment_shader - ctx->ATIFragmentShader.Enabled = GL_FALSE; - ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader; - assert(ctx->ATIFragmentShader.Current); - ctx->ATIFragmentShader.Current->RefCount++; -#endif -} - - -/** - * Free a context's vertex/fragment program state - */ -void -_mesa_free_program_data(GLcontext *ctx) -{ -#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program - _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL); - _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache); -#endif -#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program - _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL); - _mesa_delete_program_cache(ctx, ctx->FragmentProgram.Cache); -#endif - /* XXX probably move this stuff */ -#if FEATURE_ATI_fragment_shader - if (ctx->ATIFragmentShader.Current) { - ctx->ATIFragmentShader.Current->RefCount--; - if (ctx->ATIFragmentShader.Current->RefCount <= 0) { - free(ctx->ATIFragmentShader.Current); - } - } -#endif - free((void *) ctx->Program.ErrorString); -} - - -/** - * Update the default program objects in the given context to reference those - * specified in the shared state and release those referencing the old - * shared state. - */ -void -_mesa_update_default_objects_program(GLcontext *ctx) -{ -#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program - _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, - (struct gl_vertex_program *) - ctx->Shared->DefaultVertexProgram); - assert(ctx->VertexProgram.Current); -#endif - -#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program - _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, - (struct gl_fragment_program *) - ctx->Shared->DefaultFragmentProgram); - assert(ctx->FragmentProgram.Current); -#endif - - /* XXX probably move this stuff */ -#if FEATURE_ATI_fragment_shader - if (ctx->ATIFragmentShader.Current) { - ctx->ATIFragmentShader.Current->RefCount--; - if (ctx->ATIFragmentShader.Current->RefCount <= 0) { - free(ctx->ATIFragmentShader.Current); - } - } - ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader; - assert(ctx->ATIFragmentShader.Current); - ctx->ATIFragmentShader.Current->RefCount++; -#endif -} - - -/** - * Set the vertex/fragment program error state (position and error string). - * This is generally called from within the parsers. - */ -void -_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string) -{ - ctx->Program.ErrorPos = pos; - free((void *) ctx->Program.ErrorString); - if (!string) - string = ""; - ctx->Program.ErrorString = _mesa_strdup(string); -} - - -/** - * Find the line number and column for 'pos' within 'string'. - * Return a copy of the line which contains 'pos'. Free the line with - * free(). - * \param string the program string - * \param pos the position within the string - * \param line returns the line number corresponding to 'pos'. - * \param col returns the column number corresponding to 'pos'. - * \return copy of the line containing 'pos'. - */ -const GLubyte * -_mesa_find_line_column(const GLubyte *string, const GLubyte *pos, - GLint *line, GLint *col) -{ - const GLubyte *lineStart = string; - const GLubyte *p = string; - GLubyte *s; - int len; - - *line = 1; - - while (p != pos) { - if (*p == (GLubyte) '\n') { - (*line)++; - lineStart = p + 1; - } - p++; - } - - *col = (pos - lineStart) + 1; - - /* return copy of this line */ - while (*p != 0 && *p != '\n') - p++; - len = p - lineStart; - s = (GLubyte *) malloc(len + 1); - memcpy(s, lineStart, len); - s[len] = 0; - - return s; -} - - -/** - * Initialize a new vertex/fragment program object. - */ -static struct gl_program * -_mesa_init_program_struct( GLcontext *ctx, struct gl_program *prog, - GLenum target, GLuint id) -{ - (void) ctx; - if (prog) { - GLuint i; - memset(prog, 0, sizeof(*prog)); - prog->Id = id; - prog->Target = target; - prog->Resident = GL_TRUE; - prog->RefCount = 1; - prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB; - - /* default mapping from samplers to texture units */ - for (i = 0; i < MAX_SAMPLERS; i++) - prog->SamplerUnits[i] = i; - } - - return prog; -} - - -/** - * Initialize a new fragment program object. - */ -struct gl_program * -_mesa_init_fragment_program( GLcontext *ctx, struct gl_fragment_program *prog, - GLenum target, GLuint id) -{ - if (prog) - return _mesa_init_program_struct( ctx, &prog->Base, target, id ); - else - return NULL; -} - - -/** - * Initialize a new vertex program object. - */ -struct gl_program * -_mesa_init_vertex_program( GLcontext *ctx, struct gl_vertex_program *prog, - GLenum target, GLuint id) -{ - if (prog) - return _mesa_init_program_struct( ctx, &prog->Base, target, id ); - else - return NULL; -} - - -/** - * Allocate and initialize a new fragment/vertex program object but - * don't put it into the program hash table. Called via - * ctx->Driver.NewProgram. May be overridden (ie. replaced) by a - * device driver function to implement OO deriviation with additional - * types not understood by this function. - * - * \param ctx context - * \param id program id/number - * \param target program target/type - * \return pointer to new program object - */ -struct gl_program * -_mesa_new_program(GLcontext *ctx, GLenum target, GLuint id) -{ - struct gl_program *prog; - switch (target) { - case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */ - case GL_VERTEX_STATE_PROGRAM_NV: - prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program), - target, id ); - break; - case GL_FRAGMENT_PROGRAM_NV: - case GL_FRAGMENT_PROGRAM_ARB: - prog =_mesa_init_fragment_program(ctx, - CALLOC_STRUCT(gl_fragment_program), - target, id ); - break; - default: - _mesa_problem(ctx, "bad target in _mesa_new_program"); - prog = NULL; - } - return prog; -} - - -/** - * Delete a program and remove it from the hash table, ignoring the - * reference count. - * Called via ctx->Driver.DeleteProgram. May be wrapped (OO deriviation) - * by a device driver function. - */ -void -_mesa_delete_program(GLcontext *ctx, struct gl_program *prog) -{ - (void) ctx; - ASSERT(prog); - ASSERT(prog->RefCount==0); - - if (prog == &_mesa_DummyProgram) - return; - - if (prog->String) - free(prog->String); - - _mesa_free_instructions(prog->Instructions, prog->NumInstructions); - - if (prog->Parameters) { - _mesa_free_parameter_list(prog->Parameters); - } - if (prog->Varying) { - _mesa_free_parameter_list(prog->Varying); - } - if (prog->Attributes) { - _mesa_free_parameter_list(prog->Attributes); - } - - free(prog); -} - - -/** - * Return the gl_program object for a given ID. - * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of - * casts elsewhere. - */ -struct gl_program * -_mesa_lookup_program(GLcontext *ctx, GLuint id) -{ - if (id) - return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id); - else - return NULL; -} - - -/** - * Reference counting for vertex/fragment programs - */ -void -_mesa_reference_program(GLcontext *ctx, - struct gl_program **ptr, - struct gl_program *prog) -{ - assert(ptr); - if (*ptr && prog) { - /* sanity check */ - if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB) - ASSERT(prog->Target == GL_VERTEX_PROGRAM_ARB); - else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB) - ASSERT(prog->Target == GL_FRAGMENT_PROGRAM_ARB || - prog->Target == GL_FRAGMENT_PROGRAM_NV); - } - if (*ptr == prog) { - return; /* no change */ - } - if (*ptr) { - GLboolean deleteFlag; - - /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/ -#if 0 - printf("Program %p ID=%u Target=%s Refcount-- to %d\n", - *ptr, (*ptr)->Id, - ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : "FP"), - (*ptr)->RefCount - 1); -#endif - ASSERT((*ptr)->RefCount > 0); - (*ptr)->RefCount--; - - deleteFlag = ((*ptr)->RefCount == 0); - /*_glthread_UNLOCK_MUTEX((*ptr)->Mutex);*/ - - if (deleteFlag) { - ASSERT(ctx); - ctx->Driver.DeleteProgram(ctx, *ptr); - } - - *ptr = NULL; - } - - assert(!*ptr); - if (prog) { - /*_glthread_LOCK_MUTEX(prog->Mutex);*/ - prog->RefCount++; -#if 0 - printf("Program %p ID=%u Target=%s Refcount++ to %d\n", - prog, prog->Id, - (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : "FP"), - prog->RefCount); -#endif - /*_glthread_UNLOCK_MUTEX(prog->Mutex);*/ - } - - *ptr = prog; -} - - -/** - * Return a copy of a program. - * XXX Problem here if the program object is actually OO-derivation - * made by a device driver. - */ -struct gl_program * -_mesa_clone_program(GLcontext *ctx, const struct gl_program *prog) -{ - struct gl_program *clone; - - clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id); - if (!clone) - return NULL; - - assert(clone->Target == prog->Target); - assert(clone->RefCount == 1); - - clone->String = (GLubyte *) _mesa_strdup((char *) prog->String); - clone->Format = prog->Format; - clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions); - if (!clone->Instructions) { - _mesa_reference_program(ctx, &clone, NULL); - return NULL; - } - _mesa_copy_instructions(clone->Instructions, prog->Instructions, - prog->NumInstructions); - clone->InputsRead = prog->InputsRead; - clone->OutputsWritten = prog->OutputsWritten; - clone->SamplersUsed = prog->SamplersUsed; - clone->ShadowSamplers = prog->ShadowSamplers; - memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed)); - - if (prog->Parameters) - clone->Parameters = _mesa_clone_parameter_list(prog->Parameters); - memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); - if (prog->Varying) - clone->Varying = _mesa_clone_parameter_list(prog->Varying); - if (prog->Attributes) - clone->Attributes = _mesa_clone_parameter_list(prog->Attributes); - memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); - clone->NumInstructions = prog->NumInstructions; - clone->NumTemporaries = prog->NumTemporaries; - clone->NumParameters = prog->NumParameters; - clone->NumAttributes = prog->NumAttributes; - clone->NumAddressRegs = prog->NumAddressRegs; - clone->NumNativeInstructions = prog->NumNativeInstructions; - clone->NumNativeTemporaries = prog->NumNativeTemporaries; - clone->NumNativeParameters = prog->NumNativeParameters; - clone->NumNativeAttributes = prog->NumNativeAttributes; - clone->NumNativeAddressRegs = prog->NumNativeAddressRegs; - clone->NumAluInstructions = prog->NumAluInstructions; - clone->NumTexInstructions = prog->NumTexInstructions; - clone->NumTexIndirections = prog->NumTexIndirections; - clone->NumNativeAluInstructions = prog->NumNativeAluInstructions; - clone->NumNativeTexInstructions = prog->NumNativeTexInstructions; - clone->NumNativeTexIndirections = prog->NumNativeTexIndirections; - - switch (prog->Target) { - case GL_VERTEX_PROGRAM_ARB: - { - const struct gl_vertex_program *vp - = (const struct gl_vertex_program *) prog; - struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone; - vpc->IsPositionInvariant = vp->IsPositionInvariant; - vpc->IsNVProgram = vp->IsNVProgram; - } - break; - case GL_FRAGMENT_PROGRAM_ARB: - { - const struct gl_fragment_program *fp - = (const struct gl_fragment_program *) prog; - struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone; - fpc->FogOption = fp->FogOption; - fpc->UsesKill = fp->UsesKill; - fpc->OriginUpperLeft = fp->OriginUpperLeft; - fpc->PixelCenterInteger = fp->PixelCenterInteger; - } - break; - default: - _mesa_problem(NULL, "Unexpected target in _mesa_clone_program"); - } - - return clone; -} - - -/** - * Insert 'count' NOP instructions at 'start' in the given program. - * Adjust branch targets accordingly. - */ -GLboolean -_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count) -{ - const GLuint origLen = prog->NumInstructions; - const GLuint newLen = origLen + count; - struct prog_instruction *newInst; - GLuint i; - - /* adjust branches */ - for (i = 0; i < prog->NumInstructions; i++) { - struct prog_instruction *inst = prog->Instructions + i; - if (inst->BranchTarget > 0) { - if ((GLuint)inst->BranchTarget >= start) { - inst->BranchTarget += count; - } - } - } - - /* Alloc storage for new instructions */ - newInst = _mesa_alloc_instructions(newLen); - if (!newInst) { - return GL_FALSE; - } - - /* Copy 'start' instructions into new instruction buffer */ - _mesa_copy_instructions(newInst, prog->Instructions, start); - - /* init the new instructions */ - _mesa_init_instructions(newInst + start, count); - - /* Copy the remaining/tail instructions to new inst buffer */ - _mesa_copy_instructions(newInst + start + count, - prog->Instructions + start, - origLen - start); - - /* free old instructions */ - _mesa_free_instructions(prog->Instructions, origLen); - - /* install new instructions */ - prog->Instructions = newInst; - prog->NumInstructions = newLen; - - return GL_TRUE; -} - -/** - * Delete 'count' instructions at 'start' in the given program. - * Adjust branch targets accordingly. - */ -GLboolean -_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count) -{ - const GLuint origLen = prog->NumInstructions; - const GLuint newLen = origLen - count; - struct prog_instruction *newInst; - GLuint i; - - /* adjust branches */ - for (i = 0; i < prog->NumInstructions; i++) { - struct prog_instruction *inst = prog->Instructions + i; - if (inst->BranchTarget > 0) { - if (inst->BranchTarget > (GLint) start) { - inst->BranchTarget -= count; - } - } - } - - /* Alloc storage for new instructions */ - newInst = _mesa_alloc_instructions(newLen); - if (!newInst) { - return GL_FALSE; - } - - /* Copy 'start' instructions into new instruction buffer */ - _mesa_copy_instructions(newInst, prog->Instructions, start); - - /* Copy the remaining/tail instructions to new inst buffer */ - _mesa_copy_instructions(newInst + start, - prog->Instructions + start + count, - newLen - start); - - /* free old instructions */ - _mesa_free_instructions(prog->Instructions, origLen); - - /* install new instructions */ - prog->Instructions = newInst; - prog->NumInstructions = newLen; - - return GL_TRUE; -} - - -/** - * Search instructions for registers that match (oldFile, oldIndex), - * replacing them with (newFile, newIndex). - */ -static void -replace_registers(struct prog_instruction *inst, GLuint numInst, - GLuint oldFile, GLuint oldIndex, - GLuint newFile, GLuint newIndex) -{ - GLuint i, j; - for (i = 0; i < numInst; i++) { - /* src regs */ - for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) { - if (inst[i].SrcReg[j].File == oldFile && - inst[i].SrcReg[j].Index == oldIndex) { - inst[i].SrcReg[j].File = newFile; - inst[i].SrcReg[j].Index = newIndex; - } - } - /* dst reg */ - if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) { - inst[i].DstReg.File = newFile; - inst[i].DstReg.Index = newIndex; - } - } -} - - -/** - * Search instructions for references to program parameters. When found, - * increment the parameter index by 'offset'. - * Used when combining programs. - */ -static void -adjust_param_indexes(struct prog_instruction *inst, GLuint numInst, - GLuint offset) -{ - GLuint i, j; - for (i = 0; i < numInst; i++) { - for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) { - GLuint f = inst[i].SrcReg[j].File; - if (f == PROGRAM_CONSTANT || - f == PROGRAM_UNIFORM || - f == PROGRAM_STATE_VAR) { - inst[i].SrcReg[j].Index += offset; - } - } - } -} - - -/** - * Combine two programs into one. Fix instructions so the outputs of - * the first program go to the inputs of the second program. - */ -struct gl_program * -_mesa_combine_programs(GLcontext *ctx, - const struct gl_program *progA, - const struct gl_program *progB) -{ - struct prog_instruction *newInst; - struct gl_program *newProg; - const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */ - const GLuint lenB = progB->NumInstructions; - const GLuint numParamsA = _mesa_num_parameters(progA->Parameters); - const GLuint newLength = lenA + lenB; - GLboolean usedTemps[MAX_PROGRAM_TEMPS]; - GLuint firstTemp = 0; - GLbitfield inputsB; - GLuint i; - - ASSERT(progA->Target == progB->Target); - - newInst = _mesa_alloc_instructions(newLength); - if (!newInst) - return GL_FALSE; - - _mesa_copy_instructions(newInst, progA->Instructions, lenA); - _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB); - - /* adjust branch / instruction addresses for B's instructions */ - for (i = 0; i < lenB; i++) { - newInst[lenA + i].BranchTarget += lenA; - } - - newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0); - newProg->Instructions = newInst; - newProg->NumInstructions = newLength; - - /* find used temp regs (we may need new temps below) */ - _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY, - usedTemps, MAX_PROGRAM_TEMPS); - - if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) { - struct gl_fragment_program *fprogA, *fprogB, *newFprog; - GLbitfield progB_inputsRead = progB->InputsRead; - GLint progB_colorFile, progB_colorIndex; - - fprogA = (struct gl_fragment_program *) progA; - fprogB = (struct gl_fragment_program *) progB; - newFprog = (struct gl_fragment_program *) newProg; - - newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill; - - /* We'll do a search and replace for instances - * of progB_colorFile/progB_colorIndex below... - */ - progB_colorFile = PROGRAM_INPUT; - progB_colorIndex = FRAG_ATTRIB_COL0; - - /* - * The fragment program may get color from a state var rather than - * a fragment input (vertex output) if it's constant. - * See the texenvprogram.c code. - * So, search the program's parameter list now to see if the program - * gets color from a state var instead of a conventional fragment - * input register. - */ - for (i = 0; i < progB->Parameters->NumParameters; i++) { - struct gl_program_parameter *p = &progB->Parameters->Parameters[i]; - if (p->Type == PROGRAM_STATE_VAR && - p->StateIndexes[0] == STATE_INTERNAL && - p->StateIndexes[1] == STATE_CURRENT_ATTRIB && - p->StateIndexes[2] == VERT_ATTRIB_COLOR0) { - progB_inputsRead |= FRAG_BIT_COL0; - progB_colorFile = PROGRAM_STATE_VAR; - progB_colorIndex = i; - break; - } - } - - /* Connect color outputs of fprogA to color inputs of fprogB, via a - * new temporary register. - */ - if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) && - (progB_inputsRead & FRAG_BIT_COL0)) { - GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS, - firstTemp); - if (tempReg < 0) { - _mesa_problem(ctx, "No free temp regs found in " - "_mesa_combine_programs(), using 31"); - tempReg = 31; - } - firstTemp = tempReg + 1; - - /* replace writes to result.color[0] with tempReg */ - replace_registers(newInst, lenA, - PROGRAM_OUTPUT, FRAG_RESULT_COLOR, - PROGRAM_TEMPORARY, tempReg); - /* replace reads from the input color with tempReg */ - replace_registers(newInst + lenA, lenB, - progB_colorFile, progB_colorIndex, /* search for */ - PROGRAM_TEMPORARY, tempReg /* replace with */ ); - } - - /* compute combined program's InputsRead */ - inputsB = progB_inputsRead; - if (progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) { - inputsB &= ~(1 << FRAG_ATTRIB_COL0); - } - newProg->InputsRead = progA->InputsRead | inputsB; - newProg->OutputsWritten = progB->OutputsWritten; - newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed; - } - else { - /* vertex program */ - assert(0); /* XXX todo */ - } - - /* - * Merge parameters (uniforms, constants, etc) - */ - newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters, - progB->Parameters); - - adjust_param_indexes(newInst + lenA, lenB, numParamsA); - - - return newProg; -} - - -/** - * Populate the 'used' array with flags indicating which registers (TEMPs, - * INPUTs, OUTPUTs, etc, are used by the given program. - * \param file type of register to scan for - * \param used returns true/false flags for in use / free - * \param usedSize size of the 'used' array - */ -void -_mesa_find_used_registers(const struct gl_program *prog, - gl_register_file file, - GLboolean used[], GLuint usedSize) -{ - GLuint i, j; - - memset(used, 0, usedSize); - - for (i = 0; i < prog->NumInstructions; i++) { - const struct prog_instruction *inst = prog->Instructions + i; - const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); - - if (inst->DstReg.File == file) { - used[inst->DstReg.Index] = GL_TRUE; - } - - for (j = 0; j < n; j++) { - if (inst->SrcReg[j].File == file) { - used[inst->SrcReg[j].Index] = GL_TRUE; - } - } - } -} - - -/** - * Scan the given 'used' register flag array for the first entry - * that's >= firstReg. - * \param used vector of flags indicating registers in use (as returned - * by _mesa_find_used_registers()) - * \param usedSize size of the 'used' array - * \param firstReg first register to start searching at - * \return index of unused register, or -1 if none. - */ -GLint -_mesa_find_free_register(const GLboolean used[], - GLuint usedSize, GLuint firstReg) -{ - GLuint i; - - assert(firstReg < usedSize); - - for (i = firstReg; i < usedSize; i++) - if (!used[i]) - return i; - - return -1; -} - - -/** - * "Post-process" a GPU program. This is intended to be used for debugging. - * Example actions include no-op'ing instructions or changing instruction - * behaviour. - */ -void -_mesa_postprocess_program(GLcontext *ctx, struct gl_program *prog) -{ - static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 }; - GLuint i; - GLuint whiteSwizzle; - GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters, - white, 4, &whiteSwizzle); - - (void) whiteIndex; - - for (i = 0; i < prog->NumInstructions; i++) { - struct prog_instruction *inst = prog->Instructions + i; - const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); - - (void) n; - - if (_mesa_is_tex_instruction(inst->Opcode)) { -#if 0 - /* replace TEX/TXP/TXB with MOV */ - inst->Opcode = OPCODE_MOV; - inst->DstReg.WriteMask = WRITEMASK_XYZW; - inst->SrcReg[0].Swizzle = SWIZZLE_XYZW; - inst->SrcReg[0].Negate = NEGATE_NONE; -#endif - -#if 0 - /* disable shadow texture mode */ - inst->TexShadow = 0; -#endif - } - - if (inst->Opcode == OPCODE_TXP) { -#if 0 - inst->Opcode = OPCODE_MOV; - inst->DstReg.WriteMask = WRITEMASK_XYZW; - inst->SrcReg[0].File = PROGRAM_CONSTANT; - inst->SrcReg[0].Index = whiteIndex; - inst->SrcReg[0].Swizzle = SWIZZLE_XYZW; - inst->SrcReg[0].Negate = NEGATE_NONE; -#endif -#if 0 - inst->TexShadow = 0; -#endif -#if 0 - inst->Opcode = OPCODE_TEX; - inst->TexShadow = 0; -#endif - } - - } -} diff --git a/src/mesa/shader/program.h b/src/mesa/shader/program.h deleted file mode 100644 index af9f4170d1..0000000000 --- a/src/mesa/shader/program.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file program.c - * Vertex and fragment program support functions. - * \author Brian Paul - */ - - -/** - * \mainpage Mesa vertex and fragment program module - * - * This module or directory contains most of the code for vertex and - * fragment programs and shaders, including state management, parsers, - * and (some) software routines for executing programs - */ - -#ifndef PROGRAM_H -#define PROGRAM_H - -#include "main/mtypes.h" - - -extern struct gl_program _mesa_DummyProgram; - - -extern void -_mesa_init_program(GLcontext *ctx); - -extern void -_mesa_free_program_data(GLcontext *ctx); - -extern void -_mesa_update_default_objects_program(GLcontext *ctx); - -extern void -_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string); - -extern const GLubyte * -_mesa_find_line_column(const GLubyte *string, const GLubyte *pos, - GLint *line, GLint *col); - - -extern struct gl_program * -_mesa_init_vertex_program(GLcontext *ctx, - struct gl_vertex_program *prog, - GLenum target, GLuint id); - -extern struct gl_program * -_mesa_init_fragment_program(GLcontext *ctx, - struct gl_fragment_program *prog, - GLenum target, GLuint id); - -extern struct gl_program * -_mesa_new_program(GLcontext *ctx, GLenum target, GLuint id); - -extern void -_mesa_delete_program(GLcontext *ctx, struct gl_program *prog); - -extern struct gl_program * -_mesa_lookup_program(GLcontext *ctx, GLuint id); - -extern void -_mesa_reference_program(GLcontext *ctx, - struct gl_program **ptr, - struct gl_program *prog); - -static INLINE void -_mesa_reference_vertprog(GLcontext *ctx, - struct gl_vertex_program **ptr, - struct gl_vertex_program *prog) -{ - _mesa_reference_program(ctx, (struct gl_program **) ptr, - (struct gl_program *) prog); -} - -static INLINE void -_mesa_reference_fragprog(GLcontext *ctx, - struct gl_fragment_program **ptr, - struct gl_fragment_program *prog) -{ - _mesa_reference_program(ctx, (struct gl_program **) ptr, - (struct gl_program *) prog); -} - -extern struct gl_program * -_mesa_clone_program(GLcontext *ctx, const struct gl_program *prog); - -static INLINE struct gl_vertex_program * -_mesa_clone_vertex_program(GLcontext *ctx, - const struct gl_vertex_program *prog) -{ - return (struct gl_vertex_program *) _mesa_clone_program(ctx, &prog->Base); -} - - -static INLINE struct gl_fragment_program * -_mesa_clone_fragment_program(GLcontext *ctx, - const struct gl_fragment_program *prog) -{ - return (struct gl_fragment_program *) _mesa_clone_program(ctx, &prog->Base); -} - - -extern GLboolean -_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count); - -extern GLboolean -_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count); - -extern struct gl_program * -_mesa_combine_programs(GLcontext *ctx, - const struct gl_program *progA, - const struct gl_program *progB); - -extern void -_mesa_find_used_registers(const struct gl_program *prog, - gl_register_file file, - GLboolean used[], GLuint usedSize); - -extern GLint -_mesa_find_free_register(const GLboolean used[], - GLuint maxRegs, GLuint firstReg); - -extern void -_mesa_postprocess_program(GLcontext *ctx, struct gl_program *prog); - - -#endif /* PROGRAM_H */ diff --git a/src/mesa/shader/program_lexer.l b/src/mesa/shader/program_lexer.l deleted file mode 100644 index fe18272cdb..0000000000 --- a/src/mesa/shader/program_lexer.l +++ /dev/null @@ -1,495 +0,0 @@ -%{ -/* - * Copyright © 2009 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#include "main/glheader.h" -#include "main/imports.h" -#include "shader/prog_instruction.h" -#include "shader/prog_statevars.h" - -#include "shader/symbol_table.h" -#include "shader/program_parser.h" -#include "shader/program_parse.tab.h" - -#define require_ARB_vp (yyextra->mode == ARB_vertex) -#define require_ARB_fp (yyextra->mode == ARB_fragment) -#define require_NV_fp (yyextra->option.NV_fragment) -#define require_shadow (yyextra->option.Shadow) -#define require_rect (yyextra->option.TexRect) -#define require_texarray (yyextra->option.TexArray) - -#ifndef HAVE_UNISTD_H -#define YY_NO_UNISTD_H -#endif - -#define return_token_or_IDENTIFIER(condition, token) \ - do { \ - if (condition) { \ - return token; \ - } else { \ - return handle_ident(yyextra, yytext, yylval); \ - } \ - } while (0) - -#define return_token_or_DOT(condition, token) \ - do { \ - if (condition) { \ - return token; \ - } else { \ - yyless(1); \ - return DOT; \ - } \ - } while (0) - - -#define return_opcode(condition, token, opcode, len) \ - do { \ - if (condition && \ - _mesa_parse_instruction_suffix(yyextra, \ - yytext + len, \ - & yylval->temp_inst)) { \ - yylval->temp_inst.Opcode = OPCODE_ ## opcode; \ - return token; \ - } else { \ - return handle_ident(yyextra, yytext, yylval); \ - } \ - } while (0) - -#define SWIZZLE_INVAL MAKE_SWIZZLE4(SWIZZLE_NIL, SWIZZLE_NIL, \ - SWIZZLE_NIL, SWIZZLE_NIL) - -static unsigned -mask_from_char(char c) -{ - switch (c) { - case 'x': - case 'r': - return WRITEMASK_X; - case 'y': - case 'g': - return WRITEMASK_Y; - case 'z': - case 'b': - return WRITEMASK_Z; - case 'w': - case 'a': - return WRITEMASK_W; - } - - return 0; -} - -static unsigned -swiz_from_char(char c) -{ - switch (c) { - case 'x': - case 'r': - return SWIZZLE_X; - case 'y': - case 'g': - return SWIZZLE_Y; - case 'z': - case 'b': - return SWIZZLE_Z; - case 'w': - case 'a': - return SWIZZLE_W; - } - - return 0; -} - -static int -handle_ident(struct asm_parser_state *state, const char *text, YYSTYPE *lval) -{ - lval->string = strdup(text); - - return (_mesa_symbol_table_find_symbol(state->st, 0, text) == NULL) - ? IDENTIFIER : USED_IDENTIFIER; -} - -#define YY_USER_ACTION \ - do { \ - yylloc->first_column = yylloc->last_column; \ - yylloc->last_column += yyleng; \ - if ((yylloc->first_line == 1) \ - && (yylloc->first_column == 1)) { \ - yylloc->position = 1; \ - } else { \ - yylloc->position += yylloc->last_column - yylloc->first_column; \ - } \ - } while(0); - -#define YY_EXTRA_TYPE struct asm_parser_state * -%} - -num [0-9]+ -exp [Ee][-+]?[0-9]+ -frac "."[0-9]+ -dot "."[ \t]* - -sz [HRX]? -szf [HR]? -cc C? -sat (_SAT)? - -%option bison-bridge bison-locations reentrant noyywrap -%% - -"!!ARBvp1.0" { return ARBvp_10; } -"!!ARBfp1.0" { return ARBfp_10; } -ADDRESS { - yylval->integer = at_address; - return_token_or_IDENTIFIER(require_ARB_vp, ADDRESS); -} -ALIAS { return ALIAS; } -ATTRIB { return ATTRIB; } -END { return END; } -OPTION { return OPTION; } -OUTPUT { return OUTPUT; } -PARAM { return PARAM; } -TEMP { yylval->integer = at_temp; return TEMP; } - -ABS{sz}{cc}{sat} { return_opcode( 1, VECTOR_OP, ABS, 3); } -ADD{sz}{cc}{sat} { return_opcode( 1, BIN_OP, ADD, 3); } -ARL { return_opcode(require_ARB_vp, ARL, ARL, 3); } - -CMP{sat} { return_opcode(require_ARB_fp, TRI_OP, CMP, 3); } -COS{szf}{cc}{sat} { return_opcode(require_ARB_fp, SCALAR_OP, COS, 3); } - -DDX{szf}{cc}{sat} { return_opcode(require_NV_fp, VECTOR_OP, DDX, 3); } -DDY{szf}{cc}{sat} { return_opcode(require_NV_fp, VECTOR_OP, DDY, 3); } -DP3{sz}{cc}{sat} { return_opcode( 1, BIN_OP, DP3, 3); } -DP4{sz}{cc}{sat} { return_opcode( 1, BIN_OP, DP4, 3); } -DPH{sz}{cc}{sat} { return_opcode( 1, BIN_OP, DPH, 3); } -DST{szf}{cc}{sat} { return_opcode( 1, BIN_OP, DST, 3); } - -EX2{szf}{cc}{sat} { return_opcode( 1, SCALAR_OP, EX2, 3); } -EXP { return_opcode(require_ARB_vp, SCALAR_OP, EXP, 3); } - -FLR{sz}{cc}{sat} { return_opcode( 1, VECTOR_OP, FLR, 3); } -FRC{sz}{cc}{sat} { return_opcode( 1, VECTOR_OP, FRC, 3); } - -KIL { return_opcode(require_ARB_fp, KIL, KIL, 3); } - -LIT{szf}{cc}{sat} { return_opcode( 1, VECTOR_OP, LIT, 3); } -LG2{szf}{cc}{sat} { return_opcode( 1, SCALAR_OP, LG2, 3); } -LOG { return_opcode(require_ARB_vp, SCALAR_OP, LOG, 3); } -LRP{sz}{cc}{sat} { return_opcode(require_ARB_fp, TRI_OP, LRP, 3); } - -MAD{sz}{cc}{sat} { return_opcode( 1, TRI_OP, MAD, 3); } -MAX{sz}{cc}{sat} { return_opcode( 1, BIN_OP, MAX, 3); } -MIN{sz}{cc}{sat} { return_opcode( 1, BIN_OP, MIN, 3); } -MOV{sz}{cc}{sat} { return_opcode( 1, VECTOR_OP, MOV, 3); } -MUL{sz}{cc}{sat} { return_opcode( 1, BIN_OP, MUL, 3); } - -PK2H { return_opcode(require_NV_fp, VECTOR_OP, PK2H, 4); } -PK2US { return_opcode(require_NV_fp, VECTOR_OP, PK2US, 5); } -PK4B { return_opcode(require_NV_fp, VECTOR_OP, PK4B, 4); } -PK4UB { return_opcode(require_NV_fp, VECTOR_OP, PK4UB, 5); } -POW{szf}{cc}{sat} { return_opcode( 1, BINSC_OP, POW, 3); } - -RCP{szf}{cc}{sat} { return_opcode( 1, SCALAR_OP, RCP, 3); } -RFL{szf}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, RFL, 3); } -RSQ{szf}{cc}{sat} { return_opcode( 1, SCALAR_OP, RSQ, 3); } - -SCS{sat} { return_opcode(require_ARB_fp, SCALAR_OP, SCS, 3); } -SEQ{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SEQ, 3); } -SFL{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SFL, 3); } -SGE{sz}{cc}{sat} { return_opcode( 1, BIN_OP, SGE, 3); } -SGT{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SGT, 3); } -SIN{szf}{cc}{sat} { return_opcode(require_ARB_fp, SCALAR_OP, SIN, 3); } -SLE{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SLE, 3); } -SLT{sz}{cc}{sat} { return_opcode( 1, BIN_OP, SLT, 3); } -SNE{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SNE, 3); } -STR{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, STR, 3); } -SUB{sz}{cc}{sat} { return_opcode( 1, BIN_OP, SUB, 3); } -SWZ{sat} { return_opcode( 1, SWZ, SWZ, 3); } - -TEX{cc}{sat} { return_opcode(require_ARB_fp, SAMPLE_OP, TEX, 3); } -TXB{cc}{sat} { return_opcode(require_ARB_fp, SAMPLE_OP, TXB, 3); } -TXD{cc}{sat} { return_opcode(require_NV_fp, TXD_OP, TXD, 3); } -TXP{cc}{sat} { return_opcode(require_ARB_fp, SAMPLE_OP, TXP, 3); } - -UP2H{cc}{sat} { return_opcode(require_NV_fp, SCALAR_OP, UP2H, 4); } -UP2US{cc}{sat} { return_opcode(require_NV_fp, SCALAR_OP, UP2US, 5); } -UP4B{cc}{sat} { return_opcode(require_NV_fp, SCALAR_OP, UP4B, 4); } -UP4UB{cc}{sat} { return_opcode(require_NV_fp, SCALAR_OP, UP4UB, 5); } - -X2D{szf}{cc}{sat} { return_opcode(require_NV_fp, TRI_OP, X2D, 3); } -XPD{sat} { return_opcode( 1, BIN_OP, XPD, 3); } - -vertex { return_token_or_IDENTIFIER(require_ARB_vp, VERTEX); } -fragment { return_token_or_IDENTIFIER(require_ARB_fp, FRAGMENT); } -program { return PROGRAM; } -state { return STATE; } -result { return RESULT; } - -{dot}ambient { return AMBIENT; } -{dot}attenuation { return ATTENUATION; } -{dot}back { return BACK; } -{dot}clip { return_token_or_DOT(require_ARB_vp, CLIP); } -{dot}color { return COLOR; } -{dot}depth { return_token_or_DOT(require_ARB_fp, DEPTH); } -{dot}diffuse { return DIFFUSE; } -{dot}direction { return DIRECTION; } -{dot}emission { return EMISSION; } -{dot}env { return ENV; } -{dot}eye { return EYE; } -{dot}fogcoord { return FOGCOORD; } -{dot}fog { return FOG; } -{dot}front { return FRONT; } -{dot}half { return HALF; } -{dot}inverse { return INVERSE; } -{dot}invtrans { return INVTRANS; } -{dot}light { return LIGHT; } -{dot}lightmodel { return LIGHTMODEL; } -{dot}lightprod { return LIGHTPROD; } -{dot}local { return LOCAL; } -{dot}material { return MATERIAL; } -{dot}program { return MAT_PROGRAM; } -{dot}matrix { return MATRIX; } -{dot}matrixindex { return_token_or_DOT(require_ARB_vp, MATRIXINDEX); } -{dot}modelview { return MODELVIEW; } -{dot}mvp { return MVP; } -{dot}normal { return_token_or_DOT(require_ARB_vp, NORMAL); } -{dot}object { return OBJECT; } -{dot}palette { return PALETTE; } -{dot}params { return PARAMS; } -{dot}plane { return PLANE; } -{dot}point { return_token_or_DOT(require_ARB_vp, POINT_TOK); } -{dot}pointsize { return_token_or_DOT(require_ARB_vp, POINTSIZE); } -{dot}position { return POSITION; } -{dot}primary { return PRIMARY; } -{dot}projection { return PROJECTION; } -{dot}range { return_token_or_DOT(require_ARB_fp, RANGE); } -{dot}row { return ROW; } -{dot}scenecolor { return SCENECOLOR; } -{dot}secondary { return SECONDARY; } -{dot}shininess { return SHININESS; } -{dot}size { return_token_or_DOT(require_ARB_vp, SIZE_TOK); } -{dot}specular { return SPECULAR; } -{dot}spot { return SPOT; } -{dot}texcoord { return TEXCOORD; } -{dot}texenv { return_token_or_DOT(require_ARB_fp, TEXENV); } -{dot}texgen { return_token_or_DOT(require_ARB_vp, TEXGEN); } -{dot}q { return_token_or_DOT(require_ARB_vp, TEXGEN_Q); } -{dot}s { return_token_or_DOT(require_ARB_vp, TEXGEN_S); } -{dot}t { return_token_or_DOT(require_ARB_vp, TEXGEN_T); } -{dot}texture { return TEXTURE; } -{dot}transpose { return TRANSPOSE; } -{dot}attrib { return_token_or_DOT(require_ARB_vp, VTXATTRIB); } -{dot}weight { return_token_or_DOT(require_ARB_vp, WEIGHT); } - -texture { return_token_or_IDENTIFIER(require_ARB_fp, TEXTURE_UNIT); } -1D { return_token_or_IDENTIFIER(require_ARB_fp, TEX_1D); } -2D { return_token_or_IDENTIFIER(require_ARB_fp, TEX_2D); } -3D { return_token_or_IDENTIFIER(require_ARB_fp, TEX_3D); } -CUBE { return_token_or_IDENTIFIER(require_ARB_fp, TEX_CUBE); } -RECT { return_token_or_IDENTIFIER(require_ARB_fp && require_rect, TEX_RECT); } -SHADOW1D { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow, TEX_SHADOW1D); } -SHADOW2D { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow, TEX_SHADOW2D); } -SHADOWRECT { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_rect, TEX_SHADOWRECT); } -ARRAY1D { return_token_or_IDENTIFIER(require_ARB_fp && require_texarray, TEX_ARRAY1D); } -ARRAY2D { return_token_or_IDENTIFIER(require_ARB_fp && require_texarray, TEX_ARRAY2D); } -ARRAYSHADOW1D { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_texarray, TEX_ARRAYSHADOW1D); } -ARRAYSHADOW2D { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_texarray, TEX_ARRAYSHADOW2D); } - -[_a-zA-Z$][_a-zA-Z0-9$]* { return handle_ident(yyextra, yytext, yylval); } - -".." { return DOT_DOT; } - -{num} { - yylval->integer = strtol(yytext, NULL, 10); - return INTEGER; -} -{num}?{frac}{exp}? { - yylval->real = _mesa_strtof(yytext, NULL); - return REAL; -} -{num}"."/[^.] { - yylval->real = _mesa_strtof(yytext, NULL); - return REAL; -} -{num}{exp} { - yylval->real = _mesa_strtof(yytext, NULL); - return REAL; -} -{num}"."{exp} { - yylval->real = _mesa_strtof(yytext, NULL); - return REAL; -} - -".xyzw" { - yylval->swiz_mask.swizzle = SWIZZLE_NOOP; - yylval->swiz_mask.mask = WRITEMASK_XYZW; - return MASK4; -} - -".xy"[zw] { - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_XY - | mask_from_char(yytext[3]); - return MASK3; -} -".xzw" { - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_XZW; - return MASK3; -} -".yzw" { - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_YZW; - return MASK3; -} - -".x"[yzw] { - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_X - | mask_from_char(yytext[2]); - return MASK2; -} -".y"[zw] { - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_Y - | mask_from_char(yytext[2]); - return MASK2; -} -".zw" { - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_ZW; - return MASK2; -} - -"."[xyzw] { - const unsigned s = swiz_from_char(yytext[1]); - yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(s, s, s, s); - yylval->swiz_mask.mask = mask_from_char(yytext[1]); - return MASK1; -} - -"."[xyzw]{4} { - yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(swiz_from_char(yytext[1]), - swiz_from_char(yytext[2]), - swiz_from_char(yytext[3]), - swiz_from_char(yytext[4])); - yylval->swiz_mask.mask = 0; - return SWIZZLE; -} - -".rgba" { - yylval->swiz_mask.swizzle = SWIZZLE_NOOP; - yylval->swiz_mask.mask = WRITEMASK_XYZW; - return_token_or_DOT(require_ARB_fp, MASK4); -} - -".rg"[ba] { - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_XY - | mask_from_char(yytext[3]); - return_token_or_DOT(require_ARB_fp, MASK3); -} -".rba" { - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_XZW; - return_token_or_DOT(require_ARB_fp, MASK3); -} -".gba" { - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_YZW; - return_token_or_DOT(require_ARB_fp, MASK3); -} - -".r"[gba] { - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_X - | mask_from_char(yytext[2]); - return_token_or_DOT(require_ARB_fp, MASK2); -} -".g"[ba] { - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_Y - | mask_from_char(yytext[2]); - return_token_or_DOT(require_ARB_fp, MASK2); -} -".ba" { - yylval->swiz_mask.swizzle = SWIZZLE_INVAL; - yylval->swiz_mask.mask = WRITEMASK_ZW; - return_token_or_DOT(require_ARB_fp, MASK2); -} - -"."[gba] { - const unsigned s = swiz_from_char(yytext[1]); - yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(s, s, s, s); - yylval->swiz_mask.mask = mask_from_char(yytext[1]); - return_token_or_DOT(require_ARB_fp, MASK1); -} - - -".r" { - if (require_ARB_vp) { - return TEXGEN_R; - } else { - yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, - SWIZZLE_X, SWIZZLE_X); - yylval->swiz_mask.mask = WRITEMASK_X; - return MASK1; - } -} - -"."[rgba]{4} { - yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(swiz_from_char(yytext[1]), - swiz_from_char(yytext[2]), - swiz_from_char(yytext[3]), - swiz_from_char(yytext[4])); - yylval->swiz_mask.mask = 0; - return_token_or_DOT(require_ARB_fp, SWIZZLE); -} - -"." { return DOT; } - -\n { - yylloc->first_line++; - yylloc->first_column = 1; - yylloc->last_line++; - yylloc->last_column = 1; - yylloc->position++; -} -[ \t\r]+ /* eat whitespace */ ; -#.*$ /* eat comments */ ; -. { return yytext[0]; } -%% - -void -_mesa_program_lexer_ctor(void **scanner, struct asm_parser_state *state, - const char *string, size_t len) -{ - yylex_init_extra(state, scanner); - yy_scan_bytes(string, len, *scanner); -} - -void -_mesa_program_lexer_dtor(void *scanner) -{ - yylex_destroy(scanner); -} diff --git a/src/mesa/shader/program_parse.tab.c b/src/mesa/shader/program_parse.tab.c deleted file mode 100644 index 7da7226c32..0000000000 --- a/src/mesa/shader/program_parse.tab.c +++ /dev/null @@ -1,5729 +0,0 @@ - -/* A Bison parser, made by GNU Bison 2.4.1. */ - -/* Skeleton implementation for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Bison version. */ -#define YYBISON_VERSION "2.4.1" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 1 - -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 - -/* Using locations. */ -#define YYLSP_NEEDED 1 - - - -/* Copy the first part of user declarations. */ - -/* Line 189 of yacc.c */ -#line 1 "program_parse.y" - -/* - * Copyright © 2009 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#include -#include -#include - -#include "main/mtypes.h" -#include "main/imports.h" -#include "shader/program.h" -#include "shader/prog_parameter.h" -#include "shader/prog_parameter_layout.h" -#include "shader/prog_statevars.h" -#include "shader/prog_instruction.h" - -#include "shader/symbol_table.h" -#include "shader/program_parser.h" - -extern void *yy_scan_string(char *); -extern void yy_delete_buffer(void *); - -static struct asm_symbol *declare_variable(struct asm_parser_state *state, - char *name, enum asm_type t, struct YYLTYPE *locp); - -static int add_state_reference(struct gl_program_parameter_list *param_list, - const gl_state_index tokens[STATE_LENGTH]); - -static int initialize_symbol_from_state(struct gl_program *prog, - struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]); - -static int initialize_symbol_from_param(struct gl_program *prog, - struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]); - -static int initialize_symbol_from_const(struct gl_program *prog, - struct asm_symbol *param_var, const struct asm_vector *vec, - GLboolean allowSwizzle); - -static int yyparse(struct asm_parser_state *state); - -static char *make_error_string(const char *fmt, ...); - -static void yyerror(struct YYLTYPE *locp, struct asm_parser_state *state, - const char *s); - -static int validate_inputs(struct YYLTYPE *locp, - struct asm_parser_state *state); - -static void init_dst_reg(struct prog_dst_register *r); - -static void set_dst_reg(struct prog_dst_register *r, - gl_register_file file, GLint index); - -static void init_src_reg(struct asm_src_register *r); - -static void set_src_reg(struct asm_src_register *r, - gl_register_file file, GLint index); - -static void set_src_reg_swz(struct asm_src_register *r, - gl_register_file file, GLint index, GLuint swizzle); - -static void asm_instruction_set_operands(struct asm_instruction *inst, - const struct prog_dst_register *dst, const struct asm_src_register *src0, - const struct asm_src_register *src1, const struct asm_src_register *src2); - -static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op, - const struct prog_dst_register *dst, const struct asm_src_register *src0, - const struct asm_src_register *src1, const struct asm_src_register *src2); - -static struct asm_instruction *asm_instruction_copy_ctor( - const struct prog_instruction *base, const struct prog_dst_register *dst, - const struct asm_src_register *src0, const struct asm_src_register *src1, - const struct asm_src_register *src2); - -#ifndef FALSE -#define FALSE 0 -#define TRUE (!FALSE) -#endif - -#define YYLLOC_DEFAULT(Current, Rhs, N) \ - do { \ - if (YYID(N)) { \ - (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ - (Current).position = YYRHSLOC(Rhs, 1).position; \ - (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC(Rhs, N).last_column; \ - } else { \ - (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \ - (Current).last_line = (Current).first_line; \ - (Current).first_column = YYRHSLOC(Rhs, 0).last_column; \ - (Current).last_column = (Current).first_column; \ - (Current).position = YYRHSLOC(Rhs, 0).position \ - + (Current).first_column; \ - } \ - } while(YYID(0)) - -#define YYLEX_PARAM state->scanner - - -/* Line 189 of yacc.c */ -#line 193 "program_parse.tab.c" - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 1 -#endif - -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 -#endif - - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - ARBvp_10 = 258, - ARBfp_10 = 259, - ADDRESS = 260, - ALIAS = 261, - ATTRIB = 262, - OPTION = 263, - OUTPUT = 264, - PARAM = 265, - TEMP = 266, - END = 267, - BIN_OP = 268, - BINSC_OP = 269, - SAMPLE_OP = 270, - SCALAR_OP = 271, - TRI_OP = 272, - VECTOR_OP = 273, - ARL = 274, - KIL = 275, - SWZ = 276, - TXD_OP = 277, - INTEGER = 278, - REAL = 279, - AMBIENT = 280, - ATTENUATION = 281, - BACK = 282, - CLIP = 283, - COLOR = 284, - DEPTH = 285, - DIFFUSE = 286, - DIRECTION = 287, - EMISSION = 288, - ENV = 289, - EYE = 290, - FOG = 291, - FOGCOORD = 292, - FRAGMENT = 293, - FRONT = 294, - HALF = 295, - INVERSE = 296, - INVTRANS = 297, - LIGHT = 298, - LIGHTMODEL = 299, - LIGHTPROD = 300, - LOCAL = 301, - MATERIAL = 302, - MAT_PROGRAM = 303, - MATRIX = 304, - MATRIXINDEX = 305, - MODELVIEW = 306, - MVP = 307, - NORMAL = 308, - OBJECT = 309, - PALETTE = 310, - PARAMS = 311, - PLANE = 312, - POINT_TOK = 313, - POINTSIZE = 314, - POSITION = 315, - PRIMARY = 316, - PROGRAM = 317, - PROJECTION = 318, - RANGE = 319, - RESULT = 320, - ROW = 321, - SCENECOLOR = 322, - SECONDARY = 323, - SHININESS = 324, - SIZE_TOK = 325, - SPECULAR = 326, - SPOT = 327, - STATE = 328, - TEXCOORD = 329, - TEXENV = 330, - TEXGEN = 331, - TEXGEN_Q = 332, - TEXGEN_R = 333, - TEXGEN_S = 334, - TEXGEN_T = 335, - TEXTURE = 336, - TRANSPOSE = 337, - TEXTURE_UNIT = 338, - TEX_1D = 339, - TEX_2D = 340, - TEX_3D = 341, - TEX_CUBE = 342, - TEX_RECT = 343, - TEX_SHADOW1D = 344, - TEX_SHADOW2D = 345, - TEX_SHADOWRECT = 346, - TEX_ARRAY1D = 347, - TEX_ARRAY2D = 348, - TEX_ARRAYSHADOW1D = 349, - TEX_ARRAYSHADOW2D = 350, - VERTEX = 351, - VTXATTRIB = 352, - WEIGHT = 353, - IDENTIFIER = 354, - USED_IDENTIFIER = 355, - MASK4 = 356, - MASK3 = 357, - MASK2 = 358, - MASK1 = 359, - SWIZZLE = 360, - DOT_DOT = 361, - DOT = 362 - }; -#endif - - - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -{ - -/* Line 214 of yacc.c */ -#line 126 "program_parse.y" - - struct asm_instruction *inst; - struct asm_symbol *sym; - struct asm_symbol temp_sym; - struct asm_swizzle_mask swiz_mask; - struct asm_src_register src_reg; - struct prog_dst_register dst_reg; - struct prog_instruction temp_inst; - char *string; - unsigned result; - unsigned attrib; - int integer; - float real; - gl_state_index state[STATE_LENGTH]; - int negate; - struct asm_vector vector; - gl_inst_opcode opcode; - - struct { - unsigned swz; - unsigned rgba_valid:1; - unsigned xyzw_valid:1; - unsigned negate:1; - } ext_swizzle; - - - -/* Line 214 of yacc.c */ -#line 364 "program_parse.tab.c" -} YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -#endif - -#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE -{ - int first_line; - int first_column; - int last_line; - int last_column; -} YYLTYPE; -# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ -# define YYLTYPE_IS_DECLARED 1 -# define YYLTYPE_IS_TRIVIAL 1 -#endif - - -/* Copy the second part of user declarations. */ - -/* Line 264 of yacc.c */ -#line 271 "program_parse.y" - -extern int yylex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param, - void *yyscanner); - - -/* Line 264 of yacc.c */ -#line 395 "program_parse.tab.c" - -#ifdef short -# undef short -#endif - -#ifdef YYTYPE_UINT8 -typedef YYTYPE_UINT8 yytype_uint8; -#else -typedef unsigned char yytype_uint8; -#endif - -#ifdef YYTYPE_INT8 -typedef YYTYPE_INT8 yytype_int8; -#elif (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -typedef signed char yytype_int8; -#else -typedef short int yytype_int8; -#endif - -#ifdef YYTYPE_UINT16 -typedef YYTYPE_UINT16 yytype_uint16; -#else -typedef unsigned short int yytype_uint16; -#endif - -#ifdef YYTYPE_INT16 -typedef YYTYPE_INT16 yytype_int16; -#else -typedef short int yytype_int16; -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned int -# endif -#endif - -#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) - -#ifndef YY_ -# if YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(msgid) dgettext ("bison-runtime", msgid) -# endif -# endif -# ifndef YY_ -# define YY_(msgid) msgid -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YYUSE(e) ((void) (e)) -#else -# define YYUSE(e) /* empty */ -#endif - -/* Identity function, used to suppress warnings about constant conditions. */ -#ifndef lint -# define YYID(n) (n) -#else -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static int -YYID (int yyi) -#else -static int -YYID (yyi) - int yyi; -#endif -{ - return yyi; -} -#endif - -#if ! defined yyoverflow || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined _STDLIB_H \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ - - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ - && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yytype_int16 yyss_alloc; - YYSTYPE yyvs_alloc; - YYLTYPE yyls_alloc; -}; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ - + 2 * YYSTACK_GAP_MAXIMUM) - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (YYID (0)) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (YYID (0)) - -#endif - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 5 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 396 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 120 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 143 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 282 -/* YYNRULES -- Number of states. */ -#define YYNSTATES 475 - -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 362 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ -static const yytype_uint8 yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 115, 116, 2, 113, 109, 114, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 108, - 2, 117, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 111, 2, 112, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 118, 110, 119, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107 -}; - -#if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const yytype_uint16 yyprhs[] = -{ - 0, 0, 3, 8, 10, 12, 15, 16, 20, 23, - 24, 27, 30, 32, 34, 36, 38, 40, 42, 44, - 46, 48, 50, 52, 54, 59, 64, 69, 76, 83, - 92, 101, 104, 107, 120, 123, 125, 127, 129, 131, - 133, 135, 137, 139, 141, 143, 145, 147, 154, 157, - 162, 165, 167, 171, 177, 181, 184, 192, 195, 197, - 199, 201, 203, 208, 210, 212, 214, 216, 218, 220, - 222, 226, 227, 230, 233, 235, 237, 239, 241, 243, - 245, 247, 249, 251, 252, 254, 256, 258, 260, 261, - 265, 269, 270, 273, 276, 278, 280, 282, 284, 286, - 288, 290, 292, 297, 300, 303, 305, 308, 310, 313, - 315, 318, 323, 328, 330, 331, 335, 337, 339, 342, - 344, 347, 349, 351, 355, 362, 363, 365, 368, 373, - 375, 379, 381, 383, 385, 387, 389, 391, 393, 395, - 397, 399, 402, 405, 408, 411, 414, 417, 420, 423, - 426, 429, 432, 435, 439, 441, 443, 445, 451, 453, - 455, 457, 460, 462, 464, 467, 469, 472, 479, 481, - 485, 487, 489, 491, 493, 495, 500, 502, 504, 506, - 508, 510, 512, 515, 517, 519, 525, 527, 530, 532, - 534, 540, 543, 544, 551, 555, 556, 558, 560, 562, - 564, 566, 569, 571, 573, 576, 581, 586, 587, 591, - 593, 595, 597, 600, 602, 604, 606, 608, 614, 616, - 620, 626, 632, 634, 638, 644, 646, 648, 650, 652, - 654, 656, 658, 660, 662, 666, 672, 680, 690, 693, - 696, 698, 700, 701, 702, 707, 709, 710, 711, 715, - 719, 721, 727, 730, 733, 736, 739, 743, 746, 750, - 751, 753, 755, 756, 758, 760, 761, 763, 765, 766, - 768, 770, 771, 775, 776, 780, 781, 785, 787, 789, - 791, 796, 798 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yytype_int16 yyrhs[] = -{ - 121, 0, -1, 122, 123, 125, 12, -1, 3, -1, - 4, -1, 123, 124, -1, -1, 8, 262, 108, -1, - 125, 126, -1, -1, 127, 108, -1, 170, 108, -1, - 128, -1, 129, -1, 130, -1, 131, -1, 132, -1, - 133, -1, 134, -1, 135, -1, 141, -1, 136, -1, - 137, -1, 138, -1, 19, 146, 109, 142, -1, 18, - 145, 109, 144, -1, 16, 145, 109, 142, -1, 14, - 145, 109, 142, 109, 142, -1, 13, 145, 109, 144, - 109, 144, -1, 17, 145, 109, 144, 109, 144, 109, - 144, -1, 15, 145, 109, 144, 109, 139, 109, 140, - -1, 20, 144, -1, 20, 166, -1, 22, 145, 109, - 144, 109, 144, 109, 144, 109, 139, 109, 140, -1, - 83, 256, -1, 84, -1, 85, -1, 86, -1, 87, - -1, 88, -1, 89, -1, 90, -1, 91, -1, 92, - -1, 93, -1, 94, -1, 95, -1, 21, 145, 109, - 150, 109, 147, -1, 241, 143, -1, 241, 110, 143, - 110, -1, 150, 162, -1, 238, -1, 241, 150, 163, - -1, 241, 110, 150, 163, 110, -1, 151, 164, 165, - -1, 159, 161, -1, 148, 109, 148, 109, 148, 109, - 148, -1, 241, 149, -1, 23, -1, 262, -1, 100, - -1, 172, -1, 152, 111, 153, 112, -1, 186, -1, - 249, -1, 100, -1, 100, -1, 154, -1, 155, -1, - 23, -1, 159, 160, 156, -1, -1, 113, 157, -1, - 114, 158, -1, 23, -1, 23, -1, 100, -1, 104, - -1, 104, -1, 104, -1, 104, -1, 101, -1, 105, - -1, -1, 101, -1, 102, -1, 103, -1, 104, -1, - -1, 115, 166, 116, -1, 115, 167, 116, -1, -1, - 168, 163, -1, 169, 163, -1, 99, -1, 100, -1, - 171, -1, 178, -1, 242, -1, 245, -1, 248, -1, - 261, -1, 7, 99, 117, 172, -1, 96, 173, -1, - 38, 177, -1, 60, -1, 98, 175, -1, 53, -1, - 29, 254, -1, 37, -1, 74, 255, -1, 50, 111, - 176, 112, -1, 97, 111, 174, 112, -1, 23, -1, - -1, 111, 176, 112, -1, 23, -1, 60, -1, 29, - 254, -1, 37, -1, 74, 255, -1, 179, -1, 180, - -1, 10, 99, 182, -1, 10, 99, 111, 181, 112, - 183, -1, -1, 23, -1, 117, 185, -1, 117, 118, - 184, 119, -1, 187, -1, 184, 109, 187, -1, 189, - -1, 225, -1, 235, -1, 189, -1, 225, -1, 236, - -1, 188, -1, 226, -1, 235, -1, 189, -1, 73, - 213, -1, 73, 190, -1, 73, 192, -1, 73, 195, - -1, 73, 197, -1, 73, 203, -1, 73, 199, -1, - 73, 206, -1, 73, 208, -1, 73, 210, -1, 73, - 212, -1, 73, 224, -1, 47, 253, 191, -1, 201, - -1, 33, -1, 69, -1, 43, 111, 202, 112, 193, - -1, 201, -1, 60, -1, 26, -1, 72, 194, -1, - 40, -1, 32, -1, 44, 196, -1, 25, -1, 253, - 67, -1, 45, 111, 202, 112, 253, 198, -1, 201, - -1, 75, 257, 200, -1, 29, -1, 25, -1, 31, - -1, 71, -1, 23, -1, 76, 255, 204, 205, -1, - 35, -1, 54, -1, 79, -1, 80, -1, 78, -1, - 77, -1, 36, 207, -1, 29, -1, 56, -1, 28, - 111, 209, 112, 57, -1, 23, -1, 58, 211, -1, - 70, -1, 26, -1, 215, 66, 111, 218, 112, -1, - 215, 214, -1, -1, 66, 111, 218, 106, 218, 112, - -1, 49, 219, 216, -1, -1, 217, -1, 41, -1, - 82, -1, 42, -1, 23, -1, 51, 220, -1, 63, - -1, 52, -1, 81, 255, -1, 55, 111, 222, 112, - -1, 48, 111, 223, 112, -1, -1, 111, 221, 112, - -1, 23, -1, 23, -1, 23, -1, 30, 64, -1, - 229, -1, 232, -1, 227, -1, 230, -1, 62, 34, - 111, 228, 112, -1, 233, -1, 233, 106, 233, -1, - 62, 34, 111, 233, 112, -1, 62, 46, 111, 231, - 112, -1, 234, -1, 234, 106, 234, -1, 62, 46, - 111, 234, 112, -1, 23, -1, 23, -1, 237, -1, - 239, -1, 238, -1, 239, -1, 240, -1, 24, -1, - 23, -1, 118, 240, 119, -1, 118, 240, 109, 240, - 119, -1, 118, 240, 109, 240, 109, 240, 119, -1, - 118, 240, 109, 240, 109, 240, 109, 240, 119, -1, - 241, 24, -1, 241, 23, -1, 113, -1, 114, -1, - -1, -1, 244, 11, 243, 247, -1, 262, -1, -1, - -1, 5, 246, 247, -1, 247, 109, 99, -1, 99, - -1, 244, 9, 99, 117, 249, -1, 65, 60, -1, - 65, 37, -1, 65, 250, -1, 65, 59, -1, 65, - 74, 255, -1, 65, 30, -1, 29, 251, 252, -1, - -1, 39, -1, 27, -1, -1, 61, -1, 68, -1, - -1, 39, -1, 27, -1, -1, 61, -1, 68, -1, - -1, 111, 258, 112, -1, -1, 111, 259, 112, -1, - -1, 111, 260, 112, -1, 23, -1, 23, -1, 23, - -1, 6, 99, 117, 100, -1, 99, -1, 100, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const yytype_uint16 yyrline[] = -{ - 0, 278, 278, 281, 289, 301, 302, 305, 329, 330, - 333, 348, 351, 356, 363, 364, 365, 366, 367, 368, - 369, 372, 373, 374, 377, 383, 389, 395, 402, 408, - 415, 459, 464, 474, 518, 524, 525, 526, 527, 528, - 529, 530, 531, 532, 533, 534, 535, 538, 550, 558, - 575, 582, 601, 612, 632, 657, 664, 697, 704, 719, - 774, 817, 826, 847, 857, 861, 890, 909, 909, 911, - 918, 930, 931, 932, 935, 949, 963, 983, 994, 1006, - 1008, 1009, 1010, 1011, 1014, 1014, 1014, 1014, 1015, 1018, - 1022, 1027, 1034, 1041, 1048, 1071, 1094, 1095, 1096, 1097, - 1098, 1099, 1102, 1121, 1125, 1131, 1135, 1139, 1143, 1152, - 1161, 1165, 1170, 1176, 1187, 1187, 1188, 1190, 1194, 1198, - 1202, 1208, 1208, 1210, 1228, 1254, 1257, 1268, 1274, 1280, - 1281, 1288, 1294, 1300, 1308, 1314, 1320, 1328, 1334, 1340, - 1348, 1349, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, - 1360, 1361, 1362, 1365, 1374, 1378, 1382, 1388, 1397, 1401, - 1405, 1414, 1418, 1424, 1430, 1437, 1442, 1450, 1460, 1462, - 1470, 1476, 1480, 1484, 1490, 1501, 1510, 1514, 1519, 1523, - 1527, 1531, 1537, 1544, 1548, 1554, 1562, 1573, 1580, 1584, - 1590, 1600, 1611, 1615, 1633, 1642, 1645, 1651, 1655, 1659, - 1665, 1676, 1681, 1686, 1691, 1696, 1701, 1709, 1712, 1717, - 1730, 1738, 1749, 1757, 1757, 1759, 1759, 1761, 1771, 1776, - 1783, 1793, 1802, 1807, 1814, 1824, 1834, 1846, 1846, 1847, - 1847, 1849, 1859, 1867, 1877, 1885, 1893, 1902, 1913, 1917, - 1923, 1924, 1925, 1928, 1928, 1931, 1966, 1970, 1970, 1973, - 1980, 1989, 2003, 2012, 2021, 2025, 2034, 2043, 2054, 2061, - 2066, 2075, 2087, 2090, 2099, 2110, 2111, 2112, 2115, 2116, - 2117, 2120, 2121, 2124, 2125, 2128, 2129, 2132, 2143, 2154, - 2165, 2191, 2192 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "$end", "error", "$undefined", "ARBvp_10", "ARBfp_10", "ADDRESS", - "ALIAS", "ATTRIB", "OPTION", "OUTPUT", "PARAM", "TEMP", "END", "BIN_OP", - "BINSC_OP", "SAMPLE_OP", "SCALAR_OP", "TRI_OP", "VECTOR_OP", "ARL", - "KIL", "SWZ", "TXD_OP", "INTEGER", "REAL", "AMBIENT", "ATTENUATION", - "BACK", "CLIP", "COLOR", "DEPTH", "DIFFUSE", "DIRECTION", "EMISSION", - "ENV", "EYE", "FOG", "FOGCOORD", "FRAGMENT", "FRONT", "HALF", "INVERSE", - "INVTRANS", "LIGHT", "LIGHTMODEL", "LIGHTPROD", "LOCAL", "MATERIAL", - "MAT_PROGRAM", "MATRIX", "MATRIXINDEX", "MODELVIEW", "MVP", "NORMAL", - "OBJECT", "PALETTE", "PARAMS", "PLANE", "POINT_TOK", "POINTSIZE", - "POSITION", "PRIMARY", "PROGRAM", "PROJECTION", "RANGE", "RESULT", "ROW", - "SCENECOLOR", "SECONDARY", "SHININESS", "SIZE_TOK", "SPECULAR", "SPOT", - "STATE", "TEXCOORD", "TEXENV", "TEXGEN", "TEXGEN_Q", "TEXGEN_R", - "TEXGEN_S", "TEXGEN_T", "TEXTURE", "TRANSPOSE", "TEXTURE_UNIT", "TEX_1D", - "TEX_2D", "TEX_3D", "TEX_CUBE", "TEX_RECT", "TEX_SHADOW1D", - "TEX_SHADOW2D", "TEX_SHADOWRECT", "TEX_ARRAY1D", "TEX_ARRAY2D", - "TEX_ARRAYSHADOW1D", "TEX_ARRAYSHADOW2D", "VERTEX", "VTXATTRIB", - "WEIGHT", "IDENTIFIER", "USED_IDENTIFIER", "MASK4", "MASK3", "MASK2", - "MASK1", "SWIZZLE", "DOT_DOT", "DOT", "';'", "','", "'|'", "'['", "']'", - "'+'", "'-'", "'('", "')'", "'='", "'{'", "'}'", "$accept", "program", - "language", "optionSequence", "option", "statementSequence", "statement", - "instruction", "ALU_instruction", "TexInstruction", "ARL_instruction", - "VECTORop_instruction", "SCALARop_instruction", "BINSCop_instruction", - "BINop_instruction", "TRIop_instruction", "SAMPLE_instruction", - "KIL_instruction", "TXD_instruction", "texImageUnit", "texTarget", - "SWZ_instruction", "scalarSrcReg", "scalarUse", "swizzleSrcReg", - "maskedDstReg", "maskedAddrReg", "extendedSwizzle", "extSwizComp", - "extSwizSel", "srcReg", "dstReg", "progParamArray", "progParamArrayMem", - "progParamArrayAbs", "progParamArrayRel", "addrRegRelOffset", - "addrRegPosOffset", "addrRegNegOffset", "addrReg", "addrComponent", - "addrWriteMask", "scalarSuffix", "swizzleSuffix", "optionalMask", - "optionalCcMask", "ccTest", "ccTest2", "ccMaskRule", "ccMaskRule2", - "namingStatement", "ATTRIB_statement", "attribBinding", "vtxAttribItem", - "vtxAttribNum", "vtxOptWeightNum", "vtxWeightNum", "fragAttribItem", - "PARAM_statement", "PARAM_singleStmt", "PARAM_multipleStmt", - "optArraySize", "paramSingleInit", "paramMultipleInit", - "paramMultInitList", "paramSingleItemDecl", "paramSingleItemUse", - "paramMultipleItem", "stateMultipleItem", "stateSingleItem", - "stateMaterialItem", "stateMatProperty", "stateLightItem", - "stateLightProperty", "stateSpotProperty", "stateLightModelItem", - "stateLModProperty", "stateLightProdItem", "stateLProdProperty", - "stateTexEnvItem", "stateTexEnvProperty", "ambDiffSpecProperty", - "stateLightNumber", "stateTexGenItem", "stateTexGenType", - "stateTexGenCoord", "stateFogItem", "stateFogProperty", - "stateClipPlaneItem", "stateClipPlaneNum", "statePointItem", - "statePointProperty", "stateMatrixRow", "stateMatrixRows", - "optMatrixRows", "stateMatrixItem", "stateOptMatModifier", - "stateMatModifier", "stateMatrixRowNum", "stateMatrixName", - "stateOptModMatNum", "stateModMatNum", "statePaletteMatNum", - "stateProgramMatNum", "stateDepthItem", "programSingleItem", - "programMultipleItem", "progEnvParams", "progEnvParamNums", - "progEnvParam", "progLocalParams", "progLocalParamNums", - "progLocalParam", "progEnvParamNum", "progLocalParamNum", - "paramConstDecl", "paramConstUse", "paramConstScalarDecl", - "paramConstScalarUse", "paramConstVector", "signedFloatConstant", - "optionalSign", "TEMP_statement", "@1", "optVarSize", - "ADDRESS_statement", "@2", "varNameList", "OUTPUT_statement", - "resultBinding", "resultColBinding", "optResultFaceType", - "optResultColorType", "optFaceType", "optColorType", - "optTexCoordUnitNum", "optTexImageUnitNum", "optLegacyTexUnitNum", - "texCoordUnitNum", "texImageUnitNum", "legacyTexUnitNum", - "ALIAS_statement", "string", 0 -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ -static const yytype_uint16 yytoknum[] = -{ - 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 362, 59, 44, - 124, 91, 93, 43, 45, 40, 41, 61, 123, 125 -}; -# endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint16 yyr1[] = -{ - 0, 120, 121, 122, 122, 123, 123, 124, 125, 125, - 126, 126, 127, 127, 128, 128, 128, 128, 128, 128, - 128, 129, 129, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 137, 138, 139, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 141, 142, 142, - 143, 143, 144, 144, 145, 146, 147, 148, 149, 149, - 150, 150, 150, 150, 151, 151, 152, 153, 153, 154, - 155, 156, 156, 156, 157, 158, 159, 160, 161, 162, - 163, 163, 163, 163, 164, 164, 164, 164, 164, 165, - 165, 165, 166, 167, 168, 169, 170, 170, 170, 170, - 170, 170, 171, 172, 172, 173, 173, 173, 173, 173, - 173, 173, 173, 174, 175, 175, 176, 177, 177, 177, - 177, 178, 178, 179, 180, 181, 181, 182, 183, 184, - 184, 185, 185, 185, 186, 186, 186, 187, 187, 187, - 188, 188, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 190, 191, 191, 191, 192, 193, 193, - 193, 193, 193, 194, 195, 196, 196, 197, 198, 199, - 200, 201, 201, 201, 202, 203, 204, 204, 205, 205, - 205, 205, 206, 207, 207, 208, 209, 210, 211, 211, - 212, 213, 214, 214, 215, 216, 216, 217, 217, 217, - 218, 219, 219, 219, 219, 219, 219, 220, 220, 221, - 222, 223, 224, 225, 225, 226, 226, 227, 228, 228, - 229, 230, 231, 231, 232, 233, 234, 235, 235, 236, - 236, 237, 238, 238, 239, 239, 239, 239, 240, 240, - 241, 241, 241, 243, 242, 244, 244, 246, 245, 247, - 247, 248, 249, 249, 249, 249, 249, 249, 250, 251, - 251, 251, 252, 252, 252, 253, 253, 253, 254, 254, - 254, 255, 255, 256, 256, 257, 257, 258, 259, 260, - 261, 262, 262 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = -{ - 0, 2, 4, 1, 1, 2, 0, 3, 2, 0, - 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 4, 4, 4, 6, 6, 8, - 8, 2, 2, 12, 2, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 6, 2, 4, - 2, 1, 3, 5, 3, 2, 7, 2, 1, 1, - 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, - 3, 0, 2, 2, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 1, 1, 1, 1, 0, 3, - 3, 0, 2, 2, 1, 1, 1, 1, 1, 1, - 1, 1, 4, 2, 2, 1, 2, 1, 2, 1, - 2, 4, 4, 1, 0, 3, 1, 1, 2, 1, - 2, 1, 1, 3, 6, 0, 1, 2, 4, 1, - 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 3, 1, 1, 1, 5, 1, 1, - 1, 2, 1, 1, 2, 1, 2, 6, 1, 3, - 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, - 1, 1, 2, 1, 1, 5, 1, 2, 1, 1, - 5, 2, 0, 6, 3, 0, 1, 1, 1, 1, - 1, 2, 1, 1, 2, 4, 4, 0, 3, 1, - 1, 1, 2, 1, 1, 1, 1, 5, 1, 3, - 5, 5, 1, 3, 5, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 5, 7, 9, 2, 2, - 1, 1, 0, 0, 4, 1, 0, 0, 3, 3, - 1, 5, 2, 2, 2, 2, 3, 2, 3, 0, - 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, - 1, 0, 3, 0, 3, 0, 3, 1, 1, 1, - 4, 1, 1 -}; - -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ -static const yytype_uint16 yydefact[] = -{ - 0, 3, 4, 0, 6, 1, 9, 0, 5, 246, - 281, 282, 0, 247, 0, 0, 0, 2, 0, 0, - 0, 0, 0, 0, 0, 242, 0, 0, 8, 0, - 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, - 23, 20, 0, 96, 97, 121, 122, 98, 0, 99, - 100, 101, 245, 7, 0, 0, 0, 0, 0, 65, - 0, 88, 64, 0, 0, 0, 0, 0, 76, 0, - 0, 94, 240, 241, 31, 32, 83, 0, 0, 0, - 10, 11, 0, 243, 250, 248, 0, 0, 125, 242, - 123, 259, 257, 253, 255, 252, 271, 254, 242, 84, - 85, 86, 87, 91, 242, 242, 242, 242, 242, 242, - 78, 55, 81, 80, 82, 92, 233, 232, 0, 0, - 0, 0, 60, 0, 242, 83, 0, 61, 63, 134, - 135, 213, 214, 136, 229, 230, 0, 242, 0, 0, - 0, 280, 102, 126, 0, 127, 131, 132, 133, 227, - 228, 231, 0, 261, 260, 262, 0, 256, 0, 0, - 54, 0, 0, 0, 26, 0, 25, 24, 268, 119, - 117, 271, 104, 0, 0, 0, 0, 0, 0, 265, - 0, 265, 0, 0, 275, 271, 142, 143, 144, 145, - 147, 146, 148, 149, 150, 151, 0, 152, 268, 109, - 0, 107, 105, 271, 0, 114, 103, 83, 0, 52, - 0, 0, 0, 0, 244, 249, 0, 239, 238, 263, - 264, 258, 277, 0, 242, 95, 0, 0, 83, 242, - 0, 48, 0, 51, 0, 242, 269, 270, 118, 120, - 0, 0, 0, 212, 183, 184, 182, 0, 165, 267, - 266, 164, 0, 0, 0, 0, 207, 203, 0, 202, - 271, 195, 189, 188, 187, 0, 0, 0, 0, 108, - 0, 110, 0, 0, 106, 0, 242, 234, 69, 0, - 67, 68, 0, 242, 242, 251, 0, 124, 272, 28, - 89, 90, 93, 27, 0, 79, 50, 273, 0, 0, - 225, 0, 226, 0, 186, 0, 174, 0, 166, 0, - 171, 172, 155, 156, 173, 153, 154, 0, 0, 201, - 0, 204, 197, 199, 198, 194, 196, 279, 0, 170, - 169, 176, 177, 0, 0, 116, 0, 113, 0, 0, - 53, 0, 62, 77, 71, 47, 0, 0, 0, 242, - 49, 0, 34, 0, 242, 220, 224, 0, 0, 265, - 211, 0, 209, 0, 210, 0, 276, 181, 180, 178, - 179, 175, 200, 0, 111, 112, 115, 242, 235, 0, - 0, 70, 242, 58, 57, 59, 242, 0, 0, 0, - 129, 137, 140, 138, 215, 216, 139, 278, 0, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 30, 29, 185, 160, 162, 159, 0, 157, 158, - 0, 206, 208, 205, 190, 0, 74, 72, 75, 73, - 0, 0, 0, 0, 141, 192, 242, 128, 274, 163, - 161, 167, 168, 242, 236, 242, 0, 0, 0, 0, - 191, 130, 0, 0, 0, 0, 218, 0, 222, 0, - 237, 242, 0, 217, 0, 221, 0, 0, 56, 33, - 219, 223, 0, 0, 193 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - -1, 3, 4, 6, 8, 9, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 298, - 411, 41, 161, 231, 74, 60, 69, 345, 346, 384, - 232, 61, 126, 279, 280, 281, 381, 427, 429, 70, - 344, 111, 296, 115, 103, 160, 75, 227, 76, 228, - 42, 43, 127, 206, 338, 274, 336, 172, 44, 45, - 46, 144, 90, 287, 389, 145, 128, 390, 391, 129, - 186, 315, 187, 418, 440, 188, 251, 189, 441, 190, - 330, 316, 307, 191, 333, 371, 192, 246, 193, 305, - 194, 264, 195, 434, 450, 196, 325, 326, 373, 261, - 319, 363, 365, 361, 197, 130, 393, 394, 455, 131, - 395, 457, 132, 301, 303, 396, 133, 149, 134, 135, - 151, 77, 47, 139, 48, 49, 54, 85, 50, 62, - 97, 155, 221, 252, 238, 157, 352, 266, 223, 398, - 328, 51, 12 -}; - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -401 -static const yytype_int16 yypact[] = -{ - 193, -401, -401, 27, -401, -401, 62, 143, -401, 24, - -401, -401, -30, -401, -18, 12, 83, -401, 15, 15, - 15, 15, 15, 15, 67, 61, 15, 15, -401, 127, - -401, -401, -401, -401, -401, -401, -401, -401, -401, -401, - -401, -401, 144, -401, -401, -401, -401, -401, 204, -401, - -401, -401, -401, -401, 155, 136, 138, 34, 140, -401, - 147, 108, -401, 150, 156, 157, 158, 160, -401, 162, - 159, -401, -401, -401, -401, -401, 102, -13, 163, 164, - -401, -401, 165, -401, -401, 166, 170, 10, 235, 0, - -401, 141, -401, -401, -401, -401, 167, -401, 131, -401, - -401, -401, -401, 168, 131, 131, 131, 131, 131, 131, - -401, -401, -401, -401, -401, -401, -401, -401, 104, 97, - 114, 38, 169, 30, 131, 102, 171, -401, -401, -401, - -401, -401, -401, -401, -401, -401, 30, 131, 172, 155, - 175, -401, -401, -401, 173, -401, -401, -401, -401, -401, - -401, -401, 223, -401, -401, 123, 253, -401, 177, 149, - -401, 178, -10, 181, -401, 182, -401, -401, 134, -401, - -401, 167, -401, 183, 184, 185, 213, 99, 186, 154, - 187, 146, 153, 7, 188, 167, -401, -401, -401, -401, - -401, -401, -401, -401, -401, -401, 215, -401, 134, -401, - 190, -401, -401, 167, 191, 192, -401, 102, -48, -401, - 1, 195, 196, 214, 166, -401, 189, -401, -401, -401, - -401, -401, -401, 180, 131, -401, 194, 197, 102, 131, - 30, -401, 203, 205, 201, 131, -401, -401, -401, -401, - 285, 288, 289, -401, -401, -401, -401, 291, -401, -401, - -401, -401, 248, 291, 33, 206, 207, -401, 208, -401, - 167, 14, -401, -401, -401, 293, 292, 92, 209, -401, - 299, -401, 301, 299, -401, 216, 131, -401, -401, 217, - -401, -401, 221, 131, 131, -401, 212, -401, -401, -401, - -401, -401, -401, -401, 218, -401, -401, 220, 224, 225, - -401, 226, -401, 227, -401, 228, -401, 230, -401, 231, - -401, -401, -401, -401, -401, -401, -401, 304, 309, -401, - 312, -401, -401, -401, -401, -401, -401, -401, 232, -401, - -401, -401, -401, 161, 313, -401, 233, -401, 234, 238, - -401, 13, -401, -401, 137, -401, 242, -15, 243, 3, - -401, 314, -401, 133, 131, -401, -401, 296, 94, 146, - -401, 245, -401, 246, -401, 247, -401, -401, -401, -401, - -401, -401, -401, 249, -401, -401, -401, 131, -401, 332, - 337, -401, 131, -401, -401, -401, 131, 142, 114, 28, - -401, -401, -401, -401, -401, -401, -401, -401, 250, -401, - -401, -401, -401, -401, -401, -401, -401, -401, -401, -401, - -401, -401, -401, -401, -401, -401, -401, 331, -401, -401, - 68, -401, -401, -401, -401, 43, -401, -401, -401, -401, - 255, 256, 257, 258, -401, 300, 3, -401, -401, -401, - -401, -401, -401, 131, -401, 131, 201, 285, 288, 259, - -401, -401, 252, 264, 265, 263, 261, 266, 270, 313, - -401, 131, 133, -401, 285, -401, 288, 80, -401, -401, - -401, -401, 313, 267, -401 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -401, -401, -401, -401, -401, -401, -401, -401, -401, -401, - -401, -401, -401, -401, -401, -401, -401, -401, -401, -69, - -82, -401, -100, 151, -86, 210, -401, -401, -366, -401, - -54, -401, -401, -401, -401, -401, -401, -401, -401, 174, - -401, -401, -401, -118, -401, -401, 229, -401, -401, -401, - -401, -401, 295, -401, -401, -401, 110, -401, -401, -401, - -401, -401, -401, -401, -401, -401, -401, -51, -401, -88, - -401, -401, -401, -401, -401, -401, -401, -401, -401, -401, - -401, -311, 139, -401, -401, -401, -401, -401, -401, -401, - -401, -401, -401, -401, -401, -2, -401, -401, -400, -401, - -401, -401, -401, -401, -401, 298, -401, -401, -401, -401, - -401, -401, -401, -390, -295, 302, -401, -401, -136, -87, - -120, -89, -401, -401, -401, -401, -401, 251, -401, 176, - -401, -401, -401, -176, 198, -153, -401, -401, -401, -401, - -401, -401, -6 -}; - -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -230 -static const yytype_int16 yytable[] = -{ - 152, 146, 150, 52, 208, 254, 164, 209, 383, 167, - 116, 117, 158, 116, 117, 162, 430, 162, 239, 163, - 162, 165, 166, 125, 278, 118, 233, 5, 118, 13, - 14, 15, 267, 262, 16, 152, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 419, 118, 119, - 271, 212, 119, 116, 117, 322, 323, 456, 310, 467, - 120, 276, 119, 120, 311, 387, 312, 198, 118, 207, - 7, 277, 473, 120, 470, 199, 388, 263, 53, 453, - 58, 55, 211, 121, 10, 11, 121, 122, 200, 275, - 122, 201, 119, 310, 233, 468, 324, 123, 202, 311, - 230, 68, 313, 120, 314, 124, 121, 321, 124, 442, - 292, 56, 203, 72, 73, 59, 72, 73, 124, 310, - 414, 124, 377, 10, 11, 311, 121, 331, 244, 293, - 122, 173, 378, 168, 415, 204, 205, 436, 289, 314, - 162, 169, 175, 174, 176, 88, 332, 437, 124, 299, - 177, 89, 443, 458, 416, 245, 341, 178, 179, 180, - 71, 181, 444, 182, 170, 314, 417, 68, 153, 91, - 92, 471, 183, 249, 72, 73, 432, 93, 171, 248, - 154, 249, 57, 420, 219, 250, 472, 152, 433, 184, - 185, 220, 424, 250, 347, 236, 1, 2, 348, 94, - 95, 255, 237, 112, 256, 257, 113, 114, 258, 99, - 100, 101, 102, 82, 96, 83, 259, 399, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 63, - 64, 65, 66, 67, 260, 80, 78, 79, 367, 368, - 369, 370, 10, 11, 72, 73, 217, 218, 71, 225, - 379, 380, 81, 86, 84, 87, 98, 425, 143, 104, - 152, 392, 150, 110, 138, 105, 106, 107, 412, 108, - 141, 109, 136, 137, 215, 140, 222, 243, 156, 58, - -66, 268, 210, 159, 297, 216, 224, 229, 152, 213, - 234, 235, 288, 347, 240, 241, 242, 247, 253, 265, - 431, 270, 272, 273, 283, 284, 286, 295, 300, -229, - 290, 302, 304, 291, 306, 308, 327, 317, 318, 320, - 334, 329, 335, 452, 337, 343, 340, 360, 350, 342, - 349, 351, 362, 353, 354, 364, 372, 397, 355, 356, - 357, 385, 358, 359, 366, 374, 375, 152, 392, 150, - 376, 382, 386, 413, 152, 426, 347, 421, 422, 423, - 428, 424, 438, 439, 445, 446, 449, 464, 447, 448, - 459, 460, 347, 461, 462, 463, 466, 454, 465, 474, - 469, 294, 142, 339, 282, 451, 435, 147, 226, 285, - 214, 148, 309, 0, 0, 0, 269 -}; - -static const yytype_int16 yycheck[] = -{ - 89, 89, 89, 9, 124, 181, 106, 125, 23, 109, - 23, 24, 98, 23, 24, 104, 382, 106, 171, 105, - 109, 107, 108, 77, 23, 38, 162, 0, 38, 5, - 6, 7, 185, 26, 10, 124, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 358, 38, 62, - 203, 137, 62, 23, 24, 41, 42, 447, 25, 459, - 73, 109, 62, 73, 31, 62, 33, 29, 38, 123, - 8, 119, 472, 73, 464, 37, 73, 70, 108, 445, - 65, 99, 136, 96, 99, 100, 96, 100, 50, 207, - 100, 53, 62, 25, 230, 461, 82, 110, 60, 31, - 110, 100, 69, 73, 71, 118, 96, 260, 118, 420, - 228, 99, 74, 113, 114, 100, 113, 114, 118, 25, - 26, 118, 109, 99, 100, 31, 96, 35, 29, 229, - 100, 34, 119, 29, 40, 97, 98, 109, 224, 71, - 229, 37, 28, 46, 30, 111, 54, 119, 118, 235, - 36, 117, 109, 448, 60, 56, 276, 43, 44, 45, - 99, 47, 119, 49, 60, 71, 72, 100, 27, 29, - 30, 466, 58, 27, 113, 114, 34, 37, 74, 25, - 39, 27, 99, 359, 61, 39, 106, 276, 46, 75, - 76, 68, 112, 39, 283, 61, 3, 4, 284, 59, - 60, 48, 68, 101, 51, 52, 104, 105, 55, 101, - 102, 103, 104, 9, 74, 11, 63, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 19, - 20, 21, 22, 23, 81, 108, 26, 27, 77, 78, - 79, 80, 99, 100, 113, 114, 23, 24, 99, 100, - 113, 114, 108, 117, 99, 117, 109, 377, 23, 109, - 349, 349, 349, 104, 99, 109, 109, 109, 354, 109, - 100, 109, 109, 109, 99, 109, 23, 64, 111, 65, - 111, 66, 111, 115, 83, 112, 109, 109, 377, 117, - 109, 109, 112, 382, 111, 111, 111, 111, 111, 111, - 386, 111, 111, 111, 109, 109, 117, 104, 23, 104, - 116, 23, 23, 116, 23, 67, 23, 111, 111, 111, - 111, 29, 23, 443, 23, 104, 110, 23, 110, 112, - 118, 111, 23, 109, 109, 23, 23, 23, 112, 112, - 112, 347, 112, 112, 112, 112, 112, 436, 436, 436, - 112, 109, 109, 57, 443, 23, 445, 112, 112, 112, - 23, 112, 112, 32, 109, 109, 66, 106, 111, 111, - 111, 119, 461, 109, 109, 112, 106, 446, 112, 112, - 462, 230, 87, 273, 210, 436, 388, 89, 159, 213, - 139, 89, 253, -1, -1, -1, 198 -}; - -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const yytype_uint16 yystos[] = -{ - 0, 3, 4, 121, 122, 0, 123, 8, 124, 125, - 99, 100, 262, 5, 6, 7, 10, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 141, 170, 171, 178, 179, 180, 242, 244, 245, - 248, 261, 262, 108, 246, 99, 99, 99, 65, 100, - 145, 151, 249, 145, 145, 145, 145, 145, 100, 146, - 159, 99, 113, 114, 144, 166, 168, 241, 145, 145, - 108, 108, 9, 11, 99, 247, 117, 117, 111, 117, - 182, 29, 30, 37, 59, 60, 74, 250, 109, 101, - 102, 103, 104, 164, 109, 109, 109, 109, 109, 109, - 104, 161, 101, 104, 105, 163, 23, 24, 38, 62, - 73, 96, 100, 110, 118, 150, 152, 172, 186, 189, - 225, 229, 232, 236, 238, 239, 109, 109, 99, 243, - 109, 100, 172, 23, 181, 185, 189, 225, 235, 237, - 239, 240, 241, 27, 39, 251, 111, 255, 144, 115, - 165, 142, 241, 144, 142, 144, 144, 142, 29, 37, - 60, 74, 177, 34, 46, 28, 30, 36, 43, 44, - 45, 47, 49, 58, 75, 76, 190, 192, 195, 197, - 199, 203, 206, 208, 210, 212, 215, 224, 29, 37, - 50, 53, 60, 74, 97, 98, 173, 150, 240, 163, - 111, 150, 144, 117, 247, 99, 112, 23, 24, 61, - 68, 252, 23, 258, 109, 100, 166, 167, 169, 109, - 110, 143, 150, 238, 109, 109, 61, 68, 254, 255, - 111, 111, 111, 64, 29, 56, 207, 111, 25, 27, - 39, 196, 253, 111, 253, 48, 51, 52, 55, 63, - 81, 219, 26, 70, 211, 111, 257, 255, 66, 254, - 111, 255, 111, 111, 175, 163, 109, 119, 23, 153, - 154, 155, 159, 109, 109, 249, 117, 183, 112, 144, - 116, 116, 163, 142, 143, 104, 162, 83, 139, 144, - 23, 233, 23, 234, 23, 209, 23, 202, 67, 202, - 25, 31, 33, 69, 71, 191, 201, 111, 111, 220, - 111, 255, 41, 42, 82, 216, 217, 23, 260, 29, - 200, 35, 54, 204, 111, 23, 176, 23, 174, 176, - 110, 240, 112, 104, 160, 147, 148, 241, 144, 118, - 110, 111, 256, 109, 109, 112, 112, 112, 112, 112, - 23, 223, 23, 221, 23, 222, 112, 77, 78, 79, - 80, 205, 23, 218, 112, 112, 112, 109, 119, 113, - 114, 156, 109, 23, 149, 262, 109, 62, 73, 184, - 187, 188, 189, 226, 227, 230, 235, 23, 259, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 140, 144, 57, 26, 40, 60, 72, 193, 201, - 253, 112, 112, 112, 112, 240, 23, 157, 23, 158, - 148, 144, 34, 46, 213, 215, 109, 119, 112, 32, - 194, 198, 201, 109, 119, 109, 109, 111, 111, 66, - 214, 187, 240, 148, 139, 228, 233, 231, 234, 111, - 119, 109, 109, 112, 106, 112, 106, 218, 148, 140, - 233, 234, 106, 218, 112 -}; - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ - -#define YYFAIL goto yyerrlab - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK (1); \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (&yylloc, state, YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (YYID (0)) - - -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. - If N is 0, then set CURRENT to the empty location which ends - the previous symbol: RHS[0] (always defined). */ - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (YYID (N)) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (YYID (0)) -#endif - - -/* YY_LOCATION_PRINT -- Print the location on the stream. - This macro was not mandated originally: define only if we know - we won't break user code: when these are the locations we know. */ - -#ifndef YY_LOCATION_PRINT -# if YYLTYPE_IS_TRIVIAL -# define YY_LOCATION_PRINT(File, Loc) \ - fprintf (File, "%d.%d-%d.%d", \ - (Loc).first_line, (Loc).first_column, \ - (Loc).last_line, (Loc).last_column) -# else -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -# endif -#endif - - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) -#else -# define YYLEX yylex (&yylval, &yylloc, scanner) -#endif - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (YYID (0)) - -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value, Location, state); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (YYID (0)) - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct asm_parser_state *state) -#else -static void -yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, state) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; - YYLTYPE const * const yylocationp; - struct asm_parser_state *state; -#endif -{ - if (!yyvaluep) - return; - YYUSE (yylocationp); - YYUSE (state); -# ifdef YYPRINT - if (yytype < YYNTOKENS) - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# else - YYUSE (yyoutput); -# endif - switch (yytype) - { - default: - break; - } -} - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct asm_parser_state *state) -#else -static void -yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, state) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; - YYLTYPE const * const yylocationp; - struct asm_parser_state *state; -#endif -{ - if (yytype < YYNTOKENS) - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - - YY_LOCATION_PRINT (yyoutput, *yylocationp); - YYFPRINTF (yyoutput, ": "); - yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, state); - YYFPRINTF (yyoutput, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) -#else -static void -yy_stack_print (yybottom, yytop) - yytype_int16 *yybottom; - yytype_int16 *yytop; -#endif -{ - YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (YYID (0)) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, struct asm_parser_state *state) -#else -static void -yy_reduce_print (yyvsp, yylsp, yyrule, state) - YYSTYPE *yyvsp; - YYLTYPE *yylsp; - int yyrule; - struct asm_parser_state *state; -#endif -{ - int yynrhs = yyr2[yyrule]; - int yyi; - unsigned long int yylno = yyrline[yyrule]; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - YYFPRINTF (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], - &(yyvsp[(yyi + 1) - (yynrhs)]) - , &(yylsp[(yyi + 1) - (yynrhs)]) , state); - YYFPRINTF (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyvsp, yylsp, Rule, state); \ -} while (YYID (0)) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined __GLIBC__ && defined _STRING_H -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static YYSIZE_T -yystrlen (const char *yystr) -#else -static YYSIZE_T -yystrlen (yystr) - const char *yystr; -#endif -{ - YYSIZE_T yylen; - for (yylen = 0; yystr[yylen]; yylen++) - continue; - return yylen; -} -# endif -# endif - -# ifndef yystpcpy -# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static char * -yystpcpy (char *yydest, const char *yysrc) -#else -static char * -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -#endif -{ - char *yyd = yydest; - const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -# ifndef yytnamerr -/* Copy to YYRES the contents of YYSTR after stripping away unnecessary - quotes and backslashes, so that it's suitable for yyerror. The - heuristic is that double-quoting is unnecessary unless the string - contains an apostrophe, a comma, or backslash (other than - backslash-backslash). YYSTR is taken from yytname. If YYRES is - null, do not copy; instead, return the length of what the result - would have been. */ -static YYSIZE_T -yytnamerr (char *yyres, const char *yystr) -{ - if (*yystr == '"') - { - YYSIZE_T yyn = 0; - char const *yyp = yystr; - - for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } - do_not_strip_quotes: ; - } - - if (! yyres) - return yystrlen (yystr); - - return yystpcpy (yyres, yystr) - yyres; -} -# endif - -/* Copy into YYRESULT an error message about the unexpected token - YYCHAR while in state YYSTATE. Return the number of bytes copied, - including the terminating null byte. If YYRESULT is null, do not - copy anything; just return the number of bytes that would be - copied. As a special case, return 0 if an ordinary "syntax error" - message will do. Return YYSIZE_MAXIMUM if overflow occurs during - size calculation. */ -static YYSIZE_T -yysyntax_error (char *yyresult, int yystate, int yychar) -{ - int yyn = yypact[yystate]; - - if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) - return 0; - else - { - int yytype = YYTRANSLATE (yychar); - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - int yysize_overflow = 0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - int yyx; - -# if 0 - /* This is so xgettext sees the translatable formats that are - constructed on the fly. */ - YY_("syntax error, unexpected %s"); - YY_("syntax error, unexpected %s, expecting %s"); - YY_("syntax error, unexpected %s, expecting %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); -# endif - char *yyfmt; - char const *yyf; - static char const yyunexpected[] = "syntax error, unexpected %s"; - static char const yyexpecting[] = ", expecting %s"; - static char const yyor[] = " or %s"; - char yyformat[sizeof yyunexpected - + sizeof yyexpecting - 1 - + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) - * (sizeof yyor - 1))]; - char const *yyprefix = yyexpecting; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 1; - - yyarg[0] = yytname[yytype]; - yyfmt = yystpcpy (yyformat, yyunexpected); - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - yyformat[sizeof yyunexpected - 1] = '\0'; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - yyfmt = yystpcpy (yyfmt, yyprefix); - yyprefix = yyor; - } - - yyf = YY_(yyformat); - yysize1 = yysize + yystrlen (yyf); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - - if (yysize_overflow) - return YYSIZE_MAXIMUM; - - if (yyresult) - { - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - char *yyp = yyresult; - int yyi = 0; - while ((*yyp = *yyf) != '\0') - { - if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyf += 2; - } - else - { - yyp++; - yyf++; - } - } - } - return yysize; - } -} -#endif /* YYERROR_VERBOSE */ - - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, struct asm_parser_state *state) -#else -static void -yydestruct (yymsg, yytype, yyvaluep, yylocationp, state) - const char *yymsg; - int yytype; - YYSTYPE *yyvaluep; - YYLTYPE *yylocationp; - struct asm_parser_state *state; -#endif -{ - YYUSE (yyvaluep); - YYUSE (yylocationp); - YYUSE (state); - - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - - switch (yytype) - { - - default: - break; - } -} - -/* Prevent warnings from -Wmissing-prototypes. */ -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (struct asm_parser_state *state); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - - - - - -/*-------------------------. -| yyparse or yypush_parse. | -`-------------------------*/ - -#ifdef YYPARSE_PARAM -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void *YYPARSE_PARAM) -#else -int -yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -#endif -#else /* ! YYPARSE_PARAM */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (struct asm_parser_state *state) -#else -int -yyparse (state) - struct asm_parser_state *state; -#endif -#endif -{ -/* The lookahead symbol. */ -int yychar; - -/* The semantic value of the lookahead symbol. */ -YYSTYPE yylval; - -/* Location data for the lookahead symbol. */ -YYLTYPE yylloc; - - /* Number of syntax errors so far. */ - int yynerrs; - - int yystate; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - - /* The stacks and their tools: - `yyss': related to states. - `yyvs': related to semantic values. - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs; - YYSTYPE *yyvsp; - - /* The location stack. */ - YYLTYPE yylsa[YYINITDEPTH]; - YYLTYPE *yyls; - YYLTYPE *yylsp; - - /* The locations where the error started and ended. */ - YYLTYPE yyerror_range[2]; - - YYSIZE_T yystacksize; - - int yyn; - int yyresult; - /* Lookahead token as an internal (translated) token number. */ - int yytoken; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - YYLTYPE yyloc; - -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; -#endif - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - yytoken = 0; - yyss = yyssa; - yyvs = yyvsa; - yyls = yylsa; - yystacksize = YYINITDEPTH; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - yyssp = yyss; - yyvsp = yyvs; - yylsp = yyls; - -#if YYLTYPE_IS_TRIVIAL - /* Initialize the default location before parsing starts. */ - yylloc.first_line = yylloc.last_line = 1; - yylloc.first_column = yylloc.last_column = 1; -#endif - - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; - YYLTYPE *yyls1 = yyls; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yyls1, yysize * sizeof (*yylsp), - &yystacksize); - - yyls = yyls1; - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyexhaustedlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); - YYSTACK_RELOCATE (yyls_alloc, yyls); -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - yylsp = yyls + yysize - 1; - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - if (yystate == YYFINAL) - YYACCEPT; - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - - /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to lookahead token. */ - yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* Shift the lookahead token. */ - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - - /* Discard the shifted token. */ - yychar = YYEMPTY; - - yystate = yyn; - *++yyvsp = yylval; - *++yylsp = yylloc; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - /* Default location. */ - YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 3: - -/* Line 1455 of yacc.c */ -#line 282 "program_parse.y" - { - if (state->prog->Target != GL_VERTEX_PROGRAM_ARB) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid fragment program header"); - - } - state->mode = ARB_vertex; - ;} - break; - - case 4: - -/* Line 1455 of yacc.c */ -#line 290 "program_parse.y" - { - if (state->prog->Target != GL_FRAGMENT_PROGRAM_ARB) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid vertex program header"); - } - state->mode = ARB_fragment; - - state->option.TexRect = - (state->ctx->Extensions.NV_texture_rectangle != GL_FALSE); - ;} - break; - - case 7: - -/* Line 1455 of yacc.c */ -#line 306 "program_parse.y" - { - int valid = 0; - - if (state->mode == ARB_vertex) { - valid = _mesa_ARBvp_parse_option(state, (yyvsp[(2) - (3)].string)); - } else if (state->mode == ARB_fragment) { - valid = _mesa_ARBfp_parse_option(state, (yyvsp[(2) - (3)].string)); - } - - - free((yyvsp[(2) - (3)].string)); - - if (!valid) { - const char *const err_str = (state->mode == ARB_vertex) - ? "invalid ARB vertex program option" - : "invalid ARB fragment program option"; - - yyerror(& (yylsp[(2) - (3)]), state, err_str); - YYERROR; - } - ;} - break; - - case 10: - -/* Line 1455 of yacc.c */ -#line 334 "program_parse.y" - { - if ((yyvsp[(1) - (2)].inst) != NULL) { - if (state->inst_tail == NULL) { - state->inst_head = (yyvsp[(1) - (2)].inst); - } else { - state->inst_tail->next = (yyvsp[(1) - (2)].inst); - } - - state->inst_tail = (yyvsp[(1) - (2)].inst); - (yyvsp[(1) - (2)].inst)->next = NULL; - - state->prog->NumInstructions++; - } - ;} - break; - - case 12: - -/* Line 1455 of yacc.c */ -#line 352 "program_parse.y" - { - (yyval.inst) = (yyvsp[(1) - (1)].inst); - state->prog->NumAluInstructions++; - ;} - break; - - case 13: - -/* Line 1455 of yacc.c */ -#line 357 "program_parse.y" - { - (yyval.inst) = (yyvsp[(1) - (1)].inst); - state->prog->NumTexInstructions++; - ;} - break; - - case 24: - -/* Line 1455 of yacc.c */ -#line 378 "program_parse.y" - { - (yyval.inst) = asm_instruction_ctor(OPCODE_ARL, & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL); - ;} - break; - - case 25: - -/* Line 1455 of yacc.c */ -#line 384 "program_parse.y" - { - (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (4)].temp_inst), & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL); - ;} - break; - - case 26: - -/* Line 1455 of yacc.c */ -#line 390 "program_parse.y" - { - (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (4)].temp_inst), & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL); - ;} - break; - - case 27: - -/* Line 1455 of yacc.c */ -#line 396 "program_parse.y" - { - (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (6)].temp_inst), & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), & (yyvsp[(6) - (6)].src_reg), NULL); - ;} - break; - - case 28: - -/* Line 1455 of yacc.c */ -#line 403 "program_parse.y" - { - (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (6)].temp_inst), & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), & (yyvsp[(6) - (6)].src_reg), NULL); - ;} - break; - - case 29: - -/* Line 1455 of yacc.c */ -#line 410 "program_parse.y" - { - (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (8)].temp_inst), & (yyvsp[(2) - (8)].dst_reg), & (yyvsp[(4) - (8)].src_reg), & (yyvsp[(6) - (8)].src_reg), & (yyvsp[(8) - (8)].src_reg)); - ;} - break; - - case 30: - -/* Line 1455 of yacc.c */ -#line 416 "program_parse.y" - { - (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (8)].temp_inst), & (yyvsp[(2) - (8)].dst_reg), & (yyvsp[(4) - (8)].src_reg), NULL, NULL); - if ((yyval.inst) != NULL) { - const GLbitfield tex_mask = (1U << (yyvsp[(6) - (8)].integer)); - GLbitfield shadow_tex = 0; - GLbitfield target_mask = 0; - - - (yyval.inst)->Base.TexSrcUnit = (yyvsp[(6) - (8)].integer); - - if ((yyvsp[(8) - (8)].integer) < 0) { - shadow_tex = tex_mask; - - (yyval.inst)->Base.TexSrcTarget = -(yyvsp[(8) - (8)].integer); - (yyval.inst)->Base.TexShadow = 1; - } else { - (yyval.inst)->Base.TexSrcTarget = (yyvsp[(8) - (8)].integer); - } - - target_mask = (1U << (yyval.inst)->Base.TexSrcTarget); - - /* If this texture unit was previously accessed and that access - * had a different texture target, generate an error. - * - * If this texture unit was previously accessed and that access - * had a different shadow mode, generate an error. - */ - if ((state->prog->TexturesUsed[(yyvsp[(6) - (8)].integer)] != 0) - && ((state->prog->TexturesUsed[(yyvsp[(6) - (8)].integer)] != target_mask) - || ((state->prog->ShadowSamplers & tex_mask) - != shadow_tex))) { - yyerror(& (yylsp[(8) - (8)]), state, - "multiple targets used on one texture image unit"); - YYERROR; - } - - - state->prog->TexturesUsed[(yyvsp[(6) - (8)].integer)] |= target_mask; - state->prog->ShadowSamplers |= shadow_tex; - } - ;} - break; - - case 31: - -/* Line 1455 of yacc.c */ -#line 460 "program_parse.y" - { - (yyval.inst) = asm_instruction_ctor(OPCODE_KIL, NULL, & (yyvsp[(2) - (2)].src_reg), NULL, NULL); - state->fragment.UsesKill = 1; - ;} - break; - - case 32: - -/* Line 1455 of yacc.c */ -#line 465 "program_parse.y" - { - (yyval.inst) = asm_instruction_ctor(OPCODE_KIL_NV, NULL, NULL, NULL, NULL); - (yyval.inst)->Base.DstReg.CondMask = (yyvsp[(2) - (2)].dst_reg).CondMask; - (yyval.inst)->Base.DstReg.CondSwizzle = (yyvsp[(2) - (2)].dst_reg).CondSwizzle; - (yyval.inst)->Base.DstReg.CondSrc = (yyvsp[(2) - (2)].dst_reg).CondSrc; - state->fragment.UsesKill = 1; - ;} - break; - - case 33: - -/* Line 1455 of yacc.c */ -#line 475 "program_parse.y" - { - (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (12)].temp_inst), & (yyvsp[(2) - (12)].dst_reg), & (yyvsp[(4) - (12)].src_reg), & (yyvsp[(6) - (12)].src_reg), & (yyvsp[(8) - (12)].src_reg)); - if ((yyval.inst) != NULL) { - const GLbitfield tex_mask = (1U << (yyvsp[(10) - (12)].integer)); - GLbitfield shadow_tex = 0; - GLbitfield target_mask = 0; - - - (yyval.inst)->Base.TexSrcUnit = (yyvsp[(10) - (12)].integer); - - if ((yyvsp[(12) - (12)].integer) < 0) { - shadow_tex = tex_mask; - - (yyval.inst)->Base.TexSrcTarget = -(yyvsp[(12) - (12)].integer); - (yyval.inst)->Base.TexShadow = 1; - } else { - (yyval.inst)->Base.TexSrcTarget = (yyvsp[(12) - (12)].integer); - } - - target_mask = (1U << (yyval.inst)->Base.TexSrcTarget); - - /* If this texture unit was previously accessed and that access - * had a different texture target, generate an error. - * - * If this texture unit was previously accessed and that access - * had a different shadow mode, generate an error. - */ - if ((state->prog->TexturesUsed[(yyvsp[(10) - (12)].integer)] != 0) - && ((state->prog->TexturesUsed[(yyvsp[(10) - (12)].integer)] != target_mask) - || ((state->prog->ShadowSamplers & tex_mask) - != shadow_tex))) { - yyerror(& (yylsp[(12) - (12)]), state, - "multiple targets used on one texture image unit"); - YYERROR; - } - - - state->prog->TexturesUsed[(yyvsp[(10) - (12)].integer)] |= target_mask; - state->prog->ShadowSamplers |= shadow_tex; - } - ;} - break; - - case 34: - -/* Line 1455 of yacc.c */ -#line 519 "program_parse.y" - { - (yyval.integer) = (yyvsp[(2) - (2)].integer); - ;} - break; - - case 35: - -/* Line 1455 of yacc.c */ -#line 524 "program_parse.y" - { (yyval.integer) = TEXTURE_1D_INDEX; ;} - break; - - case 36: - -/* Line 1455 of yacc.c */ -#line 525 "program_parse.y" - { (yyval.integer) = TEXTURE_2D_INDEX; ;} - break; - - case 37: - -/* Line 1455 of yacc.c */ -#line 526 "program_parse.y" - { (yyval.integer) = TEXTURE_3D_INDEX; ;} - break; - - case 38: - -/* Line 1455 of yacc.c */ -#line 527 "program_parse.y" - { (yyval.integer) = TEXTURE_CUBE_INDEX; ;} - break; - - case 39: - -/* Line 1455 of yacc.c */ -#line 528 "program_parse.y" - { (yyval.integer) = TEXTURE_RECT_INDEX; ;} - break; - - case 40: - -/* Line 1455 of yacc.c */ -#line 529 "program_parse.y" - { (yyval.integer) = -TEXTURE_1D_INDEX; ;} - break; - - case 41: - -/* Line 1455 of yacc.c */ -#line 530 "program_parse.y" - { (yyval.integer) = -TEXTURE_2D_INDEX; ;} - break; - - case 42: - -/* Line 1455 of yacc.c */ -#line 531 "program_parse.y" - { (yyval.integer) = -TEXTURE_RECT_INDEX; ;} - break; - - case 43: - -/* Line 1455 of yacc.c */ -#line 532 "program_parse.y" - { (yyval.integer) = TEXTURE_1D_ARRAY_INDEX; ;} - break; - - case 44: - -/* Line 1455 of yacc.c */ -#line 533 "program_parse.y" - { (yyval.integer) = TEXTURE_2D_ARRAY_INDEX; ;} - break; - - case 45: - -/* Line 1455 of yacc.c */ -#line 534 "program_parse.y" - { (yyval.integer) = -TEXTURE_1D_ARRAY_INDEX; ;} - break; - - case 46: - -/* Line 1455 of yacc.c */ -#line 535 "program_parse.y" - { (yyval.integer) = -TEXTURE_2D_ARRAY_INDEX; ;} - break; - - case 47: - -/* Line 1455 of yacc.c */ -#line 539 "program_parse.y" - { - /* FIXME: Is this correct? Should the extenedSwizzle be applied - * FIXME: to the existing swizzle? - */ - (yyvsp[(4) - (6)].src_reg).Base.Swizzle = (yyvsp[(6) - (6)].swiz_mask).swizzle; - (yyvsp[(4) - (6)].src_reg).Base.Negate = (yyvsp[(6) - (6)].swiz_mask).mask; - - (yyval.inst) = asm_instruction_copy_ctor(& (yyvsp[(1) - (6)].temp_inst), & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), NULL, NULL); - ;} - break; - - case 48: - -/* Line 1455 of yacc.c */ -#line 551 "program_parse.y" - { - (yyval.src_reg) = (yyvsp[(2) - (2)].src_reg); - - if ((yyvsp[(1) - (2)].negate)) { - (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate; - } - ;} - break; - - case 49: - -/* Line 1455 of yacc.c */ -#line 559 "program_parse.y" - { - (yyval.src_reg) = (yyvsp[(3) - (4)].src_reg); - - if (!state->option.NV_fragment) { - yyerror(& (yylsp[(2) - (4)]), state, "unexpected character '|'"); - YYERROR; - } - - if ((yyvsp[(1) - (4)].negate)) { - (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate; - } - - (yyval.src_reg).Base.Abs = 1; - ;} - break; - - case 50: - -/* Line 1455 of yacc.c */ -#line 576 "program_parse.y" - { - (yyval.src_reg) = (yyvsp[(1) - (2)].src_reg); - - (yyval.src_reg).Base.Swizzle = _mesa_combine_swizzles((yyval.src_reg).Base.Swizzle, - (yyvsp[(2) - (2)].swiz_mask).swizzle); - ;} - break; - - case 51: - -/* Line 1455 of yacc.c */ -#line 583 "program_parse.y" - { - struct asm_symbol temp_sym; - - if (!state->option.NV_fragment) { - yyerror(& (yylsp[(1) - (1)]), state, "expected scalar suffix"); - YYERROR; - } - - memset(& temp_sym, 0, sizeof(temp_sym)); - temp_sym.param_binding_begin = ~0; - initialize_symbol_from_const(state->prog, & temp_sym, & (yyvsp[(1) - (1)].vector), GL_TRUE); - - set_src_reg_swz(& (yyval.src_reg), PROGRAM_CONSTANT, - temp_sym.param_binding_begin, - temp_sym.param_binding_swizzle); - ;} - break; - - case 52: - -/* Line 1455 of yacc.c */ -#line 602 "program_parse.y" - { - (yyval.src_reg) = (yyvsp[(2) - (3)].src_reg); - - if ((yyvsp[(1) - (3)].negate)) { - (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate; - } - - (yyval.src_reg).Base.Swizzle = _mesa_combine_swizzles((yyval.src_reg).Base.Swizzle, - (yyvsp[(3) - (3)].swiz_mask).swizzle); - ;} - break; - - case 53: - -/* Line 1455 of yacc.c */ -#line 613 "program_parse.y" - { - (yyval.src_reg) = (yyvsp[(3) - (5)].src_reg); - - if (!state->option.NV_fragment) { - yyerror(& (yylsp[(2) - (5)]), state, "unexpected character '|'"); - YYERROR; - } - - if ((yyvsp[(1) - (5)].negate)) { - (yyval.src_reg).Base.Negate = ~(yyval.src_reg).Base.Negate; - } - - (yyval.src_reg).Base.Abs = 1; - (yyval.src_reg).Base.Swizzle = _mesa_combine_swizzles((yyval.src_reg).Base.Swizzle, - (yyvsp[(4) - (5)].swiz_mask).swizzle); - ;} - break; - - case 54: - -/* Line 1455 of yacc.c */ -#line 633 "program_parse.y" - { - (yyval.dst_reg) = (yyvsp[(1) - (3)].dst_reg); - (yyval.dst_reg).WriteMask = (yyvsp[(2) - (3)].swiz_mask).mask; - (yyval.dst_reg).CondMask = (yyvsp[(3) - (3)].dst_reg).CondMask; - (yyval.dst_reg).CondSwizzle = (yyvsp[(3) - (3)].dst_reg).CondSwizzle; - (yyval.dst_reg).CondSrc = (yyvsp[(3) - (3)].dst_reg).CondSrc; - - if ((yyval.dst_reg).File == PROGRAM_OUTPUT) { - /* Technically speaking, this should check that it is in - * vertex program mode. However, PositionInvariant can never be - * set in fragment program mode, so it is somewhat irrelevant. - */ - if (state->option.PositionInvariant - && ((yyval.dst_reg).Index == VERT_RESULT_HPOS)) { - yyerror(& (yylsp[(1) - (3)]), state, "position-invariant programs cannot " - "write position"); - YYERROR; - } - - state->prog->OutputsWritten |= BITFIELD64_BIT((yyval.dst_reg).Index); - } - ;} - break; - - case 55: - -/* Line 1455 of yacc.c */ -#line 658 "program_parse.y" - { - set_dst_reg(& (yyval.dst_reg), PROGRAM_ADDRESS, 0); - (yyval.dst_reg).WriteMask = (yyvsp[(2) - (2)].swiz_mask).mask; - ;} - break; - - case 56: - -/* Line 1455 of yacc.c */ -#line 665 "program_parse.y" - { - const unsigned xyzw_valid = - ((yyvsp[(1) - (7)].ext_swizzle).xyzw_valid << 0) - | ((yyvsp[(3) - (7)].ext_swizzle).xyzw_valid << 1) - | ((yyvsp[(5) - (7)].ext_swizzle).xyzw_valid << 2) - | ((yyvsp[(7) - (7)].ext_swizzle).xyzw_valid << 3); - const unsigned rgba_valid = - ((yyvsp[(1) - (7)].ext_swizzle).rgba_valid << 0) - | ((yyvsp[(3) - (7)].ext_swizzle).rgba_valid << 1) - | ((yyvsp[(5) - (7)].ext_swizzle).rgba_valid << 2) - | ((yyvsp[(7) - (7)].ext_swizzle).rgba_valid << 3); - - /* All of the swizzle components have to be valid in either RGBA - * or XYZW. Note that 0 and 1 are valid in both, so both masks - * can have some bits set. - * - * We somewhat deviate from the spec here. It would be really hard - * to figure out which component is the error, and there probably - * isn't a lot of benefit. - */ - if ((rgba_valid != 0x0f) && (xyzw_valid != 0x0f)) { - yyerror(& (yylsp[(1) - (7)]), state, "cannot combine RGBA and XYZW swizzle " - "components"); - YYERROR; - } - - (yyval.swiz_mask).swizzle = MAKE_SWIZZLE4((yyvsp[(1) - (7)].ext_swizzle).swz, (yyvsp[(3) - (7)].ext_swizzle).swz, (yyvsp[(5) - (7)].ext_swizzle).swz, (yyvsp[(7) - (7)].ext_swizzle).swz); - (yyval.swiz_mask).mask = ((yyvsp[(1) - (7)].ext_swizzle).negate) | ((yyvsp[(3) - (7)].ext_swizzle).negate << 1) | ((yyvsp[(5) - (7)].ext_swizzle).negate << 2) - | ((yyvsp[(7) - (7)].ext_swizzle).negate << 3); - ;} - break; - - case 57: - -/* Line 1455 of yacc.c */ -#line 698 "program_parse.y" - { - (yyval.ext_swizzle) = (yyvsp[(2) - (2)].ext_swizzle); - (yyval.ext_swizzle).negate = ((yyvsp[(1) - (2)].negate)) ? 1 : 0; - ;} - break; - - case 58: - -/* Line 1455 of yacc.c */ -#line 705 "program_parse.y" - { - if (((yyvsp[(1) - (1)].integer) != 0) && ((yyvsp[(1) - (1)].integer) != 1)) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid extended swizzle selector"); - YYERROR; - } - - (yyval.ext_swizzle).swz = ((yyvsp[(1) - (1)].integer) == 0) ? SWIZZLE_ZERO : SWIZZLE_ONE; - - /* 0 and 1 are valid for both RGBA swizzle names and XYZW - * swizzle names. - */ - (yyval.ext_swizzle).xyzw_valid = 1; - (yyval.ext_swizzle).rgba_valid = 1; - ;} - break; - - case 59: - -/* Line 1455 of yacc.c */ -#line 720 "program_parse.y" - { - char s; - - if (strlen((yyvsp[(1) - (1)].string)) > 1) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid extended swizzle selector"); - YYERROR; - } - - s = (yyvsp[(1) - (1)].string)[0]; - free((yyvsp[(1) - (1)].string)); - - switch (s) { - case 'x': - (yyval.ext_swizzle).swz = SWIZZLE_X; - (yyval.ext_swizzle).xyzw_valid = 1; - break; - case 'y': - (yyval.ext_swizzle).swz = SWIZZLE_Y; - (yyval.ext_swizzle).xyzw_valid = 1; - break; - case 'z': - (yyval.ext_swizzle).swz = SWIZZLE_Z; - (yyval.ext_swizzle).xyzw_valid = 1; - break; - case 'w': - (yyval.ext_swizzle).swz = SWIZZLE_W; - (yyval.ext_swizzle).xyzw_valid = 1; - break; - - case 'r': - (yyval.ext_swizzle).swz = SWIZZLE_X; - (yyval.ext_swizzle).rgba_valid = 1; - break; - case 'g': - (yyval.ext_swizzle).swz = SWIZZLE_Y; - (yyval.ext_swizzle).rgba_valid = 1; - break; - case 'b': - (yyval.ext_swizzle).swz = SWIZZLE_Z; - (yyval.ext_swizzle).rgba_valid = 1; - break; - case 'a': - (yyval.ext_swizzle).swz = SWIZZLE_W; - (yyval.ext_swizzle).rgba_valid = 1; - break; - - default: - yyerror(& (yylsp[(1) - (1)]), state, "invalid extended swizzle selector"); - YYERROR; - break; - } - ;} - break; - - case 60: - -/* Line 1455 of yacc.c */ -#line 775 "program_parse.y" - { - struct asm_symbol *const s = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string)); - - free((yyvsp[(1) - (1)].string)); - - if (s == NULL) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable"); - YYERROR; - } else if ((s->type != at_param) && (s->type != at_temp) - && (s->type != at_attrib)) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable"); - YYERROR; - } else if ((s->type == at_param) && s->param_is_array) { - yyerror(& (yylsp[(1) - (1)]), state, "non-array access to array PARAM"); - YYERROR; - } - - init_src_reg(& (yyval.src_reg)); - switch (s->type) { - case at_temp: - set_src_reg(& (yyval.src_reg), PROGRAM_TEMPORARY, s->temp_binding); - break; - case at_param: - set_src_reg_swz(& (yyval.src_reg), s->param_binding_type, - s->param_binding_begin, - s->param_binding_swizzle); - break; - case at_attrib: - set_src_reg(& (yyval.src_reg), PROGRAM_INPUT, s->attrib_binding); - state->prog->InputsRead |= (1U << (yyval.src_reg).Base.Index); - - if (!validate_inputs(& (yylsp[(1) - (1)]), state)) { - YYERROR; - } - break; - - default: - YYERROR; - break; - } - ;} - break; - - case 61: - -/* Line 1455 of yacc.c */ -#line 818 "program_parse.y" - { - set_src_reg(& (yyval.src_reg), PROGRAM_INPUT, (yyvsp[(1) - (1)].attrib)); - state->prog->InputsRead |= (1U << (yyval.src_reg).Base.Index); - - if (!validate_inputs(& (yylsp[(1) - (1)]), state)) { - YYERROR; - } - ;} - break; - - case 62: - -/* Line 1455 of yacc.c */ -#line 827 "program_parse.y" - { - if (! (yyvsp[(3) - (4)].src_reg).Base.RelAddr - && ((unsigned) (yyvsp[(3) - (4)].src_reg).Base.Index >= (yyvsp[(1) - (4)].sym)->param_binding_length)) { - yyerror(& (yylsp[(3) - (4)]), state, "out of bounds array access"); - YYERROR; - } - - init_src_reg(& (yyval.src_reg)); - (yyval.src_reg).Base.File = (yyvsp[(1) - (4)].sym)->param_binding_type; - - if ((yyvsp[(3) - (4)].src_reg).Base.RelAddr) { - (yyvsp[(1) - (4)].sym)->param_accessed_indirectly = 1; - - (yyval.src_reg).Base.RelAddr = 1; - (yyval.src_reg).Base.Index = (yyvsp[(3) - (4)].src_reg).Base.Index; - (yyval.src_reg).Symbol = (yyvsp[(1) - (4)].sym); - } else { - (yyval.src_reg).Base.Index = (yyvsp[(1) - (4)].sym)->param_binding_begin + (yyvsp[(3) - (4)].src_reg).Base.Index; - } - ;} - break; - - case 63: - -/* Line 1455 of yacc.c */ -#line 848 "program_parse.y" - { - gl_register_file file = ((yyvsp[(1) - (1)].temp_sym).name != NULL) - ? (yyvsp[(1) - (1)].temp_sym).param_binding_type - : PROGRAM_CONSTANT; - set_src_reg_swz(& (yyval.src_reg), file, (yyvsp[(1) - (1)].temp_sym).param_binding_begin, - (yyvsp[(1) - (1)].temp_sym).param_binding_swizzle); - ;} - break; - - case 64: - -/* Line 1455 of yacc.c */ -#line 858 "program_parse.y" - { - set_dst_reg(& (yyval.dst_reg), PROGRAM_OUTPUT, (yyvsp[(1) - (1)].result)); - ;} - break; - - case 65: - -/* Line 1455 of yacc.c */ -#line 862 "program_parse.y" - { - struct asm_symbol *const s = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string)); - - free((yyvsp[(1) - (1)].string)); - - if (s == NULL) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable"); - YYERROR; - } else if ((s->type != at_output) && (s->type != at_temp)) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable"); - YYERROR; - } - - switch (s->type) { - case at_temp: - set_dst_reg(& (yyval.dst_reg), PROGRAM_TEMPORARY, s->temp_binding); - break; - case at_output: - set_dst_reg(& (yyval.dst_reg), PROGRAM_OUTPUT, s->output_binding); - break; - default: - set_dst_reg(& (yyval.dst_reg), s->param_binding_type, s->param_binding_begin); - break; - } - ;} - break; - - case 66: - -/* Line 1455 of yacc.c */ -#line 891 "program_parse.y" - { - struct asm_symbol *const s = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string)); - - free((yyvsp[(1) - (1)].string)); - - if (s == NULL) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid operand variable"); - YYERROR; - } else if ((s->type != at_param) || !s->param_is_array) { - yyerror(& (yylsp[(1) - (1)]), state, "array access to non-PARAM variable"); - YYERROR; - } else { - (yyval.sym) = s; - } - ;} - break; - - case 69: - -/* Line 1455 of yacc.c */ -#line 912 "program_parse.y" - { - init_src_reg(& (yyval.src_reg)); - (yyval.src_reg).Base.Index = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 70: - -/* Line 1455 of yacc.c */ -#line 919 "program_parse.y" - { - /* FINISHME: Add support for multiple address registers. - */ - /* FINISHME: Add support for 4-component address registers. - */ - init_src_reg(& (yyval.src_reg)); - (yyval.src_reg).Base.RelAddr = 1; - (yyval.src_reg).Base.Index = (yyvsp[(3) - (3)].integer); - ;} - break; - - case 71: - -/* Line 1455 of yacc.c */ -#line 930 "program_parse.y" - { (yyval.integer) = 0; ;} - break; - - case 72: - -/* Line 1455 of yacc.c */ -#line 931 "program_parse.y" - { (yyval.integer) = (yyvsp[(2) - (2)].integer); ;} - break; - - case 73: - -/* Line 1455 of yacc.c */ -#line 932 "program_parse.y" - { (yyval.integer) = -(yyvsp[(2) - (2)].integer); ;} - break; - - case 74: - -/* Line 1455 of yacc.c */ -#line 936 "program_parse.y" - { - if (((yyvsp[(1) - (1)].integer) < 0) || ((yyvsp[(1) - (1)].integer) > 63)) { - char s[100]; - _mesa_snprintf(s, sizeof(s), - "relative address offset too large (%d)", (yyvsp[(1) - (1)].integer)); - yyerror(& (yylsp[(1) - (1)]), state, s); - YYERROR; - } else { - (yyval.integer) = (yyvsp[(1) - (1)].integer); - } - ;} - break; - - case 75: - -/* Line 1455 of yacc.c */ -#line 950 "program_parse.y" - { - if (((yyvsp[(1) - (1)].integer) < 0) || ((yyvsp[(1) - (1)].integer) > 64)) { - char s[100]; - _mesa_snprintf(s, sizeof(s), - "relative address offset too large (%d)", (yyvsp[(1) - (1)].integer)); - yyerror(& (yylsp[(1) - (1)]), state, s); - YYERROR; - } else { - (yyval.integer) = (yyvsp[(1) - (1)].integer); - } - ;} - break; - - case 76: - -/* Line 1455 of yacc.c */ -#line 964 "program_parse.y" - { - struct asm_symbol *const s = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(1) - (1)].string)); - - free((yyvsp[(1) - (1)].string)); - - if (s == NULL) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid array member"); - YYERROR; - } else if (s->type != at_address) { - yyerror(& (yylsp[(1) - (1)]), state, - "invalid variable for indexed array access"); - YYERROR; - } else { - (yyval.sym) = s; - } - ;} - break; - - case 77: - -/* Line 1455 of yacc.c */ -#line 984 "program_parse.y" - { - if ((yyvsp[(1) - (1)].swiz_mask).mask != WRITEMASK_X) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid address component selector"); - YYERROR; - } else { - (yyval.swiz_mask) = (yyvsp[(1) - (1)].swiz_mask); - } - ;} - break; - - case 78: - -/* Line 1455 of yacc.c */ -#line 995 "program_parse.y" - { - if ((yyvsp[(1) - (1)].swiz_mask).mask != WRITEMASK_X) { - yyerror(& (yylsp[(1) - (1)]), state, - "address register write mask must be \".x\""); - YYERROR; - } else { - (yyval.swiz_mask) = (yyvsp[(1) - (1)].swiz_mask); - } - ;} - break; - - case 83: - -/* Line 1455 of yacc.c */ -#line 1011 "program_parse.y" - { (yyval.swiz_mask).swizzle = SWIZZLE_NOOP; (yyval.swiz_mask).mask = WRITEMASK_XYZW; ;} - break; - - case 88: - -/* Line 1455 of yacc.c */ -#line 1015 "program_parse.y" - { (yyval.swiz_mask).swizzle = SWIZZLE_NOOP; (yyval.swiz_mask).mask = WRITEMASK_XYZW; ;} - break; - - case 89: - -/* Line 1455 of yacc.c */ -#line 1019 "program_parse.y" - { - (yyval.dst_reg) = (yyvsp[(2) - (3)].dst_reg); - ;} - break; - - case 90: - -/* Line 1455 of yacc.c */ -#line 1023 "program_parse.y" - { - (yyval.dst_reg) = (yyvsp[(2) - (3)].dst_reg); - ;} - break; - - case 91: - -/* Line 1455 of yacc.c */ -#line 1027 "program_parse.y" - { - (yyval.dst_reg).CondMask = COND_TR; - (yyval.dst_reg).CondSwizzle = SWIZZLE_NOOP; - (yyval.dst_reg).CondSrc = 0; - ;} - break; - - case 92: - -/* Line 1455 of yacc.c */ -#line 1035 "program_parse.y" - { - (yyval.dst_reg) = (yyvsp[(1) - (2)].dst_reg); - (yyval.dst_reg).CondSwizzle = (yyvsp[(2) - (2)].swiz_mask).swizzle; - ;} - break; - - case 93: - -/* Line 1455 of yacc.c */ -#line 1042 "program_parse.y" - { - (yyval.dst_reg) = (yyvsp[(1) - (2)].dst_reg); - (yyval.dst_reg).CondSwizzle = (yyvsp[(2) - (2)].swiz_mask).swizzle; - ;} - break; - - case 94: - -/* Line 1455 of yacc.c */ -#line 1049 "program_parse.y" - { - const int cond = _mesa_parse_cc((yyvsp[(1) - (1)].string)); - if ((cond == 0) || ((yyvsp[(1) - (1)].string)[2] != '\0')) { - char *const err_str = - make_error_string("invalid condition code \"%s\"", (yyvsp[(1) - (1)].string)); - - yyerror(& (yylsp[(1) - (1)]), state, (err_str != NULL) - ? err_str : "invalid condition code"); - - if (err_str != NULL) { - free(err_str); - } - - YYERROR; - } - - (yyval.dst_reg).CondMask = cond; - (yyval.dst_reg).CondSwizzle = SWIZZLE_NOOP; - (yyval.dst_reg).CondSrc = 0; - ;} - break; - - case 95: - -/* Line 1455 of yacc.c */ -#line 1072 "program_parse.y" - { - const int cond = _mesa_parse_cc((yyvsp[(1) - (1)].string)); - if ((cond == 0) || ((yyvsp[(1) - (1)].string)[2] != '\0')) { - char *const err_str = - make_error_string("invalid condition code \"%s\"", (yyvsp[(1) - (1)].string)); - - yyerror(& (yylsp[(1) - (1)]), state, (err_str != NULL) - ? err_str : "invalid condition code"); - - if (err_str != NULL) { - free(err_str); - } - - YYERROR; - } - - (yyval.dst_reg).CondMask = cond; - (yyval.dst_reg).CondSwizzle = SWIZZLE_NOOP; - (yyval.dst_reg).CondSrc = 0; - ;} - break; - - case 102: - -/* Line 1455 of yacc.c */ -#line 1103 "program_parse.y" - { - struct asm_symbol *const s = - declare_variable(state, (yyvsp[(2) - (4)].string), at_attrib, & (yylsp[(2) - (4)])); - - if (s == NULL) { - free((yyvsp[(2) - (4)].string)); - YYERROR; - } else { - s->attrib_binding = (yyvsp[(4) - (4)].attrib); - state->InputsBound |= (1U << s->attrib_binding); - - if (!validate_inputs(& (yylsp[(4) - (4)]), state)) { - YYERROR; - } - } - ;} - break; - - case 103: - -/* Line 1455 of yacc.c */ -#line 1122 "program_parse.y" - { - (yyval.attrib) = (yyvsp[(2) - (2)].attrib); - ;} - break; - - case 104: - -/* Line 1455 of yacc.c */ -#line 1126 "program_parse.y" - { - (yyval.attrib) = (yyvsp[(2) - (2)].attrib); - ;} - break; - - case 105: - -/* Line 1455 of yacc.c */ -#line 1132 "program_parse.y" - { - (yyval.attrib) = VERT_ATTRIB_POS; - ;} - break; - - case 106: - -/* Line 1455 of yacc.c */ -#line 1136 "program_parse.y" - { - (yyval.attrib) = VERT_ATTRIB_WEIGHT; - ;} - break; - - case 107: - -/* Line 1455 of yacc.c */ -#line 1140 "program_parse.y" - { - (yyval.attrib) = VERT_ATTRIB_NORMAL; - ;} - break; - - case 108: - -/* Line 1455 of yacc.c */ -#line 1144 "program_parse.y" - { - if (!state->ctx->Extensions.EXT_secondary_color) { - yyerror(& (yylsp[(2) - (2)]), state, "GL_EXT_secondary_color not supported"); - YYERROR; - } - - (yyval.attrib) = VERT_ATTRIB_COLOR0 + (yyvsp[(2) - (2)].integer); - ;} - break; - - case 109: - -/* Line 1455 of yacc.c */ -#line 1153 "program_parse.y" - { - if (!state->ctx->Extensions.EXT_fog_coord) { - yyerror(& (yylsp[(1) - (1)]), state, "GL_EXT_fog_coord not supported"); - YYERROR; - } - - (yyval.attrib) = VERT_ATTRIB_FOG; - ;} - break; - - case 110: - -/* Line 1455 of yacc.c */ -#line 1162 "program_parse.y" - { - (yyval.attrib) = VERT_ATTRIB_TEX0 + (yyvsp[(2) - (2)].integer); - ;} - break; - - case 111: - -/* Line 1455 of yacc.c */ -#line 1166 "program_parse.y" - { - yyerror(& (yylsp[(1) - (4)]), state, "GL_ARB_matrix_palette not supported"); - YYERROR; - ;} - break; - - case 112: - -/* Line 1455 of yacc.c */ -#line 1171 "program_parse.y" - { - (yyval.attrib) = VERT_ATTRIB_GENERIC0 + (yyvsp[(3) - (4)].integer); - ;} - break; - - case 113: - -/* Line 1455 of yacc.c */ -#line 1177 "program_parse.y" - { - if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->limits->MaxAttribs) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid vertex attribute reference"); - YYERROR; - } - - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 117: - -/* Line 1455 of yacc.c */ -#line 1191 "program_parse.y" - { - (yyval.attrib) = FRAG_ATTRIB_WPOS; - ;} - break; - - case 118: - -/* Line 1455 of yacc.c */ -#line 1195 "program_parse.y" - { - (yyval.attrib) = FRAG_ATTRIB_COL0 + (yyvsp[(2) - (2)].integer); - ;} - break; - - case 119: - -/* Line 1455 of yacc.c */ -#line 1199 "program_parse.y" - { - (yyval.attrib) = FRAG_ATTRIB_FOGC; - ;} - break; - - case 120: - -/* Line 1455 of yacc.c */ -#line 1203 "program_parse.y" - { - (yyval.attrib) = FRAG_ATTRIB_TEX0 + (yyvsp[(2) - (2)].integer); - ;} - break; - - case 123: - -/* Line 1455 of yacc.c */ -#line 1211 "program_parse.y" - { - struct asm_symbol *const s = - declare_variable(state, (yyvsp[(2) - (3)].string), at_param, & (yylsp[(2) - (3)])); - - if (s == NULL) { - free((yyvsp[(2) - (3)].string)); - YYERROR; - } else { - s->param_binding_type = (yyvsp[(3) - (3)].temp_sym).param_binding_type; - s->param_binding_begin = (yyvsp[(3) - (3)].temp_sym).param_binding_begin; - s->param_binding_length = (yyvsp[(3) - (3)].temp_sym).param_binding_length; - s->param_binding_swizzle = (yyvsp[(3) - (3)].temp_sym).param_binding_swizzle; - s->param_is_array = 0; - } - ;} - break; - - case 124: - -/* Line 1455 of yacc.c */ -#line 1229 "program_parse.y" - { - if (((yyvsp[(4) - (6)].integer) != 0) && ((unsigned) (yyvsp[(4) - (6)].integer) != (yyvsp[(6) - (6)].temp_sym).param_binding_length)) { - free((yyvsp[(2) - (6)].string)); - yyerror(& (yylsp[(4) - (6)]), state, - "parameter array size and number of bindings must match"); - YYERROR; - } else { - struct asm_symbol *const s = - declare_variable(state, (yyvsp[(2) - (6)].string), (yyvsp[(6) - (6)].temp_sym).type, & (yylsp[(2) - (6)])); - - if (s == NULL) { - free((yyvsp[(2) - (6)].string)); - YYERROR; - } else { - s->param_binding_type = (yyvsp[(6) - (6)].temp_sym).param_binding_type; - s->param_binding_begin = (yyvsp[(6) - (6)].temp_sym).param_binding_begin; - s->param_binding_length = (yyvsp[(6) - (6)].temp_sym).param_binding_length; - s->param_binding_swizzle = SWIZZLE_XYZW; - s->param_is_array = 1; - } - } - ;} - break; - - case 125: - -/* Line 1455 of yacc.c */ -#line 1254 "program_parse.y" - { - (yyval.integer) = 0; - ;} - break; - - case 126: - -/* Line 1455 of yacc.c */ -#line 1258 "program_parse.y" - { - if (((yyvsp[(1) - (1)].integer) < 1) || ((unsigned) (yyvsp[(1) - (1)].integer) > state->limits->MaxParameters)) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid parameter array size"); - YYERROR; - } else { - (yyval.integer) = (yyvsp[(1) - (1)].integer); - } - ;} - break; - - case 127: - -/* Line 1455 of yacc.c */ -#line 1269 "program_parse.y" - { - (yyval.temp_sym) = (yyvsp[(2) - (2)].temp_sym); - ;} - break; - - case 128: - -/* Line 1455 of yacc.c */ -#line 1275 "program_parse.y" - { - (yyval.temp_sym) = (yyvsp[(3) - (4)].temp_sym); - ;} - break; - - case 130: - -/* Line 1455 of yacc.c */ -#line 1282 "program_parse.y" - { - (yyvsp[(1) - (3)].temp_sym).param_binding_length += (yyvsp[(3) - (3)].temp_sym).param_binding_length; - (yyval.temp_sym) = (yyvsp[(1) - (3)].temp_sym); - ;} - break; - - case 131: - -/* Line 1455 of yacc.c */ -#line 1289 "program_parse.y" - { - memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); - (yyval.temp_sym).param_binding_begin = ~0; - initialize_symbol_from_state(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state)); - ;} - break; - - case 132: - -/* Line 1455 of yacc.c */ -#line 1295 "program_parse.y" - { - memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); - (yyval.temp_sym).param_binding_begin = ~0; - initialize_symbol_from_param(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state)); - ;} - break; - - case 133: - -/* Line 1455 of yacc.c */ -#line 1301 "program_parse.y" - { - memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); - (yyval.temp_sym).param_binding_begin = ~0; - initialize_symbol_from_const(state->prog, & (yyval.temp_sym), & (yyvsp[(1) - (1)].vector), GL_TRUE); - ;} - break; - - case 134: - -/* Line 1455 of yacc.c */ -#line 1309 "program_parse.y" - { - memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); - (yyval.temp_sym).param_binding_begin = ~0; - initialize_symbol_from_state(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state)); - ;} - break; - - case 135: - -/* Line 1455 of yacc.c */ -#line 1315 "program_parse.y" - { - memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); - (yyval.temp_sym).param_binding_begin = ~0; - initialize_symbol_from_param(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state)); - ;} - break; - - case 136: - -/* Line 1455 of yacc.c */ -#line 1321 "program_parse.y" - { - memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); - (yyval.temp_sym).param_binding_begin = ~0; - initialize_symbol_from_const(state->prog, & (yyval.temp_sym), & (yyvsp[(1) - (1)].vector), GL_TRUE); - ;} - break; - - case 137: - -/* Line 1455 of yacc.c */ -#line 1329 "program_parse.y" - { - memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); - (yyval.temp_sym).param_binding_begin = ~0; - initialize_symbol_from_state(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state)); - ;} - break; - - case 138: - -/* Line 1455 of yacc.c */ -#line 1335 "program_parse.y" - { - memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); - (yyval.temp_sym).param_binding_begin = ~0; - initialize_symbol_from_param(state->prog, & (yyval.temp_sym), (yyvsp[(1) - (1)].state)); - ;} - break; - - case 139: - -/* Line 1455 of yacc.c */ -#line 1341 "program_parse.y" - { - memset(& (yyval.temp_sym), 0, sizeof((yyval.temp_sym))); - (yyval.temp_sym).param_binding_begin = ~0; - initialize_symbol_from_const(state->prog, & (yyval.temp_sym), & (yyvsp[(1) - (1)].vector), GL_FALSE); - ;} - break; - - case 140: - -/* Line 1455 of yacc.c */ -#line 1348 "program_parse.y" - { memcpy((yyval.state), (yyvsp[(1) - (1)].state), sizeof((yyval.state))); ;} - break; - - case 141: - -/* Line 1455 of yacc.c */ -#line 1349 "program_parse.y" - { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} - break; - - case 142: - -/* Line 1455 of yacc.c */ -#line 1352 "program_parse.y" - { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} - break; - - case 143: - -/* Line 1455 of yacc.c */ -#line 1353 "program_parse.y" - { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} - break; - - case 144: - -/* Line 1455 of yacc.c */ -#line 1354 "program_parse.y" - { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} - break; - - case 145: - -/* Line 1455 of yacc.c */ -#line 1355 "program_parse.y" - { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} - break; - - case 146: - -/* Line 1455 of yacc.c */ -#line 1356 "program_parse.y" - { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} - break; - - case 147: - -/* Line 1455 of yacc.c */ -#line 1357 "program_parse.y" - { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} - break; - - case 148: - -/* Line 1455 of yacc.c */ -#line 1358 "program_parse.y" - { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} - break; - - case 149: - -/* Line 1455 of yacc.c */ -#line 1359 "program_parse.y" - { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} - break; - - case 150: - -/* Line 1455 of yacc.c */ -#line 1360 "program_parse.y" - { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} - break; - - case 151: - -/* Line 1455 of yacc.c */ -#line 1361 "program_parse.y" - { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} - break; - - case 152: - -/* Line 1455 of yacc.c */ -#line 1362 "program_parse.y" - { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} - break; - - case 153: - -/* Line 1455 of yacc.c */ -#line 1366 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = STATE_MATERIAL; - (yyval.state)[1] = (yyvsp[(2) - (3)].integer); - (yyval.state)[2] = (yyvsp[(3) - (3)].integer); - ;} - break; - - case 154: - -/* Line 1455 of yacc.c */ -#line 1375 "program_parse.y" - { - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 155: - -/* Line 1455 of yacc.c */ -#line 1379 "program_parse.y" - { - (yyval.integer) = STATE_EMISSION; - ;} - break; - - case 156: - -/* Line 1455 of yacc.c */ -#line 1383 "program_parse.y" - { - (yyval.integer) = STATE_SHININESS; - ;} - break; - - case 157: - -/* Line 1455 of yacc.c */ -#line 1389 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = STATE_LIGHT; - (yyval.state)[1] = (yyvsp[(3) - (5)].integer); - (yyval.state)[2] = (yyvsp[(5) - (5)].integer); - ;} - break; - - case 158: - -/* Line 1455 of yacc.c */ -#line 1398 "program_parse.y" - { - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 159: - -/* Line 1455 of yacc.c */ -#line 1402 "program_parse.y" - { - (yyval.integer) = STATE_POSITION; - ;} - break; - - case 160: - -/* Line 1455 of yacc.c */ -#line 1406 "program_parse.y" - { - if (!state->ctx->Extensions.EXT_point_parameters) { - yyerror(& (yylsp[(1) - (1)]), state, "GL_ARB_point_parameters not supported"); - YYERROR; - } - - (yyval.integer) = STATE_ATTENUATION; - ;} - break; - - case 161: - -/* Line 1455 of yacc.c */ -#line 1415 "program_parse.y" - { - (yyval.integer) = (yyvsp[(2) - (2)].integer); - ;} - break; - - case 162: - -/* Line 1455 of yacc.c */ -#line 1419 "program_parse.y" - { - (yyval.integer) = STATE_HALF_VECTOR; - ;} - break; - - case 163: - -/* Line 1455 of yacc.c */ -#line 1425 "program_parse.y" - { - (yyval.integer) = STATE_SPOT_DIRECTION; - ;} - break; - - case 164: - -/* Line 1455 of yacc.c */ -#line 1431 "program_parse.y" - { - (yyval.state)[0] = (yyvsp[(2) - (2)].state)[0]; - (yyval.state)[1] = (yyvsp[(2) - (2)].state)[1]; - ;} - break; - - case 165: - -/* Line 1455 of yacc.c */ -#line 1438 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = STATE_LIGHTMODEL_AMBIENT; - ;} - break; - - case 166: - -/* Line 1455 of yacc.c */ -#line 1443 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = STATE_LIGHTMODEL_SCENECOLOR; - (yyval.state)[1] = (yyvsp[(1) - (2)].integer); - ;} - break; - - case 167: - -/* Line 1455 of yacc.c */ -#line 1451 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = STATE_LIGHTPROD; - (yyval.state)[1] = (yyvsp[(3) - (6)].integer); - (yyval.state)[2] = (yyvsp[(5) - (6)].integer); - (yyval.state)[3] = (yyvsp[(6) - (6)].integer); - ;} - break; - - case 169: - -/* Line 1455 of yacc.c */ -#line 1463 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = (yyvsp[(3) - (3)].integer); - (yyval.state)[1] = (yyvsp[(2) - (3)].integer); - ;} - break; - - case 170: - -/* Line 1455 of yacc.c */ -#line 1471 "program_parse.y" - { - (yyval.integer) = STATE_TEXENV_COLOR; - ;} - break; - - case 171: - -/* Line 1455 of yacc.c */ -#line 1477 "program_parse.y" - { - (yyval.integer) = STATE_AMBIENT; - ;} - break; - - case 172: - -/* Line 1455 of yacc.c */ -#line 1481 "program_parse.y" - { - (yyval.integer) = STATE_DIFFUSE; - ;} - break; - - case 173: - -/* Line 1455 of yacc.c */ -#line 1485 "program_parse.y" - { - (yyval.integer) = STATE_SPECULAR; - ;} - break; - - case 174: - -/* Line 1455 of yacc.c */ -#line 1491 "program_parse.y" - { - if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxLights) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid light selector"); - YYERROR; - } - - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 175: - -/* Line 1455 of yacc.c */ -#line 1502 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = STATE_TEXGEN; - (yyval.state)[1] = (yyvsp[(2) - (4)].integer); - (yyval.state)[2] = (yyvsp[(3) - (4)].integer) + (yyvsp[(4) - (4)].integer); - ;} - break; - - case 176: - -/* Line 1455 of yacc.c */ -#line 1511 "program_parse.y" - { - (yyval.integer) = STATE_TEXGEN_EYE_S; - ;} - break; - - case 177: - -/* Line 1455 of yacc.c */ -#line 1515 "program_parse.y" - { - (yyval.integer) = STATE_TEXGEN_OBJECT_S; - ;} - break; - - case 178: - -/* Line 1455 of yacc.c */ -#line 1520 "program_parse.y" - { - (yyval.integer) = STATE_TEXGEN_EYE_S - STATE_TEXGEN_EYE_S; - ;} - break; - - case 179: - -/* Line 1455 of yacc.c */ -#line 1524 "program_parse.y" - { - (yyval.integer) = STATE_TEXGEN_EYE_T - STATE_TEXGEN_EYE_S; - ;} - break; - - case 180: - -/* Line 1455 of yacc.c */ -#line 1528 "program_parse.y" - { - (yyval.integer) = STATE_TEXGEN_EYE_R - STATE_TEXGEN_EYE_S; - ;} - break; - - case 181: - -/* Line 1455 of yacc.c */ -#line 1532 "program_parse.y" - { - (yyval.integer) = STATE_TEXGEN_EYE_Q - STATE_TEXGEN_EYE_S; - ;} - break; - - case 182: - -/* Line 1455 of yacc.c */ -#line 1538 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = (yyvsp[(2) - (2)].integer); - ;} - break; - - case 183: - -/* Line 1455 of yacc.c */ -#line 1545 "program_parse.y" - { - (yyval.integer) = STATE_FOG_COLOR; - ;} - break; - - case 184: - -/* Line 1455 of yacc.c */ -#line 1549 "program_parse.y" - { - (yyval.integer) = STATE_FOG_PARAMS; - ;} - break; - - case 185: - -/* Line 1455 of yacc.c */ -#line 1555 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = STATE_CLIPPLANE; - (yyval.state)[1] = (yyvsp[(3) - (5)].integer); - ;} - break; - - case 186: - -/* Line 1455 of yacc.c */ -#line 1563 "program_parse.y" - { - if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxClipPlanes) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid clip plane selector"); - YYERROR; - } - - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 187: - -/* Line 1455 of yacc.c */ -#line 1574 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = (yyvsp[(2) - (2)].integer); - ;} - break; - - case 188: - -/* Line 1455 of yacc.c */ -#line 1581 "program_parse.y" - { - (yyval.integer) = STATE_POINT_SIZE; - ;} - break; - - case 189: - -/* Line 1455 of yacc.c */ -#line 1585 "program_parse.y" - { - (yyval.integer) = STATE_POINT_ATTENUATION; - ;} - break; - - case 190: - -/* Line 1455 of yacc.c */ -#line 1591 "program_parse.y" - { - (yyval.state)[0] = (yyvsp[(1) - (5)].state)[0]; - (yyval.state)[1] = (yyvsp[(1) - (5)].state)[1]; - (yyval.state)[2] = (yyvsp[(4) - (5)].integer); - (yyval.state)[3] = (yyvsp[(4) - (5)].integer); - (yyval.state)[4] = (yyvsp[(1) - (5)].state)[2]; - ;} - break; - - case 191: - -/* Line 1455 of yacc.c */ -#line 1601 "program_parse.y" - { - (yyval.state)[0] = (yyvsp[(1) - (2)].state)[0]; - (yyval.state)[1] = (yyvsp[(1) - (2)].state)[1]; - (yyval.state)[2] = (yyvsp[(2) - (2)].state)[2]; - (yyval.state)[3] = (yyvsp[(2) - (2)].state)[3]; - (yyval.state)[4] = (yyvsp[(1) - (2)].state)[2]; - ;} - break; - - case 192: - -/* Line 1455 of yacc.c */ -#line 1611 "program_parse.y" - { - (yyval.state)[2] = 0; - (yyval.state)[3] = 3; - ;} - break; - - case 193: - -/* Line 1455 of yacc.c */ -#line 1616 "program_parse.y" - { - /* It seems logical that the matrix row range specifier would have - * to specify a range or more than one row (i.e., $5 > $3). - * However, the ARB_vertex_program spec says "a program will fail - * to load if is greater than ." This means that $3 == $5 - * is valid. - */ - if ((yyvsp[(3) - (6)].integer) > (yyvsp[(5) - (6)].integer)) { - yyerror(& (yylsp[(3) - (6)]), state, "invalid matrix row range"); - YYERROR; - } - - (yyval.state)[2] = (yyvsp[(3) - (6)].integer); - (yyval.state)[3] = (yyvsp[(5) - (6)].integer); - ;} - break; - - case 194: - -/* Line 1455 of yacc.c */ -#line 1634 "program_parse.y" - { - (yyval.state)[0] = (yyvsp[(2) - (3)].state)[0]; - (yyval.state)[1] = (yyvsp[(2) - (3)].state)[1]; - (yyval.state)[2] = (yyvsp[(3) - (3)].integer); - ;} - break; - - case 195: - -/* Line 1455 of yacc.c */ -#line 1642 "program_parse.y" - { - (yyval.integer) = 0; - ;} - break; - - case 196: - -/* Line 1455 of yacc.c */ -#line 1646 "program_parse.y" - { - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 197: - -/* Line 1455 of yacc.c */ -#line 1652 "program_parse.y" - { - (yyval.integer) = STATE_MATRIX_INVERSE; - ;} - break; - - case 198: - -/* Line 1455 of yacc.c */ -#line 1656 "program_parse.y" - { - (yyval.integer) = STATE_MATRIX_TRANSPOSE; - ;} - break; - - case 199: - -/* Line 1455 of yacc.c */ -#line 1660 "program_parse.y" - { - (yyval.integer) = STATE_MATRIX_INVTRANS; - ;} - break; - - case 200: - -/* Line 1455 of yacc.c */ -#line 1666 "program_parse.y" - { - if ((yyvsp[(1) - (1)].integer) > 3) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid matrix row reference"); - YYERROR; - } - - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 201: - -/* Line 1455 of yacc.c */ -#line 1677 "program_parse.y" - { - (yyval.state)[0] = STATE_MODELVIEW_MATRIX; - (yyval.state)[1] = (yyvsp[(2) - (2)].integer); - ;} - break; - - case 202: - -/* Line 1455 of yacc.c */ -#line 1682 "program_parse.y" - { - (yyval.state)[0] = STATE_PROJECTION_MATRIX; - (yyval.state)[1] = 0; - ;} - break; - - case 203: - -/* Line 1455 of yacc.c */ -#line 1687 "program_parse.y" - { - (yyval.state)[0] = STATE_MVP_MATRIX; - (yyval.state)[1] = 0; - ;} - break; - - case 204: - -/* Line 1455 of yacc.c */ -#line 1692 "program_parse.y" - { - (yyval.state)[0] = STATE_TEXTURE_MATRIX; - (yyval.state)[1] = (yyvsp[(2) - (2)].integer); - ;} - break; - - case 205: - -/* Line 1455 of yacc.c */ -#line 1697 "program_parse.y" - { - yyerror(& (yylsp[(1) - (4)]), state, "GL_ARB_matrix_palette not supported"); - YYERROR; - ;} - break; - - case 206: - -/* Line 1455 of yacc.c */ -#line 1702 "program_parse.y" - { - (yyval.state)[0] = STATE_PROGRAM_MATRIX; - (yyval.state)[1] = (yyvsp[(3) - (4)].integer); - ;} - break; - - case 207: - -/* Line 1455 of yacc.c */ -#line 1709 "program_parse.y" - { - (yyval.integer) = 0; - ;} - break; - - case 208: - -/* Line 1455 of yacc.c */ -#line 1713 "program_parse.y" - { - (yyval.integer) = (yyvsp[(2) - (3)].integer); - ;} - break; - - case 209: - -/* Line 1455 of yacc.c */ -#line 1718 "program_parse.y" - { - /* Since GL_ARB_vertex_blend isn't supported, only modelview matrix - * zero is valid. - */ - if ((yyvsp[(1) - (1)].integer) != 0) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid modelview matrix index"); - YYERROR; - } - - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 210: - -/* Line 1455 of yacc.c */ -#line 1731 "program_parse.y" - { - /* Since GL_ARB_matrix_palette isn't supported, just let any value - * through here. The error will be generated later. - */ - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 211: - -/* Line 1455 of yacc.c */ -#line 1739 "program_parse.y" - { - if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxProgramMatrices) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid program matrix selector"); - YYERROR; - } - - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 212: - -/* Line 1455 of yacc.c */ -#line 1750 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = STATE_DEPTH_RANGE; - ;} - break; - - case 217: - -/* Line 1455 of yacc.c */ -#line 1762 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = state->state_param_enum; - (yyval.state)[1] = STATE_ENV; - (yyval.state)[2] = (yyvsp[(4) - (5)].state)[0]; - (yyval.state)[3] = (yyvsp[(4) - (5)].state)[1]; - ;} - break; - - case 218: - -/* Line 1455 of yacc.c */ -#line 1772 "program_parse.y" - { - (yyval.state)[0] = (yyvsp[(1) - (1)].integer); - (yyval.state)[1] = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 219: - -/* Line 1455 of yacc.c */ -#line 1777 "program_parse.y" - { - (yyval.state)[0] = (yyvsp[(1) - (3)].integer); - (yyval.state)[1] = (yyvsp[(3) - (3)].integer); - ;} - break; - - case 220: - -/* Line 1455 of yacc.c */ -#line 1784 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = state->state_param_enum; - (yyval.state)[1] = STATE_ENV; - (yyval.state)[2] = (yyvsp[(4) - (5)].integer); - (yyval.state)[3] = (yyvsp[(4) - (5)].integer); - ;} - break; - - case 221: - -/* Line 1455 of yacc.c */ -#line 1794 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = state->state_param_enum; - (yyval.state)[1] = STATE_LOCAL; - (yyval.state)[2] = (yyvsp[(4) - (5)].state)[0]; - (yyval.state)[3] = (yyvsp[(4) - (5)].state)[1]; - ;} - break; - - case 222: - -/* Line 1455 of yacc.c */ -#line 1803 "program_parse.y" - { - (yyval.state)[0] = (yyvsp[(1) - (1)].integer); - (yyval.state)[1] = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 223: - -/* Line 1455 of yacc.c */ -#line 1808 "program_parse.y" - { - (yyval.state)[0] = (yyvsp[(1) - (3)].integer); - (yyval.state)[1] = (yyvsp[(3) - (3)].integer); - ;} - break; - - case 224: - -/* Line 1455 of yacc.c */ -#line 1815 "program_parse.y" - { - memset((yyval.state), 0, sizeof((yyval.state))); - (yyval.state)[0] = state->state_param_enum; - (yyval.state)[1] = STATE_LOCAL; - (yyval.state)[2] = (yyvsp[(4) - (5)].integer); - (yyval.state)[3] = (yyvsp[(4) - (5)].integer); - ;} - break; - - case 225: - -/* Line 1455 of yacc.c */ -#line 1825 "program_parse.y" - { - if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->limits->MaxEnvParams) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid environment parameter reference"); - YYERROR; - } - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 226: - -/* Line 1455 of yacc.c */ -#line 1835 "program_parse.y" - { - if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->limits->MaxLocalParams) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid local parameter reference"); - YYERROR; - } - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 231: - -/* Line 1455 of yacc.c */ -#line 1850 "program_parse.y" - { - (yyval.vector).count = 4; - (yyval.vector).data[0] = (yyvsp[(1) - (1)].real); - (yyval.vector).data[1] = (yyvsp[(1) - (1)].real); - (yyval.vector).data[2] = (yyvsp[(1) - (1)].real); - (yyval.vector).data[3] = (yyvsp[(1) - (1)].real); - ;} - break; - - case 232: - -/* Line 1455 of yacc.c */ -#line 1860 "program_parse.y" - { - (yyval.vector).count = 1; - (yyval.vector).data[0] = (yyvsp[(1) - (1)].real); - (yyval.vector).data[1] = (yyvsp[(1) - (1)].real); - (yyval.vector).data[2] = (yyvsp[(1) - (1)].real); - (yyval.vector).data[3] = (yyvsp[(1) - (1)].real); - ;} - break; - - case 233: - -/* Line 1455 of yacc.c */ -#line 1868 "program_parse.y" - { - (yyval.vector).count = 1; - (yyval.vector).data[0] = (float) (yyvsp[(1) - (1)].integer); - (yyval.vector).data[1] = (float) (yyvsp[(1) - (1)].integer); - (yyval.vector).data[2] = (float) (yyvsp[(1) - (1)].integer); - (yyval.vector).data[3] = (float) (yyvsp[(1) - (1)].integer); - ;} - break; - - case 234: - -/* Line 1455 of yacc.c */ -#line 1878 "program_parse.y" - { - (yyval.vector).count = 4; - (yyval.vector).data[0] = (yyvsp[(2) - (3)].real); - (yyval.vector).data[1] = 0.0f; - (yyval.vector).data[2] = 0.0f; - (yyval.vector).data[3] = 1.0f; - ;} - break; - - case 235: - -/* Line 1455 of yacc.c */ -#line 1886 "program_parse.y" - { - (yyval.vector).count = 4; - (yyval.vector).data[0] = (yyvsp[(2) - (5)].real); - (yyval.vector).data[1] = (yyvsp[(4) - (5)].real); - (yyval.vector).data[2] = 0.0f; - (yyval.vector).data[3] = 1.0f; - ;} - break; - - case 236: - -/* Line 1455 of yacc.c */ -#line 1895 "program_parse.y" - { - (yyval.vector).count = 4; - (yyval.vector).data[0] = (yyvsp[(2) - (7)].real); - (yyval.vector).data[1] = (yyvsp[(4) - (7)].real); - (yyval.vector).data[2] = (yyvsp[(6) - (7)].real); - (yyval.vector).data[3] = 1.0f; - ;} - break; - - case 237: - -/* Line 1455 of yacc.c */ -#line 1904 "program_parse.y" - { - (yyval.vector).count = 4; - (yyval.vector).data[0] = (yyvsp[(2) - (9)].real); - (yyval.vector).data[1] = (yyvsp[(4) - (9)].real); - (yyval.vector).data[2] = (yyvsp[(6) - (9)].real); - (yyval.vector).data[3] = (yyvsp[(8) - (9)].real); - ;} - break; - - case 238: - -/* Line 1455 of yacc.c */ -#line 1914 "program_parse.y" - { - (yyval.real) = ((yyvsp[(1) - (2)].negate)) ? -(yyvsp[(2) - (2)].real) : (yyvsp[(2) - (2)].real); - ;} - break; - - case 239: - -/* Line 1455 of yacc.c */ -#line 1918 "program_parse.y" - { - (yyval.real) = (float)(((yyvsp[(1) - (2)].negate)) ? -(yyvsp[(2) - (2)].integer) : (yyvsp[(2) - (2)].integer)); - ;} - break; - - case 240: - -/* Line 1455 of yacc.c */ -#line 1923 "program_parse.y" - { (yyval.negate) = FALSE; ;} - break; - - case 241: - -/* Line 1455 of yacc.c */ -#line 1924 "program_parse.y" - { (yyval.negate) = TRUE; ;} - break; - - case 242: - -/* Line 1455 of yacc.c */ -#line 1925 "program_parse.y" - { (yyval.negate) = FALSE; ;} - break; - - case 243: - -/* Line 1455 of yacc.c */ -#line 1928 "program_parse.y" - { (yyval.integer) = (yyvsp[(2) - (2)].integer); ;} - break; - - case 245: - -/* Line 1455 of yacc.c */ -#line 1932 "program_parse.y" - { - /* NV_fragment_program_option defines the size qualifiers in a - * fairly broken way. "SHORT" or "LONG" can optionally be used - * before TEMP or OUTPUT. However, neither is a reserved word! - * This means that we have to parse it as an identifier, then check - * to make sure it's one of the valid values. *sigh* - * - * In addition, the grammar in the extension spec does *not* allow - * the size specifier to be optional, but all known implementations - * do. - */ - if (!state->option.NV_fragment) { - yyerror(& (yylsp[(1) - (1)]), state, "unexpected IDENTIFIER"); - YYERROR; - } - - if (strcmp("SHORT", (yyvsp[(1) - (1)].string)) == 0) { - } else if (strcmp("LONG", (yyvsp[(1) - (1)].string)) == 0) { - } else { - char *const err_str = - make_error_string("invalid storage size specifier \"%s\"", - (yyvsp[(1) - (1)].string)); - - yyerror(& (yylsp[(1) - (1)]), state, (err_str != NULL) - ? err_str : "invalid storage size specifier"); - - if (err_str != NULL) { - free(err_str); - } - - YYERROR; - } - ;} - break; - - case 246: - -/* Line 1455 of yacc.c */ -#line 1966 "program_parse.y" - { - ;} - break; - - case 247: - -/* Line 1455 of yacc.c */ -#line 1970 "program_parse.y" - { (yyval.integer) = (yyvsp[(1) - (1)].integer); ;} - break; - - case 249: - -/* Line 1455 of yacc.c */ -#line 1974 "program_parse.y" - { - if (!declare_variable(state, (yyvsp[(3) - (3)].string), (yyvsp[(0) - (3)].integer), & (yylsp[(3) - (3)]))) { - free((yyvsp[(3) - (3)].string)); - YYERROR; - } - ;} - break; - - case 250: - -/* Line 1455 of yacc.c */ -#line 1981 "program_parse.y" - { - if (!declare_variable(state, (yyvsp[(1) - (1)].string), (yyvsp[(0) - (1)].integer), & (yylsp[(1) - (1)]))) { - free((yyvsp[(1) - (1)].string)); - YYERROR; - } - ;} - break; - - case 251: - -/* Line 1455 of yacc.c */ -#line 1990 "program_parse.y" - { - struct asm_symbol *const s = - declare_variable(state, (yyvsp[(3) - (5)].string), at_output, & (yylsp[(3) - (5)])); - - if (s == NULL) { - free((yyvsp[(3) - (5)].string)); - YYERROR; - } else { - s->output_binding = (yyvsp[(5) - (5)].result); - } - ;} - break; - - case 252: - -/* Line 1455 of yacc.c */ -#line 2004 "program_parse.y" - { - if (state->mode == ARB_vertex) { - (yyval.result) = VERT_RESULT_HPOS; - } else { - yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name"); - YYERROR; - } - ;} - break; - - case 253: - -/* Line 1455 of yacc.c */ -#line 2013 "program_parse.y" - { - if (state->mode == ARB_vertex) { - (yyval.result) = VERT_RESULT_FOGC; - } else { - yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name"); - YYERROR; - } - ;} - break; - - case 254: - -/* Line 1455 of yacc.c */ -#line 2022 "program_parse.y" - { - (yyval.result) = (yyvsp[(2) - (2)].result); - ;} - break; - - case 255: - -/* Line 1455 of yacc.c */ -#line 2026 "program_parse.y" - { - if (state->mode == ARB_vertex) { - (yyval.result) = VERT_RESULT_PSIZ; - } else { - yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name"); - YYERROR; - } - ;} - break; - - case 256: - -/* Line 1455 of yacc.c */ -#line 2035 "program_parse.y" - { - if (state->mode == ARB_vertex) { - (yyval.result) = VERT_RESULT_TEX0 + (yyvsp[(3) - (3)].integer); - } else { - yyerror(& (yylsp[(2) - (3)]), state, "invalid program result name"); - YYERROR; - } - ;} - break; - - case 257: - -/* Line 1455 of yacc.c */ -#line 2044 "program_parse.y" - { - if (state->mode == ARB_fragment) { - (yyval.result) = FRAG_RESULT_DEPTH; - } else { - yyerror(& (yylsp[(2) - (2)]), state, "invalid program result name"); - YYERROR; - } - ;} - break; - - case 258: - -/* Line 1455 of yacc.c */ -#line 2055 "program_parse.y" - { - (yyval.result) = (yyvsp[(2) - (3)].integer) + (yyvsp[(3) - (3)].integer); - ;} - break; - - case 259: - -/* Line 1455 of yacc.c */ -#line 2061 "program_parse.y" - { - (yyval.integer) = (state->mode == ARB_vertex) - ? VERT_RESULT_COL0 - : FRAG_RESULT_COLOR; - ;} - break; - - case 260: - -/* Line 1455 of yacc.c */ -#line 2067 "program_parse.y" - { - if (state->mode == ARB_vertex) { - (yyval.integer) = VERT_RESULT_COL0; - } else { - yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name"); - YYERROR; - } - ;} - break; - - case 261: - -/* Line 1455 of yacc.c */ -#line 2076 "program_parse.y" - { - if (state->mode == ARB_vertex) { - (yyval.integer) = VERT_RESULT_BFC0; - } else { - yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name"); - YYERROR; - } - ;} - break; - - case 262: - -/* Line 1455 of yacc.c */ -#line 2087 "program_parse.y" - { - (yyval.integer) = 0; - ;} - break; - - case 263: - -/* Line 1455 of yacc.c */ -#line 2091 "program_parse.y" - { - if (state->mode == ARB_vertex) { - (yyval.integer) = 0; - } else { - yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name"); - YYERROR; - } - ;} - break; - - case 264: - -/* Line 1455 of yacc.c */ -#line 2100 "program_parse.y" - { - if (state->mode == ARB_vertex) { - (yyval.integer) = 1; - } else { - yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name"); - YYERROR; - } - ;} - break; - - case 265: - -/* Line 1455 of yacc.c */ -#line 2110 "program_parse.y" - { (yyval.integer) = 0; ;} - break; - - case 266: - -/* Line 1455 of yacc.c */ -#line 2111 "program_parse.y" - { (yyval.integer) = 0; ;} - break; - - case 267: - -/* Line 1455 of yacc.c */ -#line 2112 "program_parse.y" - { (yyval.integer) = 1; ;} - break; - - case 268: - -/* Line 1455 of yacc.c */ -#line 2115 "program_parse.y" - { (yyval.integer) = 0; ;} - break; - - case 269: - -/* Line 1455 of yacc.c */ -#line 2116 "program_parse.y" - { (yyval.integer) = 0; ;} - break; - - case 270: - -/* Line 1455 of yacc.c */ -#line 2117 "program_parse.y" - { (yyval.integer) = 1; ;} - break; - - case 271: - -/* Line 1455 of yacc.c */ -#line 2120 "program_parse.y" - { (yyval.integer) = 0; ;} - break; - - case 272: - -/* Line 1455 of yacc.c */ -#line 2121 "program_parse.y" - { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;} - break; - - case 273: - -/* Line 1455 of yacc.c */ -#line 2124 "program_parse.y" - { (yyval.integer) = 0; ;} - break; - - case 274: - -/* Line 1455 of yacc.c */ -#line 2125 "program_parse.y" - { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;} - break; - - case 275: - -/* Line 1455 of yacc.c */ -#line 2128 "program_parse.y" - { (yyval.integer) = 0; ;} - break; - - case 276: - -/* Line 1455 of yacc.c */ -#line 2129 "program_parse.y" - { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;} - break; - - case 277: - -/* Line 1455 of yacc.c */ -#line 2133 "program_parse.y" - { - if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxTextureCoordUnits) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid texture coordinate unit selector"); - YYERROR; - } - - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 278: - -/* Line 1455 of yacc.c */ -#line 2144 "program_parse.y" - { - if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxTextureImageUnits) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid texture image unit selector"); - YYERROR; - } - - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 279: - -/* Line 1455 of yacc.c */ -#line 2155 "program_parse.y" - { - if ((unsigned) (yyvsp[(1) - (1)].integer) >= state->MaxTextureUnits) { - yyerror(& (yylsp[(1) - (1)]), state, "invalid texture unit selector"); - YYERROR; - } - - (yyval.integer) = (yyvsp[(1) - (1)].integer); - ;} - break; - - case 280: - -/* Line 1455 of yacc.c */ -#line 2166 "program_parse.y" - { - struct asm_symbol *exist = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(2) - (4)].string)); - struct asm_symbol *target = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, (yyvsp[(4) - (4)].string)); - - free((yyvsp[(4) - (4)].string)); - - if (exist != NULL) { - char m[1000]; - _mesa_snprintf(m, sizeof(m), "redeclared identifier: %s", (yyvsp[(2) - (4)].string)); - free((yyvsp[(2) - (4)].string)); - yyerror(& (yylsp[(2) - (4)]), state, m); - YYERROR; - } else if (target == NULL) { - free((yyvsp[(2) - (4)].string)); - yyerror(& (yylsp[(4) - (4)]), state, - "undefined variable binding in ALIAS statement"); - YYERROR; - } else { - _mesa_symbol_table_add_symbol(state->st, 0, (yyvsp[(2) - (4)].string), target); - } - ;} - break; - - - -/* Line 1455 of yacc.c */ -#line 4937 "program_parse.tab.c" - default: break; - } - YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - *++yylsp = yyloc; - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if ! YYERROR_VERBOSE - yyerror (&yylloc, state, YY_("syntax error")); -#else - { - YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); - if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) - { - YYSIZE_T yyalloc = 2 * yysize; - if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) - yyalloc = YYSTACK_ALLOC_MAXIMUM; - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yyalloc); - if (yymsg) - yymsg_alloc = yyalloc; - else - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - } - } - - if (0 < yysize && yysize <= yymsg_alloc) - { - (void) yysyntax_error (yymsg, yystate, yychar); - yyerror (&yylloc, state, yymsg); - } - else - { - yyerror (&yylloc, state, YY_("syntax error")); - if (yysize != 0) - goto yyexhaustedlab; - } - } -#endif - } - - yyerror_range[0] = yylloc; - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval, &yylloc, state); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - - /* Pacify compilers like GCC when the user code never invokes - YYERROR and the label yyerrorlab therefore never appears in user - code. */ - if (/*CONSTCOND*/ 0) - goto yyerrorlab; - - yyerror_range[0] = yylsp[1-yylen]; - /* Do not reclaim the symbols of the rule which action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - yyerror_range[0] = *yylsp; - yydestruct ("Error: popping", - yystos[yystate], yyvsp, yylsp, state); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - *++yyvsp = yylval; - - yyerror_range[1] = yylloc; - /* Using YYLLOC is tempting, but would change the location of - the lookahead. YYLOC is available though. */ - YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); - *++yylsp = yyloc; - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#if !defined(yyoverflow) || YYERROR_VERBOSE -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ -yyexhaustedlab: - yyerror (&yylloc, state, YY_("memory exhausted")); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: - if (yychar != YYEMPTY) - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval, &yylloc, state); - /* Do not reclaim the symbols of the rule which action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp, yylsp, state); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif -#if YYERROR_VERBOSE - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); -#endif - /* Make sure YYID is used. */ - return YYID (yyresult); -} - - - -/* Line 1675 of yacc.c */ -#line 2195 "program_parse.y" - - -void -asm_instruction_set_operands(struct asm_instruction *inst, - const struct prog_dst_register *dst, - const struct asm_src_register *src0, - const struct asm_src_register *src1, - const struct asm_src_register *src2) -{ - /* In the core ARB extensions only the KIL instruction doesn't have a - * destination register. - */ - if (dst == NULL) { - init_dst_reg(& inst->Base.DstReg); - } else { - inst->Base.DstReg = *dst; - } - - /* The only instruction that doesn't have any source registers is the - * condition-code based KIL instruction added by NV_fragment_program_option. - */ - if (src0 != NULL) { - inst->Base.SrcReg[0] = src0->Base; - inst->SrcReg[0] = *src0; - } else { - init_src_reg(& inst->SrcReg[0]); - } - - if (src1 != NULL) { - inst->Base.SrcReg[1] = src1->Base; - inst->SrcReg[1] = *src1; - } else { - init_src_reg(& inst->SrcReg[1]); - } - - if (src2 != NULL) { - inst->Base.SrcReg[2] = src2->Base; - inst->SrcReg[2] = *src2; - } else { - init_src_reg(& inst->SrcReg[2]); - } -} - - -struct asm_instruction * -asm_instruction_ctor(gl_inst_opcode op, - const struct prog_dst_register *dst, - const struct asm_src_register *src0, - const struct asm_src_register *src1, - const struct asm_src_register *src2) -{ - struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction); - - if (inst) { - _mesa_init_instructions(& inst->Base, 1); - inst->Base.Opcode = op; - - asm_instruction_set_operands(inst, dst, src0, src1, src2); - } - - return inst; -} - - -struct asm_instruction * -asm_instruction_copy_ctor(const struct prog_instruction *base, - const struct prog_dst_register *dst, - const struct asm_src_register *src0, - const struct asm_src_register *src1, - const struct asm_src_register *src2) -{ - struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction); - - if (inst) { - _mesa_init_instructions(& inst->Base, 1); - inst->Base.Opcode = base->Opcode; - inst->Base.CondUpdate = base->CondUpdate; - inst->Base.CondDst = base->CondDst; - inst->Base.SaturateMode = base->SaturateMode; - inst->Base.Precision = base->Precision; - - asm_instruction_set_operands(inst, dst, src0, src1, src2); - } - - return inst; -} - - -void -init_dst_reg(struct prog_dst_register *r) -{ - memset(r, 0, sizeof(*r)); - r->File = PROGRAM_UNDEFINED; - r->WriteMask = WRITEMASK_XYZW; - r->CondMask = COND_TR; - r->CondSwizzle = SWIZZLE_NOOP; -} - - -/** Like init_dst_reg() but set the File and Index fields. */ -void -set_dst_reg(struct prog_dst_register *r, gl_register_file file, GLint index) -{ - const GLint maxIndex = 1 << INST_INDEX_BITS; - const GLint minIndex = 0; - ASSERT(index >= minIndex); - (void) minIndex; - ASSERT(index <= maxIndex); - (void) maxIndex; - ASSERT(file == PROGRAM_TEMPORARY || - file == PROGRAM_ADDRESS || - file == PROGRAM_OUTPUT); - memset(r, 0, sizeof(*r)); - r->File = file; - r->Index = index; - r->WriteMask = WRITEMASK_XYZW; - r->CondMask = COND_TR; - r->CondSwizzle = SWIZZLE_NOOP; -} - - -void -init_src_reg(struct asm_src_register *r) -{ - memset(r, 0, sizeof(*r)); - r->Base.File = PROGRAM_UNDEFINED; - r->Base.Swizzle = SWIZZLE_NOOP; - r->Symbol = NULL; -} - - -/** Like init_src_reg() but set the File and Index fields. - * \return GL_TRUE if a valid src register, GL_FALSE otherwise - */ -void -set_src_reg(struct asm_src_register *r, gl_register_file file, GLint index) -{ - set_src_reg_swz(r, file, index, SWIZZLE_XYZW); -} - - -void -set_src_reg_swz(struct asm_src_register *r, gl_register_file file, GLint index, - GLuint swizzle) -{ - const GLint maxIndex = (1 << INST_INDEX_BITS) - 1; - const GLint minIndex = -(1 << INST_INDEX_BITS); - ASSERT(file < PROGRAM_FILE_MAX); - ASSERT(index >= minIndex); - (void) minIndex; - ASSERT(index <= maxIndex); - (void) maxIndex; - memset(r, 0, sizeof(*r)); - r->Base.File = file; - r->Base.Index = index; - r->Base.Swizzle = swizzle; - r->Symbol = NULL; -} - - -/** - * Validate the set of inputs used by a program - * - * Validates that legal sets of inputs are used by the program. In this case - * "used" included both reading the input or binding the input to a name using - * the \c ATTRIB command. - * - * \return - * \c TRUE if the combination of inputs used is valid, \c FALSE otherwise. - */ -int -validate_inputs(struct YYLTYPE *locp, struct asm_parser_state *state) -{ - const int inputs = state->prog->InputsRead | state->InputsBound; - - if (((inputs & 0x0ffff) & (inputs >> 16)) != 0) { - yyerror(locp, state, "illegal use of generic attribute and name attribute"); - return 0; - } - - return 1; -} - - -struct asm_symbol * -declare_variable(struct asm_parser_state *state, char *name, enum asm_type t, - struct YYLTYPE *locp) -{ - struct asm_symbol *s = NULL; - struct asm_symbol *exist = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, name); - - - if (exist != NULL) { - yyerror(locp, state, "redeclared identifier"); - } else { - s = calloc(1, sizeof(struct asm_symbol)); - s->name = name; - s->type = t; - - switch (t) { - case at_temp: - if (state->prog->NumTemporaries >= state->limits->MaxTemps) { - yyerror(locp, state, "too many temporaries declared"); - free(s); - return NULL; - } - - s->temp_binding = state->prog->NumTemporaries; - state->prog->NumTemporaries++; - break; - - case at_address: - if (state->prog->NumAddressRegs >= state->limits->MaxAddressRegs) { - yyerror(locp, state, "too many address registers declared"); - free(s); - return NULL; - } - - /* FINISHME: Add support for multiple address registers. - */ - state->prog->NumAddressRegs++; - break; - - default: - break; - } - - _mesa_symbol_table_add_symbol(state->st, 0, s->name, s); - s->next = state->sym; - state->sym = s; - } - - return s; -} - - -int add_state_reference(struct gl_program_parameter_list *param_list, - const gl_state_index tokens[STATE_LENGTH]) -{ - const GLuint size = 4; /* XXX fix */ - char *name; - GLint index; - - name = _mesa_program_state_string(tokens); - index = _mesa_add_parameter(param_list, PROGRAM_STATE_VAR, name, - size, GL_NONE, NULL, tokens, 0x0); - param_list->StateFlags |= _mesa_program_state_flags(tokens); - - /* free name string here since we duplicated it in add_parameter() */ - free(name); - - return index; -} - - -int -initialize_symbol_from_state(struct gl_program *prog, - struct asm_symbol *param_var, - const gl_state_index tokens[STATE_LENGTH]) -{ - int idx = -1; - gl_state_index state_tokens[STATE_LENGTH]; - - - memcpy(state_tokens, tokens, sizeof(state_tokens)); - - param_var->type = at_param; - param_var->param_binding_type = PROGRAM_STATE_VAR; - - /* If we are adding a STATE_MATRIX that has multiple rows, we need to - * unroll it and call add_state_reference() for each row - */ - if ((state_tokens[0] == STATE_MODELVIEW_MATRIX || - state_tokens[0] == STATE_PROJECTION_MATRIX || - state_tokens[0] == STATE_MVP_MATRIX || - state_tokens[0] == STATE_TEXTURE_MATRIX || - state_tokens[0] == STATE_PROGRAM_MATRIX) - && (state_tokens[2] != state_tokens[3])) { - int row; - const int first_row = state_tokens[2]; - const int last_row = state_tokens[3]; - - for (row = first_row; row <= last_row; row++) { - state_tokens[2] = state_tokens[3] = row; - - idx = add_state_reference(prog->Parameters, state_tokens); - if (param_var->param_binding_begin == ~0U) { - param_var->param_binding_begin = idx; - param_var->param_binding_swizzle = SWIZZLE_XYZW; - } - - param_var->param_binding_length++; - } - } - else { - idx = add_state_reference(prog->Parameters, state_tokens); - if (param_var->param_binding_begin == ~0U) { - param_var->param_binding_begin = idx; - param_var->param_binding_swizzle = SWIZZLE_XYZW; - } - param_var->param_binding_length++; - } - - return idx; -} - - -int -initialize_symbol_from_param(struct gl_program *prog, - struct asm_symbol *param_var, - const gl_state_index tokens[STATE_LENGTH]) -{ - int idx = -1; - gl_state_index state_tokens[STATE_LENGTH]; - - - memcpy(state_tokens, tokens, sizeof(state_tokens)); - - assert((state_tokens[0] == STATE_VERTEX_PROGRAM) - || (state_tokens[0] == STATE_FRAGMENT_PROGRAM)); - assert((state_tokens[1] == STATE_ENV) - || (state_tokens[1] == STATE_LOCAL)); - - /* - * The param type is STATE_VAR. The program parameter entry will - * effectively be a pointer into the LOCAL or ENV parameter array. - */ - param_var->type = at_param; - param_var->param_binding_type = PROGRAM_STATE_VAR; - - /* If we are adding a STATE_ENV or STATE_LOCAL that has multiple elements, - * we need to unroll it and call add_state_reference() for each row - */ - if (state_tokens[2] != state_tokens[3]) { - int row; - const int first_row = state_tokens[2]; - const int last_row = state_tokens[3]; - - for (row = first_row; row <= last_row; row++) { - state_tokens[2] = state_tokens[3] = row; - - idx = add_state_reference(prog->Parameters, state_tokens); - if (param_var->param_binding_begin == ~0U) { - param_var->param_binding_begin = idx; - param_var->param_binding_swizzle = SWIZZLE_XYZW; - } - param_var->param_binding_length++; - } - } - else { - idx = add_state_reference(prog->Parameters, state_tokens); - if (param_var->param_binding_begin == ~0U) { - param_var->param_binding_begin = idx; - param_var->param_binding_swizzle = SWIZZLE_XYZW; - } - param_var->param_binding_length++; - } - - return idx; -} - - -/** - * Put a float/vector constant/literal into the parameter list. - * \param param_var returns info about the parameter/constant's location, - * binding, type, etc. - * \param vec the vector/constant to add - * \param allowSwizzle if true, try to consolidate constants which only differ - * by a swizzle. We don't want to do this when building - * arrays of constants that may be indexed indirectly. - * \return index of the constant in the parameter list. - */ -int -initialize_symbol_from_const(struct gl_program *prog, - struct asm_symbol *param_var, - const struct asm_vector *vec, - GLboolean allowSwizzle) -{ - unsigned swizzle; - const int idx = _mesa_add_unnamed_constant(prog->Parameters, - vec->data, vec->count, - allowSwizzle ? &swizzle : NULL); - - param_var->type = at_param; - param_var->param_binding_type = PROGRAM_CONSTANT; - - if (param_var->param_binding_begin == ~0U) { - param_var->param_binding_begin = idx; - param_var->param_binding_swizzle = allowSwizzle ? swizzle : SWIZZLE_XYZW; - } - param_var->param_binding_length++; - - return idx; -} - - -char * -make_error_string(const char *fmt, ...) -{ - int length; - char *str; - va_list args; - - - /* Call vsnprintf once to determine how large the final string is. Call it - * again to do the actual formatting. from the vsnprintf manual page: - * - * Upon successful return, these functions return the number of - * characters printed (not including the trailing '\0' used to end - * output to strings). - */ - va_start(args, fmt); - length = 1 + vsnprintf(NULL, 0, fmt, args); - va_end(args); - - str = malloc(length); - if (str) { - va_start(args, fmt); - vsnprintf(str, length, fmt, args); - va_end(args); - } - - return str; -} - - -void -yyerror(YYLTYPE *locp, struct asm_parser_state *state, const char *s) -{ - char *err_str; - - - err_str = make_error_string("glProgramStringARB(%s)\n", s); - if (err_str) { - _mesa_error(state->ctx, GL_INVALID_OPERATION, err_str); - free(err_str); - } - - err_str = make_error_string("line %u, char %u: error: %s\n", - locp->first_line, locp->first_column, s); - _mesa_set_program_error(state->ctx, locp->position, err_str); - - if (err_str) { - free(err_str); - } -} - - -GLboolean -_mesa_parse_arb_program(GLcontext *ctx, GLenum target, const GLubyte *str, - GLsizei len, struct asm_parser_state *state) -{ - struct asm_instruction *inst; - unsigned i; - GLubyte *strz; - GLboolean result = GL_FALSE; - void *temp; - struct asm_symbol *sym; - - state->ctx = ctx; - state->prog->Target = target; - state->prog->Parameters = _mesa_new_parameter_list(); - - /* Make a copy of the program string and force it to be NUL-terminated. - */ - strz = (GLubyte *) malloc(len + 1); - if (strz == NULL) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramStringARB"); - return GL_FALSE; - } - memcpy (strz, str, len); - strz[len] = '\0'; - - state->prog->String = strz; - - state->st = _mesa_symbol_table_ctor(); - - state->limits = (target == GL_VERTEX_PROGRAM_ARB) - ? & ctx->Const.VertexProgram - : & ctx->Const.FragmentProgram; - - state->MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits; - state->MaxTextureCoordUnits = ctx->Const.MaxTextureCoordUnits; - state->MaxTextureUnits = ctx->Const.MaxTextureUnits; - state->MaxClipPlanes = ctx->Const.MaxClipPlanes; - state->MaxLights = ctx->Const.MaxLights; - state->MaxProgramMatrices = ctx->Const.MaxProgramMatrices; - - state->state_param_enum = (target == GL_VERTEX_PROGRAM_ARB) - ? STATE_VERTEX_PROGRAM : STATE_FRAGMENT_PROGRAM; - - _mesa_set_program_error(ctx, -1, NULL); - - _mesa_program_lexer_ctor(& state->scanner, state, (const char *) str, len); - yyparse(state); - _mesa_program_lexer_dtor(state->scanner); - - - if (ctx->Program.ErrorPos != -1) { - goto error; - } - - if (! _mesa_layout_parameters(state)) { - struct YYLTYPE loc; - - loc.first_line = 0; - loc.first_column = 0; - loc.position = len; - - yyerror(& loc, state, "invalid PARAM usage"); - goto error; - } - - - - /* Add one instruction to store the "END" instruction. - */ - state->prog->Instructions = - _mesa_alloc_instructions(state->prog->NumInstructions + 1); - inst = state->inst_head; - for (i = 0; i < state->prog->NumInstructions; i++) { - struct asm_instruction *const temp = inst->next; - - state->prog->Instructions[i] = inst->Base; - inst = temp; - } - - /* Finally, tag on an OPCODE_END instruction */ - { - const GLuint numInst = state->prog->NumInstructions; - _mesa_init_instructions(state->prog->Instructions + numInst, 1); - state->prog->Instructions[numInst].Opcode = OPCODE_END; - } - state->prog->NumInstructions++; - - state->prog->NumParameters = state->prog->Parameters->NumParameters; - state->prog->NumAttributes = _mesa_bitcount(state->prog->InputsRead); - - /* - * Initialize native counts to logical counts. The device driver may - * change them if program is translated into a hardware program. - */ - state->prog->NumNativeInstructions = state->prog->NumInstructions; - state->prog->NumNativeTemporaries = state->prog->NumTemporaries; - state->prog->NumNativeParameters = state->prog->NumParameters; - state->prog->NumNativeAttributes = state->prog->NumAttributes; - state->prog->NumNativeAddressRegs = state->prog->NumAddressRegs; - - result = GL_TRUE; - -error: - for (inst = state->inst_head; inst != NULL; inst = temp) { - temp = inst->next; - free(inst); - } - - state->inst_head = NULL; - state->inst_tail = NULL; - - for (sym = state->sym; sym != NULL; sym = temp) { - temp = sym->next; - - free((void *) sym->name); - free(sym); - } - state->sym = NULL; - - _mesa_symbol_table_dtor(state->st); - state->st = NULL; - - return result; -} - diff --git a/src/mesa/shader/program_parse.tab.h b/src/mesa/shader/program_parse.tab.h deleted file mode 100644 index 045241d9e7..0000000000 --- a/src/mesa/shader/program_parse.tab.h +++ /dev/null @@ -1,209 +0,0 @@ - -/* A Bison parser, made by GNU Bison 2.4.1. */ - -/* Skeleton interface for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - ARBvp_10 = 258, - ARBfp_10 = 259, - ADDRESS = 260, - ALIAS = 261, - ATTRIB = 262, - OPTION = 263, - OUTPUT = 264, - PARAM = 265, - TEMP = 266, - END = 267, - BIN_OP = 268, - BINSC_OP = 269, - SAMPLE_OP = 270, - SCALAR_OP = 271, - TRI_OP = 272, - VECTOR_OP = 273, - ARL = 274, - KIL = 275, - SWZ = 276, - TXD_OP = 277, - INTEGER = 278, - REAL = 279, - AMBIENT = 280, - ATTENUATION = 281, - BACK = 282, - CLIP = 283, - COLOR = 284, - DEPTH = 285, - DIFFUSE = 286, - DIRECTION = 287, - EMISSION = 288, - ENV = 289, - EYE = 290, - FOG = 291, - FOGCOORD = 292, - FRAGMENT = 293, - FRONT = 294, - HALF = 295, - INVERSE = 296, - INVTRANS = 297, - LIGHT = 298, - LIGHTMODEL = 299, - LIGHTPROD = 300, - LOCAL = 301, - MATERIAL = 302, - MAT_PROGRAM = 303, - MATRIX = 304, - MATRIXINDEX = 305, - MODELVIEW = 306, - MVP = 307, - NORMAL = 308, - OBJECT = 309, - PALETTE = 310, - PARAMS = 311, - PLANE = 312, - POINT_TOK = 313, - POINTSIZE = 314, - POSITION = 315, - PRIMARY = 316, - PROGRAM = 317, - PROJECTION = 318, - RANGE = 319, - RESULT = 320, - ROW = 321, - SCENECOLOR = 322, - SECONDARY = 323, - SHININESS = 324, - SIZE_TOK = 325, - SPECULAR = 326, - SPOT = 327, - STATE = 328, - TEXCOORD = 329, - TEXENV = 330, - TEXGEN = 331, - TEXGEN_Q = 332, - TEXGEN_R = 333, - TEXGEN_S = 334, - TEXGEN_T = 335, - TEXTURE = 336, - TRANSPOSE = 337, - TEXTURE_UNIT = 338, - TEX_1D = 339, - TEX_2D = 340, - TEX_3D = 341, - TEX_CUBE = 342, - TEX_RECT = 343, - TEX_SHADOW1D = 344, - TEX_SHADOW2D = 345, - TEX_SHADOWRECT = 346, - TEX_ARRAY1D = 347, - TEX_ARRAY2D = 348, - TEX_ARRAYSHADOW1D = 349, - TEX_ARRAYSHADOW2D = 350, - VERTEX = 351, - VTXATTRIB = 352, - WEIGHT = 353, - IDENTIFIER = 354, - USED_IDENTIFIER = 355, - MASK4 = 356, - MASK3 = 357, - MASK2 = 358, - MASK1 = 359, - SWIZZLE = 360, - DOT_DOT = 361, - DOT = 362 - }; -#endif - - - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -{ - -/* Line 1676 of yacc.c */ -#line 126 "program_parse.y" - - struct asm_instruction *inst; - struct asm_symbol *sym; - struct asm_symbol temp_sym; - struct asm_swizzle_mask swiz_mask; - struct asm_src_register src_reg; - struct prog_dst_register dst_reg; - struct prog_instruction temp_inst; - char *string; - unsigned result; - unsigned attrib; - int integer; - float real; - gl_state_index state[STATE_LENGTH]; - int negate; - struct asm_vector vector; - gl_inst_opcode opcode; - - struct { - unsigned swz; - unsigned rgba_valid:1; - unsigned xyzw_valid:1; - unsigned negate:1; - } ext_swizzle; - - - -/* Line 1676 of yacc.c */ -#line 187 "program_parse.tab.h" -} YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -#endif - - - -#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE -{ - int first_line; - int first_column; - int last_line; - int last_column; -} YYLTYPE; -# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ -# define YYLTYPE_IS_DECLARED 1 -# define YYLTYPE_IS_TRIVIAL 1 -#endif - - - diff --git a/src/mesa/shader/program_parse.y b/src/mesa/shader/program_parse.y deleted file mode 100644 index a2f34b863b..0000000000 --- a/src/mesa/shader/program_parse.y +++ /dev/null @@ -1,2767 +0,0 @@ -%{ -/* - * Copyright © 2009 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#include -#include -#include - -#include "main/mtypes.h" -#include "main/imports.h" -#include "shader/program.h" -#include "shader/prog_parameter.h" -#include "shader/prog_parameter_layout.h" -#include "shader/prog_statevars.h" -#include "shader/prog_instruction.h" - -#include "shader/symbol_table.h" -#include "shader/program_parser.h" - -extern void *yy_scan_string(char *); -extern void yy_delete_buffer(void *); - -static struct asm_symbol *declare_variable(struct asm_parser_state *state, - char *name, enum asm_type t, struct YYLTYPE *locp); - -static int add_state_reference(struct gl_program_parameter_list *param_list, - const gl_state_index tokens[STATE_LENGTH]); - -static int initialize_symbol_from_state(struct gl_program *prog, - struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]); - -static int initialize_symbol_from_param(struct gl_program *prog, - struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]); - -static int initialize_symbol_from_const(struct gl_program *prog, - struct asm_symbol *param_var, const struct asm_vector *vec, - GLboolean allowSwizzle); - -static int yyparse(struct asm_parser_state *state); - -static char *make_error_string(const char *fmt, ...); - -static void yyerror(struct YYLTYPE *locp, struct asm_parser_state *state, - const char *s); - -static int validate_inputs(struct YYLTYPE *locp, - struct asm_parser_state *state); - -static void init_dst_reg(struct prog_dst_register *r); - -static void set_dst_reg(struct prog_dst_register *r, - gl_register_file file, GLint index); - -static void init_src_reg(struct asm_src_register *r); - -static void set_src_reg(struct asm_src_register *r, - gl_register_file file, GLint index); - -static void set_src_reg_swz(struct asm_src_register *r, - gl_register_file file, GLint index, GLuint swizzle); - -static void asm_instruction_set_operands(struct asm_instruction *inst, - const struct prog_dst_register *dst, const struct asm_src_register *src0, - const struct asm_src_register *src1, const struct asm_src_register *src2); - -static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op, - const struct prog_dst_register *dst, const struct asm_src_register *src0, - const struct asm_src_register *src1, const struct asm_src_register *src2); - -static struct asm_instruction *asm_instruction_copy_ctor( - const struct prog_instruction *base, const struct prog_dst_register *dst, - const struct asm_src_register *src0, const struct asm_src_register *src1, - const struct asm_src_register *src2); - -#ifndef FALSE -#define FALSE 0 -#define TRUE (!FALSE) -#endif - -#define YYLLOC_DEFAULT(Current, Rhs, N) \ - do { \ - if (YYID(N)) { \ - (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ - (Current).position = YYRHSLOC(Rhs, 1).position; \ - (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC(Rhs, N).last_column; \ - } else { \ - (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \ - (Current).last_line = (Current).first_line; \ - (Current).first_column = YYRHSLOC(Rhs, 0).last_column; \ - (Current).last_column = (Current).first_column; \ - (Current).position = YYRHSLOC(Rhs, 0).position \ - + (Current).first_column; \ - } \ - } while(YYID(0)) - -#define YYLEX_PARAM state->scanner -%} - -%pure-parser -%locations -%parse-param { struct asm_parser_state *state } -%error-verbose -%lex-param { void *scanner } - -%union { - struct asm_instruction *inst; - struct asm_symbol *sym; - struct asm_symbol temp_sym; - struct asm_swizzle_mask swiz_mask; - struct asm_src_register src_reg; - struct prog_dst_register dst_reg; - struct prog_instruction temp_inst; - char *string; - unsigned result; - unsigned attrib; - int integer; - float real; - gl_state_index state[STATE_LENGTH]; - int negate; - struct asm_vector vector; - gl_inst_opcode opcode; - - struct { - unsigned swz; - unsigned rgba_valid:1; - unsigned xyzw_valid:1; - unsigned negate:1; - } ext_swizzle; -} - -%token ARBvp_10 ARBfp_10 - -/* Tokens for assembler pseudo-ops */ -%token ADDRESS -%token ALIAS ATTRIB -%token OPTION OUTPUT -%token PARAM -%token TEMP -%token END - - /* Tokens for instructions */ -%token BIN_OP BINSC_OP SAMPLE_OP SCALAR_OP TRI_OP VECTOR_OP -%token ARL KIL SWZ TXD_OP - -%token INTEGER -%token REAL - -%token AMBIENT ATTENUATION -%token BACK -%token CLIP COLOR -%token DEPTH DIFFUSE DIRECTION -%token EMISSION ENV EYE -%token FOG FOGCOORD FRAGMENT FRONT -%token HALF -%token INVERSE INVTRANS -%token LIGHT LIGHTMODEL LIGHTPROD LOCAL -%token MATERIAL MAT_PROGRAM MATRIX MATRIXINDEX MODELVIEW MVP -%token NORMAL -%token OBJECT -%token PALETTE PARAMS PLANE POINT_TOK POINTSIZE POSITION PRIMARY PROGRAM PROJECTION -%token RANGE RESULT ROW -%token SCENECOLOR SECONDARY SHININESS SIZE_TOK SPECULAR SPOT STATE -%token TEXCOORD TEXENV TEXGEN TEXGEN_Q TEXGEN_R TEXGEN_S TEXGEN_T TEXTURE TRANSPOSE -%token TEXTURE_UNIT TEX_1D TEX_2D TEX_3D TEX_CUBE TEX_RECT -%token TEX_SHADOW1D TEX_SHADOW2D TEX_SHADOWRECT -%token TEX_ARRAY1D TEX_ARRAY2D TEX_ARRAYSHADOW1D TEX_ARRAYSHADOW2D -%token VERTEX VTXATTRIB -%token WEIGHT - -%token IDENTIFIER USED_IDENTIFIER -%type string -%token MASK4 MASK3 MASK2 MASK1 SWIZZLE -%token DOT_DOT -%token DOT - -%type instruction ALU_instruction TexInstruction -%type ARL_instruction VECTORop_instruction -%type SCALARop_instruction BINSCop_instruction BINop_instruction -%type TRIop_instruction TXD_instruction SWZ_instruction SAMPLE_instruction -%type KIL_instruction - -%type dstReg maskedDstReg maskedAddrReg -%type srcReg scalarUse scalarSrcReg swizzleSrcReg -%type scalarSuffix swizzleSuffix extendedSwizzle -%type extSwizComp extSwizSel -%type optionalMask - -%type progParamArray -%type addrRegRelOffset addrRegPosOffset addrRegNegOffset -%type progParamArrayMem progParamArrayAbs progParamArrayRel -%type addrReg -%type addrComponent addrWriteMask - -%type ccMaskRule ccTest ccMaskRule2 ccTest2 optionalCcMask - -%type resultBinding resultColBinding -%type optFaceType optColorType -%type optResultFaceType optResultColorType - -%type optTexImageUnitNum texImageUnitNum -%type optTexCoordUnitNum texCoordUnitNum -%type optLegacyTexUnitNum legacyTexUnitNum -%type texImageUnit texTarget -%type vtxAttribNum - -%type attribBinding vtxAttribItem fragAttribItem - -%type paramSingleInit paramSingleItemDecl -%type optArraySize - -%type stateSingleItem stateMultipleItem -%type stateMaterialItem -%type stateLightItem stateLightModelItem stateLightProdItem -%type stateTexGenItem stateFogItem stateClipPlaneItem statePointItem -%type stateMatrixItem stateMatrixRow stateMatrixRows -%type stateTexEnvItem stateDepthItem - -%type stateLModProperty -%type stateMatrixName optMatrixRows - -%type stateMatProperty -%type stateLightProperty stateSpotProperty -%type stateLightNumber stateLProdProperty -%type stateTexGenType stateTexGenCoord -%type stateTexEnvProperty -%type stateFogProperty -%type stateClipPlaneNum -%type statePointProperty - -%type stateOptMatModifier stateMatModifier stateMatrixRowNum -%type stateOptModMatNum stateModMatNum statePaletteMatNum -%type stateProgramMatNum - -%type ambDiffSpecProperty - -%type programSingleItem progEnvParam progLocalParam -%type programMultipleItem progEnvParams progLocalParams - -%type paramMultipleInit paramMultInitList paramMultipleItem -%type paramSingleItemUse - -%type progEnvParamNum progLocalParamNum -%type progEnvParamNums progLocalParamNums - -%type paramConstDecl paramConstUse -%type paramConstScalarDecl paramConstScalarUse paramConstVector -%type signedFloatConstant -%type optionalSign - -%{ -extern int yylex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param, - void *yyscanner); -%} - -%% - -program: language optionSequence statementSequence END - ; - -language: ARBvp_10 - { - if (state->prog->Target != GL_VERTEX_PROGRAM_ARB) { - yyerror(& @1, state, "invalid fragment program header"); - - } - state->mode = ARB_vertex; - } - | ARBfp_10 - { - if (state->prog->Target != GL_FRAGMENT_PROGRAM_ARB) { - yyerror(& @1, state, "invalid vertex program header"); - } - state->mode = ARB_fragment; - - state->option.TexRect = - (state->ctx->Extensions.NV_texture_rectangle != GL_FALSE); - } - ; - -optionSequence: optionSequence option - | - ; - -option: OPTION string ';' - { - int valid = 0; - - if (state->mode == ARB_vertex) { - valid = _mesa_ARBvp_parse_option(state, $2); - } else if (state->mode == ARB_fragment) { - valid = _mesa_ARBfp_parse_option(state, $2); - } - - - free($2); - - if (!valid) { - const char *const err_str = (state->mode == ARB_vertex) - ? "invalid ARB vertex program option" - : "invalid ARB fragment program option"; - - yyerror(& @2, state, err_str); - YYERROR; - } - } - ; - -statementSequence: statementSequence statement - | - ; - -statement: instruction ';' - { - if ($1 != NULL) { - if (state->inst_tail == NULL) { - state->inst_head = $1; - } else { - state->inst_tail->next = $1; - } - - state->inst_tail = $1; - $1->next = NULL; - - state->prog->NumInstructions++; - } - } - | namingStatement ';' - ; - -instruction: ALU_instruction - { - $$ = $1; - state->prog->NumAluInstructions++; - } - | TexInstruction - { - $$ = $1; - state->prog->NumTexInstructions++; - } - ; - -ALU_instruction: ARL_instruction - | VECTORop_instruction - | SCALARop_instruction - | BINSCop_instruction - | BINop_instruction - | TRIop_instruction - | SWZ_instruction - ; - -TexInstruction: SAMPLE_instruction - | KIL_instruction - | TXD_instruction - ; - -ARL_instruction: ARL maskedAddrReg ',' scalarSrcReg - { - $$ = asm_instruction_ctor(OPCODE_ARL, & $2, & $4, NULL, NULL); - } - ; - -VECTORop_instruction: VECTOR_OP maskedDstReg ',' swizzleSrcReg - { - $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL); - } - ; - -SCALARop_instruction: SCALAR_OP maskedDstReg ',' scalarSrcReg - { - $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL); - } - ; - -BINSCop_instruction: BINSC_OP maskedDstReg ',' scalarSrcReg ',' scalarSrcReg - { - $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL); - } - ; - - -BINop_instruction: BIN_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg - { - $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL); - } - ; - -TRIop_instruction: TRI_OP maskedDstReg ',' - swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg - { - $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8); - } - ; - -SAMPLE_instruction: SAMPLE_OP maskedDstReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget - { - $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL); - if ($$ != NULL) { - const GLbitfield tex_mask = (1U << $6); - GLbitfield shadow_tex = 0; - GLbitfield target_mask = 0; - - - $$->Base.TexSrcUnit = $6; - - if ($8 < 0) { - shadow_tex = tex_mask; - - $$->Base.TexSrcTarget = -$8; - $$->Base.TexShadow = 1; - } else { - $$->Base.TexSrcTarget = $8; - } - - target_mask = (1U << $$->Base.TexSrcTarget); - - /* If this texture unit was previously accessed and that access - * had a different texture target, generate an error. - * - * If this texture unit was previously accessed and that access - * had a different shadow mode, generate an error. - */ - if ((state->prog->TexturesUsed[$6] != 0) - && ((state->prog->TexturesUsed[$6] != target_mask) - || ((state->prog->ShadowSamplers & tex_mask) - != shadow_tex))) { - yyerror(& @8, state, - "multiple targets used on one texture image unit"); - YYERROR; - } - - - state->prog->TexturesUsed[$6] |= target_mask; - state->prog->ShadowSamplers |= shadow_tex; - } - } - ; - -KIL_instruction: KIL swizzleSrcReg - { - $$ = asm_instruction_ctor(OPCODE_KIL, NULL, & $2, NULL, NULL); - state->fragment.UsesKill = 1; - } - | KIL ccTest - { - $$ = asm_instruction_ctor(OPCODE_KIL_NV, NULL, NULL, NULL, NULL); - $$->Base.DstReg.CondMask = $2.CondMask; - $$->Base.DstReg.CondSwizzle = $2.CondSwizzle; - $$->Base.DstReg.CondSrc = $2.CondSrc; - state->fragment.UsesKill = 1; - } - ; - -TXD_instruction: TXD_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget - { - $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8); - if ($$ != NULL) { - const GLbitfield tex_mask = (1U << $10); - GLbitfield shadow_tex = 0; - GLbitfield target_mask = 0; - - - $$->Base.TexSrcUnit = $10; - - if ($12 < 0) { - shadow_tex = tex_mask; - - $$->Base.TexSrcTarget = -$12; - $$->Base.TexShadow = 1; - } else { - $$->Base.TexSrcTarget = $12; - } - - target_mask = (1U << $$->Base.TexSrcTarget); - - /* If this texture unit was previously accessed and that access - * had a different texture target, generate an error. - * - * If this texture unit was previously accessed and that access - * had a different shadow mode, generate an error. - */ - if ((state->prog->TexturesUsed[$10] != 0) - && ((state->prog->TexturesUsed[$10] != target_mask) - || ((state->prog->ShadowSamplers & tex_mask) - != shadow_tex))) { - yyerror(& @12, state, - "multiple targets used on one texture image unit"); - YYERROR; - } - - - state->prog->TexturesUsed[$10] |= target_mask; - state->prog->ShadowSamplers |= shadow_tex; - } - } - ; - -texImageUnit: TEXTURE_UNIT optTexImageUnitNum - { - $$ = $2; - } - ; - -texTarget: TEX_1D { $$ = TEXTURE_1D_INDEX; } - | TEX_2D { $$ = TEXTURE_2D_INDEX; } - | TEX_3D { $$ = TEXTURE_3D_INDEX; } - | TEX_CUBE { $$ = TEXTURE_CUBE_INDEX; } - | TEX_RECT { $$ = TEXTURE_RECT_INDEX; } - | TEX_SHADOW1D { $$ = -TEXTURE_1D_INDEX; } - | TEX_SHADOW2D { $$ = -TEXTURE_2D_INDEX; } - | TEX_SHADOWRECT { $$ = -TEXTURE_RECT_INDEX; } - | TEX_ARRAY1D { $$ = TEXTURE_1D_ARRAY_INDEX; } - | TEX_ARRAY2D { $$ = TEXTURE_2D_ARRAY_INDEX; } - | TEX_ARRAYSHADOW1D { $$ = -TEXTURE_1D_ARRAY_INDEX; } - | TEX_ARRAYSHADOW2D { $$ = -TEXTURE_2D_ARRAY_INDEX; } - ; - -SWZ_instruction: SWZ maskedDstReg ',' srcReg ',' extendedSwizzle - { - /* FIXME: Is this correct? Should the extenedSwizzle be applied - * FIXME: to the existing swizzle? - */ - $4.Base.Swizzle = $6.swizzle; - $4.Base.Negate = $6.mask; - - $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL); - } - ; - -scalarSrcReg: optionalSign scalarUse - { - $$ = $2; - - if ($1) { - $$.Base.Negate = ~$$.Base.Negate; - } - } - | optionalSign '|' scalarUse '|' - { - $$ = $3; - - if (!state->option.NV_fragment) { - yyerror(& @2, state, "unexpected character '|'"); - YYERROR; - } - - if ($1) { - $$.Base.Negate = ~$$.Base.Negate; - } - - $$.Base.Abs = 1; - } - ; - -scalarUse: srcReg scalarSuffix - { - $$ = $1; - - $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle, - $2.swizzle); - } - | paramConstScalarUse - { - struct asm_symbol temp_sym; - - if (!state->option.NV_fragment) { - yyerror(& @1, state, "expected scalar suffix"); - YYERROR; - } - - memset(& temp_sym, 0, sizeof(temp_sym)); - temp_sym.param_binding_begin = ~0; - initialize_symbol_from_const(state->prog, & temp_sym, & $1, GL_TRUE); - - set_src_reg_swz(& $$, PROGRAM_CONSTANT, - temp_sym.param_binding_begin, - temp_sym.param_binding_swizzle); - } - ; - -swizzleSrcReg: optionalSign srcReg swizzleSuffix - { - $$ = $2; - - if ($1) { - $$.Base.Negate = ~$$.Base.Negate; - } - - $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle, - $3.swizzle); - } - | optionalSign '|' srcReg swizzleSuffix '|' - { - $$ = $3; - - if (!state->option.NV_fragment) { - yyerror(& @2, state, "unexpected character '|'"); - YYERROR; - } - - if ($1) { - $$.Base.Negate = ~$$.Base.Negate; - } - - $$.Base.Abs = 1; - $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle, - $4.swizzle); - } - - ; - -maskedDstReg: dstReg optionalMask optionalCcMask - { - $$ = $1; - $$.WriteMask = $2.mask; - $$.CondMask = $3.CondMask; - $$.CondSwizzle = $3.CondSwizzle; - $$.CondSrc = $3.CondSrc; - - if ($$.File == PROGRAM_OUTPUT) { - /* Technically speaking, this should check that it is in - * vertex program mode. However, PositionInvariant can never be - * set in fragment program mode, so it is somewhat irrelevant. - */ - if (state->option.PositionInvariant - && ($$.Index == VERT_RESULT_HPOS)) { - yyerror(& @1, state, "position-invariant programs cannot " - "write position"); - YYERROR; - } - - state->prog->OutputsWritten |= BITFIELD64_BIT($$.Index); - } - } - ; - -maskedAddrReg: addrReg addrWriteMask - { - set_dst_reg(& $$, PROGRAM_ADDRESS, 0); - $$.WriteMask = $2.mask; - } - ; - -extendedSwizzle: extSwizComp ',' extSwizComp ',' extSwizComp ',' extSwizComp - { - const unsigned xyzw_valid = - ($1.xyzw_valid << 0) - | ($3.xyzw_valid << 1) - | ($5.xyzw_valid << 2) - | ($7.xyzw_valid << 3); - const unsigned rgba_valid = - ($1.rgba_valid << 0) - | ($3.rgba_valid << 1) - | ($5.rgba_valid << 2) - | ($7.rgba_valid << 3); - - /* All of the swizzle components have to be valid in either RGBA - * or XYZW. Note that 0 and 1 are valid in both, so both masks - * can have some bits set. - * - * We somewhat deviate from the spec here. It would be really hard - * to figure out which component is the error, and there probably - * isn't a lot of benefit. - */ - if ((rgba_valid != 0x0f) && (xyzw_valid != 0x0f)) { - yyerror(& @1, state, "cannot combine RGBA and XYZW swizzle " - "components"); - YYERROR; - } - - $$.swizzle = MAKE_SWIZZLE4($1.swz, $3.swz, $5.swz, $7.swz); - $$.mask = ($1.negate) | ($3.negate << 1) | ($5.negate << 2) - | ($7.negate << 3); - } - ; - -extSwizComp: optionalSign extSwizSel - { - $$ = $2; - $$.negate = ($1) ? 1 : 0; - } - ; - -extSwizSel: INTEGER - { - if (($1 != 0) && ($1 != 1)) { - yyerror(& @1, state, "invalid extended swizzle selector"); - YYERROR; - } - - $$.swz = ($1 == 0) ? SWIZZLE_ZERO : SWIZZLE_ONE; - - /* 0 and 1 are valid for both RGBA swizzle names and XYZW - * swizzle names. - */ - $$.xyzw_valid = 1; - $$.rgba_valid = 1; - } - | string - { - char s; - - if (strlen($1) > 1) { - yyerror(& @1, state, "invalid extended swizzle selector"); - YYERROR; - } - - s = $1[0]; - free($1); - - switch (s) { - case 'x': - $$.swz = SWIZZLE_X; - $$.xyzw_valid = 1; - break; - case 'y': - $$.swz = SWIZZLE_Y; - $$.xyzw_valid = 1; - break; - case 'z': - $$.swz = SWIZZLE_Z; - $$.xyzw_valid = 1; - break; - case 'w': - $$.swz = SWIZZLE_W; - $$.xyzw_valid = 1; - break; - - case 'r': - $$.swz = SWIZZLE_X; - $$.rgba_valid = 1; - break; - case 'g': - $$.swz = SWIZZLE_Y; - $$.rgba_valid = 1; - break; - case 'b': - $$.swz = SWIZZLE_Z; - $$.rgba_valid = 1; - break; - case 'a': - $$.swz = SWIZZLE_W; - $$.rgba_valid = 1; - break; - - default: - yyerror(& @1, state, "invalid extended swizzle selector"); - YYERROR; - break; - } - } - ; - -srcReg: USED_IDENTIFIER /* temporaryReg | progParamSingle */ - { - struct asm_symbol *const s = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, $1); - - free($1); - - if (s == NULL) { - yyerror(& @1, state, "invalid operand variable"); - YYERROR; - } else if ((s->type != at_param) && (s->type != at_temp) - && (s->type != at_attrib)) { - yyerror(& @1, state, "invalid operand variable"); - YYERROR; - } else if ((s->type == at_param) && s->param_is_array) { - yyerror(& @1, state, "non-array access to array PARAM"); - YYERROR; - } - - init_src_reg(& $$); - switch (s->type) { - case at_temp: - set_src_reg(& $$, PROGRAM_TEMPORARY, s->temp_binding); - break; - case at_param: - set_src_reg_swz(& $$, s->param_binding_type, - s->param_binding_begin, - s->param_binding_swizzle); - break; - case at_attrib: - set_src_reg(& $$, PROGRAM_INPUT, s->attrib_binding); - state->prog->InputsRead |= (1U << $$.Base.Index); - - if (!validate_inputs(& @1, state)) { - YYERROR; - } - break; - - default: - YYERROR; - break; - } - } - | attribBinding - { - set_src_reg(& $$, PROGRAM_INPUT, $1); - state->prog->InputsRead |= (1U << $$.Base.Index); - - if (!validate_inputs(& @1, state)) { - YYERROR; - } - } - | progParamArray '[' progParamArrayMem ']' - { - if (! $3.Base.RelAddr - && ((unsigned) $3.Base.Index >= $1->param_binding_length)) { - yyerror(& @3, state, "out of bounds array access"); - YYERROR; - } - - init_src_reg(& $$); - $$.Base.File = $1->param_binding_type; - - if ($3.Base.RelAddr) { - $1->param_accessed_indirectly = 1; - - $$.Base.RelAddr = 1; - $$.Base.Index = $3.Base.Index; - $$.Symbol = $1; - } else { - $$.Base.Index = $1->param_binding_begin + $3.Base.Index; - } - } - | paramSingleItemUse - { - gl_register_file file = ($1.name != NULL) - ? $1.param_binding_type - : PROGRAM_CONSTANT; - set_src_reg_swz(& $$, file, $1.param_binding_begin, - $1.param_binding_swizzle); - } - ; - -dstReg: resultBinding - { - set_dst_reg(& $$, PROGRAM_OUTPUT, $1); - } - | USED_IDENTIFIER /* temporaryReg | vertexResultReg */ - { - struct asm_symbol *const s = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, $1); - - free($1); - - if (s == NULL) { - yyerror(& @1, state, "invalid operand variable"); - YYERROR; - } else if ((s->type != at_output) && (s->type != at_temp)) { - yyerror(& @1, state, "invalid operand variable"); - YYERROR; - } - - switch (s->type) { - case at_temp: - set_dst_reg(& $$, PROGRAM_TEMPORARY, s->temp_binding); - break; - case at_output: - set_dst_reg(& $$, PROGRAM_OUTPUT, s->output_binding); - break; - default: - set_dst_reg(& $$, s->param_binding_type, s->param_binding_begin); - break; - } - } - ; - -progParamArray: USED_IDENTIFIER - { - struct asm_symbol *const s = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, $1); - - free($1); - - if (s == NULL) { - yyerror(& @1, state, "invalid operand variable"); - YYERROR; - } else if ((s->type != at_param) || !s->param_is_array) { - yyerror(& @1, state, "array access to non-PARAM variable"); - YYERROR; - } else { - $$ = s; - } - } - ; - -progParamArrayMem: progParamArrayAbs | progParamArrayRel; - -progParamArrayAbs: INTEGER - { - init_src_reg(& $$); - $$.Base.Index = $1; - } - ; - -progParamArrayRel: addrReg addrComponent addrRegRelOffset - { - /* FINISHME: Add support for multiple address registers. - */ - /* FINISHME: Add support for 4-component address registers. - */ - init_src_reg(& $$); - $$.Base.RelAddr = 1; - $$.Base.Index = $3; - } - ; - -addrRegRelOffset: { $$ = 0; } - | '+' addrRegPosOffset { $$ = $2; } - | '-' addrRegNegOffset { $$ = -$2; } - ; - -addrRegPosOffset: INTEGER - { - if (($1 < 0) || ($1 > 63)) { - char s[100]; - _mesa_snprintf(s, sizeof(s), - "relative address offset too large (%d)", $1); - yyerror(& @1, state, s); - YYERROR; - } else { - $$ = $1; - } - } - ; - -addrRegNegOffset: INTEGER - { - if (($1 < 0) || ($1 > 64)) { - char s[100]; - _mesa_snprintf(s, sizeof(s), - "relative address offset too large (%d)", $1); - yyerror(& @1, state, s); - YYERROR; - } else { - $$ = $1; - } - } - ; - -addrReg: USED_IDENTIFIER - { - struct asm_symbol *const s = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, $1); - - free($1); - - if (s == NULL) { - yyerror(& @1, state, "invalid array member"); - YYERROR; - } else if (s->type != at_address) { - yyerror(& @1, state, - "invalid variable for indexed array access"); - YYERROR; - } else { - $$ = s; - } - } - ; - -addrComponent: MASK1 - { - if ($1.mask != WRITEMASK_X) { - yyerror(& @1, state, "invalid address component selector"); - YYERROR; - } else { - $$ = $1; - } - } - ; - -addrWriteMask: MASK1 - { - if ($1.mask != WRITEMASK_X) { - yyerror(& @1, state, - "address register write mask must be \".x\""); - YYERROR; - } else { - $$ = $1; - } - } - ; - -scalarSuffix: MASK1; - -swizzleSuffix: MASK1 - | MASK4 - | SWIZZLE - | { $$.swizzle = SWIZZLE_NOOP; $$.mask = WRITEMASK_XYZW; } - ; - -optionalMask: MASK4 | MASK3 | MASK2 | MASK1 - | { $$.swizzle = SWIZZLE_NOOP; $$.mask = WRITEMASK_XYZW; } - ; - -optionalCcMask: '(' ccTest ')' - { - $$ = $2; - } - | '(' ccTest2 ')' - { - $$ = $2; - } - | - { - $$.CondMask = COND_TR; - $$.CondSwizzle = SWIZZLE_NOOP; - $$.CondSrc = 0; - } - ; - -ccTest: ccMaskRule swizzleSuffix - { - $$ = $1; - $$.CondSwizzle = $2.swizzle; - } - ; - -ccTest2: ccMaskRule2 swizzleSuffix - { - $$ = $1; - $$.CondSwizzle = $2.swizzle; - } - ; - -ccMaskRule: IDENTIFIER - { - const int cond = _mesa_parse_cc($1); - if ((cond == 0) || ($1[2] != '\0')) { - char *const err_str = - make_error_string("invalid condition code \"%s\"", $1); - - yyerror(& @1, state, (err_str != NULL) - ? err_str : "invalid condition code"); - - if (err_str != NULL) { - free(err_str); - } - - YYERROR; - } - - $$.CondMask = cond; - $$.CondSwizzle = SWIZZLE_NOOP; - $$.CondSrc = 0; - } - ; - -ccMaskRule2: USED_IDENTIFIER - { - const int cond = _mesa_parse_cc($1); - if ((cond == 0) || ($1[2] != '\0')) { - char *const err_str = - make_error_string("invalid condition code \"%s\"", $1); - - yyerror(& @1, state, (err_str != NULL) - ? err_str : "invalid condition code"); - - if (err_str != NULL) { - free(err_str); - } - - YYERROR; - } - - $$.CondMask = cond; - $$.CondSwizzle = SWIZZLE_NOOP; - $$.CondSrc = 0; - } - ; - -namingStatement: ATTRIB_statement - | PARAM_statement - | TEMP_statement - | ADDRESS_statement - | OUTPUT_statement - | ALIAS_statement - ; - -ATTRIB_statement: ATTRIB IDENTIFIER '=' attribBinding - { - struct asm_symbol *const s = - declare_variable(state, $2, at_attrib, & @2); - - if (s == NULL) { - free($2); - YYERROR; - } else { - s->attrib_binding = $4; - state->InputsBound |= (1U << s->attrib_binding); - - if (!validate_inputs(& @4, state)) { - YYERROR; - } - } - } - ; - -attribBinding: VERTEX vtxAttribItem - { - $$ = $2; - } - | FRAGMENT fragAttribItem - { - $$ = $2; - } - ; - -vtxAttribItem: POSITION - { - $$ = VERT_ATTRIB_POS; - } - | WEIGHT vtxOptWeightNum - { - $$ = VERT_ATTRIB_WEIGHT; - } - | NORMAL - { - $$ = VERT_ATTRIB_NORMAL; - } - | COLOR optColorType - { - if (!state->ctx->Extensions.EXT_secondary_color) { - yyerror(& @2, state, "GL_EXT_secondary_color not supported"); - YYERROR; - } - - $$ = VERT_ATTRIB_COLOR0 + $2; - } - | FOGCOORD - { - if (!state->ctx->Extensions.EXT_fog_coord) { - yyerror(& @1, state, "GL_EXT_fog_coord not supported"); - YYERROR; - } - - $$ = VERT_ATTRIB_FOG; - } - | TEXCOORD optTexCoordUnitNum - { - $$ = VERT_ATTRIB_TEX0 + $2; - } - | MATRIXINDEX '[' vtxWeightNum ']' - { - yyerror(& @1, state, "GL_ARB_matrix_palette not supported"); - YYERROR; - } - | VTXATTRIB '[' vtxAttribNum ']' - { - $$ = VERT_ATTRIB_GENERIC0 + $3; - } - ; - -vtxAttribNum: INTEGER - { - if ((unsigned) $1 >= state->limits->MaxAttribs) { - yyerror(& @1, state, "invalid vertex attribute reference"); - YYERROR; - } - - $$ = $1; - } - ; - -vtxOptWeightNum: | '[' vtxWeightNum ']'; -vtxWeightNum: INTEGER; - -fragAttribItem: POSITION - { - $$ = FRAG_ATTRIB_WPOS; - } - | COLOR optColorType - { - $$ = FRAG_ATTRIB_COL0 + $2; - } - | FOGCOORD - { - $$ = FRAG_ATTRIB_FOGC; - } - | TEXCOORD optTexCoordUnitNum - { - $$ = FRAG_ATTRIB_TEX0 + $2; - } - ; - -PARAM_statement: PARAM_singleStmt | PARAM_multipleStmt; - -PARAM_singleStmt: PARAM IDENTIFIER paramSingleInit - { - struct asm_symbol *const s = - declare_variable(state, $2, at_param, & @2); - - if (s == NULL) { - free($2); - YYERROR; - } else { - s->param_binding_type = $3.param_binding_type; - s->param_binding_begin = $3.param_binding_begin; - s->param_binding_length = $3.param_binding_length; - s->param_binding_swizzle = $3.param_binding_swizzle; - s->param_is_array = 0; - } - } - ; - -PARAM_multipleStmt: PARAM IDENTIFIER '[' optArraySize ']' paramMultipleInit - { - if (($4 != 0) && ((unsigned) $4 != $6.param_binding_length)) { - free($2); - yyerror(& @4, state, - "parameter array size and number of bindings must match"); - YYERROR; - } else { - struct asm_symbol *const s = - declare_variable(state, $2, $6.type, & @2); - - if (s == NULL) { - free($2); - YYERROR; - } else { - s->param_binding_type = $6.param_binding_type; - s->param_binding_begin = $6.param_binding_begin; - s->param_binding_length = $6.param_binding_length; - s->param_binding_swizzle = SWIZZLE_XYZW; - s->param_is_array = 1; - } - } - } - ; - -optArraySize: - { - $$ = 0; - } - | INTEGER - { - if (($1 < 1) || ((unsigned) $1 > state->limits->MaxParameters)) { - yyerror(& @1, state, "invalid parameter array size"); - YYERROR; - } else { - $$ = $1; - } - } - ; - -paramSingleInit: '=' paramSingleItemDecl - { - $$ = $2; - } - ; - -paramMultipleInit: '=' '{' paramMultInitList '}' - { - $$ = $3; - } - ; - -paramMultInitList: paramMultipleItem - | paramMultInitList ',' paramMultipleItem - { - $1.param_binding_length += $3.param_binding_length; - $$ = $1; - } - ; - -paramSingleItemDecl: stateSingleItem - { - memset(& $$, 0, sizeof($$)); - $$.param_binding_begin = ~0; - initialize_symbol_from_state(state->prog, & $$, $1); - } - | programSingleItem - { - memset(& $$, 0, sizeof($$)); - $$.param_binding_begin = ~0; - initialize_symbol_from_param(state->prog, & $$, $1); - } - | paramConstDecl - { - memset(& $$, 0, sizeof($$)); - $$.param_binding_begin = ~0; - initialize_symbol_from_const(state->prog, & $$, & $1, GL_TRUE); - } - ; - -paramSingleItemUse: stateSingleItem - { - memset(& $$, 0, sizeof($$)); - $$.param_binding_begin = ~0; - initialize_symbol_from_state(state->prog, & $$, $1); - } - | programSingleItem - { - memset(& $$, 0, sizeof($$)); - $$.param_binding_begin = ~0; - initialize_symbol_from_param(state->prog, & $$, $1); - } - | paramConstUse - { - memset(& $$, 0, sizeof($$)); - $$.param_binding_begin = ~0; - initialize_symbol_from_const(state->prog, & $$, & $1, GL_TRUE); - } - ; - -paramMultipleItem: stateMultipleItem - { - memset(& $$, 0, sizeof($$)); - $$.param_binding_begin = ~0; - initialize_symbol_from_state(state->prog, & $$, $1); - } - | programMultipleItem - { - memset(& $$, 0, sizeof($$)); - $$.param_binding_begin = ~0; - initialize_symbol_from_param(state->prog, & $$, $1); - } - | paramConstDecl - { - memset(& $$, 0, sizeof($$)); - $$.param_binding_begin = ~0; - initialize_symbol_from_const(state->prog, & $$, & $1, GL_FALSE); - } - ; - -stateMultipleItem: stateSingleItem { memcpy($$, $1, sizeof($$)); } - | STATE stateMatrixRows { memcpy($$, $2, sizeof($$)); } - ; - -stateSingleItem: STATE stateMaterialItem { memcpy($$, $2, sizeof($$)); } - | STATE stateLightItem { memcpy($$, $2, sizeof($$)); } - | STATE stateLightModelItem { memcpy($$, $2, sizeof($$)); } - | STATE stateLightProdItem { memcpy($$, $2, sizeof($$)); } - | STATE stateTexGenItem { memcpy($$, $2, sizeof($$)); } - | STATE stateTexEnvItem { memcpy($$, $2, sizeof($$)); } - | STATE stateFogItem { memcpy($$, $2, sizeof($$)); } - | STATE stateClipPlaneItem { memcpy($$, $2, sizeof($$)); } - | STATE statePointItem { memcpy($$, $2, sizeof($$)); } - | STATE stateMatrixRow { memcpy($$, $2, sizeof($$)); } - | STATE stateDepthItem { memcpy($$, $2, sizeof($$)); } - ; - -stateMaterialItem: MATERIAL optFaceType stateMatProperty - { - memset($$, 0, sizeof($$)); - $$[0] = STATE_MATERIAL; - $$[1] = $2; - $$[2] = $3; - } - ; - -stateMatProperty: ambDiffSpecProperty - { - $$ = $1; - } - | EMISSION - { - $$ = STATE_EMISSION; - } - | SHININESS - { - $$ = STATE_SHININESS; - } - ; - -stateLightItem: LIGHT '[' stateLightNumber ']' stateLightProperty - { - memset($$, 0, sizeof($$)); - $$[0] = STATE_LIGHT; - $$[1] = $3; - $$[2] = $5; - } - ; - -stateLightProperty: ambDiffSpecProperty - { - $$ = $1; - } - | POSITION - { - $$ = STATE_POSITION; - } - | ATTENUATION - { - if (!state->ctx->Extensions.EXT_point_parameters) { - yyerror(& @1, state, "GL_ARB_point_parameters not supported"); - YYERROR; - } - - $$ = STATE_ATTENUATION; - } - | SPOT stateSpotProperty - { - $$ = $2; - } - | HALF - { - $$ = STATE_HALF_VECTOR; - } - ; - -stateSpotProperty: DIRECTION - { - $$ = STATE_SPOT_DIRECTION; - } - ; - -stateLightModelItem: LIGHTMODEL stateLModProperty - { - $$[0] = $2[0]; - $$[1] = $2[1]; - } - ; - -stateLModProperty: AMBIENT - { - memset($$, 0, sizeof($$)); - $$[0] = STATE_LIGHTMODEL_AMBIENT; - } - | optFaceType SCENECOLOR - { - memset($$, 0, sizeof($$)); - $$[0] = STATE_LIGHTMODEL_SCENECOLOR; - $$[1] = $1; - } - ; - -stateLightProdItem: LIGHTPROD '[' stateLightNumber ']' optFaceType stateLProdProperty - { - memset($$, 0, sizeof($$)); - $$[0] = STATE_LIGHTPROD; - $$[1] = $3; - $$[2] = $5; - $$[3] = $6; - } - ; - -stateLProdProperty: ambDiffSpecProperty; - -stateTexEnvItem: TEXENV optLegacyTexUnitNum stateTexEnvProperty - { - memset($$, 0, sizeof($$)); - $$[0] = $3; - $$[1] = $2; - } - ; - -stateTexEnvProperty: COLOR - { - $$ = STATE_TEXENV_COLOR; - } - ; - -ambDiffSpecProperty: AMBIENT - { - $$ = STATE_AMBIENT; - } - | DIFFUSE - { - $$ = STATE_DIFFUSE; - } - | SPECULAR - { - $$ = STATE_SPECULAR; - } - ; - -stateLightNumber: INTEGER - { - if ((unsigned) $1 >= state->MaxLights) { - yyerror(& @1, state, "invalid light selector"); - YYERROR; - } - - $$ = $1; - } - ; - -stateTexGenItem: TEXGEN optTexCoordUnitNum stateTexGenType stateTexGenCoord - { - memset($$, 0, sizeof($$)); - $$[0] = STATE_TEXGEN; - $$[1] = $2; - $$[2] = $3 + $4; - } - ; - -stateTexGenType: EYE - { - $$ = STATE_TEXGEN_EYE_S; - } - | OBJECT - { - $$ = STATE_TEXGEN_OBJECT_S; - } - ; -stateTexGenCoord: TEXGEN_S - { - $$ = STATE_TEXGEN_EYE_S - STATE_TEXGEN_EYE_S; - } - | TEXGEN_T - { - $$ = STATE_TEXGEN_EYE_T - STATE_TEXGEN_EYE_S; - } - | TEXGEN_R - { - $$ = STATE_TEXGEN_EYE_R - STATE_TEXGEN_EYE_S; - } - | TEXGEN_Q - { - $$ = STATE_TEXGEN_EYE_Q - STATE_TEXGEN_EYE_S; - } - ; - -stateFogItem: FOG stateFogProperty - { - memset($$, 0, sizeof($$)); - $$[0] = $2; - } - ; - -stateFogProperty: COLOR - { - $$ = STATE_FOG_COLOR; - } - | PARAMS - { - $$ = STATE_FOG_PARAMS; - } - ; - -stateClipPlaneItem: CLIP '[' stateClipPlaneNum ']' PLANE - { - memset($$, 0, sizeof($$)); - $$[0] = STATE_CLIPPLANE; - $$[1] = $3; - } - ; - -stateClipPlaneNum: INTEGER - { - if ((unsigned) $1 >= state->MaxClipPlanes) { - yyerror(& @1, state, "invalid clip plane selector"); - YYERROR; - } - - $$ = $1; - } - ; - -statePointItem: POINT_TOK statePointProperty - { - memset($$, 0, sizeof($$)); - $$[0] = $2; - } - ; - -statePointProperty: SIZE_TOK - { - $$ = STATE_POINT_SIZE; - } - | ATTENUATION - { - $$ = STATE_POINT_ATTENUATION; - } - ; - -stateMatrixRow: stateMatrixItem ROW '[' stateMatrixRowNum ']' - { - $$[0] = $1[0]; - $$[1] = $1[1]; - $$[2] = $4; - $$[3] = $4; - $$[4] = $1[2]; - } - ; - -stateMatrixRows: stateMatrixItem optMatrixRows - { - $$[0] = $1[0]; - $$[1] = $1[1]; - $$[2] = $2[2]; - $$[3] = $2[3]; - $$[4] = $1[2]; - } - ; - -optMatrixRows: - { - $$[2] = 0; - $$[3] = 3; - } - | ROW '[' stateMatrixRowNum DOT_DOT stateMatrixRowNum ']' - { - /* It seems logical that the matrix row range specifier would have - * to specify a range or more than one row (i.e., $5 > $3). - * However, the ARB_vertex_program spec says "a program will fail - * to load if is greater than ." This means that $3 == $5 - * is valid. - */ - if ($3 > $5) { - yyerror(& @3, state, "invalid matrix row range"); - YYERROR; - } - - $$[2] = $3; - $$[3] = $5; - } - ; - -stateMatrixItem: MATRIX stateMatrixName stateOptMatModifier - { - $$[0] = $2[0]; - $$[1] = $2[1]; - $$[2] = $3; - } - ; - -stateOptMatModifier: - { - $$ = 0; - } - | stateMatModifier - { - $$ = $1; - } - ; - -stateMatModifier: INVERSE - { - $$ = STATE_MATRIX_INVERSE; - } - | TRANSPOSE - { - $$ = STATE_MATRIX_TRANSPOSE; - } - | INVTRANS - { - $$ = STATE_MATRIX_INVTRANS; - } - ; - -stateMatrixRowNum: INTEGER - { - if ($1 > 3) { - yyerror(& @1, state, "invalid matrix row reference"); - YYERROR; - } - - $$ = $1; - } - ; - -stateMatrixName: MODELVIEW stateOptModMatNum - { - $$[0] = STATE_MODELVIEW_MATRIX; - $$[1] = $2; - } - | PROJECTION - { - $$[0] = STATE_PROJECTION_MATRIX; - $$[1] = 0; - } - | MVP - { - $$[0] = STATE_MVP_MATRIX; - $$[1] = 0; - } - | TEXTURE optTexCoordUnitNum - { - $$[0] = STATE_TEXTURE_MATRIX; - $$[1] = $2; - } - | PALETTE '[' statePaletteMatNum ']' - { - yyerror(& @1, state, "GL_ARB_matrix_palette not supported"); - YYERROR; - } - | MAT_PROGRAM '[' stateProgramMatNum ']' - { - $$[0] = STATE_PROGRAM_MATRIX; - $$[1] = $3; - } - ; - -stateOptModMatNum: - { - $$ = 0; - } - | '[' stateModMatNum ']' - { - $$ = $2; - } - ; -stateModMatNum: INTEGER - { - /* Since GL_ARB_vertex_blend isn't supported, only modelview matrix - * zero is valid. - */ - if ($1 != 0) { - yyerror(& @1, state, "invalid modelview matrix index"); - YYERROR; - } - - $$ = $1; - } - ; -statePaletteMatNum: INTEGER - { - /* Since GL_ARB_matrix_palette isn't supported, just let any value - * through here. The error will be generated later. - */ - $$ = $1; - } - ; -stateProgramMatNum: INTEGER - { - if ((unsigned) $1 >= state->MaxProgramMatrices) { - yyerror(& @1, state, "invalid program matrix selector"); - YYERROR; - } - - $$ = $1; - } - ; - -stateDepthItem: DEPTH RANGE - { - memset($$, 0, sizeof($$)); - $$[0] = STATE_DEPTH_RANGE; - } - ; - - -programSingleItem: progEnvParam | progLocalParam; - -programMultipleItem: progEnvParams | progLocalParams; - -progEnvParams: PROGRAM ENV '[' progEnvParamNums ']' - { - memset($$, 0, sizeof($$)); - $$[0] = state->state_param_enum; - $$[1] = STATE_ENV; - $$[2] = $4[0]; - $$[3] = $4[1]; - } - ; - -progEnvParamNums: progEnvParamNum - { - $$[0] = $1; - $$[1] = $1; - } - | progEnvParamNum DOT_DOT progEnvParamNum - { - $$[0] = $1; - $$[1] = $3; - } - ; - -progEnvParam: PROGRAM ENV '[' progEnvParamNum ']' - { - memset($$, 0, sizeof($$)); - $$[0] = state->state_param_enum; - $$[1] = STATE_ENV; - $$[2] = $4; - $$[3] = $4; - } - ; - -progLocalParams: PROGRAM LOCAL '[' progLocalParamNums ']' - { - memset($$, 0, sizeof($$)); - $$[0] = state->state_param_enum; - $$[1] = STATE_LOCAL; - $$[2] = $4[0]; - $$[3] = $4[1]; - } - -progLocalParamNums: progLocalParamNum - { - $$[0] = $1; - $$[1] = $1; - } - | progLocalParamNum DOT_DOT progLocalParamNum - { - $$[0] = $1; - $$[1] = $3; - } - ; - -progLocalParam: PROGRAM LOCAL '[' progLocalParamNum ']' - { - memset($$, 0, sizeof($$)); - $$[0] = state->state_param_enum; - $$[1] = STATE_LOCAL; - $$[2] = $4; - $$[3] = $4; - } - ; - -progEnvParamNum: INTEGER - { - if ((unsigned) $1 >= state->limits->MaxEnvParams) { - yyerror(& @1, state, "invalid environment parameter reference"); - YYERROR; - } - $$ = $1; - } - ; - -progLocalParamNum: INTEGER - { - if ((unsigned) $1 >= state->limits->MaxLocalParams) { - yyerror(& @1, state, "invalid local parameter reference"); - YYERROR; - } - $$ = $1; - } - ; - - - -paramConstDecl: paramConstScalarDecl | paramConstVector; -paramConstUse: paramConstScalarUse | paramConstVector; - -paramConstScalarDecl: signedFloatConstant - { - $$.count = 4; - $$.data[0] = $1; - $$.data[1] = $1; - $$.data[2] = $1; - $$.data[3] = $1; - } - ; - -paramConstScalarUse: REAL - { - $$.count = 1; - $$.data[0] = $1; - $$.data[1] = $1; - $$.data[2] = $1; - $$.data[3] = $1; - } - | INTEGER - { - $$.count = 1; - $$.data[0] = (float) $1; - $$.data[1] = (float) $1; - $$.data[2] = (float) $1; - $$.data[3] = (float) $1; - } - ; - -paramConstVector: '{' signedFloatConstant '}' - { - $$.count = 4; - $$.data[0] = $2; - $$.data[1] = 0.0f; - $$.data[2] = 0.0f; - $$.data[3] = 1.0f; - } - | '{' signedFloatConstant ',' signedFloatConstant '}' - { - $$.count = 4; - $$.data[0] = $2; - $$.data[1] = $4; - $$.data[2] = 0.0f; - $$.data[3] = 1.0f; - } - | '{' signedFloatConstant ',' signedFloatConstant ',' - signedFloatConstant '}' - { - $$.count = 4; - $$.data[0] = $2; - $$.data[1] = $4; - $$.data[2] = $6; - $$.data[3] = 1.0f; - } - | '{' signedFloatConstant ',' signedFloatConstant ',' - signedFloatConstant ',' signedFloatConstant '}' - { - $$.count = 4; - $$.data[0] = $2; - $$.data[1] = $4; - $$.data[2] = $6; - $$.data[3] = $8; - } - ; - -signedFloatConstant: optionalSign REAL - { - $$ = ($1) ? -$2 : $2; - } - | optionalSign INTEGER - { - $$ = (float)(($1) ? -$2 : $2); - } - ; - -optionalSign: '+' { $$ = FALSE; } - | '-' { $$ = TRUE; } - | { $$ = FALSE; } - ; - -TEMP_statement: optVarSize TEMP { $$ = $2; } varNameList - ; - -optVarSize: string - { - /* NV_fragment_program_option defines the size qualifiers in a - * fairly broken way. "SHORT" or "LONG" can optionally be used - * before TEMP or OUTPUT. However, neither is a reserved word! - * This means that we have to parse it as an identifier, then check - * to make sure it's one of the valid values. *sigh* - * - * In addition, the grammar in the extension spec does *not* allow - * the size specifier to be optional, but all known implementations - * do. - */ - if (!state->option.NV_fragment) { - yyerror(& @1, state, "unexpected IDENTIFIER"); - YYERROR; - } - - if (strcmp("SHORT", $1) == 0) { - } else if (strcmp("LONG", $1) == 0) { - } else { - char *const err_str = - make_error_string("invalid storage size specifier \"%s\"", - $1); - - yyerror(& @1, state, (err_str != NULL) - ? err_str : "invalid storage size specifier"); - - if (err_str != NULL) { - free(err_str); - } - - YYERROR; - } - } - | - { - } - ; - -ADDRESS_statement: ADDRESS { $$ = $1; } varNameList - ; - -varNameList: varNameList ',' IDENTIFIER - { - if (!declare_variable(state, $3, $0, & @3)) { - free($3); - YYERROR; - } - } - | IDENTIFIER - { - if (!declare_variable(state, $1, $0, & @1)) { - free($1); - YYERROR; - } - } - ; - -OUTPUT_statement: optVarSize OUTPUT IDENTIFIER '=' resultBinding - { - struct asm_symbol *const s = - declare_variable(state, $3, at_output, & @3); - - if (s == NULL) { - free($3); - YYERROR; - } else { - s->output_binding = $5; - } - } - ; - -resultBinding: RESULT POSITION - { - if (state->mode == ARB_vertex) { - $$ = VERT_RESULT_HPOS; - } else { - yyerror(& @2, state, "invalid program result name"); - YYERROR; - } - } - | RESULT FOGCOORD - { - if (state->mode == ARB_vertex) { - $$ = VERT_RESULT_FOGC; - } else { - yyerror(& @2, state, "invalid program result name"); - YYERROR; - } - } - | RESULT resultColBinding - { - $$ = $2; - } - | RESULT POINTSIZE - { - if (state->mode == ARB_vertex) { - $$ = VERT_RESULT_PSIZ; - } else { - yyerror(& @2, state, "invalid program result name"); - YYERROR; - } - } - | RESULT TEXCOORD optTexCoordUnitNum - { - if (state->mode == ARB_vertex) { - $$ = VERT_RESULT_TEX0 + $3; - } else { - yyerror(& @2, state, "invalid program result name"); - YYERROR; - } - } - | RESULT DEPTH - { - if (state->mode == ARB_fragment) { - $$ = FRAG_RESULT_DEPTH; - } else { - yyerror(& @2, state, "invalid program result name"); - YYERROR; - } - } - ; - -resultColBinding: COLOR optResultFaceType optResultColorType - { - $$ = $2 + $3; - } - ; - -optResultFaceType: - { - $$ = (state->mode == ARB_vertex) - ? VERT_RESULT_COL0 - : FRAG_RESULT_COLOR; - } - | FRONT - { - if (state->mode == ARB_vertex) { - $$ = VERT_RESULT_COL0; - } else { - yyerror(& @1, state, "invalid program result name"); - YYERROR; - } - } - | BACK - { - if (state->mode == ARB_vertex) { - $$ = VERT_RESULT_BFC0; - } else { - yyerror(& @1, state, "invalid program result name"); - YYERROR; - } - } - ; - -optResultColorType: - { - $$ = 0; - } - | PRIMARY - { - if (state->mode == ARB_vertex) { - $$ = 0; - } else { - yyerror(& @1, state, "invalid program result name"); - YYERROR; - } - } - | SECONDARY - { - if (state->mode == ARB_vertex) { - $$ = 1; - } else { - yyerror(& @1, state, "invalid program result name"); - YYERROR; - } - } - ; - -optFaceType: { $$ = 0; } - | FRONT { $$ = 0; } - | BACK { $$ = 1; } - ; - -optColorType: { $$ = 0; } - | PRIMARY { $$ = 0; } - | SECONDARY { $$ = 1; } - ; - -optTexCoordUnitNum: { $$ = 0; } - | '[' texCoordUnitNum ']' { $$ = $2; } - ; - -optTexImageUnitNum: { $$ = 0; } - | '[' texImageUnitNum ']' { $$ = $2; } - ; - -optLegacyTexUnitNum: { $$ = 0; } - | '[' legacyTexUnitNum ']' { $$ = $2; } - ; - -texCoordUnitNum: INTEGER - { - if ((unsigned) $1 >= state->MaxTextureCoordUnits) { - yyerror(& @1, state, "invalid texture coordinate unit selector"); - YYERROR; - } - - $$ = $1; - } - ; - -texImageUnitNum: INTEGER - { - if ((unsigned) $1 >= state->MaxTextureImageUnits) { - yyerror(& @1, state, "invalid texture image unit selector"); - YYERROR; - } - - $$ = $1; - } - ; - -legacyTexUnitNum: INTEGER - { - if ((unsigned) $1 >= state->MaxTextureUnits) { - yyerror(& @1, state, "invalid texture unit selector"); - YYERROR; - } - - $$ = $1; - } - ; - -ALIAS_statement: ALIAS IDENTIFIER '=' USED_IDENTIFIER - { - struct asm_symbol *exist = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, $2); - struct asm_symbol *target = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, $4); - - free($4); - - if (exist != NULL) { - char m[1000]; - _mesa_snprintf(m, sizeof(m), "redeclared identifier: %s", $2); - free($2); - yyerror(& @2, state, m); - YYERROR; - } else if (target == NULL) { - free($2); - yyerror(& @4, state, - "undefined variable binding in ALIAS statement"); - YYERROR; - } else { - _mesa_symbol_table_add_symbol(state->st, 0, $2, target); - } - } - ; - -string: IDENTIFIER - | USED_IDENTIFIER - ; - -%% - -void -asm_instruction_set_operands(struct asm_instruction *inst, - const struct prog_dst_register *dst, - const struct asm_src_register *src0, - const struct asm_src_register *src1, - const struct asm_src_register *src2) -{ - /* In the core ARB extensions only the KIL instruction doesn't have a - * destination register. - */ - if (dst == NULL) { - init_dst_reg(& inst->Base.DstReg); - } else { - inst->Base.DstReg = *dst; - } - - /* The only instruction that doesn't have any source registers is the - * condition-code based KIL instruction added by NV_fragment_program_option. - */ - if (src0 != NULL) { - inst->Base.SrcReg[0] = src0->Base; - inst->SrcReg[0] = *src0; - } else { - init_src_reg(& inst->SrcReg[0]); - } - - if (src1 != NULL) { - inst->Base.SrcReg[1] = src1->Base; - inst->SrcReg[1] = *src1; - } else { - init_src_reg(& inst->SrcReg[1]); - } - - if (src2 != NULL) { - inst->Base.SrcReg[2] = src2->Base; - inst->SrcReg[2] = *src2; - } else { - init_src_reg(& inst->SrcReg[2]); - } -} - - -struct asm_instruction * -asm_instruction_ctor(gl_inst_opcode op, - const struct prog_dst_register *dst, - const struct asm_src_register *src0, - const struct asm_src_register *src1, - const struct asm_src_register *src2) -{ - struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction); - - if (inst) { - _mesa_init_instructions(& inst->Base, 1); - inst->Base.Opcode = op; - - asm_instruction_set_operands(inst, dst, src0, src1, src2); - } - - return inst; -} - - -struct asm_instruction * -asm_instruction_copy_ctor(const struct prog_instruction *base, - const struct prog_dst_register *dst, - const struct asm_src_register *src0, - const struct asm_src_register *src1, - const struct asm_src_register *src2) -{ - struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction); - - if (inst) { - _mesa_init_instructions(& inst->Base, 1); - inst->Base.Opcode = base->Opcode; - inst->Base.CondUpdate = base->CondUpdate; - inst->Base.CondDst = base->CondDst; - inst->Base.SaturateMode = base->SaturateMode; - inst->Base.Precision = base->Precision; - - asm_instruction_set_operands(inst, dst, src0, src1, src2); - } - - return inst; -} - - -void -init_dst_reg(struct prog_dst_register *r) -{ - memset(r, 0, sizeof(*r)); - r->File = PROGRAM_UNDEFINED; - r->WriteMask = WRITEMASK_XYZW; - r->CondMask = COND_TR; - r->CondSwizzle = SWIZZLE_NOOP; -} - - -/** Like init_dst_reg() but set the File and Index fields. */ -void -set_dst_reg(struct prog_dst_register *r, gl_register_file file, GLint index) -{ - const GLint maxIndex = 1 << INST_INDEX_BITS; - const GLint minIndex = 0; - ASSERT(index >= minIndex); - (void) minIndex; - ASSERT(index <= maxIndex); - (void) maxIndex; - ASSERT(file == PROGRAM_TEMPORARY || - file == PROGRAM_ADDRESS || - file == PROGRAM_OUTPUT); - memset(r, 0, sizeof(*r)); - r->File = file; - r->Index = index; - r->WriteMask = WRITEMASK_XYZW; - r->CondMask = COND_TR; - r->CondSwizzle = SWIZZLE_NOOP; -} - - -void -init_src_reg(struct asm_src_register *r) -{ - memset(r, 0, sizeof(*r)); - r->Base.File = PROGRAM_UNDEFINED; - r->Base.Swizzle = SWIZZLE_NOOP; - r->Symbol = NULL; -} - - -/** Like init_src_reg() but set the File and Index fields. - * \return GL_TRUE if a valid src register, GL_FALSE otherwise - */ -void -set_src_reg(struct asm_src_register *r, gl_register_file file, GLint index) -{ - set_src_reg_swz(r, file, index, SWIZZLE_XYZW); -} - - -void -set_src_reg_swz(struct asm_src_register *r, gl_register_file file, GLint index, - GLuint swizzle) -{ - const GLint maxIndex = (1 << INST_INDEX_BITS) - 1; - const GLint minIndex = -(1 << INST_INDEX_BITS); - ASSERT(file < PROGRAM_FILE_MAX); - ASSERT(index >= minIndex); - (void) minIndex; - ASSERT(index <= maxIndex); - (void) maxIndex; - memset(r, 0, sizeof(*r)); - r->Base.File = file; - r->Base.Index = index; - r->Base.Swizzle = swizzle; - r->Symbol = NULL; -} - - -/** - * Validate the set of inputs used by a program - * - * Validates that legal sets of inputs are used by the program. In this case - * "used" included both reading the input or binding the input to a name using - * the \c ATTRIB command. - * - * \return - * \c TRUE if the combination of inputs used is valid, \c FALSE otherwise. - */ -int -validate_inputs(struct YYLTYPE *locp, struct asm_parser_state *state) -{ - const int inputs = state->prog->InputsRead | state->InputsBound; - - if (((inputs & 0x0ffff) & (inputs >> 16)) != 0) { - yyerror(locp, state, "illegal use of generic attribute and name attribute"); - return 0; - } - - return 1; -} - - -struct asm_symbol * -declare_variable(struct asm_parser_state *state, char *name, enum asm_type t, - struct YYLTYPE *locp) -{ - struct asm_symbol *s = NULL; - struct asm_symbol *exist = (struct asm_symbol *) - _mesa_symbol_table_find_symbol(state->st, 0, name); - - - if (exist != NULL) { - yyerror(locp, state, "redeclared identifier"); - } else { - s = calloc(1, sizeof(struct asm_symbol)); - s->name = name; - s->type = t; - - switch (t) { - case at_temp: - if (state->prog->NumTemporaries >= state->limits->MaxTemps) { - yyerror(locp, state, "too many temporaries declared"); - free(s); - return NULL; - } - - s->temp_binding = state->prog->NumTemporaries; - state->prog->NumTemporaries++; - break; - - case at_address: - if (state->prog->NumAddressRegs >= state->limits->MaxAddressRegs) { - yyerror(locp, state, "too many address registers declared"); - free(s); - return NULL; - } - - /* FINISHME: Add support for multiple address registers. - */ - state->prog->NumAddressRegs++; - break; - - default: - break; - } - - _mesa_symbol_table_add_symbol(state->st, 0, s->name, s); - s->next = state->sym; - state->sym = s; - } - - return s; -} - - -int add_state_reference(struct gl_program_parameter_list *param_list, - const gl_state_index tokens[STATE_LENGTH]) -{ - const GLuint size = 4; /* XXX fix */ - char *name; - GLint index; - - name = _mesa_program_state_string(tokens); - index = _mesa_add_parameter(param_list, PROGRAM_STATE_VAR, name, - size, GL_NONE, NULL, tokens, 0x0); - param_list->StateFlags |= _mesa_program_state_flags(tokens); - - /* free name string here since we duplicated it in add_parameter() */ - free(name); - - return index; -} - - -int -initialize_symbol_from_state(struct gl_program *prog, - struct asm_symbol *param_var, - const gl_state_index tokens[STATE_LENGTH]) -{ - int idx = -1; - gl_state_index state_tokens[STATE_LENGTH]; - - - memcpy(state_tokens, tokens, sizeof(state_tokens)); - - param_var->type = at_param; - param_var->param_binding_type = PROGRAM_STATE_VAR; - - /* If we are adding a STATE_MATRIX that has multiple rows, we need to - * unroll it and call add_state_reference() for each row - */ - if ((state_tokens[0] == STATE_MODELVIEW_MATRIX || - state_tokens[0] == STATE_PROJECTION_MATRIX || - state_tokens[0] == STATE_MVP_MATRIX || - state_tokens[0] == STATE_TEXTURE_MATRIX || - state_tokens[0] == STATE_PROGRAM_MATRIX) - && (state_tokens[2] != state_tokens[3])) { - int row; - const int first_row = state_tokens[2]; - const int last_row = state_tokens[3]; - - for (row = first_row; row <= last_row; row++) { - state_tokens[2] = state_tokens[3] = row; - - idx = add_state_reference(prog->Parameters, state_tokens); - if (param_var->param_binding_begin == ~0U) { - param_var->param_binding_begin = idx; - param_var->param_binding_swizzle = SWIZZLE_XYZW; - } - - param_var->param_binding_length++; - } - } - else { - idx = add_state_reference(prog->Parameters, state_tokens); - if (param_var->param_binding_begin == ~0U) { - param_var->param_binding_begin = idx; - param_var->param_binding_swizzle = SWIZZLE_XYZW; - } - param_var->param_binding_length++; - } - - return idx; -} - - -int -initialize_symbol_from_param(struct gl_program *prog, - struct asm_symbol *param_var, - const gl_state_index tokens[STATE_LENGTH]) -{ - int idx = -1; - gl_state_index state_tokens[STATE_LENGTH]; - - - memcpy(state_tokens, tokens, sizeof(state_tokens)); - - assert((state_tokens[0] == STATE_VERTEX_PROGRAM) - || (state_tokens[0] == STATE_FRAGMENT_PROGRAM)); - assert((state_tokens[1] == STATE_ENV) - || (state_tokens[1] == STATE_LOCAL)); - - /* - * The param type is STATE_VAR. The program parameter entry will - * effectively be a pointer into the LOCAL or ENV parameter array. - */ - param_var->type = at_param; - param_var->param_binding_type = PROGRAM_STATE_VAR; - - /* If we are adding a STATE_ENV or STATE_LOCAL that has multiple elements, - * we need to unroll it and call add_state_reference() for each row - */ - if (state_tokens[2] != state_tokens[3]) { - int row; - const int first_row = state_tokens[2]; - const int last_row = state_tokens[3]; - - for (row = first_row; row <= last_row; row++) { - state_tokens[2] = state_tokens[3] = row; - - idx = add_state_reference(prog->Parameters, state_tokens); - if (param_var->param_binding_begin == ~0U) { - param_var->param_binding_begin = idx; - param_var->param_binding_swizzle = SWIZZLE_XYZW; - } - param_var->param_binding_length++; - } - } - else { - idx = add_state_reference(prog->Parameters, state_tokens); - if (param_var->param_binding_begin == ~0U) { - param_var->param_binding_begin = idx; - param_var->param_binding_swizzle = SWIZZLE_XYZW; - } - param_var->param_binding_length++; - } - - return idx; -} - - -/** - * Put a float/vector constant/literal into the parameter list. - * \param param_var returns info about the parameter/constant's location, - * binding, type, etc. - * \param vec the vector/constant to add - * \param allowSwizzle if true, try to consolidate constants which only differ - * by a swizzle. We don't want to do this when building - * arrays of constants that may be indexed indirectly. - * \return index of the constant in the parameter list. - */ -int -initialize_symbol_from_const(struct gl_program *prog, - struct asm_symbol *param_var, - const struct asm_vector *vec, - GLboolean allowSwizzle) -{ - unsigned swizzle; - const int idx = _mesa_add_unnamed_constant(prog->Parameters, - vec->data, vec->count, - allowSwizzle ? &swizzle : NULL); - - param_var->type = at_param; - param_var->param_binding_type = PROGRAM_CONSTANT; - - if (param_var->param_binding_begin == ~0U) { - param_var->param_binding_begin = idx; - param_var->param_binding_swizzle = allowSwizzle ? swizzle : SWIZZLE_XYZW; - } - param_var->param_binding_length++; - - return idx; -} - - -char * -make_error_string(const char *fmt, ...) -{ - int length; - char *str; - va_list args; - - - /* Call vsnprintf once to determine how large the final string is. Call it - * again to do the actual formatting. from the vsnprintf manual page: - * - * Upon successful return, these functions return the number of - * characters printed (not including the trailing '\0' used to end - * output to strings). - */ - va_start(args, fmt); - length = 1 + vsnprintf(NULL, 0, fmt, args); - va_end(args); - - str = malloc(length); - if (str) { - va_start(args, fmt); - vsnprintf(str, length, fmt, args); - va_end(args); - } - - return str; -} - - -void -yyerror(YYLTYPE *locp, struct asm_parser_state *state, const char *s) -{ - char *err_str; - - - err_str = make_error_string("glProgramStringARB(%s)\n", s); - if (err_str) { - _mesa_error(state->ctx, GL_INVALID_OPERATION, err_str); - free(err_str); - } - - err_str = make_error_string("line %u, char %u: error: %s\n", - locp->first_line, locp->first_column, s); - _mesa_set_program_error(state->ctx, locp->position, err_str); - - if (err_str) { - free(err_str); - } -} - - -GLboolean -_mesa_parse_arb_program(GLcontext *ctx, GLenum target, const GLubyte *str, - GLsizei len, struct asm_parser_state *state) -{ - struct asm_instruction *inst; - unsigned i; - GLubyte *strz; - GLboolean result = GL_FALSE; - void *temp; - struct asm_symbol *sym; - - state->ctx = ctx; - state->prog->Target = target; - state->prog->Parameters = _mesa_new_parameter_list(); - - /* Make a copy of the program string and force it to be NUL-terminated. - */ - strz = (GLubyte *) malloc(len + 1); - if (strz == NULL) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramStringARB"); - return GL_FALSE; - } - memcpy (strz, str, len); - strz[len] = '\0'; - - state->prog->String = strz; - - state->st = _mesa_symbol_table_ctor(); - - state->limits = (target == GL_VERTEX_PROGRAM_ARB) - ? & ctx->Const.VertexProgram - : & ctx->Const.FragmentProgram; - - state->MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits; - state->MaxTextureCoordUnits = ctx->Const.MaxTextureCoordUnits; - state->MaxTextureUnits = ctx->Const.MaxTextureUnits; - state->MaxClipPlanes = ctx->Const.MaxClipPlanes; - state->MaxLights = ctx->Const.MaxLights; - state->MaxProgramMatrices = ctx->Const.MaxProgramMatrices; - - state->state_param_enum = (target == GL_VERTEX_PROGRAM_ARB) - ? STATE_VERTEX_PROGRAM : STATE_FRAGMENT_PROGRAM; - - _mesa_set_program_error(ctx, -1, NULL); - - _mesa_program_lexer_ctor(& state->scanner, state, (const char *) str, len); - yyparse(state); - _mesa_program_lexer_dtor(state->scanner); - - - if (ctx->Program.ErrorPos != -1) { - goto error; - } - - if (! _mesa_layout_parameters(state)) { - struct YYLTYPE loc; - - loc.first_line = 0; - loc.first_column = 0; - loc.position = len; - - yyerror(& loc, state, "invalid PARAM usage"); - goto error; - } - - - - /* Add one instruction to store the "END" instruction. - */ - state->prog->Instructions = - _mesa_alloc_instructions(state->prog->NumInstructions + 1); - inst = state->inst_head; - for (i = 0; i < state->prog->NumInstructions; i++) { - struct asm_instruction *const temp = inst->next; - - state->prog->Instructions[i] = inst->Base; - inst = temp; - } - - /* Finally, tag on an OPCODE_END instruction */ - { - const GLuint numInst = state->prog->NumInstructions; - _mesa_init_instructions(state->prog->Instructions + numInst, 1); - state->prog->Instructions[numInst].Opcode = OPCODE_END; - } - state->prog->NumInstructions++; - - state->prog->NumParameters = state->prog->Parameters->NumParameters; - state->prog->NumAttributes = _mesa_bitcount(state->prog->InputsRead); - - /* - * Initialize native counts to logical counts. The device driver may - * change them if program is translated into a hardware program. - */ - state->prog->NumNativeInstructions = state->prog->NumInstructions; - state->prog->NumNativeTemporaries = state->prog->NumTemporaries; - state->prog->NumNativeParameters = state->prog->NumParameters; - state->prog->NumNativeAttributes = state->prog->NumAttributes; - state->prog->NumNativeAddressRegs = state->prog->NumAddressRegs; - - result = GL_TRUE; - -error: - for (inst = state->inst_head; inst != NULL; inst = temp) { - temp = inst->next; - free(inst); - } - - state->inst_head = NULL; - state->inst_tail = NULL; - - for (sym = state->sym; sym != NULL; sym = temp) { - temp = sym->next; - - free((void *) sym->name); - free(sym); - } - state->sym = NULL; - - _mesa_symbol_table_dtor(state->st); - state->st = NULL; - - return result; -} diff --git a/src/mesa/shader/program_parse_extra.c b/src/mesa/shader/program_parse_extra.c deleted file mode 100644 index ae98b782b7..0000000000 --- a/src/mesa/shader/program_parse_extra.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright © 2009 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include -#include "main/mtypes.h" -#include "prog_instruction.h" -#include "program_parser.h" - - -/** - * Extra assembly-level parser routines - * - * \author Ian Romanick - */ - -int -_mesa_parse_instruction_suffix(const struct asm_parser_state *state, - const char *suffix, - struct prog_instruction *inst) -{ - inst->CondUpdate = 0; - inst->CondDst = 0; - inst->SaturateMode = SATURATE_OFF; - inst->Precision = FLOAT32; - - - /* The first possible suffix element is the precision specifier from - * NV_fragment_program_option. - */ - if (state->option.NV_fragment) { - switch (suffix[0]) { - case 'H': - inst->Precision = FLOAT16; - suffix++; - break; - case 'R': - inst->Precision = FLOAT32; - suffix++; - break; - case 'X': - inst->Precision = FIXED12; - suffix++; - break; - default: - break; - } - } - - /* The next possible suffix element is the condition code modifier selection - * from NV_fragment_program_option. - */ - if (state->option.NV_fragment) { - if (suffix[0] == 'C') { - inst->CondUpdate = 1; - suffix++; - } - } - - - /* The final possible suffix element is the saturation selector from - * ARB_fragment_program. - */ - if (state->mode == ARB_fragment) { - if (strcmp(suffix, "_SAT") == 0) { - inst->SaturateMode = SATURATE_ZERO_ONE; - suffix += 4; - } - } - - - /* It is an error for all of the suffix string not to be consumed. - */ - return suffix[0] == '\0'; -} - - -int -_mesa_parse_cc(const char *s) -{ - int cond = 0; - - switch (s[0]) { - case 'E': - if (s[1] == 'Q') { - cond = COND_EQ; - } - break; - - case 'F': - if (s[1] == 'L') { - cond = COND_FL; - } - break; - - case 'G': - if (s[1] == 'E') { - cond = COND_GE; - } else if (s[1] == 'T') { - cond = COND_GT; - } - break; - - case 'L': - if (s[1] == 'E') { - cond = COND_LE; - } else if (s[1] == 'T') { - cond = COND_LT; - } - break; - - case 'N': - if (s[1] == 'E') { - cond = COND_NE; - } - break; - - case 'T': - if (s[1] == 'R') { - cond = COND_TR; - } - break; - - default: - break; - } - - return ((cond == 0) || (s[2] != '\0')) ? 0 : cond; -} - - -int -_mesa_ARBvp_parse_option(struct asm_parser_state *state, const char *option) -{ - if (strcmp(option, "ARB_position_invariant") == 0) { - state->option.PositionInvariant = 1; - return 1; - } - - return 0; -} - - -int -_mesa_ARBfp_parse_option(struct asm_parser_state *state, const char *option) -{ - /* All of the options currently supported start with "ARB_". The code is - * currently structured with nested if-statements because eventually options - * that start with "NV_" will be supported. This structure will result in - * less churn when those options are added. - */ - if (strncmp(option, "ARB_", 4) == 0) { - /* Advance the pointer past the "ARB_" prefix. - */ - option += 4; - - - if (strncmp(option, "fog_", 4) == 0) { - option += 4; - - if (state->option.Fog == OPTION_NONE) { - if (strcmp(option, "exp") == 0) { - state->option.Fog = OPTION_FOG_EXP; - return 1; - } else if (strcmp(option, "exp2") == 0) { - state->option.Fog = OPTION_FOG_EXP2; - return 1; - } else if (strcmp(option, "linear") == 0) { - state->option.Fog = OPTION_FOG_LINEAR; - return 1; - } - } - - return 0; - } else if (strncmp(option, "precision_hint_", 15) == 0) { - option += 15; - - if (state->option.PrecisionHint == OPTION_NONE) { - if (strcmp(option, "nicest") == 0) { - state->option.PrecisionHint = OPTION_NICEST; - return 1; - } else if (strcmp(option, "fastest") == 0) { - state->option.PrecisionHint = OPTION_FASTEST; - return 1; - } - } - - return 0; - } else if (strcmp(option, "draw_buffers") == 0) { - /* Don't need to check extension availability because all Mesa-based - * drivers support GL_ARB_draw_buffers. - */ - state->option.DrawBuffers = 1; - return 1; - } else if (strcmp(option, "fragment_program_shadow") == 0) { - if (state->ctx->Extensions.ARB_fragment_program_shadow) { - state->option.Shadow = 1; - return 1; - } - } else if (strncmp(option, "fragment_coord_", 15) == 0) { - option += 15; - if (state->ctx->Extensions.ARB_fragment_coord_conventions) { - if (strcmp(option, "origin_upper_left") == 0) { - state->option.OriginUpperLeft = 1; - return 1; - } - else if (strcmp(option, "pixel_center_integer") == 0) { - state->option.PixelCenterInteger = 1; - return 1; - } - } - } - } else if (strncmp(option, "NV_fragment_program", 19) == 0) { - option += 19; - - /* Other NV_fragment_program strings may be supported later. - */ - if (option[0] == '\0') { - if (state->ctx->Extensions.NV_fragment_program_option) { - state->option.NV_fragment = 1; - return 1; - } - } - } else if (strncmp(option, "MESA_", 5) == 0) { - option += 5; - - if (strcmp(option, "texture_array") == 0) { - if (state->ctx->Extensions.MESA_texture_array) { - state->option.TexArray = 1; - return 1; - } - } - } - - return 0; -} diff --git a/src/mesa/shader/program_parser.h b/src/mesa/shader/program_parser.h deleted file mode 100644 index be952d4b9c..0000000000 --- a/src/mesa/shader/program_parser.h +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright © 2009 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#pragma once - -#include "main/config.h" - -#ifndef MTYPES_H -struct __GLcontextRec; -typedef struct __GLcontextRec GLcontext; -#endif - -enum asm_type { - at_none, - at_address, - at_attrib, - at_param, - at_temp, - at_output -}; - -struct asm_symbol { - struct asm_symbol *next; /**< List linkage for freeing. */ - const char *name; - enum asm_type type; - unsigned attrib_binding; - unsigned output_binding; /**< Output / result register number. */ - - /** - * One of PROGRAM_STATE_VAR, PROGRAM_LOCAL_PARAM, or PROGRAM_ENV_PARAM. - */ - unsigned param_binding_type; - - /** - * Offset into the program_parameter_list where the tokens representing our - * bound state (or constants) start. - */ - unsigned param_binding_begin; - - /** - * Constants put into the parameter list may be swizzled. This - * field contain's the symbol's swizzle. (SWIZZLE_X/Y/Z/W) - */ - unsigned param_binding_swizzle; - - /* This is how many entries in the program_parameter_list we take up - * with our state tokens or constants. Note that this is _not_ the same as - * the number of param registers we eventually use. - */ - unsigned param_binding_length; - - /** - * Index of the temp register assigned to this variable. - */ - unsigned temp_binding; - - /** - * Flag whether or not a PARAM is an array - */ - unsigned param_is_array:1; - - - /** - * Flag whether or not a PARAM array is accessed indirectly - */ - unsigned param_accessed_indirectly:1; - - - /** - * \brief Is first pass of parameter layout done with this variable? - * - * The parameter layout routine operates in two passes. This flag tracks - * whether or not the first pass has handled this variable. - * - * \sa _mesa_layout_parameters - */ - unsigned pass1_done:1; -}; - - -struct asm_vector { - unsigned count; - float data[4]; -}; - - -struct asm_swizzle_mask { - unsigned swizzle:12; - unsigned mask:4; -}; - - -struct asm_src_register { - struct prog_src_register Base; - - /** - * Symbol associated with indirect access to parameter arrays. - * - * If \c Base::RelAddr is 1, this will point to the symbol for the parameter - * that is being dereferenced. Further, \c Base::Index will be the offset - * from the address register being used. - */ - struct asm_symbol *Symbol; -}; - - -struct asm_instruction { - struct prog_instruction Base; - struct asm_instruction *next; - struct asm_src_register SrcReg[3]; -}; - - -struct asm_parser_state { - GLcontext *ctx; - struct gl_program *prog; - - /** - * Per-program target limits - */ - struct gl_program_constants *limits; - - struct _mesa_symbol_table *st; - - /** - * Linked list of symbols - * - * This list is \b only used when cleaning up compiler state and freeing - * memory. - */ - struct asm_symbol *sym; - - /** - * State for the lexer. - */ - void *scanner; - - /** - * Linked list of instructions generated during parsing. - */ - /*@{*/ - struct asm_instruction *inst_head; - struct asm_instruction *inst_tail; - /*@}*/ - - - /** - * Selected limits copied from gl_constants - * - * These are limits from the GL context, but various bits in the program - * must be validated against these values. - */ - /*@{*/ - unsigned MaxTextureCoordUnits; - unsigned MaxTextureImageUnits; - unsigned MaxTextureUnits; - unsigned MaxClipPlanes; - unsigned MaxLights; - unsigned MaxProgramMatrices; - /*@}*/ - - /** - * Value to use in state vector accessors for environment and local - * parameters - */ - unsigned state_param_enum; - - - /** - * Input attributes bound to specific names - * - * This is only needed so that errors can be properly produced when - * multiple ATTRIB statements bind illegal combinations of vertex - * attributes. - */ - unsigned InputsBound; - - enum { - invalid_mode = 0, - ARB_vertex, - ARB_fragment - } mode; - - struct { - unsigned PositionInvariant:1; - unsigned Fog:2; - unsigned PrecisionHint:2; - unsigned DrawBuffers:1; - unsigned Shadow:1; - unsigned TexRect:1; - unsigned TexArray:1; - unsigned NV_fragment:1; - unsigned OriginUpperLeft:1; - unsigned PixelCenterInteger:1; - } option; - - struct { - unsigned UsesKill:1; - } fragment; -}; - -#define OPTION_NONE 0 -#define OPTION_FOG_EXP 1 -#define OPTION_FOG_EXP2 2 -#define OPTION_FOG_LINEAR 3 -#define OPTION_NICEST 1 -#define OPTION_FASTEST 2 - -typedef struct YYLTYPE { - int first_line; - int first_column; - int last_line; - int last_column; - int position; -} YYLTYPE; - -#define YYLTYPE_IS_DECLARED 1 -#define YYLTYPE_IS_TRIVIAL 1 - - -extern GLboolean _mesa_parse_arb_program(GLcontext *ctx, GLenum target, - const GLubyte *str, GLsizei len, struct asm_parser_state *state); - - - -/* From program_lexer.l. */ -extern void _mesa_program_lexer_dtor(void *scanner); - -extern void _mesa_program_lexer_ctor(void **scanner, - struct asm_parser_state *state, const char *string, size_t len); - - -/** - *\name From program_parse_extra.c - */ -/*@{*/ - -/** - * Parses and processes an option string to an ARB vertex program - * - * \return - * Non-zero on success, zero on failure. - */ -extern int _mesa_ARBvp_parse_option(struct asm_parser_state *state, - const char *option); - -/** - * Parses and processes an option string to an ARB fragment program - * - * \return - * Non-zero on success, zero on failure. - */ -extern int _mesa_ARBfp_parse_option(struct asm_parser_state *state, - const char *option); - -/** - * Parses and processes instruction suffixes - * - * Instruction suffixes, such as \c _SAT, are processed. The relevant bits - * are set in \c inst. If suffixes are encountered that are either not known - * or not supported by the modes and options set in \c state, zero will be - * returned. - * - * \return - * Non-zero on success, zero on failure. - */ -extern int _mesa_parse_instruction_suffix(const struct asm_parser_state *state, - const char *suffix, struct prog_instruction *inst); - -/** - * Parses a condition code name - * - * The condition code names (e.g., \c LT, \c GT, \c NE) were added to assembly - * shaders with the \c GL_NV_fragment_program_option extension. This function - * converts a string representation into one of the \c COND_ macros. - * - * \return - * One of the \c COND_ macros defined in prog_instruction.h on success or zero - * on failure. - */ -extern int _mesa_parse_cc(const char *s); - -/*@}*/ diff --git a/src/mesa/shader/programopt.c b/src/mesa/shader/programopt.c deleted file mode 100644 index fb2ebe6338..0000000000 --- a/src/mesa/shader/programopt.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file programopt.c - * Vertex/Fragment program optimizations and transformations for program - * options, etc. - * - * \author Brian Paul - */ - - -#include "main/glheader.h" -#include "main/context.h" -#include "prog_parameter.h" -#include "prog_statevars.h" -#include "program.h" -#include "programopt.h" -#include "prog_instruction.h" - - -/** - * This function inserts instructions for coordinate modelview * projection - * into a vertex program. - * May be used to implement the position_invariant option. - */ -static void -_mesa_insert_mvp_dp4_code(GLcontext *ctx, struct gl_vertex_program *vprog) -{ - struct prog_instruction *newInst; - const GLuint origLen = vprog->Base.NumInstructions; - const GLuint newLen = origLen + 4; - GLuint i; - - /* - * Setup state references for the modelview/projection matrix. - * XXX we should check if these state vars are already declared. - */ - static const gl_state_index mvpState[4][STATE_LENGTH] = { - { STATE_MVP_MATRIX, 0, 0, 0, 0 }, /* state.matrix.mvp.row[0] */ - { STATE_MVP_MATRIX, 0, 1, 1, 0 }, /* state.matrix.mvp.row[1] */ - { STATE_MVP_MATRIX, 0, 2, 2, 0 }, /* state.matrix.mvp.row[2] */ - { STATE_MVP_MATRIX, 0, 3, 3, 0 }, /* state.matrix.mvp.row[3] */ - }; - GLint mvpRef[4]; - - for (i = 0; i < 4; i++) { - mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters, - mvpState[i]); - } - - /* Alloc storage for new instructions */ - newInst = _mesa_alloc_instructions(newLen); - if (!newInst) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, - "glProgramString(inserting position_invariant code)"); - return; - } - - /* - * Generated instructions: - * newInst[0] = DP4 result.position.x, mvp.row[0], vertex.position; - * newInst[1] = DP4 result.position.y, mvp.row[1], vertex.position; - * newInst[2] = DP4 result.position.z, mvp.row[2], vertex.position; - * newInst[3] = DP4 result.position.w, mvp.row[3], vertex.position; - */ - _mesa_init_instructions(newInst, 4); - for (i = 0; i < 4; i++) { - newInst[i].Opcode = OPCODE_DP4; - newInst[i].DstReg.File = PROGRAM_OUTPUT; - newInst[i].DstReg.Index = VERT_RESULT_HPOS; - newInst[i].DstReg.WriteMask = (WRITEMASK_X << i); - newInst[i].SrcReg[0].File = PROGRAM_STATE_VAR; - newInst[i].SrcReg[0].Index = mvpRef[i]; - newInst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP; - newInst[i].SrcReg[1].File = PROGRAM_INPUT; - newInst[i].SrcReg[1].Index = VERT_ATTRIB_POS; - newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; - } - - /* Append original instructions after new instructions */ - _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen); - - /* free old instructions */ - _mesa_free_instructions(vprog->Base.Instructions, origLen); - - /* install new instructions */ - vprog->Base.Instructions = newInst; - vprog->Base.NumInstructions = newLen; - vprog->Base.InputsRead |= VERT_BIT_POS; - vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS); -} - - -static void -_mesa_insert_mvp_mad_code(GLcontext *ctx, struct gl_vertex_program *vprog) -{ - struct prog_instruction *newInst; - const GLuint origLen = vprog->Base.NumInstructions; - const GLuint newLen = origLen + 4; - GLuint hposTemp; - GLuint i; - - /* - * Setup state references for the modelview/projection matrix. - * XXX we should check if these state vars are already declared. - */ - static const gl_state_index mvpState[4][STATE_LENGTH] = { - { STATE_MVP_MATRIX, 0, 0, 0, STATE_MATRIX_TRANSPOSE }, - { STATE_MVP_MATRIX, 0, 1, 1, STATE_MATRIX_TRANSPOSE }, - { STATE_MVP_MATRIX, 0, 2, 2, STATE_MATRIX_TRANSPOSE }, - { STATE_MVP_MATRIX, 0, 3, 3, STATE_MATRIX_TRANSPOSE }, - }; - GLint mvpRef[4]; - - for (i = 0; i < 4; i++) { - mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters, - mvpState[i]); - } - - /* Alloc storage for new instructions */ - newInst = _mesa_alloc_instructions(newLen); - if (!newInst) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, - "glProgramString(inserting position_invariant code)"); - return; - } - - /* TEMP hposTemp; */ - hposTemp = vprog->Base.NumTemporaries++; - - /* - * Generated instructions: - * emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]); - * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp); - * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp); - * emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp); - */ - _mesa_init_instructions(newInst, 4); - - newInst[0].Opcode = OPCODE_MUL; - newInst[0].DstReg.File = PROGRAM_TEMPORARY; - newInst[0].DstReg.Index = hposTemp; - newInst[0].DstReg.WriteMask = WRITEMASK_XYZW; - newInst[0].SrcReg[0].File = PROGRAM_INPUT; - newInst[0].SrcReg[0].Index = VERT_ATTRIB_POS; - newInst[0].SrcReg[0].Swizzle = SWIZZLE_XXXX; - newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR; - newInst[0].SrcReg[1].Index = mvpRef[0]; - newInst[0].SrcReg[1].Swizzle = SWIZZLE_NOOP; - - for (i = 1; i <= 2; i++) { - newInst[i].Opcode = OPCODE_MAD; - newInst[i].DstReg.File = PROGRAM_TEMPORARY; - newInst[i].DstReg.Index = hposTemp; - newInst[i].DstReg.WriteMask = WRITEMASK_XYZW; - newInst[i].SrcReg[0].File = PROGRAM_INPUT; - newInst[i].SrcReg[0].Index = VERT_ATTRIB_POS; - newInst[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(i,i,i,i); - newInst[i].SrcReg[1].File = PROGRAM_STATE_VAR; - newInst[i].SrcReg[1].Index = mvpRef[i]; - newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; - newInst[i].SrcReg[2].File = PROGRAM_TEMPORARY; - newInst[i].SrcReg[2].Index = hposTemp; - newInst[1].SrcReg[2].Swizzle = SWIZZLE_NOOP; - } - - newInst[3].Opcode = OPCODE_MAD; - newInst[3].DstReg.File = PROGRAM_OUTPUT; - newInst[3].DstReg.Index = VERT_RESULT_HPOS; - newInst[3].DstReg.WriteMask = WRITEMASK_XYZW; - newInst[3].SrcReg[0].File = PROGRAM_INPUT; - newInst[3].SrcReg[0].Index = VERT_ATTRIB_POS; - newInst[3].SrcReg[0].Swizzle = SWIZZLE_WWWW; - newInst[3].SrcReg[1].File = PROGRAM_STATE_VAR; - newInst[3].SrcReg[1].Index = mvpRef[3]; - newInst[3].SrcReg[1].Swizzle = SWIZZLE_NOOP; - newInst[3].SrcReg[2].File = PROGRAM_TEMPORARY; - newInst[3].SrcReg[2].Index = hposTemp; - newInst[3].SrcReg[2].Swizzle = SWIZZLE_NOOP; - - - /* Append original instructions after new instructions */ - _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen); - - /* free old instructions */ - _mesa_free_instructions(vprog->Base.Instructions, origLen); - - /* install new instructions */ - vprog->Base.Instructions = newInst; - vprog->Base.NumInstructions = newLen; - vprog->Base.InputsRead |= VERT_BIT_POS; - vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS); -} - - -void -_mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog) -{ - if (ctx->mvp_with_dp4) - _mesa_insert_mvp_dp4_code( ctx, vprog ); - else - _mesa_insert_mvp_mad_code( ctx, vprog ); -} - - - - - - -/** - * Append extra instructions onto the given fragment program to implement - * the fog mode specified by fprog->FogOption. - * The fragment.fogcoord input is used to compute the fog blend factor. - * - * XXX with a little work, this function could be adapted to add fog code - * to vertex programs too. - */ -void -_mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog) -{ - static const gl_state_index fogPStateOpt[STATE_LENGTH] - = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 }; - static const gl_state_index fogColorState[STATE_LENGTH] - = { STATE_FOG_COLOR, 0, 0, 0, 0}; - struct prog_instruction *newInst, *inst; - const GLuint origLen = fprog->Base.NumInstructions; - const GLuint newLen = origLen + 5; - GLuint i; - GLint fogPRefOpt, fogColorRef; /* state references */ - GLuint colorTemp, fogFactorTemp; /* temporary registerss */ - - if (fprog->FogOption == GL_NONE) { - _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program" - " with FogOption == GL_NONE"); - return; - } - - /* Alloc storage for new instructions */ - newInst = _mesa_alloc_instructions(newLen); - if (!newInst) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, - "glProgramString(inserting fog_option code)"); - return; - } - - /* Copy orig instructions into new instruction buffer */ - _mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen); - - /* PARAM fogParamsRefOpt = internal optimized fog params; */ - fogPRefOpt - = _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt); - /* PARAM fogColorRef = state.fog.color; */ - fogColorRef - = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState); - - /* TEMP colorTemp; */ - colorTemp = fprog->Base.NumTemporaries++; - /* TEMP fogFactorTemp; */ - fogFactorTemp = fprog->Base.NumTemporaries++; - - /* Scan program to find where result.color is written */ - inst = newInst; - for (i = 0; i < fprog->Base.NumInstructions; i++) { - if (inst->Opcode == OPCODE_END) - break; - if (inst->DstReg.File == PROGRAM_OUTPUT && - inst->DstReg.Index == FRAG_RESULT_COLOR) { - /* change the instruction to write to colorTemp w/ clamping */ - inst->DstReg.File = PROGRAM_TEMPORARY; - inst->DstReg.Index = colorTemp; - inst->SaturateMode = SATURATE_ZERO_ONE; - /* don't break (may be several writes to result.color) */ - } - inst++; - } - assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */ - - _mesa_init_instructions(inst, 5); - - /* emit instructions to compute fog blending factor */ - if (fprog->FogOption == GL_LINEAR) { - /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */ - inst->Opcode = OPCODE_MAD; - inst->DstReg.File = PROGRAM_TEMPORARY; - inst->DstReg.Index = fogFactorTemp; - inst->DstReg.WriteMask = WRITEMASK_X; - inst->SrcReg[0].File = PROGRAM_INPUT; - inst->SrcReg[0].Index = FRAG_ATTRIB_FOGC; - inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; - inst->SrcReg[1].File = PROGRAM_STATE_VAR; - inst->SrcReg[1].Index = fogPRefOpt; - inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; - inst->SrcReg[2].File = PROGRAM_STATE_VAR; - inst->SrcReg[2].Index = fogPRefOpt; - inst->SrcReg[2].Swizzle = SWIZZLE_YYYY; - inst->SaturateMode = SATURATE_ZERO_ONE; - inst++; - } - else { - ASSERT(fprog->FogOption == GL_EXP || fprog->FogOption == GL_EXP2); - /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */ - /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */ - /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */ - inst->Opcode = OPCODE_MUL; - inst->DstReg.File = PROGRAM_TEMPORARY; - inst->DstReg.Index = fogFactorTemp; - inst->DstReg.WriteMask = WRITEMASK_X; - inst->SrcReg[0].File = PROGRAM_STATE_VAR; - inst->SrcReg[0].Index = fogPRefOpt; - inst->SrcReg[0].Swizzle - = (fprog->FogOption == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW; - inst->SrcReg[1].File = PROGRAM_INPUT; - inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC; - inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; - inst++; - if (fprog->FogOption == GL_EXP2) { - /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */ - inst->Opcode = OPCODE_MUL; - inst->DstReg.File = PROGRAM_TEMPORARY; - inst->DstReg.Index = fogFactorTemp; - inst->DstReg.WriteMask = WRITEMASK_X; - inst->SrcReg[0].File = PROGRAM_TEMPORARY; - inst->SrcReg[0].Index = fogFactorTemp; - inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; - inst->SrcReg[1].File = PROGRAM_TEMPORARY; - inst->SrcReg[1].Index = fogFactorTemp; - inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; - inst++; - } - /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */ - inst->Opcode = OPCODE_EX2; - inst->DstReg.File = PROGRAM_TEMPORARY; - inst->DstReg.Index = fogFactorTemp; - inst->DstReg.WriteMask = WRITEMASK_X; - inst->SrcReg[0].File = PROGRAM_TEMPORARY; - inst->SrcReg[0].Index = fogFactorTemp; - inst->SrcReg[0].Negate = NEGATE_XYZW; - inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; - inst->SaturateMode = SATURATE_ZERO_ONE; - inst++; - } - /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */ - inst->Opcode = OPCODE_LRP; - inst->DstReg.File = PROGRAM_OUTPUT; - inst->DstReg.Index = FRAG_RESULT_COLOR; - inst->DstReg.WriteMask = WRITEMASK_XYZ; - inst->SrcReg[0].File = PROGRAM_TEMPORARY; - inst->SrcReg[0].Index = fogFactorTemp; - inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; - inst->SrcReg[1].File = PROGRAM_TEMPORARY; - inst->SrcReg[1].Index = colorTemp; - inst->SrcReg[1].Swizzle = SWIZZLE_NOOP; - inst->SrcReg[2].File = PROGRAM_STATE_VAR; - inst->SrcReg[2].Index = fogColorRef; - inst->SrcReg[2].Swizzle = SWIZZLE_NOOP; - inst++; - /* MOV result.color.w, colorTemp.x; # copy alpha */ - inst->Opcode = OPCODE_MOV; - inst->DstReg.File = PROGRAM_OUTPUT; - inst->DstReg.Index = FRAG_RESULT_COLOR; - inst->DstReg.WriteMask = WRITEMASK_W; - inst->SrcReg[0].File = PROGRAM_TEMPORARY; - inst->SrcReg[0].Index = colorTemp; - inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; - inst++; - /* END; */ - inst->Opcode = OPCODE_END; - inst++; - - /* free old instructions */ - _mesa_free_instructions(fprog->Base.Instructions, origLen); - - /* install new instructions */ - fprog->Base.Instructions = newInst; - fprog->Base.NumInstructions = inst - newInst; - fprog->Base.InputsRead |= FRAG_BIT_FOGC; - /* XXX do this? fprog->FogOption = GL_NONE; */ -} - - - -static GLboolean -is_texture_instruction(const struct prog_instruction *inst) -{ - switch (inst->Opcode) { - case OPCODE_TEX: - case OPCODE_TXB: - case OPCODE_TXD: - case OPCODE_TXL: - case OPCODE_TXP: - case OPCODE_TXP_NV: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Count the number of texure indirections in the given program. - * The program's NumTexIndirections field will be updated. - * See the GL_ARB_fragment_program spec (issue 24) for details. - * XXX we count texture indirections in texenvprogram.c (maybe use this code - * instead and elsewhere). - */ -void -_mesa_count_texture_indirections(struct gl_program *prog) -{ - GLuint indirections = 1; - GLbitfield tempsOutput = 0x0; - GLbitfield aluTemps = 0x0; - GLuint i; - - for (i = 0; i < prog->NumInstructions; i++) { - const struct prog_instruction *inst = prog->Instructions + i; - - if (is_texture_instruction(inst)) { - if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) && - (tempsOutput & (1 << inst->SrcReg[0].Index))) || - ((inst->Opcode != OPCODE_KIL) && - (inst->DstReg.File == PROGRAM_TEMPORARY) && - (aluTemps & (1 << inst->DstReg.Index)))) - { - indirections++; - tempsOutput = 0x0; - aluTemps = 0x0; - } - } - else { - GLuint j; - for (j = 0; j < 3; j++) { - if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) - aluTemps |= (1 << inst->SrcReg[j].Index); - } - if (inst->DstReg.File == PROGRAM_TEMPORARY) - aluTemps |= (1 << inst->DstReg.Index); - } - - if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY)) - tempsOutput |= (1 << inst->DstReg.Index); - } - - prog->NumTexIndirections = indirections; -} - - -/** - * Count number of texture instructions in given program and update the - * program's NumTexInstructions field. - */ -void -_mesa_count_texture_instructions(struct gl_program *prog) -{ - GLuint i; - prog->NumTexInstructions = 0; - for (i = 0; i < prog->NumInstructions; i++) { - prog->NumTexInstructions += is_texture_instruction(prog->Instructions + i); - } -} - - -/** - * Scan/rewrite program to remove reads of custom (output) registers. - * The passed type has to be either PROGRAM_OUTPUT or PROGRAM_VARYING - * (for vertex shaders). - * In GLSL shaders, varying vars can be read and written. - * On some hardware, trying to read an output register causes trouble. - * So, rewrite the program to use a temporary register in this case. - */ -void -_mesa_remove_output_reads(struct gl_program *prog, gl_register_file type) -{ - GLuint i; - GLint outputMap[VERT_RESULT_MAX]; - GLuint numVaryingReads = 0; - GLboolean usedTemps[MAX_PROGRAM_TEMPS]; - GLuint firstTemp = 0; - - _mesa_find_used_registers(prog, PROGRAM_TEMPORARY, - usedTemps, MAX_PROGRAM_TEMPS); - - assert(type == PROGRAM_VARYING || type == PROGRAM_OUTPUT); - assert(prog->Target == GL_VERTEX_PROGRAM_ARB || type != PROGRAM_VARYING); - - for (i = 0; i < VERT_RESULT_MAX; i++) - outputMap[i] = -1; - - /* look for instructions which read from varying vars */ - for (i = 0; i < prog->NumInstructions; i++) { - struct prog_instruction *inst = prog->Instructions + i; - const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); - GLuint j; - for (j = 0; j < numSrc; j++) { - if (inst->SrcReg[j].File == type) { - /* replace the read with a temp reg */ - const GLuint var = inst->SrcReg[j].Index; - if (outputMap[var] == -1) { - numVaryingReads++; - outputMap[var] = _mesa_find_free_register(usedTemps, - MAX_PROGRAM_TEMPS, - firstTemp); - firstTemp = outputMap[var] + 1; - } - inst->SrcReg[j].File = PROGRAM_TEMPORARY; - inst->SrcReg[j].Index = outputMap[var]; - } - } - } - - if (numVaryingReads == 0) - return; /* nothing to be done */ - - /* look for instructions which write to the varying vars identified above */ - for (i = 0; i < prog->NumInstructions; i++) { - struct prog_instruction *inst = prog->Instructions + i; - if (inst->DstReg.File == type && - outputMap[inst->DstReg.Index] >= 0) { - /* change inst to write to the temp reg, instead of the varying */ - inst->DstReg.File = PROGRAM_TEMPORARY; - inst->DstReg.Index = outputMap[inst->DstReg.Index]; - } - } - - /* insert new instructions to copy the temp vars to the varying vars */ - { - struct prog_instruction *inst; - GLint endPos, var; - - /* Look for END instruction and insert the new varying writes */ - endPos = -1; - for (i = 0; i < prog->NumInstructions; i++) { - struct prog_instruction *inst = prog->Instructions + i; - if (inst->Opcode == OPCODE_END) { - endPos = i; - _mesa_insert_instructions(prog, i, numVaryingReads); - break; - } - } - - assert(endPos >= 0); - - /* insert new MOV instructions here */ - inst = prog->Instructions + endPos; - for (var = 0; var < VERT_RESULT_MAX; var++) { - if (outputMap[var] >= 0) { - /* MOV VAR[var], TEMP[tmp]; */ - inst->Opcode = OPCODE_MOV; - inst->DstReg.File = type; - inst->DstReg.Index = var; - inst->SrcReg[0].File = PROGRAM_TEMPORARY; - inst->SrcReg[0].Index = outputMap[var]; - inst++; - } - } - } -} - - -/** - * Make the given fragment program into a "no-op" shader. - * Actually, just copy the incoming fragment color (or texcoord) - * to the output color. - * This is for debug/test purposes. - */ -void -_mesa_nop_fragment_program(GLcontext *ctx, struct gl_fragment_program *prog) -{ - struct prog_instruction *inst; - GLuint inputAttr; - - inst = _mesa_alloc_instructions(2); - if (!inst) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_fragment_program"); - return; - } - - _mesa_init_instructions(inst, 2); - - inst[0].Opcode = OPCODE_MOV; - inst[0].DstReg.File = PROGRAM_OUTPUT; - inst[0].DstReg.Index = FRAG_RESULT_COLOR; - inst[0].SrcReg[0].File = PROGRAM_INPUT; - if (prog->Base.InputsRead & FRAG_BIT_COL0) - inputAttr = FRAG_ATTRIB_COL0; - else - inputAttr = FRAG_ATTRIB_TEX0; - inst[0].SrcReg[0].Index = inputAttr; - - inst[1].Opcode = OPCODE_END; - - _mesa_free_instructions(prog->Base.Instructions, - prog->Base.NumInstructions); - - prog->Base.Instructions = inst; - prog->Base.NumInstructions = 2; - prog->Base.InputsRead = 1 << inputAttr; - prog->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR); -} - - -/** - * \sa _mesa_nop_fragment_program - * Replace the given vertex program with a "no-op" program that just - * transforms vertex position and emits color. - */ -void -_mesa_nop_vertex_program(GLcontext *ctx, struct gl_vertex_program *prog) -{ - struct prog_instruction *inst; - GLuint inputAttr; - - /* - * Start with a simple vertex program that emits color. - */ - inst = _mesa_alloc_instructions(2); - if (!inst) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_vertex_program"); - return; - } - - _mesa_init_instructions(inst, 2); - - inst[0].Opcode = OPCODE_MOV; - inst[0].DstReg.File = PROGRAM_OUTPUT; - inst[0].DstReg.Index = VERT_RESULT_COL0; - inst[0].SrcReg[0].File = PROGRAM_INPUT; - if (prog->Base.InputsRead & VERT_BIT_COLOR0) - inputAttr = VERT_ATTRIB_COLOR0; - else - inputAttr = VERT_ATTRIB_TEX0; - inst[0].SrcReg[0].Index = inputAttr; - - inst[1].Opcode = OPCODE_END; - - _mesa_free_instructions(prog->Base.Instructions, - prog->Base.NumInstructions); - - prog->Base.Instructions = inst; - prog->Base.NumInstructions = 2; - prog->Base.InputsRead = 1 << inputAttr; - prog->Base.OutputsWritten = BITFIELD64_BIT(VERT_RESULT_COL0); - - /* - * Now insert code to do standard modelview/projection transformation. - */ - _mesa_insert_mvp_code(ctx, prog); -} diff --git a/src/mesa/shader/programopt.h b/src/mesa/shader/programopt.h deleted file mode 100644 index 21fac07849..0000000000 --- a/src/mesa/shader/programopt.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#ifndef PROGRAMOPT_H -#define PROGRAMOPT_H 1 - - -extern void -_mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog); - -extern void -_mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog); - -extern void -_mesa_count_texture_indirections(struct gl_program *prog); - -extern void -_mesa_count_texture_instructions(struct gl_program *prog); - -extern void -_mesa_remove_output_reads(struct gl_program *prog, gl_register_file type); - -extern void -_mesa_nop_fragment_program(GLcontext *ctx, struct gl_fragment_program *prog); - -extern void -_mesa_nop_vertex_program(GLcontext *ctx, struct gl_vertex_program *prog); - - -#endif /* PROGRAMOPT_H */ diff --git a/src/mesa/shader/symbol_table.c b/src/mesa/shader/symbol_table.c deleted file mode 100644 index 6a5d686897..0000000000 --- a/src/mesa/shader/symbol_table.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright © 2008 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include "main/imports.h" -#include "symbol_table.h" -#include "hash_table.h" - -struct symbol { - /** - * Link to the next symbol in the table with the same name - * - * The linked list of symbols with the same name is ordered by scope - * from inner-most to outer-most. - */ - struct symbol *next_with_same_name; - - - /** - * Link to the next symbol in the table with the same scope - * - * The linked list of symbols with the same scope is unordered. Symbols - * in this list my have unique names. - */ - struct symbol *next_with_same_scope; - - - /** - * Header information for the list of symbols with the same name. - */ - struct symbol_header *hdr; - - - /** - * Name space of the symbol - * - * Name space are arbitrary user assigned integers. No two symbols can - * exist in the same name space at the same scope level. - */ - int name_space; - - - /** - * Arbitrary user supplied data. - */ - void *data; -}; - - -/** - */ -struct symbol_header { - /** Linkage in list of all headers in a given symbol table. */ - struct symbol_header *next; - - /** Symbol name. */ - const char *name; - - /** Linked list of symbols with the same name. */ - struct symbol *symbols; -}; - - -/** - * Element of the scope stack. - */ -struct scope_level { - /** Link to next (inner) scope level. */ - struct scope_level *next; - - /** Linked list of symbols with the same scope. */ - struct symbol *symbols; -}; - - -/** - * - */ -struct _mesa_symbol_table { - /** Hash table containing all symbols in the symbol table. */ - struct hash_table *ht; - - /** Top of scope stack. */ - struct scope_level *current_scope; - - /** List of all symbol headers in the table. */ - struct symbol_header *hdr; -}; - - -struct _mesa_symbol_table_iterator { - /** - * Name space of symbols returned by this iterator. - */ - int name_space; - - - /** - * Currently iterated symbol - * - * The next call to \c _mesa_symbol_table_iterator_get will return this - * value. It will also update this value to the value that should be - * returned by the next call. - */ - struct symbol *curr; -}; - - -static void -check_symbol_table(struct _mesa_symbol_table *table) -{ -#if 1 - struct scope_level *scope; - - for (scope = table->current_scope; scope != NULL; scope = scope->next) { - struct symbol *sym; - - for (sym = scope->symbols - ; sym != NULL - ; sym = sym->next_with_same_name) { - const struct symbol_header *const hdr = sym->hdr; - struct symbol *sym2; - - for (sym2 = hdr->symbols - ; sym2 != NULL - ; sym2 = sym2->next_with_same_name) { - assert(sym2->hdr == hdr); - } - } - } -#endif -} - -void -_mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table) -{ - struct scope_level *const scope = table->current_scope; - struct symbol *sym = scope->symbols; - - table->current_scope = scope->next; - - free(scope); - - while (sym != NULL) { - struct symbol *const next = sym->next_with_same_scope; - struct symbol_header *const hdr = sym->hdr; - - assert(hdr->symbols == sym); - - hdr->symbols = sym->next_with_same_name; - - free(sym); - - sym = next; - } - - check_symbol_table(table); -} - - -void -_mesa_symbol_table_push_scope(struct _mesa_symbol_table *table) -{ - struct scope_level *const scope = calloc(1, sizeof(*scope)); - - scope->next = table->current_scope; - table->current_scope = scope; -} - - -static struct symbol_header * -find_symbol(struct _mesa_symbol_table *table, const char *name) -{ - return (struct symbol_header *) hash_table_find(table->ht, name); -} - - -struct _mesa_symbol_table_iterator * -_mesa_symbol_table_iterator_ctor(struct _mesa_symbol_table *table, - int name_space, const char *name) -{ - struct _mesa_symbol_table_iterator *iter = calloc(1, sizeof(*iter)); - struct symbol_header *const hdr = find_symbol(table, name); - - iter->name_space = name_space; - - if (hdr != NULL) { - struct symbol *sym; - - for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) { - assert(sym->hdr == hdr); - - if ((name_space == -1) || (sym->name_space == name_space)) { - iter->curr = sym; - break; - } - } - } - - return iter; -} - - -void -_mesa_symbol_table_iterator_dtor(struct _mesa_symbol_table_iterator *iter) -{ - free(iter); -} - - -void * -_mesa_symbol_table_iterator_get(struct _mesa_symbol_table_iterator *iter) -{ - return (iter->curr == NULL) ? NULL : iter->curr->data; -} - - -int -_mesa_symbol_table_iterator_next(struct _mesa_symbol_table_iterator *iter) -{ - struct symbol_header *hdr; - - if (iter->curr == NULL) { - return 0; - } - - hdr = iter->curr->hdr; - iter->curr = iter->curr->next_with_same_name; - - while (iter->curr != NULL) { - assert(iter->curr->hdr == hdr); - - if ((iter->name_space == -1) - || (iter->curr->name_space == iter->name_space)) { - return 1; - } - - iter->curr = iter->curr->next_with_same_name; - } - - return 0; -} - - -void * -_mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table, - int name_space, const char *name) -{ - struct symbol_header *const hdr = find_symbol(table, name); - - if (hdr != NULL) { - struct symbol *sym; - - - for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) { - assert(sym->hdr == hdr); - - if ((name_space == -1) || (sym->name_space == name_space)) { - return sym->data; - } - } - } - - return NULL; -} - - -int -_mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table, - int name_space, const char *name, - void *declaration) -{ - struct symbol_header *hdr; - struct symbol *sym; - - check_symbol_table(table); - - hdr = find_symbol(table, name); - - check_symbol_table(table); - - if (hdr == NULL) { - hdr = calloc(1, sizeof(*hdr)); - hdr->name = name; - - hash_table_insert(table->ht, hdr, name); - hdr->next = table->hdr; - table->hdr = hdr; - } - - check_symbol_table(table); - - sym = calloc(1, sizeof(*sym)); - sym->next_with_same_name = hdr->symbols; - sym->next_with_same_scope = table->current_scope->symbols; - sym->hdr = hdr; - sym->name_space = name_space; - sym->data = declaration; - - assert(sym->hdr == hdr); - - hdr->symbols = sym; - table->current_scope->symbols = sym; - - check_symbol_table(table); - return 0; -} - - -struct _mesa_symbol_table * -_mesa_symbol_table_ctor(void) -{ - struct _mesa_symbol_table *table = calloc(1, sizeof(*table)); - - if (table != NULL) { - table->ht = hash_table_ctor(32, hash_table_string_hash, - hash_table_string_compare); - - _mesa_symbol_table_push_scope(table); - } - - return table; -} - - -void -_mesa_symbol_table_dtor(struct _mesa_symbol_table *table) -{ - struct symbol_header *hdr; - struct symbol_header *next; - - while (table->current_scope != NULL) { - _mesa_symbol_table_pop_scope(table); - } - - for (hdr = table->hdr; hdr != NULL; hdr = next) { - next = hdr->next; - free(hdr); - } - - hash_table_dtor(table->ht); - free(table); -} diff --git a/src/mesa/shader/symbol_table.h b/src/mesa/shader/symbol_table.h deleted file mode 100644 index 0c054ef139..0000000000 --- a/src/mesa/shader/symbol_table.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright © 2008 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#ifndef MESA_SYMBOL_TABLE_H -#define MESA_SYMBOL_TABLE_H - -struct _mesa_symbol_table; -struct _mesa_symbol_table_iterator; - -extern void _mesa_symbol_table_push_scope(struct _mesa_symbol_table *table); - -extern void _mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table); - -extern int _mesa_symbol_table_add_symbol(struct _mesa_symbol_table *symtab, - int name_space, const char *name, void *declaration); - -extern void *_mesa_symbol_table_find_symbol( - struct _mesa_symbol_table *symtab, int name_space, const char *name); - -extern struct _mesa_symbol_table *_mesa_symbol_table_ctor(void); - -extern void _mesa_symbol_table_dtor(struct _mesa_symbol_table *); - -extern struct _mesa_symbol_table_iterator *_mesa_symbol_table_iterator_ctor( - struct _mesa_symbol_table *table, int name_space, const char *name); - -extern void _mesa_symbol_table_iterator_dtor( - struct _mesa_symbol_table_iterator *); - -extern void *_mesa_symbol_table_iterator_get( - struct _mesa_symbol_table_iterator *iter); - -extern int _mesa_symbol_table_iterator_next( - struct _mesa_symbol_table_iterator *iter); - -#endif /* MESA_SYMBOL_TABLE_H */ diff --git a/src/mesa/slang/library/Makefile b/src/mesa/slang/library/Makefile index 75c91e7db7..5a76774208 100644 --- a/src/mesa/slang/library/Makefile +++ b/src/mesa/slang/library/Makefile @@ -1,4 +1,4 @@ -# src/mesa/shader/slang/library/Makefile +# src/mesa/slang/library/Makefile TOP = ../../../.. diff --git a/src/mesa/slang/library/SConscript b/src/mesa/slang/library/SConscript index 0b25467a4e..792a7953d3 100644 --- a/src/mesa/slang/library/SConscript +++ b/src/mesa/slang/library/SConscript @@ -28,25 +28,25 @@ env['BUILDERS']['bld_vert'] = bld_vert # Generate GLSL builtin library binaries env.bld_frag( - '#src/mesa/shader/slang/library/slang_core_gc.h', - '#src/mesa/shader/slang/library/slang_core.gc') + '#src/mesa/slang/library/slang_core_gc.h', + '#src/mesa/slang/library/slang_core.gc') env.bld_frag( - '#src/mesa/shader/slang/library/slang_common_builtin_gc.h', - '#src/mesa/shader/slang/library/slang_common_builtin.gc') + '#src/mesa/slang/library/slang_common_builtin_gc.h', + '#src/mesa/slang/library/slang_common_builtin.gc') env.bld_frag( - '#src/mesa/shader/slang/library/slang_fragment_builtin_gc.h', - '#src/mesa/shader/slang/library/slang_fragment_builtin.gc') + '#src/mesa/slang/library/slang_fragment_builtin_gc.h', + '#src/mesa/slang/library/slang_fragment_builtin.gc') env.bld_vert( - '#src/mesa/shader/slang/library/slang_vertex_builtin_gc.h', - '#src/mesa/shader/slang/library/slang_vertex_builtin.gc') + '#src/mesa/slang/library/slang_vertex_builtin_gc.h', + '#src/mesa/slang/library/slang_vertex_builtin.gc') # Generate GLSL 1.20 builtin library binaries env.bld_frag( - '#src/mesa/shader/slang/library/slang_120_core_gc.h', - '#src/mesa/shader/slang/library/slang_120_core.gc') + '#src/mesa/slang/library/slang_120_core_gc.h', + '#src/mesa/slang/library/slang_120_core.gc') env.bld_frag( - '#src/mesa/shader/slang/library/slang_builtin_120_common_gc.h', - '#src/mesa/shader/slang/library/slang_builtin_120_common.gc') + '#src/mesa/slang/library/slang_builtin_120_common_gc.h', + '#src/mesa/slang/library/slang_builtin_120_common.gc') env.bld_frag( - '#src/mesa/shader/slang/library/slang_builtin_120_fragment_gc.h', - '#src/mesa/shader/slang/library/slang_builtin_120_fragment.gc') + '#src/mesa/slang/library/slang_builtin_120_fragment_gc.h', + '#src/mesa/slang/library/slang_builtin_120_fragment.gc') diff --git a/src/mesa/slang/slang_builtin.c b/src/mesa/slang/slang_builtin.c index edb6052cb5..610e793c1d 100644 --- a/src/mesa/slang/slang_builtin.c +++ b/src/mesa/slang/slang_builtin.c @@ -31,10 +31,10 @@ #include "main/imports.h" #include "main/mtypes.h" -#include "shader/program.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" -#include "shader/prog_statevars.h" +#include "program/program.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" #include "slang/slang_ir.h" #include "slang/slang_builtin.h" diff --git a/src/mesa/slang/slang_builtin.h b/src/mesa/slang/slang_builtin.h index c3021ca33c..b04b584041 100644 --- a/src/mesa/slang/slang_builtin.h +++ b/src/mesa/slang/slang_builtin.h @@ -26,7 +26,7 @@ #ifndef SLANG_BUILTIN_H #define SLANG_BUILTIN_H -#include "shader/prog_parameter.h" +#include "program/prog_parameter.h" #include "slang_utility.h" #include "slang_ir.h" diff --git a/src/mesa/slang/slang_codegen.c b/src/mesa/slang/slang_codegen.c index 0504d47765..18a0932e4f 100644 --- a/src/mesa/slang/slang_codegen.c +++ b/src/mesa/slang/slang_codegen.c @@ -40,11 +40,11 @@ #include "main/imports.h" #include "main/macros.h" #include "main/mtypes.h" -#include "shader/program.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" -#include "shader/prog_statevars.h" +#include "program/program.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" +#include "program/prog_statevars.h" #include "slang_typeinfo.h" #include "slang_builtin.h" #include "slang_codegen.h" diff --git a/src/mesa/slang/slang_compile.c b/src/mesa/slang/slang_compile.c index b6b1f3c990..af672599ed 100644 --- a/src/mesa/slang/slang_compile.c +++ b/src/mesa/slang/slang_compile.c @@ -30,11 +30,11 @@ #include "main/imports.h" #include "main/context.h" -#include "shader/program.h" -#include "shader/programopt.h" -#include "shader/prog_optimize.h" -#include "shader/prog_print.h" -#include "shader/prog_parameter.h" +#include "program/program.h" +#include "program/programopt.h" +#include "program/prog_optimize.h" +#include "program/prog_print.h" +#include "program/prog_parameter.h" #include "../../glsl/pp/sl_pp_public.h" #include "../../glsl/cl/sl_cl_parse.h" #include "slang_codegen.h" diff --git a/src/mesa/slang/slang_emit.c b/src/mesa/slang/slang_emit.c index 4d4c611dfe..9997d5b0a0 100644 --- a/src/mesa/slang/slang_emit.c +++ b/src/mesa/slang/slang_emit.c @@ -38,10 +38,10 @@ #include "main/imports.h" #include "main/context.h" -#include "shader/program.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" +#include "program/program.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" #include "slang_builtin.h" #include "slang_emit.h" #include "slang_mem.h" diff --git a/src/mesa/slang/slang_ir.c b/src/mesa/slang/slang_ir.c index c223004b22..e9aef9878e 100644 --- a/src/mesa/slang/slang_ir.c +++ b/src/mesa/slang/slang_ir.c @@ -27,8 +27,8 @@ #include "main/context.h" #include "slang_ir.h" #include "slang_mem.h" -#include "shader/prog_instruction.h" -#include "shader/prog_print.h" +#include "program/prog_instruction.h" +#include "program/prog_print.h" static const slang_ir_info IrInfo[] = { diff --git a/src/mesa/slang/slang_label.h b/src/mesa/slang/slang_label.h index 87068ae7a7..4d04df18d2 100644 --- a/src/mesa/slang/slang_label.h +++ b/src/mesa/slang/slang_label.h @@ -3,7 +3,7 @@ #include "main/imports.h" #include "main/mtypes.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" struct slang_label_ diff --git a/src/mesa/slang/slang_link.c b/src/mesa/slang/slang_link.c index 56d42ca0a7..2f47cba1ce 100644 --- a/src/mesa/slang/slang_link.c +++ b/src/mesa/slang/slang_link.c @@ -35,12 +35,12 @@ #include "main/shaderapi.h" #include "main/shaderobj.h" #include "main/uniforms.h" -#include "shader/program.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" -#include "shader/prog_statevars.h" -#include "shader/prog_uniform.h" +#include "program/program.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" +#include "program/prog_statevars.h" +#include "program/prog_uniform.h" #include "slang_builtin.h" #include "slang_link.h" diff --git a/src/mesa/slang/slang_typeinfo.c b/src/mesa/slang/slang_typeinfo.c index 0f96768b02..d039a12e98 100644 --- a/src/mesa/slang/slang_typeinfo.c +++ b/src/mesa/slang/slang_typeinfo.c @@ -29,7 +29,7 @@ */ #include "main/imports.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" #include "slang_typeinfo.h" #include "slang_compile.h" #include "slang_log.h" diff --git a/src/mesa/slang/slang_vartable.c b/src/mesa/slang/slang_vartable.c index e07e3a226a..8371631578 100644 --- a/src/mesa/slang/slang_vartable.c +++ b/src/mesa/slang/slang_vartable.c @@ -1,7 +1,7 @@ #include "main/imports.h" -#include "shader/program.h" -#include "shader/prog_print.h" +#include "program/program.h" +#include "program/prog_print.h" #include "slang_compile.h" #include "slang_compile_variable.h" #include "slang_emit.h" diff --git a/src/mesa/sources.mak b/src/mesa/sources.mak index 236baf5e2f..f01b60c4fc 100644 --- a/src/mesa/sources.mak +++ b/src/mesa/sources.mak @@ -228,27 +228,27 @@ STATETRACKER_SOURCES = \ state_tracker/st_program.c \ state_tracker/st_texture.c -SHADER_SOURCES = \ - shader/arbprogparse.c \ - shader/hash_table.c \ - shader/lex.yy.c \ - shader/nvfragparse.c \ - shader/nvvertparse.c \ - shader/program.c \ - shader/program_parse.tab.c \ - shader/program_parse_extra.c \ - shader/prog_cache.c \ - shader/prog_execute.c \ - shader/prog_instruction.c \ - shader/prog_noise.c \ - shader/prog_optimize.c \ - shader/prog_parameter.c \ - shader/prog_parameter_layout.c \ - shader/prog_print.c \ - shader/prog_statevars.c \ - shader/prog_uniform.c \ - shader/programopt.c \ - shader/symbol_table.c +PROGRAM_SOURCES = \ + program/arbprogparse.c \ + program/hash_table.c \ + program/lex.yy.c \ + program/nvfragparse.c \ + program/nvvertparse.c \ + program/program.c \ + program/program_parse.tab.c \ + program/program_parse_extra.c \ + program/prog_cache.c \ + program/prog_execute.c \ + program/prog_instruction.c \ + program/prog_noise.c \ + program/prog_optimize.c \ + program/prog_parameter.c \ + program/prog_parameter_layout.c \ + program/prog_print.c \ + program/prog_statevars.c \ + program/prog_uniform.c \ + program/programopt.c \ + program/symbol_table.c SLANG_SOURCES = \ slang/slang_builtin.c \ @@ -320,7 +320,7 @@ MESA_SOURCES = \ $(MATH_XFORM_SOURCES) \ $(VBO_SOURCES) \ $(TNL_SOURCES) \ - $(SHADER_SOURCES) \ + $(PROGRAM_SOURCES) \ $(SWRAST_SOURCES) \ $(SWRAST_SETUP_SOURCES) \ $(COMMON_DRIVER_SOURCES)\ @@ -333,7 +333,7 @@ MESA_GALLIUM_SOURCES = \ $(MATH_SOURCES) \ $(VBO_SOURCES) \ $(STATETRACKER_SOURCES) \ - $(SHADER_SOURCES) \ + $(PROGRAM_SOURCES) \ ppc/common_ppc.c \ x86/common_x86.c \ $(SLANG_SOURCES) diff --git a/src/mesa/state_tracker/st_atom_constbuf.c b/src/mesa/state_tracker/st_atom_constbuf.c index 28439103b2..38fadb2016 100644 --- a/src/mesa/state_tracker/st_atom_constbuf.c +++ b/src/mesa/state_tracker/st_atom_constbuf.c @@ -32,8 +32,8 @@ */ #include "main/imports.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" #include "pipe/p_context.h" #include "pipe/p_defines.h" diff --git a/src/mesa/state_tracker/st_atom_pixeltransfer.c b/src/mesa/state_tracker/st_atom_pixeltransfer.c index b8644faaf8..b88c74fa03 100644 --- a/src/mesa/state_tracker/st_atom_pixeltransfer.c +++ b/src/mesa/state_tracker/st_atom_pixeltransfer.c @@ -36,10 +36,10 @@ #include "main/imports.h" #include "main/image.h" #include "main/macros.h" -#include "shader/program.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" +#include "program/program.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" #include "st_context.h" #include "st_format.h" diff --git a/src/mesa/state_tracker/st_atom_shader.c b/src/mesa/state_tracker/st_atom_shader.c index ad151edf3b..dcaad83a3c 100644 --- a/src/mesa/state_tracker/st_atom_shader.c +++ b/src/mesa/state_tracker/st_atom_shader.c @@ -37,7 +37,7 @@ #include "main/imports.h" #include "main/mtypes.h" -#include "shader/program.h" +#include "program/program.h" #include "pipe/p_context.h" #include "pipe/p_shader_tokens.h" diff --git a/src/mesa/state_tracker/st_atom_texture.c b/src/mesa/state_tracker/st_atom_texture.c index 895681cb23..5a650b305d 100644 --- a/src/mesa/state_tracker/st_atom_texture.c +++ b/src/mesa/state_tracker/st_atom_texture.c @@ -33,7 +33,7 @@ #include "main/macros.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" #include "st_context.h" #include "st_atom.h" diff --git a/src/mesa/state_tracker/st_cb_bitmap.c b/src/mesa/state_tracker/st_cb_bitmap.c index 5aca1105ee..ba600ccef6 100644 --- a/src/mesa/state_tracker/st_cb_bitmap.c +++ b/src/mesa/state_tracker/st_cb_bitmap.c @@ -34,8 +34,8 @@ #include "main/image.h" #include "main/bufferobj.h" #include "main/macros.h" -#include "shader/program.h" -#include "shader/prog_print.h" +#include "program/program.h" +#include "program/prog_print.h" #include "st_context.h" #include "st_atom.h" @@ -49,7 +49,7 @@ #include "util/u_inlines.h" #include "util/u_draw_quad.h" #include "util/u_simple_shaders.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" #include "cso_cache/cso_context.h" diff --git a/src/mesa/state_tracker/st_cb_clear.c b/src/mesa/state_tracker/st_cb_clear.c index b15792504a..ea2414c4a0 100644 --- a/src/mesa/state_tracker/st_cb_clear.c +++ b/src/mesa/state_tracker/st_cb_clear.c @@ -36,7 +36,7 @@ #include "main/glheader.h" #include "main/formats.h" #include "main/macros.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" #include "st_context.h" #include "st_atom.h" #include "st_cb_accum.h" diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c index f74d8cd42d..69a3dd45e8 100644 --- a/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/src/mesa/state_tracker/st_cb_drawpixels.c @@ -36,8 +36,8 @@ #include "main/macros.h" #include "main/texformat.h" #include "main/texstore.h" -#include "shader/program.h" -#include "shader/prog_print.h" +#include "program/program.h" +#include "program/prog_print.h" #include "st_debug.h" #include "st_context.h" @@ -58,7 +58,7 @@ #include "util/u_draw_quad.h" #include "util/u_format.h" #include "util/u_math.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" #include "cso_cache/cso_context.h" diff --git a/src/mesa/state_tracker/st_cb_drawtex.c b/src/mesa/state_tracker/st_cb_drawtex.c index 3d99d6c8a1..b191a7f890 100644 --- a/src/mesa/state_tracker/st_cb_drawtex.c +++ b/src/mesa/state_tracker/st_cb_drawtex.c @@ -16,8 +16,8 @@ #include "main/image.h" #include "main/bufferobj.h" #include "main/macros.h" -#include "shader/program.h" -#include "shader/prog_print.h" +#include "program/program.h" +#include "program/prog_print.h" #include "st_context.h" #include "st_atom.h" diff --git a/src/mesa/state_tracker/st_cb_program.c b/src/mesa/state_tracker/st_cb_program.c index d0c9772e8e..c39ae3e4c4 100644 --- a/src/mesa/state_tracker/st_cb_program.c +++ b/src/mesa/state_tracker/st_cb_program.c @@ -35,9 +35,9 @@ #include "main/enums.h" #include "main/shaderapi.h" #include "main/shaderobj.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" -#include "shader/program.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "program/program.h" #include "cso_cache/cso_context.h" #include "draw/draw_context.h" diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h index efff55a905..4edfb2ae85 100644 --- a/src/mesa/state_tracker/st_context.h +++ b/src/mesa/state_tracker/st_context.h @@ -29,7 +29,7 @@ #define ST_CONTEXT_H #include "main/mtypes.h" -#include "shader/prog_cache.h" +#include "program/prog_cache.h" #include "pipe/p_state.h" #include "state_tracker/st_api.h" diff --git a/src/mesa/state_tracker/st_debug.c b/src/mesa/state_tracker/st_debug.c index 0b3768341e..ebf6ec6e7e 100644 --- a/src/mesa/state_tracker/st_debug.c +++ b/src/mesa/state_tracker/st_debug.c @@ -27,7 +27,7 @@ #include "main/context.h" -#include "shader/prog_print.h" +#include "program/prog_print.h" #include "pipe/p_state.h" #include "pipe/p_shader_tokens.h" diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c index eb2e5b2bbf..eed8e2aa5d 100644 --- a/src/mesa/state_tracker/st_draw.c +++ b/src/mesa/state_tracker/st_draw.c @@ -43,7 +43,7 @@ #include "main/imports.h" #include "main/image.h" #include "main/macros.h" -#include "shader/prog_uniform.h" +#include "program/prog_uniform.h" #include "vbo/vbo.h" diff --git a/src/mesa/state_tracker/st_mesa_to_tgsi.c b/src/mesa/state_tracker/st_mesa_to_tgsi.c index 35016d80e6..49b7b5d1c1 100644 --- a/src/mesa/state_tracker/st_mesa_to_tgsi.c +++ b/src/mesa/state_tracker/st_mesa_to_tgsi.c @@ -38,8 +38,8 @@ #include "tgsi/tgsi_ureg.h" #include "st_mesa_to_tgsi.h" #include "st_context.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" #include "util/u_debug.h" #include "util/u_math.h" #include "util/u_memory.h" diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c index 3c865028a7..3ea325bb42 100644 --- a/src/mesa/state_tracker/st_program.c +++ b/src/mesa/state_tracker/st_program.c @@ -33,8 +33,8 @@ #include "main/imports.h" #include "main/mtypes.h" -#include "shader/prog_print.h" -#include "shader/programopt.h" +#include "program/prog_print.h" +#include "program/programopt.h" #include "pipe/p_context.h" #include "pipe/p_defines.h" diff --git a/src/mesa/state_tracker/st_program.h b/src/mesa/state_tracker/st_program.h index 1b3f75ca27..d4b7151e92 100644 --- a/src/mesa/state_tracker/st_program.h +++ b/src/mesa/state_tracker/st_program.h @@ -35,7 +35,7 @@ #define ST_PROGRAM_H #include "main/mtypes.h" -#include "shader/program.h" +#include "program/program.h" #include "pipe/p_shader_tokens.h" diff --git a/src/mesa/swrast/s_context.c b/src/mesa/swrast/s_context.c index 751966348b..6d2d17c61d 100644 --- a/src/mesa/swrast/s_context.c +++ b/src/mesa/swrast/s_context.c @@ -32,8 +32,8 @@ #include "main/colormac.h" #include "main/mtypes.h" #include "main/teximage.h" -#include "shader/prog_parameter.h" -#include "shader/prog_statevars.h" +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" #include "swrast.h" #include "s_blend.h" #include "s_context.h" diff --git a/src/mesa/swrast/s_context.h b/src/mesa/swrast/s_context.h index 9059f9b5ec..c9755e6da1 100644 --- a/src/mesa/swrast/s_context.h +++ b/src/mesa/swrast/s_context.h @@ -44,7 +44,7 @@ #define S_CONTEXT_H #include "main/mtypes.h" -#include "shader/prog_execute.h" +#include "program/prog_execute.h" #include "swrast.h" #include "s_span.h" diff --git a/src/mesa/swrast/s_fragprog.c b/src/mesa/swrast/s_fragprog.c index 7c1de62e87..413f136cd5 100644 --- a/src/mesa/swrast/s_fragprog.c +++ b/src/mesa/swrast/s_fragprog.c @@ -25,7 +25,7 @@ #include "main/glheader.h" #include "main/colormac.h" #include "main/context.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" #include "s_fragprog.h" #include "s_span.h" diff --git a/src/mesa/swrast/s_texcombine.c b/src/mesa/swrast/s_texcombine.c index f322663ad4..2ac0aaa246 100644 --- a/src/mesa/swrast/s_texcombine.c +++ b/src/mesa/swrast/s_texcombine.c @@ -29,7 +29,7 @@ #include "main/colormac.h" #include "main/image.h" #include "main/imports.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" #include "s_context.h" #include "s_texcombine.h" diff --git a/src/mesa/swrast/s_triangle.c b/src/mesa/swrast/s_triangle.c index 812dddf15c..d1b369bcdf 100644 --- a/src/mesa/swrast/s_triangle.c +++ b/src/mesa/swrast/s_triangle.c @@ -35,7 +35,7 @@ #include "main/imports.h" #include "main/macros.h" #include "main/texformat.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" #include "s_aatriangle.h" #include "s_context.h" diff --git a/src/mesa/tnl/t_vb_program.c b/src/mesa/tnl/t_vb_program.c index 0137e52fc4..614c67d05e 100644 --- a/src/mesa/tnl/t_vb_program.c +++ b/src/mesa/tnl/t_vb_program.c @@ -36,9 +36,9 @@ #include "main/context.h" #include "main/macros.h" #include "main/imports.h" -#include "shader/prog_instruction.h" -#include "shader/prog_statevars.h" -#include "shader/prog_execute.h" +#include "program/prog_instruction.h" +#include "program/prog_statevars.h" +#include "program/prog_execute.h" #include "swrast/s_context.h" #include "tnl/tnl.h" -- cgit v1.2.3