diff options
Diffstat (limited to 'src/mesa')
152 files changed, 20489 insertions, 665 deletions
diff --git a/src/mesa/Makefile b/src/mesa/Makefile index ba65ce695f..2fba2e153b 100644 --- a/src/mesa/Makefile +++ b/src/mesa/Makefile @@ -3,8 +3,7 @@ TOP = ../.. include $(TOP)/configs/current -include sources - +include sources.mak .SUFFIXES : .cpp @@ -24,6 +23,9 @@ include sources default: depend asm_subdirs libmesa.a libglapi.a driver_subdirs +# Default: build dependencies, then asm_subdirs, then convenience +# libs (.a) and finally the device drivers: +default: depend asm_subdirs libmesa.a $(GLAPI_LIB) driver_subdirs ###################################################################### # Helper libraries used by many drivers: @@ -36,6 +38,13 @@ libmesa.a: $(MESA_OBJECTS) libglapi.a: $(GLAPI_OBJECTS) @ $(MKLIB) -o glapi -static $(GLAPI_OBJECTS) +# Make archive of gl* API dispatcher functions only +$(GLAPI_LIB): $(GLAPI_OBJECTS) + @if [ "${WINDOW_SYSTEM}" = "dri" ] ; then \ + touch libglapi.a ; \ + else \ + $(TOP)/bin/mklib -o glapi -static $(GLAPI_OBJECTS) ; \ + fi ###################################################################### # Device drivers diff --git a/src/mesa/Makefile.DJ b/src/mesa/Makefile.DJ deleted file mode 100644 index 06a13fb1ab..0000000000 --- a/src/mesa/Makefile.DJ +++ /dev/null @@ -1,166 +0,0 @@ -# Mesa 3-D graphics library -# Version: 5.1 -# -# Copyright (C) 1999-2003 Brian Paul All Rights Reserved. -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -# DOS/DJGPP core makefile v1.7 for Mesa -# -# Copyright (C) 2002 - Daniel Borca -# Email : dborca@users.sourceforge.net -# Web : http://www.geocities.com/dborca - - -# -# Available options: -# -# Environment variables: -# CFLAGS -# -# GLIDE path to Glide3 SDK; used with FX. -# default = $(TOP)/glide3 -# FX=1 build for 3dfx Glide3. Note that this disables -# compilation of most DMesa code and requires fxMesa. -# As a consequence, you'll need the DJGPP Glide3 -# library to build any application. -# default = no -# X86=1 optimize for x86 (if possible, use MMX, SSE, 3DNow). -# default = no -# -# Targets: -# all: build GL -# clean: remove object files -# - - - -.PHONY: all clean -.INTERMEDIATE: x86/gen_matypes.exe - -TOP = ../.. -GLIDE ?= $(TOP)/glide3 -LIBDIR = $(TOP)/lib -GL_LIB = libgl.a -GL_DXE = gl.dxe -GL_IMP = libigl.a - -export LD_LIBRARY_PATH := $(LD_LIBRARY_PATH);$(LIBDIR);$(GLIDE)/lib - -CC = gcc -CFLAGS += $(INCLUDE_DIRS) -CFLAGS += -DUSE_EXTERNAL_DXTN_LIB=1 -ifeq ($(FX),1) -CFLAGS += -D__DOS__ -CFLAGS += -I$(GLIDE)/include -DFX -LIBNAME = "Mesa/FX DJGPP" -else -LIBNAME = "Mesa DJGPP" -endif - -AR = ar -ARFLAGS = crus - -HAVEDXE3 = $(wildcard $(DJDIR)/bin/dxe3gen.exe) - -ifeq ($(wildcard $(addsuffix /rm.exe,$(subst ;, ,$(PATH)))),) -UNLINK = del $(subst /,\,$(1)) -else -UNLINK = $(RM) $(1) -endif - -include sources - -ifeq ($(X86),1) -CFLAGS += -DUSE_X86_ASM -CFLAGS += -DUSE_MMX_ASM -CFLAGS += -DUSE_SSE_ASM -CFLAGS += -DUSE_3DNOW_ASM -X86_SOURCES += $(X86_API) -else -X86_SOURCES = -endif - -DRIVER_SOURCES = \ - drivers/dos/dmesa.c -ifeq ($(FX),1) -DRIVER_SOURCES += \ - $(GLIDE_DRIVER_SOURCES) -else -DRIVER_SOURCES += \ - $(OSMESA_DRIVER_SOURCES) \ - drivers/dos/video.c \ - drivers/dos/vesa.c \ - drivers/dos/blit.S \ - drivers/dos/vga.c \ - drivers/dos/null.c \ - drivers/dos/dpmi.c -endif - -SOURCES = $(CORE_SOURCES) $(X86_SOURCES) $(COMMON_DRIVER_SOURCES) $(DRIVER_SOURCES) - -OBJECTS = $(addsuffix .o,$(basename $(SOURCES))) - -X86_OBJECTS = $(addsuffix .o,$(basename $(X86_SOURCES))) - -.c.o: - $(CC) -o $@ $(CFLAGS) -c $< -.S.o: - $(CC) -o $@ $(CFLAGS) -c $< -.s.o: - $(CC) -o $@ $(CFLAGS) -x assembler-with-cpp -c $< - -all: $(LIBDIR)/$(GL_LIB) $(LIBDIR)/$(GL_DXE) $(LIBDIR)/$(GL_IMP) - -$(LIBDIR)/$(GL_LIB): $(OBJECTS) - $(AR) $(ARFLAGS) $@ $^ - -$(LIBDIR)/$(GL_DXE) $(LIBDIR)/$(GL_IMP): $(OBJECTS) -ifeq ($(HAVEDXE3),) - $(warning Missing DXE3 package... Skipping $(GL_DXE)) -else -ifeq ($(FX),1) - -dxe3gen -o $(LIBDIR)/$(GL_DXE) -Y $(LIBDIR)/$(GL_IMP) -D $(LIBNAME) -E _gl -E _DMesa -P glide3x.dxe -U $^ -else - -dxe3gen -o $(LIBDIR)/$(GL_DXE) -Y $(LIBDIR)/$(GL_IMP) -D $(LIBNAME) -E _gl -E _DMesa -U $^ -endif -endif - -$(X86_OBJECTS): x86/matypes.h - -x86/matypes.h: x86/gen_matypes.exe - $< > $@ - -x86/gen_matypes.exe: x86/gen_matypes.c - $(CC) -o $@ $(CFLAGS) -s $< - -clean: - -$(call UNLINK,array_cache/*.o) - -$(call UNLINK,glapi/*.o) - -$(call UNLINK,main/*.o) - -$(call UNLINK,math/*.o) - -$(call UNLINK,shader/*.o) - -$(call UNLINK,sparc/*.o) - -$(call UNLINK,ppc/*.o) - -$(call UNLINK,swrast/*.o) - -$(call UNLINK,swrast_setup/*.o) - -$(call UNLINK,tnl/*.o) - -$(call UNLINK,x86/*.o) - -$(call UNLINK,drivers/common/*.o) - -$(call UNLINK,drivers/dos/*.o) - -$(call UNLINK,drivers/glide/*.o) diff --git a/src/mesa/Makefile.mgw b/src/mesa/Makefile.mgw index 886b344ec9..097c390a83 100644 --- a/src/mesa/Makefile.mgw +++ b/src/mesa/Makefile.mgw @@ -124,7 +124,7 @@ ifneq ($(wildcard $(addsuffix /rm,$(subst :, ,$(PATH)))),) UNLINK = $(RM) $(1) endif -include sources +include sources.mak CFLAGS += $(INCLUDE_DIRS) diff --git a/src/mesa/SConscript b/src/mesa/SConscript new file mode 100644 index 0000000000..89b98b37ab --- /dev/null +++ b/src/mesa/SConscript @@ -0,0 +1,339 @@ +####################################################################### +# SConscript for Mesa + + +Import('*') + +if env['platform'] != 'winddk': + + env = env.Clone() + + env.Append(CPPPATH = [ + '#/src/mesa', + ]) + + if gcc: + env.Append(CFLAGS = [ + '-std=c99', + ]) + + # + # 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/attrib.c', + 'main/arrayobj.c', + 'main/blend.c', + 'main/bufferobj.c', + 'main/buffers.c', + 'main/clear.c', + 'main/clip.c', + 'main/colortab.c', + 'main/context.c', + 'main/convolve.c', + 'main/debug.c', + 'main/depth.c', + 'main/depthstencil.c', + 'main/dlist.c', + 'main/drawpix.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/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/pixel.c', + 'main/pixelstore.c', + 'main/points.c', + 'main/polygon.c', + 'main/queryobj.c', + 'main/rastpos.c', + 'main/rbadaptors.c', + 'main/readpix.c', + 'main/renderbuffer.c', + 'main/scissor.c', + 'main/shaders.c', + 'main/state.c', + 'main/stencil.c', + 'main/texcompress.c', + 'main/texcompress_s3tc.c', + 'main/texcompress_fxt1.c', + 'main/texenv.c', + 'main/texenvprogram.c', + 'main/texformat.c', + 'main/texgen.c', + 'main/teximage.c', + 'main/texobj.c', + 'main/texparam.c', + 'main/texrender.c', + 'main/texstate.c', + 'main/texstore.c', + 'main/varray.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_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_flush.c', + 'state_tracker/st_cb_drawpixels.c', + 'state_tracker/st_cb_fbo.c', + 'state_tracker/st_cb_get.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_context.c', + 'state_tracker/st_debug.c', + 'state_tracker/st_draw.c', + 'state_tracker/st_extensions.c', + 'state_tracker/st_format.c', + 'state_tracker/st_framebuffer.c', + 'state_tracker/st_gen_mipmap.c', + 'state_tracker/st_mesa_to_tgsi.c', + 'state_tracker/st_program.c', + 'state_tracker/st_texture.c', + ] + + shader_sources = [ + 'shader/arbprogparse.c', + 'shader/arbprogram.c', + 'shader/atifragshader.c', + 'shader/grammar/grammar_mesa.c', + 'shader/nvfragparse.c', + 'shader/nvprogram.c', + 'shader/nvvertparse.c', + 'shader/program.c', + 'shader/prog_cache.c', + 'shader/prog_debug.c', + 'shader/prog_execute.c', + 'shader/prog_instruction.c', + 'shader/prog_parameter.c', + 'shader/prog_print.c', + 'shader/prog_statevars.c', + 'shader/prog_uniform.c', + 'shader/programopt.c', + 'shader/shader_api.c', + ] + + slang_sources = [ + 'shader/slang/slang_builtin.c', + 'shader/slang/slang_codegen.c', + 'shader/slang/slang_compile.c', + 'shader/slang/slang_compile_function.c', + 'shader/slang/slang_compile_operation.c', + 'shader/slang/slang_compile_struct.c', + 'shader/slang/slang_compile_variable.c', + 'shader/slang/slang_emit.c', + 'shader/slang/slang_ir.c', + 'shader/slang/slang_label.c', + 'shader/slang/slang_library_noise.c', + 'shader/slang/slang_link.c', + 'shader/slang/slang_log.c', + 'shader/slang/slang_mem.c', + 'shader/slang/slang_preprocess.c', + 'shader/slang/slang_print.c', + 'shader/slang/slang_simplify.c', + 'shader/slang/slang_storage.c', + 'shader/slang/slang_typeinfo.c', + 'shader/slang/slang_vartable.c', + 'shader/slang/slang_utility.c', + ] + + mesa_sources = ( + main_sources + + math_sources + + vbo_sources + + vf_sources + + statetracker_sources + + shader_sources + + slang_sources + ) + + glapi_sources = [ + 'main/dispatch.c', + 'glapi/glapi.c', + 'glapi/glapi_getproc.c', + 'glapi/glthread.c', + ] + + # + # Assembly sources + # + if gcc and 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.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', + ] + glapi_sources += [ + 'x86/glapi_x86.S', + ] + elif gcc and env['machine'] == 'x86_64': + env.Append(CPPDEFINES = [ + 'USE_X86_64_ASM', + ]) + mesa_sources += [ + 'x86-64/x86-64.c', + 'x86-64/xform4.S', + ] + glapi_sources += [ + 'x86-64/glapi_x86-64.S' + ] + elif gcc and env['machine'] == 'ppc': + env.Append(CPPDEFINES = [ + 'USE_PPC_ASM', + 'USE_VMX_ASM', + ]) + mesa_sources += [ + 'ppc/common_ppc.c', + ] + glapi_sources += [ + ] + elif gcc and env['machine'] == 'sparc': + mesa_sources += [ + 'sparc/sparc.c', + 'sparc/clip.S', + 'sparc/norm.S', + 'sparc/xform.S', + ] + glapi_sources += [ + 'sparc/glapi_sparc.S' + ] + else: + pass + + # Generate matypes.h + if gcc and 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, + ) + Export('mesa') + + if not dri: + glapi = env.ConvenienceLibrary( + target = 'glapi', + source = glapi_sources, + ) + Export('glapi') diff --git a/src/mesa/drivers/dri/Makefile.template b/src/mesa/drivers/dri/Makefile.template index 2dc3664cc6..2fa36bab3f 100644 --- a/src/mesa/drivers/dri/Makefile.template +++ b/src/mesa/drivers/dri/Makefile.template @@ -2,13 +2,16 @@ MESA_MODULES = $(TOP)/src/mesa/libmesa.a -COMMON_SOURCES = \ +COMMON_GALLIUM_SOURCES = \ ../common/utils.c \ - ../common/texmem.c \ ../common/vblank.c \ ../common/dri_util.c \ - ../common/xmlconfig.c \ - ../common/drirenderbuffer.c + ../common/xmlconfig.c + +COMMON_SOURCES = $(COMMON_GALLIUM_SOURCES) \ + ../../common/driverfuncs.c \ + ../common/texmem.c \ + ../common/drirenderbuffer.c ifeq ($(WINDOW_SYSTEM),dri) WINOBJ= @@ -59,9 +62,9 @@ SHARED_INCLUDES = \ default: symlinks depend $(LIBNAME) $(TOP)/$(LIB_DIR)/$(LIBNAME) -$(LIBNAME): $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile $(TOP)/src/mesa/drivers/dri/Makefile.template +$(LIBNAME): $(OBJECTS) $(MESA_MODULES) $(PIPE_DRIVERS) $(WINOBJ) Makefile $(TOP)/src/mesa/drivers/dri/Makefile.template $(MKLIB) -o $@ -noprefix -linker '$(CC)' -ldflags '$(LDFLAGS)' \ - $(OBJECTS) $(MESA_MODULES) $(WINOBJ) $(DRI_LIB_DEPS) + $(OBJECTS) $(PIPE_DRIVERS) $(MESA_MODULES) $(WINOBJ) $(DRI_LIB_DEPS) $(TOP)/$(LIB_DIR)/$(LIBNAME): $(LIBNAME) @@ -69,6 +72,7 @@ $(TOP)/$(LIB_DIR)/$(LIBNAME): $(LIBNAME) depend: $(C_SOURCES) $(ASM_SOURCES) $(SYMLINKS) + rm -f depend touch depend $(MKDEP) $(MKDEP_OPTIONS) $(DRIVER_DEFINES) $(INCLUDES) $(C_SOURCES) \ $(ASM_SOURCES) diff --git a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c index e9b1a80b91..a2316e2662 100644 --- a/src/mesa/drivers/dri/common/dri_util.c +++ b/src/mesa/drivers/dri/common/dri_util.c @@ -315,9 +315,6 @@ static void driSwapBuffers(__DRIdrawable *dPriv) { __DRIscreen *psp = dPriv->driScreenPriv; - if (!dPriv->numClipRects) - return; - psp->DriverAPI.SwapBuffers(dPriv); driReportDamage(dPriv, dPriv->pClipRects, dPriv->numClipRects); diff --git a/src/mesa/drivers/dri/common/dri_util.h b/src/mesa/drivers/dri/common/dri_util.h index c0e1bea5e0..0feb57b3c6 100644 --- a/src/mesa/drivers/dri/common/dri_util.h +++ b/src/mesa/drivers/dri/common/dri_util.h @@ -1,25 +1,3 @@ -/* $XFree86: xc/lib/GL/dri/dri_util.h,v 1.1 2002/02/22 21:32:52 dawes Exp $ */ -/** - * \file dri_util.h - * DRI utility functions definitions. - * - * This module acts as glue between GLX and the actual hardware driver. A DRI - * driver doesn't really \e have to use any of this - it's optional. But, some - * useful stuff is done here that otherwise would have to be duplicated in most - * drivers. - * - * Basically, these utility functions take care of some of the dirty details of - * screen initialization, context creation, context binding, DRM setup, etc. - * - * These functions are compiled into each DRI driver so libGL.so knows nothing - * about them. - * - * \sa dri_util.c. - * - * \author Kevin E. Martin <kevin@precisioninsight.com> - * \author Brian Paul <brian@precisioninsight.com> - */ - /* * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -45,6 +23,26 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/** + * \file dri_util.h + * DRI utility functions definitions. + * + * This module acts as glue between GLX and the actual hardware driver. A DRI + * driver doesn't really \e have to use any of this - it's optional. But, some + * useful stuff is done here that otherwise would have to be duplicated in most + * drivers. + * + * Basically, these utility functions take care of some of the dirty details of + * screen initialization, context creation, context binding, DRM setup, etc. + * + * These functions are compiled into each DRI driver so libGL.so knows nothing + * about them. + * + * \sa dri_util.c. + * + * \author Kevin E. Martin <kevin@precisioninsight.com> + * \author Brian Paul <brian@precisioninsight.com> + */ #ifndef _DRI_UTIL_H_ #define _DRI_UTIL_H_ diff --git a/src/mesa/drivers/dri/common/drirenderbuffer.c b/src/mesa/drivers/dri/common/drirenderbuffer.c index b99bf2033b..15af99136c 100644 --- a/src/mesa/drivers/dri/common/drirenderbuffer.c +++ b/src/mesa/drivers/dri/common/drirenderbuffer.c @@ -209,6 +209,8 @@ driUpdateFramebufferSize(GLcontext *ctx, const __DRIdrawablePrivate *dPriv) struct gl_framebuffer *fb = (struct gl_framebuffer *) dPriv->driverPrivate; if (fb && (dPriv->w != fb->Width || dPriv->h != fb->Height)) { ctx->Driver.ResizeBuffers(ctx, fb, dPriv->w, dPriv->h); + /* if the driver needs the hw lock for ResizeBuffers, the drawable + might have changed again by now */ assert(fb->Width == dPriv->w); assert(fb->Height == dPriv->h); } diff --git a/src/mesa/drivers/dri/common/utils.c b/src/mesa/drivers/dri/common/utils.c index 30c860b96c..2a1ded3871 100644 --- a/src/mesa/drivers/dri/common/utils.c +++ b/src/mesa/drivers/dri/common/utils.c @@ -310,8 +310,10 @@ void driInitSingleExtension( GLcontext * ctx, */ offset = _glapi_add_dispatch( functions, parameter_signature ); if (offset == -1) { +#if 0 /* this causes noise with egl */ fprintf(stderr, "DISPATCH ERROR! _glapi_add_dispatch failed " "to add %s!\n", functions[0]); +#endif } else if (ext->functions[i].remap_index != -1) { driDispatchRemapTable[ ext->functions[i].remap_index ] = @@ -504,6 +506,9 @@ GLboolean driClipRectToFramebuffer( const GLframebuffer *buffer, * \c GLX_SWAP_UNDEFINED_OML. See the * GLX_OML_swap_method extension spec for more details. * \param num_db_modes Number of entries in \c db_modes. + * \param msaa_samples Array of msaa sample count. 0 represents a visual + * without a multisample buffer. + * \param num_msaa_modes Number of entries in \c msaa_samples. * \param visType GLX visual type. Usually either \c GLX_TRUE_COLOR or * \c GLX_DIRECT_COLOR. * @@ -523,7 +528,8 @@ __DRIconfig ** driCreateConfigs(GLenum fb_format, GLenum fb_type, const uint8_t * depth_bits, const uint8_t * stencil_bits, unsigned num_depth_stencil_bits, - const GLenum * db_modes, unsigned num_db_modes) + const GLenum * db_modes, unsigned num_db_modes, + const u_int8_t * msaa_samples, unsigned num_msaa_modes) { static const uint8_t bits_table[4][4] = { /* R G B A */ @@ -583,9 +589,7 @@ driCreateConfigs(GLenum fb_format, GLenum fb_type, int index; __DRIconfig **configs, **c; __GLcontextModes *modes; - unsigned i; - unsigned j; - unsigned k; + unsigned i, j, k, h; unsigned num_modes; unsigned num_accum_bits = 2; @@ -658,7 +662,7 @@ driCreateConfigs(GLenum fb_format, GLenum fb_type, break; } - num_modes = num_depth_stencil_bits * num_db_modes * num_accum_bits; + num_modes = num_depth_stencil_bits * num_db_modes * num_accum_bits * num_msaa_modes; configs = _mesa_calloc((num_modes + 1) * sizeof *configs); if (configs == NULL) return NULL; @@ -666,66 +670,72 @@ driCreateConfigs(GLenum fb_format, GLenum fb_type, c = configs; for ( k = 0 ; k < num_depth_stencil_bits ; k++ ) { for ( i = 0 ; i < num_db_modes ; i++ ) { - for ( j = 0 ; j < num_accum_bits ; j++ ) { - *c = _mesa_malloc (sizeof **c); - modes = &(*c)->modes; - c++; - - memset(modes, 0, sizeof *modes); - modes->redBits = bits[0]; - modes->greenBits = bits[1]; - modes->blueBits = bits[2]; - modes->alphaBits = bits[3]; - modes->redMask = masks[0]; - modes->greenMask = masks[1]; - modes->blueMask = masks[2]; - modes->alphaMask = masks[3]; - modes->rgbBits = modes->redBits + modes->greenBits - + modes->blueBits + modes->alphaBits; - - modes->accumRedBits = 16 * j; - modes->accumGreenBits = 16 * j; - modes->accumBlueBits = 16 * j; - modes->accumAlphaBits = (masks[3] != 0) ? 16 * j : 0; - modes->visualRating = (j == 0) ? GLX_NONE : GLX_SLOW_CONFIG; - - modes->stencilBits = stencil_bits[k]; - modes->depthBits = depth_bits[k]; - - modes->transparentPixel = GLX_NONE; - modes->transparentRed = GLX_DONT_CARE; - modes->transparentGreen = GLX_DONT_CARE; - modes->transparentBlue = GLX_DONT_CARE; - modes->transparentAlpha = GLX_DONT_CARE; - modes->transparentIndex = GLX_DONT_CARE; - modes->visualType = GLX_DONT_CARE; - modes->renderType = GLX_RGBA_BIT; - modes->drawableType = GLX_WINDOW_BIT; - modes->rgbMode = GL_TRUE; - - if ( db_modes[i] == GLX_NONE ) { - modes->doubleBufferMode = GL_FALSE; - } - else { - modes->doubleBufferMode = GL_TRUE; - modes->swapMethod = db_modes[i]; - } - - modes->haveAccumBuffer = ((modes->accumRedBits + + for ( h = 0 ; h < num_msaa_modes; h++ ) { + for ( j = 0 ; j < num_accum_bits ; j++ ) { + *c = _mesa_malloc (sizeof **c); + modes = &(*c)->modes; + c++; + + memset(modes, 0, sizeof *modes); + modes->redBits = bits[0]; + modes->greenBits = bits[1]; + modes->blueBits = bits[2]; + modes->alphaBits = bits[3]; + modes->redMask = masks[0]; + modes->greenMask = masks[1]; + modes->blueMask = masks[2]; + modes->alphaMask = masks[3]; + modes->rgbBits = modes->redBits + modes->greenBits + + modes->blueBits + modes->alphaBits; + + modes->accumRedBits = 16 * j; + modes->accumGreenBits = 16 * j; + modes->accumBlueBits = 16 * j; + modes->accumAlphaBits = (masks[3] != 0) ? 16 * j : 0; + modes->visualRating = (j == 0) ? GLX_NONE : GLX_SLOW_CONFIG; + + modes->stencilBits = stencil_bits[k]; + modes->depthBits = depth_bits[k]; + + modes->transparentPixel = GLX_NONE; + modes->transparentRed = GLX_DONT_CARE; + modes->transparentGreen = GLX_DONT_CARE; + modes->transparentBlue = GLX_DONT_CARE; + modes->transparentAlpha = GLX_DONT_CARE; + modes->transparentIndex = GLX_DONT_CARE; + modes->visualType = GLX_DONT_CARE; + modes->renderType = GLX_RGBA_BIT; + modes->drawableType = GLX_WINDOW_BIT; + modes->rgbMode = GL_TRUE; + + if ( db_modes[i] == GLX_NONE ) { + modes->doubleBufferMode = GL_FALSE; + } + else { + modes->doubleBufferMode = GL_TRUE; + modes->swapMethod = db_modes[i]; + } + + modes->samples = msaa_samples[h]; + modes->sampleBuffers = modes->samples ? 1 : 0; + + + modes->haveAccumBuffer = ((modes->accumRedBits + modes->accumGreenBits + modes->accumBlueBits + modes->accumAlphaBits) > 0); - modes->haveDepthBuffer = (modes->depthBits > 0); - modes->haveStencilBuffer = (modes->stencilBits > 0); - - modes->bindToTextureRgb = GL_TRUE; - modes->bindToTextureRgba = GL_TRUE; - modes->bindToMipmapTexture = GL_FALSE; - modes->bindToTextureTargets = modes->rgbMode ? - __DRI_ATTRIB_TEXTURE_1D_BIT | - __DRI_ATTRIB_TEXTURE_2D_BIT | - __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT : - 0; + modes->haveDepthBuffer = (modes->depthBits > 0); + modes->haveStencilBuffer = (modes->stencilBits > 0); + + modes->bindToTextureRgb = GL_TRUE; + modes->bindToTextureRgba = GL_TRUE; + modes->bindToMipmapTexture = GL_FALSE; + modes->bindToTextureTargets = modes->rgbMode ? + __DRI_ATTRIB_TEXTURE_1D_BIT | + __DRI_ATTRIB_TEXTURE_2D_BIT | + __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT : + 0; + } } } } diff --git a/src/mesa/drivers/dri/common/utils.h b/src/mesa/drivers/dri/common/utils.h index 0c974dbff3..4e27bd21a1 100644 --- a/src/mesa/drivers/dri/common/utils.h +++ b/src/mesa/drivers/dri/common/utils.h @@ -131,7 +131,8 @@ extern __DRIconfig ** driCreateConfigs(GLenum fb_format, GLenum fb_type, const uint8_t * depth_bits, const uint8_t * stencil_bits, unsigned num_depth_stencil_bits, - const GLenum * db_modes, unsigned num_db_modes); + const GLenum * db_modes, unsigned num_db_modes, + const uint8_t * msaa_samples, unsigned num_msaa_modes); const __DRIconfig **driConcatConfigs(__DRIconfig **a, __DRIconfig **b); diff --git a/src/mesa/drivers/dri/glcore/Makefile b/src/mesa/drivers/dri/glcore/Makefile new file mode 100644 index 0000000000..ac7e1de928 --- /dev/null +++ b/src/mesa/drivers/dri/glcore/Makefile @@ -0,0 +1,84 @@ +# src/mesa/drivers/dri/glcore/Makefile + +TOP = ../../../../.. +include $(TOP)/configs/current + +LIBNAME = glcore_dri.so + +DRIVER_SOURCES = glcore_driver.c \ + $(TOP)/src/mesa/drivers/common/driverfuncs.c \ + ../common/dri_util.c + +C_SOURCES = \ + $(DRIVER_SOURCES) \ + $(DRI_SOURCES) + + +# Include directories +INCLUDE_DIRS = \ + -I. \ + -I../common \ + -I../dri_client \ + -I../dri_client/imports \ + -Iserver \ + -I$(TOP)/include \ + -I$(DRM_SOURCE_PATH)/shared-core \ + -I$(TOP)/src/mesa \ + -I$(TOP)/src/mesa/main \ + -I$(TOP)/src/mesa/glapi \ + -I$(TOP)/src/mesa/math \ + -I$(TOP)/src/mesa/transform \ + -I$(TOP)/src/mesa/shader \ + -I$(TOP)/src/mesa/swrast \ + -I$(TOP)/src/mesa/swrast_setup + +# Core Mesa objects +MESA_MODULES = $(TOP)/src/mesa/libmesa.a + +# Libraries that the driver shared lib depends on +LIB_DEPS = -lm -lpthread -lc +# LIB_DEPS = -lGL -lm -lpthread -lc + + +ASM_SOURCES = + +OBJECTS = $(C_SOURCES:.c=.o) \ + $(ASM_SOURCES:.S=.o) + + +##### RULES ##### + +.c.o: + $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $(DEFINES) $< -o $@ + +.S.o: + $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $(DEFINES) $< -o $@ + + +##### TARGETS ##### + +default: depend $(TOP)/$(LIB_DIR)/$(LIBNAME) + + +$(TOP)/$(LIB_DIR)/$(LIBNAME): $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile + CC="$(CC)" CXX="$(CXX)" $(TOP)/bin/mklib -o $(LIBNAME) -noprefix -install $(TOP)/$(LIB_DIR) \ + $(OBJECTS) $(WINLIB) $(LIB_DEPS) $(WINOBJ) $(MESA_MODULES) + + +depend: $(C_SOURCES) $(ASM_SOURCES) + rm -f depend + touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(INCLUDE_DIRS) $(C_SOURCES) $(ASM_SOURCES) \ + > /dev/null + + +# Emacs tags +tags: + etags `find . -name \*.[ch]` `find ../include` + + +clean: + -rm -f *.o server/*.o + + +include depend diff --git a/src/mesa/glapi/descrip.mms b/src/mesa/glapi/descrip.mms deleted file mode 100644 index ee96baa6fc..0000000000 --- a/src/mesa/glapi/descrip.mms +++ /dev/null @@ -1,39 +0,0 @@ -# Makefile for core library for VMS -# contributed by Jouk Jansen joukj@hrem.nano.tudelft.nl -# Last revision : 29 September 2008 - -.first - define gl [---.include.gl] - define main [-.main] - -.include [---]mms-config. - -##### MACROS ##### - -VPATH = RCS - -INCDIR = [---.include],[-.main] -LIBDIR = [---.lib] -CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1)/name=(as_is,short)/float=ieee/ieee=denorm - -SOURCES = glapi.c glthread.c glapi_getproc.c - -OBJECTS = glapi.obj,glthread.obj,glapi_getproc.obj - -##### RULES ##### - -VERSION=Mesa V3.4 - -##### TARGETS ##### -# Make the library -$(LIBDIR)$(GL_LIB) : $(OBJECTS) - @ library $(LIBDIR)$(GL_LIB) $(OBJECTS) - -clean : - purge - delete *.obj;* - -glapi.obj : glapi.c - -glthread.obj : glthread.c -glapi_getproc.obj : glapi_getproc.c diff --git a/src/mesa/glapi/glapi.c b/src/mesa/glapi/glapi.c index c3ebf60719..9b5144a88b 100644 --- a/src/mesa/glapi/glapi.c +++ b/src/mesa/glapi/glapi.c @@ -98,6 +98,7 @@ _glapi_set_warning_func( _glapi_warning_func func ) static GLboolean warn(void) { +#if !defined(_WIN32_WCE) if ((WarnFlag || getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG")) && warning_func) { return GL_TRUE; @@ -105,6 +106,9 @@ warn(void) else { return GL_FALSE; } +#else + return GL_FALSE; +#endif } diff --git a/src/mesa/glapi/glthread.c b/src/mesa/glapi/glthread.c index b818f4e26e..56ddf7c25a 100644 --- a/src/mesa/glapi/glthread.c +++ b/src/mesa/glapi/glthread.c @@ -25,16 +25,14 @@ /* * XXX There's probably some work to do in order to make this file - * truly reusable outside of Mesa. + * truly reusable outside of Mesa. First, the glheader.h include must go. */ - #ifdef HAVE_DIX_CONFIG_H #include <dix-config.h> #endif -#include <stdlib.h> -#include <stdio.h> +#include "main/glheader.h" #include "glthread.h" diff --git a/src/mesa/glapi/glthread.h b/src/mesa/glapi/glthread.h index e2765cebb1..ad2a63584b 100644 --- a/src/mesa/glapi/glthread.h +++ b/src/mesa/glapi/glthread.h @@ -116,9 +116,49 @@ typedef pthread_mutex_t _glthread_Mutex; #define _glthread_UNLOCK_MUTEX(name) \ (void) pthread_mutex_unlock(&(name)) -#endif /* PTHREADS */ +typedef pthread_cond_t _glthread_Cond; +#define _glthread_DECLARE_STATIC_COND(name) \ + static _glthread_Cond name = PTHREAD_COND_INITIALIZER +#define _glthread_INIT_COND(cond) \ + pthread_cond_init(&(cond), NULL) + +#define _glthread_DESTROY_COND(name) \ + pthread_cond_destroy(&(name)) + +#define _glthread_COND_WAIT(cond, mutex) \ + pthread_cond_wait(&(cond), &(mutex)) + +#define _glthread_COND_SIGNAL(cond) \ + pthread_cond_signal(&(cond)) + +#define _glthread_COND_BROADCAST(cond) \ + pthread_cond_broadcast(&(cond)) + + +#else /* PTHREADS */ + +typedef unsigned int _glthread_Cond; +#define _glthread_DECLARE_STATIC_COND(name) \ +// #warning Condition variables not implemented. + +#define _glthread_INIT_COND(cond) \ + ASSERT(0); + +#define _glthread_DESTROY_COND(name) \ + ASSERT(0); + +#define _glthread_COND_WAIT(cond, mutex) \ + ASSERT(0); + +#define _glthread_COND_SIGNAL(cond) \ + ASSERT(0); + +#define _glthread_COND_BROADCAST(cond) \ + ASSERT(0); + +#endif /* @@ -259,11 +299,11 @@ typedef benaphore _glthread_Mutex; * THREADS not defined */ -typedef int _glthread_TSD; +typedef GLuint _glthread_TSD; -typedef int _glthread_Thread; +typedef GLuint _glthread_Thread; -typedef int _glthread_Mutex; +typedef GLuint _glthread_Mutex; #define _glthread_DECLARE_STATIC_MUTEX(name) static _glthread_Mutex name = 0 diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c index 98dfbb105f..bbc5933ab9 100644 --- a/src/mesa/main/api_validate.c +++ b/src/mesa/main/api_validate.c @@ -119,6 +119,12 @@ _mesa_validate_DrawElements(GLcontext *ctx, /* use indices in the buffer object */ GLuint indexBytes; + if (!ctx->Array.ElementArrayBufferObj->Size) { + _mesa_warning(ctx, + "glDrawElements called with empty array elements buffer"); + return GL_FALSE; + } + if (type == GL_UNSIGNED_INT) { indexBytes = count * sizeof(GLuint); } diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c index 918e87246f..190e6ab564 100644 --- a/src/mesa/main/bufferobj.c +++ b/src/mesa/main/bufferobj.c @@ -38,6 +38,13 @@ #include "bufferobj.h" +#ifdef FEATURE_OES_mapbuffer +#define DEFAULT_ACCESS GL_WRITE_ONLY; +#else +#define DEFAULT_ACCESS GL_READ_WRITE; +#endif + + /** * Get the buffer object bound to the specified target in a GL context. * @@ -255,7 +262,7 @@ _mesa_initialize_buffer_object( struct gl_buffer_object *obj, obj->RefCount = 1; obj->Name = name; obj->Usage = GL_STATIC_DRAW_ARB; - obj->Access = GL_READ_WRITE_ARB; + obj->Access = DEFAULT_ACCESS; } @@ -664,8 +671,8 @@ _mesa_map_drawpix_pbo(GLcontext *ctx, * \sa _mesa_unmap_bitmap_pbo */ void -_mesa_unmap_drapix_pbo(GLcontext *ctx, - const struct gl_pixelstore_attrib *unpack) +_mesa_unmap_drawpix_pbo(GLcontext *ctx, + const struct gl_pixelstore_attrib *unpack) { if (unpack->BufferObj->Name) { ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, @@ -1065,7 +1072,7 @@ _mesa_UnmapBufferARB(GLenum target) status = ctx->Driver.UnmapBuffer( ctx, target, bufObj ); } - bufObj->Access = GL_READ_WRITE_ARB; /* initial value, OK? */ + bufObj->Access = DEFAULT_ACCESS; bufObj->Pointer = NULL; return status; diff --git a/src/mesa/main/bufferobj.h b/src/mesa/main/bufferobj.h index 163fe241aa..3c08f0083c 100644 --- a/src/mesa/main/bufferobj.h +++ b/src/mesa/main/bufferobj.h @@ -103,9 +103,8 @@ _mesa_map_drawpix_pbo(GLcontext *ctx, const GLvoid *pixels); extern void -_mesa_unmap_drapix_pbo(GLcontext *ctx, - const struct gl_pixelstore_attrib *unpack); - +_mesa_unmap_drawpix_pbo(GLcontext *ctx, + const struct gl_pixelstore_attrib *unpack); extern void * _mesa_map_readpix_pbo(GLcontext *ctx, diff --git a/src/mesa/main/buffers.c b/src/mesa/main/buffers.c index b23d2f612b..5dd85de272 100644 --- a/src/mesa/main/buffers.c +++ b/src/mesa/main/buffers.c @@ -419,7 +419,7 @@ _mesa_drawbuffers(GLcontext *ctx, GLuint n, const GLenum *buffers, } } - ctx->NewState |= _NEW_COLOR; + ctx->NewState |= _NEW_BUFFERS; } @@ -494,6 +494,7 @@ _mesa_ReadBuffer(GLenum buffer) /* OK, all error checking has been completed now */ _mesa_readbuffer(ctx, buffer, srcBuffer); + ctx->NewState |= _NEW_BUFFERS; /* * Call device driver function. diff --git a/src/mesa/main/config.h b/src/mesa/main/config.h index 882e2f224a..3b340c476c 100644 --- a/src/mesa/main/config.h +++ b/src/mesa/main/config.h @@ -176,13 +176,11 @@ /** For GL_ARB_fragment_program */ /*@{*/ #define MAX_FRAGMENT_PROGRAM_ADDRESS_REGS 0 -#define MAX_FRAGMENT_PROGRAM_ALU_INSTRUCTIONS 48 -#define MAX_FRAGMENT_PROGRAM_TEX_INSTRUCTIONS 24 -#define MAX_FRAGMENT_PROGRAM_TEX_INDIRECTIONS 4 /*@}*/ /** For any program target/extension */ /*@{*/ +#define MAX_PROGRAM_INSTRUCTIONS (16 * 1024) #define MAX_PROGRAM_LOCAL_PARAMS 128 /* KW: power of two */ #define MAX_PROGRAM_ENV_PARAMS 128 #define MAX_PROGRAM_MATRICES 8 diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index a41cb42952..61c0861cbd 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -145,9 +145,7 @@ #include "glapi/glthread.h" #include "glapi/glapioffsets.h" #include "glapi/glapitable.h" -#if FEATURE_NV_vertex_program || FEATURE_NV_fragment_program #include "shader/program.h" -#endif #include "shader/shader_api.h" #if FEATURE_ATI_fragment_shader #include "shader/atifragshader.h" @@ -186,9 +184,11 @@ GLfloat _mesa_ubyte_to_float_color_tab[256]; * We have to finish any pending rendering. */ void -_mesa_notifySwapBuffers(__GLcontext *gc) +_mesa_notifySwapBuffers(__GLcontext *ctx) { - FLUSH_VERTICES( gc, 0 ); + if (ctx->Driver.Flush) { + ctx->Driver.Flush(ctx); + } } @@ -611,6 +611,7 @@ delete_program_cb(GLuint id, void *data, void *userData) ctx->Driver.DeleteProgram(ctx, prog); } +#if FEATURE_ATI_fragment_shader /** * Callback for deleting an ATI fragment shader object. * Called by _mesa_HashDeleteAll(). @@ -622,6 +623,7 @@ delete_fragshader_cb(GLuint id, void *data, void *userData) GLcontext *ctx = (GLcontext *) userData; _mesa_delete_ati_fragment_shader(ctx, shader); } +#endif /** * Callback for deleting a buffer object. Called by _mesa_HashDeleteAll(). @@ -712,7 +714,6 @@ delete_renderbuffer_cb(GLuint id, void *data, void *userData) } - /** * Deallocate a shared state object and all children structures. * @@ -818,11 +819,33 @@ _mesa_init_current(GLcontext *ctx) /** - * Init vertex/fragment program native limits from logical limits. + * Init vertex/fragment program limits. + * Important: drivers should override these with actual limits. */ static void -init_natives(struct gl_program_constants *prog) +init_program_limits(GLenum type, struct gl_program_constants *prog) { + prog->MaxInstructions = MAX_PROGRAM_INSTRUCTIONS; + prog->MaxAluInstructions = MAX_PROGRAM_INSTRUCTIONS; + prog->MaxTexInstructions = MAX_PROGRAM_INSTRUCTIONS; + prog->MaxTexIndirections = MAX_PROGRAM_INSTRUCTIONS; + prog->MaxTemps = MAX_PROGRAM_TEMPS; + prog->MaxEnvParams = MAX_PROGRAM_ENV_PARAMS; + prog->MaxLocalParams = MAX_PROGRAM_LOCAL_PARAMS; + prog->MaxUniformComponents = 4 * MAX_UNIFORMS; + + if (type == GL_VERTEX_PROGRAM_ARB) { + prog->MaxParameters = MAX_NV_VERTEX_PROGRAM_PARAMS; + prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS; + prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS; + } + else { + prog->MaxParameters = MAX_NV_FRAGMENT_PROGRAM_PARAMS; + prog->MaxAttribs = MAX_NV_FRAGMENT_PROGRAM_INPUTS; + prog->MaxAddressRegs = MAX_FRAGMENT_PROGRAM_ADDRESS_REGS; + } + + /* copy the above limits to init native limits */ prog->MaxNativeInstructions = prog->MaxInstructions; prog->MaxNativeAluInstructions = prog->MaxAluInstructions; prog->MaxNativeTexInstructions = prog->MaxTexInstructions; @@ -884,33 +907,10 @@ _mesa_init_constants(GLcontext *ctx) ctx->Const.MaxViewportWidth = MAX_WIDTH; ctx->Const.MaxViewportHeight = MAX_HEIGHT; #if FEATURE_ARB_vertex_program - ctx->Const.VertexProgram.MaxInstructions = MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS; - ctx->Const.VertexProgram.MaxAluInstructions = 0; - ctx->Const.VertexProgram.MaxTexInstructions = 0; - ctx->Const.VertexProgram.MaxTexIndirections = 0; - ctx->Const.VertexProgram.MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS; - ctx->Const.VertexProgram.MaxTemps = MAX_PROGRAM_TEMPS; - ctx->Const.VertexProgram.MaxParameters = MAX_NV_VERTEX_PROGRAM_PARAMS; - ctx->Const.VertexProgram.MaxLocalParams = MAX_PROGRAM_LOCAL_PARAMS; - ctx->Const.VertexProgram.MaxEnvParams = MAX_PROGRAM_ENV_PARAMS; - ctx->Const.VertexProgram.MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS; - ctx->Const.VertexProgram.MaxUniformComponents = 4 * MAX_UNIFORMS; - init_natives(&ctx->Const.VertexProgram); + init_program_limits(GL_VERTEX_PROGRAM_ARB, &ctx->Const.VertexProgram); #endif - #if FEATURE_ARB_fragment_program - ctx->Const.FragmentProgram.MaxInstructions = MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS; - ctx->Const.FragmentProgram.MaxAluInstructions = MAX_FRAGMENT_PROGRAM_ALU_INSTRUCTIONS; - ctx->Const.FragmentProgram.MaxTexInstructions = MAX_FRAGMENT_PROGRAM_TEX_INSTRUCTIONS; - ctx->Const.FragmentProgram.MaxTexIndirections = MAX_FRAGMENT_PROGRAM_TEX_INDIRECTIONS; - ctx->Const.FragmentProgram.MaxAttribs = MAX_NV_FRAGMENT_PROGRAM_INPUTS; - ctx->Const.FragmentProgram.MaxTemps = MAX_PROGRAM_TEMPS; - ctx->Const.FragmentProgram.MaxParameters = MAX_NV_FRAGMENT_PROGRAM_PARAMS; - ctx->Const.FragmentProgram.MaxLocalParams = MAX_PROGRAM_LOCAL_PARAMS; - ctx->Const.FragmentProgram.MaxEnvParams = MAX_PROGRAM_ENV_PARAMS; - ctx->Const.FragmentProgram.MaxAddressRegs = MAX_FRAGMENT_PROGRAM_ADDRESS_REGS; - ctx->Const.FragmentProgram.MaxUniformComponents = 4 * MAX_UNIFORMS; - init_natives(&ctx->Const.FragmentProgram); + init_program_limits(GL_FRAGMENT_PROGRAM_ARB, &ctx->Const.FragmentProgram); #endif ctx->Const.MaxProgramMatrices = MAX_PROGRAM_MATRICES; ctx->Const.MaxProgramMatrixStackDepth = MAX_PROGRAM_MATRIX_STACK_DEPTH; @@ -1063,6 +1063,7 @@ init_attrib_groups(GLcontext *ctx) /* Miscellaneous */ ctx->NewState = _NEW_ALL; ctx->ErrorValue = (GLenum) GL_NO_ERROR; + ctx->varying_vp_inputs = ~0; return GL_TRUE; } @@ -1162,7 +1163,7 @@ _mesa_initialize_context(GLcontext *ctx, const struct dd_function_table *driverFunctions, void *driverContext) { - ASSERT(driverContext); + /*ASSERT(driverContext);*/ assert(driverFunctions->NewTextureObject); assert(driverFunctions->FreeTexImageData); @@ -1267,7 +1268,7 @@ _mesa_create_context(const GLvisual *visual, GLcontext *ctx; ASSERT(visual); - ASSERT(driverContext); + /*ASSERT(driverContext);*/ ctx = (GLcontext *) _mesa_calloc(sizeof(GLcontext)); if (!ctx) @@ -1315,7 +1316,9 @@ _mesa_free_context_data( GLcontext *ctx ) _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL); _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram, NULL); +#if FEATURE_attrib_stack _mesa_free_attrib_data(ctx); +#endif _mesa_free_lighting_data( ctx ); #if FEATURE_evaluators _mesa_free_eval_data( ctx ); @@ -1632,7 +1635,22 @@ _mesa_make_current( GLcontext *newCtx, GLframebuffer *drawBuffer, * or not bound to a user-created FBO. */ if (!newCtx->DrawBuffer || newCtx->DrawBuffer->Name == 0) { + /* KW: merge conflict here, revisit. + */ + /* fix up the fb fields - these will end up wrong otherwise + * if the DRIdrawable changes, and everything relies on them. + * This is a bit messy (same as needed in _mesa_BindFramebufferEXT) + */ + unsigned int i; + GLenum buffers[MAX_DRAW_BUFFERS]; + _mesa_reference_framebuffer(&newCtx->DrawBuffer, drawBuffer); + + for(i = 0; i < newCtx->Const.MaxDrawBuffers; i++) { + buffers[i] = newCtx->Color.DrawBuffer[i]; + } + + _mesa_drawbuffers(newCtx, newCtx->Const.MaxDrawBuffers, buffers, NULL); } if (!newCtx->ReadBuffer || newCtx->ReadBuffer->Name == 0) { _mesa_reference_framebuffer(&newCtx->ReadBuffer, readBuffer); diff --git a/src/mesa/main/drawpix.c b/src/mesa/main/drawpix.c index ac97bc1ff9..13cfa0e756 100644 --- a/src/mesa/main/drawpix.c +++ b/src/mesa/main/drawpix.c @@ -153,7 +153,7 @@ _mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, return; } - if (!ctx->Current.RasterPosValid) { + if (!ctx->Current.RasterPosValid || width ==0 || height == 0) { return; } @@ -218,7 +218,7 @@ _mesa_Bitmap( GLsizei width, GLsizei height, if (ctx->RenderMode == GL_RENDER) { /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ - const GLfloat epsilon = (const GLfloat)0.0001; + const GLfloat epsilon = 0.0001F; GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig); GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig); diff --git a/src/mesa/main/enable.c b/src/mesa/main/enable.c index e0483a72e8..248df1badc 100644 --- a/src/mesa/main/enable.c +++ b/src/mesa/main/enable.c @@ -929,6 +929,7 @@ _mesa_set_enable(GLcontext *ctx, GLenum cap, GLboolean state) break; /* GL_MESA_program_debug */ +#if FEATURE_MESA_program_debug case GL_FRAGMENT_PROGRAM_CALLBACK_MESA: CHECK_EXTENSION(MESA_program_debug, cap); ctx->FragmentProgram.CallbackEnabled = state; @@ -937,6 +938,7 @@ _mesa_set_enable(GLcontext *ctx, GLenum cap, GLboolean state) CHECK_EXTENSION(MESA_program_debug, cap); ctx->VertexProgram.CallbackEnabled = state; break; +#endif #if FEATURE_ATI_fragment_shader case GL_FRAGMENT_SHADER_ATI: @@ -1378,12 +1380,15 @@ _mesa_IsEnabled( GLenum cap ) return ctx->Depth.BoundsTest; /* GL_MESA_program_debug */ +#if FEATURE_MESA_program_debug case GL_FRAGMENT_PROGRAM_CALLBACK_MESA: CHECK_EXTENSION(MESA_program_debug); return ctx->FragmentProgram.CallbackEnabled; case GL_VERTEX_PROGRAM_CALLBACK_MESA: CHECK_EXTENSION(MESA_program_debug); return ctx->VertexProgram.CallbackEnabled; +#endif + #if FEATURE_ATI_fragment_shader case GL_FRAGMENT_SHADER_ATI: CHECK_EXTENSION(ATI_fragment_shader); diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c index de75325f15..95bf1165f4 100644 --- a/src/mesa/main/extensions.c +++ b/src/mesa/main/extensions.c @@ -86,7 +86,7 @@ static const struct { { OFF, "GL_EXT_blend_logic_op", F(EXT_blend_logic_op) }, { OFF, "GL_EXT_blend_minmax", F(EXT_blend_minmax) }, { OFF, "GL_EXT_blend_subtract", F(EXT_blend_subtract) }, - { ON, "GL_EXT_clip_volume_hint", F(EXT_clip_volume_hint) }, + { OFF, "GL_EXT_clip_volume_hint", F(EXT_clip_volume_hint) }, { OFF, "GL_EXT_cull_vertex", F(EXT_cull_vertex) }, { ON, "GL_EXT_compiled_vertex_array", F(EXT_compiled_vertex_array) }, { OFF, "GL_EXT_convolution", F(EXT_convolution) }, diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index 4c92d1fb5a..dd06327972 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -173,7 +173,7 @@ _mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att) if (att->Type == GL_TEXTURE) { ASSERT(att->Texture); if (ctx->Driver.FinishRenderTexture) { - /* tell driver we're done rendering to this texobj */ + /* tell driver that we're done rendering to this texture. */ ctx->Driver.FinishRenderTexture(ctx, att); } _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ diff --git a/src/mesa/main/ffvertex_prog.c b/src/mesa/main/ffvertex_prog.c index ebc02940de..ec0a5e3896 100644 --- a/src/mesa/main/ffvertex_prog.c +++ b/src/mesa/main/ffvertex_prog.c @@ -47,17 +47,17 @@ struct state_key { + unsigned light_color_material_mask:12; + unsigned light_material_mask:12; unsigned light_global_enabled:1; unsigned light_local_viewer:1; unsigned light_twoside:1; unsigned light_color_material:1; - unsigned light_color_material_mask:12; - unsigned light_material_mask:12; unsigned material_shininess_is_zero:1; - unsigned need_eye_coords:1; unsigned normalize:1; unsigned rescale_normals:1; + unsigned fog_source_is_depth:1; unsigned tnl_do_vertex_fog:1; unsigned separate_specular:1; @@ -67,6 +67,8 @@ struct state_key { unsigned texture_enabled_global:1; unsigned fragprog_inputs_read:12; + unsigned varying_vp_inputs; + struct { unsigned light_enabled:1; unsigned light_eyepos3_is_zero:1; @@ -193,6 +195,7 @@ static void make_state_key( GLcontext *ctx, struct state_key *key ) key->need_eye_coords = ctx->_NeedEyeCoords; key->fragprog_inputs_read = fp->Base.InputsRead; + key->varying_vp_inputs = ctx->varying_vp_inputs; if (ctx->RenderMode == GL_FEEDBACK) { /* make sure the vertprog emits color and tex0 */ @@ -448,14 +451,46 @@ static void release_temps( struct tnl_program *p ) } +static struct ureg register_param5(struct tnl_program *p, + GLint s0, + GLint s1, + GLint s2, + GLint s3, + GLint s4) +{ + gl_state_index tokens[STATE_LENGTH]; + GLint idx; + tokens[0] = s0; + tokens[1] = s1; + tokens[2] = s2; + tokens[3] = s3; + tokens[4] = s4; + idx = _mesa_add_state_reference( p->program->Base.Parameters, tokens ); + return make_ureg(PROGRAM_STATE_VAR, idx); +} + + +#define register_param1(p,s0) register_param5(p,s0,0,0,0,0) +#define register_param2(p,s0,s1) register_param5(p,s0,s1,0,0,0) +#define register_param3(p,s0,s1,s2) register_param5(p,s0,s1,s2,0,0) +#define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0) + + /** * \param input one of VERT_ATTRIB_x tokens. */ static struct ureg register_input( struct tnl_program *p, GLuint input ) { - p->program->Base.InputsRead |= (1<<input); - return make_ureg(PROGRAM_INPUT, input); + /* Material attribs are passed here as inputs >= 32 + */ + if (input >= 32 || (p->state->varying_vp_inputs & (1<<input))) { + p->program->Base.InputsRead |= (1<<input); + return make_ureg(PROGRAM_INPUT, input); + } + else { + return register_param3( p, STATE_INTERNAL, STATE_CURRENT_ATTRIB, input ); + } } /** @@ -504,31 +539,6 @@ static struct ureg get_identity_param( struct tnl_program *p ) return p->identity; } -static struct ureg register_param5(struct tnl_program *p, - GLint s0, - GLint s1, - GLint s2, - GLint s3, - GLint s4) -{ - gl_state_index tokens[STATE_LENGTH]; - GLint idx; - tokens[0] = s0; - tokens[1] = s1; - tokens[2] = s2; - tokens[3] = s3; - tokens[4] = s4; - idx = _mesa_add_state_reference( p->program->Base.Parameters, tokens ); - return make_ureg(PROGRAM_STATE_VAR, idx); -} - - -#define register_param1(p,s0) register_param5(p,s0,0,0,0,0) -#define register_param2(p,s0,s1) register_param5(p,s0,s1,0,0,0) -#define register_param3(p,s0,s1,s2) register_param5(p,s0,s1,s2,0,0) -#define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0) - - static void register_matrix_param5( struct tnl_program *p, GLint s0, /* modelview, projection, etc */ GLint s1, /* texture matrix number */ diff --git a/src/mesa/main/glheader.h b/src/mesa/main/glheader.h index 1d0f178dc4..d69c7bbb21 100644 --- a/src/mesa/main/glheader.h +++ b/src/mesa/main/glheader.h @@ -64,22 +64,33 @@ #include <stdarg.h> -/* Get typedefs for uintptr_t and friends */ -#if defined(__MINGW32__) || defined(__NetBSD__) -# include <stdint.h> -#elif defined(_WIN32) -# include <BaseTsd.h> -# if _MSC_VER == 1200 - typedef UINT_PTR uintptr_t; -# endif -#elif defined(__INTERIX) -/* Interix 3.x has a gcc that shadows this. */ -# ifndef _UINTPTR_T_DEFINED - typedef unsigned long uintptr_t; -# define _UINTPTR_T_DEFINED +/* Get standard integer types */ +#if defined(_MSC_VER) + + typedef __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef __int16 int16_t; + typedef unsigned __int16 uint16_t; +# ifndef __eglplatform_h_ + typedef __int32 int32_t; +# endif + typedef unsigned __int32 uint32_t; + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; + +# if defined(_WIN64) + typedef __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +# else + typedef __int32 intptr_t; + typedef unsigned __int32 uintptr_t; # endif + +# define INT64_C(__val) __val##i64 +# define UINT64_C(__val) __val##ui64 + #else -# include <inttypes.h> +# include <stdint.h> #endif diff --git a/src/mesa/main/image.c b/src/mesa/main/image.c index 1a6e864b98..bd38e0c3d8 100644 --- a/src/mesa/main/image.c +++ b/src/mesa/main/image.c @@ -5119,7 +5119,7 @@ _mesa_clip_copytexsubimage(const GLcontext *ctx, const struct gl_framebuffer *fb = ctx->ReadBuffer; const GLint srcX0 = *srcX, srcY0 = *srcY; - if (_mesa_clip_to_region(fb->_Xmin, fb->_Ymin, fb->_Xmax, fb->_Ymax, + if (_mesa_clip_to_region(0, 0, fb->Width, fb->Height, srcX, srcY, width, height)) { *destX = *destX + *srcX - srcX0; *destY = *destY + *srcY - srcY0; diff --git a/src/mesa/main/imports.c b/src/mesa/main/imports.c index 13cb84ca4b..6cfd7ccc72 100644 --- a/src/mesa/main/imports.c +++ b/src/mesa/main/imports.c @@ -557,7 +557,7 @@ _mesa_pow(double x, double y) * Find the first bit set in a word. */ int -_mesa_ffs(int i) +_mesa_ffs(int32_t i) { #if (defined(_WIN32) ) || defined(__IBMC__) || defined(__IBMCPP__) register int bit = 0; @@ -594,11 +594,7 @@ _mesa_ffs(int i) * if no bits set. */ int -#ifdef __MINGW32__ -_mesa_ffsll(long val) -#else -_mesa_ffsll(long long val) -#endif +_mesa_ffsll(int64_t val) { #ifdef ffsll return ffsll(val); @@ -607,11 +603,11 @@ _mesa_ffsll(long long val) assert(sizeof(val) == 8); - bit = _mesa_ffs(val); + bit = _mesa_ffs((int32_t)val); if (bit != 0) return bit; - bit = _mesa_ffs(val >> 32); + bit = _mesa_ffs((int32_t)(val >> 32)); if (bit != 0) return 32 + bit; @@ -938,12 +934,10 @@ _mesa_sprintf( char *str, const char *fmt, ... ) void _mesa_printf( const char *fmtString, ... ) { - char s[MAXSTRING]; va_list args; va_start( args, fmtString ); - vsnprintf(s, MAXSTRING, fmtString, args); + vfprintf(stderr, fmtString, args); va_end( args ); - fprintf(stderr,"%s", s); } /** Wrapper around vsprintf() */ diff --git a/src/mesa/main/imports.h b/src/mesa/main/imports.h index 453151ce0b..bab0042071 100644 --- a/src/mesa/main/imports.h +++ b/src/mesa/main/imports.h @@ -708,14 +708,10 @@ extern double _mesa_pow(double x, double y); extern int -_mesa_ffs(int i); +_mesa_ffs(int32_t i); extern int -#ifdef __MINGW32__ -_mesa_ffsll(long i); -#else -_mesa_ffsll(long long i); -#endif +_mesa_ffsll(int64_t i); extern unsigned int _mesa_bitcount(unsigned int n); diff --git a/src/mesa/main/light.c b/src/mesa/main/light.c index 10ee088a2d..d4db960f1b 100644 --- a/src/mesa/main/light.c +++ b/src/mesa/main/light.c @@ -1367,6 +1367,7 @@ _mesa_init_lighting( GLcontext *ctx ) /* Miscellaneous */ ctx->Light._NeedEyeCoords = GL_FALSE; ctx->_NeedEyeCoords = GL_FALSE; + ctx->_ForceEyeCoords = GL_FALSE; ctx->_ModelViewInvScale = 1.0; } diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 284f81b7cf..5e920f7aeb 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -126,6 +126,8 @@ struct gl_program_cache; struct gl_texture_format; struct gl_texture_image; struct gl_texture_object; +struct st_context; +struct pipe_surface; typedef struct __GLcontextRec GLcontext; typedef struct __GLcontextModesRec GLvisual; typedef struct gl_framebuffer GLframebuffer; @@ -1567,7 +1569,6 @@ struct gl_texture_attrib struct gl_texture_unit Unit[MAX_TEXTURE_UNITS]; - /** Proxy texture objects */ struct gl_texture_object *ProxyTex[NUM_TEXTURE_TARGETS]; /** GL_EXT_shared_texture_palette */ @@ -1986,6 +1987,8 @@ struct gl_vertex_program_state GLboolean CallbackEnabled; GLuint CurrentPosition; #endif + + GLboolean _Overriden; }; @@ -2259,6 +2262,7 @@ struct gl_renderbuffer GLubyte IndexBits; GLubyte DepthBits; GLubyte StencilBits; + GLubyte Samples; /**< Number of samples - 0 if not multisampled */ GLvoid *Data; /**< This may not be used by some kinds of RBs */ /* Used to wrap one renderbuffer around another: */ @@ -2719,6 +2723,7 @@ struct gl_matrix_stack #define _NEW_MULTISAMPLE 0x2000000 /**< __GLcontextRec::Multisample */ #define _NEW_TRACK_MATRIX 0x4000000 /**< __GLcontextRec::VertexProgram */ #define _NEW_PROGRAM 0x8000000 /**< __GLcontextRec::VertexProgram */ +#define _NEW_CURRENT_ATTRIB 0x10000000 /**< __GLcontextRec::Current */ #define _NEW_ALL ~0 /*@}*/ @@ -3046,6 +3051,8 @@ struct __GLcontextRec GLenum RenderMode; /**< either GL_RENDER, GL_SELECT, GL_FEEDBACK */ GLbitfield NewState; /**< bitwise-or of _NEW_* flags */ + GLbitfield varying_vp_inputs; /**< mask of VERT_BIT_* flags */ + /** \name Derived state */ /*@{*/ /** Bitwise-or of DD_* flags. Note that this bitfield may be used before @@ -3091,7 +3098,7 @@ struct __GLcontextRec void *swsetup_context; void *swtnl_context; void *swtnl_im; - void *acache_context; + struct st_context *st; void *aelt_context; /*@}*/ }; diff --git a/src/mesa/main/renderbuffer.c b/src/mesa/main/renderbuffer.c index 6f1d7c3960..3c37d05b40 100644 --- a/src/mesa/main/renderbuffer.c +++ b/src/mesa/main/renderbuffer.c @@ -1199,7 +1199,8 @@ _mesa_soft_renderbuffer_storage(GLcontext *ctx, struct gl_renderbuffer *rb, if (width > 0 && height > 0) { /* allocate new buffer storage */ - rb->Data = _mesa_malloc(width * height * pixelSize); + rb->Data = malloc(width * height * pixelSize); + if (rb->Data == NULL) { rb->Width = 0; rb->Height = 0; diff --git a/src/mesa/main/sources b/src/mesa/main/sources index eb8cd900ee..468121bd1d 100644 --- a/src/mesa/main/sources +++ b/src/mesa/main/sources @@ -78,7 +78,6 @@ vsnprintf.c MESA_MAIN_HEADERS = \ accum.h \ api_arrayelt.h \ -api_eval.h \ api_exec.h \ api_loopback.h \ api_noop.h \ diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c index e87a62f59d..0d452fd879 100644 --- a/src/mesa/main/state.c +++ b/src/mesa/main/state.c @@ -1,6 +1,6 @@ /* * Mesa 3-D graphics library - * Version: 7.1 + * Version: 7.3 * * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. * @@ -439,6 +439,9 @@ _mesa_update_state_locked( GLcontext *ctx ) GLbitfield new_state = ctx->NewState; GLbitfield prog_flags = _NEW_PROGRAM; + if (new_state == _NEW_CURRENT_ATTRIB) + goto out; + if (MESA_VERBOSE & VERBOSE_STATE) _mesa_print_state("_mesa_update_state", new_state); @@ -448,7 +451,7 @@ _mesa_update_state_locked( GLcontext *ctx ) if (new_state & (_NEW_PROGRAM|_NEW_TEXTURE|_NEW_TEXTURE_MATRIX)) _mesa_update_texture( ctx, new_state ); - if (new_state & (_NEW_BUFFERS | _NEW_COLOR | _NEW_PIXEL)) + if (new_state & _NEW_BUFFERS) _mesa_update_framebuffer(ctx); if (new_state & (_NEW_SCISSOR | _NEW_BUFFERS | _NEW_VIEWPORT)) @@ -502,10 +505,13 @@ _mesa_update_state_locked( GLcontext *ctx ) _mesa_update_tnl_spaces( ctx, new_state ); if (ctx->FragmentProgram._MaintainTexEnvProgram) { - prog_flags |= (_NEW_TEXTURE | _NEW_FOG | _DD_NEW_SEPARATE_SPECULAR); + prog_flags |= (_NEW_ARRAY | _NEW_TEXTURE_MATRIX | _NEW_LIGHT | + _NEW_RENDERMODE | + _NEW_TEXTURE | _NEW_FOG | _DD_NEW_SEPARATE_SPECULAR); } if (ctx->VertexProgram._MaintainTnlProgram) { prog_flags |= (_NEW_ARRAY | _NEW_TEXTURE | _NEW_TEXTURE_MATRIX | + _NEW_RENDERMODE | _NEW_TRANSFORM | _NEW_POINT | _NEW_FOG | _NEW_LIGHT | _MESA_NEW_NEED_EYE_COORDS); @@ -524,6 +530,7 @@ _mesa_update_state_locked( GLcontext *ctx ) * Set ctx->NewState to zero to avoid recursion if * Driver.UpdateState() has to call FLUSH_VERTICES(). (fixed?) */ + out: new_state = ctx->NewState; ctx->NewState = 0; ctx->Driver.UpdateState(ctx, new_state); @@ -540,3 +547,59 @@ _mesa_update_state( GLcontext *ctx ) _mesa_update_state_locked(ctx); _mesa_unlock_context_textures(ctx); } + + + + +/** + * Want to figure out which fragment program inputs are actually + * constant/current values from ctx->Current. These should be + * referenced as a tracked state variable rather than a fragment + * program input, to save the overhead of putting a constant value in + * every submitted vertex, transferring it to hardware, interpolating + * it across the triangle, etc... + * + * When there is a VP bound, just use vp->outputs. But when we're + * generating vp from fixed function state, basically want to + * calculate: + * + * vp_out_2_fp_in( vp_in_2_vp_out( varying_inputs ) | + * potential_vp_outputs ) + * + * Where potential_vp_outputs is calculated by looking at enabled + * texgen, etc. + * + * The generated fragment program should then only declare inputs that + * may vary or otherwise differ from the ctx->Current values. + * Otherwise, the fp should track them as state values instead. + */ +void +_mesa_set_varying_vp_inputs( GLcontext *ctx, + GLbitfield varying_inputs ) +{ + if (ctx->varying_vp_inputs != varying_inputs) { + ctx->varying_vp_inputs = varying_inputs; + ctx->NewState |= _NEW_ARRAY; + /*_mesa_printf("%s %x\n", __FUNCTION__, varying_inputs);*/ + } +} + + +/** + * Used by drivers to tell core Mesa that the driver is going to + * install/ use its own vertex program. In particular, this will + * prevent generated fragment programs from using state vars instead + * of ordinary varyings/inputs. + */ +void +_mesa_set_vp_override(GLcontext *ctx, GLboolean flag) +{ + if (ctx->VertexProgram._Overriden != flag) { + ctx->VertexProgram._Overriden = flag; + + /* Set one of the bits which will trigger fragment program + * regeneration: + */ + ctx->NewState |= _NEW_ARRAY; + } +} diff --git a/src/mesa/main/state.h b/src/mesa/main/state.h index bb7cb8f32a..29db08a0b9 100644 --- a/src/mesa/main/state.h +++ b/src/mesa/main/state.h @@ -1,6 +1,6 @@ /* * Mesa 3-D graphics library - * Version: 7.1 + * Version: 7.3 * * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. * @@ -29,13 +29,21 @@ #include "mtypes.h" extern void -_mesa_update_state( GLcontext *ctx ); +_mesa_update_state(GLcontext *ctx); /* As above but can only be called between _mesa_lock_context_textures() and * _mesa_unlock_context_textures(). */ extern void -_mesa_update_state_locked( GLcontext *ctx ); +_mesa_update_state_locked(GLcontext *ctx); + + +extern void +_mesa_set_varying_vp_inputs(GLcontext *ctx, GLbitfield varying_inputs); + + +extern void +_mesa_set_vp_override(GLcontext *ctx, GLboolean flag); #endif diff --git a/src/mesa/main/texcompress.c b/src/mesa/main/texcompress.c index c44d594d68..5ad936419b 100644 --- a/src/mesa/main/texcompress.c +++ b/src/mesa/main/texcompress.c @@ -137,8 +137,10 @@ _mesa_compressed_texture_size( GLcontext *ctx, ASSERT(depth == 1); (void) depth; + (void) size; switch (mesaFormat) { +#if FEATURE_texture_fxt1 case MESA_FORMAT_RGB_FXT1: case MESA_FORMAT_RGBA_FXT1: /* round up width to next multiple of 8, height to next multiple of 4 */ @@ -152,6 +154,8 @@ _mesa_compressed_texture_size( GLcontext *ctx, if (size < 16) size = 16; return size; +#endif +#if FEATURE_texture_s3tc case MESA_FORMAT_RGB_DXT1: case MESA_FORMAT_RGBA_DXT1: /* round up width, height to next multiple of 4 */ @@ -178,6 +182,7 @@ _mesa_compressed_texture_size( GLcontext *ctx, if (size < 16) size = 16; return size; +#endif default: _mesa_problem(ctx, "bad mesaFormat in _mesa_compressed_texture_size"); return 0; @@ -202,12 +207,15 @@ _mesa_compressed_texture_size_glenum(GLcontext *ctx, GLuint mesaFormat; switch (glformat) { +#if FEATURE_texture_fxt1 case GL_COMPRESSED_RGB_FXT1_3DFX: mesaFormat = MESA_FORMAT_RGB_FXT1; break; case GL_COMPRESSED_RGBA_FXT1_3DFX: mesaFormat = MESA_FORMAT_RGBA_FXT1; break; +#endif +#if FEATURE_texture_s3tc case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: case GL_RGB_S3TC: mesaFormat = MESA_FORMAT_RGB_DXT1; @@ -224,6 +232,7 @@ _mesa_compressed_texture_size_glenum(GLcontext *ctx, case GL_RGBA4_S3TC: mesaFormat = MESA_FORMAT_RGBA_DXT5; break; +#endif default: return 0; } @@ -245,10 +254,13 @@ _mesa_compressed_row_stride(GLuint mesaFormat, GLsizei width) GLint stride; switch (mesaFormat) { +#if FEATURE_texture_fxt1 case MESA_FORMAT_RGB_FXT1: case MESA_FORMAT_RGBA_FXT1: stride = ((width + 7) / 8) * 16; /* 16 bytes per 8x4 tile */ break; +#endif +#if FEATURE_texture_s3tc case MESA_FORMAT_RGB_DXT1: case MESA_FORMAT_RGBA_DXT1: stride = ((width + 3) / 4) * 8; /* 8 bytes per 4x4 tile */ @@ -257,6 +269,7 @@ _mesa_compressed_row_stride(GLuint mesaFormat, GLsizei width) case MESA_FORMAT_RGBA_DXT5: stride = ((width + 3) / 4) * 16; /* 16 bytes per 4x4 tile */ break; +#endif default: _mesa_problem(NULL, "bad mesaFormat in _mesa_compressed_row_stride"); return 0; @@ -293,10 +306,13 @@ _mesa_compressed_image_address(GLint col, GLint row, GLint img, */ switch (mesaFormat) { +#if FEATURE_texture_fxt1 case MESA_FORMAT_RGB_FXT1: case MESA_FORMAT_RGBA_FXT1: addr = (GLubyte *) image + 16 * (((width + 7) / 8) * (row / 4) + col / 8); break; +#endif +#if FEATURE_texture_s3tc case MESA_FORMAT_RGB_DXT1: case MESA_FORMAT_RGBA_DXT1: addr = (GLubyte *) image + 8 * (((width + 3) / 4) * (row / 4) + col / 4); @@ -305,6 +321,7 @@ _mesa_compressed_image_address(GLint col, GLint row, GLint img, case MESA_FORMAT_RGBA_DXT5: addr = (GLubyte *) image + 16 * (((width + 3) / 4) * (row / 4) + col / 4); break; +#endif default: _mesa_problem(NULL, "bad mesaFormat in _mesa_compressed_image_address"); addr = NULL; diff --git a/src/mesa/main/texcompress_fxt1.c b/src/mesa/main/texcompress_fxt1.c index 45f344b0c5..fc151605c9 100644 --- a/src/mesa/main/texcompress_fxt1.c +++ b/src/mesa/main/texcompress_fxt1.c @@ -298,17 +298,17 @@ const struct gl_texture_format _mesa_texformat_rgba_fxt1 = { /* * Define a 64-bit unsigned integer type and macros */ -#ifdef GL_EXT_timer_query /* this extensions defines the GLuint64EXT type */ +#if 1 #define FX64_NATIVE 1 -typedef GLuint64EXT Fx64; +typedef uint64_t Fx64; #define FX64_MOV32(a, b) a = b #define FX64_OR32(a, b) a |= b #define FX64_SHL(a, c) a <<= c -#else /* !GL_EXT_timer_query */ +#else #define FX64_NATIVE 0 @@ -330,7 +330,7 @@ typedef struct { } \ } while (0) -#endif /* !GL_EXT_timer_query */ +#endif #define F(i) (GLfloat)1 /* can be used to obtain an oblong metric: 0.30 / 0.59 / 0.11 */ diff --git a/src/mesa/main/texenvprogram.c b/src/mesa/main/texenvprogram.c index dcd7f90567..237ddaa683 100644 --- a/src/mesa/main/texenvprogram.c +++ b/src/mesa/main/texenvprogram.c @@ -48,24 +48,24 @@ struct texenvprog_cache_item /** - * This MAX is probably a bit generous, but that's OK. There can be - * up to four instructions per texture unit (TEX + 3 for combine), - * then there's fog and specular add. + * Up to nine instructions per tex unit, plus fog, specular color. */ -#define MAX_INSTRUCTIONS ((MAX_TEXTURE_UNITS * 4) + 12) +#define MAX_INSTRUCTIONS ((MAX_TEXTURE_UNITS * 9) + 12) #define DISASSEM (MESA_VERBOSE & VERBOSE_DISASSEM) struct mode_opt { - GLuint Source:4; - GLuint Operand:3; + GLubyte Source:4; + GLubyte Operand:3; }; struct state_key { - GLbitfield enabled_units; + GLuint nr_enabled_units:8; + GLuint enabled_units:8; GLuint separate_specular:1; GLuint fog_enabled:1; GLuint fog_mode:2; + GLuint inputs_available:12; struct { GLuint enabled:1; @@ -76,10 +76,10 @@ struct state_key { GLuint NumArgsRGB:2; GLuint ModeRGB:4; - struct mode_opt OptRGB[3]; - GLuint NumArgsA:2; GLuint ModeA:4; + + struct mode_opt OptRGB[3]; struct mode_opt OptA[3]; } unit[8]; }; @@ -201,6 +201,88 @@ static GLuint translate_tex_src_bit( GLbitfield bit ) } } +#define VERT_BIT_TEX_ANY (0xff << VERT_ATTRIB_TEX0) +#define VERT_RESULT_TEX_ANY (0xff << VERT_RESULT_TEX0) + +/** + * Identify all possible varying inputs. The fragment program will + * never reference non-varying inputs, but will track them via state + * constants instead. + * + * This function figures out all the inputs that the fragment program + * has access to. The bitmask is later reduced to just those which + * are actually referenced. + */ +static GLbitfield get_fp_input_mask( GLcontext *ctx ) +{ + GLbitfield fp_inputs = 0x0; + + if (ctx->VertexProgram._Overriden) { + /* Somebody's messing with the vertex program and we don't have + * a clue what's happening. Assume that it could be producing + * all possible outputs. + */ + fp_inputs = ~0; + } + else if (ctx->RenderMode == GL_FEEDBACK) { + fp_inputs = (FRAG_BIT_COL0 | FRAG_BIT_TEX0); + } + else if (!ctx->VertexProgram._Enabled || + !ctx->VertexProgram._Current) { + + /* Fixed function logic */ + GLbitfield varying_inputs = ctx->varying_vp_inputs; + + /* These get generated in the setup routine regardless of the + * vertex program: + */ + if (ctx->Point.PointSprite) + varying_inputs |= FRAG_BITS_TEX_ANY; + + /* First look at what values may be computed by the generated + * vertex program: + */ + if (ctx->Light.Enabled) { + fp_inputs |= FRAG_BIT_COL0; + + if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) + fp_inputs |= FRAG_BIT_COL1; + } + + fp_inputs |= (ctx->Texture._TexGenEnabled | + ctx->Texture._TexMatEnabled) << FRAG_ATTRIB_TEX0; + + /* Then look at what might be varying as a result of enabled + * arrays, etc: + */ + if (varying_inputs & VERT_BIT_COLOR0) fp_inputs |= FRAG_BIT_COL0; + if (varying_inputs & VERT_BIT_COLOR1) fp_inputs |= FRAG_BIT_COL1; + + fp_inputs |= (((varying_inputs & VERT_BIT_TEX_ANY) >> VERT_ATTRIB_TEX0) + << FRAG_ATTRIB_TEX0); + + } + else { + /* calculate from vp->outputs */ + GLbitfield vp_outputs = ctx->VertexProgram._Current->Base.OutputsWritten; + + /* These get generated in the setup routine regardless of the + * vertex program: + */ + if (ctx->Point.PointSprite) + vp_outputs |= FRAG_BITS_TEX_ANY; + + if (vp_outputs & (1 << VERT_RESULT_COL0)) fp_inputs |= FRAG_BIT_COL0; + if (vp_outputs & (1 << VERT_RESULT_COL1)) fp_inputs |= FRAG_BIT_COL1; + + fp_inputs |= (((vp_outputs & VERT_RESULT_TEX_ANY) >> VERT_RESULT_TEX0) + << FRAG_ATTRIB_TEX0); + } + + return fp_inputs; +} + + /** * Examine current texture environment state and generate a unique * key to identify it. @@ -208,7 +290,9 @@ static GLuint translate_tex_src_bit( GLbitfield bit ) static void make_state_key( GLcontext *ctx, struct state_key *key ) { GLuint i, j; - + GLbitfield inputs_referenced = FRAG_BIT_COL0; + GLbitfield inputs_available = get_fp_input_mask( ctx ); + memset(key, 0, sizeof(*key)); for (i=0;i<MAX_TEXTURE_UNITS;i++) { @@ -219,6 +303,8 @@ static void make_state_key( GLcontext *ctx, struct state_key *key ) key->unit[i].enabled = 1; key->enabled_units |= (1<<i); + key->nr_enabled_units = i+1; + inputs_referenced |= FRAG_BIT_TEX(i); key->unit[i].source_index = translate_tex_src_bit(texUnit->_ReallyEnabled); @@ -247,16 +333,22 @@ static void make_state_key( GLcontext *ctx, struct state_key *key ) } } - if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) + if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) { key->separate_specular = 1; + inputs_referenced |= FRAG_BIT_COL1; + } if (ctx->Fog.Enabled) { key->fog_enabled = 1; key->fog_mode = translate_fog_mode(ctx->Fog.Mode); + inputs_referenced |= FRAG_BIT_FOGC; /* maybe */ } + + key->inputs_available = (inputs_available & inputs_referenced); } -/* Use uregs to represent registers internally, translate to Mesa's +/** + * Use uregs to represent registers internally, translate to Mesa's * expected formats on emit. * * NOTE: These are passed by value extensively in this file rather @@ -289,16 +381,16 @@ static const struct ureg undef = { }; -/* State used to build the fragment program: +/** State used to build the fragment program: */ struct texenv_fragment_program { struct gl_fragment_program *program; GLcontext *ctx; struct state_key *state; - GLbitfield alu_temps; /* Track texture indirections, see spec. */ - GLbitfield temps_output; /* Track texture indirections, see spec. */ - GLbitfield temp_in_use; /* Tracks temporary regs which are in use. */ + GLbitfield alu_temps; /**< Track texture indirections, see spec. */ + GLbitfield temps_output; /**< Track texture indirections, see spec. */ + GLbitfield temp_in_use; /**< Tracks temporary regs which are in use. */ GLboolean error; struct ureg src_texture[MAX_TEXTURE_UNITS]; @@ -306,11 +398,11 @@ struct texenv_fragment_program { * else undef. */ - struct ureg src_previous; /* Reg containing color from previous + struct ureg src_previous; /**< Reg containing color from previous * stage. May need to be decl'd. */ - GLuint last_tex_stage; /* Number of last enabled texture unit */ + GLuint last_tex_stage; /**< Number of last enabled texture unit */ struct ureg half; struct ureg one; @@ -388,7 +480,7 @@ static struct ureg get_tex_temp( struct texenv_fragment_program *p ) { int bit; - /* First try to find availble temp not previously used (to avoid + /* First try to find available temp not previously used (to avoid * starting a new texture indirection). According to the spec, the * ~p->temps_output isn't necessary, but will keep it there for * now: @@ -413,6 +505,14 @@ static struct ureg get_tex_temp( struct texenv_fragment_program *p ) } +/** Mark a temp reg as being no longer allocatable. */ +static void reserve_temp( struct texenv_fragment_program *p, struct ureg r ) +{ + if (r.file == PROGRAM_TEMPORARY) + p->temps_output |= (1 << r.idx); +} + + static void release_temps(GLcontext *ctx, struct texenv_fragment_program *p ) { GLuint max_temp = ctx->Const.FragmentProgram.MaxTemps; @@ -451,11 +551,29 @@ static struct ureg register_param5( struct texenv_fragment_program *p, #define register_param3(p,s0,s1,s2) register_param5(p,s0,s1,s2,0,0) #define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0) +static GLuint frag_to_vert_attrib( GLuint attrib ) +{ + switch (attrib) { + case FRAG_ATTRIB_COL0: return VERT_ATTRIB_COLOR0; + case FRAG_ATTRIB_COL1: return VERT_ATTRIB_COLOR1; + default: + assert(attrib >= FRAG_ATTRIB_TEX0); + assert(attrib <= FRAG_ATTRIB_TEX7); + return attrib - FRAG_ATTRIB_TEX0 + VERT_ATTRIB_TEX0; + } +} + static struct ureg register_input( struct texenv_fragment_program *p, GLuint input ) { - p->program->Base.InputsRead |= (1 << input); - return make_ureg(PROGRAM_INPUT, input); + if (p->state->inputs_available & (1<<input)) { + p->program->Base.InputsRead |= (1 << input); + return make_ureg(PROGRAM_INPUT, input); + } + else { + GLuint idx = frag_to_vert_attrib( input ); + return register_param3( p, STATE_INTERNAL, STATE_CURRENT_ATTRIB, idx ); + } } @@ -506,10 +624,12 @@ emit_op(struct texenv_fragment_program *p, emit_dst( &inst->DstReg, dest, mask ); +#if 0 /* Accounting for indirection tracking: */ if (dest.file == PROGRAM_TEMPORARY) p->temps_output |= 1 << dest.idx; +#endif return inst; } @@ -564,6 +684,10 @@ static struct ureg emit_texld( struct texenv_fragment_program *p, p->program->Base.NumTexInstructions++; + /* Accounting for indirection tracking: + */ + reserve_temp(p, dest); + /* Is this a texture indirection? */ if ((coord.file == PROGRAM_TEMPORARY && @@ -588,14 +712,16 @@ static struct ureg register_const4f( struct texenv_fragment_program *p, { GLfloat values[4]; GLuint idx, swizzle; + struct ureg r; values[0] = s0; values[1] = s1; values[2] = s2; values[3] = s3; idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4, &swizzle ); - ASSERT(swizzle == SWIZZLE_NOOP); - return make_ureg(PROGRAM_CONSTANT, idx); + r = make_ureg(PROGRAM_CONSTANT, idx); + r.swz = swizzle; + return r; } #define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0) @@ -953,6 +1079,7 @@ static void load_texture( struct texenv_fragment_program *p, GLuint unit ) p->src_texture[unit] = emit_texld( p, OPCODE_TXP, tmp, WRITEMASK_XYZW, unit, dim, texcoord ); + if (p->state->unit[unit].shadow) p->program->Base.ShadowSamplers |= 1 << unit; @@ -1078,6 +1205,7 @@ create_new_program(GLcontext *ctx, struct state_key *key, for (unit = 0 ; unit < ctx->Const.MaxTextureUnits; unit++) if (key->enabled_units & (1<<unit)) { p.src_previous = emit_texenv( &p, unit ); + reserve_temp(&p, p.src_previous); /* don't re-use this temp reg */ release_temps(ctx, &p); /* release all temps */ } } @@ -1189,6 +1317,9 @@ _mesa_get_fixed_func_fragment_program(GLcontext *ctx) * If _MaintainTexEnvProgram is set we'll generate a fragment program that * implements the current texture env/combine mode. * This function generates that program and puts it into effect. + * + * XXX: remove this function. currently only called by some drivers, + * not by mesa core. We now handle this properly from inside mesa. */ void _mesa_UpdateTexEnvProgram( GLcontext *ctx ) diff --git a/src/mesa/main/texformat.c b/src/mesa/main/texformat.c index 4442ce39a4..ce2772c299 100644 --- a/src/mesa/main/texformat.c +++ b/src/mesa/main/texformat.c @@ -1673,6 +1673,11 @@ _mesa_format_to_type_and_comps(const struct gl_texture_format *format, *comps = 1; /* XXX OK? */ return; + case MESA_FORMAT_S8_Z24: + *datatype = GL_UNSIGNED_INT; + *comps = 1; /* XXX OK? */ + return; + case MESA_FORMAT_Z16: *datatype = GL_UNSIGNED_SHORT; *comps = 1; @@ -1683,6 +1688,7 @@ _mesa_format_to_type_and_comps(const struct gl_texture_format *format, *comps = 1; return; +#if FEATURE_EXT_texture_sRGB case MESA_FORMAT_SRGB8: *datatype = GL_UNSIGNED_BYTE; *comps = 3; @@ -1699,9 +1705,13 @@ _mesa_format_to_type_and_comps(const struct gl_texture_format *format, *datatype = GL_UNSIGNED_BYTE; *comps = 2; return; +#endif +#if FEATURE_texture_fxt1 case MESA_FORMAT_RGB_FXT1: case MESA_FORMAT_RGBA_FXT1: +#endif +#if FEATURE_texture_s3tc case MESA_FORMAT_RGB_DXT1: case MESA_FORMAT_RGBA_DXT1: case MESA_FORMAT_RGBA_DXT3: @@ -1710,6 +1720,7 @@ _mesa_format_to_type_and_comps(const struct gl_texture_format *format, *datatype = GL_UNSIGNED_BYTE; *comps = 0; return; +#endif case MESA_FORMAT_RGBA: *datatype = CHAN_TYPE; diff --git a/src/mesa/main/texformat.h b/src/mesa/main/texformat.h index 18900fe08b..f34b3b8223 100644 --- a/src/mesa/main/texformat.h +++ b/src/mesa/main/texformat.h @@ -106,12 +106,16 @@ enum _format { * \name Compressed texture formats. */ /*@{*/ +#if FEATURE_texture_fxt1 MESA_FORMAT_RGB_FXT1, MESA_FORMAT_RGBA_FXT1, +#endif +#if FEATURE_texture_s3tc MESA_FORMAT_RGB_DXT1, MESA_FORMAT_RGBA_DXT1, MESA_FORMAT_RGBA_DXT3, MESA_FORMAT_RGBA_DXT5, +#endif /*@}*/ /** @@ -225,12 +229,16 @@ extern const struct gl_texture_format _mesa_texformat_ycbcr_rev; /** \name Compressed formats */ /*@{*/ +#if FEATURE_texture_fxt1 extern const struct gl_texture_format _mesa_texformat_rgb_fxt1; extern const struct gl_texture_format _mesa_texformat_rgba_fxt1; +#endif +#if FEATURE_texture_s3tc extern const struct gl_texture_format _mesa_texformat_rgb_dxt1; extern const struct gl_texture_format _mesa_texformat_rgba_dxt1; extern const struct gl_texture_format _mesa_texformat_rgba_dxt3; extern const struct gl_texture_format _mesa_texformat_rgba_dxt5; +#endif /*@}*/ /** \name The null format */ diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c index 9e968ba743..a5e0db736e 100644 --- a/src/mesa/main/teximage.c +++ b/src/mesa/main/teximage.c @@ -1217,19 +1217,30 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target, img->Width = width; img->Height = height; img->Depth = depth; + img->Width2 = width - 2 * border; /* == 1 << img->WidthLog2; */ - img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */ - img->Depth2 = depth - 2 * border; /* == 1 << img->DepthLog2; */ img->WidthLog2 = logbase2(img->Width2); - if (height == 1) /* 1-D texture */ + + if (height == 1) { /* 1-D texture */ + img->Height2 = 1; img->HeightLog2 = 0; - else + } + else { + img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */ img->HeightLog2 = logbase2(img->Height2); - if (depth == 1) /* 2-D texture */ + } + + if (depth == 1) { /* 2-D texture */ + img->Depth2 = 1; img->DepthLog2 = 0; - else + } + else { + img->Depth2 = depth - 2 * border; /* == 1 << img->DepthLog2; */ img->DepthLog2 = logbase2(img->Depth2); + } + img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2); + img->IsCompressed = GL_FALSE; img->CompressedSize = 0; diff --git a/src/mesa/main/texstore.c b/src/mesa/main/texstore.c index abeed3baa1..c1fafbae30 100644 --- a/src/mesa/main/texstore.c +++ b/src/mesa/main/texstore.c @@ -885,8 +885,8 @@ _mesa_swizzle_ubyte_image(GLcontext *ctx, /* _mesa_printf("map %d %d %d %d\n", map[0], map[1], map[2], map[3]); */ - if (srcRowStride == dstRowStride && - srcComponents == dstComponents && + if (srcComponents == dstComponents && + srcRowStride == dstRowStride && srcRowStride == srcWidth * srcComponents && dimensions < 3) { /* 1 and 2D images only */ diff --git a/src/mesa/main/varray.h b/src/mesa/main/varray.h index 6385689fcc..97d5c8219d 100644 --- a/src/mesa/main/varray.h +++ b/src/mesa/main/varray.h @@ -156,6 +156,20 @@ _mesa_LockArraysEXT(GLint first, GLsizei count); extern void GLAPIENTRY _mesa_UnlockArraysEXT( void ); + +extern void GLAPIENTRY +_mesa_DrawArrays(GLenum mode, GLint first, GLsizei count); + +extern void GLAPIENTRY +_mesa_DrawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices); + +extern void GLAPIENTRY +_mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, + GLenum type, const GLvoid *indices); + + + extern void _mesa_init_varray( GLcontext * ctx ); diff --git a/src/mesa/math/m_debug_xform.c b/src/mesa/math/m_debug_xform.c index ec22c7052d..df8cc066b6 100644 --- a/src/mesa/math/m_debug_xform.c +++ b/src/mesa/math/m_debug_xform.c @@ -206,7 +206,8 @@ static int test_transform_function( transform_func func, int psize, case VAR: break; default: - abort(); + ASSERT(0); + return 0; } } } diff --git a/src/mesa/ppc/common_ppc.c b/src/mesa/ppc/common_ppc.c index 786e1817ac..c7cec96e5d 100644 --- a/src/mesa/ppc/common_ppc.c +++ b/src/mesa/ppc/common_ppc.c @@ -85,7 +85,7 @@ void _mesa_init_all_ppc_transform_asm( void ) } # ifndef USE_VMX_ASM - _mesa_ppc_cpu_features &= ~PPC_FEATURES_HAS_ALTIVEC; + _mesa_ppc_cpu_features &= ~PPC_FEATURE_HAS_ALTIVEC; # endif #endif } diff --git a/src/mesa/shader/arbprogparse.c b/src/mesa/shader/arbprogparse.c index 39988b5fca..536404bf97 100644 --- a/src/mesa/shader/arbprogparse.c +++ b/src/mesa/shader/arbprogparse.c @@ -30,6 +30,27 @@ * \author Karl Rasche */ +/** +Notes on program parameters, etc. + +The instructions we emit will use six kinds of source registers: + + PROGRAM_INPUT - input registers + PROGRAM_TEMPORARY - temp registers + PROGRAM_ADDRESS - address/indirect register + PROGRAM_SAMPLER - texture sampler + PROGRAM_CONSTANT - indexes into program->Parameters, a known constant/literal + PROGRAM_STATE_VAR - indexes into program->Parameters, and may actually be: + + a state variable, like "state.fog.color", or + + a pointer to a "program.local[k]" parameter, or + + a pointer to a "program.env[k]" parameter + +Basically, all the program.local[] and program.env[] values will get mapped +into the unified gl_program->Parameters array. This solves the problem of +having three separate program parameter arrays. +*/ + + #include "main/glheader.h" #include "main/imports.h" #include "main/context.h" @@ -38,16 +59,11 @@ #include "shader/grammar/grammar_mesa.h" #include "arbprogparse.h" #include "program.h" +#include "programopt.h" #include "prog_parameter.h" #include "prog_statevars.h" #include "prog_instruction.h" - -/* For ARB programs, use the NV instruction limits */ -#define MAX_INSTRUCTIONS MAX2(MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS, \ - MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS) - - /** * This is basically a union of the vertex_program and fragment_program * structs that we can use to parse the program into @@ -1870,7 +1886,11 @@ parse_param_elements (GLcontext * ctx, const GLubyte ** inst, const_values, 4); if (param_var->param_binding_begin == ~0U) param_var->param_binding_begin = idx; - param_var->param_binding_type = PROGRAM_CONSTANT; + param_var->param_binding_type = PROGRAM_STATE_VAR; + /* Note: when we reference this parameter in an instruction later, + * we'll check if it's really a constant/immediate and set the + * instruction register type appropriately. + */ param_var->param_binding_length++; Program->Base.NumParameters++; break; @@ -2577,6 +2597,18 @@ parse_src_reg (GLcontext * ctx, const GLubyte ** inst, return 1; } + if (*File == PROGRAM_STATE_VAR) { + enum register_file file; + + /* If we're referencing the Program->Parameters[] array, check if the + * parameter is really a constant/literal. If so, set File to CONSTANT. + */ + assert(*Index < (GLint) Program->Base.Parameters->NumParameters); + file = Program->Base.Parameters->Parameters[*Index].Type; + if (file == PROGRAM_CONSTANT) + *File = PROGRAM_CONSTANT; + } + /* Add attributes to InputsRead only if they are used the program. * This avoids the handling of unused ATTRIB declarations in the drivers. */ if (*File == PROGRAM_INPUT) @@ -3353,11 +3385,11 @@ debug_variables (GLcontext * ctx, struct var_cache *vc_head, fprintf (stderr, "%s\n", Program->Base.Parameters->Parameters[a + b].Name); if (Program->Base.Parameters->Parameters[a + b].Type == PROGRAM_STATE_VAR) { - const char *s; + char *s; s = _mesa_program_state_string(Program->Base.Parameters->Parameters [a + b].StateIndexes); fprintf(stderr, "%s\n", s); - _mesa_free((char *) s); + _mesa_free(s); } else fprintf (stderr, "%f %f %f %f\n", @@ -3405,7 +3437,7 @@ parse_instructions(GLcontext * ctx, const GLubyte * inst, : ctx->Const.VertexProgram.MaxInstructions; GLint err = 0; - ASSERT(MAX_INSTRUCTIONS >= maxInst); + ASSERT(MAX_PROGRAM_INSTRUCTIONS >= maxInst); Program->MajorVersion = (GLuint) * inst++; Program->MinorVersion = (GLuint) * inst++; @@ -3760,7 +3792,7 @@ _mesa_parse_arb_program(GLcontext *ctx, GLenum target, /* Initialize the arb_program struct */ program->Base.String = strz; - program->Base.Instructions = _mesa_alloc_instructions(MAX_INSTRUCTIONS); + program->Base.Instructions = _mesa_alloc_instructions(MAX_PROGRAM_INSTRUCTIONS); program->Base.NumInstructions = program->Base.NumTemporaries = program->Base.NumParameters = @@ -3805,12 +3837,12 @@ _mesa_parse_arb_program(GLcontext *ctx, GLenum target, _mesa_free (parsed); - /* Reallocate the instruction array from size [MAX_INSTRUCTIONS] + /* Reallocate the instruction array from size [MAX_PROGRAM_INSTRUCTIONS] * to size [ap.Base.NumInstructions]. */ program->Base.Instructions = _mesa_realloc_instructions(program->Base.Instructions, - MAX_INSTRUCTIONS, + MAX_PROGRAM_INSTRUCTIONS, program->Base.NumInstructions); return !err; @@ -3874,6 +3906,16 @@ _mesa_parse_arb_fragment_program(GLcontext* ctx, GLenum target, _mesa_free_parameter_list(program->Base.Parameters); program->Base.Parameters = ap.Base.Parameters; + /* Append fog instructions now if the program has "OPTION ARB_fog_exp" + * or similar. We used to leave this up to drivers, but it appears + * there's no hardware that wants to do fog in a discrete stage separate + * from the fragment shader. + */ + if (program->FogOption != GL_NONE) { + _mesa_append_fog_code(ctx, program); + program->FogOption = GL_NONE; + } + #if DEBUG_FP _mesa_printf("____________Fragment program %u ________\n", program->Base.Id); _mesa_print_program(&program->Base); diff --git a/src/mesa/shader/atifragshader.h b/src/mesa/shader/atifragshader.h index 32fb3a8019..e1dc20e606 100644 --- a/src/mesa/shader/atifragshader.h +++ b/src/mesa/shader/atifragshader.h @@ -8,6 +8,8 @@ #ifndef ATIFRAGSHADER_H #define ATIFRAGSHADER_H +#include "main/mtypes.h" + #define MAX_NUM_INSTRUCTIONS_PER_PASS_ATI 8 #define MAX_NUM_PASSES_ATI 2 #define MAX_NUM_FRAGMENT_REGISTERS_ATI 6 diff --git a/src/mesa/shader/grammar/descrip.mms b/src/mesa/shader/grammar/descrip.mms deleted file mode 100644 index 6976b70d6a..0000000000 --- a/src/mesa/shader/grammar/descrip.mms +++ /dev/null @@ -1,42 +0,0 @@ -# Makefile for core library for VMS -# contributed by Jouk Jansen joukj@hrem.nano.tudelft.nl -# Last revision : 29 September 2008 - -.first - define gl [----.include.gl] - define math [--.math] - define swrast [--.swrast] - define array_cache [--.array_cache] - define main [--.main] - -.include [----]mms-config. - -##### MACROS ##### - -VPATH = RCS - -INCDIR = [----.include],[],[--.main],[--.glapi],[-.slang] -LIBDIR = [----.lib] -CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1)/name=(as_is,short)/float=ieee/ieee=denorm - -SOURCES = grammar_mesa.c - -OBJECTS = grammar_mesa.obj - -##### RULES ##### - -VERSION=Mesa V3.4 - -##### TARGETS ##### -all : - $(MMS)$(MMSQUALIFIERS) $(LIBDIR)$(GL_LIB) - -# Make the library -$(LIBDIR)$(GL_LIB) : $(OBJECTS) - @ library $(LIBDIR)$(GL_LIB) $(OBJECTS) - -clean : - purge - delete *.obj;* - -grammar_mesa.obj : grammar_mesa.c grammar.c diff --git a/src/mesa/shader/prog_cache.c b/src/mesa/shader/prog_cache.c index 36a25377c5..9437e59613 100644 --- a/src/mesa/shader/prog_cache.c +++ b/src/mesa/shader/prog_cache.c @@ -44,6 +44,7 @@ struct cache_item struct gl_program_cache { struct cache_item **items; + struct cache_item *last; GLuint size, n_items; }; @@ -83,6 +84,8 @@ rehash(struct gl_program_cache *cache) struct cache_item *c, *next; GLuint size, i; + cache->last = NULL; + size = cache->size * 3; items = (struct cache_item**) _mesa_malloc(size * sizeof(*items)); _mesa_memset(items, 0, size * sizeof(*items)); @@ -105,6 +108,8 @@ clear_cache(GLcontext *ctx, struct gl_program_cache *cache) { struct cache_item *c, *next; GLuint i; + + cache->last = NULL; for (i = 0; i < cache->size; i++) { for (c = cache->items[i]; c; c = next) { @@ -149,18 +154,26 @@ _mesa_delete_program_cache(GLcontext *ctx, struct gl_program_cache *cache) struct gl_program * -_mesa_search_program_cache(const struct gl_program_cache *cache, +_mesa_search_program_cache(struct gl_program_cache *cache, const void *key, GLuint keysize) { - const GLuint hash = hash_key(key, keysize); - struct cache_item *c; - - for (c = cache->items[hash % cache->size]; c; c = c->next) { - if (c->hash == hash && memcmp(c->key, key, keysize) == 0) - return c->program; + if (cache->last && + memcmp(cache->last->key, key, keysize) == 0) { + return cache->last->program; } + else { + const GLuint hash = hash_key(key, keysize); + struct cache_item *c; + + for (c = cache->items[hash % cache->size]; c; c = c->next) { + if (c->hash == hash && memcmp(c->key, key, keysize) == 0) { + cache->last = c; + return c->program; + } + } - return NULL; + return NULL; + } } diff --git a/src/mesa/shader/prog_cache.h b/src/mesa/shader/prog_cache.h index a8c91fba01..4e1ccac03f 100644 --- a/src/mesa/shader/prog_cache.h +++ b/src/mesa/shader/prog_cache.h @@ -42,7 +42,7 @@ _mesa_delete_program_cache(GLcontext *ctx, struct gl_program_cache *pc); extern struct gl_program * -_mesa_search_program_cache(const struct gl_program_cache *cache, +_mesa_search_program_cache(struct gl_program_cache *cache, const void *key, GLuint keysize); extern void diff --git a/src/mesa/shader/prog_instruction.h b/src/mesa/shader/prog_instruction.h index 268afc528c..f978334ab2 100644 --- a/src/mesa/shader/prog_instruction.h +++ b/src/mesa/shader/prog_instruction.h @@ -418,11 +418,13 @@ struct prog_instruction */ GLint BranchTarget; +#if 0 /** * For TEX instructions in shaders, the sampler to use for the * texture lookup. */ GLint Sampler; +#endif const char *Comment; }; diff --git a/src/mesa/shader/prog_parameter.c b/src/mesa/shader/prog_parameter.c index 29c5b33f6c..e1729c7bff 100644 --- a/src/mesa/shader/prog_parameter.c +++ b/src/mesa/shader/prog_parameter.c @@ -422,7 +422,7 @@ _mesa_add_state_reference(struct gl_program_parameter_list *paramList, const gl_state_index stateTokens[STATE_LENGTH]) { const GLuint size = 4; /* XXX fix */ - const char *name; + char *name; GLint index; /* Check if the state reference is already in the list */ @@ -449,7 +449,7 @@ _mesa_add_state_reference(struct gl_program_parameter_list *paramList, paramList->StateFlags |= _mesa_program_state_flags(stateTokens); /* free name string here since we duplicated it in add_parameter() */ - _mesa_free((void *) name); + _mesa_free(name); return index; } diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c index baa4ef85e9..db6eac4fd9 100644 --- a/src/mesa/shader/prog_print.c +++ b/src/mesa/shader/prog_print.c @@ -250,7 +250,9 @@ reg_string(enum register_file f, GLint index, gl_prog_print_mode mode, { struct gl_program_parameter *param = prog->Parameters->Parameters + index; - sprintf(str, _mesa_program_state_string(param->StateIndexes)); + char *state = _mesa_program_state_string(param->StateIndexes); + sprintf(str, state); + _mesa_free(state); } break; case PROGRAM_ADDRESS: @@ -356,6 +358,19 @@ _mesa_swizzle_string(GLuint swizzle, GLuint negateBase, GLboolean extended) } +void +_mesa_print_swizzle(GLuint swizzle) +{ + if (swizzle == SWIZZLE_XYZW) { + _mesa_printf(".xyzw\n"); + } + else { + const char *s = _mesa_swizzle_string(swizzle, 0, 0); + _mesa_printf("%s\n", s); + } +} + + const char * _mesa_writemask_string(GLuint writeMask) { diff --git a/src/mesa/shader/prog_print.h b/src/mesa/shader/prog_print.h index cd9e388e82..3966909aed 100644 --- a/src/mesa/shader/prog_print.h +++ b/src/mesa/shader/prog_print.h @@ -47,6 +47,9 @@ const char * _mesa_writemask_string(GLuint writeMask); extern void +_mesa_print_swizzle(GLuint swizzle); + +extern void _mesa_print_alu_instruction(const struct prog_instruction *inst, const char *opcode_string, GLuint numRegs); diff --git a/src/mesa/shader/prog_statevars.c b/src/mesa/shader/prog_statevars.c index 971eb25a49..34c4741350 100644 --- a/src/mesa/shader/prog_statevars.c +++ b/src/mesa/shader/prog_statevars.c @@ -395,6 +395,12 @@ _mesa_fetch_state(GLcontext *ctx, const gl_state_index state[], case STATE_INTERNAL: switch (state[1]) { + case STATE_CURRENT_ATTRIB: { + const GLuint idx = (GLuint) state[2]; + COPY_4V(value, ctx->Current.Attrib[idx]); + return; + } + case STATE_NORMAL_SCALE: ASSIGN_4V(value, ctx->_ModelViewInvScale, @@ -501,6 +507,9 @@ _mesa_fetch_state(GLcontext *ctx, const gl_state_index state[], } return; + /* XXX: make sure new tokens added here are also handled in the + * _mesa_program_state_flags() switch, below. + */ default: /* unknown state indexes are silently ignored * should be handled by the driver. @@ -574,11 +583,29 @@ _mesa_program_state_flags(const gl_state_index state[STATE_LENGTH]) case STATE_INTERNAL: switch (state[1]) { + case STATE_CURRENT_ATTRIB: + return _NEW_CURRENT_ATTRIB; + + case STATE_NORMAL_SCALE: + return _NEW_MODELVIEW; + case STATE_TEXRECT_SCALE: case STATE_SHADOW_AMBIENT: return _NEW_TEXTURE; case STATE_FOG_PARAMS_OPTIMIZED: return _NEW_FOG; + case STATE_LIGHT_SPOT_DIR_NORMALIZED: + case STATE_LIGHT_POSITION: + case STATE_LIGHT_POSITION_NORMALIZED: + case STATE_LIGHT_HALF_VECTOR: + return _NEW_LIGHT; + + case STATE_PT_SCALE: + case STATE_PT_BIAS: + case STATE_PCM_SCALE: + case STATE_PCM_BIAS: + return _NEW_PIXEL; + default: /* unknown state indexes are silently ignored and * no flag set, since it is handled by the driver. @@ -784,7 +811,7 @@ append_index(char *dst, GLint index) * For example, return "state.matrix.texture[2].inverse". * Use _mesa_free() to deallocate the string. */ -const char * +char * _mesa_program_state_string(const gl_state_index state[STATE_LENGTH]) { char str[1000] = ""; diff --git a/src/mesa/shader/prog_statevars.h b/src/mesa/shader/prog_statevars.h index d3091147f8..72e51f4031 100644 --- a/src/mesa/shader/prog_statevars.h +++ b/src/mesa/shader/prog_statevars.h @@ -104,6 +104,7 @@ typedef enum gl_state_index_ { STATE_LOCAL, STATE_INTERNAL, /* Mesa additions */ + STATE_CURRENT_ATTRIB, /* ctx->Current vertex attrib value */ STATE_NORMAL_SCALE, STATE_TEXRECT_SCALE, STATE_FOG_PARAMS_OPTIMIZED, /* for faster fog calc */ @@ -130,7 +131,7 @@ extern GLbitfield _mesa_program_state_flags(const gl_state_index state[STATE_LENGTH]); -extern const char * +extern char * _mesa_program_state_string(const gl_state_index state[STATE_LENGTH]); diff --git a/src/mesa/shader/prog_uniform.c b/src/mesa/shader/prog_uniform.c index dc76be8e46..0642713148 100644 --- a/src/mesa/shader/prog_uniform.c +++ b/src/mesa/shader/prog_uniform.c @@ -142,8 +142,8 @@ _mesa_longest_uniform_name(const struct gl_uniform_list *list) GLint max = 0; GLuint i; for (i = 0; list && i < list->NumUniforms; i++) { - GLuint len = _mesa_strlen(list->Uniforms[i].Name); - if (len > (GLuint)max) + GLint len = (GLint)_mesa_strlen(list->Uniforms[i].Name); + if (len > max) max = len; } return max; diff --git a/src/mesa/shader/program.c b/src/mesa/shader/program.c index 738891a029..37962f0e9b 100644 --- a/src/mesa/shader/program.c +++ b/src/mesa/shader/program.c @@ -554,7 +554,6 @@ _mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count) return GL_TRUE; } - /** * Delete 'count' instructions at 'start' in the given program. * Adjust branch targets accordingly. @@ -691,17 +690,47 @@ _mesa_combine_programs(GLcontext *ctx, if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) { struct gl_fragment_program *fprogA, *fprogB, *newFprog; + GLbitfield progB_inputsRead = progB->InputsRead; + GLint progB_colorFile, progB_colorIndex; + fprogA = (struct gl_fragment_program *) progA; fprogB = (struct gl_fragment_program *) progB; newFprog = (struct gl_fragment_program *) newProg; newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill; + /* We'll do a search and replace for instances + * of progB_colorFile/progB_colorIndex below... + */ + progB_colorFile = PROGRAM_INPUT; + progB_colorIndex = FRAG_ATTRIB_COL0; + + /* + * The fragment program may get color from a state var rather than + * a fragment input (vertex output) if it's constant. + * See the texenvprogram.c code. + * So, search the program's parameter list now to see if the program + * gets color from a state var instead of a conventional fragment + * input register. + */ + for (i = 0; i < progB->Parameters->NumParameters; i++) { + struct gl_program_parameter *p = &progB->Parameters->Parameters[i]; + if (p->Type == PROGRAM_STATE_VAR && + p->StateIndexes[0] == STATE_INTERNAL && + p->StateIndexes[1] == STATE_CURRENT_ATTRIB && + p->StateIndexes[2] == VERT_ATTRIB_COLOR0) { + progB_inputsRead |= FRAG_BIT_COL0; + progB_colorFile = PROGRAM_STATE_VAR; + progB_colorIndex = i; + break; + } + } + /* Connect color outputs of fprogA to color inputs of fprogB, via a * new temporary register. */ if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLR)) && - (progB->InputsRead & (1 << FRAG_ATTRIB_COL0))) { + (progB_inputsRead & FRAG_BIT_COL0)) { GLint tempReg = _mesa_find_free_register(newProg, PROGRAM_TEMPORARY); if (tempReg < 0) { _mesa_problem(ctx, "No free temp regs found in " @@ -712,13 +741,14 @@ _mesa_combine_programs(GLcontext *ctx, replace_registers(newInst, lenA, PROGRAM_OUTPUT, FRAG_RESULT_COLR, PROGRAM_TEMPORARY, tempReg); - /* replace reads from input.color[0] with tempReg */ + /* replace reads from the input color with tempReg */ replace_registers(newInst + lenA, lenB, - PROGRAM_INPUT, FRAG_ATTRIB_COL0, - PROGRAM_TEMPORARY, tempReg); + progB_colorFile, progB_colorIndex, /* search for */ + PROGRAM_TEMPORARY, tempReg /* replace with */ ); } - inputsB = progB->InputsRead; + /* compute combined program's InputsRead */ + inputsB = progB_inputsRead; if (progA->OutputsWritten & (1 << FRAG_RESULT_COLR)) { inputsB &= ~(1 << FRAG_ATTRIB_COL0); } diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c index b3d66c5bab..122688826c 100644 --- a/src/mesa/shader/shader_api.c +++ b/src/mesa/shader/shader_api.c @@ -381,7 +381,7 @@ _mesa_init_shader_state(GLcontext * ctx) * are generated by the GLSL compiler. */ ctx->Shader.EmitHighLevelInstructions = GL_TRUE; - ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */ + ctx->Shader.EmitCondCodes = GL_FALSE;/*GL_TRUE;*/ /* XXX probably want GL_FALSE... */ ctx->Shader.EmitComments = GL_FALSE; } @@ -1117,7 +1117,8 @@ get_matrix_dims(GLenum type, GLint *rows, GLint *cols) /** * Determine the number of rows and columns occupied by a uniform - * according to its datatype. + * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4), + * the number of rows = 1 and cols = number of elements in the vector. */ static void get_uniform_rows_cols(const struct gl_program_parameter *p, @@ -1126,11 +1127,17 @@ get_uniform_rows_cols(const struct gl_program_parameter *p, get_matrix_dims(p->DataType, rows, cols); if (*rows == 0 && *cols == 0) { /* not a matrix type, probably a float or vector */ - *rows = p->Size / 4 + 1; - if (p->Size % 4 == 0) - *cols = 4; - else - *cols = p->Size % 4; + if (p->Size <= 4) { + *rows = 1; + *cols = p->Size; + } + else { + *rows = p->Size / 4 + 1; + if (p->Size % 4 == 0) + *cols = 4; + else + *cols = p->Size % 4; + } } } @@ -1527,7 +1534,7 @@ set_program_uniform(GLcontext *ctx, struct gl_program *program, return; } - if (index + offset > program->Parameters->Size) { + if (index + offset > (GLint) program->Parameters->Size) { /* out of bounds! */ return; } @@ -1592,7 +1599,7 @@ set_program_uniform(GLcontext *ctx, struct gl_program *program, /* if the uniform is bool-valued, convert to 1.0 or 0.0 */ if (is_boolean_type(param->DataType)) { for (i = 0; i < elems; i++) { - uniformVal[i] = uniformVal[i] ? 1.0 : 0.0; + uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f; } } } diff --git a/src/mesa/shader/slang/library/slang_version_syn.h b/src/mesa/shader/slang/library/slang_version_syn.h deleted file mode 100644 index 3b94d85927..0000000000 --- a/src/mesa/shader/slang/library/slang_version_syn.h +++ /dev/null @@ -1,64 +0,0 @@ -".syntax version_directive;\n" -"version_directive\n" -" version_directive_1 .and .loop version_directive_2;\n" -"version_directive_1\n" -" prior_optional_spaces .and optional_version_directive .and .true .emit $;\n" -"version_directive_2\n" -" prior_optional_spaces .and version_directive_body .and .true .emit $;\n" -"optional_version_directive\n" -" version_directive_body .or .true .emit 10 .emit 1;\n" -"version_directive_body\n" -" '#' .and optional_space .and \"version\" .and space .and version_number .and optional_space .and\n" -" new_line;\n" -"version_number\n" -" version_number_110;\n" -"version_number_110\n" -" leading_zeroes .and \"110\" .emit 10 .emit 1;\n" -"leading_zeroes\n" -" .loop zero;\n" -"zero\n" -" '0';\n" -"space\n" -" single_space .and .loop single_space;\n" -"optional_space\n" -" .loop single_space;\n" -"single_space\n" -" ' ' .or '\\t';\n" -"prior_optional_spaces\n" -" .loop prior_space;\n" -"prior_space\n" -" c_style_comment_block .or cpp_style_comment_block .or space .or new_line;\n" -"c_style_comment_block\n" -" '/' .and '*' .and c_style_comment_rest;\n" -"c_style_comment_rest\n" -" .loop c_style_comment_char_no_star .and c_style_comment_rest_1;\n" -"c_style_comment_rest_1\n" -" c_style_comment_end .or c_style_comment_rest_2;\n" -"c_style_comment_rest_2\n" -" '*' .and c_style_comment_rest;\n" -"c_style_comment_char_no_star\n" -" '\\x2B'-'\\xFF' .or '\\x01'-'\\x29';\n" -"c_style_comment_end\n" -" '*' .and '/';\n" -"cpp_style_comment_block\n" -" '/' .and '/' .and cpp_style_comment_block_1;\n" -"cpp_style_comment_block_1\n" -" cpp_style_comment_block_2 .or cpp_style_comment_block_3;\n" -"cpp_style_comment_block_2\n" -" .loop cpp_style_comment_char .and new_line;\n" -"cpp_style_comment_block_3\n" -" .loop cpp_style_comment_char;\n" -"cpp_style_comment_char\n" -" '\\x0E'-'\\xFF' .or '\\x01'-'\\x09' .or '\\x0B'-'\\x0C';\n" -"new_line\n" -" cr_lf .or lf_cr .or '\\n' .or '\\r';\n" -"cr_lf\n" -" '\\r' .and '\\n';\n" -"lf_cr\n" -" '\\n' .and '\\r';\n" -".string __string_filter;\n" -"__string_filter\n" -" .loop __identifier_char;\n" -"__identifier_char\n" -" 'a'-'z' .or 'A'-'Z' .or '_' .or '0'-'9';\n" -"" diff --git a/src/mesa/shader/slang/slang_link.c b/src/mesa/shader/slang/slang_link.c index 79fd9a064f..bed8cc3ee7 100644 --- a/src/mesa/shader/slang/slang_link.c +++ b/src/mesa/shader/slang/slang_link.c @@ -422,7 +422,6 @@ _slang_update_inputs_outputs(struct gl_program *prog) maxAddrReg = MAX2(maxAddrReg, inst->DstReg.Index + 1); } } - prog->NumAddressRegs = maxAddrReg; } diff --git a/src/mesa/sources b/src/mesa/sources index 9b9eb991fd..9a34d1a989 100644 --- a/src/mesa/sources +++ b/src/mesa/sources @@ -273,20 +273,19 @@ MESA_SOURCES = \ ALL_SOURCES = \ $(MESA_SOURCES) \ $(GLAPI_SOURCES) \ - $(ASM_SOURCES) \ + $(MESA_ASM_SOURCES) \ $(COMMON_DRIVER_SOURCES) - ### Object files MESA_OBJECTS = \ $(MESA_SOURCES:.c=.o) \ - $(ASM_SOURCES:.S=.o) + $(MESA_ASM_SOURCES:.S=.o) GLAPI_OBJECTS = \ $(GLAPI_SOURCES:.c=.o) \ - $(ASM_API:.S=.o) + $(GLAPI_ASM_SOURCES:.S=.o) COMMON_DRIVER_OBJECTS = $(COMMON_DRIVER_SOURCES:.c=.o) @@ -300,5 +299,4 @@ COMMON_DRIVER_OBJECTS = $(COMMON_DRIVER_SOURCES:.c=.o) INCLUDE_DIRS = \ -I$(TOP)/include \ - -I$(TOP)/src/mesa \ - -I$(TOP)/src/mesa/main + -I$(TOP)/src/mesa diff --git a/src/mesa/sources.mak b/src/mesa/sources.mak new file mode 100644 index 0000000000..14fd8597a8 --- /dev/null +++ b/src/mesa/sources.mak @@ -0,0 +1,348 @@ +### Lists of source files, included by Makefiles + +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/attrib.c \ + main/arrayobj.c \ + main/blend.c \ + main/bufferobj.c \ + main/buffers.c \ + main/clear.c \ + main/clip.c \ + main/colortab.c \ + main/context.c \ + main/convolve.c \ + main/debug.c \ + main/depth.c \ + main/depthstencil.c \ + main/dlist.c \ + main/drawpix.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/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/pixel.c \ + main/pixelstore.c \ + main/points.c \ + main/polygon.c \ + main/queryobj.c \ + main/rastpos.c \ + main/rbadaptors.c \ + main/readpix.c \ + main/renderbuffer.c \ + main/scissor.c \ + main/shaders.c \ + main/state.c \ + main/stencil.c \ + main/texcompress.c \ + main/texcompress_s3tc.c \ + main/texcompress_fxt1.c \ + main/texenv.c \ + main/texenvprogram.c \ + main/texformat.c \ + main/texgen.c \ + main/teximage.c \ + main/texobj.c \ + main/texparam.c \ + main/texrender.c \ + main/texstate.c \ + main/texstore.c \ + main/varray.c \ + main/vtxfmt.c + +GLAPI_SOURCES = \ + main/dispatch.c \ + glapi/glapi.c \ + glapi/glapi_getproc.c \ + glapi/glthread.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 + +__SWRAST_SOURCES = \ + swrast/s_aaline.c \ + swrast/s_aatriangle.c \ + swrast/s_accum.c \ + swrast/s_alpha.c \ + swrast/s_atifragshader.c \ + swrast/s_bitmap.c \ + swrast/s_blend.c \ + swrast/s_blit.c \ + swrast/s_buffers.c \ + swrast/s_copypix.c \ + swrast/s_context.c \ + swrast/s_depth.c \ + swrast/s_drawpix.c \ + swrast/s_feedback.c \ + swrast/s_fog.c \ + swrast/s_fragprog.c \ + swrast/s_imaging.c \ + swrast/s_lines.c \ + swrast/s_logic.c \ + swrast/s_masking.c \ + swrast/s_points.c \ + swrast/s_readpix.c \ + swrast/s_span.c \ + swrast/s_stencil.c \ + swrast/s_texcombine.c \ + swrast/s_texfilter.c \ + swrast/s_texstore.c \ + swrast/s_triangle.c \ + swrast/s_zoom.c + +__SWRAST_SETUP_SOURCES = \ + swrast_setup/ss_context.c \ + swrast_setup/ss_triangle.c + +__TNL_SOURCES = \ + tnl/t_context.c \ + tnl/t_pipeline.c \ + tnl/t_draw.c \ + tnl/t_rasterpos.c \ + tnl/t_vb_program.c \ + tnl/t_vb_render.c \ + tnl/t_vb_texgen.c \ + tnl/t_vb_texmat.c \ + tnl/t_vb_vertex.c \ + tnl/t_vb_cull.c \ + tnl/t_vb_fog.c \ + tnl/t_vb_light.c \ + tnl/t_vb_normals.c \ + tnl/t_vb_points.c \ + tnl/t_vp_build.c \ + tnl/t_vertex.c \ + tnl/t_vertex_sse.c \ + tnl/t_vertex_generic.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_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_flush.c \ + state_tracker/st_cb_get.c \ + state_tracker/st_cb_drawpixels.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_api.c \ + state_tracker/st_context.c \ + state_tracker/st_debug.c \ + state_tracker/st_draw.c \ + state_tracker/st_extensions.c \ + state_tracker/st_format.c \ + state_tracker/st_framebuffer.c \ + state_tracker/st_gen_mipmap.c \ + state_tracker/st_mesa_to_tgsi.c \ + state_tracker/st_program.c \ + state_tracker/st_texture.c + +SHADER_SOURCES = \ + shader/arbprogparse.c \ + shader/arbprogram.c \ + shader/atifragshader.c \ + shader/grammar/grammar_mesa.c \ + shader/nvfragparse.c \ + shader/nvprogram.c \ + shader/nvvertparse.c \ + shader/program.c \ + shader/prog_cache.c \ + shader/prog_debug.c \ + shader/prog_execute.c \ + shader/prog_instruction.c \ + shader/prog_parameter.c \ + shader/prog_print.c \ + shader/prog_statevars.c \ + shader/prog_uniform.c \ + shader/programopt.c \ + shader/shader_api.c \ + +SLANG_SOURCES = \ + shader/slang/slang_builtin.c \ + shader/slang/slang_codegen.c \ + shader/slang/slang_compile.c \ + shader/slang/slang_compile_function.c \ + shader/slang/slang_compile_operation.c \ + shader/slang/slang_compile_struct.c \ + shader/slang/slang_compile_variable.c \ + shader/slang/slang_emit.c \ + shader/slang/slang_ir.c \ + shader/slang/slang_label.c \ + shader/slang/slang_library_noise.c \ + shader/slang/slang_link.c \ + shader/slang/slang_log.c \ + shader/slang/slang_mem.c \ + shader/slang/slang_preprocess.c \ + shader/slang/slang_print.c \ + shader/slang/slang_simplify.c \ + shader/slang/slang_storage.c \ + shader/slang/slang_typeinfo.c \ + shader/slang/slang_vartable.c \ + shader/slang/slang_utility.c + +ASM_C_SOURCES = \ + x86/common_x86.c \ + x86/x86.c \ + x86/3dnow.c \ + x86/sse.c \ + sparc/sparc.c \ + ppc/common_ppc.c \ + x86-64/x86-64.c + +X86_SOURCES = \ + 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 + +X86_API = \ + x86/glapi_x86.S + +X86-64_SOURCES = \ + x86-64/xform4.S + +X86-64_API = \ + x86-64/glapi_x86-64.S + +SPARC_SOURCES = \ + sparc/clip.S \ + sparc/norm.S \ + sparc/xform.S + +SPARC_API = \ + sparc/glapi_sparc.S + +__COMMON_DRIVER_SOURCES = \ + drivers/common/driverfuncs.c + + + +### All the core C sources + +MESA_SOURCES = \ + $(MAIN_SOURCES) \ + $(MATH_SOURCES) \ + $(VBO_SOURCES) \ + $(STATETRACKER_SOURCES) \ + $(TNL_SOURCES) \ + $(SHADER_SOURCES) \ + $(SWRAST_SOURCES) \ + $(SWRAST_SETUP_SOURCES) \ + $(ASM_C_SOURCES) \ + $(SLANG_SOURCES) + +ALL_SOURCES = \ + $(MESA_SOURCES) \ + $(GLAPI_SOURCES) \ + $(MESA_ASM_SOURCES) \ + $(COMMON_DRIVER_SOURCES) + + +### Object files + +MESA_OBJECTS = \ + $(MESA_SOURCES:.c=.o) \ + $(MESA_ASM_SOURCES:.S=.o) + +GLAPI_OBJECTS = \ + $(GLAPI_SOURCES:.c=.o) \ + $(GLAPI_ASM_SOURCES:.S=.o) + + +COMMON_DRIVER_OBJECTS = $(COMMON_DRIVER_SOURCES:.c=.o) + + + +### Include directories + +INCLUDE_DIRS = \ + -I$(TOP)/include \ + -I$(TOP)/src/mesa \ + -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/drivers \ + -I$(TOP)/src/gallium/auxiliary diff --git a/src/mesa/state_tracker/Makefile b/src/mesa/state_tracker/Makefile new file mode 100644 index 0000000000..0ab1dc6e6b --- /dev/null +++ b/src/mesa/state_tracker/Makefile @@ -0,0 +1,2 @@ +default: + cd ../.. ; make
\ No newline at end of file diff --git a/src/mesa/state_tracker/st_api.c b/src/mesa/state_tracker/st_api.c new file mode 100644 index 0000000000..fc0e9a2316 --- /dev/null +++ b/src/mesa/state_tracker/st_api.c @@ -0,0 +1,33 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +/** + * Just a global symbol for EGL to look for to identify the supported + * graphics API. + */ +int st_api_OpenGL = 1; diff --git a/src/mesa/state_tracker/st_atom.c b/src/mesa/state_tracker/st_atom.c new file mode 100644 index 0000000000..fc8587f459 --- /dev/null +++ b/src/mesa/state_tracker/st_atom.c @@ -0,0 +1,218 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "main/glheader.h" +#include "main/context.h" + +#include "pipe/p_defines.h" +#include "st_context.h" +#include "st_atom.h" +#include "st_cb_bitmap.h" +#include "st_program.h" + + + +/* This is used to initialize st->atoms[]. We could use this list + * directly except for a single atom, st_update_constants, which has a + * .dirty value which changes according to the parameters of the + * current fragment and vertex programs, and so cannot be a static + * value. + */ +static const struct st_tracked_state *atoms[] = +{ + &st_update_depth_stencil_alpha, + &st_update_clip, + + &st_finalize_textures, + &st_update_shader, + + &st_update_rasterizer, + &st_update_polygon_stipple, + &st_update_viewport, + &st_update_scissor, + &st_update_blend, + &st_update_sampler, + &st_update_texture, + &st_update_framebuffer, + &st_update_vs_constants, + &st_update_fs_constants, + &st_update_pixel_transfer +}; + + +void st_init_atoms( struct st_context *st ) +{ + GLuint i; + + st->atoms = malloc(sizeof(atoms)); + st->nr_atoms = sizeof(atoms)/sizeof(*atoms); + memcpy(st->atoms, atoms, sizeof(atoms)); + + /* Patch in a pointer to the dynamic state atom: + */ + for (i = 0; i < st->nr_atoms; i++) { + if (st->atoms[i] == &st_update_vs_constants) { + st->atoms[i] = &st->constants.tracked_state[PIPE_SHADER_VERTEX]; + st->atoms[i][0] = st_update_vs_constants; + } + + if (st->atoms[i] == &st_update_fs_constants) { + st->atoms[i] = &st->constants.tracked_state[PIPE_SHADER_FRAGMENT]; + st->atoms[i][0] = st_update_fs_constants; + } + } +} + + +void st_destroy_atoms( struct st_context *st ) +{ + if (st->atoms) { + free(st->atoms); + st->atoms = NULL; + } +} + + +/*********************************************************************** + */ + +static GLboolean check_state( const struct st_state_flags *a, + const struct st_state_flags *b ) +{ + return ((a->mesa & b->mesa) || + (a->st & b->st)); +} + +static void accumulate_state( struct st_state_flags *a, + const struct st_state_flags *b ) +{ + a->mesa |= b->mesa; + a->st |= b->st; +} + + +static void xor_states( struct st_state_flags *result, + const struct st_state_flags *a, + const struct st_state_flags *b ) +{ + result->mesa = a->mesa ^ b->mesa; + result->st = a->st ^ b->st; +} + + +/* Too complex to figure out, just check every time: + */ +static void check_program_state( struct st_context *st ) +{ + GLcontext *ctx = st->ctx; + + if (ctx->VertexProgram._Current != &st->vp->Base) + st->dirty.st |= ST_NEW_VERTEX_PROGRAM; + + if (ctx->FragmentProgram._Current != &st->fp->Base) + st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM; + +} + + +/*********************************************************************** + * Update all derived state: + */ + +void st_validate_state( struct st_context *st ) +{ + struct st_state_flags *state = &st->dirty; + GLuint i; + + /* The bitmap cache is immune to pixel unpack changes. + * Note that GLUT makes several calls to glPixelStore for each + * bitmap char it draws so this is an important check. + */ + if (state->mesa & ~_NEW_PACKUNPACK) + st_flush_bitmap_cache(st); + + check_program_state( st ); + + if (state->st == 0) + return; + +// _mesa_printf("%s %x/%x\n", __FUNCTION__, state->mesa, state->st); + + if (1) { + /* Debug version which enforces various sanity checks on the + * state flags which are generated and checked to help ensure + * state atoms are ordered correctly in the list. + */ + struct st_state_flags examined, prev; + memset(&examined, 0, sizeof(examined)); + prev = *state; + + for (i = 0; i < st->nr_atoms; i++) { + const struct st_tracked_state *atom = st->atoms[i]; + struct st_state_flags generated; + +// _mesa_printf("atom %s %x/%x\n", atom->name, atom->dirty.mesa, atom->dirty.st); + + if (!(atom->dirty.mesa || atom->dirty.st) || + !atom->update) { + _mesa_printf("malformed atom %s\n", atom->name); + assert(0); + } + + if (check_state(state, &atom->dirty)) { + st->atoms[i]->update( st ); +// _mesa_printf("after: %x\n", atom->dirty.mesa); + } + + accumulate_state(&examined, &atom->dirty); + + /* generated = (prev ^ state) + * if (examined & generated) + * fail; + */ + xor_states(&generated, &prev, state); + assert(!check_state(&examined, &generated)); + prev = *state; + } +// _mesa_printf("\n"); + + } + else { + const GLuint nr = st->nr_atoms; + + for (i = 0; i < nr; i++) { + if (check_state(state, &st->atoms[i]->dirty)) + st->atoms[i]->update( st ); + } + } + + memset(state, 0, sizeof(*state)); +} + + + diff --git a/src/mesa/state_tracker/st_atom.h b/src/mesa/state_tracker/st_atom.h new file mode 100644 index 0000000000..c7cffd85c8 --- /dev/null +++ b/src/mesa/state_tracker/st_atom.h @@ -0,0 +1,66 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + + +#ifndef ST_ATOM_H +#define ST_ATOM_H + +struct st_context; +struct st_tracked_state; + +void st_init_atoms( struct st_context *st ); +void st_destroy_atoms( struct st_context *st ); + + +void st_validate_state( struct st_context *st ); + + +extern const struct st_tracked_state st_update_framebuffer; +extern const struct st_tracked_state st_update_clip; +extern const struct st_tracked_state st_update_depth_stencil_alpha; +extern const struct st_tracked_state st_update_shader; +extern const struct st_tracked_state st_update_rasterizer; +extern const struct st_tracked_state st_update_polygon_stipple; +extern const struct st_tracked_state st_update_viewport; +extern const struct st_tracked_state st_update_scissor; +extern const struct st_tracked_state st_update_blend; +extern const struct st_tracked_state st_update_sampler; +extern const struct st_tracked_state st_update_texture; +extern const struct st_tracked_state st_finalize_textures; +extern const struct st_tracked_state st_update_fs_constants; +extern const struct st_tracked_state st_update_vs_constants; +extern const struct st_tracked_state st_update_pixel_transfer; + + +uint st_compare_func_to_pipe(GLenum func); + +#endif diff --git a/src/mesa/state_tracker/st_atom_blend.c b/src/mesa/state_tracker/st_atom_blend.c new file mode 100644 index 0000000000..35c09c3e08 --- /dev/null +++ b/src/mesa/state_tracker/st_atom_blend.c @@ -0,0 +1,232 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + */ + + +#include "st_context.h" +#include "st_atom.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "cso_cache/cso_context.h" + +#include "main/macros.h" + +/** + * Convert GLenum blend tokens to pipe tokens. + * Both blend factors and blend funcs are accepted. + */ +static GLuint +translate_blend(GLenum blend) +{ + switch (blend) { + /* blend functions */ + case GL_FUNC_ADD: + return PIPE_BLEND_ADD; + case GL_FUNC_SUBTRACT: + return PIPE_BLEND_SUBTRACT; + case GL_FUNC_REVERSE_SUBTRACT: + return PIPE_BLEND_REVERSE_SUBTRACT; + case GL_MIN: + return PIPE_BLEND_MIN; + case GL_MAX: + return PIPE_BLEND_MAX; + + /* blend factors */ + case GL_ONE: + return PIPE_BLENDFACTOR_ONE; + case GL_SRC_COLOR: + return PIPE_BLENDFACTOR_SRC_COLOR; + case GL_SRC_ALPHA: + return PIPE_BLENDFACTOR_SRC_ALPHA; + case GL_DST_ALPHA: + return PIPE_BLENDFACTOR_DST_ALPHA; + case GL_DST_COLOR: + return PIPE_BLENDFACTOR_DST_COLOR; + case GL_SRC_ALPHA_SATURATE: + return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE; + case GL_CONSTANT_COLOR: + return PIPE_BLENDFACTOR_CONST_COLOR; + case GL_CONSTANT_ALPHA: + return PIPE_BLENDFACTOR_CONST_ALPHA; + /* + return PIPE_BLENDFACTOR_SRC1_COLOR; + return PIPE_BLENDFACTOR_SRC1_ALPHA; + */ + case GL_ZERO: + return PIPE_BLENDFACTOR_ZERO; + case GL_ONE_MINUS_SRC_COLOR: + return PIPE_BLENDFACTOR_INV_SRC_COLOR; + case GL_ONE_MINUS_SRC_ALPHA: + return PIPE_BLENDFACTOR_INV_SRC_ALPHA; + case GL_ONE_MINUS_DST_COLOR: + return PIPE_BLENDFACTOR_INV_DST_COLOR; + case GL_ONE_MINUS_DST_ALPHA: + return PIPE_BLENDFACTOR_INV_DST_ALPHA; + case GL_ONE_MINUS_CONSTANT_COLOR: + return PIPE_BLENDFACTOR_INV_CONST_COLOR; + case GL_ONE_MINUS_CONSTANT_ALPHA: + return PIPE_BLENDFACTOR_INV_CONST_ALPHA; + /* + return PIPE_BLENDFACTOR_INV_SRC1_COLOR; + return PIPE_BLENDFACTOR_INV_SRC1_ALPHA; + */ + default: + assert("invalid GL token in translate_blend()" == NULL); + return 0; + } +} + + +/** + * Convert GLenum logicop tokens to pipe tokens. + */ +static GLuint +translate_logicop(GLenum logicop) +{ + switch (logicop) { + case GL_CLEAR: + return PIPE_LOGICOP_CLEAR; + case GL_NOR: + return PIPE_LOGICOP_NOR; + case GL_AND_INVERTED: + return PIPE_LOGICOP_AND_INVERTED; + case GL_COPY_INVERTED: + return PIPE_LOGICOP_COPY_INVERTED; + case GL_AND_REVERSE: + return PIPE_LOGICOP_AND_REVERSE; + case GL_INVERT: + return PIPE_LOGICOP_INVERT; + case GL_XOR: + return PIPE_LOGICOP_XOR; + case GL_NAND: + return PIPE_LOGICOP_NAND; + case GL_AND: + return PIPE_LOGICOP_AND; + case GL_EQUIV: + return PIPE_LOGICOP_EQUIV; + case GL_NOOP: + return PIPE_LOGICOP_NOOP; + case GL_OR_INVERTED: + return PIPE_LOGICOP_OR_INVERTED; + case GL_COPY: + return PIPE_LOGICOP_COPY; + case GL_OR_REVERSE: + return PIPE_LOGICOP_OR_REVERSE; + case GL_OR: + return PIPE_LOGICOP_OR; + case GL_SET: + return PIPE_LOGICOP_SET; + default: + assert("invalid GL token in translate_logicop()" == NULL); + return 0; + } +} + + +static void +update_blend( struct st_context *st ) +{ + struct pipe_blend_state *blend = &st->state.blend; + + memset(blend, 0, sizeof(*blend)); + + if (st->ctx->Color.ColorLogicOpEnabled || + (st->ctx->Color.BlendEnabled && + st->ctx->Color.BlendEquationRGB == GL_LOGIC_OP)) { + /* logicop enabled */ + blend->logicop_enable = 1; + blend->logicop_func = translate_logicop(st->ctx->Color.LogicOp); + } + else if (st->ctx->Color.BlendEnabled) { + /* blending enabled */ + blend->blend_enable = 1; + + blend->rgb_func = translate_blend(st->ctx->Color.BlendEquationRGB); + if (st->ctx->Color.BlendEquationRGB == GL_MIN || + st->ctx->Color.BlendEquationRGB == GL_MAX) { + /* Min/max are special */ + blend->rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend->rgb_dst_factor = PIPE_BLENDFACTOR_ONE; + } + else { + blend->rgb_src_factor = translate_blend(st->ctx->Color.BlendSrcRGB); + blend->rgb_dst_factor = translate_blend(st->ctx->Color.BlendDstRGB); + } + + blend->alpha_func = translate_blend(st->ctx->Color.BlendEquationA); + if (st->ctx->Color.BlendEquationA == GL_MIN || + st->ctx->Color.BlendEquationA == GL_MAX) { + /* Min/max are special */ + blend->alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend->alpha_dst_factor = PIPE_BLENDFACTOR_ONE; + } + else { + blend->alpha_src_factor = translate_blend(st->ctx->Color.BlendSrcA); + blend->alpha_dst_factor = translate_blend(st->ctx->Color.BlendDstA); + } + } + else { + /* no blending / logicop */ + } + + /* Colormask - maybe reverse these bits? */ + if (st->ctx->Color.ColorMask[0]) + blend->colormask |= PIPE_MASK_R; + if (st->ctx->Color.ColorMask[1]) + blend->colormask |= PIPE_MASK_G; + if (st->ctx->Color.ColorMask[2]) + blend->colormask |= PIPE_MASK_B; + if (st->ctx->Color.ColorMask[3]) + blend->colormask |= PIPE_MASK_A; + + if (st->ctx->Color.DitherFlag) + blend->dither = 1; + + cso_set_blend(st->cso_context, blend); + + { + struct pipe_blend_color bc; + COPY_4FV(bc.color, st->ctx->Color.BlendColor); + cso_set_blend_color(st->cso_context, &bc); + } +} + + +const struct st_tracked_state st_update_blend = { + "st_update_blend", /* name */ + { /* dirty */ + (_NEW_COLOR), /* XXX _NEW_BLEND someday? */ /* mesa */ + 0, /* st */ + }, + update_blend, /* update */ +}; diff --git a/src/mesa/state_tracker/st_atom_clip.c b/src/mesa/state_tracker/st_atom_clip.c new file mode 100644 index 0000000000..23d709b814 --- /dev/null +++ b/src/mesa/state_tracker/st_atom_clip.c @@ -0,0 +1,71 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + + +#include "st_context.h" +#include "pipe/p_context.h" +#include "st_atom.h" + + +/* Second state atom for user clip planes: + */ +static void update_clip( struct st_context *st ) +{ + struct pipe_clip_state clip; + GLuint i; + + memset(&clip, 0, sizeof(clip)); + + for (i = 0; i < PIPE_MAX_CLIP_PLANES; i++) { + if (st->ctx->Transform.ClipPlanesEnabled & (1 << i)) { + memcpy(clip.ucp[clip.nr], + st->ctx->Transform._ClipUserPlane[i], + sizeof(clip.ucp[0])); + clip.nr++; + } + } + + if (memcmp(&clip, &st->state.clip, sizeof(clip)) != 0) { + st->state.clip = clip; + st->pipe->set_clip_state(st->pipe, &clip); + } +} + + +const struct st_tracked_state st_update_clip = { + "st_update_clip", /* name */ + { /* dirty */ + (_NEW_TRANSFORM), /* mesa */ + 0, /* st */ + }, + update_clip /* update */ +}; diff --git a/src/mesa/state_tracker/st_atom_constbuf.c b/src/mesa/state_tracker/st_atom_constbuf.c new file mode 100644 index 0000000000..d02e51cb9a --- /dev/null +++ b/src/mesa/state_tracker/st_atom_constbuf.c @@ -0,0 +1,142 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + */ + +#include "main/imports.h" +#include "shader/prog_parameter.h" +#include "shader/prog_print.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" + +#include "st_context.h" +#include "st_atom.h" +#include "st_atom_constbuf.h" +#include "st_program.h" + + +/** + * Pass the given program parameters to the graphics pipe as a + * constant buffer. + * \param id either PIPE_SHADER_VERTEX or PIPE_SHADER_FRAGMENT + */ +void st_upload_constants( struct st_context *st, + struct gl_program_parameter_list *params, + unsigned id) +{ + struct pipe_context *pipe = st->pipe; + struct pipe_constant_buffer *cbuf = &st->state.constants[id]; + + assert(id == PIPE_SHADER_VERTEX || id == PIPE_SHADER_FRAGMENT); + + /* update constants */ + if (params && params->NumParameters) { + const uint paramBytes = params->NumParameters * sizeof(GLfloat) * 4; + + /* Update our own dependency flags. This works because this + * function will also be called whenever the program changes. + */ + st->constants.tracked_state[id].dirty.mesa = + (params->StateFlags | _NEW_PROGRAM); + + _mesa_load_state_parameters(st->ctx, params); + + /* We always need to get a new buffer, to keep the drivers simple and + * avoid gratuitous rendering synchronization. + */ + pipe_buffer_reference(pipe->screen, &cbuf->buffer, NULL ); + cbuf->buffer = pipe_buffer_create(pipe->screen, 16, PIPE_BUFFER_USAGE_CONSTANT, + paramBytes ); + + if (0) + { + printf("%s(shader=%d, numParams=%d, stateFlags=0x%x)\n", + __FUNCTION__, id, params->NumParameters, params->StateFlags); + _mesa_print_parameter_list(params); + } + + /* load Mesa constants into the constant buffer */ + if (cbuf->buffer) { + void *map = pipe_buffer_map(pipe->screen, cbuf->buffer, + PIPE_BUFFER_USAGE_CPU_WRITE); + memcpy(map, params->ParameterValues, paramBytes); + pipe_buffer_unmap(pipe->screen, cbuf->buffer); + } + + cbuf->size = paramBytes; + + st->pipe->set_constant_buffer(st->pipe, id, 0, cbuf); + } + else { + st->constants.tracked_state[id].dirty.mesa = 0; + // st->pipe->set_constant_buffer(st->pipe, id, 0, NULL); + } +} + +/* Vertex shader: + */ +static void update_vs_constants(struct st_context *st ) +{ + struct st_vertex_program *vp = st->vp; + struct gl_program_parameter_list *params = vp->Base.Base.Parameters; + + st_upload_constants( st, params, PIPE_SHADER_VERTEX ); +} + +const struct st_tracked_state st_update_vs_constants = { + "st_update_vs_constants", /* name */ + { /* dirty */ + 0, /* set dynamically above */ /* mesa */ + ST_NEW_VERTEX_PROGRAM, /* st */ + }, + update_vs_constants /* update */ +}; + +/* Fragment shader: + */ +static void update_fs_constants(struct st_context *st ) +{ + struct st_fragment_program *fp = st->fp; + struct gl_program_parameter_list *params = fp->Base.Base.Parameters; + + st_upload_constants( st, params, PIPE_SHADER_FRAGMENT ); +} + +const struct st_tracked_state st_update_fs_constants = { + "st_update_fs_constants", /* name */ + { /* dirty */ + 0, /* set dynamically above */ /* mesa */ + ST_NEW_FRAGMENT_PROGRAM, /* st */ + }, + update_fs_constants /* update */ +}; + diff --git a/src/mesa/state_tracker/st_atom_constbuf.h b/src/mesa/state_tracker/st_atom_constbuf.h new file mode 100644 index 0000000000..f707534e2c --- /dev/null +++ b/src/mesa/state_tracker/st_atom_constbuf.h @@ -0,0 +1,38 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_ATOM_CONSTBUF_H +#define ST_ATOM_CONSTBUF_H + + +void st_upload_constants( struct st_context *st, + struct gl_program_parameter_list *params, + unsigned id); + + +#endif /* ST_ATOM_CONSTBUF_H */ diff --git a/src/mesa/state_tracker/st_atom_depth.c b/src/mesa/state_tracker/st_atom_depth.c new file mode 100644 index 0000000000..0e791ceb20 --- /dev/null +++ b/src/mesa/state_tracker/st_atom_depth.c @@ -0,0 +1,151 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + * Zack Rusin + */ + + +#include "st_context.h" +#include "st_atom.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "cso_cache/cso_context.h" + + +/** + * Convert an OpenGL compare mode to a pipe tokens. + */ +GLuint +st_compare_func_to_pipe(GLenum func) +{ + /* Same values, just biased */ + assert(PIPE_FUNC_NEVER == GL_NEVER - GL_NEVER); + assert(PIPE_FUNC_LESS == GL_LESS - GL_NEVER); + assert(PIPE_FUNC_EQUAL == GL_EQUAL - GL_NEVER); + assert(PIPE_FUNC_LEQUAL == GL_LEQUAL - GL_NEVER); + assert(PIPE_FUNC_GREATER == GL_GREATER - GL_NEVER); + assert(PIPE_FUNC_NOTEQUAL == GL_NOTEQUAL - GL_NEVER); + assert(PIPE_FUNC_GEQUAL == GL_GEQUAL - GL_NEVER); + assert(PIPE_FUNC_ALWAYS == GL_ALWAYS - GL_NEVER); + assert(func >= GL_NEVER); + assert(func <= GL_ALWAYS); + return func - GL_NEVER; +} + + +/** + * Convert GLenum stencil op tokens to pipe tokens. + */ +static GLuint +gl_stencil_op_to_pipe(GLenum func) +{ + switch (func) { + case GL_KEEP: + return PIPE_STENCIL_OP_KEEP; + case GL_ZERO: + return PIPE_STENCIL_OP_ZERO; + case GL_REPLACE: + return PIPE_STENCIL_OP_REPLACE; + case GL_INCR: + return PIPE_STENCIL_OP_INCR; + case GL_DECR: + return PIPE_STENCIL_OP_DECR; + case GL_INCR_WRAP: + return PIPE_STENCIL_OP_INCR_WRAP; + case GL_DECR_WRAP: + return PIPE_STENCIL_OP_DECR_WRAP; + case GL_INVERT: + return PIPE_STENCIL_OP_INVERT; + default: + assert("invalid GL token in gl_stencil_op_to_pipe()" == NULL); + return 0; + } +} + +static void +update_depth_stencil_alpha(struct st_context *st) +{ + struct pipe_depth_stencil_alpha_state *dsa = &st->state.depth_stencil; + + memset(dsa, 0, sizeof(*dsa)); + + dsa->depth.enabled = st->ctx->Depth.Test; + dsa->depth.writemask = st->ctx->Depth.Mask; + dsa->depth.func = st_compare_func_to_pipe(st->ctx->Depth.Func); + + if (st->ctx->Query.CurrentOcclusionObject && + st->ctx->Query.CurrentOcclusionObject->Active) + dsa->depth.occlusion_count = 1; + + if (st->ctx->Stencil.Enabled && st->ctx->Visual.stencilBits > 0) { + dsa->stencil[0].enabled = 1; + dsa->stencil[0].func = st_compare_func_to_pipe(st->ctx->Stencil.Function[0]); + dsa->stencil[0].fail_op = gl_stencil_op_to_pipe(st->ctx->Stencil.FailFunc[0]); + dsa->stencil[0].zfail_op = gl_stencil_op_to_pipe(st->ctx->Stencil.ZFailFunc[0]); + dsa->stencil[0].zpass_op = gl_stencil_op_to_pipe(st->ctx->Stencil.ZPassFunc[0]); + dsa->stencil[0].ref_value = st->ctx->Stencil.Ref[0] & 0xff; + dsa->stencil[0].value_mask = st->ctx->Stencil.ValueMask[0] & 0xff; + dsa->stencil[0].write_mask = st->ctx->Stencil.WriteMask[0] & 0xff; + + if (st->ctx->Stencil._TestTwoSide) { + dsa->stencil[1].enabled = 1; + dsa->stencil[1].func = st_compare_func_to_pipe(st->ctx->Stencil.Function[1]); + dsa->stencil[1].fail_op = gl_stencil_op_to_pipe(st->ctx->Stencil.FailFunc[1]); + dsa->stencil[1].zfail_op = gl_stencil_op_to_pipe(st->ctx->Stencil.ZFailFunc[1]); + dsa->stencil[1].zpass_op = gl_stencil_op_to_pipe(st->ctx->Stencil.ZPassFunc[1]); + dsa->stencil[1].ref_value = st->ctx->Stencil.Ref[1] & 0xff; + dsa->stencil[1].value_mask = st->ctx->Stencil.ValueMask[1] & 0xff; + dsa->stencil[1].write_mask = st->ctx->Stencil.WriteMask[1] & 0xff; + } + else { + dsa->stencil[1] = dsa->stencil[0]; + dsa->stencil[1].enabled = 0; + } + } + + if (st->ctx->Color.AlphaEnabled) { + dsa->alpha.enabled = 1; + dsa->alpha.func = st_compare_func_to_pipe(st->ctx->Color.AlphaFunc); + dsa->alpha.ref = st->ctx->Color.AlphaRef; + } + + cso_set_depth_stencil_alpha(st->cso_context, dsa); +} + + +const struct st_tracked_state st_update_depth_stencil_alpha = { + "st_update_depth_stencil", /* name */ + { /* dirty */ + (_NEW_DEPTH|_NEW_STENCIL|_NEW_COLOR), /* mesa */ + 0, /* st */ + }, + update_depth_stencil_alpha /* update */ +}; diff --git a/src/mesa/state_tracker/st_atom_framebuffer.c b/src/mesa/state_tracker/st_atom_framebuffer.c new file mode 100644 index 0000000000..ca1a719a9a --- /dev/null +++ b/src/mesa/state_tracker/st_atom_framebuffer.c @@ -0,0 +1,165 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + */ + +#include "st_context.h" +#include "st_atom.h" +#include "st_cb_fbo.h" +#include "st_texture.h" +#include "pipe/p_context.h" +#include "pipe/p_inlines.h" +#include "cso_cache/cso_context.h" + + + +/** + * When doing GL render to texture, we have to be sure that finalize_texture() + * didn't yank out the pipe_texture that we earlier created a surface for. + * Check for that here and create a new surface if needed. + */ +static void +update_renderbuffer_surface(struct st_context *st, + struct st_renderbuffer *strb) +{ + struct pipe_screen *screen = st->pipe->screen; + struct pipe_texture *texture = strb->rtt->pt; + int rtt_width = strb->Base.Width; + int rtt_height = strb->Base.Height; + + if (!strb->surface || + strb->surface->texture != texture || + strb->surface->width != rtt_width || + strb->surface->height != rtt_height) { + GLuint level; + /* find matching mipmap level size */ + for (level = 0; level <= texture->last_level; level++) { + if (texture->width[level] == rtt_width && + texture->height[level] == rtt_height) { + + pipe_surface_reference(&strb->surface, NULL); + + strb->surface = screen->get_tex_surface(screen, + texture, + strb->rtt_face, + level, + strb->rtt_slice, + PIPE_BUFFER_USAGE_GPU_READ | + PIPE_BUFFER_USAGE_GPU_WRITE); +#if 0 + printf("-- alloc new surface %d x %d into tex %p\n", + strb->surface->width, strb->surface->height, + texture); +#endif + break; + } + } + } +} + + +/** + * Update framebuffer state (color, depth, stencil, etc. buffers) + */ +static void +update_framebuffer_state( struct st_context *st ) +{ + struct pipe_framebuffer_state *framebuffer = &st->state.framebuffer; + struct gl_framebuffer *fb = st->ctx->DrawBuffer; + struct st_renderbuffer *strb; + GLuint i; + + memset(framebuffer, 0, sizeof(*framebuffer)); + + framebuffer->width = fb->Width; + framebuffer->height = fb->Height; + + /*printf("------ fb size %d x %d\n", fb->Width, fb->Height);*/ + + /* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state + * to determine which surfaces to draw to + */ + framebuffer->num_cbufs = 0; + for (i = 0; i < fb->_NumColorDrawBuffers; i++) { + strb = st_renderbuffer(fb->_ColorDrawBuffers[i]); + + /*printf("--------- framebuffer surface rtt %p\n", strb->rtt);*/ + if (strb->rtt) { + /* rendering to a GL texture, may have to update surface */ + update_renderbuffer_surface(st, strb); + } + + if (strb->surface) { + framebuffer->cbufs[framebuffer->num_cbufs] = strb->surface; + framebuffer->num_cbufs++; + } + } + + strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer); + if (strb) { + strb = st_renderbuffer(strb->Base.Wrapped); + if (strb->rtt) { + /* rendering to a GL texture, may have to update surface */ + update_renderbuffer_surface(st, strb); + } + + framebuffer->zsbuf = strb->surface; + } + else { + strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer); + if (strb) { + strb = st_renderbuffer(strb->Base.Wrapped); + assert(strb->surface); + framebuffer->zsbuf = strb->surface; + } + } + + cso_set_framebuffer(st->cso_context, framebuffer); + + if (fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT) { + if (st->frontbuffer_status == FRONT_STATUS_COPY_OF_BACK) { + /* XXX copy back buf to front? */ + } + /* we're assuming we'll really draw to the front buffer */ + st->frontbuffer_status = FRONT_STATUS_DIRTY; + } +} + + +const struct st_tracked_state st_update_framebuffer = { + "st_update_framebuffer", /* name */ + { /* dirty */ + _NEW_BUFFERS, /* mesa */ + ST_NEW_FRAMEBUFFER, /* st */ + }, + update_framebuffer_state /* update */ +}; + diff --git a/src/mesa/state_tracker/st_atom_pixeltransfer.c b/src/mesa/state_tracker/st_atom_pixeltransfer.c new file mode 100644 index 0000000000..a357b71677 --- /dev/null +++ b/src/mesa/state_tracker/st_atom_pixeltransfer.c @@ -0,0 +1,474 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* + * Generate fragment programs to implement pixel transfer ops, such as + * scale/bias, colormatrix, colortable, convolution... + * + * Authors: + * Brian Paul + */ + +#include "main/imports.h" +#include "main/image.h" +#include "main/macros.h" +#include "shader/program.h" +#include "shader/prog_instruction.h" +#include "shader/prog_parameter.h" +#include "shader/prog_print.h" + +#include "st_context.h" +#include "st_format.h" +#include "st_program.h" +#include "st_texture.h" + +#include "pipe/p_screen.h" +#include "pipe/p_context.h" +#include "pipe/p_inlines.h" +#include "util/u_pack_color.h" + + +struct state_key +{ + GLuint scaleAndBias:1; + GLuint colorMatrix:1; + GLuint colorMatrixPostScaleBias:1; + GLuint pixelMaps:1; + +#if 0 + GLfloat Maps[3][256][4]; + int NumMaps; + GLint NumStages; + pipeline_stage Stages[STAGE_MAX]; + GLboolean StagesUsed[STAGE_MAX]; + GLfloat Scale1[4], Bias1[4]; + GLfloat Scale2[4], Bias2[4]; +#endif +}; + + +static GLboolean +is_identity(const GLfloat m[16]) +{ + GLuint i; + for (i = 0; i < 16; i++) { + const int row = i % 4, col = i / 4; + const float val = (GLfloat)(row == col); + if (m[i] != val) + return GL_FALSE; + } + return GL_TRUE; +} + + +static void +make_state_key(GLcontext *ctx, struct state_key *key) +{ + static const GLfloat zero[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + static const GLfloat one[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + + memset(key, 0, sizeof(*key)); + + if (ctx->Pixel.RedBias != 0.0 || ctx->Pixel.RedScale != 1.0 || + ctx->Pixel.GreenBias != 0.0 || ctx->Pixel.GreenScale != 1.0 || + ctx->Pixel.BlueBias != 0.0 || ctx->Pixel.BlueScale != 1.0 || + ctx->Pixel.AlphaBias != 0.0 || ctx->Pixel.AlphaScale != 1.0) { + key->scaleAndBias = 1; + } + + if (!is_identity(ctx->ColorMatrixStack.Top->m)) { + key->colorMatrix = 1; + } + + if (!TEST_EQ_4V(ctx->Pixel.PostColorMatrixScale, one) || + !TEST_EQ_4V(ctx->Pixel.PostColorMatrixBias, zero)) { + key->colorMatrixPostScaleBias = 1; + } + + key->pixelMaps = ctx->Pixel.MapColorFlag; +} + + +static struct pipe_texture * +create_color_map_texture(GLcontext *ctx) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct pipe_texture *pt; + enum pipe_format format; + const uint texSize = 256; /* simple, and usually perfect */ + + /* find an RGBA texture format */ + format = st_choose_format(pipe, GL_RGBA, PIPE_TEXTURE_2D, PIPE_TEXTURE_USAGE_SAMPLER); + + /* create texture for color map/table */ + pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, format, 0, + texSize, texSize, 1, 0, + PIPE_TEXTURE_USAGE_SAMPLER); + return pt; +} + + +/** + * Update the pixelmap texture with the contents of the R/G/B/A pixel maps. + */ +static void +load_color_map_texture(GLcontext *ctx, struct pipe_texture *pt) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_surface *surface; + const GLuint rSize = ctx->PixelMaps.RtoR.Size; + const GLuint gSize = ctx->PixelMaps.GtoG.Size; + const GLuint bSize = ctx->PixelMaps.BtoB.Size; + const GLuint aSize = ctx->PixelMaps.AtoA.Size; + const uint texSize = pt->width[0]; + uint *dest; + uint i, j; + + surface = screen->get_tex_surface(screen, pt, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_WRITE); + dest = (uint *) screen->surface_map(screen, surface, + PIPE_BUFFER_USAGE_CPU_WRITE); + + /* Pack four 1D maps into a 2D texture: + * R map is placed horizontally, indexed by S, in channel 0 + * G map is placed vertically, indexed by T, in channel 1 + * B map is placed horizontally, indexed by S, in channel 2 + * A map is placed vertically, indexed by T, in channel 3 + */ + for (i = 0; i < texSize; i++) { + for (j = 0; j < texSize; j++) { + int k = (i * texSize + j); + ubyte r = ctx->PixelMaps.RtoR.Map8[j * rSize / texSize]; + ubyte g = ctx->PixelMaps.GtoG.Map8[i * gSize / texSize]; + ubyte b = ctx->PixelMaps.BtoB.Map8[j * bSize / texSize]; + ubyte a = ctx->PixelMaps.AtoA.Map8[i * aSize / texSize]; + util_pack_color_ub(r, g, b, a, pt->format, dest + k); + } + } + + screen->surface_unmap(screen, surface); + pipe_surface_reference(&surface, NULL); +} + + + +#define MAX_INST 100 + +/** + * Returns a fragment program which implements the current pixel transfer ops. + */ +static struct gl_fragment_program * +get_pixel_transfer_program(GLcontext *ctx, const struct state_key *key) +{ + struct st_context *st = ctx->st; + struct prog_instruction inst[MAX_INST]; + struct gl_program_parameter_list *params; + struct gl_fragment_program *fp; + GLuint ic = 0; + const GLuint colorTemp = 0; + + fp = (struct gl_fragment_program *) + ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); + if (!fp) + return NULL; + + params = _mesa_new_parameter_list(); + + /* + * Get initial pixel color from the texture. + * TEX colorTemp, fragment.texcoord[0], texture[0], 2D; + */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_TEX; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = colorTemp; + inst[ic].SrcReg[0].File = PROGRAM_INPUT; + inst[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; + inst[ic].TexSrcUnit = 0; + inst[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + fp->Base.InputsRead = (1 << FRAG_ATTRIB_TEX0); + fp->Base.OutputsWritten = (1 << FRAG_RESULT_COLR); + fp->Base.SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ + + if (key->scaleAndBias) { + static const gl_state_index scale_state[STATE_LENGTH] = + { STATE_INTERNAL, STATE_PT_SCALE, 0, 0, 0 }; + static const gl_state_index bias_state[STATE_LENGTH] = + { STATE_INTERNAL, STATE_PT_BIAS, 0, 0, 0 }; + GLfloat scale[4], bias[4]; + GLint scale_p, bias_p; + + scale[0] = ctx->Pixel.RedScale; + scale[1] = ctx->Pixel.GreenScale; + scale[2] = ctx->Pixel.BlueScale; + scale[3] = ctx->Pixel.AlphaScale; + bias[0] = ctx->Pixel.RedBias; + bias[1] = ctx->Pixel.GreenBias; + bias[2] = ctx->Pixel.BlueBias; + bias[3] = ctx->Pixel.AlphaBias; + + scale_p = _mesa_add_state_reference(params, scale_state); + bias_p = _mesa_add_state_reference(params, bias_state); + + /* MAD colorTemp, colorTemp, scale, bias; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_MAD; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = colorTemp; + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = colorTemp; + inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR; + inst[ic].SrcReg[1].Index = scale_p; + inst[ic].SrcReg[2].File = PROGRAM_STATE_VAR; + inst[ic].SrcReg[2].Index = bias_p; + ic++; + } + + if (key->pixelMaps) { + const GLuint temp = 1; + + /* create the colormap/texture now if not already done */ + if (!st->pixel_xfer.pixelmap_texture) { + st->pixel_xfer.pixelmap_texture = create_color_map_texture(ctx); + } + + /* with a little effort, we can do four pixel map look-ups with + * two TEX instructions: + */ + + /* TEX temp.rg, colorTemp.rgba, texture[1], 2D; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_TEX; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = temp; + inst[ic].DstReg.WriteMask = WRITEMASK_XY; /* write R,G */ + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = colorTemp; + inst[ic].TexSrcUnit = 1; + inst[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + + /* TEX temp.ba, colorTemp.baba, texture[1], 2D; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_TEX; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = temp; + inst[ic].DstReg.WriteMask = WRITEMASK_ZW; /* write B,A */ + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = colorTemp; + inst[ic].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W, + SWIZZLE_Z, SWIZZLE_W); + inst[ic].TexSrcUnit = 1; + inst[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + + /* MOV colorTemp, temp; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_MOV; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = colorTemp; + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = temp; + ic++; + + fp->Base.SamplersUsed |= (1 << 1); /* sampler 1 is used */ + } + + if (key->colorMatrix) { + static const gl_state_index row0_state[STATE_LENGTH] = + { STATE_COLOR_MATRIX, 0, 0, 0, 0 }; + static const gl_state_index row1_state[STATE_LENGTH] = + { STATE_COLOR_MATRIX, 0, 1, 1, 0 }; + static const gl_state_index row2_state[STATE_LENGTH] = + { STATE_COLOR_MATRIX, 0, 2, 2, 0 }; + static const gl_state_index row3_state[STATE_LENGTH] = + { STATE_COLOR_MATRIX, 0, 3, 3, 0 }; + + GLint row0_p = _mesa_add_state_reference(params, row0_state); + GLint row1_p = _mesa_add_state_reference(params, row1_state); + GLint row2_p = _mesa_add_state_reference(params, row2_state); + GLint row3_p = _mesa_add_state_reference(params, row3_state); + const GLuint temp = 1; + + /* DP4 temp.x, colorTemp, matrow0; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_DP4; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = temp; + inst[ic].DstReg.WriteMask = WRITEMASK_X; + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = colorTemp; + inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR; + inst[ic].SrcReg[1].Index = row0_p; + ic++; + + /* DP4 temp.y, colorTemp, matrow1; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_DP4; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = temp; + inst[ic].DstReg.WriteMask = WRITEMASK_Y; + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = colorTemp; + inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR; + inst[ic].SrcReg[1].Index = row1_p; + ic++; + + /* DP4 temp.z, colorTemp, matrow2; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_DP4; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = temp; + inst[ic].DstReg.WriteMask = WRITEMASK_Z; + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = colorTemp; + inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR; + inst[ic].SrcReg[1].Index = row2_p; + ic++; + + /* DP4 temp.w, colorTemp, matrow3; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_DP4; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = temp; + inst[ic].DstReg.WriteMask = WRITEMASK_W; + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = colorTemp; + inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR; + inst[ic].SrcReg[1].Index = row3_p; + ic++; + + /* MOV colorTemp, temp; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_MOV; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = colorTemp; + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = temp; + ic++; + } + + if (key->colorMatrixPostScaleBias) { + static const gl_state_index scale_state[STATE_LENGTH] = + { STATE_INTERNAL, STATE_PT_SCALE, 0, 0, 0 }; + static const gl_state_index bias_state[STATE_LENGTH] = + { STATE_INTERNAL, STATE_PT_BIAS, 0, 0, 0 }; + GLint scale_param, bias_param; + + scale_param = _mesa_add_state_reference(params, scale_state); + bias_param = _mesa_add_state_reference(params, bias_state); + + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_MAD; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = colorTemp; + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = colorTemp; + inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR; + inst[ic].SrcReg[1].Index = scale_param; + inst[ic].SrcReg[2].File = PROGRAM_STATE_VAR; + inst[ic].SrcReg[2].Index = bias_param; + ic++; + } + + /* Modify last instruction's dst reg to write to result.color */ + { + struct prog_instruction *last = &inst[ic - 1]; + last->DstReg.File = PROGRAM_OUTPUT; + last->DstReg.Index = FRAG_RESULT_COLR; + } + + /* END; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_END; + ic++; + + assert(ic <= MAX_INST); + + + fp->Base.Instructions = _mesa_alloc_instructions(ic); + if (!fp->Base.Instructions) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "generating pixel transfer program"); + return NULL; + } + + _mesa_copy_instructions(fp->Base.Instructions, inst, ic); + fp->Base.NumInstructions = ic; + fp->Base.Parameters = params; + +#if 0 + printf("========= pixel transfer prog\n"); + _mesa_print_program(&fp->Base); + _mesa_print_parameter_list(fp->Base.Parameters); +#endif + + return fp; +} + + + +/** + * Update st->pixel_xfer.program in response to new pixel-transfer state. + */ +static void +update_pixel_transfer(struct st_context *st) +{ + GLcontext *ctx = st->ctx; + struct state_key key; + struct gl_fragment_program *fp; + + make_state_key(st->ctx, &key); + + fp = (struct gl_fragment_program *) + _mesa_search_program_cache(st->pixel_xfer.cache, &key, sizeof(key)); + if (!fp) { + fp = get_pixel_transfer_program(st->ctx, &key); + _mesa_program_cache_insert(st->ctx, st->pixel_xfer.cache, + &key, sizeof(key), &fp->Base); + } + + if (ctx->Pixel.MapColorFlag) { + load_color_map_texture(ctx, st->pixel_xfer.pixelmap_texture); + } + st->pixel_xfer.pixelmap_enabled = ctx->Pixel.MapColorFlag; + + st->pixel_xfer.program = (struct st_fragment_program *) fp; +} + + + +const struct st_tracked_state st_update_pixel_transfer = { + "st_update_pixel_transfer", /* name */ + { /* dirty */ + _NEW_PIXEL | _NEW_COLOR_MATRIX, /* mesa */ + 0, /* st */ + }, + update_pixel_transfer /* update */ +}; diff --git a/src/mesa/state_tracker/st_atom_rasterizer.c b/src/mesa/state_tracker/st_atom_rasterizer.c new file mode 100644 index 0000000000..5eef4ebe92 --- /dev/null +++ b/src/mesa/state_tracker/st_atom_rasterizer.c @@ -0,0 +1,286 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "main/macros.h" +#include "st_context.h" +#include "st_atom.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "cso_cache/cso_context.h" + + +static GLuint translate_fill( GLenum mode ) +{ + switch (mode) { + case GL_POINT: + return PIPE_POLYGON_MODE_POINT; + case GL_LINE: + return PIPE_POLYGON_MODE_LINE; + case GL_FILL: + return PIPE_POLYGON_MODE_FILL; + default: + assert(0); + return 0; + } +} + +static GLboolean get_offset_flag( GLuint fill_mode, + const struct gl_polygon_attrib *p ) +{ + switch (fill_mode) { + case PIPE_POLYGON_MODE_POINT: + return p->OffsetPoint; + case PIPE_POLYGON_MODE_LINE: + return p->OffsetLine; + case PIPE_POLYGON_MODE_FILL: + return p->OffsetFill; + default: + assert(0); + return 0; + } +} + + +static void update_raster_state( struct st_context *st ) +{ + GLcontext *ctx = st->ctx; + struct pipe_rasterizer_state *raster = &st->state.rasterizer; + const struct gl_vertex_program *vertProg = ctx->VertexProgram._Current; + uint i; + + memset(raster, 0, sizeof(*raster)); + + raster->origin_lower_left = 1; /* Always true for OpenGL */ + + /* _NEW_POLYGON, _NEW_BUFFERS + */ + { + if (ctx->Polygon.FrontFace == GL_CCW) + raster->front_winding = PIPE_WINDING_CCW; + else + raster->front_winding = PIPE_WINDING_CW; + + /* XXX + * I think the intention here is that user-created framebuffer objects + * use Y=0=TOP layout instead of OpenGL's normal Y=0=bottom layout. + * Flipping Y changes CW to CCW and vice-versa. + * But this is an implementation/driver-specific artifact - remove... + */ + if (ctx->DrawBuffer && ctx->DrawBuffer->Name != 0) + raster->front_winding ^= PIPE_WINDING_BOTH; + } + + /* _NEW_LIGHT + */ + if (ctx->Light.ShadeModel == GL_FLAT) + raster->flatshade = 1; + + /* _NEW_LIGHT | _NEW_PROGRAM + * + * Back-face colors can come from traditional lighting (when + * GL_LIGHT_MODEL_TWO_SIDE is set) or from vertex programs (when + * GL_VERTEX_PROGRAM_TWO_SIDE is set). Note the logic here. + */ + if (ctx->VertexProgram._Current) { + if (ctx->VertexProgram._Enabled) { + /* user-defined program */ + raster->light_twoside = ctx->VertexProgram.TwoSideEnabled; + } + else { + /* TNL-generated program */ + raster->light_twoside = ctx->Light.Enabled && ctx->Light.Model.TwoSide; + } + } + else if (ctx->Light.Enabled && ctx->Light.Model.TwoSide) { + raster->light_twoside = 1; + } + + /* _NEW_POLYGON + */ + if (ctx->Polygon.CullFlag) { + if (ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) { + raster->cull_mode = PIPE_WINDING_BOTH; + } + else if (ctx->Polygon.CullFaceMode == GL_FRONT) { + raster->cull_mode = raster->front_winding; + } + else { + raster->cull_mode = raster->front_winding ^ PIPE_WINDING_BOTH; + } + } + + /* _NEW_POLYGON + */ + { + GLuint fill_front = translate_fill( ctx->Polygon.FrontMode ); + GLuint fill_back = translate_fill( ctx->Polygon.BackMode ); + + if (raster->front_winding == PIPE_WINDING_CW) { + raster->fill_cw = fill_front; + raster->fill_ccw = fill_back; + } + else { + raster->fill_cw = fill_back; + raster->fill_ccw = fill_front; + } + + /* Simplify when culling is active: + */ + if (raster->cull_mode & PIPE_WINDING_CW) { + raster->fill_cw = raster->fill_ccw; + } + + if (raster->cull_mode & PIPE_WINDING_CCW) { + raster->fill_ccw = raster->fill_cw; + } + } + + /* _NEW_POLYGON + */ + if (ctx->Polygon.OffsetUnits != 0.0 || + ctx->Polygon.OffsetFactor != 0.0) { + raster->offset_cw = get_offset_flag( raster->fill_cw, &ctx->Polygon ); + raster->offset_ccw = get_offset_flag( raster->fill_ccw, &ctx->Polygon ); + raster->offset_units = ctx->Polygon.OffsetUnits; + raster->offset_scale = ctx->Polygon.OffsetFactor; + } + + if (ctx->Polygon.SmoothFlag) + raster->poly_smooth = 1; + + if (ctx->Polygon.StippleFlag) + raster->poly_stipple_enable = 1; + + + /* _NEW_BUFFERS, _NEW_POLYGON + */ + if (raster->fill_cw != PIPE_POLYGON_MODE_FILL || + raster->fill_ccw != PIPE_POLYGON_MODE_FILL) + { + GLfloat mrd = (ctx->DrawBuffer ? + ctx->DrawBuffer->_MRD : + 1.0f); + + raster->offset_units = ctx->Polygon.OffsetFactor * mrd; + raster->offset_scale = (ctx->Polygon.OffsetUnits * mrd * + st->polygon_offset_scale); + } + + /* _NEW_POINT + */ + raster->point_size = ctx->Point.Size; + + raster->point_size_min = 0; /* temporary, will go away */ + raster->point_size_max = 1000; /* temporary, will go away */ + + raster->point_smooth = ctx->Point.SmoothFlag; + raster->point_sprite = ctx->Point.PointSprite; + for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { + if (ctx->Point.CoordReplace[i]) { + if (ctx->Point.SpriteOrigin == GL_UPPER_LEFT) + raster->sprite_coord_mode[i] = PIPE_SPRITE_COORD_UPPER_LEFT; + else + raster->sprite_coord_mode[i] = PIPE_SPRITE_COORD_LOWER_LEFT; + } + else { + raster->sprite_coord_mode[i] = PIPE_SPRITE_COORD_NONE; + } + } + + /* ST_NEW_VERTEX_PROGRAM + */ + if (vertProg) { + if (vertProg->Base.Id == 0) { + if (vertProg->Base.OutputsWritten & (1 << VERT_RESULT_PSIZ)) { + /* generated program which emits point size */ + raster->point_size_per_vertex = TRUE; + } + } + else if (ctx->VertexProgram.PointSizeEnabled) { + /* user-defined program and GL_VERTEX_PROGRAM_POINT_SIZE set */ + raster->point_size_per_vertex = ctx->VertexProgram.PointSizeEnabled; + } + } + if (!raster->point_size_per_vertex) { + /* clamp size now */ + raster->point_size = CLAMP(ctx->Point.Size, + ctx->Point.MinSize, + ctx->Point.MaxSize); + } + + /* _NEW_LINE + */ + raster->line_smooth = ctx->Line.SmoothFlag; + if (ctx->Line.SmoothFlag) { + raster->line_width = CLAMP(ctx->Line.Width, + ctx->Const.MinLineWidthAA, + ctx->Const.MaxLineWidthAA); + } + else { + raster->line_width = CLAMP(ctx->Line.Width, + ctx->Const.MinLineWidth, + ctx->Const.MaxLineWidth); + } + + raster->line_stipple_enable = ctx->Line.StippleFlag; + raster->line_stipple_pattern = ctx->Line.StipplePattern; + /* GL stipple factor is in [1,256], remap to [0, 255] here */ + raster->line_stipple_factor = ctx->Line.StippleFactor - 1; + + /* _NEW_MULTISAMPLE */ + if (ctx->Multisample._Enabled || st->force_msaa) + raster->multisample = 1; + + /* _NEW_SCISSOR */ + if (ctx->Scissor.Enabled) + raster->scissor = 1; + + raster->gl_rasterization_rules = 1; + + cso_set_rasterizer(st->cso_context, raster); +} + +const struct st_tracked_state st_update_rasterizer = { + "st_update_rasterizer", /* name */ + { + (_NEW_BUFFERS | + _NEW_LIGHT | + _NEW_LINE | + _NEW_MULTISAMPLE | + _NEW_POINT | + _NEW_POLYGON | + _NEW_PROGRAM | + _NEW_SCISSOR), /* mesa state dependencies*/ + ST_NEW_VERTEX_PROGRAM, /* state tracker dependencies */ + }, + update_raster_state /* update function */ +}; diff --git a/src/mesa/state_tracker/st_atom_sampler.c b/src/mesa/state_tracker/st_atom_sampler.c new file mode 100644 index 0000000000..cef61fb55c --- /dev/null +++ b/src/mesa/state_tracker/st_atom_sampler.c @@ -0,0 +1,211 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + */ + + +#include "main/macros.h" + +#include "st_context.h" +#include "st_cb_texture.h" +#include "st_atom.h" +#include "st_program.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" + +#include "cso_cache/cso_context.h" + + +/** + * Convert GLenum texcoord wrap tokens to pipe tokens. + */ +static GLuint +gl_wrap_to_sp(GLenum wrap) +{ + switch (wrap) { + case GL_REPEAT: + return PIPE_TEX_WRAP_REPEAT; + case GL_CLAMP: + return PIPE_TEX_WRAP_CLAMP; + case GL_CLAMP_TO_EDGE: + return PIPE_TEX_WRAP_CLAMP_TO_EDGE; + case GL_CLAMP_TO_BORDER: + return PIPE_TEX_WRAP_CLAMP_TO_BORDER; + case GL_MIRRORED_REPEAT: + return PIPE_TEX_WRAP_MIRROR_REPEAT; + case GL_MIRROR_CLAMP_EXT: + return PIPE_TEX_WRAP_MIRROR_CLAMP; + case GL_MIRROR_CLAMP_TO_EDGE_EXT: + return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; + case GL_MIRROR_CLAMP_TO_BORDER_EXT: + return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; + default: + assert(0); + return 0; + } +} + + +static GLuint +gl_filter_to_mip_filter(GLenum filter) +{ + switch (filter) { + case GL_NEAREST: + case GL_LINEAR: + return PIPE_TEX_MIPFILTER_NONE; + + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + return PIPE_TEX_MIPFILTER_NEAREST; + + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + return PIPE_TEX_MIPFILTER_LINEAR; + + default: + assert(0); + return PIPE_TEX_MIPFILTER_NONE; + } +} + + +static GLuint +gl_filter_to_img_filter(GLenum filter) +{ + switch (filter) { + case GL_NEAREST: + case GL_NEAREST_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + return PIPE_TEX_FILTER_NEAREST; + + case GL_LINEAR: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_LINEAR: + return PIPE_TEX_FILTER_LINEAR; + + default: + assert(0); + return PIPE_TEX_FILTER_NEAREST; + } +} + + +static void +update_samplers(struct st_context *st) +{ + const struct st_fragment_program *fs = st->fp; + GLuint su; + + st->state.num_samplers = 0; + + /*printf("%s samplers used = 0x%x\n", __FUNCTION__, fs->Base.Base.SamplersUsed);*/ + + /* loop over sampler units (aka tex image units) */ + for (su = 0; su < st->ctx->Const.MaxTextureImageUnits; su++) { + struct pipe_sampler_state *sampler = st->state.samplers + su; + + memset(sampler, 0, sizeof(*sampler)); + + if (fs->Base.Base.SamplersUsed & (1 << su)) { + GLuint texUnit = fs->Base.Base.SamplerUnits[su]; + const struct gl_texture_object *texobj + = st->ctx->Texture.Unit[texUnit]._Current; + + if (!texobj) { + texobj = st_get_default_texture(st); + } + + sampler->wrap_s = gl_wrap_to_sp(texobj->WrapS); + sampler->wrap_t = gl_wrap_to_sp(texobj->WrapT); + sampler->wrap_r = gl_wrap_to_sp(texobj->WrapR); + + sampler->min_img_filter = gl_filter_to_img_filter(texobj->MinFilter); + sampler->min_mip_filter = gl_filter_to_mip_filter(texobj->MinFilter); + sampler->mag_img_filter = gl_filter_to_img_filter(texobj->MagFilter); + + if (texobj->Target != GL_TEXTURE_RECTANGLE_ARB) + sampler->normalized_coords = 1; + + sampler->lod_bias = st->ctx->Texture.Unit[su].LodBias; + sampler->min_lod = MAX2(0.0f, texobj->MinLod); + sampler->max_lod = MIN2(texobj->MaxLevel - texobj->BaseLevel, + texobj->MaxLod); + if (sampler->max_lod < sampler->min_lod) { + /* The GL spec doesn't seem to specify what to do in this case. + * Swap the values. + */ + float tmp = sampler->max_lod; + sampler->max_lod = sampler->min_lod; + sampler->min_lod = tmp; + assert(sampler->min_lod <= sampler->max_lod); + } + + sampler->border_color[0] = texobj->BorderColor[RCOMP]; + sampler->border_color[1] = texobj->BorderColor[GCOMP]; + sampler->border_color[2] = texobj->BorderColor[BCOMP]; + sampler->border_color[3] = texobj->BorderColor[ACOMP]; + + sampler->max_anisotropy = texobj->MaxAnisotropy; + if (sampler->max_anisotropy > 1.0) { + sampler->min_img_filter = PIPE_TEX_FILTER_ANISO; + sampler->mag_img_filter = PIPE_TEX_FILTER_ANISO; + } + + /* only care about ARB_shadow, not SGI shadow */ + if (texobj->CompareMode == GL_COMPARE_R_TO_TEXTURE) { + sampler->compare_mode = PIPE_TEX_COMPARE_R_TO_TEXTURE; + sampler->compare_func + = st_compare_func_to_pipe(texobj->CompareFunc); + } + + st->state.num_samplers = su + 1; + + /*printf("%s su=%u non-null\n", __FUNCTION__, su);*/ + cso_single_sampler(st->cso_context, su, sampler); + } + else { + /*printf("%s su=%u null\n", __FUNCTION__, su);*/ + cso_single_sampler(st->cso_context, su, NULL); + } + } + + cso_single_sampler_done(st->cso_context); +} + + +const struct st_tracked_state st_update_sampler = { + "st_update_sampler", /* name */ + { /* dirty */ + _NEW_TEXTURE, /* mesa */ + 0, /* st */ + }, + update_samplers /* update */ +}; diff --git a/src/mesa/state_tracker/st_atom_scissor.c b/src/mesa/state_tracker/st_atom_scissor.c new file mode 100644 index 0000000000..3fd59e1945 --- /dev/null +++ b/src/mesa/state_tracker/st_atom_scissor.c @@ -0,0 +1,92 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + + +#include "st_context.h" +#include "pipe/p_context.h" +#include "st_atom.h" + + +/** + * Scissor depends on the scissor box, and the framebuffer dimensions. + */ +static void +update_scissor( struct st_context *st ) +{ + struct pipe_scissor_state scissor; + const struct gl_framebuffer *fb = st->ctx->DrawBuffer; + GLint miny, maxy; + + scissor.minx = 0; + scissor.miny = 0; + scissor.maxx = fb->Width; + scissor.maxy = fb->Height; + + if (st->ctx->Scissor.Enabled) { + if ((GLuint)st->ctx->Scissor.X > scissor.minx) + scissor.minx = st->ctx->Scissor.X; + if ((GLuint)st->ctx->Scissor.Y > scissor.miny) + scissor.miny = st->ctx->Scissor.Y; + + if ((GLuint)st->ctx->Scissor.X + st->ctx->Scissor.Width < scissor.maxx) + scissor.maxx = st->ctx->Scissor.X + st->ctx->Scissor.Width; + if ((GLuint)st->ctx->Scissor.Y + st->ctx->Scissor.Height < scissor.maxy) + scissor.maxy = st->ctx->Scissor.Y + st->ctx->Scissor.Height; + + /* check for null space */ + if (scissor.minx >= scissor.maxx || scissor.miny >= scissor.maxy) + scissor.minx = scissor.miny = scissor.maxx = scissor.maxy = 0; + } + + /* Now invert Y. Pipe drivers use the convention Y=0=top for surfaces + */ + miny = fb->Height - scissor.maxy; + maxy = fb->Height - scissor.miny; + scissor.miny = miny; + scissor.maxy = maxy; + + if (memcmp(&scissor, &st->state.scissor, sizeof(scissor)) != 0) { + /* state has changed */ + st->state.scissor = scissor; /* struct copy */ + st->pipe->set_scissor_state(st->pipe, &scissor); /* activate */ + } +} + + +const struct st_tracked_state st_update_scissor = { + "st_update_scissor", /* name */ + { /* dirty */ + (_NEW_SCISSOR | _NEW_BUFFERS), /* mesa */ + 0, /* st */ + }, + update_scissor /* update */ +}; diff --git a/src/mesa/state_tracker/st_atom_shader.c b/src/mesa/state_tracker/st_atom_shader.c new file mode 100644 index 0000000000..cbd414e2d3 --- /dev/null +++ b/src/mesa/state_tracker/st_atom_shader.c @@ -0,0 +1,369 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * State validation for vertex/fragment shaders. + * Note that we have to delay most vertex/fragment shader translation + * until rendering time since the linkage between the vertex outputs and + * fragment inputs can vary depending on the pairing of shaders. + * + * Authors: + * Brian Paul + */ + + + +#include "main/imports.h" +#include "main/mtypes.h" +#include "main/macros.h" +#include "shader/program.h" + +#include "pipe/p_context.h" +#include "pipe/p_shader_tokens.h" + +#include "util/u_simple_shaders.h" + +#include "cso_cache/cso_context.h" + +#include "st_context.h" +#include "st_atom.h" +#include "st_program.h" +#include "st_atom_shader.h" +#include "st_mesa_to_tgsi.h" + + +/** + * This represents a vertex program, especially translated to match + * the inputs of a particular fragment shader. + */ +struct translated_vertex_program +{ + struct st_vertex_program *master; + + /** The fragment shader "signature" this vertex shader is meant for: */ + GLbitfield frag_inputs; + + /** Compared against master vertex program's serialNo: */ + GLuint serialNo; + + /** Maps VERT_RESULT_x to slot */ + GLuint output_to_slot[VERT_RESULT_MAX]; + ubyte output_to_semantic_name[VERT_RESULT_MAX]; + ubyte output_to_semantic_index[VERT_RESULT_MAX]; + + /** Pointer to the translated vertex program */ + struct st_vertex_program *vp; + + struct translated_vertex_program *next; /**< next in linked list */ +}; + + + +/** + * Given a vertex program output attribute, return the corresponding + * fragment program input attribute. + * \return -1 for vertex outputs that have no corresponding fragment input + */ +static GLint +vp_out_to_fp_in(GLuint vertResult) +{ + if (vertResult >= VERT_RESULT_TEX0 && + vertResult < VERT_RESULT_TEX0 + MAX_TEXTURE_COORD_UNITS) + return FRAG_ATTRIB_TEX0 + (vertResult - VERT_RESULT_TEX0); + + if (vertResult >= VERT_RESULT_VAR0 && + vertResult < VERT_RESULT_VAR0 + MAX_VARYING) + return FRAG_ATTRIB_VAR0 + (vertResult - VERT_RESULT_VAR0); + + switch (vertResult) { + case VERT_RESULT_HPOS: + return FRAG_ATTRIB_WPOS; + case VERT_RESULT_COL0: + return FRAG_ATTRIB_COL0; + case VERT_RESULT_COL1: + return FRAG_ATTRIB_COL1; + case VERT_RESULT_FOGC: + return FRAG_ATTRIB_FOGC; + default: + /* Back-face colors, edge flags, etc */ + return -1; + } +} + + +/** + * Find a translated vertex program that corresponds to stvp and + * has outputs matched to stfp's inputs. + * This performs vertex and fragment translation (to TGSI) when needed. + */ +static struct translated_vertex_program * +find_translated_vp(struct st_context *st, + struct st_vertex_program *stvp, + struct st_fragment_program *stfp) +{ + static const GLuint UNUSED = ~0; + struct translated_vertex_program *xvp; + const GLbitfield fragInputsRead = stfp->Base.Base.InputsRead; + + /* + * Translate fragment program if needed. + */ + if (!stfp->state.tokens) { + GLuint inAttr, numIn = 0; + + for (inAttr = 0; inAttr < FRAG_ATTRIB_MAX; inAttr++) { + if (fragInputsRead & (1 << inAttr)) { + stfp->input_to_slot[inAttr] = numIn; + numIn++; + } + else { + stfp->input_to_slot[inAttr] = UNUSED; + } + } + + stfp->num_input_slots = numIn; + + assert(stfp->Base.Base.NumInstructions > 1); + + st_translate_fragment_program(st, stfp, stfp->input_to_slot); + } + + + /* See if we've got a translated vertex program whose outputs match + * the fragment program's inputs. + * XXX This could be a hash lookup, using InputsRead as the key. + */ + for (xvp = stfp->vertex_programs; xvp; xvp = xvp->next) { + if (xvp->master == stvp && xvp->frag_inputs == fragInputsRead) { + break; + } + } + + /* No? Allocate translated vp object now */ + if (!xvp) { + xvp = CALLOC_STRUCT(translated_vertex_program); + xvp->frag_inputs = fragInputsRead; + xvp->master = stvp; + + xvp->next = stfp->vertex_programs; + stfp->vertex_programs = xvp; + } + + /* See if we need to translate vertex program to TGSI form */ + if (xvp->serialNo != stvp->serialNo) { + GLuint outAttr, dummySlot; + const GLbitfield outputsWritten = stvp->Base.Base.OutputsWritten; + GLuint numVpOuts = 0; + GLboolean emitPntSize = GL_FALSE, emitBFC0 = GL_FALSE, emitBFC1 = GL_FALSE; + GLint maxGeneric; + + /* Compute mapping of vertex program outputs to slots, which depends + * on the fragment program's input->slot mapping. + */ + for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) { + /* set defaults: */ + xvp->output_to_slot[outAttr] = UNUSED; + xvp->output_to_semantic_name[outAttr] = TGSI_SEMANTIC_COUNT; + xvp->output_to_semantic_index[outAttr] = 99; + + if (outAttr == VERT_RESULT_HPOS) { + /* always put xformed position into slot zero */ + xvp->output_to_slot[VERT_RESULT_HPOS] = 0; + xvp->output_to_semantic_name[outAttr] = TGSI_SEMANTIC_POSITION; + xvp->output_to_semantic_index[outAttr] = 0; + numVpOuts++; + } + else if (outputsWritten & (1 << outAttr)) { + /* see if the frag prog wants this vert output */ + GLint fpInAttrib = vp_out_to_fp_in(outAttr); + if (fpInAttrib >= 0) { + GLuint fpInSlot = stfp->input_to_slot[fpInAttrib]; + if (fpInSlot != ~0) { + /* match this vp output to the fp input */ + GLuint vpOutSlot = stfp->input_map[fpInSlot]; + xvp->output_to_slot[outAttr] = vpOutSlot; + xvp->output_to_semantic_name[outAttr] = stfp->input_semantic_name[fpInSlot]; + xvp->output_to_semantic_index[outAttr] = stfp->input_semantic_index[fpInSlot]; + numVpOuts++; + } + } + else if (outAttr == VERT_RESULT_PSIZ) + emitPntSize = GL_TRUE; + else if (outAttr == VERT_RESULT_BFC0) + emitBFC0 = GL_TRUE; + else if (outAttr == VERT_RESULT_BFC1) + emitBFC1 = GL_TRUE; + } +#if 0 /*debug*/ + printf("assign vp output_to_slot[%d] = %d\n", outAttr, + xvp->output_to_slot[outAttr]); +#endif + } + + /* must do these last */ + if (emitPntSize) { + xvp->output_to_slot[VERT_RESULT_PSIZ] = numVpOuts++; + xvp->output_to_semantic_name[VERT_RESULT_PSIZ] = TGSI_SEMANTIC_PSIZE; + xvp->output_to_semantic_index[VERT_RESULT_PSIZ] = 0; + } + if (emitBFC0) { + xvp->output_to_slot[VERT_RESULT_BFC0] = numVpOuts++; + xvp->output_to_semantic_name[VERT_RESULT_BFC0] = TGSI_SEMANTIC_COLOR; + xvp->output_to_semantic_index[VERT_RESULT_BFC0] = 0; + } + if (emitBFC1) { + xvp->output_to_slot[VERT_RESULT_BFC1] = numVpOuts++; + xvp->output_to_semantic_name[VERT_RESULT_BFC0] = TGSI_SEMANTIC_COLOR; + xvp->output_to_semantic_index[VERT_RESULT_BFC0] = 1; + } + + /* Unneeded vertex program outputs will go to this slot. + * We could use this info to do dead code elimination in the + * vertex program. + */ + dummySlot = numVpOuts; + + /* find max GENERIC slot index */ + maxGeneric = -1; + for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) { + if (xvp->output_to_semantic_name[outAttr] == TGSI_SEMANTIC_GENERIC) { + maxGeneric = MAX2(maxGeneric, + xvp->output_to_semantic_index[outAttr]); + } + } + + /* Map vert program outputs that aren't used to the dummy slot + * (and an unused generic attribute slot). + */ + for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) { + if (outputsWritten & (1 << outAttr)) { + if (xvp->output_to_slot[outAttr] == UNUSED) { + xvp->output_to_slot[outAttr] = dummySlot; + xvp->output_to_semantic_name[outAttr] = TGSI_SEMANTIC_GENERIC; + xvp->output_to_semantic_index[outAttr] = maxGeneric + 1; + } + } + +#if 0 /*debug*/ + printf("vp output_to_slot[%d] = %d\n", outAttr, + xvp->output_to_slot[outAttr]); +#endif + } + + assert(stvp->Base.Base.NumInstructions > 1); + + st_translate_vertex_program(st, stvp, xvp->output_to_slot, + xvp->output_to_semantic_name, + xvp->output_to_semantic_index); + + xvp->vp = stvp; + + /* translated VP is up to date now */ + xvp->serialNo = stvp->serialNo; + } + + return xvp; +} + + +void +st_free_translated_vertex_programs(struct st_context *st, + struct translated_vertex_program *xvp) +{ + struct translated_vertex_program *next; + + while (xvp) { + next = xvp->next; + free(xvp); + xvp = next; + } +} + + +static void * +get_passthrough_fs(struct st_context *st) +{ + struct pipe_shader_state shader; + + if (!st->passthrough_fs) { + st->passthrough_fs = + util_make_fragment_passthrough_shader(st->pipe, &shader); +#if 0 /* We actually need to keep the tokens around at this time */ + free((void *) shader.tokens); +#endif + } + + return st->passthrough_fs; +} + + +static void +update_linkage( struct st_context *st ) +{ + struct st_vertex_program *stvp; + struct st_fragment_program *stfp; + struct translated_vertex_program *xvp; + + /* find active shader and params -- Should be covered by + * ST_NEW_VERTEX_PROGRAM + */ + assert(st->ctx->VertexProgram._Current); + stvp = st_vertex_program(st->ctx->VertexProgram._Current); + assert(stvp->Base.Base.Target == GL_VERTEX_PROGRAM_ARB); + + assert(st->ctx->FragmentProgram._Current); + stfp = st_fragment_program(st->ctx->FragmentProgram._Current); + assert(stfp->Base.Base.Target == GL_FRAGMENT_PROGRAM_ARB); + + xvp = find_translated_vp(st, stvp, stfp); + + st_reference_vertprog(st, &st->vp, stvp); + st_reference_fragprog(st, &st->fp, stfp); + + cso_set_vertex_shader_handle(st->cso_context, stvp->driver_shader); + + if (st->missing_textures) { + /* use a pass-through frag shader that uses no textures */ + void *fs = get_passthrough_fs(st); + cso_set_fragment_shader_handle(st->cso_context, fs); + } + else { + cso_set_fragment_shader_handle(st->cso_context, stfp->driver_shader); + } + + st->vertex_result_to_slot = xvp->output_to_slot; +} + + +const struct st_tracked_state st_update_shader = { + "st_update_shader", /* name */ + { /* dirty */ + 0, /* mesa */ + ST_NEW_VERTEX_PROGRAM | ST_NEW_FRAGMENT_PROGRAM /* st */ + }, + update_linkage /* update */ +}; diff --git a/src/mesa/state_tracker/st_atom_shader.h b/src/mesa/state_tracker/st_atom_shader.h new file mode 100644 index 0000000000..8403bc66c9 --- /dev/null +++ b/src/mesa/state_tracker/st_atom_shader.h @@ -0,0 +1,38 @@ +/************************************************************************** + * + * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_ATOM_SHADER_H +#define ST_ATOM_SHADER_H + + +extern void +st_free_translated_vertex_programs(struct st_context *st, + struct translated_vertex_program *xvp); + + +#endif /* ST_ATOM_SHADER_H */ diff --git a/src/mesa/state_tracker/st_atom_stipple.c b/src/mesa/state_tracker/st_atom_stipple.c new file mode 100644 index 0000000000..f395930ab4 --- /dev/null +++ b/src/mesa/state_tracker/st_atom_stipple.c @@ -0,0 +1,63 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * \brief polygon stipple state + * + * Authors: + * Brian Paul + */ + + +#include "st_context.h" +#include "st_atom.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" + + +static void +update_stipple( struct st_context *st ) +{ + const GLuint sz = sizeof(st->state.poly_stipple.stipple); + assert(sz == sizeof(st->ctx->PolygonStipple)); + + if (memcmp(&st->state.poly_stipple.stipple, st->ctx->PolygonStipple, sz)) { + /* state has changed */ + memcpy(st->state.poly_stipple.stipple, st->ctx->PolygonStipple, sz); + st->pipe->set_polygon_stipple(st->pipe, &st->state.poly_stipple); + } +} + + +const struct st_tracked_state st_update_polygon_stipple = { + "st_update_polygon_stipple", /* name */ + { /* dirty */ + (_NEW_POLYGONSTIPPLE), /* mesa */ + 0, /* st */ + }, + update_stipple /* update */ +}; diff --git a/src/mesa/state_tracker/st_atom_texture.c b/src/mesa/state_tracker/st_atom_texture.c new file mode 100644 index 0000000000..fb03766ff5 --- /dev/null +++ b/src/mesa/state_tracker/st_atom_texture.c @@ -0,0 +1,154 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + */ + + +#include "st_context.h" +#include "st_atom.h" +#include "st_texture.h" +#include "st_cb_texture.h" +#include "pipe/p_context.h" +#include "pipe/p_inlines.h" +#include "cso_cache/cso_context.h" + + +static void +update_textures(struct st_context *st) +{ + struct gl_fragment_program *fprog = st->ctx->FragmentProgram._Current; + GLuint su; + + st->state.num_textures = 0; + + /*printf("%s samplers used = 0x%x\n", __FUNCTION__, fprog->Base.SamplersUsed);*/ + + for (su = 0; su < st->ctx->Const.MaxTextureCoordUnits; su++) { + struct pipe_texture *pt = NULL; + + if (fprog->Base.SamplersUsed & (1 << su)) { + const GLuint texUnit = fprog->Base.SamplerUnits[su]; + struct gl_texture_object *texObj + = st->ctx->Texture.Unit[texUnit]._Current; + struct st_texture_object *stObj; + GLboolean flush, retval; + + if (!texObj) { + texObj = st_get_default_texture(st); + } + stObj = st_texture_object(texObj); + + retval = st_finalize_texture(st->ctx, st->pipe, texObj, &flush); + if (!retval) { + /* out of mem */ + continue; + } + + st->state.num_textures = su + 1; + + pt = st_get_stobj_texture(stObj); + } + + /* + if (pt) { + printf("%s su=%u non-null\n", __FUNCTION__, su); + } + else { + printf("%s su=%u null\n", __FUNCTION__, su); + } + */ + + pipe_texture_reference(&st->state.sampler_texture[su], pt); + } + + cso_set_sampler_textures(st->cso_context, + st->state.num_textures, + st->state.sampler_texture); +} + + +const struct st_tracked_state st_update_texture = { + "st_update_texture", /* name */ + { /* dirty */ + _NEW_TEXTURE, /* mesa */ + ST_NEW_FRAGMENT_PROGRAM, /* st */ + }, + update_textures /* update */ +}; + + + + +static void +finalize_textures(struct st_context *st) +{ + struct gl_fragment_program *fprog = st->ctx->FragmentProgram._Current; + const GLboolean prev_missing_textures = st->missing_textures; + GLuint su; + + st->missing_textures = GL_FALSE; + + for (su = 0; su < st->ctx->Const.MaxTextureCoordUnits; su++) { + if (fprog->Base.SamplersUsed & (1 << su)) { + const GLuint texUnit = fprog->Base.SamplerUnits[su]; + struct gl_texture_object *texObj + = st->ctx->Texture.Unit[texUnit]._Current; + struct st_texture_object *stObj = st_texture_object(texObj); + + if (texObj) { + GLboolean flush, retval; + + retval = st_finalize_texture(st->ctx, st->pipe, texObj, &flush); + if (!retval) { + /* out of mem */ + st->missing_textures = GL_TRUE; + continue; + } + + stObj->teximage_realloc = TRUE; + } + } + } + + if (prev_missing_textures != st->missing_textures) + st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM; +} + + + +const struct st_tracked_state st_finalize_textures = { + "st_finalize_textures", /* name */ + { /* dirty */ + _NEW_TEXTURE, /* mesa */ + 0, /* st */ + }, + finalize_textures /* update */ +}; diff --git a/src/mesa/state_tracker/st_atom_viewport.c b/src/mesa/state_tracker/st_atom_viewport.c new file mode 100644 index 0000000000..27ec2eb033 --- /dev/null +++ b/src/mesa/state_tracker/st_atom_viewport.c @@ -0,0 +1,91 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "main/context.h" +#include "main/colormac.h" +#include "st_context.h" +#include "st_atom.h" +#include "pipe/p_context.h" +#include "cso_cache/cso_context.h" + +/** + * Update the viewport transformation matrix. Depends on: + * - viewport pos/size + * - depthrange + * - window pos/size or FBO size + */ +static void +update_viewport( struct st_context *st ) +{ + GLcontext *ctx = st->ctx; + GLfloat yScale, yBias; + + /* _NEW_BUFFERS + */ + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + yScale = -1; + yBias = (GLfloat)ctx->DrawBuffer->Height; + } + else { + yScale = 1.0; + yBias = 0.0; + } + + /* _NEW_VIEWPORT + */ + { + GLfloat x = (GLfloat)ctx->Viewport.X; + GLfloat y = (GLfloat)ctx->Viewport.Y; + GLfloat z = ctx->Viewport.Near; + GLfloat half_width = (GLfloat)ctx->Viewport.Width / 2.0f; + GLfloat half_height = (GLfloat)ctx->Viewport.Height / 2.0f; + GLfloat half_depth = (GLfloat)(ctx->Viewport.Far - ctx->Viewport.Near) / 2.0f; + + st->state.viewport.scale[0] = half_width; + st->state.viewport.scale[1] = half_height * yScale; + st->state.viewport.scale[2] = half_depth; + st->state.viewport.scale[3] = 1.0; + + st->state.viewport.translate[0] = half_width + x; + st->state.viewport.translate[1] = (half_height + y) * yScale + yBias; + st->state.viewport.translate[2] = half_depth + z; + st->state.viewport.translate[3] = 0.0; + + cso_set_viewport(st->cso_context, &st->state.viewport); + } +} + + +const struct st_tracked_state st_update_viewport = { + "st_update_viewport", /* name */ + { /* dirty */ + _NEW_BUFFERS | _NEW_VIEWPORT, /* mesa */ + 0, /* st */ + }, + update_viewport /* update */ +}; diff --git a/src/mesa/state_tracker/st_cache.h b/src/mesa/state_tracker/st_cache.h new file mode 100644 index 0000000000..b81de316ec --- /dev/null +++ b/src/mesa/state_tracker/st_cache.h @@ -0,0 +1,68 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Zack Rusin <zack@tungstengraphics.com> + */ + +#ifndef ST_CACHE_H +#define ST_CACHE_H + +#include "cso_cache/cso_cache.h" + +struct pipe_blend_state; +struct pipe_sampler_state; +struct st_context; + + +const struct cso_blend * +st_cached_blend_state(struct st_context *st, + const struct pipe_blend_state *blend); + +const struct cso_sampler * +st_cached_sampler_state(struct st_context *st, + const struct pipe_sampler_state *sampler); + +const struct cso_depth_stencil_alpha * +st_cached_depth_stencil_alpha_state(struct st_context *st, + const struct pipe_depth_stencil_alpha_state *depth_stencil); + +const struct cso_rasterizer * +st_cached_rasterizer_state(struct st_context *st, + const struct pipe_rasterizer_state *raster); + +const struct cso_fragment_shader * +st_cached_fs_state(struct st_context *st, + const struct pipe_shader_state *templ); + + +const struct cso_vertex_shader * +st_cached_vs_state(struct st_context *st, + const struct pipe_shader_state *templ); + +#endif diff --git a/src/mesa/state_tracker/st_cb_accum.c b/src/mesa/state_tracker/st_cb_accum.c new file mode 100644 index 0000000000..cf3a99e7e9 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_accum.c @@ -0,0 +1,361 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Brian Paul + */ + +#include "main/imports.h" +#include "main/image.h" +#include "main/macros.h" + +#include "st_context.h" +#include "st_cb_accum.h" +#include "st_cb_fbo.h" +#include "st_draw.h" +#include "st_format.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" +#include "util/u_tile.h" + + +#define UNCLAMPED_FLOAT_TO_SHORT(us, f) \ + us = ( (short) ( CLAMP((f), -1.0, 1.0) * 32767.0F) ) + + +/** + * For hardware that supports deep color buffers, we could accelerate + * most/all the accum operations with blending/texturing. + * For now, just use the get/put_tile() functions and do things in software. + */ + + +/** + * Wrapper for pipe_get_tile_rgba(). Do format/cpp override to make the + * tile util function think the surface is 16bit/channel, even if it's not. + * See also: st_renderbuffer_alloc_storage() + */ +static void +acc_get_tile_rgba(struct pipe_context *pipe, struct pipe_surface *acc_ps, + uint x, uint y, uint w, uint h, float *p) +{ + const enum pipe_format f = acc_ps->format; + const struct pipe_format_block b = acc_ps->block; + + acc_ps->format = DEFAULT_ACCUM_PIPE_FORMAT; + acc_ps->block.size = 8; + acc_ps->block.width = 1; + acc_ps->block.height = 1; + + pipe_get_tile_rgba(acc_ps, x, y, w, h, p); + + acc_ps->format = f; + acc_ps->block = b; +} + + +/** + * Wrapper for pipe_put_tile_rgba(). Do format/cpp override to make the + * tile util function think the surface is 16bit/channel, even if it's not. + * See also: st_renderbuffer_alloc_storage() + */ +static void +acc_put_tile_rgba(struct pipe_context *pipe, struct pipe_surface *acc_ps, + uint x, uint y, uint w, uint h, const float *p) +{ + enum pipe_format f = acc_ps->format; + const struct pipe_format_block b = acc_ps->block; + + acc_ps->format = DEFAULT_ACCUM_PIPE_FORMAT; + acc_ps->block.size = 8; + acc_ps->block.width = 1; + acc_ps->block.height = 1; + + pipe_put_tile_rgba(acc_ps, x, y, w, h, p); + + acc_ps->format = f; + acc_ps->block = b; +} + + + +void +st_clear_accum_buffer(GLcontext *ctx, struct gl_renderbuffer *rb) +{ + struct st_renderbuffer *acc_strb = st_renderbuffer(rb); + struct pipe_surface *acc_ps; + struct pipe_screen *screen = ctx->st->pipe->screen; + const GLint xpos = ctx->DrawBuffer->_Xmin; + const GLint ypos = ctx->DrawBuffer->_Ymin; + const GLint width = ctx->DrawBuffer->_Xmax - xpos; + const GLint height = ctx->DrawBuffer->_Ymax - ypos; + GLubyte *map; + + acc_ps = screen->get_tex_surface(screen, acc_strb->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_WRITE); + map = screen->surface_map(screen, acc_ps, + PIPE_BUFFER_USAGE_CPU_WRITE); + + /* note acc_strb->format might not equal acc_ps->format */ + switch (acc_strb->format) { + case PIPE_FORMAT_R16G16B16A16_SNORM: + { + GLshort r = FLOAT_TO_SHORT(ctx->Accum.ClearColor[0]); + GLshort g = FLOAT_TO_SHORT(ctx->Accum.ClearColor[1]); + GLshort b = FLOAT_TO_SHORT(ctx->Accum.ClearColor[2]); + GLshort a = FLOAT_TO_SHORT(ctx->Accum.ClearColor[3]); + int i, j; + for (i = 0; i < height; i++) { + GLshort *dst = (GLshort *) (map + (ypos + i) * acc_ps->stride + xpos * 8); + for (j = 0; j < width; j++) { + dst[0] = r; + dst[1] = g; + dst[2] = b; + dst[3] = a; + dst += 4; + } + } + } + break; + default: + _mesa_problem(ctx, "unexpected format in st_clear_accum_buffer()"); + } + + screen->surface_unmap(screen, acc_ps); + pipe_surface_reference(&acc_ps, NULL); +} + + +/** For ADD/MULT */ +static void +accum_mad(GLcontext *ctx, GLfloat scale, GLfloat bias, + GLint xpos, GLint ypos, GLint width, GLint height, + struct st_renderbuffer *acc_strb) +{ + struct pipe_screen *screen = ctx->st->pipe->screen; + struct pipe_surface *acc_ps = acc_strb->surface; + GLubyte *map; + + map = screen->surface_map(screen, acc_ps, + PIPE_BUFFER_USAGE_CPU_WRITE); + + /* note acc_strb->format might not equal acc_ps->format */ + switch (acc_strb->format) { + case PIPE_FORMAT_R16G16B16A16_SNORM: + { + int i, j; + for (i = 0; i < height; i++) { + GLshort *acc = (GLshort *) (map + (ypos + i) * acc_ps->stride + xpos * 8); + for (j = 0; j < width * 4; j++) { + float val = SHORT_TO_FLOAT(acc[j]) * scale + bias; + acc[j] = FLOAT_TO_SHORT(val); + } + } + } + break; + default: + _mesa_problem(NULL, "unexpected format in st_clear_accum_buffer()"); + } + + screen->surface_unmap(screen, acc_ps); +} + + +static void +accum_accum(struct pipe_context *pipe, GLfloat value, + GLint xpos, GLint ypos, GLint width, GLint height, + struct st_renderbuffer *acc_strb, + struct st_renderbuffer *color_strb) +{ + struct pipe_screen *screen = pipe->screen; + struct pipe_surface *acc_surf, *color_surf; + GLfloat *colorBuf, *accBuf; + GLint i; + + acc_surf = screen->get_tex_surface(screen, acc_strb->texture, 0, 0, 0, + (PIPE_BUFFER_USAGE_CPU_WRITE | + PIPE_BUFFER_USAGE_CPU_READ)); + + color_surf = screen->get_tex_surface(screen, color_strb->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_READ); + + colorBuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + accBuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + + pipe_get_tile_rgba(color_surf, xpos, ypos, width, height, colorBuf); + acc_get_tile_rgba(pipe, acc_surf, xpos, ypos, width, height, accBuf); + + for (i = 0; i < 4 * width * height; i++) { + accBuf[i] = accBuf[i] + colorBuf[i] * value; + } + + acc_put_tile_rgba(pipe, acc_surf, xpos, ypos, width, height, accBuf); + + free(colorBuf); + free(accBuf); + pipe_surface_reference(&acc_surf, NULL); + pipe_surface_reference(&color_surf, NULL); +} + + +static void +accum_load(struct pipe_context *pipe, GLfloat value, + GLint xpos, GLint ypos, GLint width, GLint height, + struct st_renderbuffer *acc_strb, + struct st_renderbuffer *color_strb) +{ + struct pipe_screen *screen = pipe->screen; + struct pipe_surface *acc_surf, *color_surf; + GLfloat *buf; + GLint i; + + acc_surf = screen->get_tex_surface(screen, acc_strb->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_WRITE); + + color_surf = screen->get_tex_surface(screen, color_strb->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_READ); + + buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + + pipe_get_tile_rgba(color_surf, xpos, ypos, width, height, buf); + + for (i = 0; i < 4 * width * height; i++) { + buf[i] = buf[i] * value; + } + + acc_put_tile_rgba(pipe, acc_surf, xpos, ypos, width, height, buf); + + free(buf); + pipe_surface_reference(&acc_surf, NULL); + pipe_surface_reference(&color_surf, NULL); +} + + +static void +accum_return(GLcontext *ctx, GLfloat value, + GLint xpos, GLint ypos, GLint width, GLint height, + struct st_renderbuffer *acc_strb, + struct st_renderbuffer *color_strb) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct pipe_screen *screen = pipe->screen; + const GLubyte *colormask = ctx->Color.ColorMask; + struct pipe_surface *acc_surf, *color_surf; + GLfloat *abuf, *cbuf = NULL; + GLint i, ch; + + abuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + + acc_surf = screen->get_tex_surface(screen, acc_strb->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_READ); + + color_surf = screen->get_tex_surface(screen, color_strb->texture, 0, 0, 0, + (PIPE_BUFFER_USAGE_CPU_READ | + PIPE_BUFFER_USAGE_CPU_WRITE)); + + acc_get_tile_rgba(pipe, acc_surf, xpos, ypos, width, height, abuf); + + if (!colormask[0] || !colormask[1] || !colormask[2] || !colormask[3]) { + cbuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + pipe_get_tile_rgba(color_surf, xpos, ypos, width, height, cbuf); + } + + for (i = 0; i < width * height; i++) { + for (ch = 0; ch < 4; ch++) { + if (colormask[ch]) { + GLfloat val = abuf[i * 4 + ch] * value; + abuf[i * 4 + ch] = CLAMP(val, 0.0f, 1.0f); + } + else { + abuf[i * 4 + ch] = cbuf[i * 4 + ch]; + } + } + } + + pipe_put_tile_rgba(color_surf, xpos, ypos, width, height, abuf); + + free(abuf); + if (cbuf) + free(cbuf); + pipe_surface_reference(&acc_surf, NULL); + pipe_surface_reference(&color_surf, NULL); +} + + +static void +st_Accum(GLcontext *ctx, GLenum op, GLfloat value) +{ + struct st_context *st = ctx->st; + struct pipe_context *pipe = st->pipe; + struct st_renderbuffer *acc_strb + = st_renderbuffer(ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer); + struct st_renderbuffer *color_strb + = st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer); + + const GLint xpos = ctx->DrawBuffer->_Xmin; + const GLint ypos = ctx->DrawBuffer->_Ymin; + const GLint width = ctx->DrawBuffer->_Xmax - xpos; + const GLint height = ctx->DrawBuffer->_Ymax - ypos; + + /* make sure color bufs aren't cached */ + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + + switch (op) { + case GL_ADD: + if (value != 0.0F) { + accum_mad(ctx, 1.0, value, xpos, ypos, width, height, acc_strb); + } + break; + case GL_MULT: + if (value != 1.0F) { + accum_mad(ctx, value, 0.0, xpos, ypos, width, height, acc_strb); + } + break; + case GL_ACCUM: + if (value != 0.0F) { + accum_accum(pipe, value, xpos, ypos, width, height, acc_strb, color_strb); + } + break; + case GL_LOAD: + accum_load(pipe, value, xpos, ypos, width, height, acc_strb, color_strb); + break; + case GL_RETURN: + accum_return(ctx, value, xpos, ypos, width, height, acc_strb, color_strb); + break; + default: + assert(0); + } +} + + + +void st_init_accum_functions(struct dd_function_table *functions) +{ + functions->Accum = st_Accum; +} diff --git a/src/mesa/state_tracker/st_cb_accum.h b/src/mesa/state_tracker/st_cb_accum.h new file mode 100644 index 0000000000..ed9b7dab94 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_accum.h @@ -0,0 +1,39 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_CB_ACCUM_H +#define ST_CB_ACCUM_H + + +extern void +st_clear_accum_buffer(GLcontext *ctx, struct gl_renderbuffer *rb); + +extern void st_init_accum_functions(struct dd_function_table *functions); + + +#endif /* ST_CB_ACCUM_H */ diff --git a/src/mesa/state_tracker/st_cb_bitmap.c b/src/mesa/state_tracker/st_cb_bitmap.c new file mode 100644 index 0000000000..3d508227e1 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_bitmap.c @@ -0,0 +1,791 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Brian Paul + */ + +#include "main/imports.h" +#include "main/image.h" +#include "main/bufferobj.h" +#include "main/macros.h" +#include "main/texformat.h" +#include "shader/program.h" +#include "shader/prog_parameter.h" +#include "shader/prog_print.h" + +#include "st_context.h" +#include "st_atom.h" +#include "st_atom_constbuf.h" +#include "st_program.h" +#include "st_cb_bitmap.h" +#include "st_cb_program.h" +#include "st_mesa_to_tgsi.h" +#include "st_texture.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" +#include "util/u_tile.h" +#include "util/u_draw_quad.h" +#include "util/u_simple_shaders.h" +#include "shader/prog_instruction.h" +#include "cso_cache/cso_context.h" + + + +/** + * glBitmaps are drawn as textured quads. The user's bitmap pattern + * is stored in a texture image. An alpha8 texture format is used. + * The fragment shader samples a bit (texel) from the texture, then + * discards the fragment if the bit is off. + * + * Note that we actually store the inverse image of the bitmap to + * simplify the fragment program. An "on" bit gets stored as texel=0x0 + * and an "off" bit is stored as texel=0xff. Then we kill the + * fragment if the negated texel value is less than zero. + */ + + +/** + * The bitmap cache attempts to accumulate multiple glBitmap calls in a + * buffer which is then rendered en mass upon a flush, state change, etc. + * A wide, short buffer is used to target the common case of a series + * of glBitmap calls being used to draw text. + */ +static GLboolean UseBitmapCache = GL_TRUE; + + +#define BITMAP_CACHE_WIDTH 512 +#define BITMAP_CACHE_HEIGHT 32 + +struct bitmap_cache +{ + /** Window pos to render the cached image */ + GLint xpos, ypos; + /** Bounds of region used in window coords */ + GLint xmin, ymin, xmax, ymax; + + GLfloat color[4]; + + struct pipe_texture *texture; + struct pipe_surface *surf; + + GLboolean empty; + + /** An I8 texture image: */ + ubyte *buffer; +}; + + + + +/** + * Make fragment program for glBitmap: + * Sample the texture and kill the fragment if the bit is 0. + * This program will be combined with the user's fragment program. + */ +static struct st_fragment_program * +make_bitmap_fragment_program(GLcontext *ctx, GLuint samplerIndex) +{ + struct st_fragment_program *stfp; + struct gl_program *p; + GLuint ic = 0; + + p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); + if (!p) + return NULL; + + p->NumInstructions = 3; + + p->Instructions = _mesa_alloc_instructions(p->NumInstructions); + if (!p->Instructions) { + ctx->Driver.DeleteProgram(ctx, p); + return NULL; + } + _mesa_init_instructions(p->Instructions, p->NumInstructions); + + /* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */ + p->Instructions[ic].Opcode = OPCODE_TEX; + p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY; + p->Instructions[ic].DstReg.Index = 0; + p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; + p->Instructions[ic].TexSrcUnit = samplerIndex; + p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + + /* KIL if -tmp0 < 0 # texel=0 -> keep / texel=0 -> discard */ + p->Instructions[ic].Opcode = OPCODE_KIL; + p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + p->Instructions[ic].SrcReg[0].Index = 0; + p->Instructions[ic].SrcReg[0].NegateBase = NEGATE_XYZW; + ic++; + + /* END; */ + p->Instructions[ic++].Opcode = OPCODE_END; + + assert(ic == p->NumInstructions); + + p->InputsRead = FRAG_BIT_TEX0; + p->OutputsWritten = 0x0; + p->SamplersUsed = (1 << samplerIndex); + + stfp = (struct st_fragment_program *) p; + stfp->Base.UsesKill = GL_TRUE; + st_translate_fragment_program(ctx->st, stfp, NULL); + + return stfp; +} + + +static int +find_free_bit(uint bitfield) +{ + int i; + for (i = 0; i < 32; i++) { + if ((bitfield & (1 << i)) == 0) { + return i; + } + } + return -1; +} + + +/** + * Combine basic bitmap fragment program with the user-defined program. + */ +static struct st_fragment_program * +combined_bitmap_fragment_program(GLcontext *ctx) +{ + struct st_context *st = ctx->st; + struct st_fragment_program *stfp = st->fp; + + if (!stfp->bitmap_program) { + /* + * Generate new program which is the user-defined program prefixed + * with the bitmap sampler/kill instructions. + */ + struct st_fragment_program *bitmap_prog; + uint sampler; + + sampler = find_free_bit(st->fp->Base.Base.SamplersUsed); + bitmap_prog = make_bitmap_fragment_program(ctx, sampler); + + stfp->bitmap_program = (struct st_fragment_program *) + _mesa_combine_programs(ctx, + &bitmap_prog->Base.Base, &stfp->Base.Base); + stfp->bitmap_program->bitmap_sampler = sampler; + + /* done with this after combining */ + st_reference_fragprog(st, &bitmap_prog, NULL); + +#if 0 + { + struct gl_program *p = &stfp->bitmap_program->Base.Base; + printf("Combined bitmap program:\n"); + _mesa_print_program(p); + printf("InputsRead: 0x%x\n", p->InputsRead); + printf("OutputsWritten: 0x%x\n", p->OutputsWritten); + _mesa_print_parameter_list(p->Parameters); + } +#endif + + /* translate to TGSI tokens */ + st_translate_fragment_program(st, stfp->bitmap_program, NULL); + } + + /* Ideally we'd have updated the pipe constants during the normal + * st/atom mechanism. But we can't since this is specific to glBitmap. + */ + st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT); + + return stfp->bitmap_program; +} + + +/** + * Copy user-provide bitmap bits into texture buffer, expanding + * bits into texels. + * "On" bits will set texels to 0xff. + * "Off" bits will not modify texels. + * Note that the image is actually going to be upside down in + * the texture. We deal with that with texcoords. + */ +static void +unpack_bitmap(struct st_context *st, + GLint px, GLint py, GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap, + ubyte *destBuffer, uint destStride) +{ + GLint row, col; + +#define SET_PIXEL(COL, ROW) \ + destBuffer[(py + (ROW)) * destStride + px + (COL)] = 0x0; + + for (row = 0; row < height; row++) { + const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack, + bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0); + + if (unpack->LsbFirst) { + /* Lsb first */ + GLubyte mask = 1U << (unpack->SkipPixels & 0x7); + for (col = 0; col < width; col++) { + + if (*src & mask) { + SET_PIXEL(col, row); + } + + if (mask == 128U) { + src++; + mask = 1U; + } + else { + mask = mask << 1; + } + } + + /* get ready for next row */ + if (mask != 1) + src++; + } + else { + /* Msb first */ + GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); + for (col = 0; col < width; col++) { + + if (*src & mask) { + SET_PIXEL(col, row); + } + + if (mask == 1U) { + src++; + mask = 128U; + } + else { + mask = mask >> 1; + } + } + + /* get ready for next row */ + if (mask != 128) + src++; + } + + } /* row */ + +#undef SET_PIXEL +} + + +/** + * Create a texture which represents a bitmap image. + */ +static struct pipe_texture * +make_bitmap_texture(GLcontext *ctx, GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_surface *surface; + ubyte *dest; + struct pipe_texture *pt; + + /* PBO source... */ + bitmap = _mesa_map_bitmap_pbo(ctx, unpack, bitmap); + if (!bitmap) { + return NULL; + } + + /** + * Create texture to hold bitmap pattern. + */ + pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, ctx->st->bitmap.tex_format, + 0, width, height, 1, 0, + PIPE_TEXTURE_USAGE_SAMPLER); + if (!pt) { + _mesa_unmap_bitmap_pbo(ctx, unpack); + return NULL; + } + + surface = screen->get_tex_surface(screen, pt, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_WRITE); + + /* map texture surface */ + dest = screen->surface_map(screen, surface, PIPE_BUFFER_USAGE_CPU_WRITE); + + /* Put image into texture surface */ + memset(dest, 0xff, height * surface->stride); + unpack_bitmap(ctx->st, 0, 0, width, height, unpack, bitmap, + dest, surface->stride); + + _mesa_unmap_bitmap_pbo(ctx, unpack); + + /* Release surface */ + screen->surface_unmap(screen, surface); + pipe_surface_reference(&surface, NULL); + + return pt; +} + + +static void +setup_bitmap_vertex_data(struct st_context *st, + int x, int y, int width, int height, + float z, const float color[4]) +{ + struct pipe_context *pipe = st->pipe; + const struct gl_framebuffer *fb = st->ctx->DrawBuffer; + const GLfloat fb_width = (GLfloat)fb->Width; + const GLfloat fb_height = (GLfloat)fb->Height; + const GLfloat x0 = (GLfloat)x; + const GLfloat x1 = (GLfloat)(x + width); + const GLfloat y0 = (GLfloat)y; + const GLfloat y1 = (GLfloat)(y + height); + const GLfloat sLeft = (GLfloat)0.0, sRight = (GLfloat)1.0; + const GLfloat tTop = (GLfloat)0.0, tBot = (GLfloat)1.0 - tTop; + const GLfloat clip_x0 = (GLfloat)(x0 / fb_width * 2.0 - 1.0); + const GLfloat clip_y0 = (GLfloat)(y0 / fb_height * 2.0 - 1.0); + const GLfloat clip_x1 = (GLfloat)(x1 / fb_width * 2.0 - 1.0); + const GLfloat clip_y1 = (GLfloat)(y1 / fb_height * 2.0 - 1.0); + GLuint i; + void *buf; + + if (!st->bitmap.vbuf) { + st->bitmap.vbuf = pipe_buffer_create(pipe->screen, 32, PIPE_BUFFER_USAGE_VERTEX, + sizeof(st->bitmap.vertices)); + } + + /* Positions are in clip coords since we need to do clipping in case + * the bitmap quad goes beyond the window bounds. + */ + st->bitmap.vertices[0][0][0] = clip_x0; + st->bitmap.vertices[0][0][1] = clip_y0; + st->bitmap.vertices[0][2][0] = sLeft; + st->bitmap.vertices[0][2][1] = tTop; + + st->bitmap.vertices[1][0][0] = clip_x1; + st->bitmap.vertices[1][0][1] = clip_y0; + st->bitmap.vertices[1][2][0] = sRight; + st->bitmap.vertices[1][2][1] = tTop; + + st->bitmap.vertices[2][0][0] = clip_x1; + st->bitmap.vertices[2][0][1] = clip_y1; + st->bitmap.vertices[2][2][0] = sRight; + st->bitmap.vertices[2][2][1] = tBot; + + st->bitmap.vertices[3][0][0] = clip_x0; + st->bitmap.vertices[3][0][1] = clip_y1; + st->bitmap.vertices[3][2][0] = sLeft; + st->bitmap.vertices[3][2][1] = tBot; + + /* same for all verts: */ + for (i = 0; i < 4; i++) { + st->bitmap.vertices[i][0][2] = z; + st->bitmap.vertices[i][0][3] = 1.0; + st->bitmap.vertices[i][1][0] = color[0]; + st->bitmap.vertices[i][1][1] = color[1]; + st->bitmap.vertices[i][1][2] = color[2]; + st->bitmap.vertices[i][1][3] = color[3]; + st->bitmap.vertices[i][2][2] = 0.0; /*R*/ + st->bitmap.vertices[i][2][3] = 1.0; /*Q*/ + } + + /* put vertex data into vbuf */ + buf = pipe_buffer_map(pipe->screen, st->bitmap.vbuf, PIPE_BUFFER_USAGE_CPU_WRITE); + memcpy(buf, st->bitmap.vertices, sizeof(st->bitmap.vertices)); + pipe_buffer_unmap(pipe->screen, st->bitmap.vbuf); +} + + + +/** + * Render a glBitmap by drawing a textured quad + */ +static void +draw_bitmap_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, + GLsizei width, GLsizei height, + struct pipe_texture *pt, + const GLfloat *color) +{ + struct st_context *st = ctx->st; + struct pipe_context *pipe = ctx->st->pipe; + struct cso_context *cso = ctx->st->cso_context; + struct st_fragment_program *stfp; + GLuint maxSize; + + stfp = combined_bitmap_fragment_program(ctx); + + /* limit checks */ + /* XXX if the bitmap is larger than the max texture size, break + * it up into chunks. + */ + maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); + assert(width <= (GLsizei)maxSize); + assert(height <= (GLsizei)maxSize); + + cso_save_rasterizer(cso); + cso_save_samplers(cso); + cso_save_sampler_textures(cso); + cso_save_viewport(cso); + cso_save_fragment_shader(cso); + cso_save_vertex_shader(cso); + + /* rasterizer state: just scissor */ + st->bitmap.rasterizer.scissor = ctx->Scissor.Enabled; + cso_set_rasterizer(cso, &st->bitmap.rasterizer); + + /* fragment shader state: TEX lookup program */ + cso_set_fragment_shader_handle(cso, stfp->driver_shader); + + /* vertex shader state: position + texcoord pass-through */ + cso_set_vertex_shader_handle(cso, st->bitmap.vs); + + /* user samplers, plus our bitmap sampler */ + { + struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; + uint num = MAX2(stfp->bitmap_sampler + 1, st->state.num_samplers); + uint i; + for (i = 0; i < st->state.num_samplers; i++) { + samplers[i] = &st->state.samplers[i]; + } + samplers[stfp->bitmap_sampler] = &st->bitmap.sampler; + cso_set_samplers(cso, num, (const struct pipe_sampler_state **) samplers); } + + /* user textures, plus the bitmap texture */ + { + struct pipe_texture *textures[PIPE_MAX_SAMPLERS]; + uint num = MAX2(stfp->bitmap_sampler + 1, st->state.num_textures); + memcpy(textures, st->state.sampler_texture, sizeof(textures)); + textures[stfp->bitmap_sampler] = pt; + cso_set_sampler_textures(cso, num, textures); + } + + /* viewport state: viewport matching window dims */ + { + const struct gl_framebuffer *fb = st->ctx->DrawBuffer; + const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP); + const GLfloat width = (GLfloat)fb->Width; + const GLfloat height = (GLfloat)fb->Height; + struct pipe_viewport_state vp; + vp.scale[0] = 0.5f * width; + vp.scale[1] = height * (invert ? -0.5f : 0.5f); + vp.scale[2] = 1.0f; + vp.scale[3] = 1.0f; + vp.translate[0] = 0.5f * width; + vp.translate[1] = 0.5f * height; + vp.translate[2] = 0.0f; + vp.translate[3] = 0.0f; + cso_set_viewport(cso, &vp); + } + + /* draw textured quad */ + setup_bitmap_vertex_data(st, x, y, width, height, + ctx->Current.RasterPos[2], + color); + + util_draw_vertex_buffer(pipe, st->bitmap.vbuf, + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + 3); /* attribs/vert */ + + + /* restore state */ + cso_restore_rasterizer(cso); + cso_restore_samplers(cso); + cso_restore_sampler_textures(cso); + cso_restore_viewport(cso); + cso_restore_fragment_shader(cso); + cso_restore_vertex_shader(cso); +} + + +static void +reset_cache(struct st_context *st) +{ + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + struct bitmap_cache *cache = st->bitmap.cache; + + //memset(cache->buffer, 0xff, sizeof(cache->buffer)); + cache->empty = GL_TRUE; + + cache->xmin = 1000000; + cache->xmax = -1000000; + cache->ymin = 1000000; + cache->ymax = -1000000; + + if (cache->surf) + screen->tex_surface_release(screen, &cache->surf); + + assert(!cache->texture); + + /* allocate a new texture */ + cache->texture = st_texture_create(st, PIPE_TEXTURE_2D, + st->bitmap.tex_format, 0, + BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT, + 1, 0, + PIPE_TEXTURE_USAGE_SAMPLER); + + /* Map the texture surface. + * Subsequent glBitmap calls will write into the texture image. + */ + cache->surf = screen->get_tex_surface(screen, cache->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_WRITE); + cache->buffer = screen->surface_map(screen, cache->surf, + PIPE_BUFFER_USAGE_CPU_WRITE); + + /* init image to all 0xff */ + memset(cache->buffer, 0xff, BITMAP_CACHE_WIDTH * BITMAP_CACHE_HEIGHT); +} + + +/** + * If there's anything in the bitmap cache, draw/flush it now. + */ +void +st_flush_bitmap_cache(struct st_context *st) +{ + if (!st->bitmap.cache->empty) { + struct bitmap_cache *cache = st->bitmap.cache; + + if (st->ctx->DrawBuffer) { + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + + assert(cache->xmin <= cache->xmax); + /* + printf("flush size %d x %d at %d, %d\n", + cache->xmax - cache->xmin, + cache->ymax - cache->ymin, + cache->xpos, cache->ypos); + */ + + /* The texture surface has been mapped until now. + * So unmap and release the texture surface before drawing. + */ + screen->surface_unmap(screen, cache->surf); + cache->buffer = NULL; + + screen->tex_surface_release(screen, &cache->surf); + + draw_bitmap_quad(st->ctx, + cache->xpos, + cache->ypos, + st->ctx->Current.RasterPos[2], + BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT, + cache->texture, + cache->color); + } + + /* release/free the texture */ + pipe_texture_reference(&cache->texture, NULL); + + reset_cache(st); + } +} + + +/** + * Try to accumulate this glBitmap call in the bitmap cache. + * \return GL_TRUE for success, GL_FALSE if bitmap is too large, etc. + */ +static GLboolean +accum_bitmap(struct st_context *st, + GLint x, GLint y, GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap ) +{ + struct bitmap_cache *cache = st->bitmap.cache; + int px = -999, py; + + if (width > BITMAP_CACHE_WIDTH || + height > BITMAP_CACHE_HEIGHT) + return GL_FALSE; /* too big to cache */ + + if (!cache->empty) { + px = x - cache->xpos; /* pos in buffer */ + py = y - cache->ypos; + if (px < 0 || px + width > BITMAP_CACHE_WIDTH || + py < 0 || py + height > BITMAP_CACHE_HEIGHT || + !TEST_EQ_4V(st->ctx->Current.RasterColor, cache->color)) { + /* This bitmap would extend beyond cache bounds, or the bitmap + * color is changing + * so flush and continue. + */ + st_flush_bitmap_cache(st); + } + } + + if (cache->empty) { + /* Initialize. Center bitmap vertically in the buffer. */ + px = 0; + py = (BITMAP_CACHE_HEIGHT - height) / 2; + cache->xpos = x; + cache->ypos = y - py; + cache->empty = GL_FALSE; + COPY_4FV(cache->color, st->ctx->Current.RasterColor); + } + + assert(px != -999); + + if (x < cache->xmin) + cache->xmin = x; + if (y < cache->ymin) + cache->ymin = y; + if (x + width > cache->xmax) + cache->xmax = x + width; + if (y + height > cache->ymax) + cache->ymax = y + height; + + unpack_bitmap(st, px, py, width, height, unpack, bitmap, + cache->buffer, BITMAP_CACHE_WIDTH); + + return GL_TRUE; /* accumulated */ +} + + + +/** + * Called via ctx->Driver.Bitmap() + */ +static void +st_Bitmap(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) +{ + struct st_context *st = ctx->st; + struct pipe_texture *pt; + + if (width == 0 || height == 0) + return; + + st_validate_state(st); + + if (!st->bitmap.vs) { + /* create pass-through vertex shader now */ + const uint semantic_names[] = { TGSI_SEMANTIC_POSITION, + TGSI_SEMANTIC_COLOR, + TGSI_SEMANTIC_GENERIC }; + const uint semantic_indexes[] = { 0, 0, 0 }; + st->bitmap.vs = util_make_vertex_passthrough_shader(st->pipe, 3, + semantic_names, + semantic_indexes, + &st->bitmap.vert_shader); + } + + if (UseBitmapCache && accum_bitmap(st, x, y, width, height, unpack, bitmap)) + return; + + pt = make_bitmap_texture(ctx, width, height, unpack, bitmap); + if (pt) { + assert(pt->target == PIPE_TEXTURE_2D); + draw_bitmap_quad(ctx, x, y, ctx->Current.RasterPos[2], + width, height, pt, + st->ctx->Current.RasterColor); + /* release/free the texture */ + pipe_texture_reference(&pt, NULL); + } +} + + +/** Per-context init */ +void +st_init_bitmap_functions(struct dd_function_table *functions) +{ + functions->Bitmap = st_Bitmap; +} + + +/** Per-context init */ +void +st_init_bitmap(struct st_context *st) +{ + struct pipe_sampler_state *sampler = &st->bitmap.sampler; + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + + /* init sampler state once */ + memset(sampler, 0, sizeof(*sampler)); + sampler->wrap_s = PIPE_TEX_WRAP_CLAMP; + sampler->wrap_t = PIPE_TEX_WRAP_CLAMP; + sampler->wrap_r = PIPE_TEX_WRAP_CLAMP; + sampler->min_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler->min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler->mag_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler->normalized_coords = 1; + + /* init baseline rasterizer state once */ + memset(&st->bitmap.rasterizer, 0, sizeof(st->bitmap.rasterizer)); + st->bitmap.rasterizer.gl_rasterization_rules = 1; + st->bitmap.rasterizer.bypass_vs = 1; + + /* find a usable texture format */ + if (screen->is_format_supported(screen, PIPE_FORMAT_I8_UNORM, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, 0)) { + st->bitmap.tex_format = PIPE_FORMAT_I8_UNORM; + } + else { + /* XXX support more formats */ + assert(0); + } + + /* alloc bitmap cache object */ + st->bitmap.cache = CALLOC_STRUCT(bitmap_cache); + + reset_cache(st); +} + + +/** Per-context tear-down */ +void +st_destroy_bitmap(struct st_context *st) +{ + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + struct bitmap_cache *cache = st->bitmap.cache; + + screen->surface_unmap(screen, cache->surf); + screen->tex_surface_release(screen, &cache->surf); + + if (st->bitmap.vs) { + cso_delete_vertex_shader(st->cso_context, st->bitmap.vs); + st->bitmap.vs = NULL; + } + + if (st->bitmap.vbuf) { + pipe_buffer_reference(pipe->screen, &st->bitmap.vbuf, NULL); + st->bitmap.vbuf = NULL; + } + + if (st->bitmap.cache) { + pipe_texture_release(&st->bitmap.cache->texture); + FREE(st->bitmap.cache); + st->bitmap.cache = NULL; + } +} diff --git a/src/mesa/state_tracker/st_cb_bitmap.h b/src/mesa/state_tracker/st_cb_bitmap.h new file mode 100644 index 0000000000..aae11d34c9 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_bitmap.h @@ -0,0 +1,46 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_CB_BITMAP_H +#define ST_CB_BITMAP_H + + +extern void +st_init_bitmap_functions(struct dd_function_table *functions); + +extern void +st_init_bitmap(struct st_context *st); + +extern void +st_destroy_bitmap(struct st_context *st); + +extern void +st_flush_bitmap_cache(struct st_context *st); + + +#endif /* ST_CB_BITMAP_H */ diff --git a/src/mesa/state_tracker/st_cb_blit.c b/src/mesa/state_tracker/st_cb_blit.c new file mode 100644 index 0000000000..2852623472 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_blit.c @@ -0,0 +1,111 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Brian Paul + */ + +#include "main/imports.h" +#include "main/image.h" +#include "main/macros.h" +#include "main/texformat.h" +#include "shader/program.h" +#include "shader/prog_parameter.h" +#include "shader/prog_print.h" + +#include "st_context.h" +#include "st_program.h" +#include "st_cb_blit.h" +#include "st_cb_fbo.h" + +#include "util/u_blit.h" + +#include "cso_cache/cso_context.h" + + +void +st_init_blit(struct st_context *st) +{ + st->blit = util_create_blit(st->pipe, st->cso_context); +} + + +void +st_destroy_blit(struct st_context *st) +{ + util_destroy_blit(st->blit); + st->blit = NULL; +} + + +static void +st_BlitFramebuffer(GLcontext *ctx, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + struct st_context *st = ctx->st; + + const uint pFilter = ((filter == GL_NEAREST) + ? PIPE_TEX_MIPFILTER_NEAREST + : PIPE_TEX_MIPFILTER_LINEAR); + + if (mask & GL_COLOR_BUFFER_BIT) { + struct st_renderbuffer *srcRb = + st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer); + struct st_renderbuffer *dstRb = + st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); + struct pipe_surface *srcSurf = srcRb->surface; + struct pipe_surface *dstSurf = dstRb->surface; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + /* invert Y */ + srcY0 = srcRb->Base.Height - srcY0; + srcY1 = srcRb->Base.Height - srcY1; + + dstY0 = dstRb->Base.Height - dstY0; + dstY1 = dstRb->Base.Height - dstY1; + } + + util_blit_pixels(st->blit, + srcSurf, srcX0, srcY0, srcX1, srcY1, + dstSurf, dstX0, dstY0, dstX1, dstY1, + 0.0, pFilter); + + } +} + + + +void +st_init_blit_functions(struct dd_function_table *functions) +{ +#if FEATURE_EXT_framebuffer_blit + functions->BlitFramebuffer = st_BlitFramebuffer; +#endif +} diff --git a/src/mesa/state_tracker/st_cb_blit.h b/src/mesa/state_tracker/st_cb_blit.h new file mode 100644 index 0000000000..ed22986b53 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_blit.h @@ -0,0 +1,46 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef ST_CB_BLIT_H +#define ST_CB_BLIT_H + + +#include "st_context.h" + + + +extern void +st_init_blit(struct st_context *st); + +extern void +st_destroy_blit(struct st_context *st); + +extern void +st_init_blit_functions(struct dd_function_table *functions); + + +#endif /* ST_CB_BLIT_H */ diff --git a/src/mesa/state_tracker/st_cb_bufferobjects.c b/src/mesa/state_tracker/st_cb_bufferobjects.c new file mode 100644 index 0000000000..07fa2afce0 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_bufferobjects.c @@ -0,0 +1,240 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "main/imports.h" +#include "main/mtypes.h" +#include "main/bufferobj.h" + +#include "st_context.h" +#include "st_cb_bufferobjects.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" + + + +/* Pixel buffers and Vertex/index buffers are handled through these + * mesa callbacks. Framebuffer/Renderbuffer objects are + * created/managed elsewhere. + */ + + + +/** + * There is some duplication between mesa's bufferobjects and our + * bufmgr buffers. Both have an integer handle and a hashtable to + * lookup an opaque structure. It would be nice if the handles and + * internal structure where somehow shared. + */ +static struct gl_buffer_object * +st_bufferobj_alloc(GLcontext *ctx, GLuint name, GLenum target) +{ + struct st_buffer_object *st_obj = CALLOC_STRUCT(st_buffer_object); + + if (!st_obj) + return NULL; + + _mesa_initialize_buffer_object(&st_obj->Base, name, target); + + return &st_obj->Base; +} + + + +/** + * Deallocate/free a vertex/pixel buffer object. + * Called via glDeleteBuffersARB(). + */ +static void +st_bufferobj_free(GLcontext *ctx, struct gl_buffer_object *obj) +{ + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_buffer_object *st_obj = st_buffer_object(obj); + + if (st_obj->buffer) + pipe_buffer_reference(pipe->screen, &st_obj->buffer, NULL); + + free(st_obj); +} + + + +/** + * Replace data in a subrange of buffer object. If the data range + * specified by size + offset extends beyond the end of the buffer or + * if data is NULL, no copy is performed. + * Called via glBufferSubDataARB(). + */ +static void +st_bufferobj_subdata(GLcontext *ctx, + GLenum target, + GLintptrARB offset, + GLsizeiptrARB size, + const GLvoid * data, struct gl_buffer_object *obj) +{ + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_buffer_object *st_obj = st_buffer_object(obj); + char *map; + + if (offset >= st_obj->size || size > (st_obj->size - offset)) + return; + + map = pipe_buffer_map(pipe->screen, st_obj->buffer, PIPE_BUFFER_USAGE_CPU_WRITE); + memcpy(map + offset, data, size); + pipe_buffer_unmap(pipe->screen, st_obj->buffer); +} + + +/** + * Called via glGetBufferSubDataARB(). + */ +static void +st_bufferobj_get_subdata(GLcontext *ctx, + GLenum target, + GLintptrARB offset, + GLsizeiptrARB size, + GLvoid * data, struct gl_buffer_object *obj) +{ + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_buffer_object *st_obj = st_buffer_object(obj); + char *map; + + if (offset >= st_obj->size || size > (st_obj->size - offset)) + return; + + map = pipe_buffer_map(pipe->screen, st_obj->buffer, PIPE_BUFFER_USAGE_CPU_READ); + memcpy(data, map + offset, size); + pipe_buffer_unmap(pipe->screen, st_obj->buffer); +} + + +/** + * Allocate space for and store data in a buffer object. Any data that was + * previously stored in the buffer object is lost. If data is NULL, + * memory will be allocated, but no copy will occur. + * Called via glBufferDataARB(). + */ +static void +st_bufferobj_data(GLcontext *ctx, + GLenum target, + GLsizeiptrARB size, + const GLvoid * data, + GLenum usage, + struct gl_buffer_object *obj) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct st_buffer_object *st_obj = st_buffer_object(obj); + unsigned buffer_usage; + + st_obj->Base.Size = size; + st_obj->Base.Usage = usage; + + switch(target) { + case GL_PIXEL_PACK_BUFFER_ARB: + case GL_PIXEL_UNPACK_BUFFER_ARB: + buffer_usage = PIPE_BUFFER_USAGE_PIXEL; + break; + case GL_ARRAY_BUFFER_ARB: + buffer_usage = PIPE_BUFFER_USAGE_VERTEX; + break; + case GL_ELEMENT_ARRAY_BUFFER_ARB: + buffer_usage = PIPE_BUFFER_USAGE_INDEX; + break; + default: + buffer_usage = 0; + } + + pipe_buffer_reference( pipe->screen, &st_obj->buffer, NULL ); + + st_obj->buffer = pipe_buffer_create( pipe->screen, 32, buffer_usage, size ); + + st_obj->size = size; + + if (data) + st_bufferobj_subdata(ctx, target, 0, size, data, obj); +} + + +/** + * Called via glMapBufferARB(). + */ +static void * +st_bufferobj_map(GLcontext *ctx, GLenum target, GLenum access, + struct gl_buffer_object *obj) +{ + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_buffer_object *st_obj = st_buffer_object(obj); + GLuint flags; + + switch (access) { + case GL_WRITE_ONLY: + flags = PIPE_BUFFER_USAGE_CPU_WRITE; + break; + case GL_READ_ONLY: + flags = PIPE_BUFFER_USAGE_CPU_READ; + break; + case GL_READ_WRITE: + /* fall-through */ + default: + flags = PIPE_BUFFER_USAGE_CPU_READ | PIPE_BUFFER_USAGE_CPU_WRITE; + break; + } + + obj->Pointer = pipe_buffer_map(pipe->screen, st_obj->buffer, flags); + return obj->Pointer; +} + + +/** + * Called via glMapBufferARB(). + */ +static GLboolean +st_bufferobj_unmap(GLcontext *ctx, GLenum target, struct gl_buffer_object *obj) +{ + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_buffer_object *st_obj = st_buffer_object(obj); + + pipe_buffer_unmap(pipe->screen, st_obj->buffer); + obj->Pointer = NULL; + return GL_TRUE; +} + + +void +st_init_bufferobject_functions(struct dd_function_table *functions) +{ + functions->NewBufferObject = st_bufferobj_alloc; + functions->DeleteBuffer = st_bufferobj_free; + functions->BufferData = st_bufferobj_data; + functions->BufferSubData = st_bufferobj_subdata; + functions->GetBufferSubData = st_bufferobj_get_subdata; + functions->MapBuffer = st_bufferobj_map; + functions->UnmapBuffer = st_bufferobj_unmap; +} diff --git a/src/mesa/state_tracker/st_cb_bufferobjects.h b/src/mesa/state_tracker/st_cb_bufferobjects.h new file mode 100644 index 0000000000..dcbb5a5233 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_bufferobjects.h @@ -0,0 +1,66 @@ +/************************************************************************** + * + * Copyright 2005 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef ST_CB_BUFFEROBJECTS_H +#define ST_CB_BUFFEROBJECTS_H + +struct st_context; +struct gl_buffer_object; +struct pipe_buffer; + +/** + * State_tracker vertex/pixel buffer object, derived from Mesa's + * gl_buffer_object. + */ +struct st_buffer_object +{ + struct gl_buffer_object Base; + struct pipe_buffer *buffer; + GLsizeiptrARB size; +}; + + +/* Are the obj->Name tests necessary? Unfortunately yes, mesa + * allocates a couple of gl_buffer_object structs statically, and the + * Name == 0 test is the only way to identify them and avoid casting + * them erroneously to our structs. + */ +static INLINE struct st_buffer_object * +st_buffer_object(struct gl_buffer_object *obj) +{ + if (obj->Name) + return (struct st_buffer_object *) obj; + else + return NULL; +} + + +extern void +st_init_bufferobject_functions(struct dd_function_table *functions); + + +#endif diff --git a/src/mesa/state_tracker/st_cb_clear.c b/src/mesa/state_tracker/st_cb_clear.c new file mode 100644 index 0000000000..1412a3761f --- /dev/null +++ b/src/mesa/state_tracker/st_cb_clear.c @@ -0,0 +1,577 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + */ + +#include "main/glheader.h" +#include "main/macros.h" +#include "shader/prog_instruction.h" +#include "st_context.h" +#include "st_atom.h" +#include "st_cb_accum.h" +#include "st_cb_clear.h" +#include "st_cb_fbo.h" +#include "st_draw.h" +#include "st_program.h" +#include "st_public.h" +#include "st_mesa_to_tgsi.h" + +#include "pipe/p_context.h" +#include "pipe/p_inlines.h" +#include "pipe/p_state.h" +#include "pipe/p_defines.h" +#include "util/u_pack_color.h" +#include "util/u_simple_shaders.h" +#include "util/u_draw_quad.h" + +#include "cso_cache/cso_context.h" + + +void +st_init_clear(struct st_context *st) +{ + struct pipe_context *pipe = st->pipe; + + /* rasterizer state: bypass clipping */ + memset(&st->clear.raster, 0, sizeof(st->clear.raster)); + st->clear.raster.gl_rasterization_rules = 1; + st->clear.raster.bypass_clipping = 1; + + /* viewport state: identity since we're drawing in window coords */ + st->clear.viewport.scale[0] = 1.0; + st->clear.viewport.scale[1] = 1.0; + st->clear.viewport.scale[2] = 1.0; + st->clear.viewport.scale[3] = 1.0; + st->clear.viewport.translate[0] = 0.0; + st->clear.viewport.translate[1] = 0.0; + st->clear.viewport.translate[2] = 0.0; + st->clear.viewport.translate[3] = 0.0; + + /* fragment shader state: color pass-through program */ + st->clear.fs = + util_make_fragment_passthrough_shader(pipe, &st->clear.frag_shader); + + /* vertex shader state: color/position pass-through */ + { + const uint semantic_names[] = { TGSI_SEMANTIC_POSITION, + TGSI_SEMANTIC_COLOR }; + const uint semantic_indexes[] = { 0, 0 }; + st->clear.vs = util_make_vertex_passthrough_shader(pipe, 2, + semantic_names, + semantic_indexes, + &st->clear.vert_shader); + } +} + + +void +st_destroy_clear(struct st_context *st) +{ + struct pipe_context *pipe = st->pipe; + + if (st->clear.vert_shader.tokens) { + FREE((void *) st->clear.vert_shader.tokens); + st->clear.vert_shader.tokens = NULL; + } + + if (st->clear.frag_shader.tokens) { + FREE((void *) st->clear.frag_shader.tokens); + st->clear.frag_shader.tokens = NULL; + } + + if (st->clear.fs) { + cso_delete_fragment_shader(st->cso_context, st->clear.fs); + st->clear.fs = NULL; + } + if (st->clear.vs) { + cso_delete_vertex_shader(st->cso_context, st->clear.vs); + st->clear.vs = NULL; + } + if (st->clear.vbuf) { + pipe_buffer_reference(pipe->screen, &st->clear.vbuf, NULL); + st->clear.vbuf = NULL; + } +} + + +static GLboolean +is_depth_stencil_format(enum pipe_format pipeFormat) +{ + switch (pipeFormat) { + case PIPE_FORMAT_S8Z24_UNORM: + case PIPE_FORMAT_Z24S8_UNORM: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + + +/** + * Draw a screen-aligned quadrilateral. + * Coords are window coords with y=0=bottom. These coords will be transformed + * by the vertex shader and viewport transform (which will flip Y if needed). + */ +static void +draw_quad(GLcontext *ctx, + float x0, float y0, float x1, float y1, GLfloat z, + const GLfloat color[4]) +{ + struct st_context *st = ctx->st; + struct pipe_context *pipe = st->pipe; + GLuint i; + void *buf; + + if (!st->clear.vbuf) { + st->clear.vbuf = pipe_buffer_create(pipe->screen, 32, PIPE_BUFFER_USAGE_VERTEX, + sizeof(st->clear.vertices)); + } + + /* positions */ + st->clear.vertices[0][0][0] = x0; + st->clear.vertices[0][0][1] = y0; + + st->clear.vertices[1][0][0] = x1; + st->clear.vertices[1][0][1] = y0; + + st->clear.vertices[2][0][0] = x1; + st->clear.vertices[2][0][1] = y1; + + st->clear.vertices[3][0][0] = x0; + st->clear.vertices[3][0][1] = y1; + + /* same for all verts: */ + for (i = 0; i < 4; i++) { + st->clear.vertices[i][0][2] = z; + st->clear.vertices[i][0][3] = 1.0; + st->clear.vertices[i][1][0] = color[0]; + st->clear.vertices[i][1][1] = color[1]; + st->clear.vertices[i][1][2] = color[2]; + st->clear.vertices[i][1][3] = color[3]; + } + + /* put vertex data into vbuf */ + buf = pipe_buffer_map(pipe->screen, st->clear.vbuf, PIPE_BUFFER_USAGE_CPU_WRITE); + memcpy(buf, st->clear.vertices, sizeof(st->clear.vertices)); + pipe_buffer_unmap(pipe->screen, st->clear.vbuf); + + /* draw */ + util_draw_vertex_buffer(pipe, st->clear.vbuf, + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + 2); /* attribs/vert */ +} + + + +/** + * Do glClear by drawing a quadrilateral. + * The vertices of the quad will be computed from the + * ctx->DrawBuffer->_X/Ymin/max fields. + */ +static void +clear_with_quad(GLcontext *ctx, + GLboolean color, GLboolean depth, GLboolean stencil) +{ + struct st_context *st = ctx->st; + const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin; + const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax; + GLfloat y0, y1; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + y0 = (GLfloat) (ctx->DrawBuffer->Height - ctx->DrawBuffer->_Ymax); + y1 = (GLfloat) (ctx->DrawBuffer->Height - ctx->DrawBuffer->_Ymin); + } + else { + y0 = (GLfloat) ctx->DrawBuffer->_Ymin; + y1 = (GLfloat) ctx->DrawBuffer->_Ymax; + } + + /* + printf("%s %s%s%s %f,%f %f,%f\n", __FUNCTION__, + color ? "color, " : "", + depth ? "depth, " : "", + stencil ? "stencil" : "", + x0, y0, + x1, y1); + */ + + cso_save_blend(st->cso_context); + cso_save_depth_stencil_alpha(st->cso_context); + cso_save_rasterizer(st->cso_context); + cso_save_viewport(st->cso_context); + cso_save_fragment_shader(st->cso_context); + cso_save_vertex_shader(st->cso_context); + + /* blend state: RGBA masking */ + { + struct pipe_blend_state blend; + memset(&blend, 0, sizeof(blend)); + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + if (color) { + if (ctx->Color.ColorMask[0]) + blend.colormask |= PIPE_MASK_R; + if (ctx->Color.ColorMask[1]) + blend.colormask |= PIPE_MASK_G; + if (ctx->Color.ColorMask[2]) + blend.colormask |= PIPE_MASK_B; + if (ctx->Color.ColorMask[3]) + blend.colormask |= PIPE_MASK_A; + if (st->ctx->Color.DitherFlag) + blend.dither = 1; + } + cso_set_blend(st->cso_context, &blend); + } + + /* depth_stencil state: always pass/set to ref value */ + { + struct pipe_depth_stencil_alpha_state depth_stencil; + memset(&depth_stencil, 0, sizeof(depth_stencil)); + if (depth) { + depth_stencil.depth.enabled = 1; + depth_stencil.depth.writemask = 1; + depth_stencil.depth.func = PIPE_FUNC_ALWAYS; + } + + if (stencil) { + depth_stencil.stencil[0].enabled = 1; + depth_stencil.stencil[0].func = PIPE_FUNC_ALWAYS; + depth_stencil.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; + depth_stencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; + depth_stencil.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; + depth_stencil.stencil[0].ref_value = ctx->Stencil.Clear; + depth_stencil.stencil[0].value_mask = 0xff; + depth_stencil.stencil[0].write_mask = ctx->Stencil.WriteMask[0] & 0xff; + } + + cso_set_depth_stencil_alpha(st->cso_context, &depth_stencil); + } + + cso_set_rasterizer(st->cso_context, &st->clear.raster); + cso_set_viewport(st->cso_context, &st->clear.viewport); + + cso_set_fragment_shader_handle(st->cso_context, st->clear.fs); + cso_set_vertex_shader_handle(st->cso_context, st->clear.vs); + + /* draw quad matching scissor rect (XXX verify coord round-off) */ + draw_quad(ctx, x0, y0, x1, y1, (GLfloat) ctx->Depth.Clear, ctx->Color.ClearColor); + + /* Restore pipe state */ + cso_restore_blend(st->cso_context); + cso_restore_depth_stencil_alpha(st->cso_context); + cso_restore_rasterizer(st->cso_context); + cso_restore_viewport(st->cso_context); + cso_restore_fragment_shader(st->cso_context); + cso_restore_vertex_shader(st->cso_context); +} + + +/** + * Determine if we need to clear the depth buffer by drawing a quad. + */ +static INLINE GLboolean +check_clear_color_with_quad(GLcontext *ctx, struct gl_renderbuffer *rb) +{ + const struct st_renderbuffer *strb = st_renderbuffer(rb); + + if (strb->surface->status == PIPE_SURFACE_STATUS_UNDEFINED) + return FALSE; + + if (ctx->Scissor.Enabled) + return TRUE; + + if (!ctx->Color.ColorMask[0] || + !ctx->Color.ColorMask[1] || + !ctx->Color.ColorMask[2] || + !ctx->Color.ColorMask[3]) + return TRUE; + + return FALSE; +} + + +static INLINE GLboolean +check_clear_depth_stencil_with_quad(GLcontext *ctx, struct gl_renderbuffer *rb) +{ + const struct st_renderbuffer *strb = st_renderbuffer(rb); + const GLuint stencilMax = (1 << rb->StencilBits) - 1; + GLboolean maskStencil + = (ctx->Stencil.WriteMask[0] & stencilMax) != stencilMax; + + if (strb->surface->status == PIPE_SURFACE_STATUS_UNDEFINED) + return FALSE; + + if (ctx->Scissor.Enabled) + return TRUE; + + if (maskStencil) + return TRUE; + + return FALSE; +} + + +/** + * Determine if we need to clear the depth buffer by drawing a quad. + */ +static INLINE GLboolean +check_clear_depth_with_quad(GLcontext *ctx, struct gl_renderbuffer *rb) +{ + const struct st_renderbuffer *strb = st_renderbuffer(rb); + const GLboolean isDS = is_depth_stencil_format(strb->surface->format); + + if (strb->surface->status == PIPE_SURFACE_STATUS_UNDEFINED) + return FALSE; + + if (ctx->Scissor.Enabled) + return TRUE; + + if (isDS && + strb->surface->status == PIPE_SURFACE_STATUS_DEFINED && + ctx->DrawBuffer->Visual.stencilBits > 0) + return TRUE; + + return FALSE; +} + + +/** + * Determine if we need to clear the stencil buffer by drawing a quad. + */ +static INLINE GLboolean +check_clear_stencil_with_quad(GLcontext *ctx, struct gl_renderbuffer *rb) +{ + const struct st_renderbuffer *strb = st_renderbuffer(rb); + const GLboolean isDS = is_depth_stencil_format(strb->surface->format); + const GLuint stencilMax = (1 << rb->StencilBits) - 1; + const GLboolean maskStencil + = (ctx->Stencil.WriteMask[0] & stencilMax) != stencilMax; + + if (strb->surface->status == PIPE_SURFACE_STATUS_UNDEFINED) + return FALSE; + + if (maskStencil) + return TRUE; + + if (ctx->Scissor.Enabled) + return TRUE; + + /* This is correct, but it is necessary to look at the depth clear + * value held in the surface when it comes time to issue the clear, + * rather than taking depth and stencil clear values from the + * current state. + */ + if (isDS && + strb->surface->status == PIPE_SURFACE_STATUS_DEFINED && + ctx->DrawBuffer->Visual.depthBits > 0) + return TRUE; + + return FALSE; +} + + + +static void +clear_color_buffer(GLcontext *ctx, struct gl_renderbuffer *rb) +{ + struct st_renderbuffer *strb = st_renderbuffer(rb); + + if (!strb->surface) + return; + + if (check_clear_color_with_quad( ctx, rb )) { + /* masking or scissoring */ + clear_with_quad(ctx, GL_TRUE, GL_FALSE, GL_FALSE); + } + else { + /* clear whole buffer w/out masking */ + uint clearValue; + /* NOTE: we always pass the clear color as PIPE_FORMAT_A8R8G8B8_UNORM + * at this time! + */ + util_pack_color(ctx->Color.ClearColor, PIPE_FORMAT_A8R8G8B8_UNORM, &clearValue); + ctx->st->pipe->clear(ctx->st->pipe, strb->surface, clearValue); + } +} + + +static void +clear_depth_buffer(GLcontext *ctx, struct gl_renderbuffer *rb) +{ + struct st_renderbuffer *strb = st_renderbuffer(rb); + + if (!strb->surface) + return; + + if (check_clear_depth_with_quad(ctx, rb)) { + /* scissoring or we have a combined depth/stencil buffer */ + clear_with_quad(ctx, GL_FALSE, GL_TRUE, GL_FALSE); + } + else { + /* simple clear of whole buffer */ + uint clearValue = util_pack_z(strb->surface->format, ctx->Depth.Clear); + ctx->st->pipe->clear(ctx->st->pipe, strb->surface, clearValue); + } +} + + +static void +clear_stencil_buffer(GLcontext *ctx, struct gl_renderbuffer *rb) +{ + struct st_renderbuffer *strb = st_renderbuffer(rb); + + if (!strb->surface) + return; + + if (check_clear_stencil_with_quad(ctx, rb)) { + /* masking or scissoring or combined depth/stencil buffer */ + clear_with_quad(ctx, GL_FALSE, GL_FALSE, GL_TRUE); + } + else { + /* simple clear of whole buffer */ + GLuint clearValue = ctx->Stencil.Clear; + + switch (strb->surface->format) { + case PIPE_FORMAT_S8Z24_UNORM: + clearValue <<= 24; + break; + default: + ; /* no-op, stencil value is in least significant bits */ + } + + ctx->st->pipe->clear(ctx->st->pipe, strb->surface, clearValue); + } +} + + +static void +clear_depth_stencil_buffer(GLcontext *ctx, struct gl_renderbuffer *rb) +{ + struct st_renderbuffer *strb = st_renderbuffer(rb); + + if (!strb->surface) + return; + + if (check_clear_depth_stencil_with_quad(ctx, rb)) { + /* masking or scissoring */ + clear_with_quad(ctx, GL_FALSE, GL_TRUE, GL_TRUE); + } + else { + /* clear whole buffer w/out masking */ + GLuint clearValue = util_pack_z(strb->surface->format, ctx->Depth.Clear); + + switch (strb->surface->format) { + case PIPE_FORMAT_S8Z24_UNORM: + clearValue |= ctx->Stencil.Clear << 24; + break; + case PIPE_FORMAT_Z24S8_UNORM: + clearValue |= ctx->Stencil.Clear; + break; + default: + assert(0); + } + + ctx->st->pipe->clear(ctx->st->pipe, strb->surface, clearValue); + } +} + + + +/** + * Called via ctx->Driver.Clear() + * XXX: doesn't pick up the differences between front/back/left/right + * clears. Need to sort that out... + */ +static void st_clear(GLcontext *ctx, GLbitfield mask) +{ + static const GLbitfield BUFFER_BITS_DS + = (BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL); + struct st_context *st = ctx->st; + struct gl_renderbuffer *depthRb + = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; + struct gl_renderbuffer *stencilRb + = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; + GLbitfield cmask = mask & BUFFER_BITS_COLOR; + + /* This makes sure the softpipe has the latest scissor, etc values */ + st_validate_state( st ); + + /* + * XXX TO-DO: + * If we're going to use clear_with_quad() for any reason, use it to + * clear as many other buffers as possible. + * As it is now, we sometimes call clear_with_quad() three times to clear + * color/depth/stencil individually... + */ + + if (cmask) { + GLuint b; + for (b = 0; cmask; b++) { + if (cmask & (1 << b)) { + struct gl_renderbuffer *rb + = ctx->DrawBuffer->Attachment[b].Renderbuffer; + assert(rb); + clear_color_buffer(ctx, rb); + cmask &= ~(1 << b); /* turn off bit */ + } + assert(b < BUFFER_COUNT); + } + } + + if (mask & BUFFER_BIT_ACCUM) { + st_clear_accum_buffer(ctx, + ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer); + } + + if ((mask & BUFFER_BITS_DS) == BUFFER_BITS_DS && depthRb == stencilRb) { + /* clearing combined depth + stencil */ + clear_depth_stencil_buffer(ctx, depthRb); + } + else { + /* separate depth/stencil clears */ + if (mask & BUFFER_BIT_DEPTH) { + clear_depth_buffer(ctx, depthRb); + } + if (mask & BUFFER_BIT_STENCIL) { + clear_stencil_buffer(ctx, stencilRb); + } + } +} + + +void st_init_clear_functions(struct dd_function_table *functions) +{ + functions->Clear = st_clear; +} diff --git a/src/mesa/state_tracker/st_cb_clear.h b/src/mesa/state_tracker/st_cb_clear.h new file mode 100644 index 0000000000..f49387747d --- /dev/null +++ b/src/mesa/state_tracker/st_cb_clear.h @@ -0,0 +1,46 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_CB_CLEAR_H +#define ST_CB_CLEAR_H + + +extern void +st_init_clear(struct st_context *st); + + +extern void +st_destroy_clear(struct st_context *st); + + +extern void +st_init_clear_functions(struct dd_function_table *functions); + + +#endif /* ST_CB_CLEAR_H */ + diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c new file mode 100644 index 0000000000..5b24b9f068 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_drawpixels.c @@ -0,0 +1,1104 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Brian Paul + */ + +#include "main/imports.h" +#include "main/image.h" +#include "main/bufferobj.h" +#include "main/macros.h" +#include "main/texformat.h" +#include "main/state.h" +#include "shader/program.h" +#include "shader/prog_parameter.h" +#include "shader/prog_print.h" + +#include "st_context.h" +#include "st_atom.h" +#include "st_atom_constbuf.h" +#include "st_draw.h" +#include "st_program.h" +#include "st_cb_drawpixels.h" +#include "st_cb_readpixels.h" +#include "st_cb_fbo.h" +#include "st_cb_texture.h" +#include "st_draw.h" +#include "st_format.h" +#include "st_mesa_to_tgsi.h" +#include "st_texture.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" +#include "util/u_tile.h" +#include "util/u_draw_quad.h" +#include "shader/prog_instruction.h" +#include "cso_cache/cso_context.h" + + +/** + * Check if the given program is: + * 0: MOVE result.color, fragment.color; + * 1: END; + */ +static GLboolean +is_passthrough_program(const struct gl_fragment_program *prog) +{ + if (prog->Base.NumInstructions == 2) { + const struct prog_instruction *inst = prog->Base.Instructions; + if (inst[0].Opcode == OPCODE_MOV && + inst[1].Opcode == OPCODE_END && + inst[0].DstReg.File == PROGRAM_OUTPUT && + inst[0].DstReg.Index == FRAG_RESULT_COLR && + inst[0].DstReg.WriteMask == WRITEMASK_XYZW && + inst[0].SrcReg[0].File == PROGRAM_INPUT && + inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 && + inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) { + return GL_TRUE; + } + } + return GL_FALSE; +} + + + +/** + * Make fragment shader for glDraw/CopyPixels. This shader is made + * by combining the pixel transfer shader with the user-defined shader. + */ +static struct st_fragment_program * +combined_drawpix_fragment_program(GLcontext *ctx) +{ + struct st_context *st = ctx->st; + struct st_fragment_program *stfp; + + if (st->pixel_xfer.program->serialNo == st->pixel_xfer.xfer_prog_sn + && st->fp->serialNo == st->pixel_xfer.user_prog_sn) { + /* the pixel tranfer program has not changed and the user-defined + * program has not changed, so re-use the combined program. + */ + stfp = st->pixel_xfer.combined_prog; + } + else { + /* Concatenate the pixel transfer program with the current user- + * defined program. + */ + if (is_passthrough_program(&st->fp->Base)) { + stfp = (struct st_fragment_program *) + _mesa_clone_program(ctx, &st->pixel_xfer.program->Base.Base); + } + else { +#if 0 + printf("Base program:\n"); + _mesa_print_program(&st->fp->Base.Base); + printf("DrawPix program:\n"); + _mesa_print_program(&st->pixel_xfer.program->Base.Base); +#endif + stfp = (struct st_fragment_program *) + _mesa_combine_programs(ctx, + &st->pixel_xfer.program->Base.Base, + &st->fp->Base.Base); + } + +#if 0 + { + struct gl_program *p = &stfp->Base.Base; + printf("Combined DrawPixels program:\n"); + _mesa_print_program(p); + printf("InputsRead: 0x%x\n", p->InputsRead); + printf("OutputsWritten: 0x%x\n", p->OutputsWritten); + _mesa_print_parameter_list(p->Parameters); + } +#endif + + /* translate to TGSI tokens */ + st_translate_fragment_program(st, stfp, NULL); + + /* save new program, update serial numbers */ + st->pixel_xfer.xfer_prog_sn = st->pixel_xfer.program->serialNo; + st->pixel_xfer.user_prog_sn = st->fp->serialNo; + st->pixel_xfer.combined_prog_sn = stfp->serialNo; + st->pixel_xfer.combined_prog = stfp; + } + + /* Ideally we'd have updated the pipe constants during the normal + * st/atom mechanism. But we can't since this is specific to glDrawPixels. + */ + st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT); + + return stfp; +} + + +/** + * Create fragment shader that does a TEX() instruction to get a Z + * value, then writes to FRAG_RESULT_DEPR. + * Pass fragment color through as-is. + */ +static struct st_fragment_program * +make_fragment_shader_z(struct st_context *st) +{ + GLcontext *ctx = st->ctx; + struct gl_program *p; + GLuint ic = 0; + + if (st->drawpix.z_shader) { + return st->drawpix.z_shader; + } + + /* + * Create shader now + */ + p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); + if (!p) + return NULL; + + p->NumInstructions = 3; + + p->Instructions = _mesa_alloc_instructions(p->NumInstructions); + if (!p->Instructions) { + ctx->Driver.DeleteProgram(ctx, p); + return NULL; + } + _mesa_init_instructions(p->Instructions, p->NumInstructions); + + /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */ + p->Instructions[ic].Opcode = OPCODE_TEX; + p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; + p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPR; + p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z; + p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; + p->Instructions[ic].TexSrcUnit = 0; + p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + + /* MOV result.color, fragment.color */ + p->Instructions[ic].Opcode = OPCODE_MOV; + p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; + p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR; + p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_COL0; + ic++; + + /* END; */ + p->Instructions[ic++].Opcode = OPCODE_END; + + assert(ic == p->NumInstructions); + + p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0; + p->OutputsWritten = (1 << FRAG_RESULT_COLR) | (1 << FRAG_RESULT_DEPR); + p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ + + st->drawpix.z_shader = (struct st_fragment_program *) p; + st_translate_fragment_program(st, st->drawpix.z_shader, NULL); + + return st->drawpix.z_shader; +} + + + +/** + * Create a simple vertex shader that just passes through the + * vertex position and texcoord (and optionally, color). + */ +static struct st_vertex_program * +st_make_passthrough_vertex_shader(struct st_context *st, GLboolean passColor) +{ + GLcontext *ctx = st->ctx; + struct st_vertex_program *stvp; + struct gl_program *p; + GLuint ic = 0; + + if (st->drawpix.vert_shaders[passColor]) + return st->drawpix.vert_shaders[passColor]; + + /* + * Create shader now + */ + p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0); + if (!p) + return NULL; + + if (passColor) + p->NumInstructions = 4; + else + p->NumInstructions = 3; + + p->Instructions = _mesa_alloc_instructions(p->NumInstructions); + if (!p->Instructions) { + ctx->Driver.DeleteProgram(ctx, p); + return NULL; + } + _mesa_init_instructions(p->Instructions, p->NumInstructions); + /* MOV result.pos, vertex.pos; */ + p->Instructions[0].Opcode = OPCODE_MOV; + p->Instructions[0].DstReg.File = PROGRAM_OUTPUT; + p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS; + p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS; + /* MOV result.texcoord0, vertex.texcoord0; */ + p->Instructions[1].Opcode = OPCODE_MOV; + p->Instructions[1].DstReg.File = PROGRAM_OUTPUT; + p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0; + p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0; + ic = 2; + if (passColor) { + /* MOV result.color0, vertex.color0; */ + p->Instructions[ic].Opcode = OPCODE_MOV; + p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; + p->Instructions[ic].DstReg.Index = VERT_RESULT_COL0; + p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[ic].SrcReg[0].Index = VERT_ATTRIB_COLOR0; + ic++; + } + + /* END; */ + p->Instructions[ic].Opcode = OPCODE_END; + ic++; + + assert(ic == p->NumInstructions); + + p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0; + p->OutputsWritten = ((1 << VERT_RESULT_TEX0) | + (1 << VERT_RESULT_HPOS)); + if (passColor) { + p->InputsRead |= VERT_BIT_COLOR0; + p->OutputsWritten |= (1 << VERT_RESULT_COL0); + } + + stvp = (struct st_vertex_program *) p; + st_translate_vertex_program(st, stvp, NULL, NULL, NULL); + + st->drawpix.vert_shaders[passColor] = stvp; + + return stvp; +} + + +static GLenum +_mesa_base_format(GLenum format) +{ + switch (format) { + case GL_DEPTH_COMPONENT: + return GL_DEPTH_COMPONENT; + case GL_STENCIL_INDEX: + return GL_STENCIL_INDEX; + default: + return GL_RGBA; + } +} + + +/** + * Make texture containing an image for glDrawPixels image. + * If 'pixels' is NULL, leave the texture image data undefined. + */ +static struct pipe_texture * +make_texture(struct st_context *st, + GLsizei width, GLsizei height, GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels) +{ + GLcontext *ctx = st->ctx; + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + const struct gl_texture_format *mformat; + struct pipe_texture *pt; + enum pipe_format pipeFormat; + GLuint cpp; + GLenum baseFormat; + + baseFormat = _mesa_base_format(format); + + mformat = st_ChooseTextureFormat(ctx, baseFormat, format, type); + assert(mformat); + + pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat); + assert(pipeFormat); + cpp = st_sizeof_format(pipeFormat); + + pixels = _mesa_map_drawpix_pbo(ctx, unpack, pixels); + if (!pixels) + return NULL; + + pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, 0, width, height, + 1, 0, + PIPE_TEXTURE_USAGE_SAMPLER); + if (!pt) { + _mesa_unmap_drawpix_pbo(ctx, unpack); + return NULL; + } + + { + struct pipe_surface *surface; + static const GLuint dstImageOffsets = 0; + GLboolean success; + GLubyte *dest; + const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; + + /* we'll do pixel transfer in a fragment shader */ + ctx->_ImageTransferState = 0x0; + + surface = screen->get_tex_surface(screen, pt, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_WRITE); + + /* map texture surface */ + dest = screen->surface_map(screen, surface, + PIPE_BUFFER_USAGE_CPU_WRITE); + + /* Put image into texture surface. + * Note that the image is actually going to be upside down in + * the texture. We deal with that with texcoords. + */ + success = mformat->StoreImage(ctx, 2, /* dims */ + baseFormat, /* baseInternalFormat */ + mformat, /* gl_texture_format */ + dest, /* dest */ + 0, 0, 0, /* dstX/Y/Zoffset */ + surface->stride, /* dstRowStride, bytes */ + &dstImageOffsets, /* dstImageOffsets */ + width, height, 1, /* size */ + format, type, /* src format/type */ + pixels, /* data source */ + unpack); + + /* unmap */ + screen->surface_unmap(screen, surface); + pipe_surface_reference(&surface, NULL); + + assert(success); + + /* restore */ + ctx->_ImageTransferState = imageTransferStateSave; + } + + _mesa_unmap_drawpix_pbo(ctx, unpack); + + return pt; +} + + +/** + * Draw quad with texcoords and optional color. + * Coords are window coords with y=0=bottom. + * \param color may be null + * \param invertTex if true, flip texcoords vertically + */ +static void +draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z, + GLfloat x1, GLfloat y1, const GLfloat *color, + GLboolean invertTex) +{ + struct st_context *st = ctx->st; + struct pipe_context *pipe = ctx->st->pipe; + GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */ + + /* setup vertex data */ + { + const struct gl_framebuffer *fb = st->ctx->DrawBuffer; + const GLfloat fb_width = (GLfloat) fb->Width; + const GLfloat fb_height = (GLfloat) fb->Height; + const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f; + const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f; + const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f; + const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f; + const GLfloat sLeft = 0.0f, sRight = 1.0f; + const GLfloat tTop = invertTex, tBot = 1.0f - tTop; + GLuint tex, i; + + /* upper-left */ + verts[0][0][0] = clip_x0; /* v[0].attr[0].x */ + verts[0][0][1] = clip_y0; /* v[0].attr[0].y */ + + /* upper-right */ + verts[1][0][0] = clip_x1; + verts[1][0][1] = clip_y0; + + /* lower-right */ + verts[2][0][0] = clip_x1; + verts[2][0][1] = clip_y1; + + /* lower-left */ + verts[3][0][0] = clip_x0; + verts[3][0][1] = clip_y1; + + tex = color ? 2 : 1; + verts[0][tex][0] = sLeft; /* v[0].attr[tex].s */ + verts[0][tex][1] = tTop; /* v[0].attr[tex].t */ + verts[1][tex][0] = sRight; + verts[1][tex][1] = tTop; + verts[2][tex][0] = sRight; + verts[2][tex][1] = tBot; + verts[3][tex][0] = sLeft; + verts[3][tex][1] = tBot; + + /* same for all verts: */ + if (color) { + for (i = 0; i < 4; i++) { + verts[i][0][2] = z; /*Z*/ + verts[i][0][3] = 1.0f; /*W*/ + verts[i][1][0] = color[0]; + verts[i][1][1] = color[1]; + verts[i][1][2] = color[2]; + verts[i][1][3] = color[3]; + verts[i][2][2] = 0.0f; /*R*/ + verts[i][2][3] = 1.0f; /*Q*/ + } + } + else { + for (i = 0; i < 4; i++) { + verts[i][0][2] = z; /*Z*/ + verts[i][0][3] = 1.0f; /*W*/ + verts[i][1][2] = 0.0f; /*R*/ + verts[i][1][3] = 1.0f; /*Q*/ + } + } + } + + { + struct pipe_buffer *buf; + ubyte *map; + + /* allocate/load buffer object with vertex data */ + buf = pipe_buffer_create(pipe->screen, 32, PIPE_BUFFER_USAGE_VERTEX, + sizeof(verts)); + map = pipe_buffer_map(pipe->screen, buf, PIPE_BUFFER_USAGE_CPU_WRITE); + memcpy(map, verts, sizeof(verts)); + pipe_buffer_unmap(pipe->screen, buf); + + util_draw_vertex_buffer(pipe, buf, + PIPE_PRIM_QUADS, + 4, /* verts */ + 3); /* attribs/vert */ + pipe_buffer_reference(pipe->screen, &buf, NULL); + } +} + + + +static void +draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, + GLsizei width, GLsizei height, + GLfloat zoomX, GLfloat zoomY, + struct pipe_texture *pt, + struct st_vertex_program *stvp, + struct st_fragment_program *stfp, + const GLfloat *color, + GLboolean invertTex) +{ + struct st_context *st = ctx->st; + struct pipe_context *pipe = ctx->st->pipe; + struct cso_context *cso = ctx->st->cso_context; + GLfloat x0, y0, x1, y1; + GLsizei maxSize; + + /* limit checks */ + /* XXX if DrawPixels image is larger than max texture size, break + * it up into chunks. + */ + maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); + assert(width <= maxSize); + assert(height <= maxSize); + + cso_save_rasterizer(cso); + cso_save_viewport(cso); + cso_save_samplers(cso); + cso_save_sampler_textures(cso); + cso_save_fragment_shader(cso); + cso_save_vertex_shader(cso); + + /* rasterizer state: just scissor */ + { + struct pipe_rasterizer_state rasterizer; + memset(&rasterizer, 0, sizeof(rasterizer)); + rasterizer.gl_rasterization_rules = 1; + rasterizer.scissor = ctx->Scissor.Enabled; + cso_set_rasterizer(cso, &rasterizer); + } + + /* fragment shader state: TEX lookup program */ + cso_set_fragment_shader_handle(cso, stfp->driver_shader); + + /* vertex shader state: position + texcoord pass-through */ + cso_set_vertex_shader_handle(cso, stvp->driver_shader); + + + /* texture sampling state: */ + { + struct pipe_sampler_state sampler; + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP; + sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.normalized_coords = 1; + + cso_single_sampler(cso, 0, &sampler); + if (st->pixel_xfer.pixelmap_enabled) { + cso_single_sampler(cso, 1, &sampler); + } + cso_single_sampler_done(cso); + } + + /* viewport state: viewport matching window dims */ + { + const float width = (float) ctx->DrawBuffer->Width; + const float height = (float) ctx->DrawBuffer->Height; + struct pipe_viewport_state vp; + vp.scale[0] = 0.5f * width; + vp.scale[1] = -0.5f * height; + vp.scale[2] = 1.0f; + vp.scale[3] = 1.0f; + vp.translate[0] = 0.5f * width; + vp.translate[1] = 0.5f * height; + vp.translate[2] = 0.0f; + vp.translate[3] = 0.0f; + cso_set_viewport(cso, &vp); + } + + /* texture state: */ + if (st->pixel_xfer.pixelmap_enabled) { + struct pipe_texture *textures[2]; + textures[0] = pt; + textures[1] = st->pixel_xfer.pixelmap_texture; + pipe->set_sampler_textures(pipe, 2, textures); + } + else { + pipe->set_sampler_textures(pipe, 1, &pt); + } + + /* Compute window coords (y=0=bottom) with pixel zoom. + * Recall that these coords are transformed by the current + * vertex shader and viewport transformation. + */ + x0 = (GLfloat) x; + x1 = x + width * ctx->Pixel.ZoomX; + y0 = (GLfloat) y; + y1 = y + height * ctx->Pixel.ZoomY; + //if(!color) + draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex); + //else + //printf("skip draw quad\n"); + /* restore state */ + cso_restore_rasterizer(cso); + cso_restore_viewport(cso); + cso_restore_samplers(cso); + cso_restore_sampler_textures(cso); + cso_restore_fragment_shader(cso); + cso_restore_vertex_shader(cso); +} + + +/** + * Check if a GL format/type combination is a match to the given pipe format. + * XXX probably move this to a re-usable place. + */ +static GLboolean +compatible_formats(GLenum format, GLenum type, enum pipe_format pipeFormat) +{ + static const GLuint one = 1; + GLubyte littleEndian = *((GLubyte *) &one); + + if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM && + format == GL_RGBA && + type == GL_UNSIGNED_BYTE && + !littleEndian) { + return GL_TRUE; + } + else if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM && + format == GL_ABGR_EXT && + type == GL_UNSIGNED_BYTE && + littleEndian) { + return GL_TRUE; + } + else if (pipeFormat == PIPE_FORMAT_A8R8G8B8_UNORM && + format == GL_BGRA && + type == GL_UNSIGNED_BYTE && + littleEndian) { + return GL_TRUE; + } + else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM && + format == GL_RGB && + type == GL_UNSIGNED_SHORT_5_6_5) { + /* endian don't care */ + return GL_TRUE; + } + else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM && + format == GL_BGR && + type == GL_UNSIGNED_SHORT_5_6_5_REV) { + /* endian don't care */ + return GL_TRUE; + } + else if (pipeFormat == PIPE_FORMAT_S8_UNORM && + format == GL_STENCIL_INDEX && + type == GL_UNSIGNED_BYTE) { + return GL_TRUE; + } + else if (pipeFormat == PIPE_FORMAT_Z32_UNORM && + format == GL_DEPTH_COMPONENT && + type == GL_UNSIGNED_INT) { + return GL_TRUE; + } + /* XXX add more cases */ + else { + return GL_FALSE; + } +} + + +/** + * Check if any per-fragment ops are enabled. + * XXX probably move this to a re-usable place. + */ +static GLboolean +any_fragment_ops(const struct st_context *st) +{ + if (st->state.depth_stencil.alpha.enabled || + st->state.depth_stencil.depth.enabled || + st->state.blend.blend_enable || + st->state.blend.logicop_enable) + /* XXX more checks */ + return GL_TRUE; + else + return GL_FALSE; +} + + +/** + * Check if any pixel transfer ops are enabled. + * XXX probably move this to a re-usable place. + */ +static GLboolean +any_pixel_transfer_ops(const struct st_context *st) +{ + if (st->ctx->Pixel.RedScale != 1.0 || + st->ctx->Pixel.RedBias != 0.0 || + st->ctx->Pixel.GreenScale != 1.0 || + st->ctx->Pixel.GreenBias != 0.0 || + st->ctx->Pixel.BlueScale != 1.0 || + st->ctx->Pixel.BlueBias != 0.0 || + st->ctx->Pixel.AlphaScale != 1.0 || + st->ctx->Pixel.AlphaBias != 0.0 || + st->ctx->Pixel.MapColorFlag) + /* XXX more checks */ + return GL_TRUE; + else + return GL_FALSE; +} + + +/** + * Draw image with a blit, or other non-textured quad method. + */ +static void +draw_blit(struct st_context *st, + GLsizei width, GLsizei height, + GLenum format, GLenum type, const GLvoid *pixels) +{ + + +} + + +static void +draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels) +{ + struct st_context *st = ctx->st; + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + struct st_renderbuffer *strb; + struct pipe_surface *ps; + const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; + GLint skipPixels; + ubyte *stmap; + + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + + strb = st_renderbuffer(ctx->DrawBuffer-> + Attachment[BUFFER_STENCIL].Renderbuffer); + ps = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_WRITE); + + /* map the stencil buffer */ + stmap = screen->surface_map(screen, ps, + PIPE_BUFFER_USAGE_CPU_WRITE); + + /* if width > MAX_WIDTH, have to process image in chunks */ + skipPixels = 0; + while (skipPixels < width) { + const GLint spanX = x + skipPixels; + const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); + GLint row; + for (row = 0; row < height; row++) { + GLint spanY = y + row; + GLubyte values[MAX_WIDTH]; + GLenum destType = GL_UNSIGNED_BYTE; + const GLvoid *source = _mesa_image_address2d(unpack, pixels, + width, height, + GL_COLOR_INDEX, type, + row, skipPixels); + _mesa_unpack_stencil_span(ctx, spanWidth, destType, values, + type, source, unpack, + ctx->_ImageTransferState); + if (zoom) { + /* + _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth, + spanX, spanY, values); + */ + } + else { + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + spanY = ctx->DrawBuffer->Height - spanY - 1; + } + + switch (ps->format) { + case PIPE_FORMAT_S8_UNORM: + { + ubyte *dest = stmap + spanY * ps->stride + spanX; + memcpy(dest, values, spanWidth); + } + break; + case PIPE_FORMAT_S8Z24_UNORM: + { + uint *dest = (uint *) (stmap + spanY * ps->stride + spanX*4); + GLint k; + for (k = 0; k < spanWidth; k++) { + uint p = dest[k]; + p = (p & 0xffffff) | (values[k] << 24); + dest[k] = p; + } + } + break; + default: + assert(0); + } + } + } + skipPixels += spanWidth; + } + + /* unmap the stencil buffer */ + screen->surface_unmap(screen, ps); + pipe_surface_reference(&ps, NULL); +} + + +/** + * Called via ctx->Driver.DrawPixels() + */ +static void +st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) +{ + struct st_fragment_program *stfp; + struct st_vertex_program *stvp; + struct st_context *st = ctx->st; + struct pipe_surface *ps; + GLuint bufferFormat; + const GLfloat *color; + + if (format == GL_STENCIL_INDEX) { + draw_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels); + return; + } + + _mesa_set_vp_override( ctx, TRUE ); + _mesa_update_state( ctx ); + + st_validate_state(st); + + if (format == GL_DEPTH_COMPONENT) { + ps = st->state.framebuffer.zsbuf; + stfp = make_fragment_shader_z(ctx->st); + stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE); + color = ctx->Current.RasterColor; + } + else if (format == GL_STENCIL_INDEX) { + ps = st->state.framebuffer.zsbuf; + /* XXX special case - can't use texture map */ + color = NULL; + } + else { + ps = st->state.framebuffer.cbufs[0]; + stfp = combined_drawpix_fragment_program(ctx); + stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE); + color = NULL; + } + + bufferFormat = ps->format; + + if (1/*any_fragment_ops(st) || + any_pixel_transfer_ops(st) || + !compatible_formats(format, type, ps->format)*/) { + /* textured quad */ + struct pipe_texture *pt + = make_texture(ctx->st, width, height, format, type, unpack, pixels); + if (pt) { + draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], + width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, + pt, stvp, stfp, color, GL_FALSE); + pipe_texture_reference(&pt, NULL); + } + } + else { + /* blit */ + draw_blit(st, width, height, format, type, pixels); + } + + _mesa_set_vp_override( ctx, FALSE ); +} + + + +static void +copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy, + GLsizei width, GLsizei height, + GLint dstx, GLint dsty) +{ + struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer); + struct pipe_screen *screen = ctx->st->pipe->screen; + struct pipe_surface *psDraw; + ubyte *drawMap; + ubyte *buffer; + int i; + + buffer = malloc(width * height * sizeof(ubyte)); + if (!buffer) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)"); + return; + } + + /* this will do stencil pixel transfer ops */ + st_read_stencil_pixels(ctx, srcx, srcy, width, height, GL_UNSIGNED_BYTE, + &ctx->DefaultPacking, buffer); + + psDraw = screen->get_tex_surface(screen, rbDraw->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_WRITE); + + assert(psDraw->block.width == 1); + assert(psDraw->block.height == 1); + + /* map the stencil buffer */ + drawMap = screen->surface_map(screen, psDraw, PIPE_BUFFER_USAGE_CPU_WRITE); + + /* draw */ + /* XXX PixelZoom not handled yet */ + for (i = 0; i < height; i++) { + ubyte *dst; + const ubyte *src; + int y; + + y = dsty + i; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + y = ctx->DrawBuffer->Height - y - 1; + } + + dst = drawMap + y * psDraw->stride + dstx * psDraw->block.size; + src = buffer + i * width; + + switch (psDraw->format) { + case PIPE_FORMAT_S8Z24_UNORM: + { + uint *dst4 = (uint *) dst; + int j; + for (j = 0; j < width; j++) { + *dst4 = (*dst4 & 0xffffff) | (src[j] << 24); + dst4++; + } + } + break; + case PIPE_FORMAT_S8_UNORM: + memcpy(dst, src, width); + break; + default: + assert(0); + } + } + + free(buffer); + + /* unmap the stencil buffer */ + screen->surface_unmap(screen, psDraw); + pipe_surface_reference(&psDraw, NULL); +} + + +static void +st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, + GLsizei width, GLsizei height, + GLint dstx, GLint dsty, GLenum type) +{ + struct st_context *st = ctx->st; + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + struct st_renderbuffer *rbRead; + struct st_vertex_program *stvp; + struct st_fragment_program *stfp; + struct pipe_surface *psTex; + struct pipe_texture *pt; + GLfloat *color; + enum pipe_format srcFormat, texFormat; + + /* make sure rendering has completed */ + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + + st_validate_state(st); + + if (type == GL_STENCIL) { + /* can't use texturing to do stencil */ + copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); + return; + } + + if (type == GL_COLOR) { + rbRead = st_get_color_read_renderbuffer(ctx); + color = NULL; + stfp = combined_drawpix_fragment_program(ctx); + stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE); + } + else { + assert(type == GL_DEPTH); + rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); + color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; + stfp = make_fragment_shader_z(ctx->st); + stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE); + } + + srcFormat = rbRead->texture->format; + + if (screen->is_format_supported(screen, srcFormat, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, 0)) { + texFormat = srcFormat; + } + else { + /* srcFormat can't be used as a texture format */ + if (type == GL_DEPTH) { + texFormat = st_choose_format(pipe, GL_DEPTH_COMPONENT, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL); + assert(texFormat != PIPE_FORMAT_NONE); /* XXX no depth texture formats??? */ + } + else { + /* default color format */ + texFormat = st_choose_format(pipe, GL_RGBA, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER); + assert(texFormat != PIPE_FORMAT_NONE); + } + } + + pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, texFormat, 0, + width, height, 1, 0, + PIPE_TEXTURE_USAGE_SAMPLER); + if (!pt) + return; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + srcy = ctx->DrawBuffer->Height - srcy - height; + } + + if (srcFormat == texFormat) { + /* copy source framebuffer surface into mipmap/texture */ + struct pipe_surface *psRead = screen->get_tex_surface(screen, + rbRead->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_READ); + psTex = screen->get_tex_surface(screen, pt, 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_WRITE ); + pipe->surface_copy(pipe, + FALSE, + psTex, /* dest */ + 0, 0, /* destx/y */ + psRead, + srcx, srcy, width, height); + pipe_surface_reference(&psRead, NULL); + } + else { + /* CPU-based fallback/conversion */ + struct pipe_surface *psRead = screen->get_tex_surface(screen, + rbRead->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_READ); + + psTex = screen->get_tex_surface(screen, pt, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_WRITE ); + + if (type == GL_COLOR) { + /* alternate path using get/put_tile() */ + GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + + pipe_get_tile_rgba(psRead, srcx, srcy, width, height, buf); + pipe_put_tile_rgba(psTex, 0, 0, width, height, buf); + + free(buf); + } + else { + /* GL_DEPTH */ + GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint)); + pipe_get_tile_z(psRead, srcx, srcy, width, height, buf); + pipe_put_tile_z(psTex, 0, 0, width, height, buf); + free(buf); + } + pipe_surface_reference(&psRead, NULL); + } + + pipe_surface_reference(&psTex, NULL); + + /* draw textured quad */ + draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], + width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, + pt, stvp, stfp, color, GL_TRUE); + + pipe_texture_reference(&pt, NULL); +} + + + +void st_init_drawpixels_functions(struct dd_function_table *functions) +{ + functions->DrawPixels = st_DrawPixels; + functions->CopyPixels = st_CopyPixels; +} + + +void +st_destroy_drawpix(struct st_context *st) +{ + st_reference_fragprog(st, &st->drawpix.z_shader, NULL); + st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL); + st_reference_vertprog(st, &st->drawpix.vert_shaders[0], NULL); + st_reference_vertprog(st, &st->drawpix.vert_shaders[1], NULL); +} + + diff --git a/src/mesa/state_tracker/st_cb_drawpixels.h b/src/mesa/state_tracker/st_cb_drawpixels.h new file mode 100644 index 0000000000..26fe864d18 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_drawpixels.h @@ -0,0 +1,39 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_CB_DRAWPIXELS_H +#define ST_CB_DRAWPIXELS_H + + +extern void st_init_drawpixels_functions(struct dd_function_table *functions); + +extern void +st_destroy_drawpix(struct st_context *st); + + +#endif /* ST_CB_DRAWPIXELS_H */ diff --git a/src/mesa/state_tracker/st_cb_fbo.c b/src/mesa/state_tracker/st_cb_fbo.c new file mode 100644 index 0000000000..00076f61e0 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_fbo.c @@ -0,0 +1,459 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +/** + * Framebuffer/renderbuffer functions. + * + * \author Brian Paul + */ + + +#include "main/imports.h" +#include "main/context.h" +#include "main/fbobject.h" +#include "main/framebuffer.h" +#include "main/renderbuffer.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" +#include "pipe/p_winsys.h" +#include "st_context.h" +#include "st_cb_fbo.h" +#include "st_cb_texture.h" +#include "st_format.h" +#include "st_public.h" +#include "st_texture.h" + + + +/** + * Compute the renderbuffer's Red/Green/EtcBit fields from the pipe format. + */ +static int +init_renderbuffer_bits(struct st_renderbuffer *strb, + enum pipe_format pipeFormat) +{ + struct pipe_format_info info; + + if (!st_get_format_info( pipeFormat, &info )) { + assert( 0 ); + } + + strb->Base._ActualFormat = info.base_format; + strb->Base.RedBits = info.red_bits; + strb->Base.GreenBits = info.green_bits; + strb->Base.BlueBits = info.blue_bits; + strb->Base.AlphaBits = info.alpha_bits; + strb->Base.DepthBits = info.depth_bits; + strb->Base.StencilBits = info.stencil_bits; + strb->Base.DataType = st_format_datatype(pipeFormat); + + return info.size; +} + +/** + * gl_renderbuffer::AllocStorage() + * This is called to allocate the original drawing surface, and + * during window resize. + */ +static GLboolean +st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, + GLenum internalFormat, + GLuint width, GLuint height) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct st_renderbuffer *strb = st_renderbuffer(rb); + struct pipe_texture template; + unsigned surface_usage; + + /* Free the old surface and texture + */ + pipe_surface_reference( &strb->surface, NULL ); + pipe_texture_reference( &strb->texture, NULL ); + + + memset(&template, 0, sizeof(template)); + + if (strb->format != PIPE_FORMAT_NONE) { + template.format = strb->format; + } + else { + template.format = st_choose_renderbuffer_format(pipe, internalFormat); + } + + strb->Base.Width = width; + strb->Base.Height = height; + init_renderbuffer_bits(strb, template.format); + + template.target = PIPE_TEXTURE_2D; + template.compressed = 0; + pf_get_block(template.format, &template.block); + template.width[0] = width; + template.height[0] = height; + template.depth[0] = 1; + template.last_level = 0; + template.nr_samples = rb->Samples; + + if (pf_is_depth_stencil(template.format)) { + template.tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL; + } + else { + template.tex_usage = (PIPE_TEXTURE_USAGE_DISPLAY_TARGET | + PIPE_TEXTURE_USAGE_RENDER_TARGET); + } + + + /* Probably need dedicated flags for surface usage too: + */ + surface_usage = (PIPE_BUFFER_USAGE_GPU_READ | + PIPE_BUFFER_USAGE_GPU_WRITE); +#if 0 + PIPE_BUFFER_USAGE_CPU_READ | + PIPE_BUFFER_USAGE_CPU_WRITE); +#endif + + strb->texture = pipe->screen->texture_create( pipe->screen, + &template ); + + /* Special path for accum buffers. + * + * Try a different surface format. Since accum buffers are s/w + * only for now, the surface pixel format doesn't really matter, + * only that the buffer is large enough. + */ + if (!strb->texture && template.format == DEFAULT_ACCUM_PIPE_FORMAT) + { + /* Actually, just setting this usage value should be sufficient + * to tell the driver to go ahead and allocate the buffer, even + * if HW doesn't support the format. + */ + template.tex_usage = 0; + surface_usage = (PIPE_BUFFER_USAGE_CPU_READ | + PIPE_BUFFER_USAGE_CPU_WRITE); + + strb->texture = pipe->screen->texture_create( pipe->screen, + &template ); + + } + + if (!strb->texture) + return FALSE; + + strb->surface = pipe->screen->get_tex_surface( pipe->screen, + strb->texture, + 0, 0, 0, + surface_usage ); + + assert(strb->surface->texture); + assert(strb->surface->buffer); + assert(strb->surface->format); + assert(strb->surface->block.size); + assert(strb->surface->block.width); + assert(strb->surface->block.height); + assert(strb->surface->width == width); + assert(strb->surface->height == height); + assert(strb->surface->stride); + + + return strb->surface != NULL; +} + + +/** + * gl_renderbuffer::Delete() + */ +static void +st_renderbuffer_delete(struct gl_renderbuffer *rb) +{ + struct st_renderbuffer *strb = st_renderbuffer(rb); + ASSERT(strb); + pipe_surface_reference(&strb->surface, NULL); + pipe_texture_reference(&strb->texture, NULL); + free(strb); +} + + +/** + * gl_renderbuffer::GetPointer() + */ +static void * +null_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb, + GLint x, GLint y) +{ + /* By returning NULL we force all software rendering to go through + * the span routines. + */ +#if 0 + assert(0); /* Should never get called with softpipe */ +#endif + return NULL; +} + + +/** + * Called via ctx->Driver.NewFramebuffer() + */ +static struct gl_framebuffer * +st_new_framebuffer(GLcontext *ctx, GLuint name) +{ + /* XXX not sure we need to subclass gl_framebuffer for pipe */ + return _mesa_new_framebuffer(ctx, name); +} + + +/** + * Called via ctx->Driver.NewRenderbuffer() + */ +static struct gl_renderbuffer * +st_new_renderbuffer(GLcontext *ctx, GLuint name) +{ + struct st_renderbuffer *strb = CALLOC_STRUCT(st_renderbuffer); + if (strb) { + _mesa_init_renderbuffer(&strb->Base, name); + strb->Base.Delete = st_renderbuffer_delete; + strb->Base.AllocStorage = st_renderbuffer_alloc_storage; + strb->Base.GetPointer = null_get_pointer; + strb->format = PIPE_FORMAT_NONE; + return &strb->Base; + } + return NULL; +} + + +/** + * Allocate a renderbuffer for a an on-screen window (not a user-created + * renderbuffer). The window system code determines the format. + */ +struct gl_renderbuffer * +st_new_renderbuffer_fb(enum pipe_format format, int samples) +{ + struct st_renderbuffer *strb; + + strb = CALLOC_STRUCT(st_renderbuffer); + if (!strb) { + _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer"); + return NULL; + } + + _mesa_init_renderbuffer(&strb->Base, 0); + strb->Base.ClassID = 0x4242; /* just a unique value */ + strb->Base.Samples = samples; + strb->format = format; + + switch (format) { + case PIPE_FORMAT_A8R8G8B8_UNORM: + case PIPE_FORMAT_B8G8R8A8_UNORM: + case PIPE_FORMAT_X8R8G8B8_UNORM: + case PIPE_FORMAT_B8G8R8X8_UNORM: + case PIPE_FORMAT_A1R5G5B5_UNORM: + case PIPE_FORMAT_A4R4G4B4_UNORM: + case PIPE_FORMAT_R5G6B5_UNORM: + strb->Base.InternalFormat = GL_RGBA; + strb->Base._BaseFormat = GL_RGBA; + break; + case PIPE_FORMAT_Z16_UNORM: + strb->Base.InternalFormat = GL_DEPTH_COMPONENT16; + strb->Base._BaseFormat = GL_DEPTH_COMPONENT; + break; + case PIPE_FORMAT_Z32_UNORM: + strb->Base.InternalFormat = GL_DEPTH_COMPONENT32; + strb->Base._BaseFormat = GL_DEPTH_COMPONENT; + break; + case PIPE_FORMAT_S8Z24_UNORM: + case PIPE_FORMAT_Z24S8_UNORM: + case PIPE_FORMAT_X8Z24_UNORM: + case PIPE_FORMAT_Z24X8_UNORM: + strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT; + strb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT; + break; + case PIPE_FORMAT_S8_UNORM: + strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT; + strb->Base._BaseFormat = GL_STENCIL_INDEX; + break; + case DEFAULT_ACCUM_PIPE_FORMAT: /*PIPE_FORMAT_R16G16B16A16_SNORM*/ + strb->Base.InternalFormat = GL_RGBA16; + strb->Base._BaseFormat = GL_RGBA; + break; + default: + _mesa_problem(NULL, + "Unexpected format in st_new_renderbuffer_fb"); + return NULL; + } + + /* st-specific methods */ + strb->Base.Delete = st_renderbuffer_delete; + strb->Base.AllocStorage = st_renderbuffer_alloc_storage; + strb->Base.GetPointer = null_get_pointer; + + /* surface is allocated in st_renderbuffer_alloc_storage() */ + strb->surface = NULL; + + return &strb->Base; +} + + + + +/** + * Called via ctx->Driver.BindFramebufferEXT(). + */ +static void +st_bind_framebuffer(GLcontext *ctx, GLenum target, + struct gl_framebuffer *fb, struct gl_framebuffer *fbread) +{ + +} + +/** + * Called by ctx->Driver.FramebufferRenderbuffer + */ +static void +st_framebuffer_renderbuffer(GLcontext *ctx, + struct gl_framebuffer *fb, + GLenum attachment, + struct gl_renderbuffer *rb) +{ + /* XXX no need for derivation? */ + _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); +} + + +/** + * Called by ctx->Driver.RenderTexture + */ +static void +st_render_texture(GLcontext *ctx, + struct gl_framebuffer *fb, + struct gl_renderbuffer_attachment *att) +{ + struct st_renderbuffer *strb; + struct gl_renderbuffer *rb; + struct pipe_texture *pt; + struct st_texture_object *stObj; + const struct gl_texture_image *texImage = + att->Texture->Image[att->CubeMapFace][att->TextureLevel]; + + + assert(!att->Renderbuffer); + + /* create new renderbuffer which wraps the texture image */ + rb = st_new_renderbuffer(ctx, 0); + if (!rb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); + return; + } + + _mesa_reference_renderbuffer(&att->Renderbuffer, rb); + assert(rb->RefCount == 1); + rb->AllocStorage = NULL; /* should not get called */ + strb = st_renderbuffer(rb); + + /* get the texture for the texture object */ + stObj = st_texture_object(att->Texture); + + /* point renderbuffer at texobject */ + strb->rtt = stObj; + strb->rtt_level = att->TextureLevel; + strb->rtt_face = att->CubeMapFace; + strb->rtt_slice = att->Zoffset; + + rb->Width = texImage->Width2; + rb->Height = texImage->Height2; + /*printf("***** render to texture level %d: %d x %d\n", att->TextureLevel, rb->Width, rb->Height);*/ + + pt = st_get_texobj_texture(att->Texture); + assert(pt); + /*printf("***** pipe texture %d x %d\n", pt->width[0], pt->height[0]);*/ + + pipe_texture_reference( &strb->texture, pt ); + + pipe_surface_reference(&strb->surface, NULL); + + /* the new surface will be created during framebuffer validation */ + + init_renderbuffer_bits(strb, pt->format); + + /* + printf("RENDER TO TEXTURE obj=%p pt=%p surf=%p %d x %d\n", + att->Texture, pt, strb->surface, rb->Width, rb->Height); + */ + + /* Invalidate buffer state so that the pipe's framebuffer state + * gets updated. + * That's where the new renderbuffer (which we just created) gets + * passed to the pipe as a (color/depth) render target. + */ + st_invalidate_state(ctx, _NEW_BUFFERS); +} + + +/** + * Called via ctx->Driver.FinishRenderTexture. + */ +static void +st_finish_render_texture(GLcontext *ctx, + struct gl_renderbuffer_attachment *att) +{ + struct pipe_screen *screen = ctx->st->pipe->screen; + struct st_renderbuffer *strb = st_renderbuffer(att->Renderbuffer); + + if (!strb) + return; + + ctx->st->pipe->flush(ctx->st->pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + + if (strb->surface) + screen->tex_surface_release( screen, &strb->surface ); + + strb->rtt = NULL; + + /* + printf("FINISH RENDER TO TEXTURE surf=%p\n", strb->surface); + */ + + _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); + + /* restore previous framebuffer state */ + st_invalidate_state(ctx, _NEW_BUFFERS); +} + + + +void st_init_fbo_functions(struct dd_function_table *functions) +{ + functions->NewFramebuffer = st_new_framebuffer; + functions->NewRenderbuffer = st_new_renderbuffer; + functions->BindFramebuffer = st_bind_framebuffer; + functions->FramebufferRenderbuffer = st_framebuffer_renderbuffer; + functions->RenderTexture = st_render_texture; + functions->FinishRenderTexture = st_finish_render_texture; + /* no longer needed by core Mesa, drivers handle resizes... + functions->ResizeBuffers = st_resize_buffers; + */ +} diff --git a/src/mesa/state_tracker/st_cb_fbo.h b/src/mesa/state_tracker/st_cb_fbo.h new file mode 100644 index 0000000000..44fa9fe9a4 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_fbo.h @@ -0,0 +1,71 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_CB_FBO_H +#define ST_CB_FBO_H + + +#define DEFAULT_ACCUM_PIPE_FORMAT PIPE_FORMAT_R16G16B16A16_SNORM + + + +/** + * Derived renderbuffer class. Just need to add a pointer to the + * pipe surface. + */ +struct st_renderbuffer +{ + struct gl_renderbuffer Base; + struct pipe_texture *texture; + struct pipe_surface *surface; /* temporary view into texture */ + enum pipe_format format; /** preferred format, or PIPE_FORMAT_NONE */ + + struct st_texture_object *rtt; /**< GL render to texture's texture */ + int rtt_level, rtt_face, rtt_slice; + + /** Render to texture state */ + struct pipe_texture *texture_save; + struct pipe_surface *surface_save; +}; + + +static INLINE struct st_renderbuffer * +st_renderbuffer(struct gl_renderbuffer *rb) +{ + return (struct st_renderbuffer *) rb; +} + + +extern struct gl_renderbuffer * +st_new_renderbuffer_fb(enum pipe_format format, int samples); + +extern void +st_init_fbo_functions(struct dd_function_table *functions); + + +#endif /* ST_CB_FBO_H */ diff --git a/src/mesa/state_tracker/st_cb_feedback.c b/src/mesa/state_tracker/st_cb_feedback.c new file mode 100644 index 0000000000..19021411cf --- /dev/null +++ b/src/mesa/state_tracker/st_cb_feedback.c @@ -0,0 +1,310 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * GL_SELECT and GL_FEEDBACK render modes. + * Basically, we use a private instance of the 'draw' module for doing + * selection/feedback. It would be nice to use the transform_feedback + * hardware feature, but it's defined as happening pre-clip and we want + * post-clipped primitives. Also, there's concerns about the efficiency + * of using the hardware for this anyway. + * + * Authors: + * Brian Paul + */ + +#include "main/imports.h" +#include "main/context.h" +#include "main/feedback.h" +#include "main/macros.h" + +#include "vbo/vbo.h" + +#include "st_context.h" +#include "st_atom.h" +#include "st_draw.h" +#include "st_cb_feedback.h" +#include "st_cb_bufferobjects.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_winsys.h" +#include "cso_cache/cso_cache.h" + +#include "draw/draw_context.h" +#include "draw/draw_pipe.h" + + +/** + * This is actually used for both feedback and selection. + */ +struct feedback_stage +{ + struct draw_stage stage; /**< Base class */ + GLcontext *ctx; /**< Rendering context */ + GLboolean reset_stipple_counter; +}; + + +/********************************************************************** + * GL Feedback functions + **********************************************************************/ + +static INLINE struct feedback_stage * +feedback_stage( struct draw_stage *stage ) +{ + return (struct feedback_stage *)stage; +} + + +static void +feedback_vertex(GLcontext *ctx, const struct draw_context *draw, + const struct vertex_header *v) +{ + const struct st_context *st = ctx->st; + GLfloat win[4]; + const GLfloat *color, *texcoord; + const GLfloat ci = 0; + GLuint slot; + + /* Recall that Y=0=Top of window for Gallium wincoords */ + win[0] = v->data[0][0]; + win[1] = ctx->DrawBuffer->Height - v->data[0][1]; + win[2] = v->data[0][2]; + win[3] = 1.0F / v->data[0][3]; + + /* XXX + * When we compute vertex layout, save info about position of the + * color and texcoord attribs to use here. + */ + + slot = st->vertex_result_to_slot[VERT_RESULT_COL0]; + if (slot != ~0U) + color = v->data[slot]; + else + color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; + + slot = st->vertex_result_to_slot[VERT_RESULT_TEX0]; + if (slot != ~0U) + texcoord = v->data[slot]; + else + texcoord = ctx->Current.Attrib[VERT_ATTRIB_TEX0]; + + _mesa_feedback_vertex(ctx, win, color, ci, texcoord); +} + + +static void +feedback_tri( struct draw_stage *stage, struct prim_header *prim ) +{ + struct feedback_stage *fs = feedback_stage(stage); + struct draw_context *draw = stage->draw; + FEEDBACK_TOKEN(fs->ctx, (GLfloat) GL_POLYGON_TOKEN); + FEEDBACK_TOKEN(fs->ctx, (GLfloat) 3); /* three vertices */ + feedback_vertex(fs->ctx, draw, prim->v[0]); + feedback_vertex(fs->ctx, draw, prim->v[1]); + feedback_vertex(fs->ctx, draw, prim->v[2]); +} + + +static void +feedback_line( struct draw_stage *stage, struct prim_header *prim ) +{ + struct feedback_stage *fs = feedback_stage(stage); + struct draw_context *draw = stage->draw; + if (fs->reset_stipple_counter) { + FEEDBACK_TOKEN(fs->ctx, (GLfloat) GL_LINE_RESET_TOKEN); + fs->reset_stipple_counter = GL_FALSE; + } + else { + FEEDBACK_TOKEN(fs->ctx, (GLfloat) GL_LINE_TOKEN); + } + feedback_vertex(fs->ctx, draw, prim->v[0]); + feedback_vertex(fs->ctx, draw, prim->v[1]); +} + + +static void +feedback_point( struct draw_stage *stage, struct prim_header *prim ) +{ + struct feedback_stage *fs = feedback_stage(stage); + struct draw_context *draw = stage->draw; + FEEDBACK_TOKEN(fs->ctx, (GLfloat) GL_POINT_TOKEN); + feedback_vertex(fs->ctx, draw, prim->v[0]); +} + + +static void +feedback_flush( struct draw_stage *stage, unsigned flags ) +{ + /* no-op */ +} + + +static void +feedback_reset_stipple_counter( struct draw_stage *stage ) +{ + struct feedback_stage *fs = feedback_stage(stage); + fs->reset_stipple_counter = GL_TRUE; +} + + +static void +feedback_destroy( struct draw_stage *stage ) +{ + /* no-op */ +} + +/** + * Create GL feedback drawing stage. + */ +static struct draw_stage * +draw_glfeedback_stage(GLcontext *ctx, struct draw_context *draw) +{ + struct feedback_stage *fs = CALLOC_STRUCT(feedback_stage); + + fs->stage.draw = draw; + fs->stage.next = NULL; + fs->stage.point = feedback_point; + fs->stage.line = feedback_line; + fs->stage.tri = feedback_tri; + fs->stage.flush = feedback_flush; + fs->stage.reset_stipple_counter = feedback_reset_stipple_counter; + fs->stage.destroy = feedback_destroy; + fs->ctx = ctx; + + return &fs->stage; +} + + + +/********************************************************************** + * GL Selection functions + **********************************************************************/ + +static void +select_tri( struct draw_stage *stage, struct prim_header *prim ) +{ + struct feedback_stage *fs = feedback_stage(stage); + _mesa_update_hitflag( fs->ctx, prim->v[0]->data[0][2] ); + _mesa_update_hitflag( fs->ctx, prim->v[1]->data[0][2] ); + _mesa_update_hitflag( fs->ctx, prim->v[2]->data[0][2] ); +} + +static void +select_line( struct draw_stage *stage, struct prim_header *prim ) +{ + struct feedback_stage *fs = feedback_stage(stage); + _mesa_update_hitflag( fs->ctx, prim->v[0]->data[0][2] ); + _mesa_update_hitflag( fs->ctx, prim->v[1]->data[0][2] ); +} + + +static void +select_point( struct draw_stage *stage, struct prim_header *prim ) +{ + struct feedback_stage *fs = feedback_stage(stage); + _mesa_update_hitflag( fs->ctx, prim->v[0]->data[0][2] ); +} + + +static void +select_flush( struct draw_stage *stage, unsigned flags ) +{ + /* no-op */ +} + + +static void +select_reset_stipple_counter( struct draw_stage *stage ) +{ + /* no-op */ +} + +static void +select_destroy( struct draw_stage *stage ) +{ + /* no-op */ +} + + +/** + * Create GL selection mode drawing stage. + */ +static struct draw_stage * +draw_glselect_stage(GLcontext *ctx, struct draw_context *draw) +{ + struct feedback_stage *fs = CALLOC_STRUCT(feedback_stage); + + fs->stage.draw = draw; + fs->stage.next = NULL; + fs->stage.point = select_point; + fs->stage.line = select_line; + fs->stage.tri = select_tri; + fs->stage.flush = select_flush; + fs->stage.reset_stipple_counter = select_reset_stipple_counter; + fs->stage.destroy = select_destroy; + fs->ctx = ctx; + + return &fs->stage; +} + + +static void +st_RenderMode(GLcontext *ctx, GLenum newMode ) +{ + struct st_context *st = ctx->st; + struct draw_context *draw = st->draw; + + if (newMode == GL_RENDER) { + /* restore normal VBO draw function */ + vbo_set_draw_func(ctx, st_draw_vbo); + } + else if (newMode == GL_SELECT) { + if (!st->selection_stage) + st->selection_stage = draw_glselect_stage(ctx, draw); + draw_set_rasterize_stage(draw, st->selection_stage); + /* Plug in new vbo draw function */ + vbo_set_draw_func(ctx, st_feedback_draw_vbo); + } + else { + if (!st->feedback_stage) + st->feedback_stage = draw_glfeedback_stage(ctx, draw); + draw_set_rasterize_stage(draw, st->feedback_stage); + /* Plug in new vbo draw function */ + vbo_set_draw_func(ctx, st_feedback_draw_vbo); + /* need to generate/use a vertex program that emits pos/color/tex */ + st->dirty.st |= ST_NEW_VERTEX_PROGRAM; + } +} + + + +void st_init_feedback_functions(struct dd_function_table *functions) +{ + functions->RenderMode = st_RenderMode; +} diff --git a/src/mesa/state_tracker/st_cb_feedback.h b/src/mesa/state_tracker/st_cb_feedback.h new file mode 100644 index 0000000000..2559ba3817 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_feedback.h @@ -0,0 +1,37 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_CB_FEEDBACK_H +#define ST_CB_FEEDBACK_H + + +extern void +st_init_feedback_functions(struct dd_function_table *functions); + + +#endif /* ST_CB_FEEDBACK_H */ diff --git a/src/mesa/state_tracker/st_cb_flush.c b/src/mesa/state_tracker/st_cb_flush.c new file mode 100644 index 0000000000..d8f9537d2d --- /dev/null +++ b/src/mesa/state_tracker/st_cb_flush.c @@ -0,0 +1,138 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + */ + +#include "main/glheader.h" +#include "main/macros.h" +#include "main/context.h" +#include "st_context.h" +#include "st_cb_bitmap.h" +#include "st_cb_flush.h" +#include "st_cb_fbo.h" +#include "st_public.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_winsys.h" + + +static INLINE GLboolean +is_front_buffer_dirty(struct st_context *st) +{ + return st->frontbuffer_status == FRONT_STATUS_DIRTY; +} + + +/** + * Tell the winsys to display the front color buffer on-screen. + */ +static void +display_front_buffer(struct st_context *st) +{ + GLframebuffer *fb = st->ctx->DrawBuffer; + struct st_renderbuffer *strb + = st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer); + struct pipe_surface *front_surf = strb->surface; + + /* Hook for copying "fake" frontbuffer if necessary: + */ + st->pipe->winsys->flush_frontbuffer( st->pipe->winsys, front_surf, + st->pipe->priv ); + + /* + st->frontbuffer_status = FRONT_STATUS_UNDEFINED; + */ +} + + +void st_flush( struct st_context *st, uint pipeFlushFlags, + struct pipe_fence_handle **fence ) +{ + FLUSH_VERTICES(st->ctx, 0); + + st_flush_bitmap_cache(st); + + st->pipe->flush( st->pipe, pipeFlushFlags, fence ); +} + + +/** + * Flush, and wait for completion. + */ +void st_finish( struct st_context *st ) +{ + struct pipe_fence_handle *fence = NULL; + + st_flush(st, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence); + + st->pipe->winsys->fence_finish(st->pipe->winsys, fence, 0); + st->pipe->winsys->fence_reference(st->pipe->winsys, &fence, NULL); +} + + + +/** + * Called via ctx->Driver.Flush() + */ +static void st_glFlush(GLcontext *ctx) +{ + struct st_context *st = ctx->st; + + if (is_front_buffer_dirty(st)) { + st_finish(st); + display_front_buffer(st); + } + else { + st_flush(st, PIPE_FLUSH_RENDER_CACHE, NULL); + } +} + + +/** + * Called via ctx->Driver.Finish() + */ +static void st_glFinish(GLcontext *ctx) +{ + struct st_context *st = ctx->st; + + st_finish(st); + + if (is_front_buffer_dirty(st)) { + display_front_buffer(st); + } +} + + +void st_init_flush_functions(struct dd_function_table *functions) +{ + functions->Flush = st_glFlush; + functions->Finish = st_glFinish; +} diff --git a/src/mesa/state_tracker/st_cb_flush.h b/src/mesa/state_tracker/st_cb_flush.h new file mode 100644 index 0000000000..c26f779225 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_flush.h @@ -0,0 +1,38 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_CB_FLUSH_H +#define ST_CB_FLUSH_H + + +extern void +st_init_flush_functions(struct dd_function_table *functions); + + +#endif /* ST_CB_FLUSH_H */ + diff --git a/src/mesa/state_tracker/st_cb_get.c b/src/mesa/state_tracker/st_cb_get.c new file mode 100644 index 0000000000..e7d7f03bc9 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_get.c @@ -0,0 +1,97 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +/** + * glGet functions + * + * \author Brian Paul + */ + +#include "main/imports.h" +#include "main/context.h" + +#include "pipe/p_defines.h" + +#include "st_cb_fbo.h" +#include "st_cb_get.h" + + + +/** + * Examine the current color read buffer format to determine + * which GL pixel format/type combo is the best match. + */ +static void +get_preferred_read_format_type(GLcontext *ctx, GLint *format, GLint *type) +{ + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct st_renderbuffer *strb = st_renderbuffer(fb->_ColorReadBuffer); + + /* defaults */ + *format = ctx->Const.ColorReadFormat; + *type = ctx->Const.ColorReadType; + + if (strb) { + /* XXX could add more cases here... */ + if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM) { + *format = GL_BGRA; + if (_mesa_little_endian()) + *type = GL_UNSIGNED_INT_8_8_8_8_REV; + else + *type = GL_UNSIGNED_INT_8_8_8_8; + } + } +} + + +/** + * We only intercept the OES preferred ReadPixels format/type. + * Everything else goes to the default _mesa_GetIntegerv. + */ +static GLboolean +st_GetIntegerv(GLcontext *ctx, GLenum pname, GLint *params) +{ + GLint dummy; + + switch (pname) { + case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES: + get_preferred_read_format_type(ctx, &dummy, params); + return GL_TRUE; + case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES: + get_preferred_read_format_type(ctx, params, &dummy); + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +void st_init_get_functions(struct dd_function_table *functions) +{ + functions->GetIntegerv = st_GetIntegerv; +} diff --git a/src/mesa/state_tracker/st_cb_get.h b/src/mesa/state_tracker/st_cb_get.h new file mode 100644 index 0000000000..8e9f3e9306 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_get.h @@ -0,0 +1,37 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_CB_GET_H +#define ST_CB_GET_H + + +extern void +st_init_get_functions(struct dd_function_table *functions); + + +#endif diff --git a/src/mesa/state_tracker/st_cb_program.c b/src/mesa/state_tracker/st_cb_program.c new file mode 100644 index 0000000000..ea0fa20012 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_program.c @@ -0,0 +1,266 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "main/glheader.h" +#include "main/macros.h" +#include "main/enums.h" +#include "shader/prog_instruction.h" +#include "shader/prog_parameter.h" +#include "shader/program.h" +#include "shader/programopt.h" +#include "shader/shader_api.h" + +#include "cso_cache/cso_context.h" +#include "draw/draw_context.h" + +#include "st_context.h" +#include "st_program.h" +#include "st_atom_shader.h" +#include "st_cb_program.h" + + +static GLuint SerialNo = 1; + + +/** + * Called via ctx->Driver.BindProgram() to bind an ARB vertex or + * fragment program. + */ +static void st_bind_program( GLcontext *ctx, + GLenum target, + struct gl_program *prog ) +{ + struct st_context *st = st_context(ctx); + + switch (target) { + case GL_VERTEX_PROGRAM_ARB: + st->dirty.st |= ST_NEW_VERTEX_PROGRAM; + break; + case GL_FRAGMENT_PROGRAM_ARB: + st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM; + break; + } +} + + +/** + * Called via ctx->Driver.UseProgram() to bind a linked GLSL program + * (vertex shader + fragment shader). + */ +static void st_use_program( GLcontext *ctx, + GLuint program ) +{ + struct st_context *st = st_context(ctx); + + st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM; + st->dirty.st |= ST_NEW_VERTEX_PROGRAM; + + _mesa_use_program(ctx, program); +} + + + +/** + * Called via ctx->Driver.NewProgram() to allocate a new vertex or + * fragment program. + */ +static struct gl_program *st_new_program( GLcontext *ctx, + GLenum target, + GLuint id ) +{ + switch (target) { + case GL_VERTEX_PROGRAM_ARB: { + struct st_vertex_program *prog = CALLOC_STRUCT(st_vertex_program); + + prog->serialNo = SerialNo++; + + return _mesa_init_vertex_program( ctx, + &prog->Base, + target, + id ); + } + + case GL_FRAGMENT_PROGRAM_ARB: + case GL_FRAGMENT_PROGRAM_NV: { + struct st_fragment_program *prog = CALLOC_STRUCT(st_fragment_program); + + prog->serialNo = SerialNo++; + + return _mesa_init_fragment_program( ctx, + &prog->Base, + target, + id ); + } + + default: + assert(0); + return NULL; + } +} + + +void +st_delete_program(GLcontext *ctx, struct gl_program *prog) +{ + struct st_context *st = st_context(ctx); + + switch( prog->Target ) { + case GL_VERTEX_PROGRAM_ARB: + { + struct st_vertex_program *stvp = (struct st_vertex_program *) prog; + + if (stvp->driver_shader) { + cso_delete_vertex_shader(st->cso_context, stvp->driver_shader); + stvp->driver_shader = NULL; + } + + if (stvp->draw_shader) { +#if FEATURE_feedback || FEATURE_drawpix + /* this would only have been allocated for the RasterPos path */ + draw_delete_vertex_shader(st->draw, stvp->draw_shader); + stvp->draw_shader = NULL; +#endif + } + + if (stvp->state.tokens) { + FREE((void *) stvp->state.tokens); + stvp->state.tokens = NULL; + } + } + break; + case GL_FRAGMENT_PROGRAM_ARB: + { + struct st_fragment_program *stfp = (struct st_fragment_program *) prog; + + if (stfp->driver_shader) { + cso_delete_fragment_shader(st->cso_context, stfp->driver_shader); + stfp->driver_shader = NULL; + } + + if (stfp->state.tokens) { + FREE((void *) stfp->state.tokens); + stfp->state.tokens = NULL; + } + + if (stfp->bitmap_program) { + struct gl_program *prg = &stfp->bitmap_program->Base.Base; + _mesa_reference_program(ctx, &prg, NULL); + stfp->bitmap_program = NULL; + } + + st_free_translated_vertex_programs(st, stfp->vertex_programs); + } + break; + default: + assert(0); /* problem */ + } + + /* delete base class */ + _mesa_delete_program( ctx, prog ); +} + + +static GLboolean st_is_program_native( GLcontext *ctx, + GLenum target, + struct gl_program *prog ) +{ + return GL_TRUE; +} + + +static void st_program_string_notify( GLcontext *ctx, + GLenum target, + struct gl_program *prog ) +{ + struct st_context *st = st_context(ctx); + + if (target == GL_FRAGMENT_PROGRAM_ARB) { + struct st_fragment_program *stfp = (struct st_fragment_program *) prog; + + stfp->serialNo++; + + if (stfp->driver_shader) { + cso_delete_fragment_shader(st->cso_context, stfp->driver_shader); + stfp->driver_shader = NULL; + } + + if (stfp->state.tokens) { + FREE((void *) stfp->state.tokens); + stfp->state.tokens = NULL; + } + + stfp->param_state = stfp->Base.Base.Parameters->StateFlags; + + if (st->fp == stfp) + st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM; + } + else if (target == GL_VERTEX_PROGRAM_ARB) { + struct st_vertex_program *stvp = (struct st_vertex_program *) prog; + + stvp->serialNo++; + + if (stvp->driver_shader) { + cso_delete_vertex_shader(st->cso_context, stvp->driver_shader); + stvp->driver_shader = NULL; + } + + if (stvp->draw_shader) { +#if FEATURE_feedback || FEATURE_drawpix + /* this would only have been allocated for the RasterPos path */ + draw_delete_vertex_shader(st->draw, stvp->draw_shader); + stvp->draw_shader = NULL; +#endif + } + + if (stvp->state.tokens) { + FREE((void *) stvp->state.tokens); + stvp->state.tokens = NULL; + } + + stvp->param_state = stvp->Base.Base.Parameters->StateFlags; + + if (st->vp == stvp) + st->dirty.st |= ST_NEW_VERTEX_PROGRAM; + } +} + + + +void st_init_program_functions(struct dd_function_table *functions) +{ + functions->BindProgram = st_bind_program; + functions->UseProgram = st_use_program; + functions->NewProgram = st_new_program; + functions->DeleteProgram = st_delete_program; + functions->IsProgramNative = st_is_program_native; + functions->ProgramStringNotify = st_program_string_notify; +} diff --git a/src/mesa/state_tracker/st_cb_program.h b/src/mesa/state_tracker/st_cb_program.h new file mode 100644 index 0000000000..0de96f2fd2 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_program.h @@ -0,0 +1,39 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef ST_CB_PROGRAM_H +#define ST_CB_PROGRAM_H + + +extern void +st_init_program_functions(struct dd_function_table *functions); + +extern void +st_delete_program(GLcontext *ctx, struct gl_program *prog); + + +#endif diff --git a/src/mesa/state_tracker/st_cb_queryobj.c b/src/mesa/state_tracker/st_cb_queryobj.c new file mode 100644 index 0000000000..21c2c7dd9f --- /dev/null +++ b/src/mesa/state_tracker/st_cb_queryobj.c @@ -0,0 +1,171 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +/** + * glBegin/EndQuery interface to pipe + * + * \author Brian Paul + */ + + +#include "main/imports.h" +#include "main/context.h" +#include "main/image.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "st_context.h" +#include "st_cb_queryobj.h" +#include "st_public.h" + + +struct st_query_object +{ + struct gl_query_object base; + struct pipe_query *pq; +}; + + +/** + * Cast wrapper + */ +static struct st_query_object * +st_query_object(struct gl_query_object *q) +{ + return (struct st_query_object *) q; +} + + +static struct gl_query_object * +st_NewQueryObject(GLcontext *ctx, GLuint id) +{ + struct st_query_object *stq = CALLOC_STRUCT(st_query_object); + if (stq) { + stq->base.Id = id; + stq->base.Ready = GL_TRUE; + stq->pq = NULL; + return &stq->base; + } + return NULL; +} + + + +static void +st_DeleteQuery(GLcontext *ctx, struct gl_query_object *q) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct st_query_object *stq = st_query_object(q); + + if (stq->pq) { + pipe->destroy_query(pipe, stq->pq); + stq->pq = NULL; + } + + FREE(stq); +} + + +static void +st_BeginQuery(GLcontext *ctx, struct gl_query_object *q) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct st_query_object *stq = st_query_object(q); + + switch (q->Target) { + case GL_SAMPLES_PASSED_ARB: + if (!stq->pq) + stq->pq = pipe->create_query( pipe, PIPE_QUERY_OCCLUSION_COUNTER ); + break; + default: + assert(0); + return; + } + + pipe->begin_query(pipe, stq->pq); +} + + +static void +st_EndQuery(GLcontext *ctx, struct gl_query_object *q) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct st_query_object *stq = st_query_object(q); + + pipe->end_query(pipe, stq->pq); +} + + +static void +st_WaitQuery(GLcontext *ctx, struct gl_query_object *q) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct st_query_object *stq = st_query_object(q); + + /* this function should only be called if we don't have a ready result */ + assert(!stq->base.Ready); + + while (!stq->base.Ready && + !pipe->get_query_result(pipe, + stq->pq, + TRUE, + &q->Result)) + { + /* nothing */ + } + + q->Ready = GL_TRUE; +} + + +static void +st_CheckQuery(GLcontext *ctx, struct gl_query_object *q) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct st_query_object *stq = st_query_object(q); + + if (!q->Ready) { + q->Ready = pipe->get_query_result(pipe, + stq->pq, + FALSE, + &q->Result); + } +} + + + + +void st_init_query_functions(struct dd_function_table *functions) +{ + functions->NewQueryObject = st_NewQueryObject; + functions->DeleteQuery = st_DeleteQuery; + functions->BeginQuery = st_BeginQuery; + functions->EndQuery = st_EndQuery; + functions->WaitQuery = st_WaitQuery; + functions->CheckQuery = st_CheckQuery; +} diff --git a/src/mesa/state_tracker/st_cb_queryobj.h b/src/mesa/state_tracker/st_cb_queryobj.h new file mode 100644 index 0000000000..9220a212b6 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_queryobj.h @@ -0,0 +1,36 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef ST_CB_QUERYOBJ_H +#define ST_CB_QUERYOBJ_H + + +extern void +st_init_query_functions(struct dd_function_table *functions); + + +#endif diff --git a/src/mesa/state_tracker/st_cb_rasterpos.c b/src/mesa/state_tracker/st_cb_rasterpos.c new file mode 100644 index 0000000000..3b30c2a61b --- /dev/null +++ b/src/mesa/state_tracker/st_cb_rasterpos.c @@ -0,0 +1,258 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * glRasterPos implementation. Basically render a GL_POINT with our + * private draw module. Plug in a special "rasterpos" stage at the end + * of the 'draw' pipeline to capture the results and update the current + * raster pos attributes. + * + * Authors: + * Brian Paul + */ + + +#include "main/imports.h" +#include "main/macros.h" +#include "main/feedback.h" + +#include "st_context.h" +#include "st_atom.h" +#include "st_draw.h" +#include "st_cb_rasterpos.h" +#include "st_draw.h" +#include "draw/draw_context.h" +#include "draw/draw_pipe.h" +#include "shader/prog_instruction.h" +#include "vbo/vbo.h" + + + +/** + * Our special drawing pipeline stage (replaces rasterization). + */ +struct rastpos_stage +{ + struct draw_stage stage; /**< Base class */ + GLcontext *ctx; /**< Rendering context */ + + /* vertex attrib info we can setup once and re-use */ + struct gl_client_array array[VERT_ATTRIB_MAX]; + const struct gl_client_array *arrays[VERT_ATTRIB_MAX]; + struct _mesa_prim prim; +}; + + +static INLINE struct rastpos_stage * +rastpos_stage( struct draw_stage *stage ) +{ + return (struct rastpos_stage *) stage; +} + +static void +rastpos_flush( struct draw_stage *stage, unsigned flags ) +{ + /* no-op */ +} + +static void +rastpos_reset_stipple_counter( struct draw_stage *stage ) +{ + /* no-op */ +} + +static void +rastpos_tri( struct draw_stage *stage, struct prim_header *prim ) +{ + /* should never get here */ + assert(0); +} + +static void +rastpos_line( struct draw_stage *stage, struct prim_header *prim ) +{ + /* should never get here */ + assert(0); +} + +static void +rastpos_destroy(struct draw_stage *stage) +{ + free(stage); +} + + +/** + * Update a raster pos attribute from the vertex result if it's present, + * else copy the current attrib. + */ +static void +update_attrib(GLcontext *ctx, const GLuint *outputMapping, + const struct vertex_header *vert, + GLfloat *dest, + GLuint result, GLuint defaultAttrib) +{ + const GLfloat *src; + const GLuint k = outputMapping[result]; + if (k != ~0U) + src = vert->data[k]; + else + src = ctx->Current.Attrib[defaultAttrib]; + COPY_4V(dest, src); +} + + +/** + * Normally, this function would render a GL_POINT. + */ +static void +rastpos_point(struct draw_stage *stage, struct prim_header *prim) +{ + struct rastpos_stage *rs = rastpos_stage(stage); + GLcontext *ctx = rs->ctx; + struct st_context *st = ctx->st; + const GLfloat height = (GLfloat) ctx->DrawBuffer->Height; + const GLuint *outputMapping = st->vertex_result_to_slot; + const GLfloat *pos; + GLuint i; + + /* if we get here, we didn't get clipped */ + ctx->Current.RasterPosValid = GL_TRUE; + + /* update raster pos */ + pos = prim->v[0]->data[0]; + ctx->Current.RasterPos[0] = pos[0]; + ctx->Current.RasterPos[1] = height - pos[1]; /* invert Y */ + ctx->Current.RasterPos[2] = pos[2]; + ctx->Current.RasterPos[3] = pos[3]; + + /* update other raster attribs */ + update_attrib(ctx, outputMapping, prim->v[0], + ctx->Current.RasterColor, + VERT_RESULT_COL0, VERT_ATTRIB_COLOR0); + + update_attrib(ctx, outputMapping, prim->v[0], + ctx->Current.RasterSecondaryColor, + VERT_RESULT_COL1, VERT_ATTRIB_COLOR1); + + for (i = 0; i < MAX_TEXTURE_UNITS; i++) { + update_attrib(ctx, outputMapping, prim->v[0], + ctx->Current.RasterTexCoords[i], + VERT_RESULT_TEX0 + i, VERT_ATTRIB_TEX0 + i); + } + + if (ctx->RenderMode == GL_SELECT) { + _mesa_update_hitflag( ctx, ctx->Current.RasterPos[2] ); + } +} + + +/** + * Create rasterpos "drawing" stage. + */ +static struct rastpos_stage * +new_draw_rastpos_stage(GLcontext *ctx, struct draw_context *draw) +{ + struct rastpos_stage *rs = CALLOC_STRUCT(rastpos_stage); + GLuint i; + + rs->stage.draw = draw; + rs->stage.next = NULL; + rs->stage.point = rastpos_point; + rs->stage.line = rastpos_line; + rs->stage.tri = rastpos_tri; + rs->stage.flush = rastpos_flush; + rs->stage.destroy = rastpos_destroy; + rs->stage.reset_stipple_counter = rastpos_reset_stipple_counter; + rs->stage.destroy = rastpos_destroy; + rs->ctx = ctx; + + for (i = 0; i < VERT_ATTRIB_MAX; i++) { + rs->array[i].Size = 4; + rs->array[i].Type = GL_FLOAT; + rs->array[i].Stride = 0; + rs->array[i].StrideB = 0; + rs->array[i].Ptr = (GLubyte *) ctx->Current.Attrib[i]; + rs->array[i].Enabled = GL_TRUE; + rs->array[i].Normalized = GL_TRUE; + rs->array[i].BufferObj = NULL; + rs->arrays[i] = &rs->array[i]; + } + + rs->prim.mode = GL_POINTS; + rs->prim.indexed = 0; + rs->prim.begin = 1; + rs->prim.end = 1; + rs->prim.weak = 0; + rs->prim.start = 0; + rs->prim.count = 1; + + return rs; +} + + +static void +st_RasterPos(GLcontext *ctx, const GLfloat v[4]) +{ + struct st_context *st = ctx->st; + struct draw_context *draw = st->draw; + struct rastpos_stage *rs; + + if (st->rastpos_stage) { + /* get rastpos stage info */ + rs = rastpos_stage(st->rastpos_stage); + } + else { + /* create rastpos draw stage */ + rs = new_draw_rastpos_stage(ctx, draw); + st->rastpos_stage = &rs->stage; + } + + /* plug our rastpos stage into the draw module */ + draw_set_rasterize_stage(st->draw, st->rastpos_stage); + + /* make sure everything's up to date */ + st_validate_state(ctx->st); + + /* This will get set only if rastpos_point(), above, gets called */ + ctx->Current.RasterPosValid = GL_FALSE; + + /* All vertex attribs but position were previously initialized above. + * Just plug in position pointer now. + */ + rs->array[0].Ptr = (GLubyte *) v; + + /* draw the point */ + st_feedback_draw_vbo(ctx, rs->arrays, &rs->prim, 1, NULL, 0, 1); +} + + + +void st_init_rasterpos_functions(struct dd_function_table *functions) +{ + functions->RasterPos = st_RasterPos; +} diff --git a/src/mesa/state_tracker/st_cb_rasterpos.h b/src/mesa/state_tracker/st_cb_rasterpos.h new file mode 100644 index 0000000000..2b992e1405 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_rasterpos.h @@ -0,0 +1,33 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef ST_CB_RASTERPOS_H +#define ST_CB_RASTERPOS_H + +extern void st_init_rasterpos_functions(struct dd_function_table *functions); + +#endif diff --git a/src/mesa/state_tracker/st_cb_readpixels.c b/src/mesa/state_tracker/st_cb_readpixels.c new file mode 100644 index 0000000000..c801532788 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_readpixels.c @@ -0,0 +1,466 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +/** + * glReadPixels interface to pipe + * + * \author Brian Paul + */ + + +#include "main/imports.h" +#include "main/bufferobj.h" +#include "main/context.h" +#include "main/image.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" +#include "util/u_tile.h" +#include "st_context.h" +#include "st_cb_bitmap.h" +#include "st_cb_readpixels.h" +#include "st_cb_fbo.h" +#include "st_format.h" +#include "st_public.h" + + +/** + * Special case for reading stencil buffer. + * For color/depth we use get_tile(). For stencil, map the stencil buffer. + */ +void +st_read_stencil_pixels(GLcontext *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, GLenum type, + const struct gl_pixelstore_attrib *packing, + GLvoid *pixels) +{ + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct pipe_screen *screen = ctx->st->pipe->screen; + struct st_renderbuffer *strb = st_renderbuffer(fb->_StencilBuffer); + struct pipe_surface *ps; + ubyte *stmap; + GLint j; + + /* Create a CPU-READ surface/view into the renderbuffer's texture */ + ps = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_READ); + + /* map the stencil buffer */ + stmap = screen->surface_map(screen, ps, PIPE_BUFFER_USAGE_CPU_READ); + + /* width should never be > MAX_WIDTH since we did clipping earlier */ + ASSERT(width <= MAX_WIDTH); + + /* process image row by row */ + for (j = 0; j < height; j++, y++) { + GLvoid *dest; + GLstencil values[MAX_WIDTH]; + GLint srcY; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + srcY = ctx->DrawBuffer->Height - y - 1; + } + else { + srcY = y; + } + + /* get stencil values */ + switch (ps->format) { + case PIPE_FORMAT_S8_UNORM: + { + const ubyte *src = stmap + srcY * ps->stride + x; + memcpy(values, src, width); + } + break; + case PIPE_FORMAT_S8Z24_UNORM: + { + const uint *src = (uint *) (stmap + srcY * ps->stride + x*4); + GLint k; + for (k = 0; k < width; k++) { + values[k] = src[k] >> 24; + } + } + break; + case PIPE_FORMAT_Z24S8_UNORM: + { + const uint *src = (uint *) (stmap + srcY * ps->stride + x*4); + GLint k; + for (k = 0; k < width; k++) { + values[k] = src[k] & 0xff; + } + } + break; + default: + assert(0); + } + + /* store */ + dest = _mesa_image_address2d(packing, pixels, width, height, + GL_STENCIL_INDEX, type, j, 0); + + _mesa_pack_stencil_span(ctx, width, type, dest, values, packing); + } + + + /* unmap the stencil buffer */ + screen->surface_unmap(screen, ps); + pipe_surface_reference(&ps, NULL); +} + + +/** + * Return renderbuffer to use for reading color pixels for glRead/CopyPixel + * commands. + * Special care is needed for the front buffer. + */ +struct st_renderbuffer * +st_get_color_read_renderbuffer(GLcontext *ctx) +{ + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct st_renderbuffer *strb = + st_renderbuffer(fb->_ColorReadBuffer); + struct st_renderbuffer *front = + st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer); + + if (strb == front + && ctx->st->frontbuffer_status == FRONT_STATUS_COPY_OF_BACK) { + /* reading from front color buffer, which is a logical copy of the + * back color buffer. + */ + struct st_renderbuffer *back = + st_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer); + strb = back; + } + + return strb; +} + + +/** + * Try to do glReadPixels in a fast manner for common cases. + * \return GL_TRUE for success, GL_FALSE for failure + */ +static GLboolean +st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *dest) +{ + enum combination { + A8R8G8B8_UNORM_TO_RGBA_UBYTE, + A8R8G8B8_UNORM_TO_RGB_UBYTE, + A8R8G8B8_UNORM_TO_BGRA_UINT + } combo; + + if (ctx->_ImageTransferState) + return GL_FALSE; + + if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM && + format == GL_RGBA && type == GL_UNSIGNED_BYTE) { + combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE; + } + else if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM && + format == GL_RGB && type == GL_UNSIGNED_BYTE) { + combo = A8R8G8B8_UNORM_TO_RGB_UBYTE; + } + else if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM && + format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) { + combo = A8R8G8B8_UNORM_TO_BGRA_UINT; + } + else { + return GL_FALSE; + } + + /*printf("st_fast_readpixels combo %d\n", (GLint) combo);*/ + + { + struct pipe_context *pipe = ctx->st->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_surface *surf; + const GLubyte *map; + GLubyte *dst; + GLint row, col, dy, dstStride; + + surf = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_READ); + if (!surf) { + return GL_FALSE; + } + + map = screen->surface_map(screen, surf, PIPE_BUFFER_USAGE_CPU_READ); + if (!map) { + pipe_surface_reference(&surf, NULL); + return GL_FALSE; + } + + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + y = surf->height - y - 1; + dy = -1; + } + else { + dy = 1; + } + + dst = _mesa_image_address2d(pack, dest, width, height, + format, type, 0, 0); + dstStride = _mesa_image_row_stride(pack, width, format, type); + + switch (combo) { + case A8R8G8B8_UNORM_TO_RGBA_UBYTE: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * surf->stride + x * 4; + for (col = 0; col < width; col++) { + GLuint pixel = ((GLuint *) src)[col]; + dst[col*4+0] = (pixel >> 16) & 0xff; + dst[col*4+1] = (pixel >> 8) & 0xff; + dst[col*4+2] = (pixel >> 0) & 0xff; + dst[col*4+3] = (pixel >> 24) & 0xff; + } + dst += dstStride; + y += dy; + } + break; + case A8R8G8B8_UNORM_TO_RGB_UBYTE: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * surf->stride + x * 4; + for (col = 0; col < width; col++) { + GLuint pixel = ((GLuint *) src)[col]; + dst[col*3+0] = (pixel >> 16) & 0xff; + dst[col*3+1] = (pixel >> 8) & 0xff; + dst[col*3+2] = (pixel >> 0) & 0xff; + } + dst += dstStride; + y += dy; + } + break; + case A8R8G8B8_UNORM_TO_BGRA_UINT: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * surf->stride + x * 4; + memcpy(dst, src, 4 * width); + dst += dstStride; + y += dy; + } + break; + default: + ; /* nothing */ + } + + screen->surface_unmap(screen, surf); + pipe_surface_reference(&surf, NULL); + } + + return GL_TRUE; +} + + +/** + * Do glReadPixels by getting rows from the framebuffer surface with + * get_tile(). Convert to requested format/type with Mesa image routines. + * Image transfer ops are done in software too. + */ +static void +st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *dest) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct pipe_screen *screen = pipe->screen; + GLfloat temp[MAX_WIDTH][4]; + const GLbitfield transferOps = ctx->_ImageTransferState; + GLsizei i, j; + GLint yStep, dfStride; + GLfloat *df; + struct st_renderbuffer *strb; + struct gl_pixelstore_attrib clippedPacking = *pack; + struct pipe_surface *surf; + + assert(ctx->ReadBuffer->Width > 0); + + /* XXX convolution not done yet */ + assert((transferOps & IMAGE_CONVOLUTION_BIT) == 0); + + /* Do all needed clipping here, so that we can forget about it later */ + if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) { + /* The ReadPixels surface is totally outside the window bounds */ + return; + } + + dest = _mesa_map_readpix_pbo(ctx, &clippedPacking, dest); + if (!dest) + return; + + st_flush_bitmap_cache(ctx->st); + + /* make sure rendering has completed */ + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + + if (format == GL_STENCIL_INDEX) { + st_read_stencil_pixels(ctx, x, y, width, height, type, pack, dest); + return; + } + else if (format == GL_DEPTH_COMPONENT) { + strb = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); + } + else { + /* Read color buffer */ + strb = st_get_color_read_renderbuffer(ctx); + } + + if (!strb) + return; + + /* try a fast-path readpixels before anything else */ + if (st_fast_readpixels(ctx, strb, x, y, width, height, + format, type, pack, dest)) { + /* success! */ + _mesa_unmap_readpix_pbo(ctx, &clippedPacking); + return; + } + + if (format == GL_RGBA && type == GL_FLOAT) { + /* write tile(row) directly into user's buffer */ + df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width, + height, format, type, 0, 0); + dfStride = width * 4; + } + else { + /* write tile(row) into temp row buffer */ + df = (GLfloat *) temp; + dfStride = 0; + } + + /* determine bottom-to-top vs. top-to-bottom order */ + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + y = strb->Base.Height - 1 - y; + yStep = -1; + } + else { + yStep = 1; + } + + /* Create a CPU-READ surface/view into the renderbuffer's texture */ + surf = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_READ); + + /* + * Copy pixels from pipe_surface to user memory + */ + { + /* dest of first pixel in client memory */ + GLubyte *dst = _mesa_image_address2d(&clippedPacking, dest, width, + height, format, type, 0, 0); + /* dest row stride */ + const GLint dstStride = _mesa_image_row_stride(&clippedPacking, width, + format, type); + + if (surf->format == PIPE_FORMAT_S8Z24_UNORM || + surf->format == PIPE_FORMAT_X8Z24_UNORM) { + if (format == GL_DEPTH_COMPONENT) { + for (i = 0; i < height; i++) { + GLuint ztemp[MAX_WIDTH]; + GLfloat zfloat[MAX_WIDTH]; + const double scale = 1.0 / ((1 << 24) - 1); + pipe_get_tile_raw(surf, x, y, width, 1, ztemp, 0); + y += yStep; + for (j = 0; j < width; j++) { + zfloat[j] = (float) (scale * (ztemp[j] & 0xffffff)); + } + _mesa_pack_depth_span(ctx, width, dst, type, + zfloat, &clippedPacking); + dst += dstStride; + } + } + else { + /* untested, but simple: */ + assert(format == GL_DEPTH_STENCIL_EXT); + for (i = 0; i < height; i++) { + pipe_get_tile_raw(surf, x, y, width, 1, dst, 0); + y += yStep; + dst += dstStride; + } + } + } + else if (surf->format == PIPE_FORMAT_Z16_UNORM) { + for (i = 0; i < height; i++) { + GLushort ztemp[MAX_WIDTH]; + GLfloat zfloat[MAX_WIDTH]; + const double scale = 1.0 / 0xffff; + pipe_get_tile_raw(surf, x, y, width, 1, ztemp, 0); + y += yStep; + for (j = 0; j < width; j++) { + zfloat[j] = (float) (scale * ztemp[j]); + } + _mesa_pack_depth_span(ctx, width, dst, type, + zfloat, &clippedPacking); + dst += dstStride; + } + } + else if (surf->format == PIPE_FORMAT_Z32_UNORM) { + for (i = 0; i < height; i++) { + GLuint ztemp[MAX_WIDTH]; + GLfloat zfloat[MAX_WIDTH]; + const double scale = 1.0 / 0xffffffff; + pipe_get_tile_raw(surf, x, y, width, 1, ztemp, 0); + y += yStep; + for (j = 0; j < width; j++) { + zfloat[j] = (float) (scale * ztemp[j]); + } + _mesa_pack_depth_span(ctx, width, dst, type, + zfloat, &clippedPacking); + dst += dstStride; + } + } + else { + /* RGBA format */ + /* Do a row at a time to flip image data vertically */ + for (i = 0; i < height; i++) { + pipe_get_tile_rgba(surf, x, y, width, 1, df); + y += yStep; + df += dfStride; + if (!dfStride) { + _mesa_pack_rgba_span_float(ctx, width, temp, format, type, dst, + &clippedPacking, transferOps); + dst += dstStride; + } + } + } + } + + pipe_surface_reference(&surf, NULL); + + _mesa_unmap_readpix_pbo(ctx, &clippedPacking); +} + + +void st_init_readpixels_functions(struct dd_function_table *functions) +{ + functions->ReadPixels = st_readpixels; +} diff --git a/src/mesa/state_tracker/st_cb_readpixels.h b/src/mesa/state_tracker/st_cb_readpixels.h new file mode 100644 index 0000000000..9e151be51f --- /dev/null +++ b/src/mesa/state_tracker/st_cb_readpixels.h @@ -0,0 +1,45 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_CB_READPIXELS_H +#define ST_CB_READPIXELS_H + +extern struct st_renderbuffer * +st_get_color_read_renderbuffer(GLcontext *ctx); + +extern void +st_read_stencil_pixels(GLcontext *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, GLenum type, + const struct gl_pixelstore_attrib *packing, + GLvoid *pixels); + +extern void +st_init_readpixels_functions(struct dd_function_table *functions); + + +#endif /* ST_CB_READPIXELS_H */ diff --git a/src/mesa/state_tracker/st_cb_strings.c b/src/mesa/state_tracker/st_cb_strings.c new file mode 100644 index 0000000000..09545aa8fb --- /dev/null +++ b/src/mesa/state_tracker/st_cb_strings.c @@ -0,0 +1,86 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + */ + +#include "main/glheader.h" +#include "main/macros.h" +#include "main/version.h" +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "pipe/p_winsys.h" +#include "st_context.h" +#include "st_cb_strings.h" + +#define ST_VERSION_STRING "0.2" + +static const GLubyte * +st_get_string(GLcontext * ctx, GLenum name) +{ + struct st_context *st = st_context(ctx); + struct pipe_screen *screen = st->pipe->screen; + + switch (name) { + case GL_VENDOR: { + const char *vendor = screen->get_vendor( screen ); + const char *tungsten = "Tungsten Graphics, Inc."; + + /* Tungsten Graphics, Inc. developed the state_tracker module + * (and much of Mesa), but the driver itself may come from elsewhere. + * The additional string allows "and XyzCorp" to reflect this. + */ + if (vendor && strcmp(vendor, tungsten) != 0) + util_snprintf(st->vendor, sizeof(st->vendor), + "%s and %s", tungsten, vendor); + else + util_snprintf(st->vendor, sizeof(st->vendor), "%s", tungsten); + + return (GLubyte *) st->vendor; + } + + case GL_RENDERER: + util_snprintf(st->renderer, sizeof(st->renderer), "Gallium %s, %s on %s", + ST_VERSION_STRING, + screen->get_name( screen ), + screen->winsys->get_name( screen->winsys )); + + return (GLubyte *) st->renderer; + + default: + return NULL; + } +} + + +void st_init_string_functions(struct dd_function_table *functions) +{ + functions->GetString = st_get_string; +} diff --git a/src/mesa/state_tracker/st_cb_strings.h b/src/mesa/state_tracker/st_cb_strings.h new file mode 100644 index 0000000000..3b765aaa59 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_strings.h @@ -0,0 +1,38 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_CB_STRINGS_H +#define ST_CB_STRINGS_H + + +extern void +st_init_string_functions(struct dd_function_table *functions); + + +#endif /* ST_CB_CLEAR_H */ + diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c new file mode 100644 index 0000000000..d08229b57a --- /dev/null +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -0,0 +1,1551 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "main/imports.h" +#if FEATURE_convolve +#include "main/convolve.h" +#endif +#include "main/enums.h" +#include "main/image.h" +#include "main/macros.h" +#include "main/mipmap.h" +#include "main/pixel.h" +#include "main/texcompress.h" +#include "main/texformat.h" +#include "main/teximage.h" +#include "main/texobj.h" +#include "main/texstore.h" + +#include "state_tracker/st_context.h" +#include "state_tracker/st_cb_fbo.h" +#include "state_tracker/st_cb_texture.h" +#include "state_tracker/st_format.h" +#include "state_tracker/st_public.h" +#include "state_tracker/st_texture.h" +#include "state_tracker/st_gen_mipmap.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" +#include "util/u_tile.h" +#include "util/u_blit.h" + + +#define DBG if (0) printf + + +static enum pipe_texture_target +gl_target_to_pipe(GLenum target) +{ + switch (target) { + case GL_TEXTURE_1D: + return PIPE_TEXTURE_1D; + + case GL_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE_NV: + return PIPE_TEXTURE_2D; + + case GL_TEXTURE_3D: + return PIPE_TEXTURE_3D; + + case GL_TEXTURE_CUBE_MAP_ARB: + return PIPE_TEXTURE_CUBE; + + default: + assert(0); + return 0; + } +} + + +/** + * Return nominal bytes per texel for a compressed format, 0 for non-compressed + * format. + */ +static int +compressed_num_bytes(GLuint mesaFormat) +{ + switch(mesaFormat) { +#if FEATURE_texture_fxt1 + case MESA_FORMAT_RGB_FXT1: + case MESA_FORMAT_RGBA_FXT1: +#endif +#if FEATURE_texture_s3tc + case MESA_FORMAT_RGB_DXT1: + case MESA_FORMAT_RGBA_DXT1: + return 2; + case MESA_FORMAT_RGBA_DXT3: + case MESA_FORMAT_RGBA_DXT5: + return 4; +#endif + default: + return 0; + } +} + + +/** called via ctx->Driver.NewTextureImage() */ +static struct gl_texture_image * +st_NewTextureImage(GLcontext * ctx) +{ + DBG("%s\n", __FUNCTION__); + (void) ctx; + return (struct gl_texture_image *) CALLOC_STRUCT(st_texture_image); +} + + +/** called via ctx->Driver.NewTextureObject() */ +static struct gl_texture_object * +st_NewTextureObject(GLcontext * ctx, GLuint name, GLenum target) +{ + struct st_texture_object *obj = CALLOC_STRUCT(st_texture_object); + + DBG("%s\n", __FUNCTION__); + _mesa_initialize_texture_object(&obj->base, name, target); + + return &obj->base; +} + +/** called via ctx->Driver.DeleteTextureImage() */ +static void +st_DeleteTextureObject(GLcontext *ctx, + struct gl_texture_object *texObj) +{ + struct st_texture_object *stObj = st_texture_object(texObj); + if (stObj->pt) + pipe_texture_reference(&stObj->pt, NULL); + + _mesa_delete_texture_object(ctx, texObj); +} + + +/** called via ctx->Driver.FreeTexImageData() */ +static void +st_FreeTextureImageData(GLcontext * ctx, struct gl_texture_image *texImage) +{ + struct st_texture_image *stImage = st_texture_image(texImage); + + DBG("%s\n", __FUNCTION__); + + if (stImage->pt) { + pipe_texture_reference(&stImage->pt, NULL); + } + + if (texImage->Data) { + _mesa_align_free(texImage->Data); + texImage->Data = NULL; + } +} + + +/** + * From linux kernel i386 header files, copes with odd sizes better + * than COPY_DWORDS would: + * XXX Put this in src/mesa/main/imports.h ??? + */ +#if defined(i386) || defined(__i386__) +static INLINE void * +__memcpy(void *to, const void *from, size_t n) +{ + int d0, d1, d2; + __asm__ __volatile__("rep ; movsl\n\t" + "testb $2,%b4\n\t" + "je 1f\n\t" + "movsw\n" + "1:\ttestb $1,%b4\n\t" + "je 2f\n\t" + "movsb\n" "2:":"=&c"(d0), "=&D"(d1), "=&S"(d2) + :"0"(n / 4), "q"(n), "1"((long) to), "2"((long) from) + :"memory"); + return (to); +} +#else +#define __memcpy(a,b,c) memcpy(a,b,c) +#endif + + +/** + * The system memcpy (at least on ubuntu 5.10) has problems copying + * to agp (writecombined) memory from a source which isn't 64-byte + * aligned - there is a 4x performance falloff. + * + * The x86 __memcpy is immune to this but is slightly slower + * (10%-ish) than the system memcpy. + * + * The sse_memcpy seems to have a slight cliff at 64/32 bytes, but + * isn't much faster than x86_memcpy for agp copies. + * + * TODO: switch dynamically. + */ +static void * +do_memcpy(void *dest, const void *src, size_t n) +{ + if ((((unsigned) src) & 63) || (((unsigned) dest) & 63)) { + return __memcpy(dest, src, n); + } + else + return memcpy(dest, src, n); +} + + +static int +logbase2(int n) +{ + GLint i = 1, log2 = 0; + while (n > i) { + i *= 2; + log2++; + } + return log2; +} + + +/** + * Allocate a pipe_texture object for the given st_texture_object using + * the given st_texture_image to guess the mipmap size/levels. + * + * [comments...] + * Otherwise, store it in memory if (Border != 0) or (any dimension == + * 1). + * + * Otherwise, if max_level >= level >= min_level, create texture with + * space for images from min_level down to max_level. + * + * Otherwise, create texture with space for images from (level 0)..(1x1). + * Consider pruning this texture at a validation if the saving is worth it. + */ +static void +guess_and_alloc_texture(struct st_context *st, + struct st_texture_object *stObj, + const struct st_texture_image *stImage) +{ + GLuint firstLevel; + GLuint lastLevel; + GLuint width = stImage->base.Width2; /* size w/out border */ + GLuint height = stImage->base.Height2; + GLuint depth = stImage->base.Depth2; + GLuint i, comp_byte = 0; + enum pipe_format fmt; + + DBG("%s\n", __FUNCTION__); + + assert(!stObj->pt); + + if (stObj->pt && + (GLint) stImage->level > stObj->base.BaseLevel && + (stImage->base.Width == 1 || + (stObj->base.Target != GL_TEXTURE_1D && + stImage->base.Height == 1) || + (stObj->base.Target == GL_TEXTURE_3D && + stImage->base.Depth == 1))) + return; + + /* If this image disrespects BaseLevel, allocate from level zero. + * Usually BaseLevel == 0, so it's unlikely to happen. + */ + if ((GLint) stImage->level < stObj->base.BaseLevel) + firstLevel = 0; + else + firstLevel = stObj->base.BaseLevel; + + + /* Figure out image dimensions at start level. + */ + for (i = stImage->level; i > firstLevel; i--) { + if (width != 1) + width <<= 1; + if (height != 1) + height <<= 1; + if (depth != 1) + depth <<= 1; + } + + if (width == 0 || height == 0 || depth == 0) { + /* no texture needed */ + return; + } + + /* Guess a reasonable value for lastLevel. This is probably going + * to be wrong fairly often and might mean that we have to look at + * resizable buffers, or require that buffers implement lazy + * pagetable arrangements. + */ + if ((stObj->base.MinFilter == GL_NEAREST || + stObj->base.MinFilter == GL_LINEAR) && + stImage->level == firstLevel) { + lastLevel = firstLevel; + } + else { + GLuint l2width = logbase2(width); + GLuint l2height = logbase2(height); + GLuint l2depth = logbase2(depth); + lastLevel = firstLevel + MAX2(MAX2(l2width, l2height), l2depth); + } + + if (stImage->base.IsCompressed) + comp_byte = compressed_num_bytes(stImage->base.TexFormat->MesaFormat); + + fmt = st_mesa_format_to_pipe_format(stImage->base.TexFormat->MesaFormat); + stObj->pt = st_texture_create(st, + gl_target_to_pipe(stObj->base.Target), + fmt, + lastLevel, + width, + height, + depth, + comp_byte, + ( (pf_is_depth_stencil(fmt) ? + PIPE_TEXTURE_USAGE_DEPTH_STENCIL : + PIPE_TEXTURE_USAGE_RENDER_TARGET) | + PIPE_TEXTURE_USAGE_SAMPLER )); + + DBG("%s - success\n", __FUNCTION__); +} + + +/** + * Adjust pixel unpack params and image dimensions to strip off the + * texture border. + * Gallium doesn't support texture borders. They've seldem been used + * and seldom been implemented correctly anyway. + * \param unpackNew returns the new pixel unpack parameters + */ +static void +strip_texture_border(GLint border, + GLint *width, GLint *height, GLint *depth, + const struct gl_pixelstore_attrib *unpack, + struct gl_pixelstore_attrib *unpackNew) +{ + assert(border > 0); /* sanity check */ + + *unpackNew = *unpack; + + if (unpackNew->RowLength == 0) + unpackNew->RowLength = *width; + + if (depth && unpackNew->ImageHeight == 0) + unpackNew->ImageHeight = *height; + + unpackNew->SkipPixels += border; + if (height) + unpackNew->SkipRows += border; + if (depth) + unpackNew->SkipImages += border; + + assert(*width >= 3); + *width = *width - 2 * border; + if (height && *height >= 3) + *height = *height - 2 * border; + if (depth && *depth >= 3) + *depth = *depth - 2 * border; +} + + +/** + * Do glTexImage1/2/3D(). + */ +static void +st_TexImage(GLcontext * ctx, + GLint dims, + GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint depth, + GLint border, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *unpack, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage, + GLsizei imageSize, int compressed) +{ + struct st_texture_object *stObj = st_texture_object(texObj); + struct st_texture_image *stImage = st_texture_image(texImage); + GLint postConvWidth, postConvHeight; + GLint texelBytes, sizeInBytes; + GLuint dstRowStride; + struct gl_pixelstore_attrib unpackNB; + + DBG("%s target %s level %d %dx%dx%d border %d\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(target), level, width, height, depth, border); + + /* gallium does not support texture borders, strip it off */ + if (border) { + strip_texture_border(border, &width, &height, &depth, + unpack, &unpackNB); + unpack = &unpackNB; + texImage->Width = width; + texImage->Height = height; + texImage->Depth = depth; + texImage->Border = 0; + border = 0; + } + + postConvWidth = width; + postConvHeight = height; + + stImage->face = _mesa_tex_target_to_face(target); + stImage->level = level; + +#if FEATURE_convolve + if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) { + _mesa_adjust_image_for_convolution(ctx, dims, &postConvWidth, + &postConvHeight); + } +#endif + + /* choose the texture format */ + texImage->TexFormat = st_ChooseTextureFormat(ctx, internalFormat, + format, type); + + _mesa_set_fetch_functions(texImage, dims); + + if (texImage->TexFormat->TexelBytes == 0) { + /* must be a compressed format */ + texelBytes = 0; + texImage->IsCompressed = GL_TRUE; + texImage->CompressedSize = + ctx->Driver.CompressedTextureSize(ctx, texImage->Width, + texImage->Height, texImage->Depth, + texImage->TexFormat->MesaFormat); + } + else { + texelBytes = texImage->TexFormat->TexelBytes; + + /* Minimum pitch of 32 bytes */ + if (postConvWidth * texelBytes < 32) { + postConvWidth = 32 / texelBytes; + texImage->RowStride = postConvWidth; + } + + /* we'll set RowStride elsewhere when the texture is a "mapped" state */ + /*assert(texImage->RowStride == postConvWidth);*/ + } + + /* Release the reference to a potentially orphaned buffer. + * Release any old malloced memory. + */ + if (stImage->pt) { + pipe_texture_reference(&stImage->pt, NULL); + assert(!texImage->Data); + } + else if (texImage->Data) { + _mesa_align_free(texImage->Data); + } + + if (width == 0 || height == 0 || depth == 0) { + /* stop after freeing old image */ + return; + } + + /* If this is the only mipmap level in the texture, could call + * bmBufferData with NULL data to free the old block and avoid + * waiting on any outstanding fences. + */ + if (stObj->pt && + (stObj->teximage_realloc || + (/*stObj->pt->first_level == level &&*/ + stObj->pt->last_level == level && + stObj->pt->target != PIPE_TEXTURE_CUBE && + !st_texture_match_image(stObj->pt, &stImage->base, + stImage->face, stImage->level)))) { + + DBG("release it\n"); + pipe_texture_reference(&stObj->pt, NULL); + assert(!stObj->pt); + stObj->teximage_realloc = FALSE; + } + + if (!stObj->pt) { + guess_and_alloc_texture(ctx->st, stObj, stImage); + if (!stObj->pt) { + /* Probably out of memory. + * Try flushing any pending rendering, then retry. + */ + st_finish(ctx->st); + guess_and_alloc_texture(ctx->st, stObj, stImage); + if (!stObj->pt) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); + return; + } + } + } + + assert(!stImage->pt); + + if (stObj->pt && + st_texture_match_image(stObj->pt, &stImage->base, + stImage->face, stImage->level)) { + + pipe_texture_reference(&stImage->pt, stObj->pt); + assert(stImage->pt); + } + + if (!stImage->pt) + DBG("XXX: Image did not fit into texture - storing in local memory!\n"); + + /* st_CopyTexImage calls this function with pixels == NULL, with + * the expectation that the texture will be set up but nothing + * more will be done. This is where those calls return: + */ + if (compressed) { + pixels = _mesa_validate_pbo_compressed_teximage(ctx, imageSize, pixels, + unpack, + "glCompressedTexImage"); + } else { + pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, 1, + format, type, + pixels, unpack, "glTexImage"); + } + if (!pixels) + return; + + if (stImage->pt) { + texImage->Data = st_texture_image_map(ctx->st, stImage, 0, + PIPE_BUFFER_USAGE_CPU_WRITE); + if (stImage->surface) + dstRowStride = stImage->surface->stride; + } + else { + /* Allocate regular memory and store the image there temporarily. */ + if (texImage->IsCompressed) { + sizeInBytes = texImage->CompressedSize; + dstRowStride = + _mesa_compressed_row_stride(texImage->TexFormat->MesaFormat, width); + assert(dims != 3); + } + else { + dstRowStride = postConvWidth * texelBytes; + sizeInBytes = depth * dstRowStride * postConvHeight; + } + + texImage->Data = _mesa_align_malloc(sizeInBytes, 16); + } + + if (!texImage->Data) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); + return; + } + + DBG("Upload image %dx%dx%d row_len %x pitch %x\n", + width, height, depth, width * texelBytes, dstRowStride); + + /* Copy data. Would like to know when it's ok for us to eg. use + * the blitter to copy. Or, use the hardware to do the format + * conversion and copy: + */ + if (compressed) { + memcpy(texImage->Data, pixels, imageSize); + } + else { + GLuint srcImageStride = _mesa_image_image_stride(unpack, width, height, + format, type); + int i; + const GLubyte *src = (const GLubyte *) pixels; + + for (i = 0; i++ < depth;) { + if (!texImage->TexFormat->StoreImage(ctx, dims, + texImage->_BaseFormat, + texImage->TexFormat, + texImage->Data, + 0, 0, 0, /* dstX/Y/Zoffset */ + dstRowStride, + texImage->ImageOffsets, + width, height, 1, + format, type, src, unpack)) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); + } + + if (stImage->pt && i < depth) { + st_texture_image_unmap(ctx->st, stImage); + texImage->Data = st_texture_image_map(ctx->st, stImage, i, + PIPE_BUFFER_USAGE_CPU_WRITE); + src += srcImageStride; + } + } + } + + _mesa_unmap_teximage_pbo(ctx, unpack); + + if (stImage->pt) { + st_texture_image_unmap(ctx->st, stImage); + texImage->Data = NULL; + } + + if (level == texObj->BaseLevel && texObj->GenerateMipmap) { + ctx->Driver.GenerateMipmap(ctx, target, texObj); + } +} + + +static void +st_TexImage3D(GLcontext * ctx, + GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint depth, + GLint border, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *unpack, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexImage(ctx, 3, target, level, + internalFormat, width, height, depth, border, + format, type, pixels, unpack, texObj, texImage, 0, 0); +} + + +static void +st_TexImage2D(GLcontext * ctx, + GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint border, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *unpack, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexImage(ctx, 2, target, level, + internalFormat, width, height, 1, border, + format, type, pixels, unpack, texObj, texImage, 0, 0); +} + + +static void +st_TexImage1D(GLcontext * ctx, + GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint border, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *unpack, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexImage(ctx, 1, target, level, + internalFormat, width, 1, 1, border, + format, type, pixels, unpack, texObj, texImage, 0, 0); +} + + +static void +st_CompressedTexImage2D(GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint border, + GLsizei imageSize, const GLvoid *data, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexImage(ctx, 2, target, level, + internalFormat, width, height, 1, border, + 0, 0, data, &ctx->Unpack, texObj, texImage, imageSize, 1); +} + + +/** + * Need to map texture image into memory before copying image data, + * then unmap it. + */ +static void +st_get_tex_image(GLcontext * ctx, GLenum target, GLint level, + GLenum format, GLenum type, GLvoid * pixels, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage, int compressed) +{ + struct st_texture_image *stImage = st_texture_image(texImage); + GLuint dstImageStride = _mesa_image_image_stride(&ctx->Pack, + texImage->Width, + texImage->Height, + format, type); + GLuint depth; + GLuint i; + GLubyte *dest; + + /* Map */ + if (stImage->pt) { + /* Image is stored in hardware format in a buffer managed by the + * kernel. Need to explicitly map and unmap it. + */ + texImage->Data = st_texture_image_map(ctx->st, stImage, 0, + PIPE_BUFFER_USAGE_CPU_READ); + texImage->RowStride = stImage->surface->stride / stImage->pt->block.size; + } + else { + /* Otherwise, the image should actually be stored in + * texImage->Data. This is pretty confusing for + * everybody, I'd much prefer to separate the two functions of + * texImage->Data - storage for texture images in main memory + * and access (ie mappings) of images. In other words, we'd + * create a new texImage->Map field and leave Data simply for + * storage. + */ + assert(texImage->Data); + } + + depth = texImage->Depth; + texImage->Depth = 1; + + dest = (GLubyte *) pixels; + + for (i = 0; i++ < depth;) { + if (compressed) { + _mesa_get_compressed_teximage(ctx, target, level, dest, + texObj, texImage); + } else { + _mesa_get_teximage(ctx, target, level, format, type, dest, + texObj, texImage); + } + + if (stImage->pt && i < depth) { + st_texture_image_unmap(ctx->st, stImage); + texImage->Data = st_texture_image_map(ctx->st, stImage, i, + PIPE_BUFFER_USAGE_CPU_READ); + dest += dstImageStride; + } + } + + texImage->Depth = depth; + + /* Unmap */ + if (stImage->pt) { + st_texture_image_unmap(ctx->st, stImage); + texImage->Data = NULL; + } +} + + +static void +st_GetTexImage(GLcontext * ctx, GLenum target, GLint level, + GLenum format, GLenum type, GLvoid * pixels, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_get_tex_image(ctx, target, level, format, type, pixels, + texObj, texImage, 0); +} + + +static void +st_GetCompressedTexImage(GLcontext *ctx, GLenum target, GLint level, + GLvoid *pixels, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_get_tex_image(ctx, target, level, 0, 0, pixels, + (struct gl_texture_object *) texObj, + (struct gl_texture_image *) texImage, 1); +} + + + +static void +st_TexSubimage(GLcontext * ctx, + GLint dims, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint width, GLint height, GLint depth, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + struct st_texture_image *stImage = st_texture_image(texImage); + GLuint dstRowStride; + GLuint srcImageStride = _mesa_image_image_stride(packing, width, height, + format, type); + int i; + const GLubyte *src; + + DBG("%s target %s level %d offset %d,%d %dx%d\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(target), + level, xoffset, yoffset, width, height); + + pixels = + _mesa_validate_pbo_teximage(ctx, dims, width, height, depth, format, + type, pixels, packing, "glTexSubImage2D"); + if (!pixels) + return; + + /* Map buffer if necessary. Need to lock to prevent other contexts + * from uploading the buffer under us. + */ + if (stImage->pt) { + texImage->Data = st_texture_image_map(ctx->st, stImage, zoffset, + PIPE_BUFFER_USAGE_CPU_WRITE); + if (stImage->surface) + dstRowStride = stImage->surface->stride; + } + + if (!texImage->Data) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage"); + return; + } + + src = (const GLubyte *) pixels; + + for (i = 0; i++ < depth;) { + if (!texImage->TexFormat->StoreImage(ctx, dims, texImage->_BaseFormat, + texImage->TexFormat, + texImage->Data, + xoffset, yoffset, 0, + dstRowStride, + texImage->ImageOffsets, + width, height, 1, + format, type, src, packing)) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage"); + } + + if (stImage->pt && i < depth) { + /* map next slice of 3D texture */ + st_texture_image_unmap(ctx->st, stImage); + texImage->Data = st_texture_image_map(ctx->st, stImage, zoffset + i, + PIPE_BUFFER_USAGE_CPU_WRITE); + src += srcImageStride; + } + } + + if (level == texObj->BaseLevel && texObj->GenerateMipmap) { + ctx->Driver.GenerateMipmap(ctx, target, texObj); + } + + _mesa_unmap_teximage_pbo(ctx, packing); + + if (stImage->pt) { + st_texture_image_unmap(ctx->st, stImage); + texImage->Data = NULL; + } +} + + + +static void +st_TexSubImage3D(GLcontext * ctx, + GLenum target, + GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + const GLvoid * pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexSubimage(ctx, 3, target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, type, pixels, packing, texObj, texImage); +} + + +static void +st_TexSubImage2D(GLcontext * ctx, + GLenum target, + GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const GLvoid * pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexSubimage(ctx, 2, target, level, + xoffset, yoffset, 0, + width, height, 1, + format, type, pixels, packing, texObj, texImage); +} + + +static void +st_TexSubImage1D(GLcontext * ctx, + GLenum target, + GLint level, + GLint xoffset, + GLsizei width, + GLenum format, GLenum type, + const GLvoid * pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexSubimage(ctx, 1, target, level, + xoffset, 0, 0, + width, 1, 1, + format, type, pixels, packing, texObj, texImage); +} + + + +/** + * Return 0 for GL_TEXTURE_CUBE_MAP_POSITIVE_X, + * 1 for GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + * etc. + * XXX duplicated from main/teximage.c + */ +static uint +texture_face(GLenum target) +{ + if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) + return (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + else + return 0; +} + + + +/** + * Do a CopyTexSubImage operation by mapping the source surface and + * dest surface and using get_tile()/put_tile() to access the pixels/texels. + * + * Note: srcY=0=TOP of renderbuffer + */ +static void +fallback_copy_texsubimage(GLcontext *ctx, + GLenum target, + GLint level, + struct st_renderbuffer *strb, + struct st_texture_image *stImage, + GLenum baseFormat, + GLint destX, GLint destY, GLint destZ, + GLint srcX, GLint srcY, + GLsizei width, GLsizei height) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct pipe_screen *screen = pipe->screen; + const uint face = texture_face(target); + struct pipe_texture *pt = stImage->pt; + struct pipe_surface *src_surf, *dest_surf; + + /* We'd use strb->surface, here but it's created for GPU read/write only */ + src_surf = pipe->screen->get_tex_surface( pipe->screen, + strb->texture, + 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_READ); + + dest_surf = screen->get_tex_surface(screen, pt, face, level, destZ, + PIPE_BUFFER_USAGE_CPU_WRITE); + + assert(width <= MAX_WIDTH); + + if (baseFormat == GL_DEPTH_COMPONENT) { + const GLboolean scaleOrBias = (ctx->Pixel.DepthScale != 1.0F || + ctx->Pixel.DepthBias != 0.0F); + GLint row, yStep; + + /* determine bottom-to-top vs. top-to-bottom order for src buffer */ + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + srcY = strb->Base.Height - 1 - srcY; + yStep = -1; + } + else { + yStep = 1; + } + + /* To avoid a large temp memory allocation, do copy row by row */ + for (row = 0; row < height; row++, srcY += yStep, destY++) { + uint data[MAX_WIDTH]; + pipe_get_tile_z(src_surf, srcX, srcY, width, 1, data); + if (scaleOrBias) { + _mesa_scale_and_bias_depth_uint(ctx, width, data); + } + pipe_put_tile_z(dest_surf, destX, destY, width, 1, data); + } + } + else { + /* RGBA format */ + GLfloat *tempSrc = + (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat)); + GLvoid *texDest = + st_texture_image_map(ctx->st, stImage, 0,PIPE_BUFFER_USAGE_CPU_WRITE); + + if (tempSrc && texDest) { + const GLint dims = 2; + struct gl_texture_image *texImage = &stImage->base; + GLint dstRowStride = stImage->surface->stride; + struct gl_pixelstore_attrib unpack = ctx->DefaultPacking; + + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + /* need to invert src */ + srcY = strb->Base.Height - srcY - height; + unpack.Invert = GL_TRUE; + } + + /* get float/RGBA image from framebuffer */ + /* XXX this usually involves a lot of int/float conversion. + * try to avoid that someday. + */ + pipe_get_tile_rgba(src_surf, srcX, srcY, width, height, tempSrc); + + /* Store into texture memory. + * Note that this does some special things such as pixel transfer + * ops and format conversion. In particular, if the dest tex format + * is actually RGBA but the user created the texture as GL_RGB we + * need to fill-in/override the alpha channel with 1.0. + */ + texImage->TexFormat->StoreImage(ctx, dims, + texImage->_BaseFormat, + texImage->TexFormat, + texDest, + destX, destY, destZ, + dstRowStride, + texImage->ImageOffsets, + width, height, 1, + GL_RGBA, GL_FLOAT, tempSrc, /* src */ + &unpack); + } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage"); + } + + if (tempSrc) + _mesa_free(tempSrc); + if (texDest) + st_texture_image_unmap(ctx->st, stImage); + } + + screen->tex_surface_release(screen, &dest_surf); + screen->tex_surface_release(screen, &src_surf); +} + + +/** + * Do a CopyTex[Sub]Image1/2/3D() using a hardware (blit) path if possible. + * Note that the region to copy has already been clipped so we know we + * won't read from outside the source renderbuffer's bounds. + * + * Note: srcY=0=Bottom of renderbuffer (GL convention) + */ +static void +st_copy_texsubimage(GLcontext *ctx, + GLenum target, GLint level, + GLint destX, GLint destY, GLint destZ, + GLint srcX, GLint srcY, + GLsizei width, GLsizei height) +{ + struct gl_texture_unit *texUnit = + &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + struct gl_texture_object *texObj = + _mesa_select_tex_object(ctx, texUnit, target); + struct gl_texture_image *texImage = + _mesa_select_tex_image(ctx, texObj, target, level); + struct st_texture_image *stImage = st_texture_image(texImage); + const GLenum texBaseFormat = texImage->InternalFormat; + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct st_renderbuffer *strb; + struct pipe_context *pipe = ctx->st->pipe; + struct pipe_screen *screen = pipe->screen; + enum pipe_format dest_format, src_format; + GLboolean use_fallback = GL_TRUE; + GLboolean matching_base_formats; + + /* any rendering in progress must complete before we grab the fb image */ + st_finish(ctx->st); + + /* determine if copying depth or color data */ + if (texBaseFormat == GL_DEPTH_COMPONENT) { + strb = st_renderbuffer(fb->_DepthBuffer); + } + else if (texBaseFormat == GL_DEPTH_STENCIL_EXT) { + strb = st_renderbuffer(fb->_StencilBuffer); + } + else { + /* texBaseFormat == GL_RGB, GL_RGBA, GL_ALPHA, etc */ + strb = st_renderbuffer(fb->_ColorReadBuffer); + } + + assert(strb); + assert(strb->surface); + assert(stImage->pt); + + src_format = strb->surface->format; + dest_format = stImage->pt->format; + + /* + * Determine if the src framebuffer and dest texture have the same + * base format. We need this to detect a case such as the framebuffer + * being GL_RGBA but the texture being GL_RGB. If the actual hardware + * texture format stores RGBA we need to set A=1 (overriding the + * framebuffer's alpha values). We can't do that with the blit or + * textured-quad paths. + */ + matching_base_formats = (strb->Base._BaseFormat == texImage->_BaseFormat); + + if (matching_base_formats && ctx->_ImageTransferState == 0x0) { + /* try potential hardware path */ + struct pipe_surface *dest_surface = NULL; + + if (src_format == dest_format) { + /* use surface_copy() / blit */ + boolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP); + + dest_surface = screen->get_tex_surface(screen, stImage->pt, + stImage->face, stImage->level, + destZ, + PIPE_BUFFER_USAGE_GPU_WRITE); + if (do_flip) + srcY = strb->surface->height - srcY - height; + + /* for surface_copy(), y=0=top, always */ + pipe->surface_copy(pipe, + do_flip, + /* dest */ + dest_surface, + destX, destY, + /* src */ + strb->surface, + srcX, srcY, + /* size */ + width, height); + use_fallback = GL_FALSE; + } + else if (screen->is_format_supported(screen, src_format, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, + 0) && + screen->is_format_supported(screen, dest_format, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_RENDER_TARGET, + 0)) { + /* draw textured quad to do the copy */ + boolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP); + int srcY0, srcY1; + + dest_surface = screen->get_tex_surface(screen, stImage->pt, + stImage->face, stImage->level, + destZ, + PIPE_BUFFER_USAGE_GPU_WRITE); + + if (do_flip) { + srcY1 = strb->Base.Height - srcY - height; + srcY0 = srcY1 + height; + } + else { + srcY0 = srcY; + srcY1 = srcY0 + height; + } + util_blit_pixels(ctx->st->blit, + strb->surface, + srcX, srcY0, + srcX + width, srcY1, + dest_surface, + destX, destY, + destX + width, destY + height, + 0.0, PIPE_TEX_MIPFILTER_NEAREST); + use_fallback = GL_FALSE; + } + + if (dest_surface) + pipe_surface_reference(&dest_surface, NULL); + } + + if (use_fallback) { + /* software fallback */ + fallback_copy_texsubimage(ctx, target, level, + strb, stImage, texBaseFormat, + destX, destY, destZ, + srcX, srcY, width, height); + } + + if (level == texObj->BaseLevel && texObj->GenerateMipmap) { + ctx->Driver.GenerateMipmap(ctx, target, texObj); + } +} + + + +static void +st_CopyTexImage1D(GLcontext * ctx, GLenum target, GLint level, + GLenum internalFormat, + GLint x, GLint y, GLsizei width, GLint border) +{ + struct gl_texture_unit *texUnit = + &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + struct gl_texture_object *texObj = + _mesa_select_tex_object(ctx, texUnit, target); + struct gl_texture_image *texImage = + _mesa_select_tex_image(ctx, texObj, target, level); + +#if 0 + if (border) + goto fail; +#endif + + /* Setup or redefine the texture object, texture and texture + * image. Don't populate yet. + */ + ctx->Driver.TexImage1D(ctx, target, level, internalFormat, + width, border, + GL_RGBA, CHAN_TYPE, NULL, + &ctx->DefaultPacking, texObj, texImage); + + st_copy_texsubimage(ctx, target, level, + 0, 0, 0, /* destX,Y,Z */ + x, y, width, 1); /* src X, Y, size */ +} + + +static void +st_CopyTexImage2D(GLcontext * ctx, GLenum target, GLint level, + GLenum internalFormat, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint border) +{ + struct gl_texture_unit *texUnit = + &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + struct gl_texture_object *texObj = + _mesa_select_tex_object(ctx, texUnit, target); + struct gl_texture_image *texImage = + _mesa_select_tex_image(ctx, texObj, target, level); + + /* Setup or redefine the texture object, texture and texture + * image. Don't populate yet. + */ + ctx->Driver.TexImage2D(ctx, target, level, internalFormat, + width, height, border, + GL_RGBA, CHAN_TYPE, NULL, + &ctx->DefaultPacking, texObj, texImage); + + st_copy_texsubimage(ctx, target, level, + 0, 0, 0, /* destX,Y,Z */ + x, y, width, height); /* src X, Y, size */ +} + + +static void +st_CopyTexSubImage1D(GLcontext * ctx, GLenum target, GLint level, + GLint xoffset, GLint x, GLint y, GLsizei width) +{ + const GLint yoffset = 0, zoffset = 0; + const GLsizei height = 1; + st_copy_texsubimage(ctx, target, level, + xoffset, yoffset, zoffset, /* destX,Y,Z */ + x, y, width, height); /* src X, Y, size */ +} + + +static void +st_CopyTexSubImage2D(GLcontext * ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLint x, GLint y, GLsizei width, GLsizei height) +{ + const GLint zoffset = 0; + st_copy_texsubimage(ctx, target, level, + xoffset, yoffset, zoffset, /* destX,Y,Z */ + x, y, width, height); /* src X, Y, size */ +} + + +static void +st_CopyTexSubImage3D(GLcontext * ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height) +{ + st_copy_texsubimage(ctx, target, level, + xoffset, yoffset, zoffset, /* destX,Y,Z */ + x, y, width, height); /* src X, Y, size */ +} + + +/** + * Compute which mipmap levels that really need to be sent to the hardware. + * This depends on the base image size, GL_TEXTURE_MIN_LOD, + * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL. + */ +static void +calculate_first_last_level(struct st_texture_object *stObj) +{ + struct gl_texture_object *tObj = &stObj->base; + + /* These must be signed values. MinLod and MaxLod can be negative numbers, + * and having firstLevel and lastLevel as signed prevents the need for + * extra sign checks. + */ + int firstLevel; + int lastLevel; + + /* Yes, this looks overly complicated, but it's all needed. + */ + switch (tObj->Target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + case GL_TEXTURE_CUBE_MAP: + if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) { + /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL. + */ + firstLevel = lastLevel = tObj->BaseLevel; + } + else { + firstLevel = 0; + lastLevel = MIN2(tObj->MaxLevel, + (int) tObj->Image[0][tObj->BaseLevel]->WidthLog2); + } + break; + case GL_TEXTURE_RECTANGLE_NV: + case GL_TEXTURE_4D_SGIS: + firstLevel = lastLevel = 0; + break; + default: + return; + } + + stObj->lastLevel = lastLevel; +} + + +static void +copy_image_data_to_texture(struct st_context *st, + struct st_texture_object *stObj, + GLuint dstLevel, + struct st_texture_image *stImage) +{ + if (stImage->pt) { + /* Copy potentially with the blitter: + */ + st_texture_image_copy(st->pipe, + stObj->pt, dstLevel, /* dest texture, level */ + stImage->pt, /* src texture */ + stImage->face + ); + + pipe_texture_reference(&stImage->pt, NULL); + } + else if (stImage->base.Data) { + assert(stImage->base.Data != NULL); + + /* More straightforward upload. + */ + st_texture_image_data(st->pipe, + stObj->pt, + stImage->face, + dstLevel, + stImage->base.Data, + stImage->base.RowStride * + stObj->pt->block.size, + stImage->base.RowStride * + stImage->base.Height * + stObj->pt->block.size); + _mesa_align_free(stImage->base.Data); + stImage->base.Data = NULL; + } + + pipe_texture_reference(&stImage->pt, stObj->pt); +} + + +/** + * Called during state validation. When this function is finished, + * the texture object should be ready for rendering. + * \return GL_TRUE for success, GL_FALSE for failure (out of mem) + */ +GLboolean +st_finalize_texture(GLcontext *ctx, + struct pipe_context *pipe, + struct gl_texture_object *tObj, + GLboolean *needFlush) +{ + struct st_texture_object *stObj = st_texture_object(tObj); + const GLuint nr_faces = (stObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; + int comp_byte = 0; + int cpp; + GLuint face; + struct st_texture_image *firstImage; + + *needFlush = GL_FALSE; + + /* We know/require this is true by now: + */ + assert(stObj->base._Complete); + + /* What levels must the texture include at a minimum? + */ + calculate_first_last_level(stObj); + firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]); + + /* If both firstImage and stObj point to a texture which can contain + * all active images, favour firstImage. Note that because of the + * completeness requirement, we know that the image dimensions + * will match. + */ + if (firstImage->pt && + firstImage->pt != stObj->pt && + firstImage->pt->last_level >= stObj->lastLevel) { + + pipe_texture_reference(&stObj->pt, firstImage->pt); + } + + /* FIXME: determine format block instead of cpp */ + if (firstImage->base.IsCompressed) { + comp_byte = compressed_num_bytes(firstImage->base.TexFormat->MesaFormat); + cpp = comp_byte; + } + else { + cpp = firstImage->base.TexFormat->TexelBytes; + } + + /* If we already have a gallium texture, check that it matches the texture + * object's format, target, size, num_levels, etc. + */ + if (stObj->pt) { + const enum pipe_format fmt = + st_mesa_format_to_pipe_format(firstImage->base.TexFormat->MesaFormat); + if (stObj->pt->target != gl_target_to_pipe(stObj->base.Target) || + stObj->pt->format != fmt || + stObj->pt->last_level < stObj->lastLevel || + stObj->pt->width[0] != firstImage->base.Width2 || + stObj->pt->height[0] != firstImage->base.Height2 || + stObj->pt->depth[0] != firstImage->base.Depth2 || + stObj->pt->block.size != cpp || + stObj->pt->block.width != 1 || + stObj->pt->block.height != 1 || + stObj->pt->compressed != firstImage->base.IsCompressed) { + pipe_texture_release(&stObj->pt); + ctx->st->dirty.st |= ST_NEW_FRAMEBUFFER; + } + } + + /* May need to create a new gallium texture: + */ + if (!stObj->pt) { + const enum pipe_format fmt = + st_mesa_format_to_pipe_format(firstImage->base.TexFormat->MesaFormat); + stObj->pt = st_texture_create(ctx->st, + gl_target_to_pipe(stObj->base.Target), + fmt, + stObj->lastLevel, + firstImage->base.Width2, + firstImage->base.Height2, + firstImage->base.Depth2, + comp_byte, + ( (pf_is_depth_stencil(fmt) ? + PIPE_TEXTURE_USAGE_DEPTH_STENCIL : + PIPE_TEXTURE_USAGE_RENDER_TARGET) | + PIPE_TEXTURE_USAGE_SAMPLER )); + + if (!stObj->pt) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); + return GL_FALSE; + } + } + + /* Pull in any images not in the object's texture: + */ + for (face = 0; face < nr_faces; face++) { + GLuint level; + for (level = 0; level <= stObj->lastLevel; level++) { + struct st_texture_image *stImage = + st_texture_image(stObj->base.Image[face][stObj->base.BaseLevel + level]); + + /* Need to import images in main memory or held in other textures. + */ + if (stImage && stObj->pt != stImage->pt) { + copy_image_data_to_texture(ctx->st, stObj, level, stImage); + *needFlush = GL_TRUE; + } + } + } + + return GL_TRUE; +} + + +/** + * Returns pointer to a default/dummy texture. + * This is typically used when the current shader has tex/sample instructions + * but the user has not provided a (any) texture(s). + */ +struct gl_texture_object * +st_get_default_texture(struct st_context *st) +{ + if (!st->default_texture) { + static const GLenum target = GL_TEXTURE_2D; + GLubyte pixels[16][16][4]; + struct gl_texture_object *texObj; + struct gl_texture_image *texImg; + + /* init image to gray */ + memset(pixels, 127, sizeof(pixels)); + + texObj = st->ctx->Driver.NewTextureObject(st->ctx, 0, target); + + texImg = _mesa_get_tex_image(st->ctx, texObj, target, 0); + + _mesa_init_teximage_fields(st->ctx, target, texImg, + 16, 16, 1, 0, /* w, h, d, border */ + GL_RGBA); + + st_TexImage(st->ctx, 2, target, + 0, GL_RGBA, /* level, intformat */ + 16, 16, 1, 0, /* w, h, d, border */ + GL_RGBA, GL_UNSIGNED_BYTE, pixels, + &st->ctx->DefaultPacking, + texObj, texImg, + 0, 0); + + texObj->MinFilter = GL_NEAREST; + texObj->MagFilter = GL_NEAREST; + texObj->_Complete = GL_TRUE; + + st->default_texture = texObj; + } + return st->default_texture; +} + + +void +st_init_texture_functions(struct dd_function_table *functions) +{ + functions->ChooseTextureFormat = st_ChooseTextureFormat; + functions->TexImage1D = st_TexImage1D; + functions->TexImage2D = st_TexImage2D; + functions->TexImage3D = st_TexImage3D; + functions->TexSubImage1D = st_TexSubImage1D; + functions->TexSubImage2D = st_TexSubImage2D; + functions->TexSubImage3D = st_TexSubImage3D; + functions->CopyTexImage1D = st_CopyTexImage1D; + functions->CopyTexImage2D = st_CopyTexImage2D; + functions->CopyTexSubImage1D = st_CopyTexSubImage1D; + functions->CopyTexSubImage2D = st_CopyTexSubImage2D; + functions->CopyTexSubImage3D = st_CopyTexSubImage3D; + functions->GenerateMipmap = st_generate_mipmap; + + functions->GetTexImage = st_GetTexImage; + + /* compressed texture functions */ + functions->CompressedTexImage2D = st_CompressedTexImage2D; + functions->GetCompressedTexImage = st_GetCompressedTexImage; + functions->CompressedTextureSize = _mesa_compressed_texture_size; + + functions->NewTextureObject = st_NewTextureObject; + functions->NewTextureImage = st_NewTextureImage; + functions->DeleteTexture = st_DeleteTextureObject; + functions->FreeTexImageData = st_FreeTextureImageData; + functions->UpdateTexturePalette = 0; + + functions->TextureMemCpy = do_memcpy; + + /* XXX Temporary until we can query pipe's texture sizes */ + functions->TestProxyTexImage = _mesa_test_proxy_teximage; +} diff --git a/src/mesa/state_tracker/st_cb_texture.h b/src/mesa/state_tracker/st_cb_texture.h new file mode 100644 index 0000000000..f1fe0339cd --- /dev/null +++ b/src/mesa/state_tracker/st_cb_texture.h @@ -0,0 +1,48 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_CB_TEXTURE_H +#define ST_CB_TEXTURE_H + + +extern GLboolean +st_finalize_texture(GLcontext *ctx, + struct pipe_context *pipe, + struct gl_texture_object *tObj, + GLboolean *needFlush); + + +extern struct gl_texture_object * +st_get_default_texture(struct st_context *st); + + +extern void +st_init_texture_functions(struct dd_function_table *functions); + + +#endif /* ST_CB_TEXTURE_H */ diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c new file mode 100644 index 0000000000..cca808d328 --- /dev/null +++ b/src/mesa/state_tracker/st_context.c @@ -0,0 +1,326 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "main/imports.h" +#include "main/context.h" +#include "main/extensions.h" +#include "main/matrix.h" +#include "main/buffers.h" +#include "main/scissor.h" +#include "vbo/vbo.h" +#include "shader/shader_api.h" +#include "glapi/glapi.h" +#include "st_public.h" +#include "st_context.h" +#include "st_cb_accum.h" +#include "st_cb_bitmap.h" +#include "st_cb_blit.h" +#include "st_cb_bufferobjects.h" +#include "st_cb_clear.h" +#if FEATURE_drawpix +#include "st_cb_drawpixels.h" +#include "st_cb_rasterpos.h" +#endif +#ifdef FEATURE_OES_draw_texture +#include "st_cb_drawtex.h" +#endif +#include "st_cb_fbo.h" +#include "st_cb_get.h" +#if FEATURE_feedback +#include "st_cb_feedback.h" +#endif +#include "st_cb_program.h" +#include "st_cb_queryobj.h" +#include "st_cb_readpixels.h" +#include "st_cb_texture.h" +#include "st_cb_flush.h" +#include "st_cb_strings.h" +#include "st_atom.h" +#include "st_draw.h" +#include "st_extensions.h" +#include "st_gen_mipmap.h" +#include "st_program.h" +#include "pipe/p_context.h" +#include "pipe/p_inlines.h" +#include "draw/draw_context.h" +#include "cso_cache/cso_cache.h" +#include "cso_cache/cso_context.h" + + +/** + * Called via ctx->Driver.UpdateState() + */ +void st_invalidate_state(GLcontext * ctx, GLuint new_state) +{ + struct st_context *st = st_context(ctx); + + st->dirty.mesa |= new_state; + st->dirty.st |= ST_NEW_MESA; + + /* This is the only core Mesa module we depend upon. + * No longer use swrast, swsetup, tnl. + */ + _vbo_InvalidateState(ctx, new_state); +} + + +/** + * Check for multisample env var override. + */ +int +st_get_msaa(void) +{ + const char *msaa = _mesa_getenv("__GL_FSAA_MODE"); + if (msaa) + return atoi(msaa); + return 0; +} + + +static struct st_context * +st_create_context_priv( GLcontext *ctx, struct pipe_context *pipe ) +{ + uint i; + struct st_context *st = CALLOC_STRUCT( st_context ); + + ctx->st = st; + + st->ctx = ctx; + st->pipe = pipe; + + /* state tracker needs the VBO module */ + _vbo_CreateContext(ctx); + +#if FEATURE_feedback || FEATURE_drawpix + st->draw = draw_create(); /* for selection/feedback */ + + /* Disable draw options that might convert points/lines to tris, etc. + * as that would foul-up feedback/selection mode. + */ + draw_wide_line_threshold(st->draw, 1000.0f); + draw_wide_point_threshold(st->draw, 1000.0f); + draw_enable_line_stipple(st->draw, FALSE); + draw_enable_point_sprites(st->draw, FALSE); +#endif + + st->dirty.mesa = ~0; + st->dirty.st = ~0; + + st->cso_context = cso_create_context(pipe); + + st_init_atoms( st ); + st_init_bitmap(st); + st_init_clear(st); + st_init_draw( st ); + st_init_generate_mipmap(st); + st_init_blit(st); + + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) + st->state.sampler_list[i] = &st->state.samplers[i]; + + /* we want all vertex data to be placed in buffer objects */ + vbo_use_buffer_objects(ctx); + + /* Need these flags: + */ + st->ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; + st->ctx->FragmentProgram._UseTexEnvProgram = GL_TRUE; + + st->ctx->VertexProgram._MaintainTnlProgram = GL_TRUE; + + st->pixel_xfer.cache = _mesa_new_program_cache(); + + st->force_msaa = st_get_msaa(); + + /* GL limits and extensions */ + st_init_limits(st); + st_init_extensions(st); + + return st; +} + + +struct st_context *st_create_context(struct pipe_context *pipe, + const __GLcontextModes *visual, + struct st_context *share) +{ + GLcontext *ctx; + GLcontext *shareCtx = share ? share->ctx : NULL; + struct dd_function_table funcs; + + memset(&funcs, 0, sizeof(funcs)); + st_init_driver_functions(&funcs); + + ctx = _mesa_create_context(visual, shareCtx, &funcs, NULL); + + return st_create_context_priv(ctx, pipe); +} + + +static void st_destroy_context_priv( struct st_context *st ) +{ + uint i; + +#if FEATURE_feedback || FEATURE_drawpix + draw_destroy(st->draw); +#endif + st_destroy_atoms( st ); + st_destroy_draw( st ); + st_destroy_generate_mipmap(st); +#if FEATURE_EXT_framebuffer_blit + st_destroy_blit(st); +#endif + st_destroy_clear(st); +#if FEATURE_drawpix + st_destroy_bitmap(st); + st_destroy_drawpix(st); +#endif +#ifdef FEATURE_OES_draw_texture + st_destroy_drawtex(st); +#endif + + for (i = 0; i < Elements(st->state.sampler_texture); i++) { + pipe_texture_reference(&st->state.sampler_texture[i], NULL); + } + + for (i = 0; i < Elements(st->state.constants); i++) { + if (st->state.constants[i].buffer) { + pipe_buffer_reference(st->pipe->screen, &st->state.constants[i].buffer, NULL); + } + } + + if (st->default_texture) { + st->ctx->Driver.DeleteTexture(st->ctx, st->default_texture); + st->default_texture = NULL; + } + + free( st ); +} + + +void st_destroy_context( struct st_context *st ) +{ + struct pipe_context *pipe = st->pipe; + struct cso_context *cso = st->cso_context; + GLcontext *ctx = st->ctx; + + /* need to unbind and destroy CSO objects before anything else */ + cso_release_all(st->cso_context); + + st_reference_fragprog(st, &st->fp, NULL); + st_reference_vertprog(st, &st->vp, NULL); + + _mesa_delete_program_cache(st->ctx, st->pixel_xfer.cache); + + _vbo_DestroyContext(st->ctx); + + _mesa_free_context_data(ctx); + + st_destroy_context_priv(st); + + cso_destroy_context(cso); + + pipe->destroy( pipe ); + + free(ctx); +} + + +void st_make_current(struct st_context *st, + struct st_framebuffer *draw, + struct st_framebuffer *read) +{ + if (st) { + GLboolean firstTime = st->ctx->FirstTimeCurrent; + _mesa_make_current(st->ctx, &draw->Base, &read->Base); + /* Need to initialize viewport here since draw->Base->Width/Height + * will still be zero at this point. + * This could be improved, but would require rather extensive work + * elsewhere (allocate rb surface storage sooner) + */ + if (firstTime) { + GLuint w = draw->InitWidth, h = draw->InitHeight; + _mesa_set_viewport(st->ctx, 0, 0, w, h); + _mesa_set_scissor(st->ctx, 0, 0, w, h); + + } + } + else { + _mesa_make_current(NULL, NULL, NULL); + } +} + + +void st_copy_context_state(struct st_context *dst, + struct st_context *src, + uint mask) +{ + _mesa_copy_context(dst->ctx, src->ctx, mask); +} + + + +st_proc st_get_proc_address(const char *procname) +{ + return (st_proc) _glapi_get_proc_address(procname); +} + + + +void st_init_driver_functions(struct dd_function_table *functions) +{ + _mesa_init_glsl_driver_functions(functions); + +#if FEATURE_accum + st_init_accum_functions(functions); +#endif +#if FEATURE_EXT_framebuffer_blit + st_init_blit_functions(functions); +#endif + st_init_bufferobject_functions(functions); + st_init_clear_functions(functions); +#if FEATURE_drawpix + st_init_bitmap_functions(functions); + st_init_drawpixels_functions(functions); + st_init_rasterpos_functions(functions); +#endif + st_init_fbo_functions(functions); + st_init_get_functions(functions); +#if FEATURE_feedback + st_init_feedback_functions(functions); +#endif + st_init_program_functions(functions); +#if FEATURE_ARB_occlusion_query + st_init_query_functions(functions); +#endif + st_init_readpixels_functions(functions); + st_init_texture_functions(functions); + st_init_flush_functions(functions); + st_init_string_functions(functions); + + functions->UpdateState = st_invalidate_state; +} diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h new file mode 100644 index 0000000000..1d1aca3111 --- /dev/null +++ b/src/mesa/state_tracker/st_context.h @@ -0,0 +1,247 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef ST_CONTEXT_H +#define ST_CONTEXT_H + +#include "main/mtypes.h" +#include "shader/prog_cache.h" +#include "pipe/p_state.h" + + +struct st_context; +struct st_texture_object; +struct st_fragment_program; +struct draw_context; +struct draw_stage; +struct cso_cache; +struct cso_blend; +struct gen_mipmap_state; +struct blit_state; +struct bitmap_cache; + + +#define FRONT_STATUS_UNDEFINED 0 +#define FRONT_STATUS_DIRTY 1 +#define FRONT_STATUS_COPY_OF_BACK 2 + + +#define ST_NEW_MESA 0x1 /* Mesa state has changed */ +#define ST_NEW_FRAGMENT_PROGRAM 0x2 +#define ST_NEW_VERTEX_PROGRAM 0x4 +#define ST_NEW_FRAMEBUFFER 0x8 + + +struct st_state_flags { + GLuint mesa; + GLuint st; +}; + +struct st_tracked_state { + const char *name; + struct st_state_flags dirty; + void (*update)( struct st_context *st ); +}; + + + +struct st_context +{ + GLcontext *ctx; + + struct pipe_context *pipe; + + struct draw_context *draw; /**< For selection/feedback/rastpos only */ + struct draw_stage *feedback_stage; /**< For GL_FEEDBACK rendermode */ + struct draw_stage *selection_stage; /**< For GL_SELECT rendermode */ + struct draw_stage *rastpos_stage; /**< For glRasterPos */ + + /* Some state is contained in constant objects. + * Other state is just parameter values. + */ + struct { + struct pipe_blend_state blend; + struct pipe_depth_stencil_alpha_state depth_stencil; + struct pipe_rasterizer_state rasterizer; + struct pipe_sampler_state samplers[PIPE_MAX_SAMPLERS]; + struct pipe_sampler_state *sampler_list[PIPE_MAX_SAMPLERS]; + struct pipe_clip_state clip; + struct pipe_constant_buffer constants[2]; + struct pipe_framebuffer_state framebuffer; + struct pipe_texture *sampler_texture[PIPE_MAX_SAMPLERS]; + struct pipe_poly_stipple poly_stipple; + struct pipe_scissor_state scissor; + struct pipe_viewport_state viewport; + + GLuint num_samplers; + GLuint num_textures; + } state; + + struct { + struct st_tracked_state tracked_state[2]; + } constants; + + /* XXX unused: */ + struct { + struct gl_fragment_program *fragment_program; + } cb; + + GLuint frontbuffer_status; /**< one of FRONT_STATUS_ */ + + char vendor[100]; + char renderer[100]; + + /* State to be validated: + */ + struct st_tracked_state **atoms; + GLuint nr_atoms; + + struct st_state_flags dirty; + + GLboolean missing_textures; + + GLfloat polygon_offset_scale; /* ?? */ + + /** Mapping from VERT_RESULT_x to post-transformed vertex slot */ + const GLuint *vertex_result_to_slot; + + struct st_vertex_program *vp; /**< Currently bound vertex program */ + struct st_fragment_program *fp; /**< Currently bound fragment program */ + + struct gl_texture_object *default_texture; + + struct { + struct gl_program_cache *cache; + struct st_fragment_program *program; /**< cur pixel transfer prog */ + GLuint xfer_prog_sn; /**< pixel xfer program serial no. */ + GLuint user_prog_sn; /**< user fragment program serial no. */ + struct st_fragment_program *combined_prog; + GLuint combined_prog_sn; + struct pipe_texture *pixelmap_texture; + boolean pixelmap_enabled; /**< use the pixelmap texture? */ + } pixel_xfer; + + /** for glBitmap */ + struct { + struct pipe_rasterizer_state rasterizer; + struct pipe_sampler_state sampler; + struct pipe_shader_state vert_shader; + enum pipe_format tex_format; + void *vs; + float vertices[4][3][4]; /**< vertex pos + color + texcoord */ + struct pipe_buffer *vbuf; + struct bitmap_cache *cache; + } bitmap; + + /** for glDraw/CopyPixels */ + struct { + struct st_fragment_program *z_shader; + struct st_vertex_program *vert_shaders[2]; + } drawpix; + + /** for glClear */ + struct { + struct pipe_shader_state vert_shader; + struct pipe_shader_state frag_shader; + struct pipe_rasterizer_state raster; + struct pipe_viewport_state viewport; + void *vs; + void *fs; + float vertices[4][2][4]; /**< vertex pos + color */ + struct pipe_buffer *vbuf; + } clear; + + void *passthrough_fs; /**< simple pass-through frag shader */ + + struct gen_mipmap_state *gen_mipmap; + struct blit_state *blit; + + struct cso_context *cso_context; + + int force_msaa; +}; + + +/* Need this so that we can implement Mesa callbacks in this module. + */ +static INLINE struct st_context *st_context(GLcontext *ctx) +{ + return ctx->st; +} + + +/** + * Wrapper for GLframebuffer. + * This is an opaque type to the outside world. + */ +struct st_framebuffer +{ + GLframebuffer Base; + void *Private; + GLuint InitWidth, InitHeight; +}; + + +extern void st_init_driver_functions(struct dd_function_table *functions); + +void st_invalidate_state(GLcontext * ctx, GLuint new_state); + + + +#define Y_0_TOP 1 +#define Y_0_BOTTOM 2 + +static INLINE GLuint +st_fb_orientation(const struct gl_framebuffer *fb) +{ + if (fb && fb->Name == 0) { + /* Drawing into a window (on-screen buffer). + * + * Negate Y scale to flip image vertically. + * The NDC Y coords prior to viewport transformation are in the range + * [y=-1=bottom, y=1=top] + * Hardware window coords are in the range [y=0=top, y=H-1=bottom] where + * H is the window height. + * Use the viewport transformation to invert Y. + */ + return Y_0_TOP; + } + else { + /* Drawing into user-created FBO (very likely a texture). + * + * For textures, T=0=Bottom, so by extension Y=0=Bottom for rendering. + */ + return Y_0_BOTTOM; + } +} + + +extern int +st_get_msaa(void); + + +#endif diff --git a/src/mesa/state_tracker/st_debug.c b/src/mesa/state_tracker/st_debug.c new file mode 100644 index 0000000000..c7d26ce33c --- /dev/null +++ b/src/mesa/state_tracker/st_debug.c @@ -0,0 +1,70 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "main/context.h" +#include "shader/prog_print.h" + +#include "pipe/p_state.h" +#include "pipe/p_shader_tokens.h" +#include "tgsi/tgsi_dump.h" + +#include "cso_cache/cso_cache.h" + +#include "st_context.h" +#include "st_debug.h" +#include "st_program.h" + + + +/** + * Print current state. May be called from inside gdb to see currently + * bound vertex/fragment shaders and associated constants. + */ +void +st_print_current(void) +{ + GET_CURRENT_CONTEXT(ctx); + struct st_context *st = ctx->st; + +#if 0 + int i; + + printf("Vertex Transform Inputs:\n"); + for (i = 0; i < st->vp->state.num_inputs; i++) { + printf(" Slot %d: VERT_ATTRIB_%d\n", i, st->vp->index_to_input[i]); + } +#endif + + tgsi_dump( st->vp->state.tokens, 0 ); + if (st->vp->Base.Base.Parameters) + _mesa_print_parameter_list(st->vp->Base.Base.Parameters); + + tgsi_dump( st->fp->state.tokens, 0 ); + if (st->fp->Base.Base.Parameters) + _mesa_print_parameter_list(st->fp->Base.Base.Parameters); +} diff --git a/src/mesa/state_tracker/st_debug.h b/src/mesa/state_tracker/st_debug.h new file mode 100644 index 0000000000..49d752e1b2 --- /dev/null +++ b/src/mesa/state_tracker/st_debug.h @@ -0,0 +1,36 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_DEBUG_H +#define ST_DEBUG_H + +extern void +st_print_current(void); + + +#endif /* ST_DEBUG_H */ diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c new file mode 100644 index 0000000000..4bc734bad3 --- /dev/null +++ b/src/mesa/state_tracker/st_draw.c @@ -0,0 +1,905 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "main/imports.h" +#include "main/image.h" +#include "main/macros.h" +#include "shader/prog_uniform.h" + +#include "vbo/vbo.h" + +#include "st_context.h" +#include "st_atom.h" +#include "st_cb_bufferobjects.h" +#include "st_draw.h" +#include "st_program.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" + +#include "draw/draw_private.h" +#include "draw/draw_context.h" + + +static GLuint double_types[4] = { + PIPE_FORMAT_R64_FLOAT, + PIPE_FORMAT_R64G64_FLOAT, + PIPE_FORMAT_R64G64B64_FLOAT, + PIPE_FORMAT_R64G64B64A64_FLOAT +}; + +static GLuint float_types[4] = { + PIPE_FORMAT_R32_FLOAT, + PIPE_FORMAT_R32G32_FLOAT, + PIPE_FORMAT_R32G32B32_FLOAT, + PIPE_FORMAT_R32G32B32A32_FLOAT +}; + +static GLuint uint_types_norm[4] = { + PIPE_FORMAT_R32_UNORM, + PIPE_FORMAT_R32G32_UNORM, + PIPE_FORMAT_R32G32B32_UNORM, + PIPE_FORMAT_R32G32B32A32_UNORM +}; + +static GLuint uint_types_scale[4] = { + PIPE_FORMAT_R32_USCALED, + PIPE_FORMAT_R32G32_USCALED, + PIPE_FORMAT_R32G32B32_USCALED, + PIPE_FORMAT_R32G32B32A32_USCALED +}; + +static GLuint int_types_norm[4] = { + PIPE_FORMAT_R32_SNORM, + PIPE_FORMAT_R32G32_SNORM, + PIPE_FORMAT_R32G32B32_SNORM, + PIPE_FORMAT_R32G32B32A32_SNORM +}; + +static GLuint int_types_scale[4] = { + PIPE_FORMAT_R32_SSCALED, + PIPE_FORMAT_R32G32_SSCALED, + PIPE_FORMAT_R32G32B32_SSCALED, + PIPE_FORMAT_R32G32B32A32_SSCALED +}; + +static GLuint ushort_types_norm[4] = { + PIPE_FORMAT_R16_UNORM, + PIPE_FORMAT_R16G16_UNORM, + PIPE_FORMAT_R16G16B16_UNORM, + PIPE_FORMAT_R16G16B16A16_UNORM +}; + +static GLuint ushort_types_scale[4] = { + PIPE_FORMAT_R16_USCALED, + PIPE_FORMAT_R16G16_USCALED, + PIPE_FORMAT_R16G16B16_USCALED, + PIPE_FORMAT_R16G16B16A16_USCALED +}; + +static GLuint short_types_norm[4] = { + PIPE_FORMAT_R16_SNORM, + PIPE_FORMAT_R16G16_SNORM, + PIPE_FORMAT_R16G16B16_SNORM, + PIPE_FORMAT_R16G16B16A16_SNORM +}; + +static GLuint short_types_scale[4] = { + PIPE_FORMAT_R16_SSCALED, + PIPE_FORMAT_R16G16_SSCALED, + PIPE_FORMAT_R16G16B16_SSCALED, + PIPE_FORMAT_R16G16B16A16_SSCALED +}; + +static GLuint ubyte_types_norm[4] = { + PIPE_FORMAT_R8_UNORM, + PIPE_FORMAT_R8G8_UNORM, + PIPE_FORMAT_R8G8B8_UNORM, + PIPE_FORMAT_R8G8B8A8_UNORM +}; + +static GLuint ubyte_types_scale[4] = { + PIPE_FORMAT_R8_USCALED, + PIPE_FORMAT_R8G8_USCALED, + PIPE_FORMAT_R8G8B8_USCALED, + PIPE_FORMAT_R8G8B8A8_USCALED +}; + +static GLuint byte_types_norm[4] = { + PIPE_FORMAT_R8_SNORM, + PIPE_FORMAT_R8G8_SNORM, + PIPE_FORMAT_R8G8B8_SNORM, + PIPE_FORMAT_R8G8B8A8_SNORM +}; + +static GLuint byte_types_scale[4] = { + PIPE_FORMAT_R8_SSCALED, + PIPE_FORMAT_R8G8_SSCALED, + PIPE_FORMAT_R8G8B8_SSCALED, + PIPE_FORMAT_R8G8B8A8_SSCALED +}; + +static GLuint fixed_types[4] = { + PIPE_FORMAT_R32_FIXED, + PIPE_FORMAT_R32G32_FIXED, + PIPE_FORMAT_R32G32B32_FIXED, + PIPE_FORMAT_R32G32B32A32_FIXED +}; + + + +/** + * Return a PIPE_FORMAT_x for the given GL datatype and size. + */ +static GLuint +pipe_vertex_format(GLenum type, GLuint size, GLboolean normalized) +{ + assert((type >= GL_BYTE && type <= GL_DOUBLE) || + type == GL_FIXED); + assert(size >= 1); + assert(size <= 4); + + if (normalized) { + switch (type) { + case GL_DOUBLE: return double_types[size-1]; + case GL_FLOAT: return float_types[size-1]; + case GL_INT: return int_types_norm[size-1]; + case GL_SHORT: return short_types_norm[size-1]; + case GL_BYTE: return byte_types_norm[size-1]; + case GL_UNSIGNED_INT: return uint_types_norm[size-1]; + case GL_UNSIGNED_SHORT: return ushort_types_norm[size-1]; + case GL_UNSIGNED_BYTE: return ubyte_types_norm[size-1]; + case GL_FIXED: return fixed_types[size-1]; + default: assert(0); return 0; + } + } + else { + switch (type) { + case GL_DOUBLE: return double_types[size-1]; + case GL_FLOAT: return float_types[size-1]; + case GL_INT: return int_types_scale[size-1]; + case GL_SHORT: return short_types_scale[size-1]; + case GL_BYTE: return byte_types_scale[size-1]; + case GL_UNSIGNED_INT: return uint_types_scale[size-1]; + case GL_UNSIGNED_SHORT: return ushort_types_scale[size-1]; + case GL_UNSIGNED_BYTE: return ubyte_types_scale[size-1]; + case GL_FIXED: return fixed_types[size-1]; + default: assert(0); return 0; + } + } + return 0; /* silence compiler warning */ +} + + +/* + * If edge flags are needed, setup an bitvector of flags and call + * pipe->set_edgeflags(). + * XXX memleak: need to free the returned pointer at some point + */ +static void * +setup_edgeflags(GLcontext *ctx, GLenum primMode, GLint start, GLint count, + const struct gl_client_array *array) +{ + struct pipe_context *pipe = ctx->st->pipe; + + if ((primMode == GL_TRIANGLES || + primMode == GL_QUADS || + primMode == GL_POLYGON) && + (ctx->Polygon.FrontMode != GL_FILL || + ctx->Polygon.BackMode != GL_FILL)) { + /* need edge flags */ + GLint i; + unsigned *vec; + struct st_buffer_object *stobj = st_buffer_object(array->BufferObj); + ubyte *map; + + if (!stobj) + return NULL; + + vec = (unsigned *) calloc(sizeof(unsigned), (count + 31) / 32); + if (!vec) + return NULL; + + map = pipe_buffer_map(pipe->screen, stobj->buffer, PIPE_BUFFER_USAGE_CPU_READ); + map = ADD_POINTERS(map, array->Ptr); + + for (i = 0; i < count; i++) { + if (*((float *) map)) + vec[i/32] |= 1 << (i % 32); + + map += array->StrideB; + } + + pipe_buffer_unmap(pipe->screen, stobj->buffer); + + pipe->set_edgeflags(pipe, vec); + + return vec; + } + else { + /* edge flags not needed */ + pipe->set_edgeflags(pipe, NULL); + return NULL; + } +} + + +/** + * Examine the active arrays to determine if we have interleaved + * vertex arrays all living in one VBO, or all living in user space. + * \param userSpace returns whether the arrays are in user space. + */ +static GLboolean +is_interleaved_arrays(const struct st_vertex_program *vp, + const struct gl_client_array **arrays, + GLboolean *userSpace) +{ + GLuint attr; + const struct gl_buffer_object *firstBufObj = NULL; + GLint firstStride = -1; + GLuint num_client_arrays = 0; + const GLubyte *client_addr = NULL; + + for (attr = 0; attr < vp->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + const struct gl_buffer_object *bufObj = arrays[mesaAttr]->BufferObj; + const GLsizei stride = arrays[mesaAttr]->StrideB; /* in bytes */ + + if (firstStride < 0) { + firstStride = stride; + } + else if (firstStride != stride) { + return GL_FALSE; + } + + if (!bufObj || !bufObj->Name) { + num_client_arrays++; + /* Try to detect if the client-space arrays are + * "close" to each other. + */ + if (!client_addr) { + client_addr = arrays[mesaAttr]->Ptr; + } + else if (abs(arrays[mesaAttr]->Ptr - client_addr) > firstStride) { + /* arrays start too far apart */ + return GL_FALSE; + } + } + else if (!firstBufObj) { + firstBufObj = bufObj; + } + else if (bufObj != firstBufObj) { + return GL_FALSE; + } + } + + *userSpace = (num_client_arrays == vp->num_inputs); + /*printf("user space: %d\n", (int) *userSpace);*/ + + return GL_TRUE; +} + + +/** + * Once we know all the arrays are in user space, this function + * computes the memory range occupied by the arrays. + */ +static void +get_user_arrays_bounds(const struct st_vertex_program *vp, + const struct gl_client_array **arrays, + GLuint max_index, + const GLubyte **low, const GLubyte **high) +{ + const GLubyte *low_addr = NULL; + GLuint attr; + GLint stride; + + for (attr = 0; attr < vp->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + const GLubyte *start = arrays[mesaAttr]->Ptr; + stride = arrays[mesaAttr]->StrideB; + if (attr == 0) { + low_addr = start; + } + else { + low_addr = MIN2(low_addr, start); + } + } + + *low = low_addr; + *high = low_addr + (max_index + 1) * stride; +} + + +/** + * Set up for drawing interleaved arrays that all live in one VBO + * or all live in user space. + * \param vbuffer returns vertex buffer info + * \param velements returns vertex element info + */ +static void +setup_interleaved_attribs(GLcontext *ctx, + const struct st_vertex_program *vp, + const struct gl_client_array **arrays, + GLuint max_index, + GLboolean userSpace, + struct pipe_vertex_buffer *vbuffer, + struct pipe_vertex_element velements[]) +{ + struct pipe_context *pipe = ctx->st->pipe; + GLuint attr; + const GLubyte *offset0; + + for (attr = 0; attr < vp->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; + struct st_buffer_object *stobj = st_buffer_object(bufobj); + GLsizei stride = arrays[mesaAttr]->StrideB; + + /*printf("stobj %u = %p\n", attr, (void*)stobj);*/ + + if (attr == 0) { + if (userSpace) { + const GLubyte *low, *high; + get_user_arrays_bounds(vp, arrays, max_index, &low, &high); + /*printf("user buffer range: %p %p %d\n", low, high, high-low);*/ + vbuffer->buffer = + pipe_user_buffer_create(pipe->screen, (void *) low, high - low); + vbuffer->buffer_offset = 0; + offset0 = low; + } + else { + vbuffer->buffer = NULL; + pipe_buffer_reference(pipe->screen, &vbuffer->buffer, stobj->buffer); + vbuffer->buffer_offset = (unsigned) arrays[mesaAttr]->Ptr; + offset0 = arrays[mesaAttr]->Ptr; + } + vbuffer->pitch = stride; /* in bytes */ + vbuffer->max_index = max_index; + } + + velements[attr].src_offset = + (unsigned) (arrays[mesaAttr]->Ptr - offset0); + velements[attr].vertex_buffer_index = 0; + velements[attr].nr_components = arrays[mesaAttr]->Size; + velements[attr].src_format = + pipe_vertex_format(arrays[mesaAttr]->Type, + arrays[mesaAttr]->Size, + arrays[mesaAttr]->Normalized); + assert(velements[attr].src_format); + } +} + + +/** + * Set up a separate pipe_vertex_buffer and pipe_vertex_element for each + * vertex attribute. + * \param vbuffer returns vertex buffer info + * \param velements returns vertex element info + */ +static void +setup_non_interleaved_attribs(GLcontext *ctx, + const struct st_vertex_program *vp, + const struct gl_client_array **arrays, + GLuint max_index, + struct pipe_vertex_buffer vbuffer[], + struct pipe_vertex_element velements[]) +{ + struct pipe_context *pipe = ctx->st->pipe; + GLuint attr; + + for (attr = 0; attr < vp->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; + GLsizei stride = arrays[mesaAttr]->StrideB; + + if (bufobj && bufobj->Name) { + /* Attribute data is in a VBO. + * Recall that for VBOs, the gl_client_array->Ptr field is + * really an offset from the start of the VBO, not a pointer. + */ + struct st_buffer_object *stobj = st_buffer_object(bufobj); + assert(stobj->buffer); + /*printf("stobj %u = %p\n", attr, (void*) stobj);*/ + + vbuffer[attr].buffer = NULL; + pipe_buffer_reference(pipe->screen, &vbuffer[attr].buffer, stobj->buffer); + vbuffer[attr].buffer_offset = (unsigned) arrays[mesaAttr]->Ptr; + velements[attr].src_offset = 0; + } + else { + /* attribute data is in user-space memory, not a VBO */ + uint bytes; + /*printf("user-space array %d stride %d\n", attr, stride);*/ + + /* wrap user data */ + if (arrays[mesaAttr]->Ptr) { + /* user's vertex array */ + if (arrays[mesaAttr]->StrideB) { + bytes = arrays[mesaAttr]->StrideB * (max_index + 1); + } + else { + bytes = arrays[mesaAttr]->Size + * _mesa_sizeof_type(arrays[mesaAttr]->Type); + } + vbuffer[attr].buffer = pipe_user_buffer_create(pipe->screen, + (void *) arrays[mesaAttr]->Ptr, bytes); + } + else { + /* no array, use ctx->Current.Attrib[] value */ + bytes = sizeof(ctx->Current.Attrib[0]); + vbuffer[attr].buffer = pipe_user_buffer_create(pipe->screen, + (void *) ctx->Current.Attrib[mesaAttr], bytes); + stride = 0; + } + + vbuffer[attr].buffer_offset = 0; + velements[attr].src_offset = 0; + } + + assert(velements[attr].src_offset <= 2048); /* 11-bit field */ + + /* common-case setup */ + vbuffer[attr].pitch = stride; /* in bytes */ + vbuffer[attr].max_index = max_index; + velements[attr].vertex_buffer_index = attr; + velements[attr].nr_components = arrays[mesaAttr]->Size; + velements[attr].src_format + = pipe_vertex_format(arrays[mesaAttr]->Type, + arrays[mesaAttr]->Size, + arrays[mesaAttr]->Normalized); + assert(velements[attr].src_format); + } +} + + + +/** + * Prior to drawing, check that any uniforms referenced by the + * current shader have been set. If a uniform has not been set, + * issue a warning. + */ +static void +check_uniforms(GLcontext *ctx) +{ + const struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; + if (shProg && shProg->LinkStatus) { + GLuint i; + for (i = 0; i < shProg->Uniforms->NumUniforms; i++) { + const struct gl_uniform *u = &shProg->Uniforms->Uniforms[i]; + if (!u->Initialized) { + _mesa_warning(ctx, + "Using shader with uninitialized uniform: %s", + u->Name); + } + } + } +} + + +/** + * This function gets plugged into the VBO module and is called when + * we have something to render. + * Basically, translate the information into the format expected by gallium. + */ +void +st_draw_vbo(GLcontext *ctx, + const struct gl_client_array **arrays, + const struct _mesa_prim *prims, + GLuint nr_prims, + const struct _mesa_index_buffer *ib, + GLuint min_index, + GLuint max_index) +{ + struct pipe_context *pipe = ctx->st->pipe; + const struct st_vertex_program *vp; + const struct pipe_shader_state *vs; + struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS]; + GLuint attr; + struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; + unsigned num_vbuffers, num_velements; + GLboolean userSpace; + + /* sanity check for pointer arithmetic below */ + assert(sizeof(arrays[0]->Ptr[0]) == 1); + + st_validate_state(ctx->st); + + /* must get these after state validation! */ + vp = ctx->st->vp; + vs = &ctx->st->vp->state; + + if (MESA_VERBOSE & VERBOSE_GLSL) { + check_uniforms(ctx); + } + + /* + * Setup the vbuffer[] and velements[] arrays. + */ + if (is_interleaved_arrays(vp, arrays, &userSpace)) { + /*printf("Draw interleaved\n");*/ + setup_interleaved_attribs(ctx, vp, arrays, max_index, userSpace, + vbuffer, velements); + num_vbuffers = 1; + num_velements = vp->num_inputs; + if (num_velements == 0) + num_vbuffers = 0; + } + else { + /*printf("Draw non-interleaved\n");*/ + setup_non_interleaved_attribs(ctx, vp, arrays, max_index, + vbuffer, velements); + num_vbuffers = vp->num_inputs; + num_velements = vp->num_inputs; + } + +#if 0 + { + GLuint i; + for (i = 0; i < num_vbuffers; i++) { + printf("buffers[%d].pitch = %u\n", i, vbuffer[i].pitch); + printf("buffers[%d].max_index = %u\n", i, vbuffer[i].max_index); + printf("buffers[%d].buffer_offset = %u\n", i, vbuffer[i].buffer_offset); + printf("buffers[%d].buffer = %p\n", i, (void*) vbuffer[i].buffer); + } + for (i = 0; i < num_velements; i++) { + printf("vlements[%d].vbuffer_index = %u\n", i, velements[i].vertex_buffer_index); + printf("vlements[%d].src_offset = %u\n", i, velements[i].src_offset); + printf("vlements[%d].nr_comps = %u\n", i, velements[i].nr_components); + printf("vlements[%d].format = %s\n", i, pf_name(velements[i].src_format)); + } + } +#endif + + pipe->set_vertex_buffers(pipe, num_vbuffers, vbuffer); + pipe->set_vertex_elements(pipe, num_velements, velements); + + if (num_vbuffers == 0 || num_velements == 0) + return; + + /* do actual drawing */ + if (ib) { + /* indexed primitive */ + struct gl_buffer_object *bufobj = ib->obj; + struct pipe_buffer *indexBuf = NULL; + unsigned indexSize, indexOffset, i; + + switch (ib->type) { + case GL_UNSIGNED_INT: + indexSize = 4; + break; + case GL_UNSIGNED_SHORT: + indexSize = 2; + break; + case GL_UNSIGNED_BYTE: + indexSize = 1; + break; + default: + assert(0); + return; + } + + /* get/create the index buffer object */ + if (bufobj && bufobj->Name) { + /* elements/indexes are in a real VBO */ + struct st_buffer_object *stobj = st_buffer_object(bufobj); + pipe_buffer_reference(pipe->screen, &indexBuf, stobj->buffer); + indexOffset = (unsigned) ib->ptr / indexSize; + } + else { + /* element/indicies are in user space memory */ + indexBuf = pipe_user_buffer_create(pipe->screen, (void *) ib->ptr, + ib->count * indexSize); + indexOffset = 0; + } + + /* draw */ + if (nr_prims == 1 && pipe->draw_range_elements != NULL) { + i = 0; + + /* XXX: exercise temporary path to pass min/max directly + * through to driver & draw module. These interfaces still + * need a bit of work... + */ + setup_edgeflags(ctx, prims[i].mode, + prims[i].start + indexOffset, prims[i].count, + arrays[VERT_ATTRIB_EDGEFLAG]); + + pipe->draw_range_elements(pipe, indexBuf, indexSize, + min_index, + max_index, + prims[i].mode, + prims[i].start + indexOffset, prims[i].count); + } + else { + for (i = 0; i < nr_prims; i++) { + setup_edgeflags(ctx, prims[i].mode, + prims[i].start + indexOffset, prims[i].count, + arrays[VERT_ATTRIB_EDGEFLAG]); + + pipe->draw_elements(pipe, indexBuf, indexSize, + prims[i].mode, + prims[i].start + indexOffset, prims[i].count); + } + } + + pipe_buffer_reference(pipe->screen, &indexBuf, NULL); + } + else { + /* non-indexed */ + GLuint i; + for (i = 0; i < nr_prims; i++) { + setup_edgeflags(ctx, prims[i].mode, + prims[i].start, prims[i].count, + arrays[VERT_ATTRIB_EDGEFLAG]); + + pipe->draw_arrays(pipe, prims[i].mode, prims[i].start, prims[i].count); + } + } + + /* unreference buffers (frees wrapped user-space buffer objects) */ + for (attr = 0; attr < num_vbuffers; attr++) { + pipe_buffer_reference(pipe->screen, &vbuffer[attr].buffer, NULL); + assert(!vbuffer[attr].buffer); + } + pipe->set_vertex_buffers(pipe, num_vbuffers, vbuffer); +} + + +#if FEATURE_feedback || FEATURE_drawpix + +/** + * Set the (private) draw module's post-transformed vertex format when in + * GL_SELECT or GL_FEEDBACK mode or for glRasterPos. + */ +static void +set_feedback_vertex_format(GLcontext *ctx) +{ +#if 0 + struct st_context *st = ctx->st; + struct vertex_info vinfo; + GLuint i; + + memset(&vinfo, 0, sizeof(vinfo)); + + if (ctx->RenderMode == GL_SELECT) { + assert(ctx->RenderMode == GL_SELECT); + vinfo.num_attribs = 1; + vinfo.format[0] = FORMAT_4F; + vinfo.interp_mode[0] = INTERP_LINEAR; + } + else { + /* GL_FEEDBACK, or glRasterPos */ + /* emit all attribs (pos, color, texcoord) as GLfloat[4] */ + vinfo.num_attribs = st->state.vs->cso->state.num_outputs; + for (i = 0; i < vinfo.num_attribs; i++) { + vinfo.format[i] = FORMAT_4F; + vinfo.interp_mode[i] = INTERP_LINEAR; + } + } + + draw_set_vertex_info(st->draw, &vinfo); +#endif +} + + +/** + * Called by VBO to draw arrays when in selection or feedback mode and + * to implement glRasterPos. + * This is very much like the normal draw_vbo() function above. + * Look at code refactoring some day. + * Might move this into the failover module some day. + */ +void +st_feedback_draw_vbo(GLcontext *ctx, + const struct gl_client_array **arrays, + const struct _mesa_prim *prims, + GLuint nr_prims, + const struct _mesa_index_buffer *ib, + GLuint min_index, + GLuint max_index) +{ + struct st_context *st = ctx->st; + struct pipe_context *pipe = st->pipe; + struct draw_context *draw = st->draw; + const struct st_vertex_program *vp; + const struct pipe_shader_state *vs; + struct pipe_buffer *index_buffer_handle = 0; + struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS]; + struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; + GLuint attr, i; + ubyte *mapped_constants; + + assert(draw); + + st_validate_state(ctx->st); + + /* must get these after state validation! */ + vp = ctx->st->vp; + vs = &st->vp->state; + + if (!st->vp->draw_shader) { + st->vp->draw_shader = draw_create_vertex_shader(draw, vs); + } + + /* + * Set up the draw module's state. + * + * We'd like to do this less frequently, but the normal state-update + * code sends state updates to the pipe, not to our private draw module. + */ + assert(draw); + draw_set_viewport_state(draw, &st->state.viewport); + draw_set_clip_state(draw, &st->state.clip); + draw_set_rasterizer_state(draw, &st->state.rasterizer); + draw_bind_vertex_shader(draw, st->vp->draw_shader); + set_feedback_vertex_format(ctx); + + /* loop over TGSI shader inputs to determine vertex buffer + * and attribute info + */ + for (attr = 0; attr < vp->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; + void *map; + + if (bufobj && bufobj->Name) { + /* Attribute data is in a VBO. + * Recall that for VBOs, the gl_client_array->Ptr field is + * really an offset from the start of the VBO, not a pointer. + */ + struct st_buffer_object *stobj = st_buffer_object(bufobj); + assert(stobj->buffer); + + vbuffers[attr].buffer = NULL; + pipe_buffer_reference(pipe->screen, &vbuffers[attr].buffer, stobj->buffer); + vbuffers[attr].buffer_offset = (unsigned) arrays[0]->Ptr;/* in bytes */ + velements[attr].src_offset = arrays[mesaAttr]->Ptr - arrays[0]->Ptr; + } + else { + /* attribute data is in user-space memory, not a VBO */ + uint bytes = (arrays[mesaAttr]->Size + * _mesa_sizeof_type(arrays[mesaAttr]->Type) + * (max_index + 1)); + + /* wrap user data */ + vbuffers[attr].buffer + = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr, + bytes); + vbuffers[attr].buffer_offset = 0; + velements[attr].src_offset = 0; + } + + /* common-case setup */ + vbuffers[attr].pitch = arrays[mesaAttr]->StrideB; /* in bytes */ + vbuffers[attr].max_index = max_index; + velements[attr].vertex_buffer_index = attr; + velements[attr].nr_components = arrays[mesaAttr]->Size; + velements[attr].src_format = pipe_vertex_format(arrays[mesaAttr]->Type, + arrays[mesaAttr]->Size, + arrays[mesaAttr]->Normalized); + assert(velements[attr].src_format); + + /* tell draw about this attribute */ +#if 0 + draw_set_vertex_buffer(draw, attr, &vbuffer[attr]); +#endif + + /* map the attrib buffer */ + map = pipe_buffer_map(pipe->screen, vbuffers[attr].buffer, + PIPE_BUFFER_USAGE_CPU_READ); + draw_set_mapped_vertex_buffer(draw, attr, map); + } + + draw_set_vertex_buffers(draw, vp->num_inputs, vbuffers); + draw_set_vertex_elements(draw, vp->num_inputs, velements); + + if (ib) { + unsigned indexSize; + struct gl_buffer_object *bufobj = ib->obj; + struct st_buffer_object *stobj = st_buffer_object(bufobj); + void *map; + + index_buffer_handle = stobj->buffer; + + switch (ib->type) { + case GL_UNSIGNED_INT: + indexSize = 4; + break; + case GL_UNSIGNED_SHORT: + indexSize = 2; + break; + default: + assert(0); + return; + } + + map = pipe_buffer_map(pipe->screen, index_buffer_handle, + PIPE_BUFFER_USAGE_CPU_READ); + draw_set_mapped_element_buffer(draw, indexSize, map); + } + else { + /* no index/element buffer */ + draw_set_mapped_element_buffer(draw, 0, NULL); + } + + + /* map constant buffers */ + mapped_constants = pipe_buffer_map(pipe->screen, + st->state.constants[PIPE_SHADER_VERTEX].buffer, + PIPE_BUFFER_USAGE_CPU_READ); + draw_set_mapped_constant_buffer(st->draw, mapped_constants, + st->state.constants[PIPE_SHADER_VERTEX].buffer->size); + + + /* draw here */ + for (i = 0; i < nr_prims; i++) { + draw_arrays(draw, prims[i].mode, prims[i].start, prims[i].count); + } + + + /* unmap constant buffers */ + pipe_buffer_unmap(pipe->screen, st->state.constants[PIPE_SHADER_VERTEX].buffer); + + /* + * unmap vertex/index buffers + */ + for (i = 0; i < PIPE_MAX_ATTRIBS; i++) { + if (draw->pt.vertex_buffer[i].buffer) { + pipe_buffer_unmap(pipe->screen, draw->pt.vertex_buffer[i].buffer); + pipe_buffer_reference(pipe->screen, &draw->pt.vertex_buffer[i].buffer, NULL); + draw_set_mapped_vertex_buffer(draw, i, NULL); + } + } + if (ib) { + pipe_buffer_unmap(pipe->screen, index_buffer_handle); + draw_set_mapped_element_buffer(draw, 0, NULL); + } +} + +#endif /* FEATURE_feedback || FEATURE_drawpix */ + + +void st_init_draw( struct st_context *st ) +{ + GLcontext *ctx = st->ctx; + + vbo_set_draw_func(ctx, st_draw_vbo); +} + + +void st_destroy_draw( struct st_context *st ) +{ +} + + diff --git a/src/mesa/state_tracker/st_draw.h b/src/mesa/state_tracker/st_draw.h new file mode 100644 index 0000000000..c81f2b25da --- /dev/null +++ b/src/mesa/state_tracker/st_draw.h @@ -0,0 +1,62 @@ +/************************************************************************** + * + * Copyright 2004 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + + +#ifndef ST_DRAW_H +#define ST_DRAW_H + +struct _mesa_prim; +struct _mesa_index_buffer; + +void st_init_draw( struct st_context *st ); + +void st_destroy_draw( struct st_context *st ); + +extern void +st_draw_vbo(GLcontext *ctx, + const struct gl_client_array **arrays, + const struct _mesa_prim *prims, + GLuint nr_prims, + const struct _mesa_index_buffer *ib, + GLuint min_index, + GLuint max_index); + +extern void +st_feedback_draw_vbo(GLcontext *ctx, + const struct gl_client_array **arrays, + const struct _mesa_prim *prims, + GLuint nr_prims, + const struct _mesa_index_buffer *ib, + GLuint min_index, + GLuint max_index); + +#endif diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c new file mode 100644 index 0000000000..60fd440ef7 --- /dev/null +++ b/src/mesa/state_tracker/st_extensions.c @@ -0,0 +1,263 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "main/imports.h" +#include "main/context.h" +#include "main/extensions.h" +#include "main/macros.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_screen.h" + +#include "st_context.h" +#include "st_extensions.h" + + +static int _min(int a, int b) +{ + return (a < b) ? a : b; +} + +static float _maxf(float a, float b) +{ + return (a > b) ? a : b; +} + +static int _clamp(int a, int min, int max) +{ + if (a < min) + return min; + else if (a > max) + return max; + else + return a; +} + + +/** + * Query driver to get implementation limits. + * Note that we have to limit/clamp against Mesa's internal limits too. + */ +void st_init_limits(struct st_context *st) +{ + struct pipe_screen *screen = st->pipe->screen; + struct gl_constants *c = &st->ctx->Const; + + c->MaxTextureLevels + = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS), + MAX_TEXTURE_LEVELS); + + c->Max3DTextureLevels + = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_3D_LEVELS), + MAX_3D_TEXTURE_LEVELS); + + c->MaxCubeTextureLevels + = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS), + MAX_CUBE_TEXTURE_LEVELS); + + c->MaxTextureRectSize + = _min(1 << (c->MaxTextureLevels - 1), MAX_TEXTURE_RECT_SIZE); + + c->MaxTextureUnits + = c->MaxTextureImageUnits + = c->MaxTextureCoordUnits + = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS), + MAX_TEXTURE_IMAGE_UNITS); + + c->MaxDrawBuffers + = _clamp(screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS), + 1, MAX_DRAW_BUFFERS); + + c->MaxLineWidth + = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_LINE_WIDTH)); + c->MaxLineWidthAA + = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_LINE_WIDTH_AA)); + + c->MaxPointSize + = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_POINT_WIDTH)); + c->MaxPointSizeAA + = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_POINT_WIDTH_AA)); + + c->MaxTextureMaxAnisotropy + = _maxf(2.0f, screen->get_paramf(screen, PIPE_CAP_MAX_TEXTURE_ANISOTROPY)); + + c->MaxTextureLodBias + = screen->get_paramf(screen, PIPE_CAP_MAX_TEXTURE_LOD_BIAS); + + c->MaxDrawBuffers + = CLAMP(screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS), + 1, MAX_DRAW_BUFFERS); +} + + +/** + * XXX this needs careful review + */ +void st_init_extensions(struct st_context *st) +{ + struct pipe_screen *screen = st->pipe->screen; + GLcontext *ctx = st->ctx; + + /* + * Extensions that are supported by all Gallium drivers: + */ + ctx->Extensions.ARB_multisample = GL_TRUE; /* API support */ + ctx->Extensions.ARB_fragment_program = GL_TRUE; + ctx->Extensions.ARB_texture_border_clamp = GL_TRUE; /* XXX temp */ + ctx->Extensions.ARB_texture_compression = GL_TRUE; /* API support only */ + ctx->Extensions.ARB_texture_cube_map = GL_TRUE; + ctx->Extensions.ARB_texture_env_combine = GL_TRUE; + ctx->Extensions.ARB_texture_env_crossbar = GL_TRUE; + ctx->Extensions.ARB_texture_env_dot3 = GL_TRUE; + ctx->Extensions.ARB_vertex_program = GL_TRUE; + ctx->Extensions.ARB_vertex_buffer_object = GL_TRUE; + + ctx->Extensions.EXT_blend_color = GL_TRUE; + ctx->Extensions.EXT_blend_equation_separate = GL_TRUE; + ctx->Extensions.EXT_blend_func_separate = GL_TRUE; + ctx->Extensions.EXT_blend_logic_op = GL_TRUE; + ctx->Extensions.EXT_blend_minmax = GL_TRUE; + ctx->Extensions.EXT_blend_subtract = GL_TRUE; + ctx->Extensions.EXT_framebuffer_blit = GL_TRUE; + ctx->Extensions.EXT_framebuffer_object = GL_TRUE; + ctx->Extensions.EXT_fog_coord = GL_TRUE; + ctx->Extensions.EXT_multi_draw_arrays = GL_TRUE; + ctx->Extensions.EXT_pixel_buffer_object = GL_TRUE; + ctx->Extensions.EXT_point_parameters = GL_TRUE; + ctx->Extensions.EXT_secondary_color = GL_TRUE; + ctx->Extensions.EXT_stencil_wrap = GL_TRUE; + ctx->Extensions.EXT_texture_env_add = GL_TRUE; + ctx->Extensions.EXT_texture_env_combine = GL_TRUE; + ctx->Extensions.EXT_texture_env_dot3 = GL_TRUE; + ctx->Extensions.EXT_texture_lod_bias = GL_TRUE; + + ctx->Extensions.NV_blend_square = GL_TRUE; + ctx->Extensions.NV_texgen_reflection = GL_TRUE; + + ctx->Extensions.SGI_color_matrix = GL_TRUE; + ctx->Extensions.SGIS_generate_mipmap = GL_TRUE; /* XXX temp */ + + /* + * Extensions that depend on the driver/hardware: + */ + if (screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS) > 0) { + ctx->Extensions.ARB_draw_buffers = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_GLSL)) { + ctx->Extensions.ARB_fragment_shader = GL_TRUE; + ctx->Extensions.ARB_vertex_shader = GL_TRUE; + ctx->Extensions.ARB_shader_objects = GL_TRUE; + ctx->Extensions.ARB_shading_language_100 = GL_TRUE; + ctx->Extensions.ARB_shading_language_120 = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_TEXTURE_MIRROR_REPEAT) > 0) { + ctx->Extensions.ARB_texture_mirrored_repeat = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_TEXTURE_MIRROR_CLAMP) > 0) { + ctx->Extensions.EXT_texture_mirror_clamp = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES)) { + ctx->Extensions.ARB_texture_non_power_of_two = GL_TRUE; + ctx->Extensions.NV_texture_rectangle = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS) > 1) { + ctx->Extensions.ARB_multitexture = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) { + ctx->Extensions.ATI_separate_stencil = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_ANISOTROPIC_FILTER)) { + ctx->Extensions.EXT_texture_filter_anisotropic = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_POINT_SPRITE)) { + ctx->Extensions.ARB_point_sprite = GL_TRUE; + ctx->Extensions.NV_point_sprite = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY)) { + ctx->Extensions.ARB_occlusion_query = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_TEXTURE_SHADOW_MAP)) { + ctx->Extensions.ARB_depth_texture = GL_TRUE; + ctx->Extensions.ARB_shadow = GL_TRUE; + ctx->Extensions.EXT_shadow_funcs = GL_TRUE; + /*ctx->Extensions.ARB_shadow_ambient = GL_TRUE;*/ + } + + /* GL_EXT_packed_depth_stencil requires both the ability to render to + * a depth/stencil buffer and texture from depth/stencil source. + */ + if (screen->is_format_supported(screen, PIPE_FORMAT_Z24S8_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0) && + screen->is_format_supported(screen, PIPE_FORMAT_Z24S8_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, 0)) { + ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE; + } + else if (screen->is_format_supported(screen, PIPE_FORMAT_S8Z24_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0) && + screen->is_format_supported(screen, PIPE_FORMAT_S8Z24_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, 0)) { + ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE; + } + + if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8B8A8_SRGB, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, 0)) { + ctx->Extensions.EXT_texture_sRGB = GL_TRUE; + } + +#if 01 + if (screen->is_format_supported(screen, PIPE_FORMAT_DXT5_RGBA, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, 0)) { + ctx->Extensions.EXT_texture_compression_s3tc = GL_TRUE; + } +#endif + if (screen->is_format_supported(screen, PIPE_FORMAT_YCBCR, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, 0) || + screen->is_format_supported(screen, PIPE_FORMAT_YCBCR_REV, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, 0)) { + ctx->Extensions.MESA_ycbcr_texture = GL_TRUE; + } + +} diff --git a/src/mesa/state_tracker/st_extensions.h b/src/mesa/state_tracker/st_extensions.h new file mode 100644 index 0000000000..2994f16dd3 --- /dev/null +++ b/src/mesa/state_tracker/st_extensions.h @@ -0,0 +1,38 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_EXTENSIONS_H +#define ST_EXTENSIONS_H + + +extern void st_init_limits(struct st_context *st); + +extern void st_init_extensions(struct st_context *st); + + +#endif /* ST_EXTENSIONS_H */ diff --git a/src/mesa/state_tracker/st_format.c b/src/mesa/state_tracker/st_format.c new file mode 100644 index 0000000000..a8ae30a454 --- /dev/null +++ b/src/mesa/state_tracker/st_format.c @@ -0,0 +1,621 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +/** + * Texture Image-related functions. + * \author Brian Paul + */ + +#include "main/imports.h" +#include "main/context.h" +#include "main/texstore.h" +#include "main/texformat.h" +#include "main/enums.h" +#include "main/macros.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_screen.h" +#include "st_context.h" +#include "st_format.h" + +static GLuint +format_bits( + pipe_format_rgbazs_t info, + GLuint comp ) +{ + return pf_get_component_bits( (enum pipe_format) info, comp ); +} + +static GLuint +format_max_bits( + pipe_format_rgbazs_t info ) +{ + GLuint size = format_bits( info, PIPE_FORMAT_COMP_R ); + + size = MAX2( size, format_bits( info, PIPE_FORMAT_COMP_G ) ); + size = MAX2( size, format_bits( info, PIPE_FORMAT_COMP_B ) ); + size = MAX2( size, format_bits( info, PIPE_FORMAT_COMP_A ) ); + size = MAX2( size, format_bits( info, PIPE_FORMAT_COMP_Z ) ); + size = MAX2( size, format_bits( info, PIPE_FORMAT_COMP_S ) ); + return size; +} + +static GLuint +format_size( + pipe_format_rgbazs_t info ) +{ + return + format_bits( info, PIPE_FORMAT_COMP_R ) + + format_bits( info, PIPE_FORMAT_COMP_G ) + + format_bits( info, PIPE_FORMAT_COMP_B ) + + format_bits( info, PIPE_FORMAT_COMP_A ) + + format_bits( info, PIPE_FORMAT_COMP_Z ) + + format_bits( info, PIPE_FORMAT_COMP_S ); +} + +/* + * XXX temporary here + */ +GLboolean +st_get_format_info(enum pipe_format format, struct pipe_format_info *pinfo) +{ + if (pf_layout(format) == PIPE_FORMAT_LAYOUT_RGBAZS) { + pipe_format_rgbazs_t info; + + info = format; + +#if 0 + printf("%s\n", pf_name( format ) ); +#endif + + /* Data type */ + if (format == PIPE_FORMAT_A1R5G5B5_UNORM || format == PIPE_FORMAT_R5G6B5_UNORM) { + pinfo->datatype = GL_UNSIGNED_SHORT; + } + else { + GLuint size; + + size = format_max_bits( info ); + if (size == 8) { + if (pf_type(info) == PIPE_FORMAT_TYPE_UNORM) + pinfo->datatype = GL_UNSIGNED_BYTE; + else + pinfo->datatype = GL_BYTE; + } + else if (size == 16) { + if (pf_type(info) == PIPE_FORMAT_TYPE_UNORM) + pinfo->datatype = GL_UNSIGNED_SHORT; + else + pinfo->datatype = GL_SHORT; + } + else { + assert( size <= 32 ); + if (pf_type(info) == PIPE_FORMAT_TYPE_UNORM) + pinfo->datatype = GL_UNSIGNED_INT; + else + pinfo->datatype = GL_INT; + } + } + + /* Component bits */ + pinfo->red_bits = format_bits( info, PIPE_FORMAT_COMP_R ); + pinfo->green_bits = format_bits( info, PIPE_FORMAT_COMP_G ); + pinfo->blue_bits = format_bits( info, PIPE_FORMAT_COMP_B ); + pinfo->alpha_bits = format_bits( info, PIPE_FORMAT_COMP_A ); + pinfo->depth_bits = format_bits( info, PIPE_FORMAT_COMP_Z ); + pinfo->stencil_bits = format_bits( info, PIPE_FORMAT_COMP_S ); + pinfo->luminance_bits = 0; + pinfo->intensity_bits = 0; + + /* Format size */ + pinfo->size = format_size( info ) / 8; + + /* Luminance & Intensity bits */ + if( pf_swizzle_x(info) == PIPE_FORMAT_COMP_R && + pf_swizzle_y(info) == PIPE_FORMAT_COMP_R && + pf_swizzle_z(info) == PIPE_FORMAT_COMP_R ) { + if( pf_swizzle_w(info) == PIPE_FORMAT_COMP_R ) { + pinfo->intensity_bits = pinfo->red_bits; + } + else { + pinfo->luminance_bits = pinfo->red_bits; + } + pinfo->red_bits = 0; + } + + /* Base format */ + if (pinfo->depth_bits) { + if (pinfo->stencil_bits) { + pinfo->base_format = GL_DEPTH_STENCIL_EXT; + } + else { + pinfo->base_format = GL_DEPTH_COMPONENT; + } + } + else if (pinfo->stencil_bits) { + pinfo->base_format = GL_STENCIL_INDEX; + } + else { + pinfo->base_format = GL_RGBA; + } + } + else if (pf_layout(format) == PIPE_FORMAT_LAYOUT_YCBCR) { + pinfo->base_format = GL_YCBCR_MESA; + pinfo->datatype = GL_UNSIGNED_SHORT; + pinfo->size = 2; /* two bytes per "texel" */ + } + else { + /* compressed format? */ + assert(0); + } + +#if 0 + printf( + "ST_FORMAT: R(%u), G(%u), B(%u), A(%u), Z(%u), S(%u)\n", + pinfo->red_bits, + pinfo->green_bits, + pinfo->blue_bits, + pinfo->alpha_bits, + pinfo->depth_bits, + pinfo->stencil_bits ); +#endif + + pinfo->format = format; + + return GL_TRUE; +} + + +/** + * Return bytes per pixel for the given format. + */ +GLuint +st_sizeof_format(enum pipe_format format) +{ + struct pipe_format_info info; + if (!st_get_format_info( format, &info )) { + assert( 0 ); + return 0; + } + return info.size; +} + + +/** + * Return bytes per pixel for the given format. + */ +GLenum +st_format_datatype(enum pipe_format format) +{ + struct pipe_format_info info; + if (!st_get_format_info( format, &info )) { + assert( 0 ); + return 0; + } + return info.datatype; +} + + +enum pipe_format +st_mesa_format_to_pipe_format(GLuint mesaFormat) +{ + switch (mesaFormat) { + /* fix this */ + case MESA_FORMAT_ARGB8888_REV: + case MESA_FORMAT_ARGB8888: + return PIPE_FORMAT_A8R8G8B8_UNORM; + case MESA_FORMAT_ARGB1555: + return PIPE_FORMAT_A1R5G5B5_UNORM; + case MESA_FORMAT_ARGB4444: + return PIPE_FORMAT_A4R4G4B4_UNORM; + case MESA_FORMAT_RGB565: + return PIPE_FORMAT_R5G6B5_UNORM; + case MESA_FORMAT_AL88: + return PIPE_FORMAT_A8L8_UNORM; + case MESA_FORMAT_A8: + return PIPE_FORMAT_A8_UNORM; + case MESA_FORMAT_L8: + return PIPE_FORMAT_L8_UNORM; + case MESA_FORMAT_I8: + return PIPE_FORMAT_I8_UNORM; + case MESA_FORMAT_Z16: + return PIPE_FORMAT_Z16_UNORM; + case MESA_FORMAT_Z32: + return PIPE_FORMAT_Z32_UNORM; + case MESA_FORMAT_Z24_S8: + return PIPE_FORMAT_Z24S8_UNORM; + case MESA_FORMAT_S8_Z24: + return PIPE_FORMAT_S8Z24_UNORM; + case MESA_FORMAT_YCBCR: + return PIPE_FORMAT_YCBCR; +#if FEATURE_texture_s3tc + case MESA_FORMAT_RGB_DXT1: + return PIPE_FORMAT_DXT1_RGB; + case MESA_FORMAT_RGBA_DXT1: + return PIPE_FORMAT_DXT1_RGBA; + case MESA_FORMAT_RGBA_DXT3: + return PIPE_FORMAT_DXT3_RGBA; + case MESA_FORMAT_RGBA_DXT5: + return PIPE_FORMAT_DXT5_RGBA; +#endif + default: + assert(0); + return 0; + } +} + +/** + * Find an RGBA format supported by the context/winsys. + */ +static enum pipe_format +default_rgba_format(struct pipe_screen *screen, + enum pipe_texture_target target, + unsigned tex_usage, + unsigned geom_flags) +{ + static const enum pipe_format colorFormats[] = { + PIPE_FORMAT_A8R8G8B8_UNORM, + PIPE_FORMAT_B8G8R8A8_UNORM, + PIPE_FORMAT_R8G8B8A8_UNORM, + PIPE_FORMAT_R5G6B5_UNORM + }; + uint i; + for (i = 0; i < Elements(colorFormats); i++) { + if (screen->is_format_supported( screen, colorFormats[i], target, tex_usage, geom_flags )) { + return colorFormats[i]; + } + } + return PIPE_FORMAT_NONE; +} + + +/** + * Search list of formats for first RGBA format with >8 bits/channel. + */ +static enum pipe_format +default_deep_rgba_format(struct pipe_screen *screen, + enum pipe_texture_target target, + unsigned tex_usage, + unsigned geom_flags) +{ + if (screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_SNORM, target, tex_usage, geom_flags)) { + return PIPE_FORMAT_R16G16B16A16_SNORM; + } + if (tex_usage & PIPE_TEXTURE_USAGE_RENDER_TARGET) + return default_rgba_format(screen, target, tex_usage, geom_flags); + else + return PIPE_FORMAT_NONE; +} + + +/** + * Find an Z format supported by the context/winsys. + */ +static enum pipe_format +default_depth_format(struct pipe_screen *screen, + enum pipe_texture_target target, + unsigned tex_usage, + unsigned geom_flags) +{ + static const enum pipe_format zFormats[] = { + PIPE_FORMAT_Z16_UNORM, + PIPE_FORMAT_Z32_UNORM, + PIPE_FORMAT_S8Z24_UNORM, + PIPE_FORMAT_Z24S8_UNORM + }; + uint i; + for (i = 0; i < Elements(zFormats); i++) { + if (screen->is_format_supported( screen, zFormats[i], target, tex_usage, geom_flags )) { + return zFormats[i]; + } + } + return PIPE_FORMAT_NONE; +} + + +/** + * Given an OpenGL internalFormat value for a texture or surface, return + * the best matching PIPE_FORMAT_x, or PIPE_FORMAT_NONE if there's no match. + * \param target one of PIPE_TEXTURE_x + * \param tex_usage either PIPE_TEXTURE_USAGE_RENDER_TARGET + * or PIPE_TEXTURE_USAGE_SAMPLER + */ +enum pipe_format +st_choose_format(struct pipe_context *pipe, GLint internalFormat, + enum pipe_texture_target target, unsigned tex_usage) +{ + struct pipe_screen *screen = pipe->screen; + unsigned geom_flags = 0; + + switch (internalFormat) { + case 4: + case GL_RGBA: + case GL_COMPRESSED_RGBA: + case 3: + case GL_RGB: + case GL_COMPRESSED_RGB: + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + return default_rgba_format( screen, target, tex_usage, geom_flags ); + case GL_RGBA16: + if (tex_usage & PIPE_TEXTURE_USAGE_RENDER_TARGET) + return default_deep_rgba_format( screen, target, tex_usage, geom_flags ); + else + return default_rgba_format( screen, target, tex_usage, geom_flags ); + + case GL_RGBA4: + case GL_RGBA2: + if (screen->is_format_supported( screen, PIPE_FORMAT_A4R4G4B4_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_A4R4G4B4_UNORM; + return default_rgba_format( screen, target, tex_usage, geom_flags ); + + case GL_RGB5_A1: + if (screen->is_format_supported( screen, PIPE_FORMAT_A1R5G5B5_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_A1R5G5B5_UNORM; + return default_rgba_format( screen, target, tex_usage, geom_flags ); + + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + return default_rgba_format( screen, target, tex_usage, geom_flags ); + + case GL_RGB5: + case GL_RGB4: + case GL_R3_G3_B2: + if (screen->is_format_supported( screen, PIPE_FORMAT_A1R5G5B5_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_A1R5G5B5_UNORM; + if (screen->is_format_supported( screen, PIPE_FORMAT_R5G6B5_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_R5G6B5_UNORM; + return default_rgba_format( screen, target, tex_usage, geom_flags ); + + case GL_ALPHA: + case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + case GL_COMPRESSED_ALPHA: + if (screen->is_format_supported( screen, PIPE_FORMAT_A8_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_A8_UNORM; + return default_rgba_format( screen, target, tex_usage, geom_flags ); + + case 1: + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + case GL_COMPRESSED_LUMINANCE: + if (screen->is_format_supported( screen, PIPE_FORMAT_L8_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_L8_UNORM; + return default_rgba_format( screen, target, tex_usage, geom_flags ); + + case 2: + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE4_ALPHA4: + case GL_LUMINANCE6_ALPHA2: + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE12_ALPHA4: + case GL_LUMINANCE12_ALPHA12: + case GL_LUMINANCE16_ALPHA16: + case GL_COMPRESSED_LUMINANCE_ALPHA: + if (screen->is_format_supported( screen, PIPE_FORMAT_A8L8_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_A8L8_UNORM; + return default_rgba_format( screen, target, tex_usage, geom_flags ); + + case GL_INTENSITY: + case GL_INTENSITY4: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + case GL_COMPRESSED_INTENSITY: + if (screen->is_format_supported( screen, PIPE_FORMAT_I8_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_I8_UNORM; + return default_rgba_format( screen, target, tex_usage, geom_flags ); + + case GL_YCBCR_MESA: + if (screen->is_format_supported(screen, PIPE_FORMAT_YCBCR, + target, tex_usage, geom_flags)) { + return PIPE_FORMAT_YCBCR; + } + if (screen->is_format_supported(screen, PIPE_FORMAT_YCBCR_REV, + target, tex_usage, geom_flags)) { + return PIPE_FORMAT_YCBCR_REV; + } + return PIPE_FORMAT_NONE; + + case GL_RGB_S3TC: + case GL_RGB4_S3TC: + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + return PIPE_FORMAT_DXT1_RGB; + + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return PIPE_FORMAT_DXT1_RGBA; + + case GL_RGBA_S3TC: + case GL_RGBA4_S3TC: + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + return PIPE_FORMAT_DXT3_RGBA; + + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + return PIPE_FORMAT_DXT5_RGBA; + +#if 0 + case GL_COMPRESSED_RGB_FXT1_3DFX: + return PIPE_FORMAT_RGB_FXT1; + case GL_COMPRESSED_RGBA_FXT1_3DFX: + return PIPE_FORMAT_RGB_FXT1; +#endif + + case GL_DEPTH_COMPONENT16: + if (screen->is_format_supported( screen, PIPE_FORMAT_Z16_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_Z16_UNORM; + /* fall-through */ + case GL_DEPTH_COMPONENT24: + if (screen->is_format_supported( screen, PIPE_FORMAT_S8Z24_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_S8Z24_UNORM; + if (screen->is_format_supported( screen, PIPE_FORMAT_Z24S8_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_Z24S8_UNORM; + /* fall-through */ + case GL_DEPTH_COMPONENT32: + if (screen->is_format_supported( screen, PIPE_FORMAT_Z32_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_Z32_UNORM; + /* fall-through */ + case GL_DEPTH_COMPONENT: + return default_depth_format( screen, target, tex_usage, geom_flags ); + + case GL_STENCIL_INDEX: + case GL_STENCIL_INDEX1_EXT: + case GL_STENCIL_INDEX4_EXT: + case GL_STENCIL_INDEX8_EXT: + case GL_STENCIL_INDEX16_EXT: + if (screen->is_format_supported( screen, PIPE_FORMAT_S8_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_S8_UNORM; + if (screen->is_format_supported( screen, PIPE_FORMAT_S8Z24_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_S8Z24_UNORM; + if (screen->is_format_supported( screen, PIPE_FORMAT_Z24S8_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_Z24S8_UNORM; + return PIPE_FORMAT_NONE; + + case GL_DEPTH_STENCIL_EXT: + case GL_DEPTH24_STENCIL8_EXT: + if (screen->is_format_supported( screen, PIPE_FORMAT_S8Z24_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_S8Z24_UNORM; + if (screen->is_format_supported( screen, PIPE_FORMAT_Z24S8_UNORM, target, tex_usage, geom_flags )) + return PIPE_FORMAT_Z24S8_UNORM; + return PIPE_FORMAT_NONE; + + default: + return PIPE_FORMAT_NONE; + } +} + + +static GLboolean +is_stencil_format(GLenum format) +{ + switch (format) { + case GL_STENCIL_INDEX: + case GL_STENCIL_INDEX1_EXT: + case GL_STENCIL_INDEX4_EXT: + case GL_STENCIL_INDEX8_EXT: + case GL_STENCIL_INDEX16_EXT: + case GL_DEPTH_STENCIL_EXT: + case GL_DEPTH24_STENCIL8_EXT: + return GL_TRUE; + default: + return GL_FALSE; + } +} + +/** + * Called by FBO code to choose a PIPE_FORMAT_ for drawing surfaces. + */ +enum pipe_format +st_choose_renderbuffer_format(struct pipe_context *pipe, GLint internalFormat) +{ + uint usage; + if (is_stencil_format(internalFormat)) + usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL; + else + usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; + return st_choose_format(pipe, internalFormat, PIPE_TEXTURE_2D, usage); +} + + +static const struct gl_texture_format * +translate_gallium_format_to_mesa_format(enum pipe_format format) +{ + switch (format) { + case PIPE_FORMAT_A8R8G8B8_UNORM: + return &_mesa_texformat_argb8888; + case PIPE_FORMAT_A1R5G5B5_UNORM: + return &_mesa_texformat_argb1555; + case PIPE_FORMAT_A4R4G4B4_UNORM: + return &_mesa_texformat_argb4444; + case PIPE_FORMAT_R5G6B5_UNORM: + return &_mesa_texformat_rgb565; + case PIPE_FORMAT_A8L8_UNORM: + return &_mesa_texformat_al88; + case PIPE_FORMAT_A8_UNORM: + return &_mesa_texformat_a8; + case PIPE_FORMAT_L8_UNORM: + return &_mesa_texformat_l8; + case PIPE_FORMAT_I8_UNORM: + return &_mesa_texformat_i8; + case PIPE_FORMAT_Z16_UNORM: + return &_mesa_texformat_z16; + case PIPE_FORMAT_Z32_UNORM: + return &_mesa_texformat_z32; + case PIPE_FORMAT_Z24S8_UNORM: + return &_mesa_texformat_z24_s8; + case PIPE_FORMAT_S8Z24_UNORM: + return &_mesa_texformat_s8_z24; + case PIPE_FORMAT_YCBCR: + return &_mesa_texformat_ycbcr; + case PIPE_FORMAT_YCBCR_REV: + return &_mesa_texformat_ycbcr_rev; +#if FEATURE_texture_s3tc + case PIPE_FORMAT_DXT1_RGB: + return &_mesa_texformat_rgb_dxt1; + case PIPE_FORMAT_DXT1_RGBA: + return &_mesa_texformat_rgba_dxt1; + case PIPE_FORMAT_DXT3_RGBA: + return &_mesa_texformat_rgba_dxt3; + case PIPE_FORMAT_DXT5_RGBA: + return &_mesa_texformat_rgba_dxt5; +#endif + /* XXX add additional cases */ + default: + assert(0); + return NULL; + } +} + + +/** + * Called via ctx->Driver.chooseTextureFormat(). + */ +const struct gl_texture_format * +st_ChooseTextureFormat(GLcontext *ctx, GLint internalFormat, + GLenum format, GLenum type) +{ + enum pipe_format pFormat; + + (void) format; + (void) type; + + pFormat = st_choose_format(ctx->st->pipe, internalFormat, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER); + if (pFormat == PIPE_FORMAT_NONE) + return NULL; + + return translate_gallium_format_to_mesa_format(pFormat); +} diff --git a/src/mesa/state_tracker/st_format.h b/src/mesa/state_tracker/st_format.h new file mode 100644 index 0000000000..3f5ac3201b --- /dev/null +++ b/src/mesa/state_tracker/st_format.h @@ -0,0 +1,79 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_FORMAT_H +#define ST_FORMAT_H + + +struct pipe_format_info +{ + enum pipe_format format; + GLenum base_format; + GLenum datatype; + GLubyte red_bits; + GLubyte green_bits; + GLubyte blue_bits; + GLubyte alpha_bits; + GLubyte luminance_bits; + GLubyte intensity_bits; + GLubyte depth_bits; + GLubyte stencil_bits; + GLubyte size; /**< in bytes */ +}; + + +GLboolean +st_get_format_info(enum pipe_format format, struct pipe_format_info *pinfo); + + +extern GLuint +st_sizeof_format(enum pipe_format format); + + +extern GLenum +st_format_datatype(enum pipe_format format); + + +extern enum pipe_format +st_mesa_format_to_pipe_format(GLuint mesaFormat); + + +extern enum pipe_format +st_choose_format(struct pipe_context *pipe, GLint internalFormat, + enum pipe_texture_target target, unsigned tex_usage); + +extern enum pipe_format +st_choose_renderbuffer_format(struct pipe_context *pipe, GLint internalFormat); + + +extern const struct gl_texture_format * +st_ChooseTextureFormat(GLcontext * ctx, GLint internalFormat, + GLenum format, GLenum type); + + +#endif /* ST_CB_TEXIMAGE_H */ diff --git a/src/mesa/state_tracker/st_framebuffer.c b/src/mesa/state_tracker/st_framebuffer.c new file mode 100644 index 0000000000..6fd731d209 --- /dev/null +++ b/src/mesa/state_tracker/st_framebuffer.c @@ -0,0 +1,313 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "main/imports.h" +#include "main/buffers.h" +#include "main/context.h" +#include "main/framebuffer.h" +#include "main/matrix.h" +#include "main/renderbuffer.h" +#include "main/scissor.h" +#include "st_public.h" +#include "st_context.h" +#include "st_cb_fbo.h" +#include "pipe/p_defines.h" +#include "pipe/p_context.h" +#include "pipe/p_inlines.h" + + +struct st_framebuffer * +st_create_framebuffer( const __GLcontextModes *visual, + enum pipe_format colorFormat, + enum pipe_format depthFormat, + enum pipe_format stencilFormat, + uint width, uint height, + void *private) +{ + struct st_framebuffer *stfb = CALLOC_STRUCT(st_framebuffer); + if (stfb) { + int samples = st_get_msaa(); + + if (visual->sampleBuffers) + samples = visual->samples; + + _mesa_initialize_framebuffer(&stfb->Base, visual); + + { + /* fake frontbuffer */ + /* XXX allocation should only happen in the unusual case + it's actually needed */ + struct gl_renderbuffer *rb + = st_new_renderbuffer_fb(colorFormat, samples); + _mesa_add_renderbuffer(&stfb->Base, BUFFER_FRONT_LEFT, rb); + } + + if (visual->doubleBufferMode) { + struct gl_renderbuffer *rb + = st_new_renderbuffer_fb(colorFormat, samples); + _mesa_add_renderbuffer(&stfb->Base, BUFFER_BACK_LEFT, rb); + } + + if (depthFormat == stencilFormat && depthFormat != PIPE_FORMAT_NONE) { + /* combined depth/stencil buffer */ + struct gl_renderbuffer *depthStencilRb + = st_new_renderbuffer_fb(depthFormat, samples); + /* note: bind RB to two attachment points */ + _mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthStencilRb); + _mesa_add_renderbuffer(&stfb->Base, BUFFER_STENCIL, depthStencilRb); + } + else { + /* separate depth and/or stencil */ + + if (visual->depthBits == 32) { + /* 32-bit depth buffer */ + struct gl_renderbuffer *depthRb + = st_new_renderbuffer_fb(depthFormat, samples); + _mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthRb); + } + else if (visual->depthBits == 24) { + /* 24-bit depth buffer, ignore stencil bits */ + struct gl_renderbuffer *depthRb + = st_new_renderbuffer_fb(depthFormat, samples); + _mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthRb); + } + else if (visual->depthBits > 0) { + /* 16-bit depth buffer */ + struct gl_renderbuffer *depthRb + = st_new_renderbuffer_fb(depthFormat, samples); + _mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthRb); + } + + if (visual->stencilBits > 0) { + /* 8-bit stencil */ + struct gl_renderbuffer *stencilRb + = st_new_renderbuffer_fb(stencilFormat, samples); + _mesa_add_renderbuffer(&stfb->Base, BUFFER_STENCIL, stencilRb); + } + } + + if (visual->accumRedBits > 0) { + /* 16-bit/channel accum */ + struct gl_renderbuffer *accumRb + = st_new_renderbuffer_fb(DEFAULT_ACCUM_PIPE_FORMAT, 0); /* XXX accum isn't multisampled right? */ + _mesa_add_renderbuffer(&stfb->Base, BUFFER_ACCUM, accumRb); + } + + stfb->Base.Initialized = GL_TRUE; + stfb->InitWidth = width; + stfb->InitHeight = height; + stfb->Private = private; + } + return stfb; +} + + +void st_resize_framebuffer( struct st_framebuffer *stfb, + uint width, uint height ) +{ + if (stfb->Base.Width != width || stfb->Base.Height != height) { + GET_CURRENT_CONTEXT(ctx); + if (ctx) { + if (stfb->InitWidth == 0 && stfb->InitHeight == 0) { + /* didn't have a valid size until now */ + stfb->InitWidth = width; + stfb->InitHeight = height; + if (ctx->Viewport.Width <= 1) { + /* set context's initial viewport/scissor size */ + _mesa_set_viewport(ctx, 0, 0, width, height); + _mesa_set_scissor(ctx, 0, 0, width, height); + } + } + + _mesa_resize_framebuffer(ctx, &stfb->Base, width, height); + + assert(stfb->Base.Width == width); + assert(stfb->Base.Height == height); + } + } +} + + +void st_unreference_framebuffer( struct st_framebuffer *stfb ) +{ + _mesa_unreference_framebuffer((struct gl_framebuffer **) &stfb); +} + + + +/** + * Set/replace a framebuffer surface. + * The user of the state tracker can use this instead of + * st_resize_framebuffer() to provide new surfaces when a window is resized. + */ +void +st_set_framebuffer_surface(struct st_framebuffer *stfb, + uint surfIndex, struct pipe_surface *surf) +{ + static const GLuint invalid_size = 9999999; + struct st_renderbuffer *strb; + GLuint width, height, i; + + assert(surfIndex < BUFFER_COUNT); + + strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer); + + /* fail */ + if (!strb) return; + + /* replace the renderbuffer's surface/texture pointers */ + pipe_surface_reference( &strb->surface, surf ); + pipe_texture_reference( &strb->texture, surf->texture ); + + /* update renderbuffer's width/height */ + strb->Base.Width = surf->width; + strb->Base.Height = surf->height; + + /* Try to update the framebuffer's width/height from the renderbuffer + * sizes. Before we start drawing, all the rbs _should_ be the same size. + */ + width = height = invalid_size; + for (i = 0; i < BUFFER_COUNT; i++) { + if (stfb->Base.Attachment[i].Renderbuffer) { + if (width == invalid_size) { + width = stfb->Base.Attachment[i].Renderbuffer->Width; + height = stfb->Base.Attachment[i].Renderbuffer->Height; + } + else if (width != stfb->Base.Attachment[i].Renderbuffer->Width || + height != stfb->Base.Attachment[i].Renderbuffer->Height) { + /* inconsistant renderbuffer sizes, bail out */ + return; + } + } + } + + if (width != invalid_size) { + /* OK, the renderbuffers are of a consistant size, so update the + * parent framebuffer's size. + */ + stfb->Base.Width = width; + stfb->Base.Height = height; + } +} + + + +/** + * Return the pipe_surface for the given renderbuffer. + */ +struct pipe_surface * +st_get_framebuffer_surface(struct st_framebuffer *stfb, uint surfIndex) +{ + struct st_renderbuffer *strb; + + assert(surfIndex <= ST_SURFACE_DEPTH); + + /* sanity checks, ST tokens should match Mesa tokens */ + assert(ST_SURFACE_FRONT_LEFT == BUFFER_FRONT_LEFT); + assert(ST_SURFACE_BACK_RIGHT == BUFFER_BACK_RIGHT); + + strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer); + if (strb) + return strb->surface; + return NULL; +} + +struct pipe_texture * +st_get_framebuffer_texture(struct st_framebuffer *stfb, uint surfIndex) +{ + struct st_renderbuffer *strb; + + assert(surfIndex <= ST_SURFACE_DEPTH); + + /* sanity checks, ST tokens should match Mesa tokens */ + assert(ST_SURFACE_FRONT_LEFT == BUFFER_FRONT_LEFT); + assert(ST_SURFACE_BACK_RIGHT == BUFFER_BACK_RIGHT); + + strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer); + if (strb) + return strb->texture; + return NULL; +} + +/** + * This function is to be called prior to SwapBuffers on the given + * framebuffer. It checks if the current context is bound to the framebuffer + * and flushes rendering if needed. + */ +void +st_notify_swapbuffers(struct st_framebuffer *stfb) +{ + GET_CURRENT_CONTEXT(ctx); + + if (ctx && ctx->DrawBuffer == &stfb->Base) { + st_flush( ctx->st, + PIPE_FLUSH_RENDER_CACHE | + PIPE_FLUSH_SWAPBUFFERS | + PIPE_FLUSH_FRAME, + NULL ); + ctx->st->frontbuffer_status = FRONT_STATUS_COPY_OF_BACK; + } +} + + +/** + * Quick hack - allows the winsys to inform the driver that surface + * states are now undefined after a glXSwapBuffers or similar. + */ +void +st_notify_swapbuffers_complete(struct st_framebuffer *stfb) +{ + GET_CURRENT_CONTEXT(ctx); + + if (ctx && ctx->DrawBuffer == &stfb->Base) { + struct st_renderbuffer *strb; + int i; + + for (i = 0; i < BUFFER_COUNT; i++) { + if (stfb->Base.Attachment[i].Renderbuffer) { + strb = st_renderbuffer(stfb->Base.Attachment[i].Renderbuffer); + if (strb->surface) + strb->surface->status = PIPE_SURFACE_STATUS_UNDEFINED; + } + } + } +} + + +void *st_framebuffer_private( struct st_framebuffer *stfb ) +{ + return stfb->Private; +} + +void st_get_framebuffer_dimensions( struct st_framebuffer *stfb, + uint *width, + uint *height) +{ + *width = stfb->Base.Width; + *height = stfb->Base.Height; +} diff --git a/src/mesa/state_tracker/st_gen_mipmap.c b/src/mesa/state_tracker/st_gen_mipmap.c new file mode 100644 index 0000000000..a15faf732c --- /dev/null +++ b/src/mesa/state_tracker/st_gen_mipmap.c @@ -0,0 +1,204 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "main/imports.h" +#include "main/mipmap.h" +#include "main/teximage.h" +#include "main/texformat.h" + +#include "shader/prog_instruction.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" +#include "util/u_gen_mipmap.h" + +#include "cso_cache/cso_cache.h" +#include "cso_cache/cso_context.h" + +#include "st_context.h" +#include "st_draw.h" +#include "st_gen_mipmap.h" +#include "st_program.h" +#include "st_texture.h" +#include "st_cb_texture.h" + + +/** + * one-time init for generate mipmap + * XXX Note: there may be other times we need no-op/simple state like this. + * In that case, some code refactoring would be good. + */ +void +st_init_generate_mipmap(struct st_context *st) +{ + st->gen_mipmap = util_create_gen_mipmap(st->pipe, st->cso_context); +} + + +void +st_destroy_generate_mipmap(struct st_context *st) +{ + util_destroy_gen_mipmap(st->gen_mipmap); + st->gen_mipmap = NULL; +} + + +/** + * Generate mipmap levels using hardware rendering. + * \return TRUE if successful, FALSE if not possible + */ +static boolean +st_render_mipmap(struct st_context *st, + GLenum target, + struct pipe_texture *pt, + uint baseLevel, uint lastLevel) +{ + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + const uint face = _mesa_tex_target_to_face(target); + + assert(target != GL_TEXTURE_3D); /* not done yet */ + + /* check if we can render in the texture's format */ + if (!screen->is_format_supported(screen, pt->format, target, + PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)) { + return FALSE; + } + + util_gen_mipmap(st->gen_mipmap, pt, face, baseLevel, lastLevel, + PIPE_TEX_FILTER_LINEAR); + + return TRUE; +} + + +static void +fallback_generate_mipmap(GLcontext *ctx, GLenum target, + struct gl_texture_object *texObj) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_texture *pt = st_get_texobj_texture(texObj); + const uint baseLevel = texObj->BaseLevel; + const uint lastLevel = pt->last_level; + const uint face = _mesa_tex_target_to_face(target), zslice = 0; + uint dstLevel; + GLenum datatype; + GLuint comps; + + assert(target != GL_TEXTURE_3D); /* not done yet */ + + _mesa_format_to_type_and_comps(texObj->Image[face][baseLevel]->TexFormat, + &datatype, &comps); + + for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { + const uint srcLevel = dstLevel - 1; + struct pipe_surface *srcSurf, *dstSurf; + const ubyte *srcData; + ubyte *dstData; + + srcSurf = screen->get_tex_surface(screen, pt, face, srcLevel, zslice, + PIPE_BUFFER_USAGE_CPU_READ); + dstSurf = screen->get_tex_surface(screen, pt, face, dstLevel, zslice, + PIPE_BUFFER_USAGE_CPU_WRITE); + + srcData = (ubyte *) pipe_buffer_map(pipe->screen, srcSurf->buffer, + PIPE_BUFFER_USAGE_CPU_READ) + + srcSurf->offset; + dstData = (ubyte *) pipe_buffer_map(pipe->screen, dstSurf->buffer, + PIPE_BUFFER_USAGE_CPU_WRITE) + + dstSurf->offset; + + _mesa_generate_mipmap_level(target, datatype, comps, + 0 /*border*/, + pt->width[srcLevel], pt->height[srcLevel], pt->depth[srcLevel], + srcData, + srcSurf->stride, /* stride in bytes */ + pt->width[dstLevel], pt->height[dstLevel], pt->depth[dstLevel], + dstData, + dstSurf->stride); /* stride in bytes */ + + pipe_buffer_unmap(pipe->screen, srcSurf->buffer); + pipe_buffer_unmap(pipe->screen, dstSurf->buffer); + + pipe_surface_reference(&srcSurf, NULL); + pipe_surface_reference(&dstSurf, NULL); + } +} + + +void +st_generate_mipmap(GLcontext *ctx, GLenum target, + struct gl_texture_object *texObj) +{ + struct st_context *st = ctx->st; + struct pipe_texture *pt = st_get_texobj_texture(texObj); + const uint baseLevel = texObj->BaseLevel; + const uint lastLevel = pt->last_level; + uint dstLevel; + + if (!st_render_mipmap(st, target, pt, baseLevel, lastLevel)) { + fallback_generate_mipmap(ctx, target, texObj); + } + + /* Fill in the Mesa gl_texture_image fields */ + for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { + const uint srcLevel = dstLevel - 1; + const struct gl_texture_image *srcImage + = _mesa_get_tex_image(ctx, texObj, target, srcLevel); + struct gl_texture_image *dstImage; + struct st_texture_image *stImage; + uint dstWidth = pt->width[dstLevel]; + uint dstHeight = pt->height[dstLevel]; + uint dstDepth = pt->depth[dstLevel]; + uint border = srcImage->Border; + + dstImage = _mesa_get_tex_image(ctx, texObj, target, dstLevel); + if (!dstImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps"); + return; + } + + if (dstImage->ImageOffsets) + _mesa_free(dstImage->ImageOffsets); + + /* Free old image data */ + if (dstImage->Data) + ctx->Driver.FreeTexImageData(ctx, dstImage); + + /* initialize new image */ + _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight, + dstDepth, border, srcImage->InternalFormat); + + dstImage->TexFormat = srcImage->TexFormat; + + stImage = (struct st_texture_image *) dstImage; + pipe_texture_reference(&stImage->pt, pt); + } +} diff --git a/src/mesa/state_tracker/st_gen_mipmap.h b/src/mesa/state_tracker/st_gen_mipmap.h new file mode 100644 index 0000000000..00fbae9302 --- /dev/null +++ b/src/mesa/state_tracker/st_gen_mipmap.h @@ -0,0 +1,46 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_GEN_MIPMAP_H +#define ST_GEN_MIPMAP_H + + +extern void +st_init_generate_mipmap(struct st_context *st); + + +extern void +st_destroy_generate_mipmap(struct st_context *st); + + +extern void +st_generate_mipmap(GLcontext *ctx, GLenum target, + struct gl_texture_object *texObj); + + +#endif /* ST_GEN_MIPMAP_H */ diff --git a/src/mesa/state_tracker/st_mesa_to_tgsi.c b/src/mesa/state_tracker/st_mesa_to_tgsi.c new file mode 100644 index 0000000000..59c1abe488 --- /dev/null +++ b/src/mesa/state_tracker/st_mesa_to_tgsi.c @@ -0,0 +1,1017 @@ +/************************************************************************** + * + * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* + * \author + * Michal Krol + */ + +#include "pipe/p_compiler.h" +#include "pipe/p_shader_tokens.h" +#include "tgsi/tgsi_parse.h" +#include "tgsi/tgsi_build.h" +#include "tgsi/tgsi_util.h" +#include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_sanity.h" +#include "st_mesa_to_tgsi.h" +#include "shader/prog_instruction.h" +#include "shader/prog_parameter.h" +#include "shader/prog_print.h" +#include "pipe/p_debug.h" + +/* + * Map mesa register file to TGSI register file. + */ +static GLuint +map_register_file( + enum register_file file, + GLuint index, + const GLuint immediateMapping[], + GLboolean indirectAccess ) +{ + switch( file ) { + case PROGRAM_UNDEFINED: + return TGSI_FILE_NULL; + case PROGRAM_TEMPORARY: + return TGSI_FILE_TEMPORARY; + /*case PROGRAM_LOCAL_PARAM:*/ + /*case PROGRAM_ENV_PARAM:*/ + + /* Because of the longstanding problem with mesa arb shaders + * where constants, immediates and state variables are all + * bundled together as PROGRAM_STATE_VAR, we can't tell from the + * mesa register file whether this is a CONSTANT or an + * IMMEDIATE, hence we need all the other information. + */ + case PROGRAM_STATE_VAR: + case PROGRAM_NAMED_PARAM: + case PROGRAM_UNIFORM: + if (!indirectAccess && immediateMapping && immediateMapping[index] != ~0) + return TGSI_FILE_IMMEDIATE; + else + return TGSI_FILE_CONSTANT; + case PROGRAM_CONSTANT: + if (indirectAccess) + return TGSI_FILE_CONSTANT; + assert(immediateMapping[index] != ~0); + return TGSI_FILE_IMMEDIATE; + case PROGRAM_INPUT: + return TGSI_FILE_INPUT; + case PROGRAM_OUTPUT: + return TGSI_FILE_OUTPUT; + case PROGRAM_ADDRESS: + return TGSI_FILE_ADDRESS; + default: + assert( 0 ); + return TGSI_FILE_NULL; + } +} + +/** + * Map mesa register file index to TGSI index. + * Take special care when processing input and output indices. + * \param file one of TGSI_FILE_x + * \param index the mesa register file index + * \param inputMapping maps Mesa input indexes to TGSI input indexes + * \param outputMapping maps Mesa output indexes to TGSI output indexes + */ +static GLuint +map_register_file_index( + GLuint file, + GLuint index, + const GLuint inputMapping[], + const GLuint outputMapping[], + const GLuint immediateMapping[], + GLboolean indirectAccess ) +{ + switch( file ) { + case TGSI_FILE_INPUT: + /* inputs are mapped according to the user-defined map */ + return inputMapping[index]; + + case TGSI_FILE_OUTPUT: + return outputMapping[index]; + + case TGSI_FILE_IMMEDIATE: + if (indirectAccess) + return index; + assert(immediateMapping[index] != ~0); + return immediateMapping[index]; + + default: + return index; + } +} + +/* + * Map mesa texture target to TGSI texture target. + */ +static GLuint +map_texture_target( + GLuint textarget ) +{ + switch( textarget ) { + case TEXTURE_1D_INDEX: + return TGSI_TEXTURE_1D; + case TEXTURE_2D_INDEX: + return TGSI_TEXTURE_2D; + case TEXTURE_3D_INDEX: + return TGSI_TEXTURE_3D; + case TEXTURE_CUBE_INDEX: + return TGSI_TEXTURE_CUBE; + case TEXTURE_RECT_INDEX: + return TGSI_TEXTURE_RECT; + default: + assert( 0 ); + } + + return TGSI_TEXTURE_1D; +} + +static GLuint +convert_sat( + GLuint sat ) +{ + switch( sat ) { + case SATURATE_OFF: + return TGSI_SAT_NONE; + case SATURATE_ZERO_ONE: + return TGSI_SAT_ZERO_ONE; + case SATURATE_PLUS_MINUS_ONE: + return TGSI_SAT_MINUS_PLUS_ONE; + default: + assert( 0 ); + return TGSI_SAT_NONE; + } +} + +static GLuint +convert_writemask( + GLuint writemask ) +{ + assert( WRITEMASK_X == TGSI_WRITEMASK_X ); + assert( WRITEMASK_Y == TGSI_WRITEMASK_Y ); + assert( WRITEMASK_Z == TGSI_WRITEMASK_Z ); + assert( WRITEMASK_W == TGSI_WRITEMASK_W ); + assert( (writemask & ~TGSI_WRITEMASK_XYZW) == 0 ); + + return writemask; +} + +static struct tgsi_full_immediate +make_immediate(const float *value, uint size) +{ + struct tgsi_full_immediate imm; + + imm = tgsi_default_full_immediate(); + imm.Immediate.Size += size; + imm.Immediate.DataType = TGSI_IMM_FLOAT32; + imm.u.Pointer = value; + return imm; +} + +static void +compile_instruction( + const struct prog_instruction *inst, + struct tgsi_full_instruction *fullinst, + const GLuint inputMapping[], + const GLuint outputMapping[], + const GLuint immediateMapping[], + GLboolean indirectAccess, + GLuint preamble_size, + GLuint processor, + GLboolean *insideSubroutine) +{ + GLuint i; + struct tgsi_full_dst_register *fulldst; + struct tgsi_full_src_register *fullsrc; + + *fullinst = tgsi_default_full_instruction(); + + fullinst->Instruction.Saturate = convert_sat( inst->SaturateMode ); + fullinst->Instruction.NumDstRegs = _mesa_num_inst_dst_regs( inst->Opcode ); + fullinst->Instruction.NumSrcRegs = _mesa_num_inst_src_regs( inst->Opcode ); + + fulldst = &fullinst->FullDstRegisters[0]; + fulldst->DstRegister.File = map_register_file( inst->DstReg.File, 0, NULL, GL_FALSE ); + fulldst->DstRegister.Index = map_register_file_index( + fulldst->DstRegister.File, + inst->DstReg.Index, + inputMapping, + outputMapping, + NULL, + GL_FALSE ); + fulldst->DstRegister.WriteMask = convert_writemask( inst->DstReg.WriteMask ); + + for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) { + GLuint j; + + fullsrc = &fullinst->FullSrcRegisters[i]; + fullsrc->SrcRegister.File = map_register_file( + inst->SrcReg[i].File, + inst->SrcReg[i].Index, + immediateMapping, + indirectAccess ); + fullsrc->SrcRegister.Index = map_register_file_index( + fullsrc->SrcRegister.File, + inst->SrcReg[i].Index, + inputMapping, + outputMapping, + immediateMapping, + indirectAccess ); + + + /* swizzle (ext swizzle also depends on negation) */ + { + GLuint swz[4]; + GLboolean extended = (inst->SrcReg[i].NegateBase != NEGATE_NONE && + inst->SrcReg[i].NegateBase != NEGATE_XYZW); + for( j = 0; j < 4; j++ ) { + swz[j] = GET_SWZ( inst->SrcReg[i].Swizzle, j ); + if (swz[j] > SWIZZLE_W) + extended = GL_TRUE; + } + if (extended) { + for (j = 0; j < 4; j++) { + tgsi_util_set_src_register_extswizzle(&fullsrc->SrcRegisterExtSwz, + swz[j], j); + } + } + else { + for (j = 0; j < 4; j++) { + tgsi_util_set_src_register_swizzle(&fullsrc->SrcRegister, + swz[j], j); + } + } + } + + if( inst->SrcReg[i].NegateBase == NEGATE_XYZW ) { + fullsrc->SrcRegister.Negate = 1; + } + else if( inst->SrcReg[i].NegateBase != NEGATE_NONE ) { + if( inst->SrcReg[i].NegateBase & NEGATE_X ) { + fullsrc->SrcRegisterExtSwz.NegateX = 1; + } + if( inst->SrcReg[i].NegateBase & NEGATE_Y ) { + fullsrc->SrcRegisterExtSwz.NegateY = 1; + } + if( inst->SrcReg[i].NegateBase & NEGATE_Z ) { + fullsrc->SrcRegisterExtSwz.NegateZ = 1; + } + if( inst->SrcReg[i].NegateBase & NEGATE_W ) { + fullsrc->SrcRegisterExtSwz.NegateW = 1; + } + } + + if( inst->SrcReg[i].Abs ) { + fullsrc->SrcRegisterExtMod.Absolute = 1; + } + + if( inst->SrcReg[i].NegateAbs ) { + fullsrc->SrcRegisterExtMod.Negate = 1; + } + + if( inst->SrcReg[i].RelAddr ) { + fullsrc->SrcRegister.Indirect = 1; + + fullsrc->SrcRegisterInd.File = TGSI_FILE_ADDRESS; + fullsrc->SrcRegisterInd.Index = 0; + } + } + + switch( inst->Opcode ) { + case OPCODE_ARL: + fullinst->Instruction.Opcode = TGSI_OPCODE_ARL; + break; + case OPCODE_ABS: + fullinst->Instruction.Opcode = TGSI_OPCODE_ABS; + break; + case OPCODE_ADD: + fullinst->Instruction.Opcode = TGSI_OPCODE_ADD; + break; + case OPCODE_BGNLOOP: + fullinst->Instruction.Opcode = TGSI_OPCODE_BGNLOOP2; + fullinst->InstructionExtLabel.Label = inst->BranchTarget + preamble_size; + break; + case OPCODE_BGNSUB: + fullinst->Instruction.Opcode = TGSI_OPCODE_BGNSUB; + *insideSubroutine = GL_TRUE; + break; + case OPCODE_BRA: + fullinst->Instruction.Opcode = TGSI_OPCODE_BRA; + break; + case OPCODE_BRK: + fullinst->Instruction.Opcode = TGSI_OPCODE_BRK; + break; + case OPCODE_CAL: + fullinst->Instruction.Opcode = TGSI_OPCODE_CAL; + fullinst->InstructionExtLabel.Label = inst->BranchTarget + preamble_size; + break; + case OPCODE_CMP: + fullinst->Instruction.Opcode = TGSI_OPCODE_CMP; + break; + case OPCODE_CONT: + fullinst->Instruction.Opcode = TGSI_OPCODE_CONT; + break; + case OPCODE_COS: + fullinst->Instruction.Opcode = TGSI_OPCODE_COS; + break; + case OPCODE_DDX: + fullinst->Instruction.Opcode = TGSI_OPCODE_DDX; + break; + case OPCODE_DDY: + fullinst->Instruction.Opcode = TGSI_OPCODE_DDY; + break; + case OPCODE_DP2: + fullinst->Instruction.Opcode = TGSI_OPCODE_DP2; + break; + case OPCODE_DP2A: + fullinst->Instruction.Opcode = TGSI_OPCODE_DP2A; + break; + case OPCODE_DP3: + fullinst->Instruction.Opcode = TGSI_OPCODE_DP3; + break; + case OPCODE_DP4: + fullinst->Instruction.Opcode = TGSI_OPCODE_DP4; + break; + case OPCODE_DPH: + fullinst->Instruction.Opcode = TGSI_OPCODE_DPH; + break; + case OPCODE_DST: + fullinst->Instruction.Opcode = TGSI_OPCODE_DST; + break; + case OPCODE_ELSE: + fullinst->Instruction.Opcode = TGSI_OPCODE_ELSE; + fullinst->InstructionExtLabel.Label = inst->BranchTarget + preamble_size; + break; + case OPCODE_ENDIF: + fullinst->Instruction.Opcode = TGSI_OPCODE_ENDIF; + break; + case OPCODE_ENDLOOP: + fullinst->Instruction.Opcode = TGSI_OPCODE_ENDLOOP2; + fullinst->InstructionExtLabel.Label = inst->BranchTarget + preamble_size; + break; + case OPCODE_ENDSUB: + fullinst->Instruction.Opcode = TGSI_OPCODE_ENDSUB; + *insideSubroutine = GL_FALSE; + break; + case OPCODE_EX2: + fullinst->Instruction.Opcode = TGSI_OPCODE_EX2; + break; + case OPCODE_EXP: + fullinst->Instruction.Opcode = TGSI_OPCODE_EXP; + break; + case OPCODE_FLR: + fullinst->Instruction.Opcode = TGSI_OPCODE_FLR; + break; + case OPCODE_FRC: + fullinst->Instruction.Opcode = TGSI_OPCODE_FRC; + break; + case OPCODE_IF: + fullinst->Instruction.Opcode = TGSI_OPCODE_IF; + fullinst->InstructionExtLabel.Label = inst->BranchTarget + preamble_size; + break; + case OPCODE_TRUNC: + fullinst->Instruction.Opcode = TGSI_OPCODE_TRUNC; + break; + case OPCODE_KIL: + /* conditional */ + fullinst->Instruction.Opcode = TGSI_OPCODE_KIL; + break; + case OPCODE_KIL_NV: + /* predicated */ + assert(inst->DstReg.CondMask == COND_TR); + fullinst->Instruction.Opcode = TGSI_OPCODE_KILP; + break; + case OPCODE_LG2: + fullinst->Instruction.Opcode = TGSI_OPCODE_LG2; + break; + case OPCODE_LOG: + fullinst->Instruction.Opcode = TGSI_OPCODE_LOG; + break; + case OPCODE_LIT: + fullinst->Instruction.Opcode = TGSI_OPCODE_LIT; + break; + case OPCODE_LRP: + fullinst->Instruction.Opcode = TGSI_OPCODE_LRP; + break; + case OPCODE_MAD: + fullinst->Instruction.Opcode = TGSI_OPCODE_MAD; + break; + case OPCODE_MAX: + fullinst->Instruction.Opcode = TGSI_OPCODE_MAX; + break; + case OPCODE_MIN: + fullinst->Instruction.Opcode = TGSI_OPCODE_MIN; + break; + case OPCODE_MOV: + fullinst->Instruction.Opcode = TGSI_OPCODE_MOV; + break; + case OPCODE_MUL: + fullinst->Instruction.Opcode = TGSI_OPCODE_MUL; + break; + case OPCODE_NOISE1: + fullinst->Instruction.Opcode = TGSI_OPCODE_NOISE1; + break; + case OPCODE_NOISE2: + fullinst->Instruction.Opcode = TGSI_OPCODE_NOISE2; + break; + case OPCODE_NOISE3: + fullinst->Instruction.Opcode = TGSI_OPCODE_NOISE3; + break; + case OPCODE_NOISE4: + fullinst->Instruction.Opcode = TGSI_OPCODE_NOISE4; + break; + case OPCODE_NOP: + fullinst->Instruction.Opcode = TGSI_OPCODE_NOP; + break; + case OPCODE_NRM3: + fullinst->Instruction.Opcode = TGSI_OPCODE_NRM; + break; + case OPCODE_NRM4: + fullinst->Instruction.Opcode = TGSI_OPCODE_NRM4; + break; + case OPCODE_POW: + fullinst->Instruction.Opcode = TGSI_OPCODE_POW; + break; + case OPCODE_RCP: + fullinst->Instruction.Opcode = TGSI_OPCODE_RCP; + break; + case OPCODE_RET: + /* If RET is used inside main (not a real subroutine) we may want + * to execute END instead of RET. TBD... + */ + if (1 /* *insideSubroutine */) { + fullinst->Instruction.Opcode = TGSI_OPCODE_RET; + } + else { + /* inside main() pseudo-function */ + fullinst->Instruction.Opcode = TGSI_OPCODE_END; + } + break; + case OPCODE_RSQ: + fullinst->Instruction.Opcode = TGSI_OPCODE_RSQ; + tgsi_util_set_full_src_register_sign_mode( + &fullinst->FullSrcRegisters[0], + TGSI_UTIL_SIGN_CLEAR ); + break; + case OPCODE_SCS: + fullinst->Instruction.Opcode = TGSI_OPCODE_SCS; + fulldst->DstRegister.WriteMask &= TGSI_WRITEMASK_XY; + break; + case OPCODE_SEQ: + fullinst->Instruction.Opcode = TGSI_OPCODE_SEQ; + break; + case OPCODE_SGE: + fullinst->Instruction.Opcode = TGSI_OPCODE_SGE; + break; + case OPCODE_SGT: + fullinst->Instruction.Opcode = TGSI_OPCODE_SGT; + break; + case OPCODE_SIN: + fullinst->Instruction.Opcode = TGSI_OPCODE_SIN; + break; + case OPCODE_SLE: + fullinst->Instruction.Opcode = TGSI_OPCODE_SLE; + break; + case OPCODE_SLT: + fullinst->Instruction.Opcode = TGSI_OPCODE_SLT; + break; + case OPCODE_SNE: + fullinst->Instruction.Opcode = TGSI_OPCODE_SNE; + break; + case OPCODE_SSG: + fullinst->Instruction.Opcode = TGSI_OPCODE_SSG; + break; + case OPCODE_SUB: + fullinst->Instruction.Opcode = TGSI_OPCODE_SUB; + break; + case OPCODE_SWZ: + fullinst->Instruction.Opcode = TGSI_OPCODE_SWZ; + break; + case OPCODE_TEX: + /* ordinary texture lookup */ + fullinst->Instruction.Opcode = TGSI_OPCODE_TEX; + fullinst->Instruction.NumSrcRegs = 2; + fullinst->InstructionExtTexture.Texture = map_texture_target( inst->TexSrcTarget ); + fullinst->FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_SAMPLER; + fullinst->FullSrcRegisters[1].SrcRegister.Index = inst->TexSrcUnit; + break; + case OPCODE_TXB: + /* texture lookup with LOD bias */ + fullinst->Instruction.Opcode = TGSI_OPCODE_TXB; + fullinst->Instruction.NumSrcRegs = 2; + fullinst->InstructionExtTexture.Texture = map_texture_target( inst->TexSrcTarget ); + fullinst->FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_SAMPLER; + fullinst->FullSrcRegisters[1].SrcRegister.Index = inst->TexSrcUnit; + break; + case OPCODE_TXD: + /* texture lookup with explicit partial derivatives */ + fullinst->Instruction.Opcode = TGSI_OPCODE_TXD; + fullinst->Instruction.NumSrcRegs = 4; + fullinst->InstructionExtTexture.Texture = map_texture_target( inst->TexSrcTarget ); + /* src[0] = coord, src[1] = d[strq]/dx, src[2] = d[strq]/dy */ + fullinst->FullSrcRegisters[3].SrcRegister.File = TGSI_FILE_SAMPLER; + fullinst->FullSrcRegisters[3].SrcRegister.Index = inst->TexSrcUnit; + break; + case OPCODE_TXL: + /* texture lookup with explicit LOD */ + fullinst->Instruction.Opcode = TGSI_OPCODE_TXL; + fullinst->Instruction.NumSrcRegs = 2; + fullinst->InstructionExtTexture.Texture = map_texture_target( inst->TexSrcTarget ); + fullinst->FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_SAMPLER; + fullinst->FullSrcRegisters[1].SrcRegister.Index = inst->TexSrcUnit; + break; + case OPCODE_TXP: + /* texture lookup with divide by Q component */ + /* convert to TEX w/ special flag for division */ + fullinst->Instruction.Opcode = TGSI_OPCODE_TXP; + fullinst->Instruction.NumSrcRegs = 2; + fullinst->InstructionExtTexture.Texture = map_texture_target( inst->TexSrcTarget ); + fullinst->FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_SAMPLER; + fullinst->FullSrcRegisters[1].SrcRegister.Index = inst->TexSrcUnit; + break; + case OPCODE_XPD: + fullinst->Instruction.Opcode = TGSI_OPCODE_XPD; + fulldst->DstRegister.WriteMask &= TGSI_WRITEMASK_XYZ; + break; + case OPCODE_END: + fullinst->Instruction.Opcode = TGSI_OPCODE_END; + break; + default: + assert( 0 ); + } +} + +/** + * \param usage_mask bitfield of TGSI_WRITEMASK_{XYZW} tokens + */ +static struct tgsi_full_declaration +make_input_decl( + GLuint index, + GLboolean interpolate_info, + GLuint interpolate, + GLuint usage_mask, + GLboolean semantic_info, + GLuint semantic_name, + GLbitfield semantic_index ) +{ + struct tgsi_full_declaration decl; + + assert(semantic_name < TGSI_SEMANTIC_COUNT); + + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_INPUT; + decl.Declaration.UsageMask = usage_mask; + decl.Declaration.Semantic = semantic_info; + decl.DeclarationRange.First = index; + decl.DeclarationRange.Last = index; + if (semantic_info) { + decl.Semantic.SemanticName = semantic_name; + decl.Semantic.SemanticIndex = semantic_index; + } + if (interpolate_info) { + decl.Declaration.Interpolate = interpolate; + } + + return decl; +} + +/** + * \param usage_mask bitfield of TGSI_WRITEMASK_{XYZW} tokens + */ +static struct tgsi_full_declaration +make_output_decl( + GLuint index, + GLuint semantic_name, + GLuint semantic_index, + GLbitfield usage_mask ) +{ + struct tgsi_full_declaration decl; + + assert(semantic_name < TGSI_SEMANTIC_COUNT); + + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_OUTPUT; + decl.Declaration.UsageMask = usage_mask; + decl.Declaration.Semantic = 1; + decl.DeclarationRange.First = index; + decl.DeclarationRange.Last = index; + decl.Semantic.SemanticName = semantic_name; + decl.Semantic.SemanticIndex = semantic_index; + + return decl; +} + + +static struct tgsi_full_declaration +make_temp_decl( + GLuint start_index, + GLuint end_index ) +{ + struct tgsi_full_declaration decl; + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_TEMPORARY; + decl.DeclarationRange.First = start_index; + decl.DeclarationRange.Last = end_index; + return decl; +} + +static struct tgsi_full_declaration +make_addr_decl( + GLuint start_index, + GLuint end_index ) +{ + struct tgsi_full_declaration decl; + + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_ADDRESS; + decl.DeclarationRange.First = start_index; + decl.DeclarationRange.Last = end_index; + return decl; +} + +static struct tgsi_full_declaration +make_sampler_decl(GLuint index) +{ + struct tgsi_full_declaration decl; + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_SAMPLER; + decl.DeclarationRange.First = index; + decl.DeclarationRange.Last = index; + return decl; +} + +/** Reference into a constant buffer */ +static struct tgsi_full_declaration +make_constant_decl(GLuint first, GLuint last) +{ + struct tgsi_full_declaration decl; + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_CONSTANT; + decl.DeclarationRange.First = first; + decl.DeclarationRange.Last = last; + return decl; +} + + + +/** + * Find the temporaries which are used in the given program. + */ +static void +find_temporaries(const struct gl_program *program, + GLboolean tempsUsed[MAX_PROGRAM_TEMPS]) +{ + GLuint i, j; + + for (i = 0; i < MAX_PROGRAM_TEMPS; i++) + tempsUsed[i] = GL_FALSE; + + for (i = 0; i < program->NumInstructions; i++) { + const struct prog_instruction *inst = program->Instructions + i; + const GLuint n = _mesa_num_inst_src_regs( inst->Opcode ); + for (j = 0; j < n; j++) { + if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) + tempsUsed[inst->SrcReg[j].Index] = GL_TRUE; + if (inst->DstReg.File == PROGRAM_TEMPORARY) + tempsUsed[inst->DstReg.Index] = GL_TRUE; + } + } +} + + + + +/** + * Translate Mesa program to TGSI format. + * \param program the program to translate + * \param numInputs number of input registers used + * \param inputMapping maps Mesa fragment program inputs to TGSI generic + * input indexes + * \param inputSemanticName the TGSI_SEMANTIC flag for each input + * \param inputSemanticIndex the semantic index (ex: which texcoord) for each input + * \param interpMode the TGSI_INTERPOLATE_LINEAR/PERSP mode for each input + + * \param numOutputs number of output registers used + * \param outputMapping maps Mesa fragment program outputs to TGSI + * generic outputs + * \param outputSemanticName the TGSI_SEMANTIC flag for each output + * \param outputSemanticIndex the semantic index (ex: which texcoord) for each output + * \param tokens array to store translated tokens in + * \param maxTokens size of the tokens array + * + * \return number of tokens placed in 'tokens' buffer, or zero if error + */ +GLuint +st_translate_mesa_program( + uint procType, + const struct gl_program *program, + GLuint numInputs, + const GLuint inputMapping[], + const ubyte inputSemanticName[], + const ubyte inputSemanticIndex[], + const GLuint interpMode[], + GLuint numOutputs, + const GLuint outputMapping[], + const ubyte outputSemanticName[], + const ubyte outputSemanticIndex[], + struct tgsi_token *tokens, + GLuint maxTokens ) +{ + GLuint i; + GLuint ti; /* token index */ + struct tgsi_header *header; + struct tgsi_processor *processor; + struct tgsi_full_instruction fullinst; + GLuint preamble_size = 0; + GLuint immediates[1000]; + GLuint numImmediates = 0; + GLboolean insideSubroutine = GL_FALSE; + GLboolean indirectAccess = GL_FALSE; + + assert(procType == TGSI_PROCESSOR_FRAGMENT || + procType == TGSI_PROCESSOR_VERTEX); + + *(struct tgsi_version *) &tokens[0] = tgsi_build_version(); + + header = (struct tgsi_header *) &tokens[1]; + *header = tgsi_build_header(); + + processor = (struct tgsi_processor *) &tokens[2]; + *processor = tgsi_build_processor( procType, header ); + + ti = 3; + + /* + * Declare input attributes. + */ + if (procType == TGSI_PROCESSOR_FRAGMENT) { + for (i = 0; i < numInputs; i++) { + struct tgsi_full_declaration fulldecl; + fulldecl = make_input_decl(i, + GL_TRUE, interpMode[i], + TGSI_WRITEMASK_XYZW, + GL_TRUE, inputSemanticName[i], + inputSemanticIndex[i]); + ti += tgsi_build_full_declaration(&fulldecl, + &tokens[ti], + header, + maxTokens - ti ); + } + } + else { + /* vertex prog */ + /* XXX: this could probaby be merged with the clause above. + * the only difference is the semantic tags. + */ + for (i = 0; i < numInputs; i++) { + struct tgsi_full_declaration fulldecl; + fulldecl = make_input_decl(i, + GL_FALSE, 0, + TGSI_WRITEMASK_XYZW, + GL_FALSE, 0, 0); + ti += tgsi_build_full_declaration(&fulldecl, + &tokens[ti], + header, + maxTokens - ti ); + } + } + + /* + * Declare output attributes. + */ + if (procType == TGSI_PROCESSOR_FRAGMENT) { + for (i = 0; i < numOutputs; i++) { + struct tgsi_full_declaration fulldecl; + switch (outputSemanticName[i]) { + case TGSI_SEMANTIC_POSITION: + fulldecl = make_output_decl(i, + TGSI_SEMANTIC_POSITION, /* Z / Depth */ + outputSemanticIndex[i], + TGSI_WRITEMASK_Z ); + break; + case TGSI_SEMANTIC_COLOR: + fulldecl = make_output_decl(i, + TGSI_SEMANTIC_COLOR, + outputSemanticIndex[i], + TGSI_WRITEMASK_XYZW ); + break; + default: + assert(0); + return 0; + } + ti += tgsi_build_full_declaration(&fulldecl, + &tokens[ti], + header, + maxTokens - ti ); + } + } + else { + /* vertex prog */ + for (i = 0; i < numOutputs; i++) { + struct tgsi_full_declaration fulldecl; + fulldecl = make_output_decl(i, + outputSemanticName[i], + outputSemanticIndex[i], + TGSI_WRITEMASK_XYZW ); + ti += tgsi_build_full_declaration(&fulldecl, + &tokens[ti], + header, + maxTokens - ti ); + } + } + + /* temporary decls */ + { + GLboolean tempsUsed[MAX_PROGRAM_TEMPS + 1]; + GLboolean inside_range = GL_FALSE; + GLuint start_range = 0; + + find_temporaries(program, tempsUsed); + tempsUsed[MAX_PROGRAM_TEMPS] = GL_FALSE; + for (i = 0; i < MAX_PROGRAM_TEMPS + 1; i++) { + if (tempsUsed[i] && !inside_range) { + inside_range = GL_TRUE; + start_range = i; + } + else if (!tempsUsed[i] && inside_range) { + struct tgsi_full_declaration fulldecl; + + inside_range = GL_FALSE; + fulldecl = make_temp_decl( start_range, i - 1 ); + ti += tgsi_build_full_declaration( + &fulldecl, + &tokens[ti], + header, + maxTokens - ti ); + } + } + } + + /* Declare address register. + */ + if (program->NumAddressRegs > 0) { + struct tgsi_full_declaration fulldecl; + + assert( program->NumAddressRegs == 1 ); + + fulldecl = make_addr_decl( 0, 0 ); + ti += tgsi_build_full_declaration( + &fulldecl, + &tokens[ti], + header, + maxTokens - ti ); + + indirectAccess = GL_TRUE; + } + + /* immediates/literals */ + memset(immediates, ~0, sizeof(immediates)); + + /* Emit immediates only when there is no address register in use. + * FIXME: Be smarter and recognize param arrays -- indirect addressing is + * only valid within the referenced array. + */ + if (program->Parameters && !indirectAccess) { + for (i = 0; i < program->Parameters->NumParameters; i++) { + if (program->Parameters->Parameters[i].Type == PROGRAM_CONSTANT) { + struct tgsi_full_immediate fullimm; + + fullimm = make_immediate( program->Parameters->ParameterValues[i], 4 ); + ti += tgsi_build_full_immediate( + &fullimm, + &tokens[ti], + header, + maxTokens - ti ); + immediates[i] = numImmediates; + numImmediates++; + } + } + } + + /* constant buffer refs */ + if (program->Parameters) { + GLint start = -1, end = -1; + + for (i = 0; i < program->Parameters->NumParameters; i++) { + GLboolean emit = (i == program->Parameters->NumParameters - 1); + GLboolean matches; + + switch (program->Parameters->Parameters[i].Type) { + case PROGRAM_ENV_PARAM: + case PROGRAM_STATE_VAR: + case PROGRAM_NAMED_PARAM: + case PROGRAM_UNIFORM: + matches = GL_TRUE; + break; + case PROGRAM_CONSTANT: + matches = indirectAccess; + break; + default: + matches = GL_FALSE; + } + + if (matches) { + if (start == -1) { + /* begin a sequence */ + start = i; + end = i; + } + else { + /* continue sequence */ + end = i; + } + } + else { + if (start != -1) { + /* end of sequence */ + emit = GL_TRUE; + } + } + + if (emit && start >= 0) { + struct tgsi_full_declaration fulldecl; + + fulldecl = make_constant_decl( start, end ); + ti += tgsi_build_full_declaration( + &fulldecl, + &tokens[ti], + header, + maxTokens - ti ); + start = end = -1; + } + } + } + + /* texture samplers */ + for (i = 0; i < 8; i++) { + if (program->SamplersUsed & (1 << i)) { + struct tgsi_full_declaration fulldecl; + + fulldecl = make_sampler_decl( i ); + ti += tgsi_build_full_declaration( + &fulldecl, + &tokens[ti], + header, + maxTokens - ti ); + } + } + + for (i = 0; i < program->NumInstructions; i++) { + compile_instruction( + &program->Instructions[i], + &fullinst, + inputMapping, + outputMapping, + immediates, + indirectAccess, + preamble_size, + procType, + &insideSubroutine ); + + ti += tgsi_build_full_instruction( + &fullinst, + &tokens[ti], + header, + maxTokens - ti ); + } + +#if DEBUG + if(!tgsi_sanity_check(tokens)) { + debug_printf("Due to sanity check failure(s) above the following shader program is invalid:\n"); + debug_printf("\nOriginal program:\n%s", program->String); + debug_printf("\nMesa program:\n"); + _mesa_print_program(program); + debug_printf("\nTGSI program:\n"); + tgsi_dump(tokens, 0); + assert(0); + } +#endif + + return ti; +} diff --git a/src/mesa/state_tracker/st_mesa_to_tgsi.h b/src/mesa/state_tracker/st_mesa_to_tgsi.h new file mode 100644 index 0000000000..77c74644b8 --- /dev/null +++ b/src/mesa/state_tracker/st_mesa_to_tgsi.h @@ -0,0 +1,64 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_MESA_TO_TGSI_H +#define ST_MESA_TO_TGSI_H + +#include "main/mtypes.h" + + +#if defined __cplusplus +extern "C" { +#endif + +struct tgsi_token; +struct gl_program; + +GLuint +st_translate_mesa_program( + uint procType, + const struct gl_program *program, + GLuint numInputs, + const GLuint inputMapping[], + const ubyte inputSemanticName[], + const ubyte inputSemanticIndex[], + const GLuint interpMode[], + GLuint numOutputs, + const GLuint outputMapping[], + const ubyte outputSemanticName[], + const ubyte outputSemanticIndex[], + struct tgsi_token *tokens, + GLuint maxTokens ); + + +#if defined __cplusplus +} /* extern "C" */ +#endif + +#endif /* ST_MESA_TO_TGSI_H */ + diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c new file mode 100644 index 0000000000..af0df22dc5 --- /dev/null +++ b/src/mesa/state_tracker/st_program.c @@ -0,0 +1,530 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + */ + + +#include "main/imports.h" +#include "main/mtypes.h" +#include "shader/prog_print.h" +#include "shader/programopt.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_shader_tokens.h" +#include "draw/draw_context.h" +#include "tgsi/tgsi_dump.h" + +#include "st_context.h" +#include "st_atom.h" +#include "st_program.h" +#include "st_mesa_to_tgsi.h" +#include "cso_cache/cso_context.h" + + +#define ST_MAX_SHADER_TOKENS 4096 + + +#define TGSI_DEBUG 0 + + +/** XXX we should use the version of this from u_memory.h but including + * that header causes symbol collisions. + */ +static INLINE void * +mem_dup(const void *src, uint size) +{ + void *dup = MALLOC(size); + if (dup) + memcpy(dup, src, size); + return dup; +} + + + +/** + * Translate a Mesa vertex shader into a TGSI shader. + * \param outputMapping to map vertex program output registers (VERT_RESULT_x) + * to TGSI output slots + * \param tokensOut destination for TGSI tokens + * \return pointer to cached pipe_shader object. + */ +void +st_translate_vertex_program(struct st_context *st, + struct st_vertex_program *stvp, + const GLuint outputMapping[], + const ubyte *outputSemanticName, + const ubyte *outputSemanticIndex) +{ + struct pipe_context *pipe = st->pipe; + struct tgsi_token tokens[ST_MAX_SHADER_TOKENS]; + GLuint defaultOutputMapping[VERT_RESULT_MAX]; + struct pipe_shader_state vs; + GLuint attr, i; + GLuint num_generic = 0; + GLuint num_tokens; + + ubyte vs_input_semantic_name[PIPE_MAX_SHADER_INPUTS]; + ubyte vs_input_semantic_index[PIPE_MAX_SHADER_INPUTS]; + uint vs_num_inputs = 0; + + ubyte vs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; + ubyte vs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; + uint vs_num_outputs = 0; + + memset(&vs, 0, sizeof(vs)); + + if (stvp->Base.IsPositionInvariant) + _mesa_insert_mvp_code(st->ctx, &stvp->Base); + + /* + * Determine number of inputs, the mappings between VERT_ATTRIB_x + * and TGSI generic input indexes, plus input attrib semantic info. + */ + for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { + if (stvp->Base.Base.InputsRead & (1 << attr)) { + const GLuint slot = vs_num_inputs; + + vs_num_inputs++; + + stvp->input_to_index[attr] = slot; + stvp->index_to_input[slot] = attr; + + switch (attr) { + case VERT_ATTRIB_POS: + vs_input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + vs_input_semantic_index[slot] = 0; + break; + case VERT_ATTRIB_WEIGHT: + /* fall-through */ + case VERT_ATTRIB_NORMAL: + /* just label as a generic */ + vs_input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + vs_input_semantic_index[slot] = 0; + break; + case VERT_ATTRIB_COLOR0: + vs_input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + vs_input_semantic_index[slot] = 0; + break; + case VERT_ATTRIB_COLOR1: + vs_input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + vs_input_semantic_index[slot] = 1; + break; + case VERT_ATTRIB_FOG: + vs_input_semantic_name[slot] = TGSI_SEMANTIC_FOG; + vs_input_semantic_index[slot] = 0; + break; + case VERT_ATTRIB_POINT_SIZE: + vs_input_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; + vs_input_semantic_index[slot] = 0; + break; + case VERT_ATTRIB_TEX0: + case VERT_ATTRIB_TEX1: + case VERT_ATTRIB_TEX2: + case VERT_ATTRIB_TEX3: + case VERT_ATTRIB_TEX4: + case VERT_ATTRIB_TEX5: + case VERT_ATTRIB_TEX6: + case VERT_ATTRIB_TEX7: + vs_input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + vs_input_semantic_index[slot] = num_generic++; + break; + case VERT_ATTRIB_GENERIC0: + case VERT_ATTRIB_GENERIC1: + case VERT_ATTRIB_GENERIC2: + case VERT_ATTRIB_GENERIC3: + case VERT_ATTRIB_GENERIC4: + case VERT_ATTRIB_GENERIC5: + case VERT_ATTRIB_GENERIC6: + case VERT_ATTRIB_GENERIC7: + assert(attr < VERT_ATTRIB_MAX); + vs_input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + vs_input_semantic_index[slot] = num_generic++; + break; + default: + assert(0); + } + } + } + +#if 0 + if (outputMapping && outputSemanticName) { + printf("VERT_RESULT written out_slot semantic_name semantic_index\n"); + for (attr = 0; attr < VERT_RESULT_MAX; attr++) { + printf(" %-2d %c %3d %2d %2d\n", + attr, + ((stvp->Base.Base.OutputsWritten & (1 << attr)) ? 'Y' : ' '), + outputMapping[attr], + outputSemanticName[attr], + outputSemanticIndex[attr]); + } + } +#endif + + /* initialize output semantics to defaults */ + for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) { + vs_output_semantic_name[i] = TGSI_SEMANTIC_GENERIC; + vs_output_semantic_index[i] = 0; + } + + num_generic = 0; + /* + * Determine number of outputs, the (default) output register + * mapping and the semantic information for each output. + */ + for (attr = 0; attr < VERT_RESULT_MAX; attr++) { + if (stvp->Base.Base.OutputsWritten & (1 << attr)) { + GLuint slot; + + /* XXX + * Pass in the fragment program's input's semantic info. + * Use the generic semantic indexes from there, instead of + * guessing below. + */ + + if (outputMapping) { + slot = outputMapping[attr]; + assert(slot != ~0); + } + else { + slot = vs_num_outputs; + vs_num_outputs++; + defaultOutputMapping[attr] = slot; + } + + switch (attr) { + case VERT_RESULT_HPOS: + assert(slot == 0); + vs_output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + vs_output_semantic_index[slot] = 0; + break; + case VERT_RESULT_COL0: + vs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + vs_output_semantic_index[slot] = 0; + break; + case VERT_RESULT_COL1: + vs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + vs_output_semantic_index[slot] = 1; + break; + case VERT_RESULT_BFC0: + vs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + vs_output_semantic_index[slot] = 0; + break; + case VERT_RESULT_BFC1: + vs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + vs_output_semantic_index[slot] = 1; + break; + case VERT_RESULT_FOGC: + vs_output_semantic_name[slot] = TGSI_SEMANTIC_FOG; + vs_output_semantic_index[slot] = 0; + break; + case VERT_RESULT_PSIZ: + vs_output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; + vs_output_semantic_index[slot] = 0; + break; + case VERT_RESULT_EDGE: + assert(0); + break; + case VERT_RESULT_TEX0: + case VERT_RESULT_TEX1: + case VERT_RESULT_TEX2: + case VERT_RESULT_TEX3: + case VERT_RESULT_TEX4: + case VERT_RESULT_TEX5: + case VERT_RESULT_TEX6: + case VERT_RESULT_TEX7: + /* fall-through */ + case VERT_RESULT_VAR0: + /* fall-through */ + default: + if (outputSemanticName) { + /* use provided semantic into */ + assert(outputSemanticName[attr] != TGSI_SEMANTIC_COUNT); + vs_output_semantic_name[slot] = outputSemanticName[attr]; + vs_output_semantic_index[slot] = outputSemanticIndex[attr]; + } + else { + /* use default semantic info */ + vs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + vs_output_semantic_index[slot] = num_generic++; + } + } + } + } + + assert(vs_output_semantic_name[0] == TGSI_SEMANTIC_POSITION); + + + if (outputMapping) { + /* find max output slot referenced to compute vs_num_outputs */ + GLuint maxSlot = 0; + for (attr = 0; attr < VERT_RESULT_MAX; attr++) { + if (outputMapping[attr] != ~0 && outputMapping[attr] > maxSlot) + maxSlot = outputMapping[attr]; + } + vs_num_outputs = maxSlot + 1; + } + else { + outputMapping = defaultOutputMapping; + } + + /* free old shader state, if any */ + if (stvp->state.tokens) { + FREE((void *) stvp->state.tokens); + stvp->state.tokens = NULL; + } + if (stvp->driver_shader) { + cso_delete_vertex_shader(st->cso_context, stvp->driver_shader); + stvp->driver_shader = NULL; + } + + /* XXX: fix static allocation of tokens: + */ + num_tokens = st_translate_mesa_program( TGSI_PROCESSOR_VERTEX, + &stvp->Base.Base, + /* inputs */ + vs_num_inputs, + stvp->input_to_index, + vs_input_semantic_name, + vs_input_semantic_index, + NULL, + /* outputs */ + vs_num_outputs, + outputMapping, + vs_output_semantic_name, + vs_output_semantic_index, + /* tokenized result */ + tokens, ST_MAX_SHADER_TOKENS); + + assert(num_tokens < ST_MAX_SHADER_TOKENS); + + vs.tokens = (struct tgsi_token *) + mem_dup(tokens, num_tokens * sizeof(tokens[0])); + + stvp->num_inputs = vs_num_inputs; + stvp->state = vs; /* struct copy */ + stvp->driver_shader = pipe->create_vs_state(pipe, &vs); + + if (0) + _mesa_print_program(&stvp->Base.Base); + + if (TGSI_DEBUG) + tgsi_dump( vs.tokens, 0 ); +} + + + +/** + * Translate a Mesa fragment shader into a TGSI shader. + * \param inputMapping to map fragment program input registers to TGSI + * input slots + * \param tokensOut destination for TGSI tokens + * \return pointer to cached pipe_shader object. + */ +void +st_translate_fragment_program(struct st_context *st, + struct st_fragment_program *stfp, + const GLuint inputMapping[]) +{ + struct pipe_context *pipe = st->pipe; + struct tgsi_token tokens[ST_MAX_SHADER_TOKENS]; + GLuint outputMapping[FRAG_RESULT_MAX]; + GLuint defaultInputMapping[FRAG_ATTRIB_MAX]; + struct pipe_shader_state fs; + GLuint interpMode[16]; /* XXX size? */ + GLuint attr; + const GLbitfield inputsRead = stfp->Base.Base.InputsRead; + GLuint vslot = 0; + GLuint num_generic = 0; + GLuint num_tokens; + + uint fs_num_inputs = 0; + + ubyte fs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; + ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; + uint fs_num_outputs = 0; + + memset(&fs, 0, sizeof(fs)); + + /* which vertex output goes to the first fragment input: */ + if (inputsRead & FRAG_BIT_WPOS) + vslot = 0; + else + vslot = 1; + + /* + * Convert Mesa program inputs to TGSI input register semantics. + */ + for (attr = 0; attr < FRAG_ATTRIB_MAX; attr++) { + if (inputsRead & (1 << attr)) { + const GLuint slot = fs_num_inputs; + + defaultInputMapping[attr] = slot; + + stfp->input_map[slot] = vslot++; + + fs_num_inputs++; + + switch (attr) { + case FRAG_ATTRIB_WPOS: + stfp->input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + stfp->input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + break; + case FRAG_ATTRIB_COL0: + stfp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stfp->input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + break; + case FRAG_ATTRIB_COL1: + stfp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stfp->input_semantic_index[slot] = 1; + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + break; + case FRAG_ATTRIB_FOGC: + if (stfp->Base.UsesPointCoord) + stfp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + else + stfp->input_semantic_name[slot] = TGSI_SEMANTIC_FOG; + stfp->input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; + break; + case FRAG_ATTRIB_TEX0: + case FRAG_ATTRIB_TEX1: + case FRAG_ATTRIB_TEX2: + case FRAG_ATTRIB_TEX3: + case FRAG_ATTRIB_TEX4: + case FRAG_ATTRIB_TEX5: + case FRAG_ATTRIB_TEX6: + case FRAG_ATTRIB_TEX7: + stfp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stfp->input_semantic_index[slot] = num_generic++; + interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; + break; + case FRAG_ATTRIB_VAR0: + /* fall-through */ + default: + stfp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stfp->input_semantic_index[slot] = num_generic++; + interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; + } + } + } + + /* + * Semantics and mapping for outputs + */ + { + uint numColors = 0; + GLbitfield outputsWritten = stfp->Base.Base.OutputsWritten; + + /* if z is written, emit that first */ + if (outputsWritten & (1 << FRAG_RESULT_DEPR)) { + fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_POSITION; + fs_output_semantic_index[fs_num_outputs] = 0; + outputMapping[FRAG_RESULT_DEPR] = fs_num_outputs; + fs_num_outputs++; + outputsWritten &= ~(1 << FRAG_RESULT_DEPR); + } + + /* handle remaning outputs (color) */ + for (attr = 0; attr < FRAG_RESULT_MAX; attr++) { + if (outputsWritten & (1 << attr)) { + switch (attr) { + case FRAG_RESULT_DEPR: + /* handled above */ + assert(0); + break; + case FRAG_RESULT_COLR: + fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_COLOR; + fs_output_semantic_index[fs_num_outputs] = numColors; + outputMapping[attr] = fs_num_outputs; + numColors++; + break; + default: + assert(0); + } + fs_num_outputs++; + } + } + } + + if (!inputMapping) + inputMapping = defaultInputMapping; + + /* XXX: fix static allocation of tokens: + */ + num_tokens = st_translate_mesa_program( TGSI_PROCESSOR_FRAGMENT, + &stfp->Base.Base, + /* inputs */ + fs_num_inputs, + inputMapping, + stfp->input_semantic_name, + stfp->input_semantic_index, + interpMode, + /* outputs */ + fs_num_outputs, + outputMapping, + fs_output_semantic_name, + fs_output_semantic_index, + /* tokenized result */ + tokens, ST_MAX_SHADER_TOKENS); + + assert(num_tokens < ST_MAX_SHADER_TOKENS); + + fs.tokens = (struct tgsi_token *) + mem_dup(tokens, num_tokens * sizeof(tokens[0])); + + stfp->state = fs; /* struct copy */ + stfp->driver_shader = pipe->create_fs_state(pipe, &fs); + + if (0) + _mesa_print_program(&stfp->Base.Base); + + if (TGSI_DEBUG) + tgsi_dump( fs.tokens, 0/*TGSI_DUMP_VERBOSE*/ ); +} + + +/** + * Debug- print current shader text + */ +void +st_print_shaders(GLcontext *ctx) +{ + struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; + if (shProg) { + GLuint i; + for (i = 0; i < shProg->NumShaders; i++) { + printf("GLSL shader %u of %u:\n", i, shProg->NumShaders); + printf("%s\n", shProg->Shaders[i]->Source); + } + } +} diff --git a/src/mesa/state_tracker/st_program.h b/src/mesa/state_tracker/st_program.h new file mode 100644 index 0000000000..e2e5eddef2 --- /dev/null +++ b/src/mesa/state_tracker/st_program.h @@ -0,0 +1,158 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + + +#ifndef ST_PROGRAM_H +#define ST_PROGRAM_H + +#include "main/mtypes.h" +#include "shader/program.h" +#include "pipe/p_shader_tokens.h" + + +struct cso_fragment_shader; +struct cso_vertex_shader; +struct translated_vertex_program; + + +/** + * Derived from Mesa gl_fragment_program: + */ +struct st_fragment_program +{ + struct gl_fragment_program Base; + GLuint serialNo; + + GLuint input_to_slot[FRAG_ATTRIB_MAX]; /**< Maps FRAG_ATTRIB_x to slot */ + GLuint num_input_slots; + + /** map FP input back to VP output */ + GLuint input_map[PIPE_MAX_SHADER_INPUTS]; + + ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; + ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS]; + + struct pipe_shader_state state; + void *driver_shader; + + GLuint param_state; + + /** List of vertex programs which have been translated such that their + * outputs match this fragment program's inputs. + */ + struct translated_vertex_program *vertex_programs; + + /** Program prefixed with glBitmap prologue */ + struct st_fragment_program *bitmap_program; + uint bitmap_sampler; +}; + + +/** + * Derived from Mesa gl_fragment_program: + */ +struct st_vertex_program +{ + struct gl_vertex_program Base; /**< The Mesa vertex program */ + GLuint serialNo; + + /** maps a Mesa VERT_ATTRIB_x to a packed TGSI input index */ + GLuint input_to_index[VERT_ATTRIB_MAX]; + /** maps a TGSI input index back to a Mesa VERT_ATTRIB_x */ + GLuint index_to_input[PIPE_MAX_SHADER_INPUTS]; + + GLuint num_inputs; + + struct pipe_shader_state state; + void *driver_shader; + + /** For using our private draw module (glRasterPos) */ + struct draw_vertex_shader *draw_shader; + + GLuint param_state; +}; + + +static INLINE struct st_fragment_program * +st_fragment_program( struct gl_fragment_program *fp ) +{ + return (struct st_fragment_program *)fp; +} + + +static INLINE struct st_vertex_program * +st_vertex_program( struct gl_vertex_program *vp ) +{ + return (struct st_vertex_program *)vp; +} + + +static INLINE void +st_reference_vertprog(struct st_context *st, + struct st_vertex_program **ptr, + struct st_vertex_program *prog) +{ + _mesa_reference_program(st->ctx, + (struct gl_program **) ptr, + (struct gl_program *) prog); +} + +static INLINE void +st_reference_fragprog(struct st_context *st, + struct st_fragment_program **ptr, + struct st_fragment_program *prog) +{ + _mesa_reference_program(st->ctx, + (struct gl_program **) ptr, + (struct gl_program *) prog); +} + + +extern void +st_translate_fragment_program(struct st_context *st, + struct st_fragment_program *fp, + const GLuint inputMapping[]); + + +extern void +st_translate_vertex_program(struct st_context *st, + struct st_vertex_program *vp, + const GLuint vert_output_to_slot[], + const ubyte *fs_input_semantic_name, + const ubyte *fs_input_semantic_index); + + +extern void +st_print_shaders(GLcontext *ctx); + + +#endif diff --git a/src/mesa/state_tracker/st_public.h b/src/mesa/state_tracker/st_public.h new file mode 100644 index 0000000000..88995aa874 --- /dev/null +++ b/src/mesa/state_tracker/st_public.h @@ -0,0 +1,121 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef ST_PUBLIC_H +#define ST_PUBLIC_H + +#include "GL/gl.h" +#include "GL/internal/glcore.h" /* for __GLcontextModes */ + +#include "pipe/p_compiler.h" +#include "pipe/p_format.h" + + +#define ST_SURFACE_FRONT_LEFT 0 +#define ST_SURFACE_BACK_LEFT 1 +#define ST_SURFACE_FRONT_RIGHT 2 +#define ST_SURFACE_BACK_RIGHT 3 +#define ST_SURFACE_DEPTH 8 + +#define ST_TEXTURE_2D 0x2 +#define ST_TEXTURE_RECT 0x4 + +#define ST_TEXTURE_RGB 0x1 +#define ST_TEXTURE_RGBA 0x2 + + +struct st_context; +struct st_framebuffer; +struct pipe_context; +struct pipe_fence_handle; +struct pipe_surface; + + +struct st_context *st_create_context(struct pipe_context *pipe, + const __GLcontextModes *visual, + struct st_context *share); + +void st_destroy_context( struct st_context *st ); + +void st_copy_context_state(struct st_context *dst, struct st_context *src, + uint mask); + +struct st_framebuffer *st_create_framebuffer( const __GLcontextModes *visual, + enum pipe_format colorFormat, + enum pipe_format depthFormat, + enum pipe_format stencilFormat, + uint width, uint height, + void *privateData); + +void st_resize_framebuffer( struct st_framebuffer *stfb, + uint width, uint height ); + +void st_set_framebuffer_surface(struct st_framebuffer *stfb, + uint surfIndex, struct pipe_surface *surf); + +void st_get_framebuffer_dimensions( struct st_framebuffer *stfb, + uint *width, uint *height); + +struct pipe_surface *st_get_framebuffer_surface(struct st_framebuffer *stfb, + uint surfIndex); + +struct pipe_texture *st_get_framebuffer_texture(struct st_framebuffer *stfb, + uint surfIndex); + +void *st_framebuffer_private( struct st_framebuffer *stfb ); + +void st_unreference_framebuffer( struct st_framebuffer *stfb ); + +void st_make_current(struct st_context *st, + struct st_framebuffer *draw, + struct st_framebuffer *read); + +void st_flush( struct st_context *st, uint pipeFlushFlags, + struct pipe_fence_handle **fence ); +void st_finish( struct st_context *st ); + +void st_notify_swapbuffers(struct st_framebuffer *stfb); +void st_notify_swapbuffers_complete(struct st_framebuffer *stfb); + +int st_set_teximage(struct pipe_texture *pt, int target); + +/** Redirect rendering into stfb's surface to a texture image */ +int st_bind_teximage(struct st_framebuffer *stfb, uint surfIndex, + int target, int format, int level); + +/** Undo surface-to-texture binding */ +int st_release_teximage(struct st_framebuffer *stfb, uint surfIndex, + int target, int format, int level); + + +/** Generic function type */ +typedef void (*st_proc)(); + +st_proc st_get_proc_address(const char *procname); + + +#endif diff --git a/src/mesa/state_tracker/st_texture.c b/src/mesa/state_tracker/st_texture.c new file mode 100644 index 0000000000..63cfe5fc16 --- /dev/null +++ b/src/mesa/state_tracker/st_texture.c @@ -0,0 +1,488 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "st_context.h" +#include "st_format.h" +#include "st_public.h" +#include "st_texture.h" +#include "st_cb_fbo.h" +#include "main/enums.h" +#include "main/teximage.h" +#include "main/texstore.h" + +#undef Elements /* fix re-defined macro warning */ + +#include "pipe/p_state.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" +#include "pipe/p_inlines.h" +#include "util/u_rect.h" + + +#define DBG if(0) printf + +#if 0 +static GLenum +target_to_target(GLenum target) +{ + switch (target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: + return GL_TEXTURE_CUBE_MAP_ARB; + default: + return target; + } +} +#endif + + +/** + * Allocate a new pipe_texture object + * width0, height0, depth0 are the dimensions of the level 0 image + * (the highest resolution). last_level indicates how many mipmap levels + * to allocate storage for. For non-mipmapped textures, this will be zero. + */ +struct pipe_texture * +st_texture_create(struct st_context *st, + enum pipe_texture_target target, + enum pipe_format format, + GLuint last_level, + GLuint width0, + GLuint height0, + GLuint depth0, + GLuint compress_byte, + GLuint usage ) +{ + struct pipe_texture pt, *newtex; + struct pipe_screen *screen = st->pipe->screen; + + assert(target <= PIPE_TEXTURE_CUBE); + + DBG("%s target %s format %s last_level %d\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(target), + _mesa_lookup_enum_by_nr(format), last_level); + + assert(format); + assert(screen->is_format_supported(screen, format, target, + PIPE_TEXTURE_USAGE_SAMPLER, 0)); + + memset(&pt, 0, sizeof(pt)); + pt.target = target; + pt.format = format; + pt.last_level = last_level; + pt.width[0] = width0; + pt.height[0] = height0; + pt.depth[0] = depth0; + pt.compressed = compress_byte ? 1 : 0; + pf_get_block(format, &pt.block); + pt.tex_usage = usage; + + newtex = screen->texture_create(screen, &pt); + + assert(!newtex || newtex->refcount == 1); + + return newtex; +} + + +/** + * Check if a texture image be pulled into a unified mipmap texture. + * This mirrors the completeness test in a lot of ways. + * + * Not sure whether I want to pass gl_texture_image here. + */ +GLboolean +st_texture_match_image(const struct pipe_texture *pt, + const struct gl_texture_image *image, + GLuint face, GLuint level) +{ + /* Images with borders are never pulled into mipmap textures. + */ + if (image->Border) + return GL_FALSE; + + if (st_mesa_format_to_pipe_format(image->TexFormat->MesaFormat) != pt->format || + image->IsCompressed != pt->compressed) + return GL_FALSE; + + /* Test image dimensions against the base level image adjusted for + * minification. This will also catch images not present in the + * texture, changed targets, etc. + */ + if (image->Width != pt->width[level] || + image->Height != pt->height[level] || + image->Depth != pt->depth[level]) + return GL_FALSE; + + return GL_TRUE; +} + + +#if 000 +/* Although we use the image_offset[] array to store relative offsets + * to cube faces, Mesa doesn't know anything about this and expects + * each cube face to be treated as a separate image. + * + * These functions present that view to mesa: + */ +const GLuint * +st_texture_depth_offsets(struct pipe_texture *pt, GLuint level) +{ + static const GLuint zero = 0; + + if (pt->target != PIPE_TEXTURE_3D || pt->level[level].nr_images == 1) + return &zero; + else + return pt->level[level].image_offset; +} + + +/** + * Return the offset to the given mipmap texture image within the + * texture memory buffer, in bytes. + */ +GLuint +st_texture_image_offset(const struct pipe_texture * pt, + GLuint face, GLuint level) +{ + if (pt->target == PIPE_TEXTURE_CUBE) + return (pt->level[level].level_offset + + pt->level[level].image_offset[face] * pt->cpp); + else + return pt->level[level].level_offset; +} +#endif + + +/** + * Map a teximage in a mipmap texture. + * \param row_stride returns row stride in bytes + * \param image_stride returns image stride in bytes (for 3D textures). + * \return address of mapping + */ +GLubyte * +st_texture_image_map(struct st_context *st, struct st_texture_image *stImage, + GLuint zoffset, + GLuint flags ) +{ + struct pipe_screen *screen = st->pipe->screen; + struct pipe_texture *pt = stImage->pt; + DBG("%s \n", __FUNCTION__); + + stImage->surface = screen->get_tex_surface(screen, pt, stImage->face, + stImage->level, zoffset, + flags); + + if (stImage->surface) + return screen->surface_map(screen, stImage->surface, flags); + else + return NULL; +} + + +void +st_texture_image_unmap(struct st_context *st, + struct st_texture_image *stImage) +{ + struct pipe_screen *screen = st->pipe->screen; + + DBG("%s\n", __FUNCTION__); + + screen->surface_unmap(screen, stImage->surface); + + pipe_surface_reference(&stImage->surface, NULL); +} + + + +/** + * Upload data to a rectangular sub-region. Lots of choices how to do this: + * + * - memcpy by span to current destination + * - upload data as new buffer and blit + * + * Currently always memcpy. + */ +static void +st_surface_data(struct pipe_context *pipe, + struct pipe_surface *dst, + unsigned dstx, unsigned dsty, + const void *src, unsigned src_stride, + unsigned srcx, unsigned srcy, unsigned width, unsigned height) +{ + struct pipe_screen *screen = pipe->screen; + void *map = screen->surface_map(screen, dst, PIPE_BUFFER_USAGE_CPU_WRITE); + + pipe_copy_rect(map, + &dst->block, + dst->stride, + dstx, dsty, + width, height, + src, src_stride, + srcx, srcy); + + screen->surface_unmap(screen, dst); +} + + +/* Upload data for a particular image. + */ +void +st_texture_image_data(struct pipe_context *pipe, + struct pipe_texture *dst, + GLuint face, + GLuint level, + void *src, + GLuint src_row_stride, GLuint src_image_stride) +{ + struct pipe_screen *screen = pipe->screen; + GLuint depth = dst->depth[level]; + GLuint i; + const GLubyte *srcUB = src; + struct pipe_surface *dst_surface; + + DBG("%s\n", __FUNCTION__); + for (i = 0; i < depth; i++) { + dst_surface = screen->get_tex_surface(screen, dst, face, level, i, + PIPE_BUFFER_USAGE_CPU_WRITE); + + st_surface_data(pipe, dst_surface, + 0, 0, /* dstx, dsty */ + srcUB, + src_row_stride, + 0, 0, /* source x, y */ + dst->width[level], dst->height[level]); /* width, height */ + + screen->tex_surface_release(screen, &dst_surface); + + srcUB += src_image_stride; + } +} + + +/* Copy mipmap image between textures + */ +void +st_texture_image_copy(struct pipe_context *pipe, + struct pipe_texture *dst, GLuint dstLevel, + struct pipe_texture *src, + GLuint face) +{ + struct pipe_screen *screen = pipe->screen; + GLuint width = dst->width[dstLevel]; + GLuint height = dst->height[dstLevel]; + GLuint depth = dst->depth[dstLevel]; + struct pipe_surface *src_surface; + struct pipe_surface *dst_surface; + GLuint i; + + for (i = 0; i < depth; i++) { + GLuint srcLevel; + + /* find src texture level of needed size */ + for (srcLevel = 0; srcLevel <= src->last_level; srcLevel++) { + if (src->width[srcLevel] == width && + src->height[srcLevel] == height) { + break; + } + } + assert(src->width[srcLevel] == width); + assert(src->height[srcLevel] == height); + +#if 0 + { + src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i, + PIPE_BUFFER_USAGE_CPU_READ); + ubyte *map = screen->surface_map(screen, src_surface, PIPE_BUFFER_USAGE_CPU_READ); + map += src_surface->width * src_surface->height * 4 / 2; + printf("%s center pixel: %d %d %d %d (pt %p[%d] -> %p[%d])\n", + __FUNCTION__, + map[0], map[1], map[2], map[3], + src, srcLevel, dst, dstLevel); + + screen->surface_unmap(screen, src_surface); + pipe_surface_reference(&src_surface, NULL); + } +#endif + + dst_surface = screen->get_tex_surface(screen, dst, face, dstLevel, i, + PIPE_BUFFER_USAGE_GPU_WRITE); + + src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i, + PIPE_BUFFER_USAGE_GPU_READ); + + pipe->surface_copy(pipe, + FALSE, + dst_surface, + 0, 0, /* destX, Y */ + src_surface, + 0, 0, /* srcX, Y */ + width, height); + + screen->tex_surface_release(screen, &src_surface); + screen->tex_surface_release(screen, &dst_surface); + } +} + +/** Bind a pipe surface for use as a texture image */ +int +st_set_teximage(struct pipe_texture *pt, int target) +{ + GET_CURRENT_CONTEXT(ctx); + const GLuint unit = ctx->Texture.CurrentUnit; + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + struct st_texture_image *stImage; + int internalFormat; + + switch (pt->format) { + case PIPE_FORMAT_A8R8G8B8_UNORM: + internalFormat = GL_RGBA8; + break; + default: + return 0; + }; + + switch (target) { + case ST_TEXTURE_2D: + target = GL_TEXTURE_2D; + break; + case ST_TEXTURE_RECT: + target = GL_TEXTURE_RECTANGLE_ARB; + break; + default: + return 0; + } + + texObj = _mesa_select_tex_object(ctx, texUnit, target); + texImage = _mesa_get_tex_image(ctx, texObj, target, 0); + stImage = st_texture_image(texImage); + + _mesa_init_teximage_fields(ctx, GL_TEXTURE_2D, texImage, pt->width[0], + pt->height[0], 1, 0, internalFormat); + + texImage->TexFormat = st_ChooseTextureFormat(ctx, internalFormat, GL_RGBA, + GL_UNSIGNED_BYTE); + _mesa_set_fetch_functions(texImage, 2); + + pipe_texture_reference(&stImage->pt, pt); + + return 1; +} + +/** Redirect rendering into stfb's surface to a texture image */ +int +st_bind_teximage(struct st_framebuffer *stfb, uint surfIndex, + int target, int format, int level) +{ + GET_CURRENT_CONTEXT(ctx); + struct st_context *st = ctx->st; + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + const GLuint unit = ctx->Texture.CurrentUnit; + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + struct st_texture_image *stImage; + struct st_renderbuffer *strb; + GLint face = 0, slice = 0; + + assert(surfIndex <= ST_SURFACE_DEPTH); + + strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer); + + if (strb->texture_save || strb->surface_save) { + /* Error! */ + return 0; + } + + if (target == ST_TEXTURE_2D) { + texObj = texUnit->Current2D; + texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, level); + stImage = st_texture_image(texImage); + } + else { + /* unsupported target */ + return 0; + } + + st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); + + /* save the renderbuffer's surface/texture info */ + pipe_texture_reference(&strb->texture_save, strb->texture); + pipe_surface_reference(&strb->surface_save, strb->surface); + + /* plug in new surface/texture info */ + pipe_texture_reference(&strb->texture, stImage->pt); + strb->surface = screen->get_tex_surface(screen, strb->texture, + face, level, slice, + (PIPE_BUFFER_USAGE_GPU_READ | + PIPE_BUFFER_USAGE_GPU_WRITE)); + + st->dirty.st |= ST_NEW_FRAMEBUFFER; + + return 1; +} + + +/** Undo surface-to-texture binding */ +int +st_release_teximage(struct st_framebuffer *stfb, uint surfIndex, + int target, int format, int level) +{ + GET_CURRENT_CONTEXT(ctx); + struct st_context *st = ctx->st; + struct st_renderbuffer *strb; + + assert(surfIndex <= ST_SURFACE_DEPTH); + + strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer); + + if (!strb->texture_save || !strb->surface_save) { + /* Error! */ + return 0; + } + + st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); + + /* free tex surface, restore original */ + pipe_surface_reference(&strb->surface, strb->surface_save); + pipe_texture_reference(&strb->texture, strb->texture_save); + + pipe_surface_reference(&strb->surface_save, NULL); + pipe_texture_reference(&strb->texture_save, NULL); + + st->dirty.st |= ST_NEW_FRAMEBUFFER; + + return 1; +} diff --git a/src/mesa/state_tracker/st_texture.h b/src/mesa/state_tracker/st_texture.h new file mode 100644 index 0000000000..31f66ad52c --- /dev/null +++ b/src/mesa/state_tracker/st_texture.h @@ -0,0 +1,179 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef ST_TEXTURE_H +#define ST_TEXTURE_H + + +#include "main/mtypes.h" + +struct pipe_context; +struct pipe_texture; + + +struct st_texture_image +{ + struct gl_texture_image base; + + /* These aren't stored in gl_texture_image + */ + GLuint level; + GLuint face; + + /* If stImage->pt != NULL, image data is stored here. + * Else if stImage->base.Data != NULL, image is stored there. + * Else there is no image data. + */ + struct pipe_texture *pt; + + struct pipe_surface *surface; +}; + + + +struct st_texture_object +{ + struct gl_texture_object base; /* The "parent" object */ + + /* The texture must include at levels [0..lastLevel] once validated: + */ + GLuint lastLevel; + + /* On validation any active images held in main memory or in other + * textures will be copied to this texture and the old storage freed. + */ + struct pipe_texture *pt; + + GLboolean teximage_realloc; +}; + + +static INLINE struct st_texture_image * +st_texture_image(struct gl_texture_image *img) +{ + return (struct st_texture_image *) img; +} + +static INLINE struct st_texture_object * +st_texture_object(struct gl_texture_object *obj) +{ + return (struct st_texture_object *) obj; +} + + +static INLINE struct pipe_texture * +st_get_texobj_texture(struct gl_texture_object *texObj) +{ + struct st_texture_object *stObj = st_texture_object(texObj); + return stObj ? stObj->pt : NULL; +} + + +static INLINE struct pipe_texture * +st_get_stobj_texture(struct st_texture_object *stObj) +{ + return stObj ? stObj->pt : NULL; +} + +static INLINE GLboolean pf_is_depth_stencil( enum pipe_format format ) +{ + return (pf_get_component_bits( format, PIPE_FORMAT_COMP_Z ) + + pf_get_component_bits( format, PIPE_FORMAT_COMP_S )) != 0; +} + + +extern struct pipe_texture * +st_texture_create(struct st_context *st, + enum pipe_texture_target target, + enum pipe_format format, + GLuint last_level, + GLuint width0, + GLuint height0, + GLuint depth0, + GLuint compress_byte, + GLuint tex_usage ); + + +/* Check if an image fits into an existing texture object. + */ +extern GLboolean +st_texture_match_image(const struct pipe_texture *pt, + const struct gl_texture_image *image, + GLuint face, GLuint level); + +/* Return a pointer to an image within a texture. Return image stride as + * well. + */ +extern GLubyte * +st_texture_image_map(struct st_context *st, + struct st_texture_image *stImage, + GLuint zoffset, + GLuint flags); + +extern void +st_texture_image_unmap(struct st_context *st, + struct st_texture_image *stImage); + + +/* Return pointers to each 2d slice within an image. Indexed by depth + * value. + */ +extern const GLuint * +st_texture_depth_offsets(struct pipe_texture *pt, GLuint level); + + +/* Return the linear offset of an image relative to the start of its region. + */ +extern GLuint +st_texture_image_offset(const struct pipe_texture *pt, + GLuint face, GLuint level); + +extern GLuint +st_texture_texel_offset(const struct pipe_texture * pt, + GLuint face, GLuint level, + GLuint col, GLuint row, GLuint img); + + +/* Upload an image into a texture + */ +extern void +st_texture_image_data(struct pipe_context *pipe, + struct pipe_texture *dst, + GLuint face, GLuint level, void *src, + GLuint src_row_pitch, GLuint src_image_pitch); + + +/* Copy an image between two textures + */ +extern void +st_texture_image_copy(struct pipe_context *pipe, + struct pipe_texture *dst, GLuint dstLevel, + struct pipe_texture *src, + GLuint face); + + +#endif diff --git a/src/mesa/swrast/s_context.c b/src/mesa/swrast/s_context.c index 62857ddeb0..297940adbd 100644 --- a/src/mesa/swrast/s_context.c +++ b/src/mesa/swrast/s_context.c @@ -533,6 +533,9 @@ _swrast_update_texture_samplers(GLcontext *ctx) SWcontext *swrast = SWRAST_CONTEXT(ctx); GLuint u; + if (!swrast) + return; /* pipe hack */ + for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++) { const struct gl_texture_object *tObj = ctx->Texture.Unit[u]._Current; /* Note: If tObj is NULL, the sample function will be a simple diff --git a/src/mesa/tnl/t_context.c b/src/mesa/tnl/t_context.c index 8977fadcca..ce37dc0428 100644 --- a/src/mesa/tnl/t_context.c +++ b/src/mesa/tnl/t_context.c @@ -78,6 +78,9 @@ _tnl_CreateContext( GLcontext *ctx ) tnl->nr_blocks = 0; + /* plug in the VBO drawing function */ + vbo_set_draw_func(ctx, _tnl_draw_prims); + return GL_TRUE; } diff --git a/src/mesa/tnl/t_vp_build.h b/src/mesa/tnl/t_vp_build.h index d1c147ff03..d6ebc66c04 100644 --- a/src/mesa/tnl/t_vp_build.h +++ b/src/mesa/tnl/t_vp_build.h @@ -29,6 +29,13 @@ #include "main/mtypes.h" +#define TNL_FIXED_FUNCTION_STATE_FLAGS (_NEW_PROGRAM | \ + _NEW_LIGHT | \ + _NEW_TEXTURE | \ + _NEW_TEXTURE_MATRIX | \ + _NEW_TRANSFORM | \ + _NEW_FOG | \ + _NEW_POINT) extern void _tnl_UpdateFixedFunctionProgram( GLcontext *ctx ); diff --git a/src/mesa/tnl/tnl.h b/src/mesa/tnl/tnl.h index 9a1717bf89..4d628aa9a6 100644 --- a/src/mesa/tnl/tnl.h +++ b/src/mesa/tnl/tnl.h @@ -81,6 +81,8 @@ _tnl_draw_prims( GLcontext *ctx, GLuint min_index, GLuint max_index); +extern void +_mesa_load_tracked_matrices(GLcontext *ctx); extern void _tnl_RasterPos(GLcontext *ctx, const GLfloat vObj[4]); diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h index 4c51b44cda..5362226c2f 100644 --- a/src/mesa/vbo/vbo.h +++ b/src/mesa/vbo/vbo.h @@ -117,4 +117,22 @@ void vbo_rebase_prims( GLcontext *ctx, void vbo_use_buffer_objects(GLcontext *ctx); +void vbo_set_draw_func(GLcontext *ctx, vbo_draw_func func); + + +void GLAPIENTRY +_vbo_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a); + +void GLAPIENTRY +_vbo_Normal3f(GLfloat x, GLfloat y, GLfloat z); + +void GLAPIENTRY +_vbo_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); + +void GLAPIENTRY +_vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params); + +void GLAPIENTRY +_vbo_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + #endif diff --git a/src/mesa/vbo/vbo_context.c b/src/mesa/vbo/vbo_context.c index a73a46b9c8..bbf745b0c6 100644 --- a/src/mesa/vbo/vbo_context.c +++ b/src/mesa/vbo/vbo_context.c @@ -31,6 +31,7 @@ #include "vbo.h" #include "vbo_context.h" +#if 0 /* Reach out and grab this to use as the default: */ extern void _tnl_draw_prims( GLcontext *ctx, @@ -40,6 +41,7 @@ extern void _tnl_draw_prims( GLcontext *ctx, const struct _mesa_index_buffer *ib, GLuint min_index, GLuint max_index ); +#endif @@ -212,7 +214,9 @@ GLboolean _vbo_CreateContext( GLcontext *ctx ) /* By default: */ +#if 0 /* dead - see vbo_set_draw_func() */ vbo->draw_prims = _tnl_draw_prims; +#endif /* Hook our functions into exec and compile dispatch tables. These * will pretty much be permanently installed, which means that the @@ -240,10 +244,20 @@ void _vbo_DestroyContext( GLcontext *ctx ) ctx->aelt_context = NULL; } - vbo_exec_destroy(ctx); + if (vbo_context(ctx)) { + vbo_exec_destroy(ctx); #if FEATURE_dlist - vbo_save_destroy(ctx); + vbo_save_destroy(ctx); #endif - FREE(vbo_context(ctx)); - ctx->swtnl_im = NULL; + FREE(vbo_context(ctx)); + ctx->swtnl_im = NULL; + } +} + + +void vbo_set_draw_func(GLcontext *ctx, vbo_draw_func func) +{ + struct vbo_context *vbo = vbo_context(ctx); + vbo->draw_prims = func; } + diff --git a/src/mesa/vbo/vbo_exec_api.c b/src/mesa/vbo/vbo_exec_api.c index d48f5230cb..a6ce26ffed 100644 --- a/src/mesa/vbo/vbo_exec_api.c +++ b/src/mesa/vbo/vbo_exec_api.c @@ -143,29 +143,37 @@ static void vbo_exec_copy_to_current( struct vbo_exec_context *exec ) for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { if (exec->vtx.attrsz[i]) { - GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; - /* Note: the exec->vtx.current[i] pointers point into the * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays. */ - COPY_CLEAN_4V(current, - exec->vtx.attrsz[i], - exec->vtx.attrptr[i]); + GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; + GLfloat tmp[4]; + + COPY_CLEAN_4V(tmp, + exec->vtx.attrsz[i], + exec->vtx.attrptr[i]); + + if (memcmp(current, tmp, sizeof(tmp)) != 0) + { + memcpy(current, tmp, sizeof(tmp)); - /* Given that we explicitly state size here, there is no need - * for the COPY_CLEAN above, could just copy 16 bytes and be - * done. The only problem is when Mesa accesses ctx->Current - * directly. - */ - vbo->currval[i].Size = exec->vtx.attrsz[i]; - - /* This triggers rather too much recalculation of Mesa state - * that doesn't get used (eg light positions). - */ - if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT && - i <= VBO_ATTRIB_MAT_BACK_INDEXES) - ctx->NewState |= _NEW_LIGHT; + /* Given that we explicitly state size here, there is no need + * for the COPY_CLEAN above, could just copy 16 bytes and be + * done. The only problem is when Mesa accesses ctx->Current + * directly. + */ + vbo->currval[i].Size = exec->vtx.attrsz[i]; + + /* This triggers rather too much recalculation of Mesa state + * that doesn't get used (eg light positions). + */ + if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT && + i <= VBO_ATTRIB_MAT_BACK_INDEXES) + ctx->NewState |= _NEW_LIGHT; + + ctx->NewState |= _NEW_CURRENT_ATTRIB; + } } } @@ -693,7 +701,8 @@ void vbo_exec_vtx_init( struct vbo_exec_context *exec ) GLuint i; /* Allocate a buffer object. Will just reuse this object - * continuously. + * continuously, unless vbo_use_buffer_objects() is called to enable + * use of real VBOs. */ _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, @@ -772,3 +781,36 @@ static void reset_attrfv( struct vbo_exec_context *exec ) exec->vtx.vertex_size = 0; } + +void GLAPIENTRY +_vbo_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) +{ + vbo_Color4f(r, g, b, a); +} + + +void GLAPIENTRY +_vbo_Normal3f(GLfloat x, GLfloat y, GLfloat z) +{ + vbo_Normal3f(x, y, z); +} + + +void GLAPIENTRY +_vbo_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) +{ + vbo_MultiTexCoord4f(target, s, t, r, q); +} + +void GLAPIENTRY +_vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params) +{ + vbo_Materialfv(face, pname, params); +} + + +void GLAPIENTRY +_vbo_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + vbo_VertexAttrib4fARB(index, x, y, z, w); +} diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c index 82f4db17d1..8871e10cf6 100644 --- a/src/mesa/vbo/vbo_exec_array.c +++ b/src/mesa/vbo/vbo_exec_array.c @@ -30,6 +30,8 @@ #include "main/state.h" #include "main/api_validate.h" #include "main/api_noop.h" +#include "main/varray.h" +#include "glapi/dispatch.h" #include "vbo_context.h" @@ -125,6 +127,7 @@ static void recalculate_input_bindings( GLcontext *ctx ) struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; const struct gl_client_array **inputs = &exec->array.inputs[0]; + GLbitfield const_inputs = 0x0; GLuint i; exec->array.program_mode = get_program_mode(ctx); @@ -139,19 +142,24 @@ static void recalculate_input_bindings( GLcontext *ctx ) for (i = 0; i <= VERT_ATTRIB_TEX7; i++) { if (exec->array.legacy_array[i]->Enabled) inputs[i] = exec->array.legacy_array[i]; - else + else { inputs[i] = &vbo->legacy_currval[i]; + const_inputs |= 1 << i; + } } for (i = 0; i < MAT_ATTRIB_MAX; i++) { inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->mat_currval[i]; + const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i); } /* Could use just about anything, just to fill in the empty * slots: */ - for (i = MAT_ATTRIB_MAX; i < VERT_ATTRIB_MAX - VERT_ATTRIB_GENERIC0; i++) + for (i = MAT_ATTRIB_MAX; i < VERT_ATTRIB_MAX - VERT_ATTRIB_GENERIC0; i++) { inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i]; + const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i); + } break; case VP_NV: @@ -164,15 +172,19 @@ static void recalculate_input_bindings( GLcontext *ctx ) inputs[i] = exec->array.generic_array[i]; else if (exec->array.legacy_array[i]->Enabled) inputs[i] = exec->array.legacy_array[i]; - else + else { inputs[i] = &vbo->legacy_currval[i]; + const_inputs |= 1 << i; + } } /* Could use just about anything, just to fill in the empty * slots: */ - for (i = VERT_ATTRIB_GENERIC0; i < VERT_ATTRIB_MAX; i++) + for (i = VERT_ATTRIB_GENERIC0; i < VERT_ATTRIB_MAX; i++) { inputs[i] = &vbo->generic_currval[i - VERT_ATTRIB_GENERIC0]; + const_inputs |= 1 << i; + } break; case VP_ARB: @@ -187,25 +199,34 @@ static void recalculate_input_bindings( GLcontext *ctx ) inputs[0] = exec->array.generic_array[0]; else if (exec->array.legacy_array[0]->Enabled) inputs[0] = exec->array.legacy_array[0]; - else + else { inputs[0] = &vbo->legacy_currval[0]; + const_inputs |= 1 << 0; + } for (i = 1; i <= VERT_ATTRIB_TEX7; i++) { if (exec->array.legacy_array[i]->Enabled) inputs[i] = exec->array.legacy_array[i]; - else + else { inputs[i] = &vbo->legacy_currval[i]; + const_inputs |= 1 << i; + } } for (i = 0; i < 16; i++) { if (exec->array.generic_array[i]->Enabled) inputs[VERT_ATTRIB_GENERIC0 + i] = exec->array.generic_array[i]; - else + else { inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i]; + const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i); + } + } break; } + + _mesa_set_varying_vp_inputs( ctx, ~const_inputs ); } static void bind_arrays( GLcontext *ctx ) @@ -255,6 +276,11 @@ vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count) bind_arrays( ctx ); + /* Again... + */ + if (ctx->NewState) + _mesa_update_state( ctx ); + prim[0].begin = 1; prim[0].end = 1; prim[0].weak = 0; @@ -295,6 +321,9 @@ vbo_exec_DrawRangeElements(GLenum mode, bind_arrays( ctx ); + if (ctx->NewState) + _mesa_update_state( ctx ); + ib.count = count; ib.type = type; ib.obj = ctx->Array.ElementArrayBufferObj; @@ -403,3 +432,29 @@ void vbo_exec_array_destroy( struct vbo_exec_context *exec ) { /* nothing to do */ } + + +/* This API entrypoint is not ordinarily used */ +void GLAPIENTRY +_mesa_DrawArrays(GLenum mode, GLint first, GLsizei count) +{ + vbo_exec_DrawArrays(mode, first, count); +} + + +/* This API entrypoint is not ordinarily used */ +void GLAPIENTRY +_mesa_DrawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices) +{ + vbo_exec_DrawElements(mode, count, type, indices); +} + + +/* This API entrypoint is not ordinarily used */ +void GLAPIENTRY +_mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, + GLenum type, const GLvoid *indices) +{ + vbo_exec_DrawRangeElements(mode, start, end, count, type, indices); +} diff --git a/src/mesa/vbo/vbo_exec_draw.c b/src/mesa/vbo/vbo_exec_draw.c index 92356ba977..5bf3d836db 100644 --- a/src/mesa/vbo/vbo_exec_draw.c +++ b/src/mesa/vbo/vbo_exec_draw.c @@ -150,6 +150,7 @@ static void vbo_exec_bind_arrays( GLcontext *ctx ) GLubyte *data = exec->vtx.buffer_map; const GLuint *map; GLuint attr; + GLbitfield varying_inputs = 0x0; /* Install the default (ie Current) attributes first, then overlay * all active ones. @@ -211,8 +212,11 @@ static void vbo_exec_bind_arrays( GLcontext *ctx ) arrays[attr]._MaxElement = count; /* ??? */ data += exec->vtx.attrsz[src] * sizeof(GLfloat); + varying_inputs |= 1<<attr; } } + + _mesa_set_varying_vp_inputs( ctx, varying_inputs ); } @@ -242,6 +246,9 @@ void vbo_exec_vtx_flush( struct vbo_exec_context *exec ) */ vbo_exec_bind_arrays( ctx ); + if (ctx->NewState) + _mesa_update_state( ctx ); + /* if using a real VBO, unmap it before drawing */ if (exec->vtx.bufferobj->Name) { ctx->Driver.UnmapBuffer(ctx, target, exec->vtx.bufferobj); diff --git a/src/mesa/vbo/vbo_save_draw.c b/src/mesa/vbo/vbo_save_draw.c index ed82f09958..0488c5d718 100644 --- a/src/mesa/vbo/vbo_save_draw.c +++ b/src/mesa/vbo/vbo_save_draw.c @@ -64,18 +64,26 @@ static void _playback_copy_to_current( GLcontext *ctx, for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { if (node->attrsz[i]) { GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; + GLfloat tmp[4]; - COPY_CLEAN_4V(current, - node->attrsz[i], - data); + COPY_CLEAN_4V(tmp, + node->attrsz[i], + data); + + if (memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0) + { + memcpy(current, tmp, 4 * sizeof(GLfloat)); - vbo->currval[i].Size = node->attrsz[i]; + vbo->currval[i].Size = node->attrsz[i]; - data += node->attrsz[i]; + if (i >= VBO_ATTRIB_FIRST_MATERIAL && + i <= VBO_ATTRIB_LAST_MATERIAL) + ctx->NewState |= _NEW_LIGHT; + + ctx->NewState |= _NEW_CURRENT_ATTRIB; + } - if (i >= VBO_ATTRIB_FIRST_MATERIAL && - i <= VBO_ATTRIB_LAST_MATERIAL) - ctx->NewState |= _NEW_LIGHT; + data += node->attrsz[i]; } } @@ -110,6 +118,7 @@ static void vbo_bind_vertex_list( GLcontext *ctx, GLuint data = node->buffer_offset; const GLuint *map; GLuint attr; + GLbitfield varying_inputs = 0x0; /* Install the default (ie Current) attributes first, then overlay * all active ones. @@ -159,8 +168,11 @@ static void vbo_bind_vertex_list( GLcontext *ctx, assert(arrays[attr].BufferObj->Name); data += node->attrsz[src] * sizeof(GLfloat); + varying_inputs |= 1<<attr; } } + + _mesa_set_varying_vp_inputs( ctx, varying_inputs ); } static void vbo_save_loopback_vertex_list( GLcontext *ctx, @@ -229,6 +241,11 @@ void vbo_save_playback_vertex_list( GLcontext *ctx, void *data ) vbo_bind_vertex_list( ctx, node ); + /* Again... + */ + if (ctx->NewState) + _mesa_update_state( ctx ); + vbo_context(ctx)->draw_prims( ctx, save->inputs, node->prim, diff --git a/src/mesa/vf/vf.c b/src/mesa/vf/vf.c new file mode 100644 index 0000000000..82f3d2b641 --- /dev/null +++ b/src/mesa/vf/vf.c @@ -0,0 +1,372 @@ +/* + * Copyright 2003 Tungsten Graphics, 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Keith Whitwell <keithw@tungstengraphics.com> + */ + +#include "main/glheader.h" +#include "main/context.h" +#include "main/colormac.h" + +#include "vf.h" + +#define DBG 0 + + + +static GLboolean match_fastpath( struct vertex_fetch *vf, + const struct vf_fastpath *fp) +{ + GLuint j; + + if (vf->attr_count != fp->attr_count) + return GL_FALSE; + + for (j = 0; j < vf->attr_count; j++) + if (vf->attr[j].format != fp->attr[j].format || + vf->attr[j].inputsize != fp->attr[j].size || + vf->attr[j].vertoffset != fp->attr[j].offset) + return GL_FALSE; + + if (fp->match_strides) { + if (vf->vertex_stride != fp->vertex_stride) + return GL_FALSE; + + for (j = 0; j < vf->attr_count; j++) + if (vf->attr[j].inputstride != fp->attr[j].stride) + return GL_FALSE; + } + + return GL_TRUE; +} + +static GLboolean search_fastpath_emit( struct vertex_fetch *vf ) +{ + struct vf_fastpath *fp = vf->fastpath; + + for ( ; fp ; fp = fp->next) { + if (match_fastpath(vf, fp)) { + vf->emit = fp->func; + return GL_TRUE; + } + } + + return GL_FALSE; +} + +void vf_register_fastpath( struct vertex_fetch *vf, + GLboolean match_strides ) +{ + struct vf_fastpath *fastpath = CALLOC_STRUCT(vf_fastpath); + GLuint i; + + fastpath->vertex_stride = vf->vertex_stride; + fastpath->attr_count = vf->attr_count; + fastpath->match_strides = match_strides; + fastpath->func = vf->emit; + fastpath->attr = (struct vf_attr_type *) + _mesa_malloc(vf->attr_count * sizeof(fastpath->attr[0])); + + for (i = 0; i < vf->attr_count; i++) { + fastpath->attr[i].format = vf->attr[i].format; + fastpath->attr[i].stride = vf->attr[i].inputstride; + fastpath->attr[i].size = vf->attr[i].inputsize; + fastpath->attr[i].offset = vf->attr[i].vertoffset; + } + + fastpath->next = vf->fastpath; + vf->fastpath = fastpath; +} + + + + +/*********************************************************************** + * Build codegen functions or return generic ones: + */ +static void choose_emit_func( struct vertex_fetch *vf, + GLuint count, + GLubyte *dest) +{ + vf->emit = NULL; + + /* Does this match an existing (hardwired, codegen or known-bad) + * fastpath? + */ + if (search_fastpath_emit(vf)) { + /* Use this result. If it is null, then it is already known + * that the current state will fail for codegen and there is no + * point trying again. + */ + } + else if (vf->codegen_emit) { + vf->codegen_emit( vf ); + } + + if (!vf->emit) { + vf_generate_hardwired_emit(vf); + } + + /* Otherwise use the generic version: + */ + if (!vf->emit) + vf->emit = vf_generic_emit; + + vf->emit( vf, count, dest ); +} + + + + + +/*********************************************************************** + * Public entrypoints, mostly dispatch to the above: + */ + + + +GLuint vf_set_vertex_attributes( struct vertex_fetch *vf, + const struct vf_attr_map *map, + GLuint nr, + GLuint vertex_stride ) +{ + GLuint offset = 0; + GLuint i, j; + + assert(nr < VF_ATTRIB_MAX); + + memset(vf->lookup, 0, sizeof(vf->lookup)); + + for (j = 0, i = 0; i < nr; i++) { + const GLuint format = map[i].format; + if (format == EMIT_PAD) { + if (DBG) + _mesa_printf("%d: pad %d, offset %d\n", i, + map[i].offset, offset); + + offset += map[i].offset; + + } + else { + assert(vf->lookup[map[i].attrib] == 0); + vf->lookup[map[i].attrib] = &vf->attr[j]; + + vf->attr[j].attrib = map[i].attrib; + vf->attr[j].format = format; + vf->attr[j].insert = vf_format_info[format].insert; + vf->attr[j].extract = vf_format_info[format].extract; + vf->attr[j].vertattrsize = vf_format_info[format].attrsize; + vf->attr[j].vertoffset = offset; + + if (DBG) + _mesa_printf("%d: %s, offset %d\n", i, + vf_format_info[format].name, + vf->attr[j].vertoffset); + + offset += vf_format_info[format].attrsize; + j++; + } + } + + vf->attr_count = j; + vf->vertex_stride = vertex_stride ? vertex_stride : offset; + vf->emit = choose_emit_func; + + assert(vf->vertex_stride >= offset); + return vf->vertex_stride; +} + + + +void vf_set_vp_matrix( struct vertex_fetch *vf, + const GLfloat *viewport ) +{ + assert(vf->allow_viewport_emits); + + /* scale */ + vf->vp[0] = viewport[MAT_SX]; + vf->vp[1] = viewport[MAT_SY]; + vf->vp[2] = viewport[MAT_SZ]; + vf->vp[3] = 1.0; + + /* translate */ + vf->vp[4] = viewport[MAT_TX]; + vf->vp[5] = viewport[MAT_TY]; + vf->vp[6] = viewport[MAT_TZ]; + vf->vp[7] = 0.0; +} + +void vf_set_vp_scale_translate( struct vertex_fetch *vf, + const GLfloat *scale, + const GLfloat *translate ) +{ + assert(vf->allow_viewport_emits); + + vf->vp[0] = scale[0]; + vf->vp[1] = scale[1]; + vf->vp[2] = scale[2]; + vf->vp[3] = scale[3]; + + vf->vp[4] = translate[0]; + vf->vp[5] = translate[1]; + vf->vp[6] = translate[2]; + vf->vp[7] = translate[3]; +} + + +/* Set attribute pointers, adjusted for start position: + */ +void vf_set_sources( struct vertex_fetch *vf, + GLvector4f * const sources[], + GLuint start ) +{ + struct vf_attr *a = vf->attr; + GLuint j; + + for (j = 0; j < vf->attr_count; j++) { + const GLvector4f *vptr = sources[a[j].attrib]; + + if ((a[j].inputstride != vptr->stride) || + (a[j].inputsize != vptr->size)) + vf->emit = choose_emit_func; + + a[j].inputstride = vptr->stride; + a[j].inputsize = vptr->size; + a[j].do_insert = a[j].insert[vptr->size - 1]; + a[j].inputptr = ((GLubyte *)vptr->data) + start * vptr->stride; + } +} + + + +/* Emit count VB vertices to dest. + */ +void vf_emit_vertices( struct vertex_fetch *vf, + GLuint count, + void *dest ) +{ + vf->emit( vf, count, (GLubyte*) dest ); +} + + +/* Extract a named attribute from a hardware vertex. Will have to + * reverse any viewport transformation, swizzling or other conversions + * which may have been applied. + * + * This is mainly required for on-the-fly vertex translations to + * swrast format. + */ +void vf_get_attr( struct vertex_fetch *vf, + const void *vertex, + GLenum attr, + const GLfloat *dflt, + GLfloat *dest ) +{ + const struct vf_attr *a = vf->attr; + const GLuint attr_count = vf->attr_count; + GLuint j; + + for (j = 0; j < attr_count; j++) { + if (a[j].attrib == attr) { + a[j].extract( &a[j], dest, (GLubyte *)vertex + a[j].vertoffset ); + return; + } + } + + /* Else return the value from ctx->Current. + */ + _mesa_memcpy( dest, dflt, 4*sizeof(GLfloat)); +} + + + + +struct vertex_fetch *vf_create( GLboolean allow_viewport_emits ) +{ + struct vertex_fetch *vf = CALLOC_STRUCT(vertex_fetch); + GLuint i; + + for (i = 0; i < VF_ATTRIB_MAX; i++) + vf->attr[i].vf = vf; + + vf->allow_viewport_emits = allow_viewport_emits; + + switch(CHAN_TYPE) { + case GL_UNSIGNED_BYTE: + vf->chan_scale[0] = 255.0; + vf->chan_scale[1] = 255.0; + vf->chan_scale[2] = 255.0; + vf->chan_scale[3] = 255.0; + break; + case GL_UNSIGNED_SHORT: + vf->chan_scale[0] = 65535.0; + vf->chan_scale[1] = 65535.0; + vf->chan_scale[2] = 65535.0; + vf->chan_scale[3] = 65535.0; + break; + default: + vf->chan_scale[0] = 1.0; + vf->chan_scale[1] = 1.0; + vf->chan_scale[2] = 1.0; + vf->chan_scale[3] = 1.0; + break; + } + + vf->identity[0] = 0.0; + vf->identity[1] = 0.0; + vf->identity[2] = 0.0; + vf->identity[3] = 1.0; + + vf->codegen_emit = NULL; + +#ifdef USE_SSE_ASM + if (!_mesa_getenv("MESA_NO_CODEGEN")) + vf->codegen_emit = vf_generate_sse_emit; +#endif + + return vf; +} + + +void vf_destroy( struct vertex_fetch *vf ) +{ + struct vf_fastpath *fp, *tmp; + + for (fp = vf->fastpath ; fp ; fp = tmp) { + tmp = fp->next; + FREE(fp->attr); + + /* KW: At the moment, fp->func is constrained to be allocated by + * _mesa_exec_alloc(), as the hardwired fastpaths in + * t_vertex_generic.c are handled specially. It would be nice + * to unify them, but this probably won't change until this + * module gets another overhaul. + */ + _mesa_exec_free((void *) fp->func); + FREE(fp); + } + + vf->fastpath = NULL; + FREE(vf); +} diff --git a/src/mesa/vf/vf.h b/src/mesa/vf/vf.h new file mode 100644 index 0000000000..83d7547619 --- /dev/null +++ b/src/mesa/vf/vf.h @@ -0,0 +1,234 @@ +/* + * Copyright 2003 Tungsten Graphics, 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Keith Whitwell <keithw@tungstengraphics.com> + */ + +#ifndef VF_VERTEX_H +#define VF_VERTEX_H + +#include "main/mtypes.h" +#include "math/m_vector.h" + +enum { + VF_ATTRIB_POS = 0, + VF_ATTRIB_WEIGHT = 1, + VF_ATTRIB_NORMAL = 2, + VF_ATTRIB_COLOR0 = 3, + VF_ATTRIB_COLOR1 = 4, + VF_ATTRIB_FOG = 5, + VF_ATTRIB_COLOR_INDEX = 6, + VF_ATTRIB_EDGEFLAG = 7, + VF_ATTRIB_TEX0 = 8, + VF_ATTRIB_TEX1 = 9, + VF_ATTRIB_TEX2 = 10, + VF_ATTRIB_TEX3 = 11, + VF_ATTRIB_TEX4 = 12, + VF_ATTRIB_TEX5 = 13, + VF_ATTRIB_TEX6 = 14, + VF_ATTRIB_TEX7 = 15, + VF_ATTRIB_VAR0 = 16, + VF_ATTRIB_VAR1 = 17, + VF_ATTRIB_VAR2 = 18, + VF_ATTRIB_VAR3 = 19, + VF_ATTRIB_VAR4 = 20, + VF_ATTRIB_VAR5 = 21, + VF_ATTRIB_VAR6 = 22, + VF_ATTRIB_VAR7 = 23, + VF_ATTRIB_POINTSIZE = 24, + VF_ATTRIB_BFC0 = 25, + VF_ATTRIB_BFC1 = 26, + VF_ATTRIB_CLIP_POS = 27, + VF_ATTRIB_VERTEX_HEADER = 28, + VF_ATTRIB_MAX = 29 +}; + + +enum vf_attr_format { + EMIT_1F, + EMIT_2F, + EMIT_3F, + EMIT_4F, + EMIT_2F_VIEWPORT, /* do viewport transform and emit */ + EMIT_3F_VIEWPORT, /* do viewport transform and emit */ + EMIT_4F_VIEWPORT, /* do viewport transform and emit */ + EMIT_3F_XYW, /* for projective texture */ + EMIT_1UB_1F, /* for fog coordinate */ + EMIT_3UB_3F_RGB, /* for specular color */ + EMIT_3UB_3F_BGR, /* for specular color */ + EMIT_4UB_4F_RGBA, /* for color */ + EMIT_4UB_4F_BGRA, /* for color */ + EMIT_4UB_4F_ARGB, /* for color */ + EMIT_4UB_4F_ABGR, /* for color */ + EMIT_4CHAN_4F_RGBA, /* for swrast color */ + EMIT_PAD, /* leave a hole of 'offset' bytes */ + EMIT_MAX +}; + +struct vf_attr_map { + GLuint attrib; + enum vf_attr_format format; + GLuint offset; +}; + +struct vertex_fetch; + +void vf_set_vp_matrix( struct vertex_fetch *vf, + const GLfloat *viewport ); + +void vf_set_vp_scale_translate( struct vertex_fetch *vf, + const GLfloat *scale, + const GLfloat *translate ); + +GLuint vf_set_vertex_attributes( struct vertex_fetch *vf, + const struct vf_attr_map *map, + GLuint nr, + GLuint vertex_stride ); + +void vf_set_sources( struct vertex_fetch *vf, + GLvector4f * const attrib[], + GLuint start ); + +void vf_emit_vertices( struct vertex_fetch *vf, + GLuint count, + void *dest ); + +void vf_get_attr( struct vertex_fetch *vf, + const void *vertex, + GLenum attr, + const GLfloat *dflt, + GLfloat *dest ); + +struct vertex_fetch *vf_create( GLboolean allow_viewport_emits ); + +void vf_destroy( struct vertex_fetch *vf ); + + + +/*********************************************************************** + * Internal functions and structs: + */ + +struct vf_attr; + +typedef void (*vf_extract_func)( const struct vf_attr *a, + GLfloat *out, + const GLubyte *v ); + +typedef void (*vf_insert_func)( const struct vf_attr *a, + GLubyte *v, + const GLfloat *in ); + +typedef void (*vf_emit_func)( struct vertex_fetch *vf, + GLuint count, + GLubyte *dest ); + + + +/* Describes how to convert/move a vertex attribute from a vertex + * array to a vertex structure. + */ +struct vf_attr +{ + struct vertex_fetch *vf; + + GLuint format; + GLuint inputsize; + GLuint inputstride; + GLuint vertoffset; /* position of the attrib in the vertex struct */ + + GLuint attrib; /* which vertex attrib (0=position, etc) */ + GLuint vertattrsize; /* size of the attribute in bytes */ + + GLubyte *inputptr; + const vf_insert_func *insert; + vf_insert_func do_insert; + vf_extract_func extract; +}; + +struct vertex_fetch +{ + struct vf_attr attr[VF_ATTRIB_MAX]; + GLuint attr_count; + GLuint vertex_stride; + + struct vf_attr *lookup[VF_ATTRIB_MAX]; + + vf_emit_func emit; + + /* Parameters and constants for codegen: + */ + GLboolean allow_viewport_emits; + GLfloat vp[8]; + GLfloat chan_scale[4]; + GLfloat identity[4]; + + struct vf_fastpath *fastpath; + + void (*codegen_emit)( struct vertex_fetch *vf ); +}; + + +struct vf_attr_type { + GLuint format; + GLuint size; + GLuint stride; + GLuint offset; +}; + +struct vf_fastpath { + GLuint vertex_stride; + GLuint attr_count; + GLboolean match_strides; + + struct vf_attr_type *attr; + + vf_emit_func func; + struct vf_fastpath *next; +}; + + +void vf_register_fastpath( struct vertex_fetch *vtx, + GLboolean match_strides ); + +void vf_generic_emit( struct vertex_fetch *vf, + GLuint count, + GLubyte *v ); + +void vf_generate_hardwired_emit( struct vertex_fetch *vf ); + +void vf_generate_sse_emit( struct vertex_fetch *vf ); + + +struct vf_format_info { + const char *name; + vf_extract_func extract; + vf_insert_func insert[4]; + const GLuint attrsize; +}; + +const struct vf_format_info vf_format_info[EMIT_MAX]; + + +#endif diff --git a/src/mesa/vf/vf_generic.c b/src/mesa/vf/vf_generic.c new file mode 100644 index 0000000000..baa00af29a --- /dev/null +++ b/src/mesa/vf/vf_generic.c @@ -0,0 +1,981 @@ + +/* + * Copyright 2003 Tungsten Graphics, 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Keith Whitwell <keithw@tungstengraphics.com> + */ + +#include "main/glheader.h" +#include "main/context.h" +#include "main/colormac.h" +#include "main/simple_list.h" + +#include "vf/vf.h" + + +/* + * These functions take the NDC coordinates pointed to by 'in', apply the + * NDC->Viewport mapping and store the results at 'v'. + */ + +static INLINE void insert_4f_viewport_4( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)v; + const GLfloat *scale = a->vf->vp; + const GLfloat *trans = a->vf->vp + 4; + + out[0] = scale[0] * in[0] + trans[0]; + out[1] = scale[1] * in[1] + trans[1]; + out[2] = scale[2] * in[2] + trans[2]; + out[3] = in[3]; +} + +static INLINE void insert_4f_viewport_3( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)v; + const GLfloat *scale = a->vf->vp; + const GLfloat *trans = a->vf->vp + 4; + + out[0] = scale[0] * in[0] + trans[0]; + out[1] = scale[1] * in[1] + trans[1]; + out[2] = scale[2] * in[2] + trans[2]; + out[3] = 1; +} + +static INLINE void insert_4f_viewport_2( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)v; + const GLfloat *scale = a->vf->vp; + const GLfloat *trans = a->vf->vp + 4; + + out[0] = scale[0] * in[0] + trans[0]; + out[1] = scale[1] * in[1] + trans[1]; + out[2] = trans[2]; + out[3] = 1; +} + +static INLINE void insert_4f_viewport_1( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)v; + const GLfloat *scale = a->vf->vp; + const GLfloat *trans = a->vf->vp + 4; + + out[0] = scale[0] * in[0] + trans[0]; + out[1] = trans[1]; + out[2] = trans[2]; + out[3] = 1; +} + +static INLINE void insert_3f_viewport_3( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)v; + const GLfloat *scale = a->vf->vp; + const GLfloat *trans = a->vf->vp + 4; + + out[0] = scale[0] * in[0] + trans[0]; + out[1] = scale[1] * in[1] + trans[1]; + out[2] = scale[2] * in[2] + trans[2]; +} + +static INLINE void insert_3f_viewport_2( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)v; + const GLfloat *scale = a->vf->vp; + const GLfloat *trans = a->vf->vp + 4; + + out[0] = scale[0] * in[0] + trans[0]; + out[1] = scale[1] * in[1] + trans[1]; + out[2] = scale[2] * in[2] + trans[2]; +} + +static INLINE void insert_3f_viewport_1( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)v; + const GLfloat *scale = a->vf->vp; + const GLfloat *trans = a->vf->vp + 4; + + out[0] = scale[0] * in[0] + trans[0]; + out[1] = trans[1]; + out[2] = trans[2]; +} + +static INLINE void insert_2f_viewport_2( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)v; + const GLfloat *scale = a->vf->vp; + const GLfloat *trans = a->vf->vp + 4; + + out[0] = scale[0] * in[0] + trans[0]; + out[1] = scale[1] * in[1] + trans[1]; +} + +static INLINE void insert_2f_viewport_1( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)v; + const GLfloat *scale = a->vf->vp; + const GLfloat *trans = a->vf->vp + 4; + + out[0] = scale[0] * in[0] + trans[0]; + out[1] = trans[1]; +} + + +/* + * These functions do the same as above, except for the viewport mapping. + */ + +static INLINE void insert_4f_4( const struct vf_attr *a, GLubyte *v, const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)(v); + (void) a; + + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; +} + +static INLINE void insert_4f_3( const struct vf_attr *a, GLubyte *v, const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)(v); + (void) a; + + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = 1; +} + +static INLINE void insert_4f_2( const struct vf_attr *a, GLubyte *v, const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)(v); + (void) a; + + out[0] = in[0]; + out[1] = in[1]; + out[2] = 0; + out[3] = 1; +} + +static INLINE void insert_4f_1( const struct vf_attr *a, GLubyte *v, const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)(v); + (void) a; + + out[0] = in[0]; + out[1] = 0; + out[2] = 0; + out[3] = 1; +} + +static INLINE void insert_3f_xyw_4( const struct vf_attr *a, GLubyte *v, const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)(v); + (void) a; + + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[3]; +} + +static INLINE void insert_3f_xyw_err( const struct vf_attr *a, GLubyte *v, const GLfloat *in ) +{ + (void) a; (void) v; (void) in; + _mesa_exit(1); +} + +static INLINE void insert_3f_3( const struct vf_attr *a, GLubyte *v, const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)(v); + (void) a; + + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +static INLINE void insert_3f_2( const struct vf_attr *a, GLubyte *v, const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)(v); + (void) a; + + out[0] = in[0]; + out[1] = in[1]; + out[2] = 0; +} + +static INLINE void insert_3f_1( const struct vf_attr *a, GLubyte *v, const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)(v); + (void) a; + + out[0] = in[0]; + out[1] = 0; + out[2] = 0; +} + + +static INLINE void insert_2f_2( const struct vf_attr *a, GLubyte *v, const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)(v); + (void) a; + + out[0] = in[0]; + out[1] = in[1]; +} + +static INLINE void insert_2f_1( const struct vf_attr *a, GLubyte *v, const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)(v); + (void) a; + + out[0] = in[0]; + out[1] = 0; +} + +static INLINE void insert_1f_1( const struct vf_attr *a, GLubyte *v, const GLfloat *in ) +{ + GLfloat *out = (GLfloat *)(v); + (void) a; + + out[0] = in[0]; +} + +static INLINE void insert_null( const struct vf_attr *a, GLubyte *v, const GLfloat *in ) +{ + (void) a; (void) v; (void) in; +} + +static INLINE void insert_4chan_4f_rgba_4( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + GLchan *c = (GLchan *)v; + (void) a; + UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]); + UNCLAMPED_FLOAT_TO_CHAN(c[1], in[1]); + UNCLAMPED_FLOAT_TO_CHAN(c[2], in[2]); + UNCLAMPED_FLOAT_TO_CHAN(c[3], in[3]); +} + +static INLINE void insert_4chan_4f_rgba_3( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + GLchan *c = (GLchan *)v; + (void) a; + UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]); + UNCLAMPED_FLOAT_TO_CHAN(c[1], in[1]); + UNCLAMPED_FLOAT_TO_CHAN(c[2], in[2]); + c[3] = CHAN_MAX; +} + +static INLINE void insert_4chan_4f_rgba_2( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + GLchan *c = (GLchan *)v; + (void) a; + UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]); + UNCLAMPED_FLOAT_TO_CHAN(c[1], in[1]); + c[2] = 0; + c[3] = CHAN_MAX; +} + +static INLINE void insert_4chan_4f_rgba_1( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + GLchan *c = (GLchan *)v; + (void) a; + UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]); + c[1] = 0; + c[2] = 0; + c[3] = CHAN_MAX; +} + +static INLINE void insert_4ub_4f_rgba_4( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]); + UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[3]); +} + +static INLINE void insert_4ub_4f_rgba_3( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]); + v[3] = 0xff; +} + +static INLINE void insert_4ub_4f_rgba_2( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); + v[2] = 0; + v[3] = 0xff; +} + +static INLINE void insert_4ub_4f_rgba_1( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); + v[1] = 0; + v[2] = 0; + v[3] = 0xff; +} + +static INLINE void insert_4ub_4f_bgra_4( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); + UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]); + UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[3]); +} + +static INLINE void insert_4ub_4f_bgra_3( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); + UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]); + v[3] = 0xff; +} + +static INLINE void insert_4ub_4f_bgra_2( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); + v[0] = 0; + v[3] = 0xff; +} + +static INLINE void insert_4ub_4f_bgra_1( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); + v[1] = 0; + v[0] = 0; + v[3] = 0xff; +} + +static INLINE void insert_4ub_4f_argb_4( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); + UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[2]); + UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[3]); +} + +static INLINE void insert_4ub_4f_argb_3( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); + UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[2]); + v[0] = 0xff; +} + +static INLINE void insert_4ub_4f_argb_2( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); + v[3] = 0x00; + v[0] = 0xff; +} + +static INLINE void insert_4ub_4f_argb_1( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]); + v[2] = 0x00; + v[3] = 0x00; + v[0] = 0xff; +} + +static INLINE void insert_4ub_4f_abgr_4( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[2]); + UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[3]); +} + +static INLINE void insert_4ub_4f_abgr_3( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[2]); + v[0] = 0xff; +} + +static INLINE void insert_4ub_4f_abgr_2( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); + v[1] = 0x00; + v[0] = 0xff; +} + +static INLINE void insert_4ub_4f_abgr_1( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]); + v[2] = 0x00; + v[1] = 0x00; + v[0] = 0xff; +} + +static INLINE void insert_3ub_3f_rgb_3( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]); +} + +static INLINE void insert_3ub_3f_rgb_2( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); + v[2] = 0; +} + +static INLINE void insert_3ub_3f_rgb_1( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); + v[1] = 0; + v[2] = 0; +} + +static INLINE void insert_3ub_3f_bgr_3( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); + UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]); +} + +static INLINE void insert_3ub_3f_bgr_2( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); + UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); + v[0] = 0; +} + +static INLINE void insert_3ub_3f_bgr_1( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); + v[1] = 0; + v[0] = 0; +} + + +static INLINE void insert_1ub_1f_1( const struct vf_attr *a, GLubyte *v, + const GLfloat *in ) +{ + (void) a; + UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); +} + + +/*********************************************************************** + * Functions to perform the reverse operations to the above, for + * swrast translation and clip-interpolation. + * + * Currently always extracts a full 4 floats. + */ + +static void extract_4f_viewport( const struct vf_attr *a, GLfloat *out, + const GLubyte *v ) +{ + const GLfloat *in = (const GLfloat *)v; + const GLfloat *scale = a->vf->vp; + const GLfloat *trans = a->vf->vp + 4; + + /* Although included for completeness, the position coordinate is + * usually handled differently during clipping. + */ + out[0] = (in[0] - trans[0]) / scale[0]; + out[1] = (in[1] - trans[1]) / scale[1]; + out[2] = (in[2] - trans[2]) / scale[2]; + out[3] = in[3]; +} + +static void extract_3f_viewport( const struct vf_attr *a, GLfloat *out, + const GLubyte *v ) +{ + const GLfloat *in = (const GLfloat *)v; + const GLfloat *scale = a->vf->vp; + const GLfloat *trans = a->vf->vp + 4; + + out[0] = (in[0] - trans[0]) / scale[0]; + out[1] = (in[1] - trans[1]) / scale[1]; + out[2] = (in[2] - trans[2]) / scale[2]; + out[3] = 1; +} + + +static void extract_2f_viewport( const struct vf_attr *a, GLfloat *out, + const GLubyte *v ) +{ + const GLfloat *in = (const GLfloat *)v; + const GLfloat *scale = a->vf->vp; + const GLfloat *trans = a->vf->vp + 4; + + out[0] = (in[0] - trans[0]) / scale[0]; + out[1] = (in[1] - trans[1]) / scale[1]; + out[2] = 0; + out[3] = 1; +} + + +static void extract_4f( const struct vf_attr *a, GLfloat *out, const GLubyte *v ) +{ + const GLfloat *in = (const GLfloat *)v; + (void) a; + + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; +} + +static void extract_3f_xyw( const struct vf_attr *a, GLfloat *out, const GLubyte *v ) +{ + const GLfloat *in = (const GLfloat *)v; + (void) a; + + out[0] = in[0]; + out[1] = in[1]; + out[2] = 0; + out[3] = in[2]; +} + + +static void extract_3f( const struct vf_attr *a, GLfloat *out, const GLubyte *v ) +{ + const GLfloat *in = (const GLfloat *)v; + (void) a; + + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = 1; +} + + +static void extract_2f( const struct vf_attr *a, GLfloat *out, const GLubyte *v ) +{ + const GLfloat *in = (const GLfloat *)v; + (void) a; + + out[0] = in[0]; + out[1] = in[1]; + out[2] = 0; + out[3] = 1; +} + +static void extract_1f( const struct vf_attr *a, GLfloat *out, const GLubyte *v ) +{ + const GLfloat *in = (const GLfloat *)v; + (void) a; + + out[0] = in[0]; + out[1] = 0; + out[2] = 0; + out[3] = 1; +} + +static void extract_4chan_4f_rgba( const struct vf_attr *a, GLfloat *out, + const GLubyte *v ) +{ + GLchan *c = (GLchan *)v; + (void) a; + + out[0] = CHAN_TO_FLOAT(c[0]); + out[1] = CHAN_TO_FLOAT(c[1]); + out[2] = CHAN_TO_FLOAT(c[2]); + out[3] = CHAN_TO_FLOAT(c[3]); +} + +static void extract_4ub_4f_rgba( const struct vf_attr *a, GLfloat *out, + const GLubyte *v ) +{ + (void) a; + out[0] = UBYTE_TO_FLOAT(v[0]); + out[1] = UBYTE_TO_FLOAT(v[1]); + out[2] = UBYTE_TO_FLOAT(v[2]); + out[3] = UBYTE_TO_FLOAT(v[3]); +} + +static void extract_4ub_4f_bgra( const struct vf_attr *a, GLfloat *out, + const GLubyte *v ) +{ + (void) a; + out[2] = UBYTE_TO_FLOAT(v[0]); + out[1] = UBYTE_TO_FLOAT(v[1]); + out[0] = UBYTE_TO_FLOAT(v[2]); + out[3] = UBYTE_TO_FLOAT(v[3]); +} + +static void extract_4ub_4f_argb( const struct vf_attr *a, GLfloat *out, + const GLubyte *v ) +{ + (void) a; + out[3] = UBYTE_TO_FLOAT(v[0]); + out[0] = UBYTE_TO_FLOAT(v[1]); + out[1] = UBYTE_TO_FLOAT(v[2]); + out[2] = UBYTE_TO_FLOAT(v[3]); +} + +static void extract_4ub_4f_abgr( const struct vf_attr *a, GLfloat *out, + const GLubyte *v ) +{ + (void) a; + out[3] = UBYTE_TO_FLOAT(v[0]); + out[2] = UBYTE_TO_FLOAT(v[1]); + out[1] = UBYTE_TO_FLOAT(v[2]); + out[0] = UBYTE_TO_FLOAT(v[3]); +} + +static void extract_3ub_3f_rgb( const struct vf_attr *a, GLfloat *out, + const GLubyte *v ) +{ + (void) a; + out[0] = UBYTE_TO_FLOAT(v[0]); + out[1] = UBYTE_TO_FLOAT(v[1]); + out[2] = UBYTE_TO_FLOAT(v[2]); + out[3] = 1; +} + +static void extract_3ub_3f_bgr( const struct vf_attr *a, GLfloat *out, + const GLubyte *v ) +{ + (void) a; + out[2] = UBYTE_TO_FLOAT(v[0]); + out[1] = UBYTE_TO_FLOAT(v[1]); + out[0] = UBYTE_TO_FLOAT(v[2]); + out[3] = 1; +} + +static void extract_1ub_1f( const struct vf_attr *a, GLfloat *out, const GLubyte *v ) +{ + (void) a; + out[0] = UBYTE_TO_FLOAT(v[0]); + out[1] = 0; + out[2] = 0; + out[3] = 1; +} + + +const struct vf_format_info vf_format_info[EMIT_MAX] = +{ + { "1f", + extract_1f, + { insert_1f_1, insert_1f_1, insert_1f_1, insert_1f_1 }, + sizeof(GLfloat) }, + + { "2f", + extract_2f, + { insert_2f_1, insert_2f_2, insert_2f_2, insert_2f_2 }, + 2 * sizeof(GLfloat) }, + + { "3f", + extract_3f, + { insert_3f_1, insert_3f_2, insert_3f_3, insert_3f_3 }, + 3 * sizeof(GLfloat) }, + + { "4f", + extract_4f, + { insert_4f_1, insert_4f_2, insert_4f_3, insert_4f_4 }, + 4 * sizeof(GLfloat) }, + + { "2f_viewport", + extract_2f_viewport, + { insert_2f_viewport_1, insert_2f_viewport_2, insert_2f_viewport_2, + insert_2f_viewport_2 }, + 2 * sizeof(GLfloat) }, + + { "3f_viewport", + extract_3f_viewport, + { insert_3f_viewport_1, insert_3f_viewport_2, insert_3f_viewport_3, + insert_3f_viewport_3 }, + 3 * sizeof(GLfloat) }, + + { "4f_viewport", + extract_4f_viewport, + { insert_4f_viewport_1, insert_4f_viewport_2, insert_4f_viewport_3, + insert_4f_viewport_4 }, + 4 * sizeof(GLfloat) }, + + { "3f_xyw", + extract_3f_xyw, + { insert_3f_xyw_err, insert_3f_xyw_err, insert_3f_xyw_err, + insert_3f_xyw_4 }, + 3 * sizeof(GLfloat) }, + + { "1ub_1f", + extract_1ub_1f, + { insert_1ub_1f_1, insert_1ub_1f_1, insert_1ub_1f_1, insert_1ub_1f_1 }, + sizeof(GLubyte) }, + + { "3ub_3f_rgb", + extract_3ub_3f_rgb, + { insert_3ub_3f_rgb_1, insert_3ub_3f_rgb_2, insert_3ub_3f_rgb_3, + insert_3ub_3f_rgb_3 }, + 3 * sizeof(GLubyte) }, + + { "3ub_3f_bgr", + extract_3ub_3f_bgr, + { insert_3ub_3f_bgr_1, insert_3ub_3f_bgr_2, insert_3ub_3f_bgr_3, + insert_3ub_3f_bgr_3 }, + 3 * sizeof(GLubyte) }, + + { "4ub_4f_rgba", + extract_4ub_4f_rgba, + { insert_4ub_4f_rgba_1, insert_4ub_4f_rgba_2, insert_4ub_4f_rgba_3, + insert_4ub_4f_rgba_4 }, + 4 * sizeof(GLubyte) }, + + { "4ub_4f_bgra", + extract_4ub_4f_bgra, + { insert_4ub_4f_bgra_1, insert_4ub_4f_bgra_2, insert_4ub_4f_bgra_3, + insert_4ub_4f_bgra_4 }, + 4 * sizeof(GLubyte) }, + + { "4ub_4f_argb", + extract_4ub_4f_argb, + { insert_4ub_4f_argb_1, insert_4ub_4f_argb_2, insert_4ub_4f_argb_3, + insert_4ub_4f_argb_4 }, + 4 * sizeof(GLubyte) }, + + { "4ub_4f_abgr", + extract_4ub_4f_abgr, + { insert_4ub_4f_abgr_1, insert_4ub_4f_abgr_2, insert_4ub_4f_abgr_3, + insert_4ub_4f_abgr_4 }, + 4 * sizeof(GLubyte) }, + + { "4chan_4f_rgba", + extract_4chan_4f_rgba, + { insert_4chan_4f_rgba_1, insert_4chan_4f_rgba_2, insert_4chan_4f_rgba_3, + insert_4chan_4f_rgba_4 }, + 4 * sizeof(GLchan) }, + + { "pad", + NULL, + { NULL, NULL, NULL, NULL }, + 0 } + +}; + + + + +/*********************************************************************** + * Hardwired fastpaths for emitting whole vertices or groups of + * vertices + */ +#define EMIT5(NR, F0, F1, F2, F3, F4, NAME) \ +static void NAME( struct vertex_fetch *vf, \ + GLuint count, \ + GLubyte *v ) \ +{ \ + struct vf_attr *a = vf->attr; \ + GLuint i; \ + \ + for (i = 0 ; i < count ; i++, v += vf->vertex_stride) { \ + if (NR > 0) { \ + F0( &a[0], v + a[0].vertoffset, (GLfloat *)a[0].inputptr ); \ + a[0].inputptr += a[0].inputstride; \ + } \ + \ + if (NR > 1) { \ + F1( &a[1], v + a[1].vertoffset, (GLfloat *)a[1].inputptr ); \ + a[1].inputptr += a[1].inputstride; \ + } \ + \ + if (NR > 2) { \ + F2( &a[2], v + a[2].vertoffset, (GLfloat *)a[2].inputptr ); \ + a[2].inputptr += a[2].inputstride; \ + } \ + \ + if (NR > 3) { \ + F3( &a[3], v + a[3].vertoffset, (GLfloat *)a[3].inputptr ); \ + a[3].inputptr += a[3].inputstride; \ + } \ + \ + if (NR > 4) { \ + F4( &a[4], v + a[4].vertoffset, (GLfloat *)a[4].inputptr ); \ + a[4].inputptr += a[4].inputstride; \ + } \ + } \ +} + + +#define EMIT2(F0, F1, NAME) EMIT5(2, F0, F1, insert_null, \ + insert_null, insert_null, NAME) + +#define EMIT3(F0, F1, F2, NAME) EMIT5(3, F0, F1, F2, insert_null, \ + insert_null, NAME) + +#define EMIT4(F0, F1, F2, F3, NAME) EMIT5(4, F0, F1, F2, F3, \ + insert_null, NAME) + + +EMIT2(insert_3f_viewport_3, insert_4ub_4f_rgba_4, emit_viewport3_rgba4) +EMIT2(insert_3f_viewport_3, insert_4ub_4f_bgra_4, emit_viewport3_bgra4) +EMIT2(insert_3f_3, insert_4ub_4f_rgba_4, emit_xyz3_rgba4) + +EMIT3(insert_4f_viewport_4, insert_4ub_4f_rgba_4, insert_2f_2, emit_viewport4_rgba4_st2) +EMIT3(insert_4f_viewport_4, insert_4ub_4f_bgra_4, insert_2f_2, emit_viewport4_bgra4_st2) +EMIT3(insert_4f_4, insert_4ub_4f_rgba_4, insert_2f_2, emit_xyzw4_rgba4_st2) + +EMIT4(insert_4f_viewport_4, insert_4ub_4f_rgba_4, insert_2f_2, insert_2f_2, emit_viewport4_rgba4_st2_st2) +EMIT4(insert_4f_viewport_4, insert_4ub_4f_bgra_4, insert_2f_2, insert_2f_2, emit_viewport4_bgra4_st2_st2) +EMIT4(insert_4f_4, insert_4ub_4f_rgba_4, insert_2f_2, insert_2f_2, emit_xyzw4_rgba4_st2_st2) + + +/* Use the codegen paths to select one of a number of hardwired + * fastpaths. + */ +void vf_generate_hardwired_emit( struct vertex_fetch *vf ) +{ + vf_emit_func func = NULL; + + /* Does it fit a hardwired fastpath? Help! this is growing out of + * control! + */ + switch (vf->attr_count) { + case 2: + if (vf->attr[0].do_insert == insert_3f_viewport_3) { + if (vf->attr[1].do_insert == insert_4ub_4f_bgra_4) + func = emit_viewport3_bgra4; + else if (vf->attr[1].do_insert == insert_4ub_4f_rgba_4) + func = emit_viewport3_rgba4; + } + else if (vf->attr[0].do_insert == insert_3f_3 && + vf->attr[1].do_insert == insert_4ub_4f_rgba_4) { + func = emit_xyz3_rgba4; + } + break; + case 3: + if (vf->attr[2].do_insert == insert_2f_2) { + if (vf->attr[1].do_insert == insert_4ub_4f_rgba_4) { + if (vf->attr[0].do_insert == insert_4f_viewport_4) + func = emit_viewport4_rgba4_st2; + else if (vf->attr[0].do_insert == insert_4f_4) + func = emit_xyzw4_rgba4_st2; + } + else if (vf->attr[1].do_insert == insert_4ub_4f_bgra_4 && + vf->attr[0].do_insert == insert_4f_viewport_4) + func = emit_viewport4_bgra4_st2; + } + break; + case 4: + if (vf->attr[2].do_insert == insert_2f_2 && + vf->attr[3].do_insert == insert_2f_2) { + if (vf->attr[1].do_insert == insert_4ub_4f_rgba_4) { + if (vf->attr[0].do_insert == insert_4f_viewport_4) + func = emit_viewport4_rgba4_st2_st2; + else if (vf->attr[0].do_insert == insert_4f_4) + func = emit_xyzw4_rgba4_st2_st2; + } + else if (vf->attr[1].do_insert == insert_4ub_4f_bgra_4 && + vf->attr[0].do_insert == insert_4f_viewport_4) + func = emit_viewport4_bgra4_st2_st2; + } + break; + } + + vf->emit = func; +} + +/*********************************************************************** + * Generic (non-codegen) functions for whole vertices or groups of + * vertices + */ + +void vf_generic_emit( struct vertex_fetch *vf, + GLuint count, + GLubyte *v ) +{ + struct vf_attr *a = vf->attr; + const GLuint attr_count = vf->attr_count; + const GLuint stride = vf->vertex_stride; + GLuint i, j; + + for (i = 0 ; i < count ; i++, v += stride) { + for (j = 0; j < attr_count; j++) { + GLfloat *in = (GLfloat *)a[j].inputptr; + a[j].inputptr += a[j].inputstride; + a[j].do_insert( &a[j], v + a[j].vertoffset, in ); + } + } +} + + diff --git a/src/mesa/vf/vf_sse.c b/src/mesa/vf/vf_sse.c new file mode 100644 index 0000000000..4d70196ffe --- /dev/null +++ b/src/mesa/vf/vf_sse.c @@ -0,0 +1,662 @@ +/* + * Copyright 2003 Tungsten Graphics, 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Keith Whitwell <keithw@tungstengraphics.com> + */ + +#include "main/glheader.h" +#include "main/colormac.h" +#include "main/simple_list.h" +#include "main/enums.h" + +#include "vf/vf.h" + +#if defined(USE_SSE_ASM) + +#include "x86/rtasm/x86sse.h" +#include "x86/common_x86_asm.h" + + +#define X 0 +#define Y 1 +#define Z 2 +#define W 3 + + +struct x86_program { + struct x86_function func; + + struct vertex_fetch *vf; + GLboolean inputs_safe; + GLboolean outputs_safe; + GLboolean have_sse2; + + struct x86_reg identity; + struct x86_reg chan0; +}; + + +static struct x86_reg get_identity( struct x86_program *p ) +{ + return p->identity; +} + +static void emit_load4f_4( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + sse_movups(&p->func, dest, arg0); +} + +static void emit_load4f_3( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + /* Have to jump through some hoops: + * + * c 0 0 0 + * c 0 0 1 + * 0 0 c 1 + * a b c 1 + */ + sse_movss(&p->func, dest, x86_make_disp(arg0, 8)); + sse_shufps(&p->func, dest, get_identity(p), SHUF(X,Y,Z,W) ); + sse_shufps(&p->func, dest, dest, SHUF(Y,Z,X,W) ); + sse_movlps(&p->func, dest, arg0); +} + +static void emit_load4f_2( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + /* Initialize from identity, then pull in low two words: + */ + sse_movups(&p->func, dest, get_identity(p)); + sse_movlps(&p->func, dest, arg0); +} + +static void emit_load4f_1( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + /* Pull in low word, then swizzle in identity */ + sse_movss(&p->func, dest, arg0); + sse_shufps(&p->func, dest, get_identity(p), SHUF(X,Y,Z,W) ); +} + + + +static void emit_load3f_3( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + /* Over-reads by 1 dword - potential SEGV if input is a vertex + * array. + */ + if (p->inputs_safe) { + sse_movups(&p->func, dest, arg0); + } + else { + /* c 0 0 0 + * c c c c + * a b c c + */ + sse_movss(&p->func, dest, x86_make_disp(arg0, 8)); + sse_shufps(&p->func, dest, dest, SHUF(X,X,X,X)); + sse_movlps(&p->func, dest, arg0); + } +} + +static void emit_load3f_2( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + emit_load4f_2(p, dest, arg0); +} + +static void emit_load3f_1( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + emit_load4f_1(p, dest, arg0); +} + +static void emit_load2f_2( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + sse_movlps(&p->func, dest, arg0); +} + +static void emit_load2f_1( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + emit_load4f_1(p, dest, arg0); +} + +static void emit_load1f_1( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + sse_movss(&p->func, dest, arg0); +} + +static void (*load[4][4])( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) = { + { emit_load1f_1, + emit_load1f_1, + emit_load1f_1, + emit_load1f_1 }, + + { emit_load2f_1, + emit_load2f_2, + emit_load2f_2, + emit_load2f_2 }, + + { emit_load3f_1, + emit_load3f_2, + emit_load3f_3, + emit_load3f_3 }, + + { emit_load4f_1, + emit_load4f_2, + emit_load4f_3, + emit_load4f_4 } +}; + +static void emit_load( struct x86_program *p, + struct x86_reg dest, + GLuint sz, + struct x86_reg src, + GLuint src_sz) +{ + load[sz-1][src_sz-1](p, dest, src); +} + +static void emit_store4f( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + sse_movups(&p->func, dest, arg0); +} + +static void emit_store3f( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + if (p->outputs_safe) { + /* Emit the extra dword anyway. This may hurt writecombining, + * may cause other problems. + */ + sse_movups(&p->func, dest, arg0); + } + else { + /* Alternate strategy - emit two, shuffle, emit one. + */ + sse_movlps(&p->func, dest, arg0); + sse_shufps(&p->func, arg0, arg0, SHUF(Z,Z,Z,Z) ); /* NOTE! destructive */ + sse_movss(&p->func, x86_make_disp(dest,8), arg0); + } +} + +static void emit_store2f( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + sse_movlps(&p->func, dest, arg0); +} + +static void emit_store1f( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) +{ + sse_movss(&p->func, dest, arg0); +} + + +static void (*store[4])( struct x86_program *p, + struct x86_reg dest, + struct x86_reg arg0 ) = +{ + emit_store1f, + emit_store2f, + emit_store3f, + emit_store4f +}; + +static void emit_store( struct x86_program *p, + struct x86_reg dest, + GLuint sz, + struct x86_reg temp ) + +{ + store[sz-1](p, dest, temp); +} + +static void emit_pack_store_4ub( struct x86_program *p, + struct x86_reg dest, + struct x86_reg temp ) +{ + /* Scale by 255.0 + */ + sse_mulps(&p->func, temp, p->chan0); + + if (p->have_sse2) { + sse2_cvtps2dq(&p->func, temp, temp); + sse2_packssdw(&p->func, temp, temp); + sse2_packuswb(&p->func, temp, temp); + sse_movss(&p->func, dest, temp); + } + else { + struct x86_reg mmx0 = x86_make_reg(file_MMX, 0); + struct x86_reg mmx1 = x86_make_reg(file_MMX, 1); + sse_cvtps2pi(&p->func, mmx0, temp); + sse_movhlps(&p->func, temp, temp); + sse_cvtps2pi(&p->func, mmx1, temp); + mmx_packssdw(&p->func, mmx0, mmx1); + mmx_packuswb(&p->func, mmx0, mmx0); + mmx_movd(&p->func, dest, mmx0); + } +} + +static GLint get_offset( const void *a, const void *b ) +{ + return (const char *)b - (const char *)a; +} + +/* Not much happens here. Eventually use this function to try and + * avoid saving/reloading the source pointers each vertex (if some of + * them can fit in registers). + */ +static void get_src_ptr( struct x86_program *p, + struct x86_reg srcREG, + struct x86_reg vfREG, + struct vf_attr *a ) +{ + struct vertex_fetch *vf = p->vf; + struct x86_reg ptr_to_src = x86_make_disp(vfREG, get_offset(vf, &a->inputptr)); + + /* Load current a[j].inputptr + */ + x86_mov(&p->func, srcREG, ptr_to_src); +} + +static void update_src_ptr( struct x86_program *p, + struct x86_reg srcREG, + struct x86_reg vfREG, + struct vf_attr *a ) +{ + if (a->inputstride) { + struct vertex_fetch *vf = p->vf; + struct x86_reg ptr_to_src = x86_make_disp(vfREG, get_offset(vf, &a->inputptr)); + + /* add a[j].inputstride (hardcoded value - could just as easily + * pull the stride value from memory each time). + */ + x86_lea(&p->func, srcREG, x86_make_disp(srcREG, a->inputstride)); + + /* save new value of a[j].inputptr + */ + x86_mov(&p->func, ptr_to_src, srcREG); + } +} + + +/* Lots of hardcoding + * + * EAX -- pointer to current output vertex + * ECX -- pointer to current attribute + * + */ +static GLboolean build_vertex_emit( struct x86_program *p ) +{ + struct vertex_fetch *vf = p->vf; + GLuint j = 0; + + struct x86_reg vertexEAX = x86_make_reg(file_REG32, reg_AX); + struct x86_reg srcECX = x86_make_reg(file_REG32, reg_CX); + struct x86_reg countEBP = x86_make_reg(file_REG32, reg_BP); + struct x86_reg vfESI = x86_make_reg(file_REG32, reg_SI); + struct x86_reg temp = x86_make_reg(file_XMM, 0); + struct x86_reg vp0 = x86_make_reg(file_XMM, 1); + struct x86_reg vp1 = x86_make_reg(file_XMM, 2); + GLubyte *fixup, *label; + + /* Push a few regs? + */ + x86_push(&p->func, countEBP); + x86_push(&p->func, vfESI); + + + /* Get vertex count, compare to zero + */ + x86_xor(&p->func, srcECX, srcECX); + x86_mov(&p->func, countEBP, x86_fn_arg(&p->func, 2)); + x86_cmp(&p->func, countEBP, srcECX); + fixup = x86_jcc_forward(&p->func, cc_E); + + /* Initialize destination register. + */ + x86_mov(&p->func, vertexEAX, x86_fn_arg(&p->func, 3)); + + /* Move argument 1 (vf) into a reg: + */ + x86_mov(&p->func, vfESI, x86_fn_arg(&p->func, 1)); + + + /* Possibly load vp0, vp1 for viewport calcs: + */ + if (vf->allow_viewport_emits) { + sse_movups(&p->func, vp0, x86_make_disp(vfESI, get_offset(vf, &vf->vp[0]))); + sse_movups(&p->func, vp1, x86_make_disp(vfESI, get_offset(vf, &vf->vp[4]))); + } + + /* always load, needed or not: + */ + sse_movups(&p->func, p->chan0, x86_make_disp(vfESI, get_offset(vf, &vf->chan_scale[0]))); + sse_movups(&p->func, p->identity, x86_make_disp(vfESI, get_offset(vf, &vf->identity[0]))); + + /* Note address for loop jump */ + label = x86_get_label(&p->func); + + /* Emit code for each of the attributes. Currently routes + * everything through SSE registers, even when it might be more + * efficient to stick with regular old x86. No optimization or + * other tricks - enough new ground to cover here just getting + * things working. + */ + while (j < vf->attr_count) { + struct vf_attr *a = &vf->attr[j]; + struct x86_reg dest = x86_make_disp(vertexEAX, a->vertoffset); + + /* Now, load an XMM reg from src, perhaps transform, then save. + * Could be shortcircuited in specific cases: + */ + switch (a->format) { + case EMIT_1F: + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 1, x86_deref(srcECX), a->inputsize); + emit_store(p, dest, 1, temp); + update_src_ptr(p, srcECX, vfESI, a); + break; + case EMIT_2F: + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 2, x86_deref(srcECX), a->inputsize); + emit_store(p, dest, 2, temp); + update_src_ptr(p, srcECX, vfESI, a); + break; + case EMIT_3F: + /* Potentially the worst case - hardcode 2+1 copying: + */ + if (0) { + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize); + emit_store(p, dest, 3, temp); + update_src_ptr(p, srcECX, vfESI, a); + } + else { + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 2, x86_deref(srcECX), a->inputsize); + emit_store(p, dest, 2, temp); + if (a->inputsize > 2) { + emit_load(p, temp, 1, x86_make_disp(srcECX, 8), 1); + emit_store(p, x86_make_disp(dest,8), 1, temp); + } + else { + sse_movss(&p->func, x86_make_disp(dest,8), get_identity(p)); + } + update_src_ptr(p, srcECX, vfESI, a); + } + break; + case EMIT_4F: + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); + emit_store(p, dest, 4, temp); + update_src_ptr(p, srcECX, vfESI, a); + break; + case EMIT_2F_VIEWPORT: + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 2, x86_deref(srcECX), a->inputsize); + sse_mulps(&p->func, temp, vp0); + sse_addps(&p->func, temp, vp1); + emit_store(p, dest, 2, temp); + update_src_ptr(p, srcECX, vfESI, a); + break; + case EMIT_3F_VIEWPORT: + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize); + sse_mulps(&p->func, temp, vp0); + sse_addps(&p->func, temp, vp1); + emit_store(p, dest, 3, temp); + update_src_ptr(p, srcECX, vfESI, a); + break; + case EMIT_4F_VIEWPORT: + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); + sse_mulps(&p->func, temp, vp0); + sse_addps(&p->func, temp, vp1); + emit_store(p, dest, 4, temp); + update_src_ptr(p, srcECX, vfESI, a); + break; + case EMIT_3F_XYW: + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); + sse_shufps(&p->func, temp, temp, SHUF(X,Y,W,Z)); + emit_store(p, dest, 3, temp); + update_src_ptr(p, srcECX, vfESI, a); + break; + + case EMIT_1UB_1F: + /* Test for PAD3 + 1UB: + */ + if (j > 0 && + a[-1].vertoffset + a[-1].vertattrsize <= a->vertoffset - 3) + { + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 1, x86_deref(srcECX), a->inputsize); + sse_shufps(&p->func, temp, temp, SHUF(X,X,X,X)); + emit_pack_store_4ub(p, x86_make_disp(dest, -3), temp); /* overkill! */ + update_src_ptr(p, srcECX, vfESI, a); + } + else { + _mesa_printf("Can't emit 1ub %x %x %d\n", a->vertoffset, a[-1].vertoffset, a[-1].vertattrsize ); + return GL_FALSE; + } + break; + case EMIT_3UB_3F_RGB: + case EMIT_3UB_3F_BGR: + /* Test for 3UB + PAD1: + */ + if (j == vf->attr_count - 1 || + a[1].vertoffset >= a->vertoffset + 4) { + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize); + if (a->format == EMIT_3UB_3F_BGR) + sse_shufps(&p->func, temp, temp, SHUF(Z,Y,X,W)); + emit_pack_store_4ub(p, dest, temp); + update_src_ptr(p, srcECX, vfESI, a); + } + /* Test for 3UB + 1UB: + */ + else if (j < vf->attr_count - 1 && + a[1].format == EMIT_1UB_1F && + a[1].vertoffset == a->vertoffset + 3) { + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize); + update_src_ptr(p, srcECX, vfESI, a); + + /* Make room for incoming value: + */ + sse_shufps(&p->func, temp, temp, SHUF(W,X,Y,Z)); + + get_src_ptr(p, srcECX, vfESI, &a[1]); + emit_load(p, temp, 1, x86_deref(srcECX), a[1].inputsize); + update_src_ptr(p, srcECX, vfESI, &a[1]); + + /* Rearrange and possibly do BGR conversion: + */ + if (a->format == EMIT_3UB_3F_BGR) + sse_shufps(&p->func, temp, temp, SHUF(W,Z,Y,X)); + else + sse_shufps(&p->func, temp, temp, SHUF(Y,Z,W,X)); + + emit_pack_store_4ub(p, dest, temp); + j++; /* NOTE: two attrs consumed */ + } + else { + _mesa_printf("Can't emit 3ub\n"); + } + return GL_FALSE; /* add this later */ + break; + + case EMIT_4UB_4F_RGBA: + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); + emit_pack_store_4ub(p, dest, temp); + update_src_ptr(p, srcECX, vfESI, a); + break; + case EMIT_4UB_4F_BGRA: + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); + sse_shufps(&p->func, temp, temp, SHUF(Z,Y,X,W)); + emit_pack_store_4ub(p, dest, temp); + update_src_ptr(p, srcECX, vfESI, a); + break; + case EMIT_4UB_4F_ARGB: + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); + sse_shufps(&p->func, temp, temp, SHUF(W,X,Y,Z)); + emit_pack_store_4ub(p, dest, temp); + update_src_ptr(p, srcECX, vfESI, a); + break; + case EMIT_4UB_4F_ABGR: + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); + sse_shufps(&p->func, temp, temp, SHUF(W,Z,Y,X)); + emit_pack_store_4ub(p, dest, temp); + update_src_ptr(p, srcECX, vfESI, a); + break; + case EMIT_4CHAN_4F_RGBA: + switch (CHAN_TYPE) { + case GL_UNSIGNED_BYTE: + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); + emit_pack_store_4ub(p, dest, temp); + update_src_ptr(p, srcECX, vfESI, a); + break; + case GL_FLOAT: + get_src_ptr(p, srcECX, vfESI, a); + emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); + emit_store(p, dest, 4, temp); + update_src_ptr(p, srcECX, vfESI, a); + break; + case GL_UNSIGNED_SHORT: + default: + _mesa_printf("unknown CHAN_TYPE %s\n", _mesa_lookup_enum_by_nr(CHAN_TYPE)); + return GL_FALSE; + } + break; + default: + _mesa_printf("unknown a[%d].format %d\n", j, a->format); + return GL_FALSE; /* catch any new opcodes */ + } + + /* Increment j by at least 1 - may have been incremented above also: + */ + j++; + } + + /* Next vertex: + */ + x86_lea(&p->func, vertexEAX, x86_make_disp(vertexEAX, vf->vertex_stride)); + + /* decr count, loop if not zero + */ + x86_dec(&p->func, countEBP); + x86_test(&p->func, countEBP, countEBP); + x86_jcc(&p->func, cc_NZ, label); + + /* Exit mmx state? + */ + if (p->func.need_emms) + mmx_emms(&p->func); + + /* Land forward jump here: + */ + x86_fixup_fwd_jump(&p->func, fixup); + + /* Pop regs and return + */ + x86_pop(&p->func, x86_get_base_reg(vfESI)); + x86_pop(&p->func, countEBP); + x86_ret(&p->func); + + vf->emit = (vf_emit_func)x86_get_func(&p->func); + return GL_TRUE; +} + + + +void vf_generate_sse_emit( struct vertex_fetch *vf ) +{ + struct x86_program p; + + if (!cpu_has_xmm) { + vf->codegen_emit = NULL; + return; + } + + _mesa_memset(&p, 0, sizeof(p)); + + p.vf = vf; + p.inputs_safe = 0; /* for now */ + p.outputs_safe = 0; /* for now */ + p.have_sse2 = cpu_has_xmm2; + p.identity = x86_make_reg(file_XMM, 6); + p.chan0 = x86_make_reg(file_XMM, 7); + + x86_init_func(&p.func); + + if (build_vertex_emit(&p)) { + vf_register_fastpath( vf, GL_TRUE ); + } + else { + /* Note the failure so that we don't keep trying to codegen an + * impossible state: + */ + vf_register_fastpath( vf, GL_FALSE ); + x86_release_func(&p.func); + } +} + +#else + +void vf_generate_sse_emit( struct vertex_fetch *vf ) +{ + /* Dummy version for when USE_SSE_ASM not defined */ +} + +#endif diff --git a/src/mesa/x86/Makefile b/src/mesa/x86/Makefile index dc8c7f355e..aa49a9134a 100644 --- a/src/mesa/x86/Makefile +++ b/src/mesa/x86/Makefile @@ -21,7 +21,7 @@ clean: gen_matypes: gen_matypes.c - $(CC) $(INCLUDE_DIRS) $(CFLAGS) gen_matypes.c -o gen_matypes + $(HOST_CC) $(INCLUDE_DIRS) $(HOST_CFLAGS) gen_matypes.c -o gen_matypes # need some special rules here, unfortunately matypes.h: ../main/mtypes.h ../tnl/t_context.h gen_matypes diff --git a/src/mesa/x86/rtasm/x86sse.c b/src/mesa/x86/rtasm/x86sse.c index e68f8dfec1..5aedf5b04b 100644 --- a/src/mesa/x86/rtasm/x86sse.c +++ b/src/mesa/x86/rtasm/x86sse.c @@ -1,3 +1,4 @@ +#ifdef USE_X86_ASM #if defined(__i386__) || defined(__386__) #include "main/imports.h" @@ -290,7 +291,7 @@ void x86_call( struct x86_function *p, void (*label)()) void x86_call( struct x86_function *p, struct x86_reg reg) { emit_1ub(p, 0xff); - emit_modrm(p, reg, reg); + emit_modrm_noreg(p, 2, reg); } #endif @@ -1192,3 +1193,9 @@ void x86sse_dummy( void ) } #endif + +#else /* USE_X86_ASM */ + +int x86sse_c_dummy_var; /* silence warning */ + +#endif /* USE_X86_ASM */ |