From 0bf07d32cbd460220c67d726900772cf3692746d Mon Sep 17 00:00:00 2001 From: marha Date: Tue, 1 Feb 2011 10:02:38 +0000 Subject: libX11 libXinerama mesa git update 1 Feb 2011 --- mesalib/src/mesa/Makefile | 376 ++++----- mesalib/src/mesa/SConscript | 784 +++++++++-------- mesalib/src/mesa/main/arrayobj.c | 1156 +++++++++++++------------- mesalib/src/mesa/main/shaderapi.c | 8 +- mesalib/src/mesa/main/shaderobj.c | 826 +++++++++--------- mesalib/src/mesa/program/ir_to_mesa.cpp | 42 +- mesalib/src/mesa/program/register_allocate.c | 913 ++++++++++---------- mesalib/src/mesa/program/sampler.cpp | 278 +++---- 8 files changed, 2188 insertions(+), 2195 deletions(-) (limited to 'mesalib/src/mesa') diff --git a/mesalib/src/mesa/Makefile b/mesalib/src/mesa/Makefile index c9a5eaf5b..a6025e990 100644 --- a/mesalib/src/mesa/Makefile +++ b/mesalib/src/mesa/Makefile @@ -1,188 +1,188 @@ -# src/mesa/Makefile - -TOP = ../.. -include $(TOP)/configs/current - -MESA_LIBS := libmesa.a libmesagallium.a -DEPENDS := depend - -MESA_OBJ_DIR := . - - -include sources.mak - -# adjust object dirs -MESA_OBJECTS := $(addprefix $(MESA_OBJ_DIR)/, $(MESA_OBJECTS)) -MESA_GALLIUM_OBJECTS := $(addprefix $(MESA_OBJ_DIR)/, $(MESA_GALLIUM_OBJECTS)) - -# define preprocessor flags -MESA_CPPFLAGS := $(API_DEFINES) $(DEFINES) - -# append include dirs -MESA_CPPFLAGS += $(INCLUDE_DIRS) $(TALLOC_CFLAGS) - -# tidy compiler flags -CFLAGS := $(filter-out $(DEFINES), $(CFLAGS)) -CXXFLAGS := $(filter-out $(DEFINES), $(CXXFLAGS)) - -# LLVM is needed for the state tracker -MESA_CFLAGS := $(LLVM_CFLAGS) - -define mesa-cc-c - @mkdir -p $(dir $@) - $(CC) -c -o $@ $< $($(1)_CPPFLAGS) $($(1)_CFLAGS) $(CFLAGS) -endef - -define mesa-cxx-c - @mkdir -p $(dir $@) - $(CXX) -c -o $@ $< $($(1)_CPPFLAGS) $($(1)_CFLAGS) $(CXXFLAGS) -endef - -$(MESA_OBJ_DIR)/%.o: %.c - $(call mesa-cc-c,MESA) - -$(MESA_OBJ_DIR)/%.o: %.cpp - $(call mesa-cxx-c,MESA) - -$(MESA_OBJ_DIR)/%.o: %.S - $(call mesa-cc-c,MESA) - -# Default: build dependencies, then asm_subdirs, GLSL built-in lib, -# then convenience libs (.a) and finally the device drivers: -default: $(DEPENDS) asm_subdirs $(MESA_LIBS) driver_subdirs - -main/api_exec_es1.c: main/APIspec.xml main/es_generator.py main/APIspecutil.py main/APIspec.py - $(PYTHON2) $(PYTHON_FLAGS) main/es_generator.py -S main/APIspec.xml -V GLES1.1 > $@ - -main/api_exec_es2.c: main/APIspec.xml main/es_generator.py main/APIspecutil.py main/APIspec.py - $(PYTHON2) $(PYTHON_FLAGS) main/es_generator.py -S main/APIspec.xml -V GLES2.0 > $@ - -###################################################################### -# Helper libraries used by many drivers: - -# Make archive of core mesa object files -libmesa.a: $(MESA_OBJECTS) $(GLSL_LIBS) - @ $(MKLIB) -o mesa -static $(MESA_OBJECTS) $(GLSL_LIBS) - -# Make archive of subset of core mesa object files for gallium -libmesagallium.a: $(MESA_GALLIUM_OBJECTS) $(GLSL_LIBS) - @ $(MKLIB) -o mesagallium -static $(MESA_GALLIUM_OBJECTS) $(GLSL_LIBS) - -###################################################################### -# Device drivers -driver_subdirs: $(MESA_LIBS) - @ (cd drivers && $(MAKE)) - - -###################################################################### -# Assembly subdirs -asm_subdirs: - @ if echo "$(ASM_FLAGS)" | grep -q USE_X86_ASM ; then \ - (cd x86 && $(MAKE)) || exit 1 ; \ - fi - @ if echo "$(ASM_FLAGS)" | grep -q USE_X86_64_ASM ; then \ - (cd x86 && $(MAKE)) || exit 1 ; \ - (cd x86-64 && $(MAKE)) || exit 1 ; \ - fi - - -###################################################################### -# Dependency generation - -depend: $(ALL_SOURCES) - @ echo "running $(MKDEP)" - @ touch depend - @$(MKDEP) $(MKDEP_OPTIONS) -p$(MESA_OBJ_DIR)/ $(MESA_CPPFLAGS) \ - $(ALL_SOURCES) > /dev/null 2>/dev/null - -###################################################################### -# Installation rules - -# this isn't fleshed out yet but is probably the way to go in the future -new_install: - (cd drivers && $(MAKE) install) - - -# XXX replace this with new_install above someday -install: default - @for driver in $(DRIVER_DIRS) ; do \ - case "$$driver" in \ - osmesa) if [ "$(DRIVER_DIRS)" = osmesa ]; then \ - $(MAKE) install-headers install-osmesa || exit 1 ; \ - else \ - $(MAKE) install-osmesa || exit 1 ; \ - fi ;; \ - dri) $(MAKE) install-libgl install-dri || exit 1 ;; \ - *) $(MAKE) install-libgl || exit 1 ;; \ - esac ; \ - done - -pcedit = \ - -e 's,@INSTALL_DIR@,$(INSTALL_DIR),' \ - -e 's,@INSTALL_LIB_DIR@,$(INSTALL_LIB_DIR),' \ - -e 's,@INSTALL_INC_DIR@,$(INSTALL_INC_DIR),' \ - -e 's,@VERSION@,$(MESA_MAJOR).$(MESA_MINOR).$(MESA_TINY),' \ - - -gl_pcedit = sed \ - $(pcedit) \ - -e 's,@GL_PC_REQ_PRIV@,$(GL_PC_REQ_PRIV),' \ - -e 's,@GL_PC_LIB_PRIV@,$(GL_PC_LIB_PRIV),' \ - -e 's,@GL_PC_CFLAGS@,$(GL_PC_CFLAGS),' \ - -e 's,@GLX_TLS@,$(GLX_TLS),' \ - -e 's,@GL_LIB@,$(GL_LIB),' - -gl.pc: gl.pc.in - $(gl_pcedit) $< > $@ - -osmesa_pcedit = sed \ - $(pcedit) \ - -e 's,@OSMESA_LIB@,$(OSMESA_LIB),' \ - -e 's,@OSMESA_PC_REQ@,$(OSMESA_PC_REQ),' \ - -e 's,@OSMESA_PC_LIB_PRIV@,$(OSMESA_PC_LIB_PRIV),' - -osmesa.pc: osmesa.pc.in - $(osmesa_pcedit) $< > $@ - -install-headers: - $(INSTALL) -d $(DESTDIR)$(INSTALL_INC_DIR)/GL - $(INSTALL) -m 644 $(TOP)/include/GL/*.h \ - $(DESTDIR)$(INSTALL_INC_DIR)/GL - -install-libgl: default gl.pc install-headers - $(INSTALL) -d $(DESTDIR)$(INSTALL_LIB_DIR) - $(INSTALL) -d $(DESTDIR)$(INSTALL_LIB_DIR)/pkgconfig - $(MINSTALL) $(TOP)/$(LIB_DIR)/$(GL_LIB_GLOB) \ - $(DESTDIR)$(INSTALL_LIB_DIR) - $(INSTALL) -m 644 gl.pc $(DESTDIR)$(INSTALL_LIB_DIR)/pkgconfig - -install-osmesa: default osmesa.pc - $(INSTALL) -d $(DESTDIR)$(INSTALL_LIB_DIR) - $(INSTALL) -d $(DESTDIR)$(INSTALL_LIB_DIR)/pkgconfig - $(MINSTALL) $(TOP)/$(LIB_DIR)/$(OSMESA_LIB_GLOB) \ - $(DESTDIR)$(INSTALL_LIB_DIR) - $(INSTALL) -m 644 osmesa.pc $(DESTDIR)$(INSTALL_LIB_DIR)/pkgconfig - -install-dri: default - cd drivers/dri && $(MAKE) install - - - -# Emacs tags -tags: - etags `find . -name \*.[ch]` $(TOP)/include/GL/*.h - -clean: - -rm -f */*.o - -rm -f */*/*.o - -rm -f depend depend.bak libmesa.a libmesagallium.a - -rm -f drivers/*/*.o - -rm -f *.pc - -@cd drivers/dri && $(MAKE) clean - -@cd drivers/x11 && $(MAKE) clean - -@cd drivers/osmesa && $(MAKE) clean - -@cd x86 && $(MAKE) clean - -@cd x86-64 && $(MAKE) clean - - --include $(DEPENDS) +# src/mesa/Makefile + +TOP = ../.. +include $(TOP)/configs/current + +MESA_LIBS := libmesa.a libmesagallium.a +DEPENDS := depend + +MESA_OBJ_DIR := . + + +include sources.mak + +# adjust object dirs +MESA_OBJECTS := $(addprefix $(MESA_OBJ_DIR)/, $(MESA_OBJECTS)) +MESA_GALLIUM_OBJECTS := $(addprefix $(MESA_OBJ_DIR)/, $(MESA_GALLIUM_OBJECTS)) + +# define preprocessor flags +MESA_CPPFLAGS := $(API_DEFINES) $(DEFINES) + +# append include dirs +MESA_CPPFLAGS += $(INCLUDE_DIRS) + +# tidy compiler flags +CFLAGS := $(filter-out $(DEFINES), $(CFLAGS)) +CXXFLAGS := $(filter-out $(DEFINES), $(CXXFLAGS)) + +# LLVM is needed for the state tracker +MESA_CFLAGS := $(LLVM_CFLAGS) + +define mesa-cc-c + @mkdir -p $(dir $@) + $(CC) -c -o $@ $< $($(1)_CPPFLAGS) $($(1)_CFLAGS) $(CFLAGS) +endef + +define mesa-cxx-c + @mkdir -p $(dir $@) + $(CXX) -c -o $@ $< $($(1)_CPPFLAGS) $($(1)_CFLAGS) $(CXXFLAGS) +endef + +$(MESA_OBJ_DIR)/%.o: %.c + $(call mesa-cc-c,MESA) + +$(MESA_OBJ_DIR)/%.o: %.cpp + $(call mesa-cxx-c,MESA) + +$(MESA_OBJ_DIR)/%.o: %.S + $(call mesa-cc-c,MESA) + +# Default: build dependencies, then asm_subdirs, GLSL built-in lib, +# then convenience libs (.a) and finally the device drivers: +default: $(DEPENDS) asm_subdirs $(MESA_LIBS) driver_subdirs + +main/api_exec_es1.c: main/APIspec.xml main/es_generator.py main/APIspecutil.py main/APIspec.py + $(PYTHON2) $(PYTHON_FLAGS) main/es_generator.py -S main/APIspec.xml -V GLES1.1 > $@ + +main/api_exec_es2.c: main/APIspec.xml main/es_generator.py main/APIspecutil.py main/APIspec.py + $(PYTHON2) $(PYTHON_FLAGS) main/es_generator.py -S main/APIspec.xml -V GLES2.0 > $@ + +###################################################################### +# Helper libraries used by many drivers: + +# Make archive of core mesa object files +libmesa.a: $(MESA_OBJECTS) $(GLSL_LIBS) + @ $(MKLIB) -o mesa -static $(MESA_OBJECTS) $(GLSL_LIBS) + +# Make archive of subset of core mesa object files for gallium +libmesagallium.a: $(MESA_GALLIUM_OBJECTS) $(GLSL_LIBS) + @ $(MKLIB) -o mesagallium -static $(MESA_GALLIUM_OBJECTS) $(GLSL_LIBS) + +###################################################################### +# Device drivers +driver_subdirs: $(MESA_LIBS) + @ (cd drivers && $(MAKE)) + + +###################################################################### +# Assembly subdirs +asm_subdirs: + @ if echo "$(ASM_FLAGS)" | grep -q USE_X86_ASM ; then \ + (cd x86 && $(MAKE)) || exit 1 ; \ + fi + @ if echo "$(ASM_FLAGS)" | grep -q USE_X86_64_ASM ; then \ + (cd x86 && $(MAKE)) || exit 1 ; \ + (cd x86-64 && $(MAKE)) || exit 1 ; \ + fi + + +###################################################################### +# Dependency generation + +depend: $(ALL_SOURCES) + @ echo "running $(MKDEP)" + @ touch depend + @$(MKDEP) $(MKDEP_OPTIONS) -p$(MESA_OBJ_DIR)/ $(MESA_CPPFLAGS) \ + $(ALL_SOURCES) > /dev/null 2>/dev/null + +###################################################################### +# Installation rules + +# this isn't fleshed out yet but is probably the way to go in the future +new_install: + (cd drivers && $(MAKE) install) + + +# XXX replace this with new_install above someday +install: default + @for driver in $(DRIVER_DIRS) ; do \ + case "$$driver" in \ + osmesa) if [ "$(DRIVER_DIRS)" = osmesa ]; then \ + $(MAKE) install-headers install-osmesa || exit 1 ; \ + else \ + $(MAKE) install-osmesa || exit 1 ; \ + fi ;; \ + dri) $(MAKE) install-libgl install-dri || exit 1 ;; \ + *) $(MAKE) install-libgl || exit 1 ;; \ + esac ; \ + done + +pcedit = \ + -e 's,@INSTALL_DIR@,$(INSTALL_DIR),' \ + -e 's,@INSTALL_LIB_DIR@,$(INSTALL_LIB_DIR),' \ + -e 's,@INSTALL_INC_DIR@,$(INSTALL_INC_DIR),' \ + -e 's,@VERSION@,$(MESA_MAJOR).$(MESA_MINOR).$(MESA_TINY),' \ + + +gl_pcedit = sed \ + $(pcedit) \ + -e 's,@GL_PC_REQ_PRIV@,$(GL_PC_REQ_PRIV),' \ + -e 's,@GL_PC_LIB_PRIV@,$(GL_PC_LIB_PRIV),' \ + -e 's,@GL_PC_CFLAGS@,$(GL_PC_CFLAGS),' \ + -e 's,@GLX_TLS@,$(GLX_TLS),' \ + -e 's,@GL_LIB@,$(GL_LIB),' + +gl.pc: gl.pc.in + $(gl_pcedit) $< > $@ + +osmesa_pcedit = sed \ + $(pcedit) \ + -e 's,@OSMESA_LIB@,$(OSMESA_LIB),' \ + -e 's,@OSMESA_PC_REQ@,$(OSMESA_PC_REQ),' \ + -e 's,@OSMESA_PC_LIB_PRIV@,$(OSMESA_PC_LIB_PRIV),' + +osmesa.pc: osmesa.pc.in + $(osmesa_pcedit) $< > $@ + +install-headers: + $(INSTALL) -d $(DESTDIR)$(INSTALL_INC_DIR)/GL + $(INSTALL) -m 644 $(TOP)/include/GL/*.h \ + $(DESTDIR)$(INSTALL_INC_DIR)/GL + +install-libgl: default gl.pc install-headers + $(INSTALL) -d $(DESTDIR)$(INSTALL_LIB_DIR) + $(INSTALL) -d $(DESTDIR)$(INSTALL_LIB_DIR)/pkgconfig + $(MINSTALL) $(TOP)/$(LIB_DIR)/$(GL_LIB_GLOB) \ + $(DESTDIR)$(INSTALL_LIB_DIR) + $(INSTALL) -m 644 gl.pc $(DESTDIR)$(INSTALL_LIB_DIR)/pkgconfig + +install-osmesa: default osmesa.pc + $(INSTALL) -d $(DESTDIR)$(INSTALL_LIB_DIR) + $(INSTALL) -d $(DESTDIR)$(INSTALL_LIB_DIR)/pkgconfig + $(MINSTALL) $(TOP)/$(LIB_DIR)/$(OSMESA_LIB_GLOB) \ + $(DESTDIR)$(INSTALL_LIB_DIR) + $(INSTALL) -m 644 osmesa.pc $(DESTDIR)$(INSTALL_LIB_DIR)/pkgconfig + +install-dri: default + cd drivers/dri && $(MAKE) install + + + +# Emacs tags +tags: + etags `find . -name \*.[ch]` $(TOP)/include/GL/*.h + +clean: + -rm -f */*.o + -rm -f */*/*.o + -rm -f depend depend.bak libmesa.a libmesagallium.a + -rm -f drivers/*/*.o + -rm -f *.pc + -@cd drivers/dri && $(MAKE) clean + -@cd drivers/x11 && $(MAKE) clean + -@cd drivers/osmesa && $(MAKE) clean + -@cd x86 && $(MAKE) clean + -@cd x86-64 && $(MAKE) clean + + +-include $(DEPENDS) diff --git a/mesalib/src/mesa/SConscript b/mesalib/src/mesa/SConscript index 6ac8b0d4c..ea04fb1a0 100644 --- a/mesalib/src/mesa/SConscript +++ b/mesalib/src/mesa/SConscript @@ -1,393 +1,391 @@ -####################################################################### -# SConscript for Mesa - - -Import('*') - -env = env.Clone() - -env.Append(CPPPATH = [ - '#/src/mapi', - '#/src/glsl', - '#/src/mesa', -]) - -env.Append(CPPDEFINES = [ - 'FEATURE_GL=1', -]) - -if env['platform'] == 'windows': - env.Append(CPPDEFINES = [ - '_GDI32_', # prevent gl* being declared __declspec(dllimport) in MS headers - 'BUILD_GL32', # declare gl* as __declspec(dllexport) in Mesa headers - ]) - if not env['gles']: - # prevent _glapi_* from being declared __declspec(dllimport) - env.Append(CPPDEFINES = ['_GLAPI_NO_EXPORTS']) - - env.Prepend(CPPPATH = ['#src/talloc']) -else: - env.Append(CPPDEFINES = [ - 'IN_DRI_DRIVER', # enable the remap table (for DRI drivers) - ]) - -# -# Source files -# - -main_sources = [ - 'main/api_arrayelt.c', - 'main/api_exec.c', - 'main/api_loopback.c', - 'main/api_noop.c', - 'main/api_validate.c', - 'main/accum.c', - 'main/arbprogram.c', - 'main/atifragshader.c', - 'main/attrib.c', - 'main/arrayobj.c', - 'main/blend.c', - 'main/bufferobj.c', - 'main/buffers.c', - 'main/clear.c', - 'main/clip.c', - 'main/colortab.c', - 'main/condrender.c', - 'main/context.c', - 'main/convolve.c', - 'main/cpuinfo.c', - 'main/debug.c', - 'main/depth.c', - 'main/depthstencil.c', - 'main/dlist.c', - 'main/dlopen.c', - 'main/drawpix.c', - 'main/drawtex.c', - 'main/enable.c', - 'main/enums.c', - 'main/eval.c', - 'main/execmem.c', - 'main/extensions.c', - 'main/fbobject.c', - 'main/feedback.c', - 'main/ffvertex_prog.c', - 'main/fog.c', - 'main/formats.c', - 'main/framebuffer.c', - 'main/get.c', - 'main/getstring.c', - 'main/hash.c', - 'main/hint.c', - 'main/histogram.c', - 'main/image.c', - 'main/imports.c', - 'main/light.c', - 'main/lines.c', - 'main/matrix.c', - 'main/mipmap.c', - 'main/mm.c', - 'main/multisample.c', - 'main/nvprogram.c', - 'main/pack.c', - 'main/pixel.c', - 'main/pixelstore.c', - 'main/pixeltransfer.c', - 'main/points.c', - 'main/polygon.c', - 'main/querymatrix.c', - 'main/queryobj.c', - 'main/rastpos.c', - 'main/readpix.c', - 'main/remap.c', - 'main/renderbuffer.c', - 'main/scissor.c', - 'main/shaderapi.c', - 'main/shaderobj.c', - 'main/shared.c', - 'main/state.c', - 'main/stencil.c', - 'main/syncobj.c', - 'main/texcompress.c', - 'main/texcompress_s3tc.c', - 'main/texcompress_fxt1.c', - 'main/texenv.c', - 'main/texenvprogram.c', - 'main/texfetch.c', - 'main/texformat.c', - 'main/texgen.c', - 'main/texgetimage.c', - 'main/teximage.c', - 'main/texobj.c', - 'main/texpal.c', - 'main/texparam.c', - 'main/texrender.c', - 'main/texstate.c', - 'main/texstore.c', - 'main/transformfeedback.c', - 'main/uniforms.c', - 'main/varray.c', - 'main/version.c', - 'main/viewport.c', - 'main/vtxfmt.c', -] - -math_sources = [ - 'math/m_debug_clip.c', - 'math/m_debug_norm.c', - 'math/m_debug_xform.c', - 'math/m_eval.c', - 'math/m_matrix.c', - 'math/m_translate.c', - 'math/m_vector.c', - 'math/m_xform.c', -] - -vbo_sources = [ - 'vbo/vbo_context.c', - 'vbo/vbo_exec.c', - 'vbo/vbo_exec_api.c', - 'vbo/vbo_exec_array.c', - 'vbo/vbo_exec_draw.c', - 'vbo/vbo_exec_eval.c', - 'vbo/vbo_rebase.c', - 'vbo/vbo_split.c', - 'vbo/vbo_split_copy.c', - 'vbo/vbo_split_inplace.c', - 'vbo/vbo_save.c', - 'vbo/vbo_save_api.c', - 'vbo/vbo_save_draw.c', - 'vbo/vbo_save_loopback.c', -] - -vf_sources = [ - 'vf/vf.c', - 'vf/vf_generic.c', - 'vf/vf_sse.c', -] - -statetracker_sources = [ - 'state_tracker/st_atom.c', - 'state_tracker/st_atom_blend.c', - 'state_tracker/st_atom_clip.c', - 'state_tracker/st_atom_constbuf.c', - 'state_tracker/st_atom_depth.c', - 'state_tracker/st_atom_framebuffer.c', - 'state_tracker/st_atom_msaa.c', - 'state_tracker/st_atom_pixeltransfer.c', - 'state_tracker/st_atom_sampler.c', - 'state_tracker/st_atom_scissor.c', - 'state_tracker/st_atom_shader.c', - 'state_tracker/st_atom_rasterizer.c', - 'state_tracker/st_atom_stipple.c', - 'state_tracker/st_atom_texture.c', - 'state_tracker/st_atom_viewport.c', - 'state_tracker/st_cb_accum.c', - 'state_tracker/st_cb_bitmap.c', - 'state_tracker/st_cb_blit.c', - 'state_tracker/st_cb_bufferobjects.c', - 'state_tracker/st_cb_clear.c', - 'state_tracker/st_cb_condrender.c', - 'state_tracker/st_cb_flush.c', - 'state_tracker/st_cb_drawpixels.c', - 'state_tracker/st_cb_drawtex.c', - 'state_tracker/st_cb_eglimage.c', - 'state_tracker/st_cb_fbo.c', - 'state_tracker/st_cb_feedback.c', - 'state_tracker/st_cb_program.c', - 'state_tracker/st_cb_queryobj.c', - 'state_tracker/st_cb_rasterpos.c', - 'state_tracker/st_cb_readpixels.c', - 'state_tracker/st_cb_strings.c', - 'state_tracker/st_cb_texture.c', - 'state_tracker/st_cb_viewport.c', - 'state_tracker/st_cb_xformfb.c', - 'state_tracker/st_context.c', - 'state_tracker/st_debug.c', - 'state_tracker/st_draw.c', - 'state_tracker/st_draw_feedback.c', - 'state_tracker/st_extensions.c', - 'state_tracker/st_format.c', - 'state_tracker/st_gen_mipmap.c', - 'state_tracker/st_manager.c', - 'state_tracker/st_mesa_to_tgsi.c', - 'state_tracker/st_program.c', - 'state_tracker/st_texture.c', -] - -program_sources = [ - 'program/arbprogparse.c', - 'program/hash_table.c', - 'program/ir_to_mesa.cpp', - '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/sampler.cpp', - 'program/symbol_table.c', -] - -mesa_sources = ( - main_sources + - math_sources + - program_sources + - vbo_sources + - vf_sources + - statetracker_sources -) - -if env['gles']: - from sys import executable as python_cmd - - env.Append(CPPDEFINES = ['FEATURE_ES1=1', 'FEATURE_ES2=1']) - - # generate GLES sources - gles_sources = [] - gles_sources += env.CodeGenerate( - target = 'main/api_exec_es1.c', - script = 'main/es_generator.py', - source = 'main/APIspec.xml', - command = python_cmd + ' $SCRIPT -S $SOURCE -V GLES1.1 > $TARGET' - ) - gles_sources += env.CodeGenerate( - target = 'main/api_exec_es2.c', - script = 'main/es_generator.py', - source = 'main/APIspec.xml', - command = python_cmd + ' $SCRIPT -S $SOURCE -V GLES2.0 > $TARGET' - ) - - # generate GLES headers - GLAPI = '#src/mapi/glapi/' - gles_headers = [] - gles_headers += env.CodeGenerate( - target = 'es1api/main/glapidispatch.h', - script = GLAPI + 'gen/gl_table.py', - source = GLAPI + 'gen-es/es1_API.xml', - command = python_cmd + ' $SCRIPT -c -m remap_table -f $SOURCE > $TARGET', - ) - gles_headers += env.CodeGenerate( - target = 'es1api/main/remap_helper.h', - script = GLAPI + 'gen/remap_helper.py', - source = GLAPI + 'gen-es/es1_API.xml', - command = python_cmd + ' $SCRIPT -f $SOURCE > $TARGET', - ) - gles_headers += env.CodeGenerate( - target = 'es2api/main/glapidispatch.h', - script = GLAPI + 'gen/gl_table.py', - source = GLAPI + 'gen-es/es2_API.xml', - command = python_cmd + ' $SCRIPT -c -m remap_table -f $SOURCE > $TARGET', - ) - gles_headers += env.CodeGenerate( - target = 'es2api/main/remap_helper.h', - script = GLAPI + 'gen/remap_helper.py', - source = GLAPI + 'gen-es/es2_API.xml', - command = python_cmd + ' $SCRIPT -f $SOURCE > $TARGET', - ) - - env.Depends(gles_sources, gles_headers) - - # gles_sources #include gles_headers with full path - env.Append(CPPPATH = [gles_headers[0].dir.up().up()]) - - mesa_sources += gles_sources - -# -# Assembly sources -# -if env['gcc'] and env['platform'] != 'windows': - if env['machine'] == 'x86': - env.Append(CPPDEFINES = [ - 'USE_X86_ASM', - 'USE_MMX_ASM', - 'USE_3DNOW_ASM', - 'USE_SSE_ASM', - ]) - mesa_sources += [ - 'x86/common_x86.c', - 'x86/x86_xform.c', - 'x86/3dnow.c', - 'x86/sse.c', - 'x86/common_x86_asm.S', - 'x86/x86_xform2.S', - 'x86/x86_xform3.S', - 'x86/x86_xform4.S', - 'x86/x86_cliptest.S', - 'x86/mmx_blend.S', - 'x86/3dnow_xform1.S', - 'x86/3dnow_xform2.S', - 'x86/3dnow_xform3.S', - 'x86/3dnow_xform4.S', - 'x86/3dnow_normal.S', - 'x86/sse_xform1.S', - 'x86/sse_xform2.S', - 'x86/sse_xform3.S', - 'x86/sse_xform4.S', - 'x86/sse_normal.S', - 'x86/read_rgba_span_x86.S', - ] - elif env['machine'] == 'x86_64': - env.Append(CPPDEFINES = [ - 'USE_X86_64_ASM', - ]) - mesa_sources += [ - 'x86-64/x86-64.c', - 'x86-64/xform4.S', - ] - elif env['machine'] == 'ppc': - env.Append(CPPDEFINES = [ - 'USE_PPC_ASM', - 'USE_VMX_ASM', - ]) - mesa_sources += [ - 'ppc/common_ppc.c', - ] - elif env['machine'] == 'sparc': - mesa_sources += [ - 'sparc/sparc.c', - 'sparc/clip.S', - 'sparc/norm.S', - 'sparc/xform.S', - ] - else: - pass - - # Generate matypes.h - if env['machine'] in ('x86', 'x86_64'): - # See http://www.scons.org/wiki/UsingCodeGenerators - gen_matypes = env.Program( - target = 'gen_matypes', - source = 'x86/gen_matypes.c', - ) - matypes = env.Command( - 'matypes.h', - gen_matypes, - gen_matypes[0].abspath + ' > $TARGET', - ) - # Add the dir containing the generated header (somewhere inside the - # build dir) to the include path - env.Append(CPPPATH = [matypes[0].dir]) - -# -# Libraries -# - -mesa = env.ConvenienceLibrary( - target = 'mesa', - source = mesa_sources, -) - -env.Alias('mesa', mesa) - -Export('mesa') +####################################################################### +# SConscript for Mesa + + +Import('*') + +env = env.Clone() + +env.Append(CPPPATH = [ + '#/src/mapi', + '#/src/glsl', + '#/src/mesa', +]) + +env.Append(CPPDEFINES = [ + 'FEATURE_GL=1', +]) + +if env['platform'] == 'windows': + env.Append(CPPDEFINES = [ + '_GDI32_', # prevent gl* being declared __declspec(dllimport) in MS headers + 'BUILD_GL32', # declare gl* as __declspec(dllexport) in Mesa headers + ]) + if not env['gles']: + # prevent _glapi_* from being declared __declspec(dllimport) + env.Append(CPPDEFINES = ['_GLAPI_NO_EXPORTS']) +else: + env.Append(CPPDEFINES = [ + 'IN_DRI_DRIVER', # enable the remap table (for DRI drivers) + ]) + +# +# Source files +# + +main_sources = [ + 'main/api_arrayelt.c', + 'main/api_exec.c', + 'main/api_loopback.c', + 'main/api_noop.c', + 'main/api_validate.c', + 'main/accum.c', + 'main/arbprogram.c', + 'main/atifragshader.c', + 'main/attrib.c', + 'main/arrayobj.c', + 'main/blend.c', + 'main/bufferobj.c', + 'main/buffers.c', + 'main/clear.c', + 'main/clip.c', + 'main/colortab.c', + 'main/condrender.c', + 'main/context.c', + 'main/convolve.c', + 'main/cpuinfo.c', + 'main/debug.c', + 'main/depth.c', + 'main/depthstencil.c', + 'main/dlist.c', + 'main/dlopen.c', + 'main/drawpix.c', + 'main/drawtex.c', + 'main/enable.c', + 'main/enums.c', + 'main/eval.c', + 'main/execmem.c', + 'main/extensions.c', + 'main/fbobject.c', + 'main/feedback.c', + 'main/ffvertex_prog.c', + 'main/fog.c', + 'main/formats.c', + 'main/framebuffer.c', + 'main/get.c', + 'main/getstring.c', + 'main/hash.c', + 'main/hint.c', + 'main/histogram.c', + 'main/image.c', + 'main/imports.c', + 'main/light.c', + 'main/lines.c', + 'main/matrix.c', + 'main/mipmap.c', + 'main/mm.c', + 'main/multisample.c', + 'main/nvprogram.c', + 'main/pack.c', + 'main/pixel.c', + 'main/pixelstore.c', + 'main/pixeltransfer.c', + 'main/points.c', + 'main/polygon.c', + 'main/querymatrix.c', + 'main/queryobj.c', + 'main/rastpos.c', + 'main/readpix.c', + 'main/remap.c', + 'main/renderbuffer.c', + 'main/scissor.c', + 'main/shaderapi.c', + 'main/shaderobj.c', + 'main/shared.c', + 'main/state.c', + 'main/stencil.c', + 'main/syncobj.c', + 'main/texcompress.c', + 'main/texcompress_s3tc.c', + 'main/texcompress_fxt1.c', + 'main/texenv.c', + 'main/texenvprogram.c', + 'main/texfetch.c', + 'main/texformat.c', + 'main/texgen.c', + 'main/texgetimage.c', + 'main/teximage.c', + 'main/texobj.c', + 'main/texpal.c', + 'main/texparam.c', + 'main/texrender.c', + 'main/texstate.c', + 'main/texstore.c', + 'main/transformfeedback.c', + 'main/uniforms.c', + 'main/varray.c', + 'main/version.c', + 'main/viewport.c', + 'main/vtxfmt.c', +] + +math_sources = [ + 'math/m_debug_clip.c', + 'math/m_debug_norm.c', + 'math/m_debug_xform.c', + 'math/m_eval.c', + 'math/m_matrix.c', + 'math/m_translate.c', + 'math/m_vector.c', + 'math/m_xform.c', +] + +vbo_sources = [ + 'vbo/vbo_context.c', + 'vbo/vbo_exec.c', + 'vbo/vbo_exec_api.c', + 'vbo/vbo_exec_array.c', + 'vbo/vbo_exec_draw.c', + 'vbo/vbo_exec_eval.c', + 'vbo/vbo_rebase.c', + 'vbo/vbo_split.c', + 'vbo/vbo_split_copy.c', + 'vbo/vbo_split_inplace.c', + 'vbo/vbo_save.c', + 'vbo/vbo_save_api.c', + 'vbo/vbo_save_draw.c', + 'vbo/vbo_save_loopback.c', +] + +vf_sources = [ + 'vf/vf.c', + 'vf/vf_generic.c', + 'vf/vf_sse.c', +] + +statetracker_sources = [ + 'state_tracker/st_atom.c', + 'state_tracker/st_atom_blend.c', + 'state_tracker/st_atom_clip.c', + 'state_tracker/st_atom_constbuf.c', + 'state_tracker/st_atom_depth.c', + 'state_tracker/st_atom_framebuffer.c', + 'state_tracker/st_atom_msaa.c', + 'state_tracker/st_atom_pixeltransfer.c', + 'state_tracker/st_atom_sampler.c', + 'state_tracker/st_atom_scissor.c', + 'state_tracker/st_atom_shader.c', + 'state_tracker/st_atom_rasterizer.c', + 'state_tracker/st_atom_stipple.c', + 'state_tracker/st_atom_texture.c', + 'state_tracker/st_atom_viewport.c', + 'state_tracker/st_cb_accum.c', + 'state_tracker/st_cb_bitmap.c', + 'state_tracker/st_cb_blit.c', + 'state_tracker/st_cb_bufferobjects.c', + 'state_tracker/st_cb_clear.c', + 'state_tracker/st_cb_condrender.c', + 'state_tracker/st_cb_flush.c', + 'state_tracker/st_cb_drawpixels.c', + 'state_tracker/st_cb_drawtex.c', + 'state_tracker/st_cb_eglimage.c', + 'state_tracker/st_cb_fbo.c', + 'state_tracker/st_cb_feedback.c', + 'state_tracker/st_cb_program.c', + 'state_tracker/st_cb_queryobj.c', + 'state_tracker/st_cb_rasterpos.c', + 'state_tracker/st_cb_readpixels.c', + 'state_tracker/st_cb_strings.c', + 'state_tracker/st_cb_texture.c', + 'state_tracker/st_cb_viewport.c', + 'state_tracker/st_cb_xformfb.c', + 'state_tracker/st_context.c', + 'state_tracker/st_debug.c', + 'state_tracker/st_draw.c', + 'state_tracker/st_draw_feedback.c', + 'state_tracker/st_extensions.c', + 'state_tracker/st_format.c', + 'state_tracker/st_gen_mipmap.c', + 'state_tracker/st_manager.c', + 'state_tracker/st_mesa_to_tgsi.c', + 'state_tracker/st_program.c', + 'state_tracker/st_texture.c', +] + +program_sources = [ + 'program/arbprogparse.c', + 'program/hash_table.c', + 'program/ir_to_mesa.cpp', + '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/sampler.cpp', + 'program/symbol_table.c', +] + +mesa_sources = ( + main_sources + + math_sources + + program_sources + + vbo_sources + + vf_sources + + statetracker_sources +) + +if env['gles']: + from sys import executable as python_cmd + + env.Append(CPPDEFINES = ['FEATURE_ES1=1', 'FEATURE_ES2=1']) + + # generate GLES sources + gles_sources = [] + gles_sources += env.CodeGenerate( + target = 'main/api_exec_es1.c', + script = 'main/es_generator.py', + source = 'main/APIspec.xml', + command = python_cmd + ' $SCRIPT -S $SOURCE -V GLES1.1 > $TARGET' + ) + gles_sources += env.CodeGenerate( + target = 'main/api_exec_es2.c', + script = 'main/es_generator.py', + source = 'main/APIspec.xml', + command = python_cmd + ' $SCRIPT -S $SOURCE -V GLES2.0 > $TARGET' + ) + + # generate GLES headers + GLAPI = '#src/mapi/glapi/' + gles_headers = [] + gles_headers += env.CodeGenerate( + target = 'es1api/main/glapidispatch.h', + script = GLAPI + 'gen/gl_table.py', + source = GLAPI + 'gen-es/es1_API.xml', + command = python_cmd + ' $SCRIPT -c -m remap_table -f $SOURCE > $TARGET', + ) + gles_headers += env.CodeGenerate( + target = 'es1api/main/remap_helper.h', + script = GLAPI + 'gen/remap_helper.py', + source = GLAPI + 'gen-es/es1_API.xml', + command = python_cmd + ' $SCRIPT -f $SOURCE > $TARGET', + ) + gles_headers += env.CodeGenerate( + target = 'es2api/main/glapidispatch.h', + script = GLAPI + 'gen/gl_table.py', + source = GLAPI + 'gen-es/es2_API.xml', + command = python_cmd + ' $SCRIPT -c -m remap_table -f $SOURCE > $TARGET', + ) + gles_headers += env.CodeGenerate( + target = 'es2api/main/remap_helper.h', + script = GLAPI + 'gen/remap_helper.py', + source = GLAPI + 'gen-es/es2_API.xml', + command = python_cmd + ' $SCRIPT -f $SOURCE > $TARGET', + ) + + env.Depends(gles_sources, gles_headers) + + # gles_sources #include gles_headers with full path + env.Append(CPPPATH = [gles_headers[0].dir.up().up()]) + + mesa_sources += gles_sources + +# +# Assembly sources +# +if env['gcc'] and env['platform'] != 'windows': + if env['machine'] == 'x86': + env.Append(CPPDEFINES = [ + 'USE_X86_ASM', + 'USE_MMX_ASM', + 'USE_3DNOW_ASM', + 'USE_SSE_ASM', + ]) + mesa_sources += [ + 'x86/common_x86.c', + 'x86/x86_xform.c', + 'x86/3dnow.c', + 'x86/sse.c', + 'x86/common_x86_asm.S', + 'x86/x86_xform2.S', + 'x86/x86_xform3.S', + 'x86/x86_xform4.S', + 'x86/x86_cliptest.S', + 'x86/mmx_blend.S', + 'x86/3dnow_xform1.S', + 'x86/3dnow_xform2.S', + 'x86/3dnow_xform3.S', + 'x86/3dnow_xform4.S', + 'x86/3dnow_normal.S', + 'x86/sse_xform1.S', + 'x86/sse_xform2.S', + 'x86/sse_xform3.S', + 'x86/sse_xform4.S', + 'x86/sse_normal.S', + 'x86/read_rgba_span_x86.S', + ] + elif env['machine'] == 'x86_64': + env.Append(CPPDEFINES = [ + 'USE_X86_64_ASM', + ]) + mesa_sources += [ + 'x86-64/x86-64.c', + 'x86-64/xform4.S', + ] + elif env['machine'] == 'ppc': + env.Append(CPPDEFINES = [ + 'USE_PPC_ASM', + 'USE_VMX_ASM', + ]) + mesa_sources += [ + 'ppc/common_ppc.c', + ] + elif env['machine'] == 'sparc': + mesa_sources += [ + 'sparc/sparc.c', + 'sparc/clip.S', + 'sparc/norm.S', + 'sparc/xform.S', + ] + else: + pass + + # Generate matypes.h + if env['machine'] in ('x86', 'x86_64'): + # See http://www.scons.org/wiki/UsingCodeGenerators + gen_matypes = env.Program( + target = 'gen_matypes', + source = 'x86/gen_matypes.c', + ) + matypes = env.Command( + 'matypes.h', + gen_matypes, + gen_matypes[0].abspath + ' > $TARGET', + ) + # Add the dir containing the generated header (somewhere inside the + # build dir) to the include path + env.Append(CPPPATH = [matypes[0].dir]) + +# +# Libraries +# + +mesa = env.ConvenienceLibrary( + target = 'mesa', + source = mesa_sources, +) + +env.Alias('mesa', mesa) + +Export('mesa') diff --git a/mesalib/src/mesa/main/arrayobj.c b/mesalib/src/mesa/main/arrayobj.c index 2d85b88ae..460102233 100644 --- a/mesalib/src/mesa/main/arrayobj.c +++ b/mesalib/src/mesa/main/arrayobj.c @@ -1,578 +1,578 @@ -/* - * Mesa 3-D graphics library - * Version: 7.6 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * (C) Copyright IBM Corporation 2006 - * 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 OR IBM 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 arrayobj.c - * Functions for the GL_APPLE_vertex_array_object extension. - * - * \todo - * The code in this file borrows a lot from bufferobj.c. There's a certain - * amount of cruft left over from that origin that may be unnecessary. - * - * \author Ian Romanick - * \author Brian Paul - */ - - -#include "glheader.h" -#include "hash.h" -#include "imports.h" -#include "context.h" -#include "mfeatures.h" -#if FEATURE_ARB_vertex_buffer_object -#include "bufferobj.h" -#endif -#include "arrayobj.h" -#include "macros.h" -#include "mtypes.h" -#include "main/dispatch.h" - - -/** - * Look up the array object for the given ID. - * - * \returns - * Either a pointer to the array object with the specified ID or \c NULL for - * a non-existent ID. The spec defines ID 0 as being technically - * non-existent. - */ - -static INLINE struct gl_array_object * -lookup_arrayobj(struct gl_context *ctx, GLuint id) -{ - if (id == 0) - return NULL; - else - return (struct gl_array_object *) - _mesa_HashLookup(ctx->Array.Objects, id); -} - - -/** - * For all the vertex arrays in the array object, unbind any pointers - * to any buffer objects (VBOs). - * This is done just prior to array object destruction. - */ -static void -unbind_array_object_vbos(struct gl_context *ctx, struct gl_array_object *obj) -{ - GLuint i; - - _mesa_reference_buffer_object(ctx, &obj->Vertex.BufferObj, NULL); - _mesa_reference_buffer_object(ctx, &obj->Weight.BufferObj, NULL); - _mesa_reference_buffer_object(ctx, &obj->Normal.BufferObj, NULL); - _mesa_reference_buffer_object(ctx, &obj->Color.BufferObj, NULL); - _mesa_reference_buffer_object(ctx, &obj->SecondaryColor.BufferObj, NULL); - _mesa_reference_buffer_object(ctx, &obj->FogCoord.BufferObj, NULL); - _mesa_reference_buffer_object(ctx, &obj->Index.BufferObj, NULL); - _mesa_reference_buffer_object(ctx, &obj->EdgeFlag.BufferObj, NULL); - - for (i = 0; i < Elements(obj->TexCoord); i++) - _mesa_reference_buffer_object(ctx, &obj->TexCoord[i].BufferObj, NULL); - - for (i = 0; i < Elements(obj->VertexAttrib); i++) - _mesa_reference_buffer_object(ctx, &obj->VertexAttrib[i].BufferObj,NULL); - -#if FEATURE_point_size_array - _mesa_reference_buffer_object(ctx, &obj->PointSize.BufferObj, NULL); -#endif -} - - -/** - * Allocate and initialize a new vertex array object. - * - * This function is intended to be called via - * \c dd_function_table::NewArrayObject. - */ -struct gl_array_object * -_mesa_new_array_object( struct gl_context *ctx, GLuint name ) -{ - struct gl_array_object *obj = CALLOC_STRUCT(gl_array_object); - if (obj) - _mesa_initialize_array_object(ctx, obj, name); - return obj; -} - - -/** - * Delete an array object. - * - * This function is intended to be called via - * \c dd_function_table::DeleteArrayObject. - */ -void -_mesa_delete_array_object( struct gl_context *ctx, struct gl_array_object *obj ) -{ - (void) ctx; - unbind_array_object_vbos(ctx, obj); - _glthread_DESTROY_MUTEX(obj->Mutex); - free(obj); -} - - -/** - * Set ptr to arrayObj w/ reference counting. - */ -void -_mesa_reference_array_object(struct gl_context *ctx, - struct gl_array_object **ptr, - struct gl_array_object *arrayObj) -{ - if (*ptr == arrayObj) - return; - - if (*ptr) { - /* Unreference the old array object */ - GLboolean deleteFlag = GL_FALSE; - struct gl_array_object *oldObj = *ptr; - - _glthread_LOCK_MUTEX(oldObj->Mutex); - ASSERT(oldObj->RefCount > 0); - oldObj->RefCount--; -#if 0 - printf("ArrayObj %p %d DECR to %d\n", - (void *) oldObj, oldObj->Name, oldObj->RefCount); -#endif - deleteFlag = (oldObj->RefCount == 0); - _glthread_UNLOCK_MUTEX(oldObj->Mutex); - - if (deleteFlag) { - ASSERT(ctx->Driver.DeleteArrayObject); - ctx->Driver.DeleteArrayObject(ctx, oldObj); - } - - *ptr = NULL; - } - ASSERT(!*ptr); - - if (arrayObj) { - /* reference new array object */ - _glthread_LOCK_MUTEX(arrayObj->Mutex); - if (arrayObj->RefCount == 0) { - /* this array's being deleted (look just above) */ - /* Not sure this can every really happen. Warn if it does. */ - _mesa_problem(NULL, "referencing deleted array object"); - *ptr = NULL; - } - else { - arrayObj->RefCount++; -#if 0 - printf("ArrayObj %p %d INCR to %d\n", - (void *) arrayObj, arrayObj->Name, arrayObj->RefCount); -#endif - *ptr = arrayObj; - } - _glthread_UNLOCK_MUTEX(arrayObj->Mutex); - } -} - - - -static void -init_array(struct gl_context *ctx, - struct gl_client_array *array, GLint size, GLint type) -{ - array->Size = size; - array->Type = type; - array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */ - array->Stride = 0; - array->StrideB = 0; - array->Ptr = NULL; - array->Enabled = GL_FALSE; - array->Normalized = GL_FALSE; -#if FEATURE_ARB_vertex_buffer_object - /* Vertex array buffers */ - _mesa_reference_buffer_object(ctx, &array->BufferObj, - ctx->Shared->NullBufferObj); -#endif -} - - -/** - * Initialize a gl_array_object's arrays. - */ -void -_mesa_initialize_array_object( struct gl_context *ctx, - struct gl_array_object *obj, - GLuint name ) -{ - GLuint i; - - obj->Name = name; - - _glthread_INIT_MUTEX(obj->Mutex); - obj->RefCount = 1; - - /* Init the individual arrays */ - init_array(ctx, &obj->Vertex, 4, GL_FLOAT); - init_array(ctx, &obj->Weight, 1, GL_FLOAT); - init_array(ctx, &obj->Normal, 3, GL_FLOAT); - init_array(ctx, &obj->Color, 4, GL_FLOAT); - init_array(ctx, &obj->SecondaryColor, 4, GL_FLOAT); - init_array(ctx, &obj->FogCoord, 1, GL_FLOAT); - init_array(ctx, &obj->Index, 1, GL_FLOAT); - for (i = 0; i < Elements(obj->TexCoord); i++) { - init_array(ctx, &obj->TexCoord[i], 4, GL_FLOAT); - } - init_array(ctx, &obj->EdgeFlag, 1, GL_BOOL); - for (i = 0; i < Elements(obj->VertexAttrib); i++) { - init_array(ctx, &obj->VertexAttrib[i], 4, GL_FLOAT); - } - -#if FEATURE_point_size_array - init_array(ctx, &obj->PointSize, 1, GL_FLOAT); -#endif -} - - -/** - * Add the given array object to the array object pool. - */ -static void -save_array_object( struct gl_context *ctx, struct gl_array_object *obj ) -{ - if (obj->Name > 0) { - /* insert into hash table */ - _mesa_HashInsert(ctx->Array.Objects, obj->Name, obj); - } -} - - -/** - * Remove the given array object from the array object pool. - * Do not deallocate the array object though. - */ -static void -remove_array_object( struct gl_context *ctx, struct gl_array_object *obj ) -{ - if (obj->Name > 0) { - /* remove from hash table */ - _mesa_HashRemove(ctx->Array.Objects, obj->Name); - } -} - - - -/** - * Compute the index of the last array element that can be safely accessed - * in a vertex array. We can really only do this when the array lives in - * a VBO. - * The array->_MaxElement field will be updated. - * Later in glDrawArrays/Elements/etc we can do some bounds checking. - */ -static void -compute_max_element(struct gl_client_array *array) -{ - if (array->BufferObj->Name) { - /* Compute the max element we can access in the VBO without going - * out of bounds. - */ - array->_MaxElement = ((GLsizeiptrARB) array->BufferObj->Size - - (GLsizeiptrARB) array->Ptr + array->StrideB - - array->_ElementSize) / array->StrideB; - if (0) - printf("%s Object %u Size %u MaxElement %u\n", - __FUNCTION__, - array->BufferObj->Name, - (GLuint) array->BufferObj->Size, - array->_MaxElement); - } - else { - /* user-space array, no idea how big it is */ - array->_MaxElement = 2 * 1000 * 1000 * 1000; /* just a big number */ - } -} - - -/** - * Helper for update_arrays(). - * \return min(current min, array->_MaxElement). - */ -static GLuint -update_min(GLuint min, struct gl_client_array *array) -{ - compute_max_element(array); - if (array->Enabled) - return MIN2(min, array->_MaxElement); - else - return min; -} - - -/** - * Examine vertex arrays to update the gl_array_object::_MaxElement field. - */ -void -_mesa_update_array_object_max_element(struct gl_context *ctx, - struct gl_array_object *arrayObj) -{ - GLuint i, min = ~0; - - min = update_min(min, &arrayObj->Vertex); - min = update_min(min, &arrayObj->Weight); - min = update_min(min, &arrayObj->Normal); - min = update_min(min, &arrayObj->Color); - min = update_min(min, &arrayObj->SecondaryColor); - min = update_min(min, &arrayObj->FogCoord); - min = update_min(min, &arrayObj->Index); - min = update_min(min, &arrayObj->EdgeFlag); -#if FEATURE_point_size_array - min = update_min(min, &arrayObj->PointSize); -#endif - for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) - min = update_min(min, &arrayObj->TexCoord[i]); - for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) - min = update_min(min, &arrayObj->VertexAttrib[i]); - - /* _MaxElement is one past the last legal array element */ - arrayObj->_MaxElement = min; -} - - -/**********************************************************************/ -/* API Functions */ -/**********************************************************************/ - - -/** - * Helper for _mesa_BindVertexArray() and _mesa_BindVertexArrayAPPLE(). - * \param genRequired specifies behavour when id was not generated with - * glGenVertexArrays(). - */ -static void -bind_vertex_array(struct gl_context *ctx, GLuint id, GLboolean genRequired) -{ - struct gl_array_object * const oldObj = ctx->Array.ArrayObj; - struct gl_array_object *newObj = NULL; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - ASSERT(oldObj != NULL); - - if ( oldObj->Name == id ) - return; /* rebinding the same array object- no change */ - - /* - * Get pointer to new array object (newObj) - */ - if (id == 0) { - /* The spec says there is no array object named 0, but we use - * one internally because it simplifies things. - */ - newObj = ctx->Array.DefaultArrayObj; - } - else { - /* non-default array object */ - newObj = lookup_arrayobj(ctx, id); - if (!newObj) { - if (genRequired) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBindVertexArray(id)"); - return; - } - - /* For APPLE version, generate a new array object now */ - newObj = (*ctx->Driver.NewArrayObject)(ctx, id); - if (!newObj) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindVertexArrayAPPLE"); - return; - } - save_array_object(ctx, newObj); - } - } - - ctx->NewState |= _NEW_ARRAY; - ctx->Array.NewState |= _NEW_ARRAY_ALL; - _mesa_reference_array_object(ctx, &ctx->Array.ArrayObj, newObj); - - /* Pass BindVertexArray call to device driver */ - if (ctx->Driver.BindArrayObject && newObj) - ctx->Driver.BindArrayObject(ctx, newObj); -} - - -/** - * ARB version of glBindVertexArray() - * This function behaves differently from glBindVertexArrayAPPLE() in - * that this function requires all ids to have been previously generated - * by glGenVertexArrays[APPLE](). - */ -void GLAPIENTRY -_mesa_BindVertexArray( GLuint id ) -{ - GET_CURRENT_CONTEXT(ctx); - bind_vertex_array(ctx, id, GL_TRUE); -} - - -/** - * Bind a new array. - * - * \todo - * The binding could be done more efficiently by comparing the non-NULL - * pointers in the old and new objects. The only arrays that are "dirty" are - * the ones that are non-NULL in either object. - */ -void GLAPIENTRY -_mesa_BindVertexArrayAPPLE( GLuint id ) -{ - GET_CURRENT_CONTEXT(ctx); - bind_vertex_array(ctx, id, GL_FALSE); -} - - -/** - * Delete a set of array objects. - * - * \param n Number of array objects to delete. - * \param ids Array of \c n array object IDs. - */ -void GLAPIENTRY -_mesa_DeleteVertexArraysAPPLE(GLsizei n, const GLuint *ids) -{ - GET_CURRENT_CONTEXT(ctx); - GLsizei i; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArrayAPPLE(n)"); - return; - } - - for (i = 0; i < n; i++) { - struct gl_array_object *obj = lookup_arrayobj(ctx, ids[i]); - - if ( obj != NULL ) { - ASSERT( obj->Name == ids[i] ); - - /* If the array object is currently bound, the spec says "the binding - * for that object reverts to zero and the default vertex array - * becomes current." - */ - if ( obj == ctx->Array.ArrayObj ) { - CALL_BindVertexArrayAPPLE( ctx->Exec, (0) ); - } - - /* The ID is immediately freed for re-use */ - remove_array_object(ctx, obj); - - /* Unreference the array object. - * If refcount hits zero, the object will be deleted. - */ - _mesa_reference_array_object(ctx, &obj, NULL); - } - } -} - - -/** - * Generate a set of unique array object IDs and store them in \c arrays. - * Helper for _mesa_GenVertexArrays[APPLE]() functions below. - * \param n Number of IDs to generate. - * \param arrays Array of \c n locations to store the IDs. - * \param vboOnly Will arrays have to reside in VBOs? - */ -static void -gen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays, GLboolean vboOnly) -{ - GLuint first; - GLint i; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGenVertexArraysAPPLE"); - return; - } - - if (!arrays) { - return; - } - - first = _mesa_HashFindFreeKeyBlock(ctx->Array.Objects, n); - - /* Allocate new, empty array objects and return identifiers */ - for (i = 0; i < n; i++) { - struct gl_array_object *obj; - GLuint name = first + i; - - obj = (*ctx->Driver.NewArrayObject)( ctx, name ); - if (!obj) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenVertexArraysAPPLE"); - return; - } - obj->VBOonly = vboOnly; - save_array_object(ctx, obj); - arrays[i] = first + i; - } -} - - -/** - * ARB version of glGenVertexArrays() - * All arrays will be required to live in VBOs. - */ -void GLAPIENTRY -_mesa_GenVertexArrays(GLsizei n, GLuint *arrays) -{ - GET_CURRENT_CONTEXT(ctx); - gen_vertex_arrays(ctx, n, arrays, GL_TRUE); -} - - -/** - * APPLE version of glGenVertexArraysAPPLE() - * Arrays may live in VBOs or ordinary memory. - */ -void GLAPIENTRY -_mesa_GenVertexArraysAPPLE(GLsizei n, GLuint *arrays) -{ - GET_CURRENT_CONTEXT(ctx); - gen_vertex_arrays(ctx, n, arrays, GL_FALSE); -} - - -/** - * Determine if ID is the name of an array object. - * - * \param id ID of the potential array object. - * \return \c GL_TRUE if \c id is the name of a array object, - * \c GL_FALSE otherwise. - */ -GLboolean GLAPIENTRY -_mesa_IsVertexArrayAPPLE( GLuint id ) -{ - struct gl_array_object * obj; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - - if (id == 0) - return GL_FALSE; - - obj = lookup_arrayobj(ctx, id); - - return (obj != NULL) ? GL_TRUE : GL_FALSE; -} +/* + * Mesa 3-D graphics library + * Version: 7.6 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * (C) Copyright IBM Corporation 2006 + * 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 OR IBM 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 arrayobj.c + * Functions for the GL_APPLE_vertex_array_object extension. + * + * \todo + * The code in this file borrows a lot from bufferobj.c. There's a certain + * amount of cruft left over from that origin that may be unnecessary. + * + * \author Ian Romanick + * \author Brian Paul + */ + + +#include "glheader.h" +#include "hash.h" +#include "imports.h" +#include "context.h" +#include "mfeatures.h" +#if FEATURE_ARB_vertex_buffer_object +#include "bufferobj.h" +#endif +#include "arrayobj.h" +#include "macros.h" +#include "mtypes.h" +#include "main/dispatch.h" + + +/** + * Look up the array object for the given ID. + * + * \returns + * Either a pointer to the array object with the specified ID or \c NULL for + * a non-existent ID. The spec defines ID 0 as being technically + * non-existent. + */ + +static INLINE struct gl_array_object * +lookup_arrayobj(struct gl_context *ctx, GLuint id) +{ + if (id == 0) + return NULL; + else + return (struct gl_array_object *) + _mesa_HashLookup(ctx->Array.Objects, id); +} + + +/** + * For all the vertex arrays in the array object, unbind any pointers + * to any buffer objects (VBOs). + * This is done just prior to array object destruction. + */ +static void +unbind_array_object_vbos(struct gl_context *ctx, struct gl_array_object *obj) +{ + GLuint i; + + _mesa_reference_buffer_object(ctx, &obj->Vertex.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &obj->Weight.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &obj->Normal.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &obj->Color.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &obj->SecondaryColor.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &obj->FogCoord.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &obj->Index.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &obj->EdgeFlag.BufferObj, NULL); + + for (i = 0; i < Elements(obj->TexCoord); i++) + _mesa_reference_buffer_object(ctx, &obj->TexCoord[i].BufferObj, NULL); + + for (i = 0; i < Elements(obj->VertexAttrib); i++) + _mesa_reference_buffer_object(ctx, &obj->VertexAttrib[i].BufferObj,NULL); + +#if FEATURE_point_size_array + _mesa_reference_buffer_object(ctx, &obj->PointSize.BufferObj, NULL); +#endif +} + + +/** + * Allocate and initialize a new vertex array object. + * + * This function is intended to be called via + * \c dd_function_table::NewArrayObject. + */ +struct gl_array_object * +_mesa_new_array_object( struct gl_context *ctx, GLuint name ) +{ + struct gl_array_object *obj = CALLOC_STRUCT(gl_array_object); + if (obj) + _mesa_initialize_array_object(ctx, obj, name); + return obj; +} + + +/** + * Delete an array object. + * + * This function is intended to be called via + * \c dd_function_table::DeleteArrayObject. + */ +void +_mesa_delete_array_object( struct gl_context *ctx, struct gl_array_object *obj ) +{ + (void) ctx; + unbind_array_object_vbos(ctx, obj); + _glthread_DESTROY_MUTEX(obj->Mutex); + free(obj); +} + + +/** + * Set ptr to arrayObj w/ reference counting. + */ +void +_mesa_reference_array_object(struct gl_context *ctx, + struct gl_array_object **ptr, + struct gl_array_object *arrayObj) +{ + if (*ptr == arrayObj) + return; + + if (*ptr) { + /* Unreference the old array object */ + GLboolean deleteFlag = GL_FALSE; + struct gl_array_object *oldObj = *ptr; + + _glthread_LOCK_MUTEX(oldObj->Mutex); + ASSERT(oldObj->RefCount > 0); + oldObj->RefCount--; +#if 0 + printf("ArrayObj %p %d DECR to %d\n", + (void *) oldObj, oldObj->Name, oldObj->RefCount); +#endif + deleteFlag = (oldObj->RefCount == 0); + _glthread_UNLOCK_MUTEX(oldObj->Mutex); + + if (deleteFlag) { + ASSERT(ctx->Driver.DeleteArrayObject); + ctx->Driver.DeleteArrayObject(ctx, oldObj); + } + + *ptr = NULL; + } + ASSERT(!*ptr); + + if (arrayObj) { + /* reference new array object */ + _glthread_LOCK_MUTEX(arrayObj->Mutex); + if (arrayObj->RefCount == 0) { + /* this array's being deleted (look just above) */ + /* Not sure this can every really happen. Warn if it does. */ + _mesa_problem(NULL, "referencing deleted array object"); + *ptr = NULL; + } + else { + arrayObj->RefCount++; +#if 0 + printf("ArrayObj %p %d INCR to %d\n", + (void *) arrayObj, arrayObj->Name, arrayObj->RefCount); +#endif + *ptr = arrayObj; + } + _glthread_UNLOCK_MUTEX(arrayObj->Mutex); + } +} + + + +static void +init_array(struct gl_context *ctx, + struct gl_client_array *array, GLint size, GLint type) +{ + array->Size = size; + array->Type = type; + array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */ + array->Stride = 0; + array->StrideB = 0; + array->Ptr = NULL; + array->Enabled = GL_FALSE; + array->Normalized = GL_FALSE; +#if FEATURE_ARB_vertex_buffer_object + /* Vertex array buffers */ + _mesa_reference_buffer_object(ctx, &array->BufferObj, + ctx->Shared->NullBufferObj); +#endif +} + + +/** + * Initialize a gl_array_object's arrays. + */ +void +_mesa_initialize_array_object( struct gl_context *ctx, + struct gl_array_object *obj, + GLuint name ) +{ + GLuint i; + + obj->Name = name; + + _glthread_INIT_MUTEX(obj->Mutex); + obj->RefCount = 1; + + /* Init the individual arrays */ + init_array(ctx, &obj->Vertex, 4, GL_FLOAT); + init_array(ctx, &obj->Weight, 1, GL_FLOAT); + init_array(ctx, &obj->Normal, 3, GL_FLOAT); + init_array(ctx, &obj->Color, 4, GL_FLOAT); + init_array(ctx, &obj->SecondaryColor, 3, GL_FLOAT); + init_array(ctx, &obj->FogCoord, 1, GL_FLOAT); + init_array(ctx, &obj->Index, 1, GL_FLOAT); + for (i = 0; i < Elements(obj->TexCoord); i++) { + init_array(ctx, &obj->TexCoord[i], 4, GL_FLOAT); + } + init_array(ctx, &obj->EdgeFlag, 1, GL_BOOL); + for (i = 0; i < Elements(obj->VertexAttrib); i++) { + init_array(ctx, &obj->VertexAttrib[i], 4, GL_FLOAT); + } + +#if FEATURE_point_size_array + init_array(ctx, &obj->PointSize, 1, GL_FLOAT); +#endif +} + + +/** + * Add the given array object to the array object pool. + */ +static void +save_array_object( struct gl_context *ctx, struct gl_array_object *obj ) +{ + if (obj->Name > 0) { + /* insert into hash table */ + _mesa_HashInsert(ctx->Array.Objects, obj->Name, obj); + } +} + + +/** + * Remove the given array object from the array object pool. + * Do not deallocate the array object though. + */ +static void +remove_array_object( struct gl_context *ctx, struct gl_array_object *obj ) +{ + if (obj->Name > 0) { + /* remove from hash table */ + _mesa_HashRemove(ctx->Array.Objects, obj->Name); + } +} + + + +/** + * Compute the index of the last array element that can be safely accessed + * in a vertex array. We can really only do this when the array lives in + * a VBO. + * The array->_MaxElement field will be updated. + * Later in glDrawArrays/Elements/etc we can do some bounds checking. + */ +static void +compute_max_element(struct gl_client_array *array) +{ + if (array->BufferObj->Name) { + /* Compute the max element we can access in the VBO without going + * out of bounds. + */ + array->_MaxElement = ((GLsizeiptrARB) array->BufferObj->Size + - (GLsizeiptrARB) array->Ptr + array->StrideB + - array->_ElementSize) / array->StrideB; + if (0) + printf("%s Object %u Size %u MaxElement %u\n", + __FUNCTION__, + array->BufferObj->Name, + (GLuint) array->BufferObj->Size, + array->_MaxElement); + } + else { + /* user-space array, no idea how big it is */ + array->_MaxElement = 2 * 1000 * 1000 * 1000; /* just a big number */ + } +} + + +/** + * Helper for update_arrays(). + * \return min(current min, array->_MaxElement). + */ +static GLuint +update_min(GLuint min, struct gl_client_array *array) +{ + compute_max_element(array); + if (array->Enabled) + return MIN2(min, array->_MaxElement); + else + return min; +} + + +/** + * Examine vertex arrays to update the gl_array_object::_MaxElement field. + */ +void +_mesa_update_array_object_max_element(struct gl_context *ctx, + struct gl_array_object *arrayObj) +{ + GLuint i, min = ~0; + + min = update_min(min, &arrayObj->Vertex); + min = update_min(min, &arrayObj->Weight); + min = update_min(min, &arrayObj->Normal); + min = update_min(min, &arrayObj->Color); + min = update_min(min, &arrayObj->SecondaryColor); + min = update_min(min, &arrayObj->FogCoord); + min = update_min(min, &arrayObj->Index); + min = update_min(min, &arrayObj->EdgeFlag); +#if FEATURE_point_size_array + min = update_min(min, &arrayObj->PointSize); +#endif + for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) + min = update_min(min, &arrayObj->TexCoord[i]); + for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) + min = update_min(min, &arrayObj->VertexAttrib[i]); + + /* _MaxElement is one past the last legal array element */ + arrayObj->_MaxElement = min; +} + + +/**********************************************************************/ +/* API Functions */ +/**********************************************************************/ + + +/** + * Helper for _mesa_BindVertexArray() and _mesa_BindVertexArrayAPPLE(). + * \param genRequired specifies behavour when id was not generated with + * glGenVertexArrays(). + */ +static void +bind_vertex_array(struct gl_context *ctx, GLuint id, GLboolean genRequired) +{ + struct gl_array_object * const oldObj = ctx->Array.ArrayObj; + struct gl_array_object *newObj = NULL; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + ASSERT(oldObj != NULL); + + if ( oldObj->Name == id ) + return; /* rebinding the same array object- no change */ + + /* + * Get pointer to new array object (newObj) + */ + if (id == 0) { + /* The spec says there is no array object named 0, but we use + * one internally because it simplifies things. + */ + newObj = ctx->Array.DefaultArrayObj; + } + else { + /* non-default array object */ + newObj = lookup_arrayobj(ctx, id); + if (!newObj) { + if (genRequired) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBindVertexArray(id)"); + return; + } + + /* For APPLE version, generate a new array object now */ + newObj = (*ctx->Driver.NewArrayObject)(ctx, id); + if (!newObj) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindVertexArrayAPPLE"); + return; + } + save_array_object(ctx, newObj); + } + } + + ctx->NewState |= _NEW_ARRAY; + ctx->Array.NewState |= _NEW_ARRAY_ALL; + _mesa_reference_array_object(ctx, &ctx->Array.ArrayObj, newObj); + + /* Pass BindVertexArray call to device driver */ + if (ctx->Driver.BindArrayObject && newObj) + ctx->Driver.BindArrayObject(ctx, newObj); +} + + +/** + * ARB version of glBindVertexArray() + * This function behaves differently from glBindVertexArrayAPPLE() in + * that this function requires all ids to have been previously generated + * by glGenVertexArrays[APPLE](). + */ +void GLAPIENTRY +_mesa_BindVertexArray( GLuint id ) +{ + GET_CURRENT_CONTEXT(ctx); + bind_vertex_array(ctx, id, GL_TRUE); +} + + +/** + * Bind a new array. + * + * \todo + * The binding could be done more efficiently by comparing the non-NULL + * pointers in the old and new objects. The only arrays that are "dirty" are + * the ones that are non-NULL in either object. + */ +void GLAPIENTRY +_mesa_BindVertexArrayAPPLE( GLuint id ) +{ + GET_CURRENT_CONTEXT(ctx); + bind_vertex_array(ctx, id, GL_FALSE); +} + + +/** + * Delete a set of array objects. + * + * \param n Number of array objects to delete. + * \param ids Array of \c n array object IDs. + */ +void GLAPIENTRY +_mesa_DeleteVertexArraysAPPLE(GLsizei n, const GLuint *ids) +{ + GET_CURRENT_CONTEXT(ctx); + GLsizei i; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArrayAPPLE(n)"); + return; + } + + for (i = 0; i < n; i++) { + struct gl_array_object *obj = lookup_arrayobj(ctx, ids[i]); + + if ( obj != NULL ) { + ASSERT( obj->Name == ids[i] ); + + /* If the array object is currently bound, the spec says "the binding + * for that object reverts to zero and the default vertex array + * becomes current." + */ + if ( obj == ctx->Array.ArrayObj ) { + CALL_BindVertexArrayAPPLE( ctx->Exec, (0) ); + } + + /* The ID is immediately freed for re-use */ + remove_array_object(ctx, obj); + + /* Unreference the array object. + * If refcount hits zero, the object will be deleted. + */ + _mesa_reference_array_object(ctx, &obj, NULL); + } + } +} + + +/** + * Generate a set of unique array object IDs and store them in \c arrays. + * Helper for _mesa_GenVertexArrays[APPLE]() functions below. + * \param n Number of IDs to generate. + * \param arrays Array of \c n locations to store the IDs. + * \param vboOnly Will arrays have to reside in VBOs? + */ +static void +gen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays, GLboolean vboOnly) +{ + GLuint first; + GLint i; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGenVertexArraysAPPLE"); + return; + } + + if (!arrays) { + return; + } + + first = _mesa_HashFindFreeKeyBlock(ctx->Array.Objects, n); + + /* Allocate new, empty array objects and return identifiers */ + for (i = 0; i < n; i++) { + struct gl_array_object *obj; + GLuint name = first + i; + + obj = (*ctx->Driver.NewArrayObject)( ctx, name ); + if (!obj) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenVertexArraysAPPLE"); + return; + } + obj->VBOonly = vboOnly; + save_array_object(ctx, obj); + arrays[i] = first + i; + } +} + + +/** + * ARB version of glGenVertexArrays() + * All arrays will be required to live in VBOs. + */ +void GLAPIENTRY +_mesa_GenVertexArrays(GLsizei n, GLuint *arrays) +{ + GET_CURRENT_CONTEXT(ctx); + gen_vertex_arrays(ctx, n, arrays, GL_TRUE); +} + + +/** + * APPLE version of glGenVertexArraysAPPLE() + * Arrays may live in VBOs or ordinary memory. + */ +void GLAPIENTRY +_mesa_GenVertexArraysAPPLE(GLsizei n, GLuint *arrays) +{ + GET_CURRENT_CONTEXT(ctx); + gen_vertex_arrays(ctx, n, arrays, GL_FALSE); +} + + +/** + * Determine if ID is the name of an array object. + * + * \param id ID of the potential array object. + * \return \c GL_TRUE if \c id is the name of a array object, + * \c GL_FALSE otherwise. + */ +GLboolean GLAPIENTRY +_mesa_IsVertexArrayAPPLE( GLuint id ) +{ + struct gl_array_object * obj; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + + if (id == 0) + return GL_FALSE; + + obj = lookup_arrayobj(ctx, id); + + return (obj != NULL) ? GL_TRUE : GL_FALSE; +} diff --git a/mesalib/src/mesa/main/shaderapi.c b/mesalib/src/mesa/main/shaderapi.c index a5e90d7cb..f2b8aa449 100644 --- a/mesalib/src/mesa/main/shaderapi.c +++ b/mesalib/src/mesa/main/shaderapi.c @@ -48,7 +48,7 @@ #include "program/program.h" #include "program/prog_parameter.h" #include "program/prog_uniform.h" -#include "talloc.h" +#include "ralloc.h" #include #include "../glsl/glsl_parser_extras.h" @@ -1137,9 +1137,9 @@ validate_program(struct gl_context *ctx, GLuint program) if (!shProg->Validated) { /* update info log */ if (shProg->InfoLog) { - talloc_free(shProg->InfoLog); + ralloc_free(shProg->InfoLog); } - shProg->InfoLog = talloc_strdup(shProg, errMsg); + shProg->InfoLog = ralloc_strdup(shProg, errMsg); } } @@ -1855,7 +1855,7 @@ _mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string) #endif } - shProg->InfoLog = talloc_strdup_append(shProg->InfoLog, sh->InfoLog); + ralloc_strcat(&shProg->InfoLog, sh->InfoLog); } delete_shader(ctx, shader); diff --git a/mesalib/src/mesa/main/shaderobj.c b/mesalib/src/mesa/main/shaderobj.c index efee05ac6..1d7584559 100644 --- a/mesalib/src/mesa/main/shaderobj.c +++ b/mesalib/src/mesa/main/shaderobj.c @@ -1,413 +1,413 @@ -/* - * Mesa 3-D graphics library - * - * Copyright (C) 2004-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009-2010 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 shaderobj.c - * \author Brian Paul - * - */ - - -#include "main/glheader.h" -#include "main/context.h" -#include "main/hash.h" -#include "main/mfeatures.h" -#include "main/mtypes.h" -#include "main/shaderobj.h" -#include "program/program.h" -#include "program/prog_parameter.h" -#include "program/prog_uniform.h" -#include "talloc.h" - -/**********************************************************************/ -/*** Shader object functions ***/ -/**********************************************************************/ - - -/** - * Set ptr to point to sh. - * If ptr is pointing to another shader, decrement its refcount (and delete - * if refcount hits zero). - * Then set ptr to point to sh, incrementing its refcount. - */ -void -_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr, - struct gl_shader *sh) -{ - assert(ptr); - if (*ptr == sh) { - /* no-op */ - return; - } - if (*ptr) { - /* Unreference the old shader */ - GLboolean deleteFlag = GL_FALSE; - struct gl_shader *old = *ptr; - - ASSERT(old->RefCount > 0); - old->RefCount--; - /*printf("SHADER DECR %p (%d) to %d\n", - (void*) old, old->Name, old->RefCount);*/ - deleteFlag = (old->RefCount == 0); - - if (deleteFlag) { - _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name); - ctx->Driver.DeleteShader(ctx, old); - } - - *ptr = NULL; - } - assert(!*ptr); - - if (sh) { - /* reference new */ - sh->RefCount++; - /*printf("SHADER INCR %p (%d) to %d\n", - (void*) sh, sh->Name, sh->RefCount);*/ - *ptr = sh; - } -} - -void -_mesa_init_shader(struct gl_context *ctx, struct gl_shader *shader) -{ - shader->RefCount = 1; -} - -/** - * Allocate a new gl_shader object, initialize it. - * Called via ctx->Driver.NewShader() - */ -struct gl_shader * -_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type) -{ - struct gl_shader *shader; - assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER || - type == GL_GEOMETRY_SHADER_ARB); - shader = talloc_zero(NULL, struct gl_shader); - if (shader) { - shader->Type = type; - shader->Name = name; - _mesa_init_shader(ctx, shader); - } - return shader; -} - - -/** - * Delete a shader object. - * Called via ctx->Driver.DeleteShader(). - */ -static void -_mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh) -{ - if (sh->Source) - free((void *) sh->Source); - _mesa_reference_program(ctx, &sh->Program, NULL); - talloc_free(sh); -} - - -/** - * Lookup a GLSL shader object. - */ -struct gl_shader * -_mesa_lookup_shader(struct gl_context *ctx, GLuint name) -{ - if (name) { - struct gl_shader *sh = (struct gl_shader *) - _mesa_HashLookup(ctx->Shared->ShaderObjects, name); - /* Note that both gl_shader and gl_shader_program objects are kept - * in the same hash table. Check the object's type to be sure it's - * what we're expecting. - */ - if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) { - return NULL; - } - return sh; - } - return NULL; -} - - -/** - * As above, but record an error if shader is not found. - */ -struct gl_shader * -_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller) -{ - if (!name) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); - return NULL; - } - else { - struct gl_shader *sh = (struct gl_shader *) - _mesa_HashLookup(ctx->Shared->ShaderObjects, name); - if (!sh) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); - return NULL; - } - if (sh->Type == GL_SHADER_PROGRAM_MESA) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); - return NULL; - } - return sh; - } -} - - - -/**********************************************************************/ -/*** Shader Program object functions ***/ -/**********************************************************************/ - - -/** - * Set ptr to point to shProg. - * If ptr is pointing to another object, decrement its refcount (and delete - * if refcount hits zero). - * Then set ptr to point to shProg, incrementing its refcount. - */ -void -_mesa_reference_shader_program(struct gl_context *ctx, - struct gl_shader_program **ptr, - struct gl_shader_program *shProg) -{ - assert(ptr); - if (*ptr == shProg) { - /* no-op */ - return; - } - if (*ptr) { - /* Unreference the old shader program */ - GLboolean deleteFlag = GL_FALSE; - struct gl_shader_program *old = *ptr; - - ASSERT(old->RefCount > 0); - old->RefCount--; -#if 0 - printf("ShaderProgram %p ID=%u RefCount-- to %d\n", - (void *) old, old->Name, old->RefCount); -#endif - deleteFlag = (old->RefCount == 0); - - if (deleteFlag) { - _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name); - ctx->Driver.DeleteShaderProgram(ctx, old); - } - - *ptr = NULL; - } - assert(!*ptr); - - if (shProg) { - shProg->RefCount++; -#if 0 - printf("ShaderProgram %p ID=%u RefCount++ to %d\n", - (void *) shProg, shProg->Name, shProg->RefCount); -#endif - *ptr = shProg; - } -} - -void -_mesa_init_shader_program(struct gl_context *ctx, struct gl_shader_program *prog) -{ - prog->Type = GL_SHADER_PROGRAM_MESA; - prog->RefCount = 1; - prog->Attributes = _mesa_new_parameter_list(); -#if FEATURE_ARB_geometry_shader4 - prog->Geom.VerticesOut = 0; - prog->Geom.InputType = GL_TRIANGLES; - prog->Geom.OutputType = GL_TRIANGLE_STRIP; -#endif -} - -/** - * Allocate a new gl_shader_program object, initialize it. - * Called via ctx->Driver.NewShaderProgram() - */ -static struct gl_shader_program * -_mesa_new_shader_program(struct gl_context *ctx, GLuint name) -{ - struct gl_shader_program *shProg; - shProg = talloc_zero(NULL, struct gl_shader_program); - if (shProg) { - shProg->Name = name; - _mesa_init_shader_program(ctx, shProg); - } - return shProg; -} - - -/** - * Clear (free) the shader program state that gets produced by linking. - */ -void -_mesa_clear_shader_program_data(struct gl_context *ctx, - struct gl_shader_program *shProg) -{ - _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL); - _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL); - _mesa_reference_geomprog(ctx, &shProg->GeometryProgram, NULL); - - if (shProg->Uniforms) { - _mesa_free_uniform_list(shProg->Uniforms); - shProg->Uniforms = NULL; - } - - if (shProg->Varying) { - _mesa_free_parameter_list(shProg->Varying); - shProg->Varying = NULL; - } -} - - -/** - * Free all the data that hangs off a shader program object, but not the - * object itself. - */ -void -_mesa_free_shader_program_data(struct gl_context *ctx, - struct gl_shader_program *shProg) -{ - GLuint i; - gl_shader_type sh; - - assert(shProg->Type == GL_SHADER_PROGRAM_MESA); - - _mesa_clear_shader_program_data(ctx, shProg); - - if (shProg->Attributes) { - _mesa_free_parameter_list(shProg->Attributes); - shProg->Attributes = NULL; - } - - /* detach shaders */ - for (i = 0; i < shProg->NumShaders; i++) { - _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); - } - shProg->NumShaders = 0; - - if (shProg->Shaders) { - free(shProg->Shaders); - shProg->Shaders = NULL; - } - - if (shProg->InfoLog) { - talloc_free(shProg->InfoLog); - shProg->InfoLog = NULL; - } - - /* Transform feedback varying vars */ - for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) { - free(shProg->TransformFeedback.VaryingNames[i]); - } - free(shProg->TransformFeedback.VaryingNames); - shProg->TransformFeedback.VaryingNames = NULL; - shProg->TransformFeedback.NumVarying = 0; - - - for (sh = 0; sh < MESA_SHADER_TYPES; sh++) { - if (shProg->_LinkedShaders[sh] != NULL) { - ctx->Driver.DeleteShader(ctx, shProg->_LinkedShaders[sh]); - shProg->_LinkedShaders[sh] = NULL; - } - } -} - - -/** - * Free/delete a shader program object. - * Called via ctx->Driver.DeleteShaderProgram(). - */ -static void -_mesa_delete_shader_program(struct gl_context *ctx, struct gl_shader_program *shProg) -{ - _mesa_free_shader_program_data(ctx, shProg); - - talloc_free(shProg); -} - - -/** - * Lookup a GLSL program object. - */ -struct gl_shader_program * -_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name) -{ - struct gl_shader_program *shProg; - if (name) { - shProg = (struct gl_shader_program *) - _mesa_HashLookup(ctx->Shared->ShaderObjects, name); - /* Note that both gl_shader and gl_shader_program objects are kept - * in the same hash table. Check the object's type to be sure it's - * what we're expecting. - */ - if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) { - return NULL; - } - return shProg; - } - return NULL; -} - - -/** - * As above, but record an error if program is not found. - */ -struct gl_shader_program * -_mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name, - const char *caller) -{ - if (!name) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); - return NULL; - } - else { - struct gl_shader_program *shProg = (struct gl_shader_program *) - _mesa_HashLookup(ctx->Shared->ShaderObjects, name); - if (!shProg) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); - return NULL; - } - if (shProg->Type != GL_SHADER_PROGRAM_MESA) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); - return NULL; - } - return shProg; - } -} - - -void -_mesa_init_shader_object_functions(struct dd_function_table *driver) -{ - driver->NewShader = _mesa_new_shader; - driver->DeleteShader = _mesa_delete_shader; - driver->NewShaderProgram = _mesa_new_shader_program; - driver->DeleteShaderProgram = _mesa_delete_shader_program; - driver->CompileShader = _mesa_ir_compile_shader; - driver->LinkShader = _mesa_ir_link_shader; -} +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2004-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009-2010 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 shaderobj.c + * \author Brian Paul + * + */ + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/hash.h" +#include "main/mfeatures.h" +#include "main/mtypes.h" +#include "main/shaderobj.h" +#include "program/program.h" +#include "program/prog_parameter.h" +#include "program/prog_uniform.h" +#include "ralloc.h" + +/**********************************************************************/ +/*** Shader object functions ***/ +/**********************************************************************/ + + +/** + * Set ptr to point to sh. + * If ptr is pointing to another shader, decrement its refcount (and delete + * if refcount hits zero). + * Then set ptr to point to sh, incrementing its refcount. + */ +void +_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr, + struct gl_shader *sh) +{ + assert(ptr); + if (*ptr == sh) { + /* no-op */ + return; + } + if (*ptr) { + /* Unreference the old shader */ + GLboolean deleteFlag = GL_FALSE; + struct gl_shader *old = *ptr; + + ASSERT(old->RefCount > 0); + old->RefCount--; + /*printf("SHADER DECR %p (%d) to %d\n", + (void*) old, old->Name, old->RefCount);*/ + deleteFlag = (old->RefCount == 0); + + if (deleteFlag) { + _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name); + ctx->Driver.DeleteShader(ctx, old); + } + + *ptr = NULL; + } + assert(!*ptr); + + if (sh) { + /* reference new */ + sh->RefCount++; + /*printf("SHADER INCR %p (%d) to %d\n", + (void*) sh, sh->Name, sh->RefCount);*/ + *ptr = sh; + } +} + +void +_mesa_init_shader(struct gl_context *ctx, struct gl_shader *shader) +{ + shader->RefCount = 1; +} + +/** + * Allocate a new gl_shader object, initialize it. + * Called via ctx->Driver.NewShader() + */ +struct gl_shader * +_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type) +{ + struct gl_shader *shader; + assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER || + type == GL_GEOMETRY_SHADER_ARB); + shader = rzalloc(NULL, struct gl_shader); + if (shader) { + shader->Type = type; + shader->Name = name; + _mesa_init_shader(ctx, shader); + } + return shader; +} + + +/** + * Delete a shader object. + * Called via ctx->Driver.DeleteShader(). + */ +static void +_mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh) +{ + if (sh->Source) + free((void *) sh->Source); + _mesa_reference_program(ctx, &sh->Program, NULL); + ralloc_free(sh); +} + + +/** + * Lookup a GLSL shader object. + */ +struct gl_shader * +_mesa_lookup_shader(struct gl_context *ctx, GLuint name) +{ + if (name) { + struct gl_shader *sh = (struct gl_shader *) + _mesa_HashLookup(ctx->Shared->ShaderObjects, name); + /* Note that both gl_shader and gl_shader_program objects are kept + * in the same hash table. Check the object's type to be sure it's + * what we're expecting. + */ + if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) { + return NULL; + } + return sh; + } + return NULL; +} + + +/** + * As above, but record an error if shader is not found. + */ +struct gl_shader * +_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller) +{ + if (!name) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); + return NULL; + } + else { + struct gl_shader *sh = (struct gl_shader *) + _mesa_HashLookup(ctx->Shared->ShaderObjects, name); + if (!sh) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); + return NULL; + } + if (sh->Type == GL_SHADER_PROGRAM_MESA) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); + return NULL; + } + return sh; + } +} + + + +/**********************************************************************/ +/*** Shader Program object functions ***/ +/**********************************************************************/ + + +/** + * Set ptr to point to shProg. + * If ptr is pointing to another object, decrement its refcount (and delete + * if refcount hits zero). + * Then set ptr to point to shProg, incrementing its refcount. + */ +void +_mesa_reference_shader_program(struct gl_context *ctx, + struct gl_shader_program **ptr, + struct gl_shader_program *shProg) +{ + assert(ptr); + if (*ptr == shProg) { + /* no-op */ + return; + } + if (*ptr) { + /* Unreference the old shader program */ + GLboolean deleteFlag = GL_FALSE; + struct gl_shader_program *old = *ptr; + + ASSERT(old->RefCount > 0); + old->RefCount--; +#if 0 + printf("ShaderProgram %p ID=%u RefCount-- to %d\n", + (void *) old, old->Name, old->RefCount); +#endif + deleteFlag = (old->RefCount == 0); + + if (deleteFlag) { + _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name); + ctx->Driver.DeleteShaderProgram(ctx, old); + } + + *ptr = NULL; + } + assert(!*ptr); + + if (shProg) { + shProg->RefCount++; +#if 0 + printf("ShaderProgram %p ID=%u RefCount++ to %d\n", + (void *) shProg, shProg->Name, shProg->RefCount); +#endif + *ptr = shProg; + } +} + +void +_mesa_init_shader_program(struct gl_context *ctx, struct gl_shader_program *prog) +{ + prog->Type = GL_SHADER_PROGRAM_MESA; + prog->RefCount = 1; + prog->Attributes = _mesa_new_parameter_list(); +#if FEATURE_ARB_geometry_shader4 + prog->Geom.VerticesOut = 0; + prog->Geom.InputType = GL_TRIANGLES; + prog->Geom.OutputType = GL_TRIANGLE_STRIP; +#endif +} + +/** + * Allocate a new gl_shader_program object, initialize it. + * Called via ctx->Driver.NewShaderProgram() + */ +static struct gl_shader_program * +_mesa_new_shader_program(struct gl_context *ctx, GLuint name) +{ + struct gl_shader_program *shProg; + shProg = rzalloc(NULL, struct gl_shader_program); + if (shProg) { + shProg->Name = name; + _mesa_init_shader_program(ctx, shProg); + } + return shProg; +} + + +/** + * Clear (free) the shader program state that gets produced by linking. + */ +void +_mesa_clear_shader_program_data(struct gl_context *ctx, + struct gl_shader_program *shProg) +{ + _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL); + _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL); + _mesa_reference_geomprog(ctx, &shProg->GeometryProgram, NULL); + + if (shProg->Uniforms) { + _mesa_free_uniform_list(shProg->Uniforms); + shProg->Uniforms = NULL; + } + + if (shProg->Varying) { + _mesa_free_parameter_list(shProg->Varying); + shProg->Varying = NULL; + } +} + + +/** + * Free all the data that hangs off a shader program object, but not the + * object itself. + */ +void +_mesa_free_shader_program_data(struct gl_context *ctx, + struct gl_shader_program *shProg) +{ + GLuint i; + gl_shader_type sh; + + assert(shProg->Type == GL_SHADER_PROGRAM_MESA); + + _mesa_clear_shader_program_data(ctx, shProg); + + if (shProg->Attributes) { + _mesa_free_parameter_list(shProg->Attributes); + shProg->Attributes = NULL; + } + + /* detach shaders */ + for (i = 0; i < shProg->NumShaders; i++) { + _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); + } + shProg->NumShaders = 0; + + if (shProg->Shaders) { + free(shProg->Shaders); + shProg->Shaders = NULL; + } + + if (shProg->InfoLog) { + ralloc_free(shProg->InfoLog); + shProg->InfoLog = NULL; + } + + /* Transform feedback varying vars */ + for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) { + free(shProg->TransformFeedback.VaryingNames[i]); + } + free(shProg->TransformFeedback.VaryingNames); + shProg->TransformFeedback.VaryingNames = NULL; + shProg->TransformFeedback.NumVarying = 0; + + + for (sh = 0; sh < MESA_SHADER_TYPES; sh++) { + if (shProg->_LinkedShaders[sh] != NULL) { + ctx->Driver.DeleteShader(ctx, shProg->_LinkedShaders[sh]); + shProg->_LinkedShaders[sh] = NULL; + } + } +} + + +/** + * Free/delete a shader program object. + * Called via ctx->Driver.DeleteShaderProgram(). + */ +static void +_mesa_delete_shader_program(struct gl_context *ctx, struct gl_shader_program *shProg) +{ + _mesa_free_shader_program_data(ctx, shProg); + + ralloc_free(shProg); +} + + +/** + * Lookup a GLSL program object. + */ +struct gl_shader_program * +_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name) +{ + struct gl_shader_program *shProg; + if (name) { + shProg = (struct gl_shader_program *) + _mesa_HashLookup(ctx->Shared->ShaderObjects, name); + /* Note that both gl_shader and gl_shader_program objects are kept + * in the same hash table. Check the object's type to be sure it's + * what we're expecting. + */ + if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) { + return NULL; + } + return shProg; + } + return NULL; +} + + +/** + * As above, but record an error if program is not found. + */ +struct gl_shader_program * +_mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name, + const char *caller) +{ + if (!name) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); + return NULL; + } + else { + struct gl_shader_program *shProg = (struct gl_shader_program *) + _mesa_HashLookup(ctx->Shared->ShaderObjects, name); + if (!shProg) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); + return NULL; + } + if (shProg->Type != GL_SHADER_PROGRAM_MESA) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); + return NULL; + } + return shProg; + } +} + + +void +_mesa_init_shader_object_functions(struct dd_function_table *driver) +{ + driver->NewShader = _mesa_new_shader; + driver->DeleteShader = _mesa_delete_shader; + driver->NewShaderProgram = _mesa_new_shader_program; + driver->DeleteShaderProgram = _mesa_delete_shader_program; + driver->CompileShader = _mesa_ir_compile_shader; + driver->LinkShader = _mesa_ir_link_shader; +} diff --git a/mesalib/src/mesa/program/ir_to_mesa.cpp b/mesalib/src/mesa/program/ir_to_mesa.cpp index 404b6c646..3794c0de0 100644 --- a/mesalib/src/mesa/program/ir_to_mesa.cpp +++ b/mesalib/src/mesa/program/ir_to_mesa.cpp @@ -105,13 +105,13 @@ extern ir_to_mesa_src_reg ir_to_mesa_undef; class ir_to_mesa_instruction : public exec_node { public: - /* Callers of this talloc-based new need not call delete. It's - * easier to just talloc_free 'ctx' (or any of its ancestors). */ + /* Callers of this ralloc-based new need not call delete. It's + * easier to just ralloc_free 'ctx' (or any of its ancestors). */ static void* operator new(size_t size, void *ctx) { void *node; - node = talloc_zero_size(ctx, size); + node = rzalloc_size(ctx, size); assert(node != NULL); return node; @@ -318,7 +318,7 @@ fail_link(struct gl_shader_program *prog, const char *fmt, ...) { va_list args; va_start(args, fmt); - prog->InfoLog = talloc_vasprintf_append(prog->InfoLog, fmt, args); + ralloc_vasprintf_append(&prog->InfoLog, fmt, args); va_end(args); prog->LinkStatus = GL_FALSE; @@ -1570,7 +1570,7 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) this->result, src_reg_for_float(element_size)); } - src_reg.reladdr = talloc(mem_ctx, ir_to_mesa_src_reg); + src_reg.reladdr = ralloc(mem_ctx, ir_to_mesa_src_reg); memcpy(src_reg.reladdr, &index_reg, sizeof(index_reg)); } @@ -1927,7 +1927,7 @@ ir_to_mesa_visitor::get_function_signature(ir_function_signature *sig) return entry; } - entry = talloc(mem_ctx, function_entry); + entry = ralloc(mem_ctx, function_entry); entry->sig = sig; entry->sig_id = this->next_signature_id++; entry->bgn_inst = NULL; @@ -2264,12 +2264,12 @@ ir_to_mesa_visitor::ir_to_mesa_visitor() next_temp = 1; next_signature_id = 1; current_function = NULL; - mem_ctx = talloc_new(NULL); + mem_ctx = ralloc_context(NULL); } ir_to_mesa_visitor::~ir_to_mesa_visitor() { - talloc_free(mem_ctx); + ralloc_free(mem_ctx); } static struct prog_src_register @@ -2318,8 +2318,8 @@ set_branchtargets(ir_to_mesa_visitor *v, } } - if_stack = talloc_zero_array(v->mem_ctx, int, if_count); - loop_stack = talloc_zero_array(v->mem_ctx, int, loop_count); + if_stack = rzalloc_array(v->mem_ctx, int, if_count); + loop_stack = rzalloc_array(v->mem_ctx, int, loop_count); for (i = 0; i < num_instructions; i++) { switch (mesa_instructions[i].Opcode) { @@ -2462,7 +2462,7 @@ add_uniforms_to_parameters_list(struct gl_shader_program *shader_program, unsigned int next_sampler = 0, num_uniforms = 0; struct uniform_sort *sorted_uniforms; - sorted_uniforms = talloc_array(NULL, struct uniform_sort, + sorted_uniforms = ralloc_array(NULL, struct uniform_sort, shader_program->Uniforms->NumUniforms); for (i = 0; i < shader_program->Uniforms->NumUniforms; i++) { @@ -2541,7 +2541,7 @@ add_uniforms_to_parameters_list(struct gl_shader_program *shader_program, } } - talloc_free(sorted_uniforms); + ralloc_free(sorted_uniforms); } static void @@ -2557,7 +2557,7 @@ set_uniform_initializer(struct gl_context *ctx, void *mem_ctx, for (unsigned int i = 0; i < type->length; i++) { const glsl_type *field_type = type->fields.structure[i].type; - const char *field_name = talloc_asprintf(mem_ctx, "%s.%s", name, + const char *field_name = ralloc_asprintf(mem_ctx, "%s.%s", name, type->fields.structure[i].name); set_uniform_initializer(ctx, mem_ctx, shader_program, field_name, field_type, field_constant); @@ -2588,7 +2588,7 @@ set_uniform_initializer(struct gl_context *ctx, void *mem_ctx, void *values; if (element_type->base_type == GLSL_TYPE_BOOL) { - int *conv = talloc_array(mem_ctx, int, element_type->components()); + int *conv = ralloc_array(mem_ctx, int, element_type->components()); for (unsigned int j = 0; j < element_type->components(); j++) { conv[j] = element->value.b[j]; } @@ -2634,14 +2634,14 @@ set_uniform_initializers(struct gl_context *ctx, continue; if (!mem_ctx) - mem_ctx = talloc_new(NULL); + mem_ctx = ralloc_context(NULL); set_uniform_initializer(ctx, mem_ctx, shader_program, var->name, var->type, var->constant_value); } } - talloc_free(mem_ctx); + ralloc_free(mem_ctx); } /* @@ -2667,7 +2667,7 @@ set_uniform_initializers(struct gl_context *ctx, void ir_to_mesa_visitor::copy_propagate(void) { - ir_to_mesa_instruction **acp = talloc_zero_array(mem_ctx, + ir_to_mesa_instruction **acp = rzalloc_array(mem_ctx, ir_to_mesa_instruction *, this->next_temp * 4); @@ -2771,7 +2771,7 @@ ir_to_mesa_visitor::copy_propagate(void) } } - talloc_free(acp); + ralloc_free(acp); } @@ -2870,7 +2870,7 @@ get_mesa_program(struct gl_context *ctx, mesa_instructions = (struct prog_instruction *)calloc(num_instructions, sizeof(*mesa_instructions)); - mesa_instruction_annotation = talloc_array(v.mem_ctx, ir_instruction *, + mesa_instruction_annotation = ralloc_array(v.mem_ctx, ir_instruction *, num_instructions); v.copy_propagate(); @@ -3127,7 +3127,7 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader) _mesa_glsl_lexer_dtor(state); } - talloc_free(shader->ir); + ralloc_free(shader->ir); shader->ir = new(shader) exec_list; if (!state->error && !state->translation_unit.is_empty()) _mesa_ast_to_hir(shader->ir, state); @@ -3174,7 +3174,7 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader) /* Retain any live IR, but trash the rest. */ reparent_ir(shader->ir, shader->ir); - talloc_free(state); + ralloc_free(state); if (shader->CompileStatus) { if (!ctx->Driver.CompileShader(ctx, shader)) diff --git a/mesalib/src/mesa/program/register_allocate.c b/mesalib/src/mesa/program/register_allocate.c index 8992b91b6..95a9bde40 100644 --- a/mesalib/src/mesa/program/register_allocate.c +++ b/mesalib/src/mesa/program/register_allocate.c @@ -1,458 +1,455 @@ -/* - * Copyright © 2010 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. - * - * Authors: - * Eric Anholt - * - */ - -/** @file register_allocate.c - * - * Graph-coloring register allocator. - */ - -#include - -#include "main/imports.h" -#include "main/macros.h" -#include "main/mtypes.h" -#include "register_allocate.h" - -struct ra_reg { - GLboolean *conflicts; - unsigned int *conflict_list; - unsigned int conflict_list_size; - unsigned int num_conflicts; -}; - -struct ra_regs { - struct ra_reg *regs; - unsigned int count; - - struct ra_class **classes; - unsigned int class_count; -}; - -struct ra_class { - GLboolean *regs; - - /** - * p_B in Runeson/Nyström paper. - * - * This is "how many regs are in the set." - */ - unsigned int p; - - /** - * q_B,C in Runeson/Nyström paper. - */ - unsigned int *q; -}; - -struct ra_node { - GLboolean *adjacency; - unsigned int *adjacency_list; - unsigned int class; - unsigned int adjacency_count; - unsigned int reg; - GLboolean in_stack; - float spill_cost; -}; - -struct ra_graph { - struct ra_regs *regs; - /** - * the variables that need register allocation. - */ - struct ra_node *nodes; - unsigned int count; /**< count of nodes. */ - - unsigned int *stack; - unsigned int stack_count; -}; - -struct ra_regs * -ra_alloc_reg_set(unsigned int count) -{ - unsigned int i; - struct ra_regs *regs; - - regs = talloc_zero(NULL, struct ra_regs); - regs->count = count; - regs->regs = talloc_zero_array(regs, struct ra_reg, count); - - for (i = 0; i < count; i++) { - regs->regs[i].conflicts = talloc_zero_array(regs->regs, GLboolean, count); - regs->regs[i].conflicts[i] = GL_TRUE; - - regs->regs[i].conflict_list = talloc_array(regs->regs, unsigned int, 4); - regs->regs[i].conflict_list_size = 4; - regs->regs[i].conflict_list[0] = i; - regs->regs[i].num_conflicts = 1; - } - - return regs; -} - -static void -ra_add_conflict_list(struct ra_regs *regs, unsigned int r1, unsigned int r2) -{ - struct ra_reg *reg1 = ®s->regs[r1]; - - if (reg1->conflict_list_size == reg1->num_conflicts) { - reg1->conflict_list_size *= 2; - reg1->conflict_list = talloc_realloc(regs->regs, - reg1->conflict_list, - unsigned int, - reg1->conflict_list_size); - } - reg1->conflict_list[reg1->num_conflicts++] = r2; - reg1->conflicts[r2] = GL_TRUE; -} - -void -ra_add_reg_conflict(struct ra_regs *regs, unsigned int r1, unsigned int r2) -{ - if (!regs->regs[r1].conflicts[r2]) { - ra_add_conflict_list(regs, r1, r2); - ra_add_conflict_list(regs, r2, r1); - } -} - -unsigned int -ra_alloc_reg_class(struct ra_regs *regs) -{ - struct ra_class *class; - - regs->classes = talloc_realloc(regs->regs, regs->classes, - struct ra_class *, - regs->class_count + 1); - - class = talloc_zero(regs, struct ra_class); - regs->classes[regs->class_count] = class; - - class->regs = talloc_zero_array(class, GLboolean, regs->count); - - return regs->class_count++; -} - -void -ra_class_add_reg(struct ra_regs *regs, unsigned int c, unsigned int r) -{ - struct ra_class *class = regs->classes[c]; - - class->regs[r] = GL_TRUE; - class->p++; -} - -/** - * Must be called after all conflicts and register classes have been - * set up and before the register set is used for allocation. - */ -void -ra_set_finalize(struct ra_regs *regs) -{ - unsigned int b, c; - - for (b = 0; b < regs->class_count; b++) { - regs->classes[b]->q = talloc_array(regs, unsigned int, regs->class_count); - } - - /* Compute, for each class B and C, how many regs of B an - * allocation to C could conflict with. - */ - for (b = 0; b < regs->class_count; b++) { - for (c = 0; c < regs->class_count; c++) { - unsigned int rc; - int max_conflicts = 0; - - for (rc = 0; rc < regs->count; rc++) { - int conflicts = 0; - int i; - - if (!regs->classes[c]->regs[rc]) - continue; - - for (i = 0; i < regs->regs[rc].num_conflicts; i++) { - unsigned int rb = regs->regs[rc].conflict_list[i]; - if (regs->classes[b]->regs[rb]) - conflicts++; - } - max_conflicts = MAX2(max_conflicts, conflicts); - } - regs->classes[b]->q[c] = max_conflicts; - } - } -} - -static void -ra_add_node_adjacency(struct ra_graph *g, unsigned int n1, unsigned int n2) -{ - g->nodes[n1].adjacency[n2] = GL_TRUE; - g->nodes[n1].adjacency_list[g->nodes[n1].adjacency_count] = n2; - g->nodes[n1].adjacency_count++; -} - -struct ra_graph * -ra_alloc_interference_graph(struct ra_regs *regs, unsigned int count) -{ - struct ra_graph *g; - unsigned int i; - - g = talloc_zero(regs, struct ra_graph); - g->regs = regs; - g->nodes = talloc_zero_array(g, struct ra_node, count); - g->count = count; - - g->stack = talloc_zero_array(g, unsigned int, count); - - for (i = 0; i < count; i++) { - g->nodes[i].adjacency = talloc_zero_array(g, GLboolean, count); - g->nodes[i].adjacency_list = talloc_array(g, unsigned int, count); - g->nodes[i].adjacency_count = 0; - ra_add_node_adjacency(g, i, i); - g->nodes[i].reg = ~0; - } - - return g; -} - -void -ra_set_node_class(struct ra_graph *g, - unsigned int n, unsigned int class) -{ - g->nodes[n].class = class; -} - -void -ra_add_node_interference(struct ra_graph *g, - unsigned int n1, unsigned int n2) -{ - if (!g->nodes[n1].adjacency[n2]) { - ra_add_node_adjacency(g, n1, n2); - ra_add_node_adjacency(g, n2, n1); - } -} - -static GLboolean pq_test(struct ra_graph *g, unsigned int n) -{ - unsigned int j; - unsigned int q = 0; - int n_class = g->nodes[n].class; - - for (j = 0; j < g->nodes[n].adjacency_count; j++) { - unsigned int n2 = g->nodes[n].adjacency_list[j]; - unsigned int n2_class = g->nodes[n2].class; - - if (n != n2 && !g->nodes[n2].in_stack) { - q += g->regs->classes[n_class]->q[n2_class]; - } - } - - return q < g->regs->classes[n_class]->p; -} - -/** - * Simplifies the interference graph by pushing all - * trivially-colorable nodes into a stack of nodes to be colored, - * removing them from the graph, and rinsing and repeating. - * - * Returns GL_TRUE if all nodes were removed from the graph. GL_FALSE - * means that either spilling will be required, or optimistic coloring - * should be applied. - */ -GLboolean -ra_simplify(struct ra_graph *g) -{ - GLboolean progress = GL_TRUE; - int i; - - while (progress) { - progress = GL_FALSE; - - for (i = g->count - 1; i >= 0; i--) { - if (g->nodes[i].in_stack) - continue; - - if (pq_test(g, i)) { - g->stack[g->stack_count] = i; - g->stack_count++; - g->nodes[i].in_stack = GL_TRUE; - progress = GL_TRUE; - } - } - } - - for (i = 0; i < g->count; i++) { - if (!g->nodes[i].in_stack) - return GL_FALSE; - } - - return GL_TRUE; -} - -/** - * Pops nodes from the stack back into the graph, coloring them with - * registers as they go. - * - * If all nodes were trivially colorable, then this must succeed. If - * not (optimistic coloring), then it may return GL_FALSE; - */ -GLboolean -ra_select(struct ra_graph *g) -{ - int i; - - while (g->stack_count != 0) { - unsigned int r; - int n = g->stack[g->stack_count - 1]; - struct ra_class *c = g->regs->classes[g->nodes[n].class]; - - /* Find the lowest-numbered reg which is not used by a member - * of the graph adjacent to us. - */ - for (r = 0; r < g->regs->count; r++) { - if (!c->regs[r]) - continue; - - /* Check if any of our neighbors conflict with this register choice. */ - for (i = 0; i < g->nodes[n].adjacency_count; i++) { - unsigned int n2 = g->nodes[n].adjacency_list[i]; - - if (!g->nodes[n2].in_stack && - g->regs->regs[r].conflicts[g->nodes[n2].reg]) { - break; - } - } - if (i == g->nodes[n].adjacency_count) - break; - } - if (r == g->regs->count) - return GL_FALSE; - - g->nodes[n].reg = r; - g->nodes[n].in_stack = GL_FALSE; - g->stack_count--; - } - - return GL_TRUE; -} - -/** - * Optimistic register coloring: Just push the remaining nodes - * on the stack. They'll be colored first in ra_select(), and - * if they succeed then the locally-colorable nodes are still - * locally-colorable and the rest of the register allocation - * will succeed. - */ -void -ra_optimistic_color(struct ra_graph *g) -{ - unsigned int i; - - for (i = 0; i < g->count; i++) { - if (g->nodes[i].in_stack) - continue; - - g->stack[g->stack_count] = i; - g->stack_count++; - g->nodes[i].in_stack = GL_TRUE; - } -} - -GLboolean -ra_allocate_no_spills(struct ra_graph *g) -{ - if (!ra_simplify(g)) { - ra_optimistic_color(g); - } - return ra_select(g); -} - -unsigned int -ra_get_node_reg(struct ra_graph *g, unsigned int n) -{ - return g->nodes[n].reg; -} - -static float -ra_get_spill_benefit(struct ra_graph *g, unsigned int n) -{ - int j; - float benefit = 0; - int n_class = g->nodes[n].class; - - /* Define the benefit of eliminating an interference between n, n2 - * through spilling as q(C, B) / p(C). This is similar to the - * "count number of edges" approach of traditional graph coloring, - * but takes classes into account. - */ - for (j = 0; j < g->nodes[n].adjacency_count; j++) { - unsigned int n2 = g->nodes[n].adjacency_list[j]; - if (n != n2) { - unsigned int n2_class = g->nodes[n2].class; - benefit += ((float)g->regs->classes[n_class]->q[n2_class] / - g->regs->classes[n_class]->p); - } - } - - return benefit; -} - -/** - * Returns a node number to be spilled according to the cost/benefit using - * the pq test, or -1 if there are no spillable nodes. - */ -int -ra_get_best_spill_node(struct ra_graph *g) -{ - unsigned int best_node = -1; - unsigned int best_benefit = 0.0; - unsigned int n; - - for (n = 0; n < g->count; n++) { - float cost = g->nodes[n].spill_cost; - float benefit; - - if (cost <= 0.0) - continue; - - benefit = ra_get_spill_benefit(g, n); - - if (benefit / cost > best_benefit) { - best_benefit = benefit / cost; - best_node = n; - } - } - - return best_node; -} - -/** - * Only nodes with a spill cost set (cost != 0.0) will be considered - * for register spilling. - */ -void -ra_set_node_spill_cost(struct ra_graph *g, unsigned int n, float cost) -{ - g->nodes[n].spill_cost = cost; -} +/* + * Copyright © 2010 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. + * + * Authors: + * Eric Anholt + * + */ + +/** @file register_allocate.c + * + * Graph-coloring register allocator. + */ + +#include + +#include "main/imports.h" +#include "main/macros.h" +#include "main/mtypes.h" +#include "register_allocate.h" + +struct ra_reg { + GLboolean *conflicts; + unsigned int *conflict_list; + unsigned int conflict_list_size; + unsigned int num_conflicts; +}; + +struct ra_regs { + struct ra_reg *regs; + unsigned int count; + + struct ra_class **classes; + unsigned int class_count; +}; + +struct ra_class { + GLboolean *regs; + + /** + * p_B in Runeson/Nyström paper. + * + * This is "how many regs are in the set." + */ + unsigned int p; + + /** + * q_B,C in Runeson/Nyström paper. + */ + unsigned int *q; +}; + +struct ra_node { + GLboolean *adjacency; + unsigned int *adjacency_list; + unsigned int class; + unsigned int adjacency_count; + unsigned int reg; + GLboolean in_stack; + float spill_cost; +}; + +struct ra_graph { + struct ra_regs *regs; + /** + * the variables that need register allocation. + */ + struct ra_node *nodes; + unsigned int count; /**< count of nodes. */ + + unsigned int *stack; + unsigned int stack_count; +}; + +struct ra_regs * +ra_alloc_reg_set(unsigned int count) +{ + unsigned int i; + struct ra_regs *regs; + + regs = rzalloc(NULL, struct ra_regs); + regs->count = count; + regs->regs = rzalloc_array(regs, struct ra_reg, count); + + for (i = 0; i < count; i++) { + regs->regs[i].conflicts = rzalloc_array(regs->regs, GLboolean, count); + regs->regs[i].conflicts[i] = GL_TRUE; + + regs->regs[i].conflict_list = ralloc_array(regs->regs, unsigned int, 4); + regs->regs[i].conflict_list_size = 4; + regs->regs[i].conflict_list[0] = i; + regs->regs[i].num_conflicts = 1; + } + + return regs; +} + +static void +ra_add_conflict_list(struct ra_regs *regs, unsigned int r1, unsigned int r2) +{ + struct ra_reg *reg1 = ®s->regs[r1]; + + if (reg1->conflict_list_size == reg1->num_conflicts) { + reg1->conflict_list_size *= 2; + reg1->conflict_list = reralloc(regs->regs, reg1->conflict_list, + unsigned int, reg1->conflict_list_size); + } + reg1->conflict_list[reg1->num_conflicts++] = r2; + reg1->conflicts[r2] = GL_TRUE; +} + +void +ra_add_reg_conflict(struct ra_regs *regs, unsigned int r1, unsigned int r2) +{ + if (!regs->regs[r1].conflicts[r2]) { + ra_add_conflict_list(regs, r1, r2); + ra_add_conflict_list(regs, r2, r1); + } +} + +unsigned int +ra_alloc_reg_class(struct ra_regs *regs) +{ + struct ra_class *class; + + regs->classes = reralloc(regs->regs, regs->classes, struct ra_class *, + regs->class_count + 1); + + class = rzalloc(regs, struct ra_class); + regs->classes[regs->class_count] = class; + + class->regs = rzalloc_array(class, GLboolean, regs->count); + + return regs->class_count++; +} + +void +ra_class_add_reg(struct ra_regs *regs, unsigned int c, unsigned int r) +{ + struct ra_class *class = regs->classes[c]; + + class->regs[r] = GL_TRUE; + class->p++; +} + +/** + * Must be called after all conflicts and register classes have been + * set up and before the register set is used for allocation. + */ +void +ra_set_finalize(struct ra_regs *regs) +{ + unsigned int b, c; + + for (b = 0; b < regs->class_count; b++) { + regs->classes[b]->q = ralloc_array(regs, unsigned int, regs->class_count); + } + + /* Compute, for each class B and C, how many regs of B an + * allocation to C could conflict with. + */ + for (b = 0; b < regs->class_count; b++) { + for (c = 0; c < regs->class_count; c++) { + unsigned int rc; + int max_conflicts = 0; + + for (rc = 0; rc < regs->count; rc++) { + int conflicts = 0; + int i; + + if (!regs->classes[c]->regs[rc]) + continue; + + for (i = 0; i < regs->regs[rc].num_conflicts; i++) { + unsigned int rb = regs->regs[rc].conflict_list[i]; + if (regs->classes[b]->regs[rb]) + conflicts++; + } + max_conflicts = MAX2(max_conflicts, conflicts); + } + regs->classes[b]->q[c] = max_conflicts; + } + } +} + +static void +ra_add_node_adjacency(struct ra_graph *g, unsigned int n1, unsigned int n2) +{ + g->nodes[n1].adjacency[n2] = GL_TRUE; + g->nodes[n1].adjacency_list[g->nodes[n1].adjacency_count] = n2; + g->nodes[n1].adjacency_count++; +} + +struct ra_graph * +ra_alloc_interference_graph(struct ra_regs *regs, unsigned int count) +{ + struct ra_graph *g; + unsigned int i; + + g = rzalloc(regs, struct ra_graph); + g->regs = regs; + g->nodes = rzalloc_array(g, struct ra_node, count); + g->count = count; + + g->stack = rzalloc_array(g, unsigned int, count); + + for (i = 0; i < count; i++) { + g->nodes[i].adjacency = rzalloc_array(g, GLboolean, count); + g->nodes[i].adjacency_list = ralloc_array(g, unsigned int, count); + g->nodes[i].adjacency_count = 0; + ra_add_node_adjacency(g, i, i); + g->nodes[i].reg = ~0; + } + + return g; +} + +void +ra_set_node_class(struct ra_graph *g, + unsigned int n, unsigned int class) +{ + g->nodes[n].class = class; +} + +void +ra_add_node_interference(struct ra_graph *g, + unsigned int n1, unsigned int n2) +{ + if (!g->nodes[n1].adjacency[n2]) { + ra_add_node_adjacency(g, n1, n2); + ra_add_node_adjacency(g, n2, n1); + } +} + +static GLboolean pq_test(struct ra_graph *g, unsigned int n) +{ + unsigned int j; + unsigned int q = 0; + int n_class = g->nodes[n].class; + + for (j = 0; j < g->nodes[n].adjacency_count; j++) { + unsigned int n2 = g->nodes[n].adjacency_list[j]; + unsigned int n2_class = g->nodes[n2].class; + + if (n != n2 && !g->nodes[n2].in_stack) { + q += g->regs->classes[n_class]->q[n2_class]; + } + } + + return q < g->regs->classes[n_class]->p; +} + +/** + * Simplifies the interference graph by pushing all + * trivially-colorable nodes into a stack of nodes to be colored, + * removing them from the graph, and rinsing and repeating. + * + * Returns GL_TRUE if all nodes were removed from the graph. GL_FALSE + * means that either spilling will be required, or optimistic coloring + * should be applied. + */ +GLboolean +ra_simplify(struct ra_graph *g) +{ + GLboolean progress = GL_TRUE; + int i; + + while (progress) { + progress = GL_FALSE; + + for (i = g->count - 1; i >= 0; i--) { + if (g->nodes[i].in_stack) + continue; + + if (pq_test(g, i)) { + g->stack[g->stack_count] = i; + g->stack_count++; + g->nodes[i].in_stack = GL_TRUE; + progress = GL_TRUE; + } + } + } + + for (i = 0; i < g->count; i++) { + if (!g->nodes[i].in_stack) + return GL_FALSE; + } + + return GL_TRUE; +} + +/** + * Pops nodes from the stack back into the graph, coloring them with + * registers as they go. + * + * If all nodes were trivially colorable, then this must succeed. If + * not (optimistic coloring), then it may return GL_FALSE; + */ +GLboolean +ra_select(struct ra_graph *g) +{ + int i; + + while (g->stack_count != 0) { + unsigned int r; + int n = g->stack[g->stack_count - 1]; + struct ra_class *c = g->regs->classes[g->nodes[n].class]; + + /* Find the lowest-numbered reg which is not used by a member + * of the graph adjacent to us. + */ + for (r = 0; r < g->regs->count; r++) { + if (!c->regs[r]) + continue; + + /* Check if any of our neighbors conflict with this register choice. */ + for (i = 0; i < g->nodes[n].adjacency_count; i++) { + unsigned int n2 = g->nodes[n].adjacency_list[i]; + + if (!g->nodes[n2].in_stack && + g->regs->regs[r].conflicts[g->nodes[n2].reg]) { + break; + } + } + if (i == g->nodes[n].adjacency_count) + break; + } + if (r == g->regs->count) + return GL_FALSE; + + g->nodes[n].reg = r; + g->nodes[n].in_stack = GL_FALSE; + g->stack_count--; + } + + return GL_TRUE; +} + +/** + * Optimistic register coloring: Just push the remaining nodes + * on the stack. They'll be colored first in ra_select(), and + * if they succeed then the locally-colorable nodes are still + * locally-colorable and the rest of the register allocation + * will succeed. + */ +void +ra_optimistic_color(struct ra_graph *g) +{ + unsigned int i; + + for (i = 0; i < g->count; i++) { + if (g->nodes[i].in_stack) + continue; + + g->stack[g->stack_count] = i; + g->stack_count++; + g->nodes[i].in_stack = GL_TRUE; + } +} + +GLboolean +ra_allocate_no_spills(struct ra_graph *g) +{ + if (!ra_simplify(g)) { + ra_optimistic_color(g); + } + return ra_select(g); +} + +unsigned int +ra_get_node_reg(struct ra_graph *g, unsigned int n) +{ + return g->nodes[n].reg; +} + +static float +ra_get_spill_benefit(struct ra_graph *g, unsigned int n) +{ + int j; + float benefit = 0; + int n_class = g->nodes[n].class; + + /* Define the benefit of eliminating an interference between n, n2 + * through spilling as q(C, B) / p(C). This is similar to the + * "count number of edges" approach of traditional graph coloring, + * but takes classes into account. + */ + for (j = 0; j < g->nodes[n].adjacency_count; j++) { + unsigned int n2 = g->nodes[n].adjacency_list[j]; + if (n != n2) { + unsigned int n2_class = g->nodes[n2].class; + benefit += ((float)g->regs->classes[n_class]->q[n2_class] / + g->regs->classes[n_class]->p); + } + } + + return benefit; +} + +/** + * Returns a node number to be spilled according to the cost/benefit using + * the pq test, or -1 if there are no spillable nodes. + */ +int +ra_get_best_spill_node(struct ra_graph *g) +{ + unsigned int best_node = -1; + unsigned int best_benefit = 0.0; + unsigned int n; + + for (n = 0; n < g->count; n++) { + float cost = g->nodes[n].spill_cost; + float benefit; + + if (cost <= 0.0) + continue; + + benefit = ra_get_spill_benefit(g, n); + + if (benefit / cost > best_benefit) { + best_benefit = benefit / cost; + best_node = n; + } + } + + return best_node; +} + +/** + * Only nodes with a spill cost set (cost != 0.0) will be considered + * for register spilling. + */ +void +ra_set_node_spill_cost(struct ra_graph *g, unsigned int n, float cost) +{ + g->nodes[n].spill_cost = cost; +} diff --git a/mesalib/src/mesa/program/sampler.cpp b/mesalib/src/mesa/program/sampler.cpp index cd44467a3..12c4a40a2 100644 --- a/mesalib/src/mesa/program/sampler.cpp +++ b/mesalib/src/mesa/program/sampler.cpp @@ -1,140 +1,138 @@ -/* - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. - * Copyright (C) 2008 VMware, Inc. All Rights Reserved. - * Copyright © 2010 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 "ir.h" -#include "glsl_types.h" -#include "ir_visitor.h" - -extern "C" { -#include "main/compiler.h" -#include "main/mtypes.h" -#include "program/prog_parameter.h" -} - -static void fail_link(struct gl_shader_program *prog, const char *fmt, ...) PRINTFLIKE(2, 3); - -static void fail_link(struct gl_shader_program *prog, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - prog->InfoLog = talloc_vasprintf_append(prog->InfoLog, fmt, args); - va_end(args); - - prog->LinkStatus = GL_FALSE; -} - -class get_sampler_name : public ir_hierarchical_visitor -{ -public: - get_sampler_name(ir_dereference *last, - struct gl_shader_program *shader_program) - { - this->mem_ctx = talloc_new(NULL); - this->shader_program = shader_program; - this->name = NULL; - this->offset = 0; - this->last = last; - } - - ~get_sampler_name() - { - talloc_free(this->mem_ctx); - } - - virtual ir_visitor_status visit(ir_dereference_variable *ir) - { - this->name = ir->var->name; - return visit_continue; - } - - virtual ir_visitor_status visit_leave(ir_dereference_record *ir) - { - this->name = talloc_asprintf(mem_ctx, "%s.%s", name, ir->field); - return visit_continue; - } - - virtual ir_visitor_status visit_leave(ir_dereference_array *ir) - { - ir_constant *index = ir->array_index->as_constant(); - int i; - - if (index) { - i = index->value.i[0]; - } else { - /* GLSL 1.10 and 1.20 allowed variable sampler array indices, - * while GLSL 1.30 requires that the array indices be - * constant integer expressions. We don't expect any driver - * to actually work with a really variable array index, so - * all that would work would be an unrolled loop counter that ends - * up being constant above. - */ - shader_program->InfoLog = - talloc_asprintf_append(shader_program->InfoLog, - "warning: Variable sampler array index " - "unsupported.\nThis feature of the language " - "was removed in GLSL 1.20 and is unlikely " - "to be supported for 1.10 in Mesa.\n"); - i = 0; - } - if (ir != last) { - this->name = talloc_asprintf(mem_ctx, "%s[%d]", name, i); - } else { - offset = i; - } - return visit_continue; - } - - struct gl_shader_program *shader_program; - const char *name; - void *mem_ctx; - int offset; - ir_dereference *last; -}; - -extern "C" { -int -_mesa_get_sampler_uniform_value(class ir_dereference *sampler, - struct gl_shader_program *shader_program, - const struct gl_program *prog) -{ - get_sampler_name getname(sampler, shader_program); - - sampler->accept(&getname); - - GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1, - getname.name); - - if (index < 0) { - fail_link(shader_program, - "failed to find sampler named %s.\n", getname.name); - return 0; - } - - index += getname.offset; - - return prog->Parameters->ParameterValues[index][0]; -} -} +/* + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2008 VMware, Inc. All Rights Reserved. + * Copyright © 2010 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 "ir.h" +#include "glsl_types.h" +#include "ir_visitor.h" + +extern "C" { +#include "main/compiler.h" +#include "main/mtypes.h" +#include "program/prog_parameter.h" +} + +static void fail_link(struct gl_shader_program *prog, const char *fmt, ...) PRINTFLIKE(2, 3); + +static void fail_link(struct gl_shader_program *prog, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + ralloc_vasprintf_append(&prog->InfoLog, fmt, args); + va_end(args); + + prog->LinkStatus = GL_FALSE; +} + +class get_sampler_name : public ir_hierarchical_visitor +{ +public: + get_sampler_name(ir_dereference *last, + struct gl_shader_program *shader_program) + { + this->mem_ctx = ralloc_context(NULL); + this->shader_program = shader_program; + this->name = NULL; + this->offset = 0; + this->last = last; + } + + ~get_sampler_name() + { + ralloc_free(this->mem_ctx); + } + + virtual ir_visitor_status visit(ir_dereference_variable *ir) + { + this->name = ir->var->name; + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_dereference_record *ir) + { + this->name = ralloc_asprintf(mem_ctx, "%s.%s", name, ir->field); + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_dereference_array *ir) + { + ir_constant *index = ir->array_index->as_constant(); + int i; + + if (index) { + i = index->value.i[0]; + } else { + /* GLSL 1.10 and 1.20 allowed variable sampler array indices, + * while GLSL 1.30 requires that the array indices be + * constant integer expressions. We don't expect any driver + * to actually work with a really variable array index, so + * all that would work would be an unrolled loop counter that ends + * up being constant above. + */ + ralloc_strcat(&shader_program->InfoLog, + "warning: Variable sampler array index unsupported.\n" + "This feature of the language was removed in GLSL 1.20 " + "and is unlikely to be supported for 1.10 in Mesa.\n"); + i = 0; + } + if (ir != last) { + this->name = ralloc_asprintf(mem_ctx, "%s[%d]", name, i); + } else { + offset = i; + } + return visit_continue; + } + + struct gl_shader_program *shader_program; + const char *name; + void *mem_ctx; + int offset; + ir_dereference *last; +}; + +extern "C" { +int +_mesa_get_sampler_uniform_value(class ir_dereference *sampler, + struct gl_shader_program *shader_program, + const struct gl_program *prog) +{ + get_sampler_name getname(sampler, shader_program); + + sampler->accept(&getname); + + GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1, + getname.name); + + if (index < 0) { + fail_link(shader_program, + "failed to find sampler named %s.\n", getname.name); + return 0; + } + + index += getname.offset; + + return prog->Parameters->ParameterValues[index][0]; +} +} -- cgit v1.2.3