Merge remote branch 'origin/master' into lp-binning
authorJosé Fonseca <jfonseca@vmware.com>
Fri, 8 Jan 2010 15:42:57 +0000 (15:42 +0000)
committerJosé Fonseca <jfonseca@vmware.com>
Fri, 8 Jan 2010 15:42:57 +0000 (15:42 +0000)
Conflicts:
src/gallium/auxiliary/util/u_surface.c
src/gallium/drivers/llvmpipe/Makefile
src/gallium/drivers/llvmpipe/SConscript
src/gallium/drivers/llvmpipe/lp_bld_arit.c
src/gallium/drivers/llvmpipe/lp_bld_flow.c
src/gallium/drivers/llvmpipe/lp_bld_interp.c
src/gallium/drivers/llvmpipe/lp_clear.c
src/gallium/drivers/llvmpipe/lp_context.c
src/gallium/drivers/llvmpipe/lp_context.h
src/gallium/drivers/llvmpipe/lp_draw_arrays.c
src/gallium/drivers/llvmpipe/lp_jit.c
src/gallium/drivers/llvmpipe/lp_jit.h
src/gallium/drivers/llvmpipe/lp_prim_vbuf.c
src/gallium/drivers/llvmpipe/lp_setup.c
src/gallium/drivers/llvmpipe/lp_setup_point.c
src/gallium/drivers/llvmpipe/lp_state.h
src/gallium/drivers/llvmpipe/lp_state_blend.c
src/gallium/drivers/llvmpipe/lp_state_derived.c
src/gallium/drivers/llvmpipe/lp_state_fs.c
src/gallium/drivers/llvmpipe/lp_state_sampler.c
src/gallium/drivers/llvmpipe/lp_state_surface.c
src/gallium/drivers/llvmpipe/lp_tex_cache.c
src/gallium/drivers/llvmpipe/lp_tex_cache.h
src/gallium/drivers/llvmpipe/lp_tex_sample.h
src/gallium/drivers/llvmpipe/lp_tile_cache.c

67 files changed:
Makefile
configs/linux-llvm
configs/linux-llvm-debug [new file with mode: 0644]
progs/demos/gloss.c
progs/trivial/Makefile
progs/trivial/SConscript
progs/trivial/sub-tex.c [new file with mode: 0644]
progs/trivial/tex-quads.c [new file with mode: 0644]
progs/trivial/tri-z-eq.c
src/gallium/auxiliary/util/u_surface.c
src/gallium/auxiliary/util/u_surface.h
src/gallium/drivers/llvmpipe/Makefile
src/gallium/drivers/llvmpipe/SConscript
src/gallium/drivers/llvmpipe/lp_bld_arit.c
src/gallium/drivers/llvmpipe/lp_bld_conv.c
src/gallium/drivers/llvmpipe/lp_bld_flow.c
src/gallium/drivers/llvmpipe/lp_bld_flow.h
src/gallium/drivers/llvmpipe/lp_bld_interp.c
src/gallium/drivers/llvmpipe/lp_bld_interp.h
src/gallium/drivers/llvmpipe/lp_bld_logic.c
src/gallium/drivers/llvmpipe/lp_bld_logic.h
src/gallium/drivers/llvmpipe/lp_bld_type.c
src/gallium/drivers/llvmpipe/lp_bld_type.h
src/gallium/drivers/llvmpipe/lp_buffer.c
src/gallium/drivers/llvmpipe/lp_clear.c
src/gallium/drivers/llvmpipe/lp_context.c
src/gallium/drivers/llvmpipe/lp_context.h
src/gallium/drivers/llvmpipe/lp_draw_arrays.c
src/gallium/drivers/llvmpipe/lp_fence.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_fence.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_flush.c
src/gallium/drivers/llvmpipe/lp_jit.h
src/gallium/drivers/llvmpipe/lp_prim_vbuf.c [deleted file]
src/gallium/drivers/llvmpipe/lp_prim_vbuf.h [deleted file]
src/gallium/drivers/llvmpipe/lp_quad.h [deleted file]
src/gallium/drivers/llvmpipe/lp_rast.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_rast.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_rast_priv.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_rast_tri.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_scene.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_scene.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_scene_queue.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_scene_queue.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_screen.c
src/gallium/drivers/llvmpipe/lp_setup.c
src/gallium/drivers/llvmpipe/lp_setup.h
src/gallium/drivers/llvmpipe/lp_setup_context.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_setup_line.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_setup_point.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_setup_tri.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_setup_vbuf.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_state.h
src/gallium/drivers/llvmpipe/lp_state_blend.c
src/gallium/drivers/llvmpipe/lp_state_derived.c
src/gallium/drivers/llvmpipe/lp_state_fs.c
src/gallium/drivers/llvmpipe/lp_state_rasterizer.c
src/gallium/drivers/llvmpipe/lp_state_sampler.c
src/gallium/drivers/llvmpipe/lp_state_surface.c
src/gallium/drivers/llvmpipe/lp_tex_cache.c [deleted file]
src/gallium/drivers/llvmpipe/lp_tex_cache.h [deleted file]
src/gallium/drivers/llvmpipe/lp_tex_sample_llvm.c
src/gallium/drivers/llvmpipe/lp_texture.c
src/gallium/drivers/llvmpipe/lp_tile_cache.c [deleted file]
src/gallium/drivers/llvmpipe/lp_tile_cache.h [deleted file]
src/gallium/drivers/llvmpipe/lp_tile_soa.h
src/gallium/drivers/llvmpipe/lp_tile_soa.py
src/gallium/include/pipe/p_thread.h

index 1b46a9193ef0dbf6c2705aa68cbf5cb7ea9fcb18..340747d5609c75f7e8df82873124448e451af67d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -127,6 +127,7 @@ linux-ia64-icc-static \
 linux-icc \
 linux-icc-static \
 linux-llvm \
+linux-llvm-debug \
 linux-osmesa \
 linux-osmesa-static \
 linux-osmesa16 \
index dbf7e3ed7a9e85291d424633deed173ac463eacd..988b7057d4efcbf9d48a1e68e35bd38c81ee9d19 100644 (file)
@@ -1,5 +1,5 @@
 # -*-makefile-*-
-# Configuration for Linux and LLVM with debugging info
+# Configuration for Linux and LLVM with optimizations
 # Builds the llvmpipe gallium driver
 
 include $(TOP)/configs/linux
@@ -9,8 +9,10 @@ CONFIG_NAME = linux-llvm
 # Add llvmpipe driver
 GALLIUM_DRIVERS_DIRS += llvmpipe
 
-OPT_FLAGS = -g -ansi -pedantic
-DEFINES += -DDEBUG -DDEBUG_MATH -DGALLIUM_LLVMPIPE -DHAVE_UDIS86
+OPT_FLAGS = -O3 -ansi -pedantic
+ARCH_FLAGS = -m32 -mmmx -msse -msse2 -mstackrealign
+
+DEFINES += -DNDEBUG -DGALLIUM_LLVMPIPE -DHAVE_UDIS86
 
 # override -std=c99
 CFLAGS += -std=gnu99
diff --git a/configs/linux-llvm-debug b/configs/linux-llvm-debug
new file mode 100644 (file)
index 0000000..28bcfdb
--- /dev/null
@@ -0,0 +1,12 @@
+# -*-makefile-*-
+# Configuration for Linux and LLVM with debugging info
+# Builds the llvmpipe gallium driver
+
+include $(TOP)/configs/linux-llvm
+
+CONFIG_NAME = linux-llvm-debug
+
+OPT_FLAGS = -g -ansi -pedantic
+
+DEFINES += -DDEBUG -UNDEBUG
+
index 578736b4e27c0e654ea8f1f13cbd17a8366c3f29..450861e57781934cdcebb9788c4cf391a6d3e249 100644 (file)
@@ -41,6 +41,7 @@
 /* for convolution */
 #define FILTER_SIZE 7
 
+static GLint Win;
 static GLint WinWidth = 500, WinHeight = 500;
 static GLuint CylinderObj = 0;
 static GLuint TeapotObj = 0;
@@ -214,7 +215,11 @@ static void Key( unsigned char key, int x, int y )
       case ' ':
          ToggleAnimate();
          break;
+      case 'n':
+         Idle();
+         break;
       case 27:
+         glutDestroyWindow(Win);
          exit(0);
          break;
    }
@@ -439,7 +444,7 @@ int main( int argc, char *argv[] )
    glutInitWindowSize(WinWidth, WinHeight);
    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
-   glutCreateWindow(argv[0] );
+   Win = glutCreateWindow(argv[0] );
    glewInit();
    glutReshapeFunc( Reshape );
    glutKeyboardFunc( Key );
index e15ec33ab5922ef8bda76994f4dce7f99031fdc5..784715db1620b1c2a783dad13699e3a2fb53c962 100644 (file)
@@ -90,6 +90,8 @@ SOURCES = \
        quadstrip-flat.c \
        quadstrip.c \
        readpixels.c \
+       sub-tex.c \
+       tex-quads.c \
        tri-alpha.c \
        tri-alpha-tex.c \
        tri-array-interleaved.c \
index 613383c77b1a374e887a6386e99b9065b7fadc6d..29062564adc6eed3c9585a88070ac557dc0bd73e 100644 (file)
@@ -70,6 +70,8 @@ progs = [
        'quadstrip-cont',
        'quadstrip-flat',
        'quadstrip',
+       'sub-tex',
+       'tex-quads',
        'tri-alpha',
        'tri-blend-color',
        'tri-blend-max',
diff --git a/progs/trivial/sub-tex.c b/progs/trivial/sub-tex.c
new file mode 100644 (file)
index 0000000..0b8bb28
--- /dev/null
@@ -0,0 +1,137 @@
+/**
+ * Draw a series of textured quads after each quad, use glTexSubImage()
+ * to change one row of the texture image.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <GL/glew.h>
+#include <GL/glut.h>
+
+
+static GLint Win = 0;
+static GLuint Tex = 0;
+
+
+static void Init(void)
+{
+   fprintf(stderr, "GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
+   fflush(stderr);
+
+   glGenTextures(1, &Tex);
+   glBindTexture(GL_TEXTURE_2D, Tex);
+
+   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+}
+
+
+static void Reshape(int width, int height)
+{
+   float ar = (float) width / height;
+   glViewport(0, 0, width, height);
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glOrtho(-ar, ar, -1.0, 1.0, -1.0, 1.0);
+   glMatrixMode(GL_MODELVIEW);
+}
+
+
+static void Key(unsigned char key, int x, int y)
+{
+   if (key == 27) {
+      glDeleteTextures(1, &Tex);
+      glutDestroyWindow(Win);
+      exit(1);
+   }
+   glutPostRedisplay();
+}
+
+
+static void Draw(void)
+{
+   GLubyte tex[16][16][4];
+   GLubyte row[16][4];
+   int i, j;
+
+   for (i = 0; i < 16; i++) {
+      for (j = 0; j < 16; j++) {
+         if ((i + j) & 1) {
+            tex[i][j][0] = 128;
+            tex[i][j][1] = 128;
+            tex[i][j][2] = 128;
+            tex[i][j][3] = 255;
+         }
+         else {
+            tex[i][j][0] = 255;
+            tex[i][j][1] = 255;
+            tex[i][j][2] = 255;
+            tex[i][j][3] = 255;
+         }
+      }
+   }
+
+   for (i = 0; i < 16; i++) {
+      row[i][0] = 255;
+      row[i][1] = 0;
+      row[i][2] = 0;
+      row[i][3] = 255;
+   }
+
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, tex);
+   glEnable(GL_TEXTURE_2D);
+
+   glClear(GL_COLOR_BUFFER_BIT);
+
+   for (i = 0; i < 9; i++) {
+
+      glPushMatrix();
+      glTranslatef(-4.0 + i, 0, 0);
+      glScalef(0.5, 0.5, 1.0);
+
+      glBegin(GL_QUADS);
+      glTexCoord2f(1,0);
+      glVertex3f( 0.9, -0.9, 0.0);
+      glTexCoord2f(1,1);
+      glVertex3f( 0.9,  0.9, 0.0);
+      glTexCoord2f(0,1);
+      glVertex3f(-0.9,  0.9, 0.0);
+      glTexCoord2f(0,0);
+      glVertex3f(-0.9,  -0.9, 0.0);
+      glEnd();
+
+      glPopMatrix();
+
+      /* replace a row of the texture image with red texels */
+      if (i * 2 < 16)
+         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i*2, 16, 1,
+                         GL_RGBA, GL_UNSIGNED_BYTE, row);
+   }
+
+
+   glutSwapBuffers();
+}
+
+
+int main(int argc, char **argv)
+{
+   glutInit(&argc, argv);
+   glutInitWindowSize(900, 200);
+   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
+   Win = glutCreateWindow(*argv);
+   if (!Win) {
+      exit(1);
+   }
+   glewInit();
+   Init();
+   glutReshapeFunc(Reshape);
+   glutKeyboardFunc(Key);
+   glutDisplayFunc(Draw);
+   glutMainLoop();
+   return 0;
+}
diff --git a/progs/trivial/tex-quads.c b/progs/trivial/tex-quads.c
new file mode 100644 (file)
index 0000000..626e178
--- /dev/null
@@ -0,0 +1,143 @@
+/**
+ * Draw a series of quads, each with a different texture.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <GL/glew.h>
+#include <GL/glut.h>
+
+#define NUM_TEX 10
+
+static GLint Win = 0;
+static GLuint Tex[NUM_TEX];
+
+
+static void Init(void)
+{
+   int i;
+
+   fprintf(stderr, "GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
+   fflush(stderr);
+
+   glGenTextures(NUM_TEX, Tex);
+
+   for (i = 0; i < NUM_TEX; i++) {
+      glBindTexture(GL_TEXTURE_2D, Tex[i]);
+
+      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+   }
+}
+
+
+static void Reshape(int width, int height)
+{
+   float ar = (float) width / height;
+   glViewport(0, 0, width, height);
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glOrtho(-ar, ar, -1.0, 1.0, -1.0, 1.0);
+   glMatrixMode(GL_MODELVIEW);
+}
+
+
+static void Key(unsigned char key, int x, int y)
+{
+   if (key == 27) {
+      glDeleteTextures(NUM_TEX, Tex);
+      glutDestroyWindow(Win);
+      exit(1);
+   }
+   glutPostRedisplay();
+}
+
+
+static void Draw(void)
+{
+   GLubyte tex[16][16][4];
+   int t, i, j;
+
+   for (t = 0; t < NUM_TEX; t++) {
+
+      for (i = 0; i < 16; i++) {
+         for (j = 0; j < 16; j++) {
+            if (i < t) {
+               /* red row */
+               tex[i][j][0] = 255;
+               tex[i][j][1] = 0;
+               tex[i][j][2] = 0;
+               tex[i][j][3] = 255;
+            }
+            else if ((i + j) & 1) {
+               tex[i][j][0] = 128;
+               tex[i][j][1] = 128;
+               tex[i][j][2] = 128;
+               tex[i][j][3] = 255;
+            }
+            else {
+               tex[i][j][0] = 255;
+               tex[i][j][1] = 255;
+               tex[i][j][2] = 255;
+               tex[i][j][3] = 255;
+            }
+         }
+      }
+
+      glBindTexture(GL_TEXTURE_2D, Tex[t]);
+      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0,
+                   GL_RGBA, GL_UNSIGNED_BYTE, tex);
+   }
+
+   glEnable(GL_TEXTURE_2D);
+
+   glClear(GL_COLOR_BUFFER_BIT);
+
+   for (i = 0; i < NUM_TEX; i++) {
+
+      glBindTexture(GL_TEXTURE_2D, Tex[i]);
+
+      glPushMatrix();
+      glTranslatef(-4.0 + i, 0, 0);
+      glScalef(0.5, 0.5, 1.0);
+
+      glBegin(GL_QUADS);
+      glTexCoord2f(1,0);
+      glVertex3f( 0.9, -0.9, 0.0);
+      glTexCoord2f(1,1);
+      glVertex3f( 0.9,  0.9, 0.0);
+      glTexCoord2f(0,1);
+      glVertex3f(-0.9,  0.9, 0.0);
+      glTexCoord2f(0,0);
+      glVertex3f(-0.9,  -0.9, 0.0);
+      glEnd();
+
+      glPopMatrix();
+   }
+
+
+   glutSwapBuffers();
+}
+
+
+int main(int argc, char **argv)
+{
+   glutInit(&argc, argv);
+   glutInitWindowSize(900, 200);
+   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
+   Win = glutCreateWindow(*argv);
+   if (!Win) {
+      exit(1);
+   }
+   glewInit();
+   Init();
+   glutReshapeFunc(Reshape);
+   glutKeyboardFunc(Key);
+   glutDisplayFunc(Draw);
+   glutMainLoop();
+   return 0;
+}
index 6bdac4741961ab31ef0c6232208163e64cbd6c7b..c04ffae7f1a34b69f1ef251c2bf89ae27908510b 100644 (file)
@@ -69,6 +69,8 @@ static void Key(unsigned char key, int x, int y)
 
 static void Draw(void)
 {
+   float z = 1.0;
+
    glClearColor(0.0, 0.0, 1.0, 0.0);
    glClearDepth(1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
@@ -77,15 +79,21 @@ static void Draw(void)
 
    glBegin(GL_TRIANGLES);
    glColor3f(0,0,.7); 
-   glVertex3f( 0.9, -0.9, 1.0);
+   glVertex3f( 0.9, -0.9, z);
    glColor3f(.8,0,0); 
-   glVertex3f( 0.9,  0.9, 1.0);
+   glVertex3f( 0.9,  0.9, z);
    glColor3f(0,.9,0); 
-   glVertex3f(-0.9,  0.0, 1.0);
+   glVertex3f(-0.9,  0.0, z);
    glEnd();
 
    glFlush();
 
+   {
+      GLfloat z;
+      glReadPixels(125, 125, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);
+      printf("Z at (125, 125) = %f\n", z);
+   }
+
    if (doubleBuffer) {
       glutSwapBuffers();
    }
index 35c497820434e5bbb506853101e844c341c8502a..f66376ad7509ff04eda038d0db9e865a0feea22b 100644 (file)
@@ -36,6 +36,7 @@
 #include "pipe/p_state.h"
 #include "pipe/p_defines.h"
 
+#include "util/u_memory.h"
 #include "util/u_format.h"
 #include "util/u_surface.h"
 
@@ -111,3 +112,73 @@ util_destroy_rgba_surface(struct pipe_texture *texture,
    pipe_texture_reference(&texture, NULL);
 }
 
+
+
+/**
+ * Compare pipe_framebuffer_state objects.
+ * \return TRUE if same, FALSE if different
+ */
+boolean
+util_framebuffer_state_equal(const struct pipe_framebuffer_state *dst,
+                             const struct pipe_framebuffer_state *src)
+{
+   unsigned i;
+
+   if (dst->width != src->width ||
+       dst->height != src->height)
+      return FALSE;
+
+   for (i = 0; i < Elements(src->cbufs); i++) {
+      if (dst->cbufs[i] != src->cbufs[i]) {
+         return FALSE;
+      }
+   }
+
+   if (dst->nr_cbufs != src->nr_cbufs) {
+      return FALSE;
+   }
+
+   if (dst->zsbuf != src->zsbuf) {
+      return FALSE;
+   }
+
+   return TRUE;
+}
+
+
+/**
+ * Copy framebuffer state from src to dst, updating refcounts.
+ */
+void
+util_copy_framebuffer_state(struct pipe_framebuffer_state *dst,
+                            const struct pipe_framebuffer_state *src)
+{
+   unsigned i;
+
+   dst->width = src->width;
+   dst->height = src->height;
+
+   for (i = 0; i < Elements(src->cbufs); i++) {
+      pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]);
+   }
+
+   dst->nr_cbufs = src->nr_cbufs;
+
+   pipe_surface_reference(&dst->zsbuf, src->zsbuf);
+}
+
+
+void
+util_unreference_framebuffer_state(struct pipe_framebuffer_state *fb)
+{
+   unsigned i;
+
+   for (i = 0; i < fb->nr_cbufs; i++) {
+      pipe_surface_reference(&fb->cbufs[i], NULL);
+   }
+
+   pipe_surface_reference(&fb->zsbuf, NULL);
+
+   fb->width = fb->height = 0;
+   fb->nr_cbufs = 0;
+}
index ce84ed7ad06a3b788dc36b7fa58f8bf7c82b1147..3c60df2c3e52249991ca3c92b5a3ebcd94c8afcf 100644 (file)
 
 
 #include "pipe/p_compiler.h"
-
-
-struct pipe_screen;
-struct pipe_texture;
-struct pipe_surface;
+#include "pipe/p_state.h"
 
 
 /**
@@ -66,4 +62,17 @@ util_destroy_rgba_surface(struct pipe_texture *texture,
                           struct pipe_surface *surface);
 
 
+extern boolean
+util_framebuffer_state_equal(const struct pipe_framebuffer_state *dst,
+                             const struct pipe_framebuffer_state *src);
+
+extern void
+util_copy_framebuffer_state(struct pipe_framebuffer_state *dst,
+                            const struct pipe_framebuffer_state *src);
+
+
+extern void
+util_unreference_framebuffer_state(struct pipe_framebuffer_state *fb);
+
+
 #endif /* U_SURFACE_H */
index 7c6e46006b9569736fc31873684cf179aef481ec..264999a7ceaa301ba335f713864d2da1cfd1670f 100644 (file)
@@ -6,6 +6,8 @@ LIBNAME = llvmpipe
 CFLAGS += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
 
 C_SOURCES = \
+       lp_scene.c \
+       lp_scene_queue.c \
        lp_bld_alpha.c \
        lp_bld_arit.c \
        lp_bld_blend_aos.c \
@@ -33,10 +35,16 @@ C_SOURCES = \
        lp_clear.c \
        lp_context.c \
        lp_draw_arrays.c \
+       lp_fence.c \
        lp_flush.c \
        lp_jit.c \
-       lp_prim_vbuf.c \
+       lp_rast.c \
+       lp_rast_tri.c \
        lp_setup.c \
+       lp_setup_line.c \
+       lp_setup_point.c \
+       lp_setup_tri.c \
+       lp_setup_vbuf.c \
        lp_query.c \
        lp_screen.c \
        lp_state_blend.c \
@@ -49,10 +57,8 @@ C_SOURCES = \
        lp_state_vertex.c \
        lp_state_vs.c \
        lp_surface.c \
-       lp_tex_cache.c \
        lp_tex_sample_llvm.c \
        lp_texture.c \
-       lp_tile_cache.c \
        lp_tile_soa.c
 
 CPP_SOURCES = \
index 6bb545a501f8f1c11c41ad057e854469f8cb3691..5af77c4a12d68c5eaaef4e8085f18bae238fad01 100644 (file)
@@ -36,12 +36,12 @@ llvmpipe = env.ConvenienceLibrary(
                'lp_bld_format_soa.c',
                'lp_bld_interp.c',
                'lp_bld_intr.c',
+               'lp_bld_logic.c',
                'lp_bld_misc.cpp',
         'lp_bld_pack.c',
         'lp_bld_sample.c',
                'lp_bld_sample_soa.c',
                'lp_bld_struct.c',
-               'lp_bld_logic.c',
                'lp_bld_swizzle.c',
                'lp_bld_tgsi_soa.c',            
                'lp_bld_type.c',
@@ -49,12 +49,18 @@ llvmpipe = env.ConvenienceLibrary(
                'lp_clear.c',
                'lp_context.c',
                'lp_draw_arrays.c',
+               'lp_fence.c',
                'lp_flush.c',
                'lp_jit.c',
-               'lp_prim_vbuf.c',
-               'lp_setup.c',
                'lp_query.c',
+               'lp_scene.c',
+               'lp_scene_queue.c',
                'lp_screen.c',
+               'lp_setup.c',
+               'lp_setup_line.c',
+               'lp_setup_point.c',
+               'lp_setup_tri.c',
+               'lp_setup_vbuf.c',
                'lp_state_blend.c',
                'lp_state_clip.c',
                'lp_state_derived.c',
@@ -65,10 +71,10 @@ llvmpipe = env.ConvenienceLibrary(
                'lp_state_vertex.c',
                'lp_state_vs.c',
                'lp_surface.c',
-               'lp_tex_cache.c',
+               'lp_rast.c',
+               'lp_rast_tri.c',
                'lp_tex_sample_llvm.c',
                'lp_texture.c',
-               'lp_tile_cache.c',
                'lp_tile_soa.c',
        ])
 
index eea6b5d6a5c9d2d1002fa9ff5b6edac8dba0c07c..2df86dd32e50e63476af819728907994ea7988a9 100644 (file)
@@ -629,7 +629,7 @@ lp_build_abs(struct lp_build_context *bld,
    if(type.floating) {
       /* Mask out the sign bit */
       LLVMTypeRef int_vec_type = lp_build_int_vec_type(type);
-      unsigned long absMask = ~(1 << (type.width - 1));
+      unsigned long long absMask = ~(1ULL << (type.width - 1));
       LLVMValueRef mask = lp_build_int_const_scalar(type, ((unsigned long long) absMask));
       a = LLVMBuildBitCast(bld->builder, a, int_vec_type, "");
       a = LLVMBuildAnd(bld->builder, a, mask, "");
index 99352094379f81e0aca4ab03555082803264907f..9fa8837202207cfd46828d4a5931e5db48c167c2 100644 (file)
@@ -125,6 +125,10 @@ lp_build_clamped_float_to_unsigned_norm(LLVMBuilderRef builder,
       res = LLVMBuildShl(builder, res, lp_build_int_const_scalar(src_type, shift), "");
 
       /* TODO: Fill in the empty lower bits for additional precision? */
+      /* YES: this fixes progs/trivial/tri-z-eq.c.
+       * Otherwise vertex Z=1.0 values get converted to something like
+       * 0xfffffb00 and the test for equality with 0xffffffff fails.
+       */
 #if 0
       {
          LLVMValueRef msb;
index 25c10af29f0fe7bcfe1b16309dbca9aea1a40685..230edc6a5cfd27c67bb1abafd6b408347fc0f211 100644 (file)
 #define LP_BUILD_FLOW_MAX_VARIABLES 32
 #define LP_BUILD_FLOW_MAX_DEPTH 32
 
+#define LP_BUILD_IF_MAX_VARIABLES 8
+
 
 /**
  * Enumeration of all possible flow constructs.
  */
 enum lp_build_flow_construct_kind {
-   lP_BUILD_FLOW_SCOPE,
-   LP_BUILD_FLOW_SKIP
+   LP_BUILD_FLOW_SCOPE,
+   LP_BUILD_FLOW_SKIP,
+   LP_BUILD_FLOW_IF
 };
 
 
@@ -73,7 +76,24 @@ struct lp_build_flow_skip
    /** Number of variables declared at the beginning */
    unsigned num_variables;
 
-   LLVMValueRef *phi;
+   LLVMValueRef *phi;  /**< array [num_variables] */
+};
+
+
+/**
+ * if/else/endif.
+ */
+struct lp_build_flow_if
+{
+   unsigned num_variables;
+
+   /** phi variables in the true clause */
+   LLVMValueRef true_variables[LP_BUILD_IF_MAX_VARIABLES];
+   unsigned num_true_variables;
+
+   /** phi variables in the false clause */
+   LLVMValueRef false_variables[LP_BUILD_IF_MAX_VARIABLES];
+   unsigned num_false_variables;
 };
 
 
@@ -84,6 +104,7 @@ union lp_build_flow_construct_data
 {
    struct lp_build_flow_scope scope;
    struct lp_build_flow_skip skip;
+   struct lp_build_flow_if ifthen;
 };
 
 
@@ -145,6 +166,10 @@ lp_build_flow_destroy(struct lp_build_flow_context *flow)
 }
 
 
+/**
+ * Begin/push a new flow control construct, such as a loop, skip block
+ * or variable scope.
+ */
 static union lp_build_flow_construct_data *
 lp_build_flow_push(struct lp_build_flow_context *flow,
                    enum lp_build_flow_construct_kind kind)
@@ -158,6 +183,10 @@ lp_build_flow_push(struct lp_build_flow_context *flow,
 }
 
 
+/**
+ * Return the current/top flow control construct on the stack.
+ * \param kind  the expected type of the top-most construct
+ */
 static union lp_build_flow_construct_data *
 lp_build_flow_peek(struct lp_build_flow_context *flow,
                    enum lp_build_flow_construct_kind kind)
@@ -174,6 +203,10 @@ lp_build_flow_peek(struct lp_build_flow_context *flow,
 }
 
 
+/**
+ * End/pop the current/top flow control construct on the stack.
+ * \param kind  the expected type of the top-most construct
+ */
 static union lp_build_flow_construct_data *
 lp_build_flow_pop(struct lp_build_flow_context *flow,
                   enum lp_build_flow_construct_kind kind)
@@ -200,7 +233,7 @@ lp_build_flow_scope_begin(struct lp_build_flow_context *flow)
 {
    struct lp_build_flow_scope *scope;
 
-   scope = &lp_build_flow_push(flow, lP_BUILD_FLOW_SCOPE)->scope;
+   scope = &lp_build_flow_push(flow, LP_BUILD_FLOW_SCOPE)->scope;
    if(!scope)
       return;
 
@@ -213,11 +246,11 @@ lp_build_flow_scope_begin(struct lp_build_flow_context *flow)
  *
  * A variable is a named entity which can have different LLVMValueRef's at
  * different points of the program. This is relevant for control flow because
- * when there are mutiple branches to a same location we need to replace
+ * when there are multiple branches to a same location we need to replace
  * the variable's value with a Phi function as explained in
  * http://en.wikipedia.org/wiki/Static_single_assignment_form .
  *
- * We keep track of variables by keeping around a pointer to where their
+ * We keep track of variables by keeping around a pointer to where they're
  * current.
  *
  * There are a few cautions to observe:
@@ -241,7 +274,7 @@ lp_build_flow_scope_declare(struct lp_build_flow_context *flow,
 {
    struct lp_build_flow_scope *scope;
 
-   scope = &lp_build_flow_peek(flow, lP_BUILD_FLOW_SCOPE)->scope;
+   scope = &lp_build_flow_peek(flow, LP_BUILD_FLOW_SCOPE)->scope;
    if(!scope)
       return;
 
@@ -263,7 +296,7 @@ lp_build_flow_scope_end(struct lp_build_flow_context *flow)
 {
    struct lp_build_flow_scope *scope;
 
-   scope = &lp_build_flow_pop(flow, lP_BUILD_FLOW_SCOPE)->scope;
+   scope = &lp_build_flow_pop(flow, LP_BUILD_FLOW_SCOPE)->scope;
    if(!scope)
       return;
 
@@ -298,6 +331,11 @@ lp_build_flow_insert_block(struct lp_build_flow_context *flow)
    return new_block;
 }
 
+
+/**
+ * Begin a "skip" block.  Inside this block we can test a condition and
+ * skip to the end of the block if the condition is false.
+ */
 void
 lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
 {
@@ -309,13 +347,16 @@ lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
    if(!skip)
       return;
 
+   /* create new basic block */
    skip->block = lp_build_flow_insert_block(flow);
+
    skip->num_variables = flow->num_variables;
    if(!skip->num_variables) {
       skip->phi = NULL;
       return;
    }
 
+   /* Allocate a Phi node for each variable in this skip scope */
    skip->phi = MALLOC(skip->num_variables * sizeof *skip->phi);
    if(!skip->phi) {
       skip->num_variables = 0;
@@ -325,6 +366,7 @@ lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
    builder = LLVMCreateBuilder();
    LLVMPositionBuilderAtEnd(builder, skip->block);
 
+   /* create a Phi node for each variable */
    for(i = 0; i < skip->num_variables; ++i)
       skip->phi[i] = LLVMBuildPhi(builder, LLVMTypeOf(*flow->variables[i]), "");
 
@@ -332,6 +374,10 @@ lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
 }
 
 
+/**
+ * Insert code to test a condition and branch to the end of the current
+ * skip block if the condition is true.
+ */
 void
 lp_build_flow_skip_cond_break(struct lp_build_flow_context *flow,
                               LLVMValueRef cond)
@@ -349,15 +395,17 @@ lp_build_flow_skip_cond_break(struct lp_build_flow_context *flow,
 
    new_block = lp_build_flow_insert_block(flow);
 
+   /* for each variable, update the Phi node with a (variable, block) pair */
    for(i = 0; i < skip->num_variables; ++i) {
       assert(*flow->variables[i]);
       LLVMAddIncoming(skip->phi[i], flow->variables[i], &current_block, 1);
    }
 
+   /* if cond is true, goto skip->block, else goto new_block */
    LLVMBuildCondBr(flow->builder, cond, skip->block, new_block);
 
    LLVMPositionBuilderAtEnd(flow->builder, new_block);
- }
+}
 
 
 void
@@ -373,12 +421,14 @@ lp_build_flow_skip_end(struct lp_build_flow_context *flow)
 
    current_block = LLVMGetInsertBlock(flow->builder);
 
+   /* add (variable, block) tuples to the phi nodes */
    for(i = 0; i < skip->num_variables; ++i) {
       assert(*flow->variables[i]);
       LLVMAddIncoming(skip->phi[i], flow->variables[i], &current_block, 1);
       *flow->variables[i] = skip->phi[i];
    }
 
+   /* goto block */
    LLVMBuildBr(flow->builder, skip->block);
    LLVMPositionBuilderAtEnd(flow->builder, skip->block);
 
@@ -386,22 +436,34 @@ lp_build_flow_skip_end(struct lp_build_flow_context *flow)
 }
 
 
+/**
+ * Check if the mask predicate is zero.  If so, jump to the end of the block.
+ */
 static void
 lp_build_mask_check(struct lp_build_mask_context *mask)
 {
    LLVMBuilderRef builder = mask->flow->builder;
    LLVMValueRef cond;
 
+   /* cond = (mask == 0) */
    cond = LLVMBuildICmp(builder,
                         LLVMIntEQ,
                         LLVMBuildBitCast(builder, mask->value, mask->reg_type, ""),
                         LLVMConstNull(mask->reg_type),
                         "");
 
+   /* if cond, goto end of block */
    lp_build_flow_skip_cond_break(mask->flow, cond);
 }
 
 
+/**
+ * Begin a section of code which is predicated on a mask.
+ * \param mask  the mask context, initialized here
+ * \param flow  the flow context
+ * \param type  the type of the mask
+ * \param value  storage for the mask
+ */
 void
 lp_build_mask_begin(struct lp_build_mask_context *mask,
                     struct lp_build_flow_context *flow,
@@ -422,6 +484,11 @@ lp_build_mask_begin(struct lp_build_mask_context *mask,
 }
 
 
+/**
+ * Update boolean mask with given value (bitwise AND).
+ * Typically used to update the quad's pixel alive/killed mask
+ * after depth testing, alpha testing, TGSI_OPCODE_KIL, etc.
+ */
 void
 lp_build_mask_update(struct lp_build_mask_context *mask,
                      LLVMValueRef value)
@@ -432,6 +499,9 @@ lp_build_mask_update(struct lp_build_mask_context *mask,
 }
 
 
+/**
+ * End section of code which is predicated on a mask.
+ */
 LLVMValueRef
 lp_build_mask_end(struct lp_build_mask_context *mask)
 {
@@ -491,3 +561,223 @@ lp_build_loop_end(LLVMBuilderRef builder,
    LLVMPositionBuilderAtEnd(builder, after_block);
 }
 
+
+
+/*
+  Example of if/then/else building:
+
+     int x;
+     if (cond) {
+        x = 1 + 2;
+     }
+     else {
+        x = 2 + 3;
+     }
+
+  Is built with:
+
+     flow = lp_build_flow_create(builder);
+     ...
+
+     lp_build_flow_scope_declare(flow, "x");
+
+     lp_build_if(ctx, flow, builder, cond);
+        x = LLVMAdd(1, 2);
+        lp_build_if_phi_var(ctx, "x");
+     lp_build_else(ctx);
+        x = LLVMAdd(2, 3);
+        lp_build_if_phi_var(ctx, "x");
+     lp_build_endif(ctx);
+
+     ...
+
+     flow = lp_build_flow_end(flow);
+ */
+
+
+
+/**
+ * Begin an if/else/endif construct.
+ */
+void
+lp_build_if(struct lp_build_if_state *ctx,
+            struct lp_build_flow_context *flow,
+            LLVMBuilderRef builder,
+            LLVMValueRef condition)
+{
+   LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
+   LLVMValueRef function = LLVMGetBasicBlockParent(block);
+   struct lp_build_flow_if *ifthen;
+
+   memset(ctx, 0, sizeof(*ctx));
+   ctx->builder = builder;
+   ctx->flow = flow;
+   ctx->condition = condition;
+   ctx->entry_block = block;
+
+   /* push/create new scope */
+   ifthen = &lp_build_flow_push(flow, LP_BUILD_FLOW_IF)->ifthen;
+   assert(ifthen);
+
+   ifthen->num_variables = flow->num_variables;
+   ifthen->num_true_variables = 0;
+   ifthen->num_false_variables = 0;
+
+   /* allocate the block for the if/true clause */
+   ctx->true_block = LLVMAppendBasicBlock(function, "true block");
+   /* XXX is this correct ??? */
+   LLVMPositionBuilderAtEnd(builder, ctx->true_block);
+}
+
+
+/**
+ * Begin else-part of a conditional
+ */
+void
+lp_build_else(struct lp_build_if_state *ctx)
+{
+   LLVMBasicBlockRef block = LLVMGetInsertBlock(ctx->builder);
+   LLVMValueRef function = LLVMGetBasicBlockParent(block);
+   struct lp_build_flow_if *ifthen;
+
+   ifthen = &lp_build_flow_peek(ctx->flow, LP_BUILD_FLOW_IF)->ifthen;
+   assert(ifthen);
+
+   /* allocate the block for the else/false clause */
+   ctx->false_block = LLVMAppendBasicBlock(function, "false block");
+   /* XXX is this correct ??? */
+   LLVMPositionBuilderAtEnd(ctx->builder, ctx->false_block);
+}
+
+
+/**
+ * End a conditional.
+ * This involves building a "merge" block at the endif which
+ * contains the phi instructions.
+ */
+void
+lp_build_endif(struct lp_build_if_state *ctx)
+{
+   LLVMBasicBlockRef block = LLVMGetInsertBlock(ctx->builder);
+   LLVMValueRef function = LLVMGetBasicBlockParent(block);
+   LLVMBasicBlockRef merge_block = LLVMAppendBasicBlock(function, "endif block");
+   LLVMValueRef phi[LP_BUILD_FLOW_MAX_VARIABLES];
+   struct lp_build_flow_if *ifthen;
+   unsigned i;
+
+   /* build the endif/merge block now */
+   /* XXX this is probably wrong */
+   LLVMPositionBuilderAtEnd(ctx->builder, merge_block);
+
+   ifthen = &lp_build_flow_pop(ctx->flow, LP_BUILD_FLOW_IF)->ifthen;
+   assert(ifthen);
+
+   memset(phi, 0, sizeof(phi));
+
+   /* build phi nodes for any variables which were declared inside if part */
+
+   for (i = 0; i < ifthen->num_variables; i++) {
+      LLVMValueRef *var = ctx->flow->variables[i];
+      const char *name = LLVMGetValueName(*var);
+      unsigned j;
+
+      /* search true-clause variables list for 'name' */
+      for (j = 0; j < ifthen->num_true_variables; j++) {
+         LLVMValueRef v = ifthen->true_variables[j];
+         if (strcmp(LLVMGetValueName(v), name) == 0) {
+            /* add phi */
+            if (!phi[i])
+               phi[i] = LLVMBuildPhi(ctx->builder, LLVMTypeOf(*var), "");
+            LLVMAddIncoming(phi[i], &v, &ctx->true_block, 1);
+         }
+      }
+
+      /* search false-clause variables list for 'name' */
+      for (j = 0; j < ifthen->num_false_variables; j++) {
+         LLVMValueRef v = ifthen->false_variables[j];
+         if (strcmp(LLVMGetValueName(v), name) == 0) {
+            /* add phi */
+            if (!phi[i])
+               phi[i] = LLVMBuildPhi(ctx->builder, LLVMTypeOf(*var), "");
+            LLVMAddIncoming(phi[i], &v, &ctx->false_block, 1);
+         }
+      }
+
+      /* "return" new phi variable to calling code */
+      if (phi[i])
+         *var = phi[i];
+   }
+
+   /***
+    *** Insert the various branch instructions here.
+    *** XXX need to verify all the builder/block positioning is correct.
+    ***/
+
+   /* Insert the conditional branch instruction at the end of entry_block */
+   LLVMPositionBuilderAtEnd(ctx->builder, ctx->entry_block);
+
+   if (ctx->false_block) {
+      /* we have an else clause */
+      LLVMBuildCondBr(ctx->builder, ctx->condition,
+                      ctx->true_block, ctx->false_block);
+   }
+   else {
+      /* no else clause */
+      LLVMBuildCondBr(ctx->builder, ctx->condition,
+                      ctx->true_block, merge_block);
+   }
+
+   /* Append an unconditional Br(anch) instruction on the true_block */
+   LLVMPositionBuilderAtEnd(ctx->builder, ctx->true_block);
+   LLVMBuildBr(ctx->builder, merge_block);
+   if (ctx->false_block) {
+      /* Append an unconditional Br(anch) instruction on the false_block */
+      LLVMPositionBuilderAtEnd(ctx->builder, ctx->false_block);
+      LLVMBuildBr(ctx->builder, merge_block);
+   }
+
+
+   /* Finish-up: continue building at end of the merge_block */
+   /* XXX is this right? */
+   LLVMPositionBuilderAtEnd(ctx->builder, merge_block);
+}
+
+
+/**
+ * Declare a variable that needs to be merged with another variable
+ * via a phi function.
+ * This function must be called after lp_build_if() and lp_build_endif().
+ */              
+void
+lp_build_if_phi_var(struct lp_build_if_state *ctx, LLVMValueRef var)
+{
+   struct lp_build_flow_if *ifthen;
+   const char *name;
+
+   name = LLVMGetValueName(var);
+   assert(name && "variable requires a name");
+
+   /* make sure the var existed before the if/then/else */
+   {
+      boolean found = FALSE;
+      uint i;
+      for (i = 0; i < ctx->flow->num_variables; i++) {
+         LLVMValueRef *var = ctx->flow->variables[i];
+         if (strcmp(LLVMGetValueName(*var), name) == 0) {
+            found = TRUE;
+            break;
+         }
+      }
+      assert(found);
+   }
+
+   ifthen = &lp_build_flow_pop(ctx->flow, LP_BUILD_FLOW_IF)->ifthen;
+
+   if (ctx->false_block) {
+      ifthen->false_variables[ifthen->num_false_variables++] = var;
+   }
+   else {
+      assert(ctx->true_block);
+      ifthen->true_variables[ifthen->num_true_variables++] = var;
+   }
+}
index e61999ff06be6e1f4d6e8cc88936e697e5fefded..1f294b8a49dac404e6b9ef0ba19f08fe02ec7294 100644 (file)
@@ -126,4 +126,31 @@ lp_build_loop_end(LLVMBuilderRef builder,
 
 
 
+
+struct lp_build_if_state
+{
+   LLVMBuilderRef builder;
+   struct lp_build_flow_context *flow;
+   LLVMValueRef condition;
+   LLVMBasicBlockRef entry_block, true_block, false_block;
+};
+
+
+void
+lp_build_if(struct lp_build_if_state *ctx,
+            struct lp_build_flow_context *flow,
+            LLVMBuilderRef builder,
+            LLVMValueRef condition);
+
+void
+lp_build_if_phi_var(struct lp_build_if_state *ctx, LLVMValueRef var);
+
+void
+lp_build_else(struct lp_build_if_state *ctx);
+
+void
+lp_build_endif(struct lp_build_if_state *ctx);
+              
+
+
 #endif /* !LP_BLD_FLOW_H */
index 49dab8ab61eed907c5d465e1579a29c910fa47a5..daedf40d558b6e95465d79e26d1b6ca9d4e42faa 100644 (file)
 #include "lp_bld_interp.h"
 
 
+/*
+ * The shader JIT function operates on blocks of quads.
+ * Each block has 2x2 quads and each quad has 2x2 pixels.
+ *
+ * We iterate over the quads in order 0, 1, 2, 3:
+ *
+ * #################
+ * #   |   #   |   #
+ * #---0---#---1---#
+ * #   |   #   |   #
+ * #################
+ * #   |   #   |   #
+ * #---2---#---3---#
+ * #   |   #   |   #
+ * #################
+ *
+ * Within each quad, we have four pixels which are represented in SOA
+ * order:
+ *
+ * #########
+ * # 0 | 1 #
+ * #---+---#
+ * # 2 | 3 #
+ * #########
+ *
+ * So the green channel (for example) of the four pixels is stored in
+ * a single vector register: {g0, g1, g2, g3}.
+ */
+
+
 static void
 attrib_name(LLVMValueRef val, unsigned attrib, unsigned chan, const char *suffix)
 {
@@ -55,6 +85,10 @@ attrib_name(LLVMValueRef val, unsigned attrib, unsigned chan, const char *suffix
 }
 
 
+/**
+ * Initialize the bld->a0, dadx, dady fields.  This involves fetching
+ * those values from the arrays which are passed into the JIT function.
+ */
 static void
 coeffs_init(struct lp_build_interp_soa_context *bld,
             LLVMValueRef a0_ptr,
@@ -91,7 +125,7 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
             case TGSI_INTERPOLATE_CONSTANT:
                a0 = LLVMBuildLoad(builder, LLVMBuildGEP(builder, a0_ptr, &index, 1, ""), "");
                a0 = lp_build_broadcast_scalar(&bld->base, a0);
-               attrib_name(a0, attrib, chan, ".dady");
+               attrib_name(a0, attrib, chan, ".a0");
                break;
 
             default:
@@ -109,29 +143,12 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
 
 
 /**
- * Multiply the dadx and dady with the xstep and ystep respectively.
+ * Emit LLVM code to compute the fragment shader input attribute values.
+ * For example, for a color input, we'll compute red, green, blue and alpha
+ * values for the four pixels in a quad.
+ * Recall that we're operating on 4-element vectors so each arithmetic
+ * operation is operating on the four pixels in a quad.
  */
-static void
-coeffs_update(struct lp_build_interp_soa_context *bld)
-{
-   unsigned attrib;
-   unsigned chan;
-
-   for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
-      unsigned mask = bld->mask[attrib];
-      unsigned mode = bld->mode[attrib];
-      if (mode != TGSI_INTERPOLATE_CONSTANT) {
-         for(chan = 0; chan < NUM_CHANNELS; ++chan) {
-            if(mask & (1 << chan)) {
-               bld->dadx[attrib][chan] = lp_build_mul_imm(&bld->base, bld->dadx[attrib][chan], bld->xstep);
-               bld->dady[attrib][chan] = lp_build_mul_imm(&bld->base, bld->dady[attrib][chan], bld->ystep);
-            }
-         }
-      }
-   }
-}
-
-
 static void
 attribs_init(struct lp_build_interp_soa_context *bld)
 {
@@ -154,7 +171,9 @@ attribs_init(struct lp_build_interp_soa_context *bld)
             res = a0;
 
             if (mode != TGSI_INTERPOLATE_CONSTANT) {
+               /* res = res + x * dadx */
                res = lp_build_add(&bld->base, res, lp_build_mul(&bld->base, x, dadx));
+               /* res = res + y * dady */
                res = lp_build_add(&bld->base, res, lp_build_mul(&bld->base, y, dady));
             }
 
@@ -178,13 +197,19 @@ attribs_init(struct lp_build_interp_soa_context *bld)
 }
 
 
+/**
+ * Increment the shader input attribute values.
+ * This is called when we move from one quad to the next.
+ */
 static void
-attribs_update(struct lp_build_interp_soa_context *bld)
+attribs_update(struct lp_build_interp_soa_context *bld, int quad_index)
 {
    LLVMValueRef oow = NULL;
    unsigned attrib;
    unsigned chan;
 
+   assert(quad_index < 4);
+
    for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
       unsigned mask = bld->mask[attrib];
       unsigned mode = bld->mode[attrib];
@@ -198,13 +223,21 @@ attribs_update(struct lp_build_interp_soa_context *bld)
 
                res = bld->attribs_pre[attrib][chan];
 
-               if(bld->xstep)
+               if (quad_index == 1 || quad_index == 3) {
+                  /* top-right or bottom-right quad */
+                  /* build res = res + dadx + dadx */
                   res = lp_build_add(&bld->base, res, dadx);
+                  res = lp_build_add(&bld->base, res, dadx);
+               }
 
-               if(bld->ystep)
+               if (quad_index == 2 || quad_index == 3) {
+                  /* bottom-left or bottom-right quad */
+                  /* build res = res + dady + dady */
                   res = lp_build_add(&bld->base, res, dady);
+                  res = lp_build_add(&bld->base, res, dady);
+               }
 
-               bld->attribs_pre[attrib][chan] = res;
+               //XXX bld->attribs_pre[attrib][chan] = res;
 
                if (mode == TGSI_INTERPOLATE_PERSPECTIVE) {
                   LLVMValueRef w = bld->pos[3];
@@ -242,17 +275,32 @@ pos_init(struct lp_build_interp_soa_context *bld,
 }
 
 
+/**
+ * Update quad position values when moving to the next quad.
+ */
 static void
-pos_update(struct lp_build_interp_soa_context *bld)
+pos_update(struct lp_build_interp_soa_context *bld, int quad_index)
 {
    LLVMValueRef x = bld->attribs[0][0];
    LLVMValueRef y = bld->attribs[0][1];
+   const int xstep = 2, ystep = 2;
 
-   if(bld->xstep)
-      x = lp_build_add(&bld->base, x, lp_build_const_scalar(bld->base.type, bld->xstep));
+   if (quad_index == 1 || quad_index == 3) {
+      /* top-right or bottom-right quad in block */
+      /* build x += xstep */
+      x = lp_build_add(&bld->base, x,
+                       lp_build_const_scalar(bld->base.type, xstep));
+   }
 
-   if(bld->ystep)
-      y = lp_build_add(&bld->base, y, lp_build_const_scalar(bld->base.type, bld->ystep));
+   if (quad_index == 2) {
+      /* bottom-left quad in block */
+      /* build y += ystep */
+      y = lp_build_add(&bld->base, y,
+                       lp_build_const_scalar(bld->base.type, ystep));
+      /* build x -= xstep */
+      x = lp_build_sub(&bld->base, x,
+                       lp_build_const_scalar(bld->base.type, xstep));
+   }
 
    lp_build_name(x, "pos.x");
    lp_build_name(y, "pos.y");
@@ -262,6 +310,9 @@ pos_update(struct lp_build_interp_soa_context *bld)
 }
 
 
+/**
+ * Initialize fragment shader input attribute info.
+ */
 void
 lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
                          const struct tgsi_token *tokens,
@@ -271,9 +322,7 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
                          LLVMValueRef dadx_ptr,
                          LLVMValueRef dady_ptr,
                          LLVMValueRef x0,
-                         LLVMValueRef y0,
-                         int xstep,
-                         int ystep)
+                         LLVMValueRef y0)
 {
    struct tgsi_parse_context parse;
    struct tgsi_full_declaration *decl;
@@ -331,21 +380,19 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
    pos_init(bld, x0, y0);
 
    attribs_init(bld);
-
-   bld->xstep = xstep;
-   bld->ystep = ystep;
-
-   coeffs_update(bld);
 }
 
 
 /**
- * Advance the position and inputs with the xstep and ystep.
+ * Advance the position and inputs to the given quad within the block.
  */
 void
-lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld)
+lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld,
+                           int quad_index)
 {
-   pos_update(bld);
+   assert(quad_index < 4);
+
+   pos_update(bld, quad_index);
 
-   attribs_update(bld);
+   attribs_update(bld, quad_index);
 }
index 9c57a10879b32423d30e2c5c2d423fc72d46ce35..e2b3bc1bf0b537a3f514d0f3c81c5d05d59837c3 100644 (file)
@@ -63,9 +63,6 @@ struct lp_build_interp_soa_context
    LLVMValueRef dadx[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
    LLVMValueRef dady[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
 
-   int xstep;
-   int ystep;
-
    /* Attribute values before perspective divide */
    LLVMValueRef attribs_pre[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
 
@@ -88,12 +85,11 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
                          LLVMValueRef dadx_ptr,
                          LLVMValueRef dady_ptr,
                          LLVMValueRef x0,
-                         LLVMValueRef y0,
-                         int xstep,
-                         int ystep);
+                         LLVMValueRef y0);
 
 void
-lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld);
+lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld,
+                           int quad_index);
 
 
 #endif /* LP_BLD_INTERP_H */
index db22a8028a6a2306bd8d5e733169abe51e94e998..d094a040d6a693509f07c993afa41e9f660c7c1d 100644 (file)
 #include "lp_bld_logic.h"
 
 
+/**
+ * Build code to compare two values 'a' and 'b' of 'type' using the given func.
+ * \param func  one of PIPE_FUNC_x
+ */
 LLVMValueRef
-lp_build_cmp(struct lp_build_context *bld,
-             unsigned func,
-             LLVMValueRef a,
-             LLVMValueRef b)
+lp_build_compare(LLVMBuilderRef builder,
+                 const struct lp_type type,
+                 unsigned func,
+                 LLVMValueRef a,
+                 LLVMValueRef b)
 {
-   const struct lp_type type = bld->type;
    LLVMTypeRef vec_type = lp_build_vec_type(type);
    LLVMTypeRef int_vec_type = lp_build_int_vec_type(type);
    LLVMValueRef zeros = LLVMConstNull(int_vec_type);
@@ -56,6 +60,9 @@ lp_build_cmp(struct lp_build_context *bld,
    LLVMValueRef res;
    unsigned i;
 
+   assert(func >= PIPE_FUNC_NEVER);
+   assert(func <= PIPE_FUNC_ALWAYS);
+
    if(func == PIPE_FUNC_NEVER)
       return zeros;
    if(func == PIPE_FUNC_ALWAYS)
@@ -68,6 +75,7 @@ lp_build_cmp(struct lp_build_context *bld,
 #if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
    if(type.width * type.length == 128) {
       if(type.floating && util_cpu_caps.has_sse) {
+         /* float[4] comparison */
          LLVMValueRef args[3];
          unsigned cc;
          boolean swap;
@@ -96,7 +104,7 @@ lp_build_cmp(struct lp_build_context *bld,
             break;
          default:
             assert(0);
-            return bld->undef;
+            return lp_build_undef(type);
          }
 
          if(swap) {
@@ -109,14 +117,15 @@ lp_build_cmp(struct lp_build_context *bld,
          }
 
          args[2] = LLVMConstInt(LLVMInt8Type(), cc, 0);
-         res = lp_build_intrinsic(bld->builder,
+         res = lp_build_intrinsic(builder,
                                   "llvm.x86.sse.cmp.ps",
                                   vec_type,
                                   args, 3);
-         res = LLVMBuildBitCast(bld->builder, res, int_vec_type, "");
+         res = LLVMBuildBitCast(builder, res, int_vec_type, "");
          return res;
       }
       else if(util_cpu_caps.has_sse2) {
+         /* int[4] comparison */
          static const struct {
             unsigned swap:1;
             unsigned eq:1;
@@ -152,7 +161,7 @@ lp_build_cmp(struct lp_build_context *bld,
             break;
          default:
             assert(0);
-            return bld->undef;
+            return lp_build_undef(type);
          }
 
          /* There are no signed byte and unsigned word/dword comparison
@@ -162,8 +171,8 @@ lp_build_cmp(struct lp_build_context *bld,
             ((type.width == 8 && type.sign) ||
              (type.width != 8 && !type.sign))) {
             LLVMValueRef msb = lp_build_int_const_scalar(type, (unsigned long long)1 << (type.width - 1));
-            a = LLVMBuildXor(bld->builder, a, msb, "");
-            b = LLVMBuildXor(bld->builder, b, msb, "");
+            a = LLVMBuildXor(builder, a, msb, "");
+            b = LLVMBuildXor(builder, b, msb, "");
          }
 
          if(table[func].swap) {
@@ -176,14 +185,14 @@ lp_build_cmp(struct lp_build_context *bld,
          }
 
          if(table[func].eq)
-            res = lp_build_intrinsic(bld->builder, pcmpeq, vec_type, args, 2);
+            res = lp_build_intrinsic(builder, pcmpeq, vec_type, args, 2);
          else if (table[func].gt)
-            res = lp_build_intrinsic(bld->builder, pcmpgt, vec_type, args, 2);
+            res = lp_build_intrinsic(builder, pcmpgt, vec_type, args, 2);
          else
             res = LLVMConstNull(vec_type);
 
          if(table[func].not)
-            res = LLVMBuildNot(bld->builder, res, "");
+            res = LLVMBuildNot(builder, res, "");
 
          return res;
       }
@@ -219,28 +228,28 @@ lp_build_cmp(struct lp_build_context *bld,
          break;
       default:
          assert(0);
-         return bld->undef;
+         return lp_build_undef(type);
       }
 
 #if 0
       /* XXX: Although valid IR, no LLVM target currently support this */
-      cond = LLVMBuildFCmp(bld->builder, op, a, b, "");
-      res = LLVMBuildSelect(bld->builder, cond, ones, zeros, "");
+      cond = LLVMBuildFCmp(builder, op, a, b, "");
+      res = LLVMBuildSelect(builder, cond, ones, zeros, "");
 #else
       debug_printf("%s: warning: using slow element-wise vector comparison\n",
                    __FUNCTION__);
       res = LLVMGetUndef(int_vec_type);
       for(i = 0; i < type.length; ++i) {
          LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
-         cond = LLVMBuildFCmp(bld->builder, op,
-                              LLVMBuildExtractElement(bld->builder, a, index, ""),
-                              LLVMBuildExtractElement(bld->builder, b, index, ""),
+         cond = LLVMBuildFCmp(builder, op,
+                              LLVMBuildExtractElement(builder, a, index, ""),
+                              LLVMBuildExtractElement(builder, b, index, ""),
                               "");
-         cond = LLVMBuildSelect(bld->builder, cond,
+         cond = LLVMBuildSelect(builder, cond,
                                 LLVMConstExtractElement(ones, index),
                                 LLVMConstExtractElement(zeros, index),
                                 "");
-         res = LLVMBuildInsertElement(bld->builder, res, cond, index, "");
+         res = LLVMBuildInsertElement(builder, res, cond, index, "");
       }
 #endif
    }
@@ -267,28 +276,28 @@ lp_build_cmp(struct lp_build_context *bld,
          break;
       default:
          assert(0);
-         return bld->undef;
+         return lp_build_undef(type);
       }
 
 #if 0
       /* XXX: Although valid IR, no LLVM target currently support this */
-      cond = LLVMBuildICmp(bld->builder, op, a, b, "");
-      res = LLVMBuildSelect(bld->builder, cond, ones, zeros, "");
+      cond = LLVMBuildICmp(builder, op, a, b, "");
+      res = LLVMBuildSelect(builder, cond, ones, zeros, "");
 #else
-      debug_printf("%s: warning: using slow element-wise vector comparison\n",
+      debug_printf("%s: warning: using slow element-wise int vector comparison\n",
                    __FUNCTION__);
       res = LLVMGetUndef(int_vec_type);
       for(i = 0; i < type.length; ++i) {
          LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
-         cond = LLVMBuildICmp(bld->builder, op,
-                              LLVMBuildExtractElement(bld->builder, a, index, ""),
-                              LLVMBuildExtractElement(bld->builder, b, index, ""),
+         cond = LLVMBuildICmp(builder, op,
+                              LLVMBuildExtractElement(builder, a, index, ""),
+                              LLVMBuildExtractElement(builder, b, index, ""),
                               "");
-         cond = LLVMBuildSelect(bld->builder, cond,
+         cond = LLVMBuildSelect(builder, cond,
                                 LLVMConstExtractElement(ones, index),
                                 LLVMConstExtractElement(zeros, index),
                                 "");
-         res = LLVMBuildInsertElement(bld->builder, res, cond, index, "");
+         res = LLVMBuildInsertElement(builder, res, cond, index, "");
       }
 #endif
    }
@@ -297,6 +306,21 @@ lp_build_cmp(struct lp_build_context *bld,
 }
 
 
+
+/**
+ * Build code to compare two values 'a' and 'b' using the given func.
+ * \param func  one of PIPE_FUNC_x
+ */
+LLVMValueRef
+lp_build_cmp(struct lp_build_context *bld,
+             unsigned func,
+             LLVMValueRef a,
+             LLVMValueRef b)
+{
+   return lp_build_compare(bld->builder, bld->type, func, a, b);
+}
+
+
 LLVMValueRef
 lp_build_select(struct lp_build_context *bld,
                 LLVMValueRef mask,
index d67500ef7074e00930dafc9a6722ea869dbc3188..40d64eb2c1917c2089865224b7105e2f2b2c56f3 100644 (file)
@@ -46,6 +46,14 @@ struct lp_type;
 struct lp_build_context;
 
 
+LLVMValueRef
+lp_build_compare(LLVMBuilderRef builder,
+                 const struct lp_type type,
+                 unsigned func,
+                 LLVMValueRef a,
+                 LLVMValueRef b);
+
+
 /**
  * @param func is one of PIPE_FUNC_xxx
  */
index 1320a2672142d6ded4f15c2e5deff8f8408ab811..8270cd057f61c114c2f532d09d331f212194bac5 100644 (file)
@@ -157,6 +157,27 @@ lp_build_int_vec_type(struct lp_type type)
 }
 
 
+/**
+ * Build int32[4] vector type
+ */
+LLVMTypeRef
+lp_build_int32_vec4_type(void)
+{
+   struct lp_type t;
+   LLVMTypeRef type;
+
+   memset(&t, 0, sizeof(t));
+   t.floating = FALSE; /* floating point values */
+   t.sign = TRUE;      /* values are signed */
+   t.norm = FALSE;     /* values are not limited to [0,1] or [-1,1] */
+   t.width = 32;       /* 32-bit int */
+   t.length = 4;       /* 4 elements per vector */
+
+   type = lp_build_int_elem_type(t);
+   return LLVMVectorType(type, t.length);
+}
+
+
 struct lp_type
 lp_int_type(struct lp_type type)
 {
index 2fb233d335f6b3546d7ef3041209ff903de24b1b..b7d8aed396dec41d0b984128521bf58b797453f1 100644 (file)
@@ -252,6 +252,10 @@ LLVMTypeRef
 lp_build_int_vec_type(struct lp_type type);
 
 
+LLVMTypeRef
+lp_build_int32_vec4_type();
+
+
 struct lp_type
 lp_int_type(struct lp_type type);
 
index 66f1f8e13837b772fdae240339009d0a56725ff6..a5ef221a216e952800e1d109a239f4f854053271 100644 (file)
@@ -108,32 +108,6 @@ llvmpipe_user_buffer_create(struct pipe_screen *screen,
 }
 
 
-static void
-llvmpipe_fence_reference(struct pipe_screen *screen,
-                         struct pipe_fence_handle **ptr,
-                         struct pipe_fence_handle *fence)
-{
-}
-
-
-static int
-llvmpipe_fence_signalled(struct pipe_screen *screen,
-                         struct pipe_fence_handle *fence,
-                         unsigned flag)
-{
-   return 0;
-}
-
-
-static int
-llvmpipe_fence_finish(struct pipe_screen *screen,
-                      struct pipe_fence_handle *fence,
-                      unsigned flag)
-{
-   return 0;
-}
-
-
 void
 llvmpipe_init_screen_buffer_funcs(struct pipe_screen *screen)
 {
@@ -142,9 +116,4 @@ llvmpipe_init_screen_buffer_funcs(struct pipe_screen *screen)
    screen->buffer_map = llvmpipe_buffer_map;
    screen->buffer_unmap = llvmpipe_buffer_unmap;
    screen->buffer_destroy = llvmpipe_buffer_destroy;
-
-   screen->fence_reference = llvmpipe_fence_reference;
-   screen->fence_signalled = llvmpipe_fence_signalled;
-   screen->fence_finish = llvmpipe_fence_finish;
-
 }
index 08d9f2e2735e3f7eb2ce7eb5f20b3981dd6fa472..3e8c4109251bf6a96dfba285eed17c5feb3f3d17 100644 (file)
 
 
 #include "pipe/p_defines.h"
-#include "util/u_pack_color.h"
 #include "lp_clear.h"
 #include "lp_context.h"
-#include "lp_surface.h"
-#include "lp_state.h"
-#include "lp_tile_cache.h"
+#include "lp_setup.h"
 
 
 /**
  * No masking, no scissor (clear entire buffer).
  */
 void
-llvmpipe_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba,
-               double depth, unsigned stencil)
+llvmpipe_clear(struct pipe_context *pipe, 
+               unsigned buffers,
+               const float *rgba,
+               double depth,
+               unsigned stencil)
 {
    struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
-   union util_color uc;
-   unsigned cv;
-   uint i;
 
    if (llvmpipe->no_rast)
       return;
 
-#if 0
-   llvmpipe_update_derived(llvmpipe); /* not needed?? */
-#endif
-
-   if (buffers & PIPE_CLEAR_COLOR) {
-      for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++) {
-         struct pipe_surface *ps = llvmpipe->framebuffer.cbufs[i];
-
-         util_pack_color(rgba, ps->format, &uc);
-         lp_tile_cache_clear(llvmpipe->cbuf_cache[i], rgba, uc.ui);
-      }
-      llvmpipe->dirty_render_cache = TRUE;
-   }
-
-   if (buffers & PIPE_CLEAR_DEPTHSTENCIL) {
-      struct pipe_surface *ps = llvmpipe->framebuffer.zsbuf;
-
-      cv = util_pack_z_stencil(ps->format, depth, stencil);
-
-      /* non-cached surface */
-      pipe->surface_fill(pipe, ps, 0, 0, ps->width, ps->height, cv);
-   }
+   lp_setup_clear( llvmpipe->setup, rgba, depth, stencil, buffers );
 }
index 1cc3c9227cc8175c91c16c3396a89fd5d8d2cf90..8d965175f8c32c90c93c12f7c3ec360046babd3a 100644 (file)
 #include "lp_clear.h"
 #include "lp_context.h"
 #include "lp_flush.h"
-#include "lp_prim_vbuf.h"
 #include "lp_state.h"
 #include "lp_surface.h"
-#include "lp_tile_cache.h"
-#include "lp_tex_cache.h"
 #include "lp_texture.h"
 #include "lp_winsys.h"
 #include "lp_query.h"
+#include "lp_setup.h"
 
 
 
-/**
- * Map any drawing surfaces which aren't already mapped
- */
-void
-llvmpipe_map_transfers(struct llvmpipe_context *lp)
-{
-   struct pipe_screen *screen = lp->pipe.screen;
-   struct pipe_surface *zsbuf = lp->framebuffer.zsbuf;
-   unsigned i;
-
-   for (i = 0; i < lp->framebuffer.nr_cbufs; i++) {
-      lp_tile_cache_map_transfers(lp->cbuf_cache[i]);
-   }
-
-   if(zsbuf) {
-      if(!lp->zsbuf_transfer)
-         lp->zsbuf_transfer = screen->get_tex_transfer(screen, zsbuf->texture,
-                                                       zsbuf->face, zsbuf->level, zsbuf->zslice,
-                                                       PIPE_TRANSFER_READ_WRITE,
-                                                       0, 0, zsbuf->width, zsbuf->height);
-      if(lp->zsbuf_transfer && !lp->zsbuf_map)
-         lp->zsbuf_map = screen->transfer_map(screen, lp->zsbuf_transfer);
-
-   }
-}
-
-
-/**
- * Unmap any mapped drawing surfaces
- */
-void
-llvmpipe_unmap_transfers(struct llvmpipe_context *lp)
-{
-   uint i;
-
-   for (i = 0; i < lp->framebuffer.nr_cbufs; i++) {
-      lp_tile_cache_unmap_transfers(lp->cbuf_cache[i]);
-   }
-
-   if(lp->zsbuf_transfer) {
-      struct pipe_screen *screen = lp->pipe.screen;
-
-      if(lp->zsbuf_map) {
-         screen->transfer_unmap(screen, lp->zsbuf_transfer);
-         lp->zsbuf_map = NULL;
-      }
-   }
-}
 
 
 static void llvmpipe_destroy( struct pipe_context *pipe )
@@ -104,22 +54,22 @@ static void llvmpipe_destroy( struct pipe_context *pipe )
    struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
    uint i;
 
+   /* This will also destroy llvmpipe->setup:
+    */
    if (llvmpipe->draw)
       draw_destroy( llvmpipe->draw );
 
    for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
-      lp_destroy_tile_cache(llvmpipe->cbuf_cache[i]);
       pipe_surface_reference(&llvmpipe->framebuffer.cbufs[i], NULL);
    }
+
    pipe_surface_reference(&llvmpipe->framebuffer.zsbuf, NULL);
 
    for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
-      lp_destroy_tex_tile_cache(llvmpipe->tex_cache[i]);
       pipe_texture_reference(&llvmpipe->texture[i], NULL);
    }
 
    for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
-      lp_destroy_tex_tile_cache(llvmpipe->vertex_tex_cache[i]);
       pipe_texture_reference(&llvmpipe->vertex_textures[i], NULL);
    }
 
@@ -138,33 +88,8 @@ llvmpipe_is_texture_referenced( struct pipe_context *pipe,
                                unsigned face, unsigned level)
 {
    struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
-   unsigned i;
-
-   /* check if any of the bound drawing surfaces are this texture */
-   if(llvmpipe->dirty_render_cache) {
-      for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++) {
-         if(llvmpipe->framebuffer.cbufs[i] && 
-            llvmpipe->framebuffer.cbufs[i]->texture == texture)
-            return PIPE_REFERENCED_FOR_WRITE;
-      }
-      if(llvmpipe->framebuffer.zsbuf && 
-         llvmpipe->framebuffer.zsbuf->texture == texture)
-         return PIPE_REFERENCED_FOR_WRITE;
-   }
 
-   /* check if any of the tex_cache textures are this texture */
-   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
-      if (llvmpipe->tex_cache[i] &&
-            llvmpipe->tex_cache[i]->texture == texture)
-         return PIPE_REFERENCED_FOR_READ;
-   }
-   for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
-      if (llvmpipe->vertex_tex_cache[i] &&
-          llvmpipe->vertex_tex_cache[i]->texture == texture)
-         return PIPE_REFERENCED_FOR_READ;
-   }
-   
-   return PIPE_UNREFERENCED;
+   return lp_setup_is_texture_referenced(llvmpipe->setup, texture);
 }
 
 static unsigned int
@@ -178,7 +103,6 @@ struct pipe_context *
 llvmpipe_create( struct pipe_screen *screen )
 {
    struct llvmpipe_context *llvmpipe;
-   uint i;
 
    llvmpipe = align_malloc(sizeof(struct llvmpipe_context), 16);
    if (!llvmpipe)
@@ -244,18 +168,6 @@ llvmpipe_create( struct pipe_screen *screen )
    llvmpipe_init_query_funcs( llvmpipe );
    llvmpipe_init_texture_funcs( llvmpipe );
 
-   /*
-    * Alloc caches for accessing drawing surfaces and textures.
-    */
-   for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
-      llvmpipe->cbuf_cache[i] = lp_create_tile_cache( screen );
-
-   for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
-      llvmpipe->tex_cache[i] = lp_create_tex_tile_cache( screen );
-   for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++)
-      llvmpipe->vertex_tex_cache[i] = lp_create_tex_tile_cache(screen);
-
-
    /*
     * Create drawing context and plug our rendering stage into it.
     */
@@ -268,19 +180,11 @@ llvmpipe_create( struct pipe_screen *screen )
    if (debug_get_bool_option( "LP_NO_RAST", FALSE ))
       llvmpipe->no_rast = TRUE;
 
-   llvmpipe->vbuf_backend = lp_create_vbuf_backend(llvmpipe);
-   if (!llvmpipe->vbuf_backend)
+   llvmpipe->setup = lp_setup_create( screen,
+                                      llvmpipe->draw );
+   if (!llvmpipe->setup)
       goto fail;
 
-   llvmpipe->vbuf = draw_vbuf_stage(llvmpipe->draw, llvmpipe->vbuf_backend);
-   if (!llvmpipe->vbuf)
-      goto fail;
-
-   draw_set_rasterize_stage(llvmpipe->draw, llvmpipe->vbuf);
-   draw_set_render(llvmpipe->draw, llvmpipe->vbuf_backend);
-
-
-
    /* plug in AA line/point stages */
    draw_install_aaline_stage(llvmpipe->draw, &llvmpipe->pipe);
    draw_install_aapoint_stage(llvmpipe->draw, &llvmpipe->pipe);
index 6411797cf5d280afe7f4909486fb11cc70b4c1a3..1ede6a6a72f9bc69bce5c690194dc3145962601d 100644 (file)
 struct llvmpipe_vbuf_render;
 struct draw_context;
 struct draw_stage;
-struct llvmpipe_tile_cache;
-struct llvmpipe_tex_tile_cache;
 struct lp_fragment_shader;
 struct lp_vertex_shader;
 struct lp_blend_state;
-
+struct setup_context;
 
 struct llvmpipe_context {
    struct pipe_context pipe;  /**< base class */
@@ -62,7 +60,7 @@ struct llvmpipe_context {
    const struct lp_vertex_shader *vs;
 
    /** Other rendering state */
-   struct pipe_blend_color blend_color[4][16];
+   struct pipe_blend_color blend_color;
    struct pipe_clip_state clip;
    struct pipe_constant_buffer constants[PIPE_SHADER_TYPES];
    struct pipe_framebuffer_state framebuffer;
@@ -94,49 +92,22 @@ struct llvmpipe_context {
    
    /** Vertex format */
    struct vertex_info vertex_info;
-   struct vertex_info vertex_info_vbuf;
 
    /** Which vertex shader output slot contains point size */
    int psize_slot;
 
-   /* The reduced version of the primitive supplied by the state
-    * tracker.
-    */
-   unsigned reduced_api_prim;
-
-   /* The reduced primitive after unfilled triangles, wide-line
-    * decomposition, etc, are taken into account.  This is the
-    * primitive actually rasterized.
-    */
-   unsigned reduced_prim;
-
    /** Derived from scissor and surface bounds: */
    struct pipe_scissor_state cliprect;
 
-   unsigned line_stipple_counter;
+   /** The tiling engine */
+   struct setup_context *setup;
 
    /** The primitive drawing context */
    struct draw_context *draw;
 
-   /** Draw module backend */
-   struct vbuf_render *vbuf_backend;
-   struct draw_stage *vbuf;
-
-   boolean dirty_render_cache;
-   
-   struct llvmpipe_tile_cache *cbuf_cache[PIPE_MAX_COLOR_BUFS];
-   
-   /* TODO: we shouldn't be using external interfaces internally like this */
-   struct pipe_transfer *zsbuf_transfer;
-   uint8_t *zsbuf_map;
-
    unsigned tex_timestamp;
-   struct llvmpipe_tex_tile_cache *tex_cache[PIPE_MAX_SAMPLERS];
-   struct llvmpipe_tex_tile_cache *vertex_tex_cache[PIPE_MAX_VERTEX_SAMPLERS];
-
-   unsigned no_rast : 1;
+   boolean no_rast;
 
-   struct lp_jit_context jit_context;
 };
 
 
index c152b4413fcf00fc31d06ef7cbbe57744d60c3c9..3989cce7445e49b5266b58ecd5dbb004ae45d843 100644 (file)
@@ -70,13 +70,9 @@ llvmpipe_draw_range_elements(struct pipe_context *pipe,
    struct draw_context *draw = lp->draw;
    unsigned i;
 
-   lp->reduced_api_prim = u_reduced_prim(mode);
-
    if (lp->dirty)
       llvmpipe_update_derived( lp );
 
-   llvmpipe_map_transfers(lp);
-
    /*
     * Map vertex buffers
     */
@@ -118,10 +114,6 @@ llvmpipe_draw_range_elements(struct pipe_context *pipe,
     * internally when this condition is seen?)
     */
    draw_flush(draw);
-
-   /* Note: leave drawing surfaces mapped */
-
-   lp->dirty_render_cache = TRUE;
 }
 
 
diff --git a/src/gallium/drivers/llvmpipe/lp_fence.c b/src/gallium/drivers/llvmpipe/lp_fence.c
new file mode 100644 (file)
index 0000000..97c4608
--- /dev/null
@@ -0,0 +1,109 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 VMWARE 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 "pipe/p_screen.h"
+#include "util/u_memory.h"
+#include "lp_fence.h"
+
+
+struct lp_fence *
+lp_fence_create(unsigned rank)
+{
+   struct lp_fence *fence = CALLOC_STRUCT(lp_fence);
+
+   pipe_reference_init(&fence->reference, 1);
+
+   pipe_mutex_init(fence->mutex);
+   pipe_condvar_init(fence->signalled);
+
+   fence->rank = rank;
+
+   return fence;
+}
+
+
+static void
+lp_fence_destroy(struct lp_fence *fence)
+{
+   pipe_mutex_destroy(fence->mutex);
+   pipe_condvar_destroy(fence->signalled);
+   FREE(fence);
+}
+
+
+static void
+llvmpipe_fence_reference(struct pipe_screen *screen,
+                         struct pipe_fence_handle **ptr,
+                         struct pipe_fence_handle *fence)
+{
+   struct lp_fence *old = (struct lp_fence *) *ptr;
+   struct lp_fence *f = (struct lp_fence *) fence;
+
+   if (pipe_reference(&old->reference, &f->reference)) {
+      lp_fence_destroy(old);
+   }
+}
+
+
+static int
+llvmpipe_fence_signalled(struct pipe_screen *screen,
+                         struct pipe_fence_handle *fence,
+                         unsigned flag)
+{
+   struct lp_fence *f = (struct lp_fence *) fence;
+
+   return f->count == f->rank;
+}
+
+
+static int
+llvmpipe_fence_finish(struct pipe_screen *screen,
+                      struct pipe_fence_handle *fence_handle,
+                      unsigned flag)
+{
+   struct lp_fence *fence = (struct lp_fence *) fence_handle;
+
+   pipe_mutex_lock(fence->mutex);
+   while (fence->count < fence->rank) {
+      pipe_condvar_wait(fence->signalled, fence->mutex);
+   }
+   pipe_mutex_unlock(fence->mutex);
+
+   return 0;
+}
+
+
+
+
+void
+llvmpipe_init_screen_fence_funcs(struct pipe_screen *screen)
+{
+   screen->fence_reference = llvmpipe_fence_reference;
+   screen->fence_signalled = llvmpipe_fence_signalled;
+   screen->fence_finish = llvmpipe_fence_finish;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_fence.h b/src/gallium/drivers/llvmpipe/lp_fence.h
new file mode 100644 (file)
index 0000000..d45318f
--- /dev/null
@@ -0,0 +1,60 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 VMWARE 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 LP_FENCE_H
+#define LP_FENCE_H
+
+
+#include "pipe/p_refcnt.h"
+#include "pipe/p_thread.h"
+
+
+struct pipe_screen;
+
+
+struct lp_fence
+{
+   struct pipe_reference reference;
+
+   pipe_mutex mutex;
+   pipe_condvar signalled;
+
+   unsigned rank;
+   unsigned count;
+};
+
+
+struct lp_fence *
+lp_fence_create(unsigned rank);
+
+
+void
+llvmpipe_init_screen_fence_funcs(struct pipe_screen *screen);
+
+
+#endif /* LP_FENCE_H */
index cd8381fe3086c1c6702286c488a04ee05cf0bfcd..9405150c4f7ff0db0d26c9e8564ed04a1d13f854 100644 (file)
 #include "lp_flush.h"
 #include "lp_context.h"
 #include "lp_surface.h"
-#include "lp_state.h"
-#include "lp_tile_cache.h"
-#include "lp_tex_cache.h"
 #include "lp_winsys.h"
+#include "lp_setup.h"
 
 
 void
@@ -47,40 +45,31 @@ llvmpipe_flush( struct pipe_context *pipe,
                 struct pipe_fence_handle **fence )
 {
    struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
-   uint i;
 
    draw_flush(llvmpipe->draw);
 
-   if (flags & PIPE_FLUSH_SWAPBUFFERS) {
-      /* If this is a swapbuffers, just flush color buffers.
-       *
-       * The zbuffer changes are not discarded, but held in the cache
-       * in the hope that a later clear will wipe them out.
-       */
-      for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++)
-         if (llvmpipe->cbuf_cache[i]) {
-            lp_tile_cache_map_transfers(llvmpipe->cbuf_cache[i]);
-            lp_flush_tile_cache(llvmpipe->cbuf_cache[i]);
-         }
+   if (fence) {
+      if ((flags & (PIPE_FLUSH_SWAPBUFFERS |
+                    PIPE_FLUSH_RENDER_CACHE))) {
+         /* if we're going to flush the setup/rasterization modules, emit
+          * a fence.
+          * XXX this (and the code below) may need fine tuning...
+          */
+         *fence = lp_setup_fence( llvmpipe->setup );
+      }
+      else {
+         *fence = NULL;
+      }
+   }
 
-      /* Need this call for hardware buffers before swapbuffers.
-       *
-       * there should probably be another/different flush-type function
-       * that's called before swapbuffers because we don't always want
-       * to unmap surfaces when flushing.
-       */
-      llvmpipe_unmap_transfers(llvmpipe);
+   /* XXX the lp_setup_flush(flags) param is not a bool, and it's ignored
+    * at this time!
+    */
+   if (flags & PIPE_FLUSH_SWAPBUFFERS) {
+      lp_setup_flush( llvmpipe->setup, FALSE );
    }
    else if (flags & PIPE_FLUSH_RENDER_CACHE) {
-      for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++)
-         if (llvmpipe->cbuf_cache[i]) {
-            lp_tile_cache_map_transfers(llvmpipe->cbuf_cache[i]);
-            lp_flush_tile_cache(llvmpipe->cbuf_cache[i]);
-         }
-
-      /* FIXME: untile zsbuf! */
-     
-      llvmpipe->dirty_render_cache = FALSE;
+      lp_setup_flush( llvmpipe->setup, TRUE );
    }
 
    /* Enable to dump BMPs of the color/depth buffers each frame */
@@ -95,8 +84,5 @@ llvmpipe_flush( struct pipe_context *pipe,
       ++frame_no;
    }
 #endif
-   
-   if (fence)
-      *fence = NULL;
 }
 
index 277b690c02ca8d5ba6c31ef7c9a074e8490f45ba..1a6e939aa247752ee340ebe3f7df4fb92d70af23 100644 (file)
@@ -102,15 +102,21 @@ struct lp_jit_context
 
 
 typedef void
-(*lp_jit_frag_func)(struct lp_jit_context *context,
+(*lp_jit_frag_func)(const struct lp_jit_context *context,
                     uint32_t x,
                     uint32_t y,
                     const void *a0,
                     const void *dadx,
                     const void *dady,
-                    uint32_t *mask,
                     void *color,
-                    void *depth);
+                    void *depth,
+                    const int32_t c1,
+                    const int32_t c2,
+                    const int32_t c3,
+                    const int32_t *step1,
+                    const int32_t *step2,
+                    const int32_t *step3);
+
 
 void
 lp_jit_screen_cleanup(struct llvmpipe_screen *screen);
diff --git a/src/gallium/drivers/llvmpipe/lp_prim_vbuf.c b/src/gallium/drivers/llvmpipe/lp_prim_vbuf.c
deleted file mode 100644 (file)
index e8e2e25..0000000
+++ /dev/null
@@ -1,563 +0,0 @@
-/**************************************************************************
- *
- * 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.
- *
- **************************************************************************/
-
-/**
- * Interface between 'draw' module's output and the llvmpipe rasterizer/setup
- * code.  When the 'draw' module has finished filling a vertex buffer, the
- * draw_arrays() functions below will be called.  Loop over the vertices and
- * call the point/line/tri setup functions.
- *
- * Authors
- *  Brian Paul
- */
-
-
-#include "lp_context.h"
-#include "lp_setup.h"
-#include "lp_state.h"
-#include "lp_prim_vbuf.h"
-#include "draw/draw_context.h"
-#include "draw/draw_vbuf.h"
-#include "util/u_memory.h"
-#include "util/u_prim.h"
-
-
-#define LP_MAX_VBUF_INDEXES 1024
-#define LP_MAX_VBUF_SIZE    4096
-
-typedef const float (*cptrf4)[4];
-
-/**
- * Subclass of vbuf_render.
- */
-struct llvmpipe_vbuf_render
-{
-   struct vbuf_render base;
-   struct llvmpipe_context *llvmpipe;
-   struct setup_context *setup;
-
-   uint prim;
-   uint vertex_size;
-   uint nr_vertices;
-   uint vertex_buffer_size;
-   void *vertex_buffer;
-};
-
-
-/** cast wrapper */
-static struct llvmpipe_vbuf_render *
-llvmpipe_vbuf_render(struct vbuf_render *vbr)
-{
-   return (struct llvmpipe_vbuf_render *) vbr;
-}
-
-
-
-
-
-
-
-static const struct vertex_info *
-lp_vbuf_get_vertex_info(struct vbuf_render *vbr)
-{
-   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
-   return llvmpipe_get_vbuf_vertex_info(cvbr->llvmpipe);
-}
-
-
-static boolean
-lp_vbuf_allocate_vertices(struct vbuf_render *vbr,
-                          ushort vertex_size, ushort nr_vertices)
-{
-   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
-   unsigned size = vertex_size * nr_vertices;
-
-   if (cvbr->vertex_buffer_size < size) {
-      align_free(cvbr->vertex_buffer);
-      cvbr->vertex_buffer = align_malloc(size, 16);
-      cvbr->vertex_buffer_size = size;
-   }
-
-   cvbr->vertex_size = vertex_size;
-   cvbr->nr_vertices = nr_vertices;
-   
-   return cvbr->vertex_buffer != NULL;
-}
-
-static void
-lp_vbuf_release_vertices(struct vbuf_render *vbr)
-{
-   /* keep the old allocation for next time */
-}
-
-static void *
-lp_vbuf_map_vertices(struct vbuf_render *vbr)
-{
-   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
-   return cvbr->vertex_buffer;
-}
-
-static void 
-lp_vbuf_unmap_vertices(struct vbuf_render *vbr, 
-                       ushort min_index,
-                       ushort max_index )
-{
-   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
-   assert( cvbr->vertex_buffer_size >= (max_index+1) * cvbr->vertex_size );
-   (void) cvbr;
-   /* do nothing */
-}
-
-
-static boolean
-lp_vbuf_set_primitive(struct vbuf_render *vbr, unsigned prim)
-{
-   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
-   struct setup_context *setup_ctx = cvbr->setup;
-   
-   llvmpipe_setup_prepare( setup_ctx );
-
-   cvbr->llvmpipe->reduced_prim = u_reduced_prim(prim);
-   cvbr->prim = prim;
-   return TRUE;
-
-}
-
-
-static INLINE cptrf4 get_vert( const void *vertex_buffer,
-                               int index,
-                               int stride )
-{
-   return (cptrf4)((char *)vertex_buffer + index * stride);
-}
-
-
-/**
- * draw elements / indexed primitives
- */
-static void
-lp_vbuf_draw(struct vbuf_render *vbr, const ushort *indices, uint nr)
-{
-   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
-   struct llvmpipe_context *llvmpipe = cvbr->llvmpipe;
-   const unsigned stride = llvmpipe->vertex_info_vbuf.size * sizeof(float);
-   const void *vertex_buffer = cvbr->vertex_buffer;
-   struct setup_context *setup_ctx = cvbr->setup;
-   unsigned i;
-
-   switch (cvbr->prim) {
-   case PIPE_PRIM_POINTS:
-      for (i = 0; i < nr; i++) {
-         llvmpipe_setup_point( setup_ctx,
-                      get_vert(vertex_buffer, indices[i-0], stride) );
-      }
-      break;
-
-   case PIPE_PRIM_LINES:
-      for (i = 1; i < nr; i += 2) {
-         llvmpipe_setup_line( setup_ctx,
-                     get_vert(vertex_buffer, indices[i-1], stride),
-                     get_vert(vertex_buffer, indices[i-0], stride) );
-      }
-      break;
-
-   case PIPE_PRIM_LINE_STRIP:
-      for (i = 1; i < nr; i ++) {
-         llvmpipe_setup_line( setup_ctx,
-                     get_vert(vertex_buffer, indices[i-1], stride),
-                     get_vert(vertex_buffer, indices[i-0], stride) );
-      }
-      break;
-
-   case PIPE_PRIM_LINE_LOOP:
-      for (i = 1; i < nr; i ++) {
-         llvmpipe_setup_line( setup_ctx,
-                     get_vert(vertex_buffer, indices[i-1], stride),
-                     get_vert(vertex_buffer, indices[i-0], stride) );
-      }
-      if (nr) {
-         llvmpipe_setup_line( setup_ctx,
-                     get_vert(vertex_buffer, indices[nr-1], stride),
-                     get_vert(vertex_buffer, indices[0], stride) );
-      }
-      break;
-
-   case PIPE_PRIM_TRIANGLES:
-      if (llvmpipe->rasterizer->flatshade_first) {
-         for (i = 2; i < nr; i += 3) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-1], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride),
-                       get_vert(vertex_buffer, indices[i-2], stride) );
-         }
-      }
-      else {
-         for (i = 2; i < nr; i += 3) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-2], stride),
-                       get_vert(vertex_buffer, indices[i-1], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride) );
-         }
-      }
-      break;
-
-   case PIPE_PRIM_TRIANGLE_STRIP:
-      if (llvmpipe->rasterizer->flatshade_first) {
-         for (i = 2; i < nr; i += 1) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i+(i&1)-1], stride),
-                       get_vert(vertex_buffer, indices[i-(i&1)], stride),
-                       get_vert(vertex_buffer, indices[i-2], stride) );
-         }
-      }
-      else {
-         for (i = 2; i < nr; i += 1) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i+(i&1)-2], stride),
-                       get_vert(vertex_buffer, indices[i-(i&1)-1], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride) );
-         }
-      }
-      break;
-
-   case PIPE_PRIM_TRIANGLE_FAN:
-      if (llvmpipe->rasterizer->flatshade_first) {
-         for (i = 2; i < nr; i += 1) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-0], stride),
-                       get_vert(vertex_buffer, indices[0], stride),
-                       get_vert(vertex_buffer, indices[i-1], stride) );
-         }
-      }
-      else {
-         for (i = 2; i < nr; i += 1) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[0], stride),
-                       get_vert(vertex_buffer, indices[i-1], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride) );
-         }
-      }
-      break;
-
-   case PIPE_PRIM_QUADS:
-      if (llvmpipe->rasterizer->flatshade_first) {
-         for (i = 3; i < nr; i += 4) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-2], stride),
-                       get_vert(vertex_buffer, indices[i-1], stride),
-                       get_vert(vertex_buffer, indices[i-3], stride) );
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-1], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride),
-                       get_vert(vertex_buffer, indices[i-3], stride) );
-         }
-      }
-      else {
-         for (i = 3; i < nr; i += 4) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-3], stride),
-                       get_vert(vertex_buffer, indices[i-2], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride) );
-
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-2], stride),
-                       get_vert(vertex_buffer, indices[i-1], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride) );
-         }
-      }
-      break;
-
-   case PIPE_PRIM_QUAD_STRIP:
-      if (llvmpipe->rasterizer->flatshade_first) {
-         for (i = 3; i < nr; i += 2) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-0], stride),
-                       get_vert(vertex_buffer, indices[i-1], stride),
-                       get_vert(vertex_buffer, indices[i-3], stride));
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-2], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride),
-                       get_vert(vertex_buffer, indices[i-3], stride) );
-         }
-      }
-      else {
-         for (i = 3; i < nr; i += 2) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-3], stride),
-                       get_vert(vertex_buffer, indices[i-2], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride) );
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-1], stride),
-                       get_vert(vertex_buffer, indices[i-3], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride) );
-         }
-      }
-      break;
-
-   case PIPE_PRIM_POLYGON:
-      /* Almost same as tri fan but the _first_ vertex specifies the flat
-       * shading color.  Note that the first polygon vertex is passed as
-       * the last triangle vertex here.
-       * flatshade_first state makes no difference.
-       */
-      for (i = 2; i < nr; i += 1) {
-         llvmpipe_setup_tri( setup_ctx,
-                    get_vert(vertex_buffer, indices[i-0], stride),
-                    get_vert(vertex_buffer, indices[i-1], stride),
-                    get_vert(vertex_buffer, indices[0], stride) );
-      }
-      break;
-
-   default:
-      assert(0);
-   }
-}
-
-
-/**
- * This function is hit when the draw module is working in pass-through mode.
- * It's up to us to convert the vertex array into point/line/tri prims.
- */
-static void
-lp_vbuf_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
-{
-   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
-   struct llvmpipe_context *llvmpipe = cvbr->llvmpipe;
-   struct setup_context *setup_ctx = cvbr->setup;
-   const unsigned stride = llvmpipe->vertex_info_vbuf.size * sizeof(float);
-   const void *vertex_buffer =
-      (void *) get_vert(cvbr->vertex_buffer, start, stride);
-   unsigned i;
-
-   switch (cvbr->prim) {
-   case PIPE_PRIM_POINTS:
-      for (i = 0; i < nr; i++) {
-         llvmpipe_setup_point( setup_ctx,
-                      get_vert(vertex_buffer, i-0, stride) );
-      }
-      break;
-
-   case PIPE_PRIM_LINES:
-      for (i = 1; i < nr; i += 2) {
-         llvmpipe_setup_line( setup_ctx,
-                     get_vert(vertex_buffer, i-1, stride),
-                     get_vert(vertex_buffer, i-0, stride) );
-      }
-      break;
-
-   case PIPE_PRIM_LINE_STRIP:
-      for (i = 1; i < nr; i ++) {
-         llvmpipe_setup_line( setup_ctx,
-                     get_vert(vertex_buffer, i-1, stride),
-                     get_vert(vertex_buffer, i-0, stride) );
-      }
-      break;
-
-   case PIPE_PRIM_LINE_LOOP:
-      for (i = 1; i < nr; i ++) {
-         llvmpipe_setup_line( setup_ctx,
-                     get_vert(vertex_buffer, i-1, stride),
-                     get_vert(vertex_buffer, i-0, stride) );
-      }
-      if (nr) {
-         llvmpipe_setup_line( setup_ctx,
-                     get_vert(vertex_buffer, nr-1, stride),
-                     get_vert(vertex_buffer, 0, stride) );
-      }
-      break;
-
-   case PIPE_PRIM_TRIANGLES:
-      if (llvmpipe->rasterizer->flatshade_first) {
-         for (i = 2; i < nr; i += 3) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-1, stride),
-                       get_vert(vertex_buffer, i-0, stride),
-                       get_vert(vertex_buffer, i-2, stride) );
-         }
-      }
-      else {
-         for (i = 2; i < nr; i += 3) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-2, stride),
-                       get_vert(vertex_buffer, i-1, stride),
-                       get_vert(vertex_buffer, i-0, stride) );
-         }
-      }
-      break;
-
-   case PIPE_PRIM_TRIANGLE_STRIP:
-      if (llvmpipe->rasterizer->flatshade_first) {
-         for (i = 2; i < nr; i++) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i+(i&1)-1, stride),
-                       get_vert(vertex_buffer, i-(i&1), stride),
-                       get_vert(vertex_buffer, i-2, stride) );
-         }
-      }
-      else {
-         for (i = 2; i < nr; i++) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i+(i&1)-2, stride),
-                       get_vert(vertex_buffer, i-(i&1)-1, stride),
-                       get_vert(vertex_buffer, i-0, stride) );
-         }
-      }
-      break;
-
-   case PIPE_PRIM_TRIANGLE_FAN:
-      if (llvmpipe->rasterizer->flatshade_first) {
-         for (i = 2; i < nr; i += 1) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-0, stride),
-                       get_vert(vertex_buffer, 0, stride),
-                       get_vert(vertex_buffer, i-1, stride) );
-         }
-      }
-      else {
-         for (i = 2; i < nr; i += 1) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, 0, stride),
-                       get_vert(vertex_buffer, i-1, stride),
-                       get_vert(vertex_buffer, i-0, stride) );
-         }
-      }
-      break;
-
-   case PIPE_PRIM_QUADS:
-      if (llvmpipe->rasterizer->flatshade_first) {
-         for (i = 3; i < nr; i += 4) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-2, stride),
-                       get_vert(vertex_buffer, i-1, stride),
-                       get_vert(vertex_buffer, i-3, stride) );
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-1, stride),
-                       get_vert(vertex_buffer, i-0, stride),
-                       get_vert(vertex_buffer, i-3, stride) );
-         }
-      }
-      else {
-         for (i = 3; i < nr; i += 4) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-3, stride),
-                       get_vert(vertex_buffer, i-2, stride),
-                       get_vert(vertex_buffer, i-0, stride) );
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-2, stride),
-                       get_vert(vertex_buffer, i-1, stride),
-                       get_vert(vertex_buffer, i-0, stride) );
-         }
-      }
-      break;
-
-   case PIPE_PRIM_QUAD_STRIP:
-      if (llvmpipe->rasterizer->flatshade_first) {
-         for (i = 3; i < nr; i += 2) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-0, stride),
-                       get_vert(vertex_buffer, i-1, stride),
-                       get_vert(vertex_buffer, i-3, stride) );
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-2, stride),
-                       get_vert(vertex_buffer, i-0, stride),
-                       get_vert(vertex_buffer, i-3, stride) );
-         }
-      }
-      else {
-         for (i = 3; i < nr; i += 2) {
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-3, stride),
-                       get_vert(vertex_buffer, i-2, stride),
-                       get_vert(vertex_buffer, i-0, stride) );
-            llvmpipe_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-1, stride),
-                       get_vert(vertex_buffer, i-3, stride),
-                       get_vert(vertex_buffer, i-0, stride) );
-         }
-      }
-      break;
-
-   case PIPE_PRIM_POLYGON:
-      /* Almost same as tri fan but the _first_ vertex specifies the flat
-       * shading color.  Note that the first polygon vertex is passed as
-       * the last triangle vertex here.
-       * flatshade_first state makes no difference.
-       */
-      for (i = 2; i < nr; i += 1) {
-         llvmpipe_setup_tri( setup_ctx,
-                    get_vert(vertex_buffer, i-1, stride),
-                    get_vert(vertex_buffer, i-0, stride),
-                    get_vert(vertex_buffer, 0, stride) );
-      }
-      break;
-
-   default:
-      assert(0);
-   }
-}
-
-
-
-static void
-lp_vbuf_destroy(struct vbuf_render *vbr)
-{
-   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
-   llvmpipe_setup_destroy_context(cvbr->setup);
-   FREE(cvbr);
-}
-
-
-/**
- * Create the post-transform vertex handler for the given context.
- */
-struct vbuf_render *
-lp_create_vbuf_backend(struct llvmpipe_context *lp)
-{
-   struct llvmpipe_vbuf_render *cvbr = CALLOC_STRUCT(llvmpipe_vbuf_render);
-
-   assert(lp->draw);
-
-
-   cvbr->base.max_indices = LP_MAX_VBUF_INDEXES;
-   cvbr->base.max_vertex_buffer_bytes = LP_MAX_VBUF_SIZE;
-
-   cvbr->base.get_vertex_info = lp_vbuf_get_vertex_info;
-   cvbr->base.allocate_vertices = lp_vbuf_allocate_vertices;
-   cvbr->base.map_vertices = lp_vbuf_map_vertices;
-   cvbr->base.unmap_vertices = lp_vbuf_unmap_vertices;
-   cvbr->base.set_primitive = lp_vbuf_set_primitive;
-   cvbr->base.draw = lp_vbuf_draw;
-   cvbr->base.draw_arrays = lp_vbuf_draw_arrays;
-   cvbr->base.release_vertices = lp_vbuf_release_vertices;
-   cvbr->base.destroy = lp_vbuf_destroy;
-
-   cvbr->llvmpipe = lp;
-
-   cvbr->setup = llvmpipe_setup_create_context(cvbr->llvmpipe);
-
-   return &cvbr->base;
-}
diff --git a/src/gallium/drivers/llvmpipe/lp_prim_vbuf.h b/src/gallium/drivers/llvmpipe/lp_prim_vbuf.h
deleted file mode 100644 (file)
index 0676e2f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/**************************************************************************
- * 
- * 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 LP_VBUF_H
-#define LP_VBUF_H
-
-
-struct llvmpipe_context;
-
-extern struct vbuf_render *
-lp_create_vbuf_backend(struct llvmpipe_context *llvmpipe);
-
-
-#endif /* LP_VBUF_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_quad.h b/src/gallium/drivers/llvmpipe/lp_quad.h
deleted file mode 100644 (file)
index 7eb05de..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/**************************************************************************
- * 
- * 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>
- */
-
-#ifndef LP_QUAD_H
-#define LP_QUAD_H
-
-#include "pipe/p_state.h"
-#include "tgsi/tgsi_exec.h"
-
-
-#define QUAD_PRIM_POINT 1
-#define QUAD_PRIM_LINE  2
-#define QUAD_PRIM_TRI   3
-
-
-/* The rasterizer generates 2x2 quads of fragment and feeds them to
- * the current fp_machine (see below).
- * Remember that Y=0=top with Y increasing down the window.
- */
-#define QUAD_TOP_LEFT     0
-#define QUAD_TOP_RIGHT    1
-#define QUAD_BOTTOM_LEFT  2
-#define QUAD_BOTTOM_RIGHT 3
-
-#define MASK_TOP_LEFT     (1 << QUAD_TOP_LEFT)
-#define MASK_TOP_RIGHT    (1 << QUAD_TOP_RIGHT)
-#define MASK_BOTTOM_LEFT  (1 << QUAD_BOTTOM_LEFT)
-#define MASK_BOTTOM_RIGHT (1 << QUAD_BOTTOM_RIGHT)
-#define MASK_ALL          0xf
-
-
-/**
- * Quad stage inputs (pos, coverage, front/back face, etc)
- */
-struct quad_header_input
-{
-   int x0, y0;                /**< quad window pos, always even */
-   float coverage[QUAD_SIZE]; /**< fragment coverage for antialiasing */
-   unsigned facing:1;         /**< Front (0) or back (1) facing? */
-   unsigned prim:2;           /**< QUAD_PRIM_POINT, LINE, TRI */
-};
-
-
-/**
- * Quad stage inputs/outputs.
- */
-struct quad_header_inout
-{
-   unsigned mask:4;
-};
-
-
-/**
- * Quad stage outputs (color & depth).
- */
-struct quad_header_output
-{
-   /** colors in SOA format (rrrr, gggg, bbbb, aaaa) */
-   float ALIGN16_ATTRIB color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS][QUAD_SIZE];
-};
-
-
-/**
- * Input interpolation coefficients
- */
-struct quad_interp_coef
-{
-   float ALIGN16_ATTRIB a0[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
-   float ALIGN16_ATTRIB dadx[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
-   float ALIGN16_ATTRIB dady[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
-};
-
-
-/**
- * Encodes everything we need to know about a 2x2 pixel block.  Uses
- * "Channel-Serial" or "SoA" layout.  
- */
-struct quad_header {
-   struct quad_header_input input;
-   struct quad_header_inout inout;
-
-   /* Redundant/duplicated:
-    */
-   const struct quad_interp_coef *coef;
-};
-
-#endif /* LP_QUAD_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c b/src/gallium/drivers/llvmpipe/lp_rast.c
new file mode 100644 (file)
index 0000000..6535e69
--- /dev/null
@@ -0,0 +1,793 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 VMWARE 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 <limits.h>
+#include "util/u_memory.h"
+#include "util/u_math.h"
+#include "util/u_cpu_detect.h"
+#include "util/u_surface.h"
+
+#include "lp_scene_queue.h"
+#include "lp_debug.h"
+#include "lp_fence.h"
+#include "lp_rast.h"
+#include "lp_rast_priv.h"
+#include "lp_tile_soa.h"
+#include "lp_bld_debug.h"
+#include "lp_scene.h"
+
+
+/**
+ * Begin the rasterization phase.
+ * Map the framebuffer surfaces.  Initialize the 'rast' state.
+ */
+static boolean
+lp_rast_begin( struct lp_rasterizer *rast,
+               const struct pipe_framebuffer_state *fb,
+               boolean write_color,
+               boolean write_zstencil )
+{
+   struct pipe_screen *screen = rast->screen;
+   struct pipe_surface *cbuf, *zsbuf;
+
+   LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+
+   util_copy_framebuffer_state(&rast->state.fb, fb);
+
+   rast->state.write_zstencil = write_zstencil;
+   rast->state.write_color = write_color;
+
+   rast->check_for_clipped_tiles = (fb->width % TILE_SIZE != 0 ||
+                                    fb->height % TILE_SIZE != 0);
+
+   /* XXX support multiple color buffers here */
+   cbuf = rast->state.fb.cbufs[0];
+   if (cbuf) {
+      rast->cbuf_transfer = screen->get_tex_transfer(rast->screen,
+                                                     cbuf->texture,
+                                                     cbuf->face,
+                                                     cbuf->level,
+                                                     cbuf->zslice,
+                                                     PIPE_TRANSFER_READ_WRITE,
+                                                     0, 0,
+                                                     fb->width, fb->height);
+      if (!rast->cbuf_transfer)
+         return FALSE;
+
+      rast->cbuf_map = screen->transfer_map(rast->screen, 
+                                            rast->cbuf_transfer);
+      if (!rast->cbuf_map)
+         return FALSE;
+   }
+
+   zsbuf = rast->state.fb.zsbuf;
+   if (zsbuf) {
+      rast->zsbuf_transfer = screen->get_tex_transfer(rast->screen,
+                                                      zsbuf->texture,
+                                                      zsbuf->face,
+                                                      zsbuf->level,
+                                                      zsbuf->zslice,
+                                                      PIPE_TRANSFER_READ_WRITE,
+                                                      0, 0,
+                                                      fb->width, fb->height);
+      if (!rast->zsbuf_transfer)
+         return FALSE;
+
+      rast->zsbuf_map = screen->transfer_map(rast->screen, 
+                                            rast->zsbuf_transfer);
+      if (!rast->zsbuf_map)
+         return FALSE;
+   }
+
+   return TRUE;
+}
+
+
+/**
+ * Finish the rasterization phase.
+ * Unmap framebuffer surfaces.
+ */
+static void
+lp_rast_end( struct lp_rasterizer *rast )
+{
+   struct pipe_screen *screen = rast->screen;
+
+   if (rast->cbuf_map) 
+      screen->transfer_unmap(screen, rast->cbuf_transfer);
+
+   if (rast->zsbuf_map) 
+      screen->transfer_unmap(screen, rast->zsbuf_transfer);
+
+   if (rast->cbuf_transfer)
+      screen->tex_transfer_destroy(rast->cbuf_transfer);
+
+   if (rast->zsbuf_transfer)
+      screen->tex_transfer_destroy(rast->zsbuf_transfer);
+
+   rast->cbuf_transfer = NULL;
+   rast->zsbuf_transfer = NULL;
+   rast->cbuf_map = NULL;
+   rast->zsbuf_map = NULL;
+}
+
+
+/**
+ * Begining rasterization of a tile.
+ * \param x  window X position of the tile, in pixels
+ * \param y  window Y position of the tile, in pixels
+ */
+static void
+lp_rast_start_tile( struct lp_rasterizer *rast,
+                    unsigned thread_index,
+                    unsigned x, unsigned y )
+{
+   LP_DBG(DEBUG_RAST, "%s %d,%d\n", __FUNCTION__, x, y);
+
+   rast->tasks[thread_index].x = x;
+   rast->tasks[thread_index].y = y;
+}
+
+
+/**
+ * Clear the rasterizer's current color tile.
+ * This is a bin command called during bin processing.
+ */
+void lp_rast_clear_color( struct lp_rasterizer *rast,
+                          unsigned thread_index,
+                          const union lp_rast_cmd_arg arg )
+{
+   const uint8_t *clear_color = arg.clear_color;
+   uint8_t *color_tile = rast->tasks[thread_index].tile.color;
+   
+   LP_DBG(DEBUG_RAST, "%s 0x%x,0x%x,0x%x,0x%x\n", __FUNCTION__, 
+              clear_color[0],
+              clear_color[1],
+              clear_color[2],
+              clear_color[3]);
+
+   if (clear_color[0] == clear_color[1] &&
+       clear_color[1] == clear_color[2] &&
+       clear_color[2] == clear_color[3]) {
+      memset(color_tile, clear_color[0], TILE_SIZE * TILE_SIZE * 4);
+   }
+   else {
+      unsigned x, y, chan;
+      for (y = 0; y < TILE_SIZE; y++)
+         for (x = 0; x < TILE_SIZE; x++)
+            for (chan = 0; chan < 4; ++chan)
+               TILE_PIXEL(color_tile, x, y, chan) = clear_color[chan];
+   }
+}
+
+
+/**
+ * Clear the rasterizer's current z/stencil tile.
+ * This is a bin command called during bin processing.
+ */
+void lp_rast_clear_zstencil( struct lp_rasterizer *rast,
+                             unsigned thread_index,
+                             const union lp_rast_cmd_arg arg)
+{
+   unsigned i, j;
+   uint32_t *depth_tile = rast->tasks[thread_index].tile.depth;
+   
+   LP_DBG(DEBUG_RAST, "%s 0x%x\n", __FUNCTION__, arg.clear_zstencil);
+
+   for (i = 0; i < TILE_SIZE; i++)
+      for (j = 0; j < TILE_SIZE; j++)
+        depth_tile[i*TILE_SIZE + j] = arg.clear_zstencil;
+}
+
+
+/**
+ * Load tile color from the framebuffer surface.
+ * This is a bin command called during bin processing.
+ */
+void lp_rast_load_color( struct lp_rasterizer *rast,
+                         unsigned thread_index,
+                         const union lp_rast_cmd_arg arg)
+{
+   struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+   const unsigned x = task->x;
+   const unsigned y = task->y;
+   int w = TILE_SIZE;
+   int h = TILE_SIZE;
+
+   LP_DBG(DEBUG_RAST, "%s at %u, %u\n", __FUNCTION__, x, y);
+
+   if (x + w > rast->state.fb.width)
+      w -= x + w - rast->state.fb.width;
+
+   if (y + h > rast->state.fb.height)
+      h -= y + h - rast->state.fb.height;
+
+   assert(w >= 0);
+   assert(h >= 0);
+   assert(w <= TILE_SIZE);
+   assert(h <= TILE_SIZE);
+
+   lp_tile_read_4ub(rast->cbuf_transfer->texture->format,
+                     rast->tasks[thread_index].tile.color,
+                     rast->cbuf_map, 
+                     rast->cbuf_transfer->stride,
+                     x, y,
+                     w, h);
+}
+
+
+/**
+ * Load tile z/stencil from the framebuffer surface.
+ * This is a bin command called during bin processing.
+ */
+void lp_rast_load_zstencil( struct lp_rasterizer *rast,
+                            unsigned thread_index,
+                            const union lp_rast_cmd_arg arg )
+{
+   LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+
+   /* call u_tile func to load depth (and stencil?) from surface */
+}
+
+
+void lp_rast_set_state( struct lp_rasterizer *rast,
+                        unsigned thread_index,
+                        const union lp_rast_cmd_arg arg )
+{
+   const struct lp_rast_state *state = arg.set_state;
+
+   LP_DBG(DEBUG_RAST, "%s %p\n", __FUNCTION__, (void *) state);
+
+   /* just set the current state pointer for this rasterizer */
+   rast->tasks[thread_index].current_state = state;
+}
+
+
+
+/* Within a tile:
+ */
+
+/**
+ * Run the shader on all blocks in a tile.  This is used when a tile is
+ * completely contained inside a triangle.
+ * This is a bin command called during bin processing.
+ */
+void lp_rast_shade_tile( struct lp_rasterizer *rast,
+                         unsigned thread_index,
+                         const union lp_rast_cmd_arg arg )
+{
+   /* Set c1,c2,c3 to large values so the in/out test always passes */
+   const int32_t c1 = INT_MIN, c2 = INT_MIN, c3 = INT_MIN;
+   const struct lp_rast_shader_inputs *inputs = arg.shade_tile;
+   const unsigned tile_x = rast->tasks[thread_index].x;
+   const unsigned tile_y = rast->tasks[thread_index].y;
+   unsigned x, y;
+
+   LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+
+   /* Use the existing preference for 4x4 (four quads) shading:
+    */
+   for (y = 0; y < TILE_SIZE; y += 4)
+      for (x = 0; x < TILE_SIZE; x += 4)
+         lp_rast_shade_quads( rast,
+                              thread_index,
+                              inputs,
+                              tile_x + x,
+                              tile_y + y,
+                              c1, c2, c3);
+}
+
+
+/**
+ * Compute shading for a 4x4 block of pixels.
+ * This is a bin command called during bin processing.
+ */
+void lp_rast_shade_quads( struct lp_rasterizer *rast,
+                          unsigned thread_index,
+                          const struct lp_rast_shader_inputs *inputs,
+                          unsigned x, unsigned y,
+                          int32_t c1, int32_t c2, int32_t c3)
+{
+   const struct lp_rast_state *state = rast->tasks[thread_index].current_state;
+   struct lp_rast_tile *tile = &rast->tasks[thread_index].tile;
+   void *color;
+   void *depth;
+   unsigned ix, iy;
+   int block_offset;
+
+#ifdef DEBUG
+   assert(state);
+
+   /* Sanity checks */
+   assert(x % TILE_VECTOR_WIDTH == 0);
+   assert(y % TILE_VECTOR_HEIGHT == 0);
+
+   assert((x % 4) == 0);
+   assert((y % 4) == 0);
+#endif
+
+   ix = x % TILE_SIZE;
+   iy = y % TILE_SIZE;
+
+   /* offset of the 16x16 pixel block within the tile */
+   block_offset = ((iy/4)*(16*16) + (ix/4)*16);
+
+   /* color buffer */
+   color = tile->color + 4 * block_offset;
+
+   /* depth buffer */
+   depth = tile->depth + block_offset;
+
+#ifdef DEBUG
+   assert(lp_check_alignment(depth, 16));
+   assert(lp_check_alignment(color, 16));
+   assert(lp_check_alignment(state->jit_context.blend_color, 16));
+
+   assert(lp_check_alignment(inputs->step[0], 16));
+   assert(lp_check_alignment(inputs->step[1], 16));
+   assert(lp_check_alignment(inputs->step[2], 16));
+#endif
+
+   /* run shader */
+   state->jit_function( &state->jit_context,
+                        x, y,
+                        inputs->a0,
+                        inputs->dadx,
+                        inputs->dady,
+                        color,
+                        depth,
+                        c1, c2, c3,
+                        inputs->step[0], inputs->step[1], inputs->step[2]
+                        );
+}
+
+
+/* End of tile:
+ */
+
+
+/**
+ * Write the rasterizer's color tile to the framebuffer.
+ */
+static void lp_rast_store_color( struct lp_rasterizer *rast,
+                                 unsigned thread_index)
+{
+   const unsigned x = rast->tasks[thread_index].x;
+   const unsigned y = rast->tasks[thread_index].y;
+   int w = TILE_SIZE;
+   int h = TILE_SIZE;
+
+   if (x + w > rast->state.fb.width)
+      w -= x + w - rast->state.fb.width;
+
+   if (y + h > rast->state.fb.height)
+      h -= y + h - rast->state.fb.height;
+
+   assert(w >= 0);
+   assert(h >= 0);
+   assert(w <= TILE_SIZE);
+   assert(h <= TILE_SIZE);
+
+   LP_DBG(DEBUG_RAST, "%s [%u] %d,%d %dx%d\n", __FUNCTION__,
+          thread_index, x, y, w, h);
+
+   lp_tile_write_4ub(rast->cbuf_transfer->texture->format,
+                     rast->tasks[thread_index].tile.color,
+                     rast->cbuf_map, 
+                     rast->cbuf_transfer->stride,
+                     x, y,
+                     w, h);
+}
+
+
+static void
+lp_tile_write_z32(const uint32_t *src, uint8_t *dst, unsigned dst_stride,
+                  unsigned x0, unsigned y0, unsigned w, unsigned h)
+{
+   unsigned x, y;
+   uint8_t *dst_row = dst + y0*dst_stride;
+   for (y = 0; y < h; ++y) {
+      uint32_t *dst_pixel = (uint32_t *)(dst_row + x0*4);
+      for (x = 0; x < w; ++x) {
+         *dst_pixel++ = *src++;
+      }
+      dst_row += dst_stride;
+   }
+}
+
+/**
+ * Write the rasterizer's z/stencil tile to the framebuffer.
+ */
+static void lp_rast_store_zstencil( struct lp_rasterizer *rast,
+                                    unsigned thread_index )
+{
+   const unsigned x = rast->tasks[thread_index].x;
+   const unsigned y = rast->tasks[thread_index].y;
+   unsigned w = TILE_SIZE;
+   unsigned h = TILE_SIZE;
+
+   if (x + w > rast->state.fb.width)
+      w -= x + w - rast->state.fb.width;
+
+   if (y + h > rast->state.fb.height)
+      h -= y + h - rast->state.fb.height;
+
+   LP_DBG(DEBUG_RAST, "%s %d,%d %dx%d\n", __FUNCTION__, x, y, w, h);
+
+   assert(rast->zsbuf_transfer->texture->format == PIPE_FORMAT_Z32_UNORM);
+   lp_tile_write_z32(rast->tasks[thread_index].tile.depth,
+                     rast->zsbuf_map, 
+                     rast->zsbuf_transfer->stride,
+                     x, y, w, h);
+}
+
+
+/**
+ * Write the rasterizer's tiles to the framebuffer.
+ */
+static void
+lp_rast_end_tile( struct lp_rasterizer *rast,
+                  unsigned thread_index )
+{
+   LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+
+   if (rast->state.write_color)
+      lp_rast_store_color(rast, thread_index);
+
+   if (rast->state.write_zstencil)
+      lp_rast_store_zstencil(rast, thread_index);
+}
+
+
+/**
+ * Signal on a fence.  This is called during bin execution/rasterization.
+ * Called per thread.
+ */
+void lp_rast_fence( struct lp_rasterizer *rast,
+                    unsigned thread_index,
+                    const union lp_rast_cmd_arg arg )
+{
+   struct lp_fence *fence = arg.fence;
+
+   pipe_mutex_lock( fence->mutex );
+
+   fence->count++;
+   assert(fence->count <= fence->rank);
+
+   LP_DBG(DEBUG_RAST, "%s count=%u rank=%u\n", __FUNCTION__,
+          fence->count, fence->rank);
+
+   pipe_condvar_signal( fence->signalled );
+
+   pipe_mutex_unlock( fence->mutex );
+}
+
+
+/**
+ * When all the threads are done rasterizing a scene, one thread will
+ * call this function to reset the scene and put it onto the empty queue.
+ */
+static void
+release_scene( struct lp_rasterizer *rast,
+              struct lp_scene *scene )
+{
+   util_unreference_framebuffer_state( &scene->fb );
+
+   lp_scene_reset( scene );
+   lp_scene_enqueue( rast->empty_scenes, scene );
+   rast->curr_scene = NULL;
+}
+
+
+/**
+ * Rasterize commands for a single bin.
+ * \param x, y  position of the bin's tile in the framebuffer
+ * Must be called between lp_rast_begin() and lp_rast_end().
+ * Called per thread.
+ */
+static void
+rasterize_bin( struct lp_rasterizer *rast,
+               unsigned thread_index,
+               const struct cmd_bin *bin,
+               int x, int y)
+{
+   const struct cmd_block_list *commands = &bin->commands;
+   struct cmd_block *block;
+   unsigned k;
+
+   lp_rast_start_tile( rast, thread_index, x, y );
+
+   /* simply execute each of the commands in the block list */
+   for (block = commands->head; block; block = block->next) {
+      for (k = 0; k < block->count; k++) {
+         block->cmd[k]( rast, thread_index, block->arg[k] );
+      }
+   }
+
+   lp_rast_end_tile( rast, thread_index );
+}
+
+
+/**
+ * Rasterize/execute all bins within a scene.
+ * Called per thread.
+ */
+static void
+rasterize_scene( struct lp_rasterizer *rast,
+                unsigned thread_index,
+                struct lp_scene *scene,
+                bool write_depth )
+{
+   /* loop over scene bins, rasterize each */
+#if 0
+   {
+      unsigned i, j;
+      for (i = 0; i < scene->tiles_x; i++) {
+         for (j = 0; j < scene->tiles_y; j++) {
+            struct cmd_bin *bin = lp_get_bin(scene, i, j);
+            rasterize_bin( rast, thread_index,
+                           bin, i * TILE_SIZE, j * TILE_SIZE );
+         }
+      }
+   }
+#else
+   {
+      struct cmd_bin *bin;
+      int x, y;
+
+      assert(scene);
+      while ((bin = lp_scene_bin_iter_next(scene, &x, &y))) {
+         rasterize_bin( rast, thread_index, bin, x * TILE_SIZE, y * TILE_SIZE);
+      }
+   }
+#endif
+}
+
+
+/**
+ * Called by setup module when it has something for us to render.
+ */
+void
+lp_rasterize_scene( struct lp_rasterizer *rast,
+                   struct lp_scene *scene,
+                   const struct pipe_framebuffer_state *fb,
+                   bool write_depth )
+{
+   boolean debug = false;
+
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+
+   if (debug) {
+      unsigned x, y;
+      printf("rasterize scene:\n");
+      printf("  data size: %u\n", lp_scene_data_size(scene));
+      for (y = 0; y < scene->tiles_y; y++) {
+         for (x = 0; x < scene->tiles_x; x++) {
+            printf("  bin %u, %u size: %u\n", x, y,
+                   lp_scene_bin_size(scene, x, y));
+         }
+      }
+   }
+
+   /* save framebuffer state in the bin */
+   util_copy_framebuffer_state(&scene->fb, fb);
+   scene->write_depth = write_depth;
+
+   if (rast->num_threads == 0) {
+      /* no threading */
+
+      lp_rast_begin( rast, fb,
+                     fb->cbufs[0]!= NULL,
+                     fb->zsbuf != NULL && write_depth );
+
+      lp_scene_bin_iter_begin( scene );
+      rasterize_scene( rast, 0, scene, write_depth );
+
+      release_scene( rast, scene );
+
+      lp_rast_end( rast );
+   }
+   else {
+      /* threaded rendering! */
+      unsigned i;
+
+      lp_scene_enqueue( rast->full_scenes, scene );
+
+      /* signal the threads that there's work to do */
+      for (i = 0; i < rast->num_threads; i++) {
+         pipe_semaphore_signal(&rast->tasks[i].work_ready);
+      }
+
+      /* wait for work to complete */
+      for (i = 0; i < rast->num_threads; i++) {
+         pipe_semaphore_wait(&rast->tasks[i].work_done);
+      }
+   }
+
+   LP_DBG(DEBUG_SETUP, "%s done \n", __FUNCTION__);
+}
+
+
+/**
+ * This is the thread's main entrypoint.
+ * It's a simple loop:
+ *   1. wait for work
+ *   2. do work
+ *   3. signal that we're done
+ */
+static void *
+thread_func( void *init_data )
+{
+   struct lp_rasterizer_task *task = (struct lp_rasterizer_task *) init_data;
+   struct lp_rasterizer *rast = task->rast;
+   boolean debug = false;
+
+   while (1) {
+      /* wait for work */
+      if (debug)
+         debug_printf("thread %d waiting for work\n", task->thread_index);
+      pipe_semaphore_wait(&task->work_ready);
+
+      if (task->thread_index == 0) {
+         /* thread[0]:
+          *  - get next scene to rasterize
+          *  - map the framebuffer surfaces
+          */
+         const struct pipe_framebuffer_state *fb;
+         boolean write_depth;
+
+         rast->curr_scene = lp_scene_dequeue( rast->full_scenes );
+
+         lp_scene_bin_iter_begin( rast->curr_scene );
+
+         fb = &rast->curr_scene->fb;
+         write_depth = rast->curr_scene->write_depth;
+
+         lp_rast_begin( rast, fb,
+                        fb->cbufs[0] != NULL,
+                        fb->zsbuf != NULL && write_depth );
+      }
+
+      /* Wait for all threads to get here so that threads[1+] don't
+       * get a null rast->curr_scene pointer.
+       */
+      pipe_barrier_wait( &rast->barrier );
+
+      /* do work */
+      if (debug)
+         debug_printf("thread %d doing work\n", task->thread_index);
+      rasterize_scene(rast, 
+                    task->thread_index,
+                     rast->curr_scene, 
+                    rast->curr_scene->write_depth);
+      
+      /* wait for all threads to finish with this scene */
+      pipe_barrier_wait( &rast->barrier );
+
+      if (task->thread_index == 0) {
+         /* thread[0]:
+          * - release the scene object
+          * - unmap the framebuffer surfaces
+          */
+         release_scene( rast, rast->curr_scene );
+         lp_rast_end( rast );
+      }
+
+      /* signal done with work */
+      if (debug)
+         debug_printf("thread %d done working\n", task->thread_index);
+      pipe_semaphore_signal(&task->work_done);
+   }
+
+   return NULL;
+}
+
+
+/**
+ * Initialize semaphores and spawn the threads.
+ */
+static void
+create_rast_threads(struct lp_rasterizer *rast)
+{
+   unsigned i;
+
+   rast->num_threads = util_cpu_caps.nr_cpus;
+   rast->num_threads = debug_get_num_option("LP_NUM_THREADS", rast->num_threads);
+   rast->num_threads = MIN2(rast->num_threads, MAX_THREADS);
+
+   /* NOTE: if num_threads is zero, we won't use any threads */
+   for (i = 0; i < rast->num_threads; i++) {
+      pipe_semaphore_init(&rast->tasks[i].work_ready, 0);
+      pipe_semaphore_init(&rast->tasks[i].work_done, 0);
+      rast->threads[i] = pipe_thread_create(thread_func,
+                                            (void *) &rast->tasks[i]);
+   }
+}
+
+
+
+/**
+ * Create new lp_rasterizer.
+ * \param empty  the queue to put empty scenes on after we've finished
+ *               processing them.
+ */
+struct lp_rasterizer *
+lp_rast_create( struct pipe_screen *screen, struct lp_scene_queue *empty )
+{
+   struct lp_rasterizer *rast;
+   unsigned i;
+
+   rast = CALLOC_STRUCT(lp_rasterizer);
+   if(!rast)
+      return NULL;
+
+   rast->screen = screen;
+
+   rast->empty_scenes = empty;
+   rast->full_scenes = lp_scene_queue_create();
+
+   for (i = 0; i < Elements(rast->tasks); i++) {
+      rast->tasks[i].tile.color = align_malloc( TILE_SIZE*TILE_SIZE*4, 16 );
+      rast->tasks[i].tile.depth = align_malloc( TILE_SIZE*TILE_SIZE*4, 16 );
+      rast->tasks[i].rast = rast;
+      rast->tasks[i].thread_index = i;
+   }
+
+   create_rast_threads(rast);
+
+   /* for synchronizing rasterization threads */
+   pipe_barrier_init( &rast->barrier, rast->num_threads );
+
+   return rast;
+}
+
+
+/* Shutdown:
+ */
+void lp_rast_destroy( struct lp_rasterizer *rast )
+{
+   unsigned i;
+
+   util_unreference_framebuffer_state(&rast->state.fb);
+
+   for (i = 0; i < Elements(rast->tasks); i++) {
+      align_free(rast->tasks[i].tile.depth);
+      align_free(rast->tasks[i].tile.color);
+   }
+
+   /* for synchronizing rasterization threads */
+   pipe_barrier_destroy( &rast->barrier );
+
+   FREE(rast);
+}
+
+
+/** Return number of rasterization threads */
+unsigned
+lp_rast_get_num_threads( struct lp_rasterizer *rast )
+{
+   return rast->num_threads;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_rast.h b/src/gallium/drivers/llvmpipe/lp_rast.h
new file mode 100644 (file)
index 0000000..46e22f6
--- /dev/null
@@ -0,0 +1,238 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 VMWARE 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.
+ *
+ **************************************************************************/
+
+/**
+ * The rast code is concerned with rasterization of command bins.
+ * Each screen tile has a bin associated with it.  To render the
+ * scene we iterate over the tile bins and execute the commands
+ * in each bin.
+ * We'll do that with multiple threads...
+ */
+
+
+#ifndef LP_RAST_H
+#define LP_RAST_H
+
+#include "pipe/p_compiler.h"
+#include "lp_jit.h"
+
+
+struct lp_rasterizer;
+struct lp_scene;
+struct lp_scene_queue;
+struct lp_fence;
+struct cmd_bin;
+struct pipe_screen;
+
+/** For sub-pixel positioning */
+#define FIXED_ORDER 4
+#define FIXED_ONE (1<<FIXED_ORDER)
+
+
+/**
+ * Rasterization state.
+ * Objects of this type are put into the shared data bin and pointed
+ * to by commands in the per-tile bins.
+ */
+struct lp_rast_state {
+   /* State for the shader.  This also contains state which feeds into
+    * the fragment shader, such as blend color and alpha ref value.
+    */
+   struct lp_jit_context jit_context;
+   
+   /* The shader itself.  Probably we also need to pass a pointer to
+    * the tile color/z/stencil data somehow:
+    */
+   lp_jit_frag_func jit_function;
+};
+
+
+/**
+ * Coefficients necessary to run the shader at a given location.
+ * First coefficient is position.
+ * These pointers point into the bin data buffer.
+ */
+struct lp_rast_shader_inputs {
+   float (*a0)[4];
+   float (*dadx)[4];
+   float (*dady)[4];
+
+   /* edge/step info for 3 edges and 4x4 block of pixels */
+   int ALIGN16_ATTRIB step[3][16];
+};
+
+
+/**
+ * Rasterization information for a triangle known to be in this bin,
+ * plus inputs to run the shader:
+ * These fields are tile- and bin-independent.
+ * Objects of this type are put into the setup_context::data buffer.
+ */
+struct lp_rast_triangle {
+   /* bounding box of tri (in pixels) */
+   int minx;
+   int maxx;
+   int miny;
+   int maxy;
+
+   /* one-pixel sized trivial accept offsets for each plane */
+   int ei1;                   
+   int ei2;
+   int ei3;
+
+   /* one-pixel sized trivial reject offsets for each plane */
+   int eo1;                   
+   int eo2;
+   int eo3;
+
+   /* y deltas for vertex pairs (in fixed pt) */
+   int dy12;
+   int dy23;
+   int dy31;
+
+   /* x deltas for vertex pairs (in fixed pt) */
+   int dx12;
+   int dx23;
+   int dx31;
+
+   /* edge function values at minx,miny ?? */
+   int c1, c2, c3;
+
+   /* inputs for the shader */
+   struct lp_rast_shader_inputs ALIGN16_ATTRIB inputs;
+};
+
+
+
+struct lp_rasterizer *lp_rast_create( struct pipe_screen *screen,
+                                      struct lp_scene_queue *empty );
+
+void lp_rast_destroy( struct lp_rasterizer * );
+
+unsigned lp_rast_get_num_threads( struct lp_rasterizer * );
+
+void lp_rasterize_scene( struct lp_rasterizer *rast,
+                        struct lp_scene *scene,
+                        const struct pipe_framebuffer_state *fb,
+                        bool write_depth );
+
+
+
+union lp_rast_cmd_arg {
+   const struct lp_rast_shader_inputs *shade_tile;
+   const struct lp_rast_triangle *triangle;
+   const struct lp_rast_state *set_state;
+   uint8_t clear_color[4];
+   unsigned clear_zstencil;
+   struct lp_fence *fence;
+};
+
+
+/* Cast wrappers.  Hopefully these compile to noops!
+ */
+static INLINE const union lp_rast_cmd_arg
+lp_rast_arg_inputs( const struct lp_rast_shader_inputs *shade_tile )
+{
+   union lp_rast_cmd_arg arg;
+   arg.shade_tile = shade_tile;
+   return arg;
+}
+
+static INLINE const union lp_rast_cmd_arg
+lp_rast_arg_triangle( const struct lp_rast_triangle *triangle )
+{
+   union lp_rast_cmd_arg arg;
+   arg.triangle = triangle;
+   return arg;
+}
+
+static INLINE const union lp_rast_cmd_arg
+lp_rast_arg_state( const struct lp_rast_state *state )
+{
+   union lp_rast_cmd_arg arg;
+   arg.set_state = state;
+   return arg;
+}
+
+static INLINE const union lp_rast_cmd_arg
+lp_rast_arg_fence( struct lp_fence *fence )
+{
+   union lp_rast_cmd_arg arg;
+   arg.fence = fence;
+   return arg;
+}
+
+
+static INLINE const union lp_rast_cmd_arg
+lp_rast_arg_null( void )
+{
+   union lp_rast_cmd_arg arg;
+   arg.set_state = NULL;
+   return arg;
+}
+
+
+
+/**
+ * Binnable Commands.
+ * These get put into bins by the setup code and are called when
+ * the bins are executed.
+ */
+
+void lp_rast_clear_color( struct lp_rasterizer *, 
+                          unsigned thread_index,
+                          const union lp_rast_cmd_arg );
+
+void lp_rast_clear_zstencil( struct lp_rasterizer *, 
+                             unsigned thread_index,
+                             const union lp_rast_cmd_arg );
+
+void lp_rast_load_color( struct lp_rasterizer *, 
+                         unsigned thread_index,
+                         const union lp_rast_cmd_arg );
+
+void lp_rast_load_zstencil( struct lp_rasterizer *, 
+                            unsigned thread_index,
+                            const union lp_rast_cmd_arg );
+
+void lp_rast_set_state( struct lp_rasterizer *, 
+                        unsigned thread_index,
+                        const union lp_rast_cmd_arg );
+
+void lp_rast_triangle( struct lp_rasterizer *, 
+                       unsigned thread_index,
+                       const union lp_rast_cmd_arg );
+
+void lp_rast_shade_tile( struct lp_rasterizer *,
+                         unsigned thread_index,
+                         const union lp_rast_cmd_arg );
+
+void lp_rast_fence( struct lp_rasterizer *,
+                    unsigned thread_index,
+                    const union lp_rast_cmd_arg );
+
+#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_rast_priv.h b/src/gallium/drivers/llvmpipe/lp_rast_priv.h
new file mode 100644 (file)
index 0000000..cd72d7e
--- /dev/null
@@ -0,0 +1,129 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 VMWARE 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 LP_RAST_PRIV_H
+#define LP_RAST_PRIV_H
+
+#include "pipe/p_thread.h"
+#include "lp_rast.h"
+
+
+#define MAX_THREADS 8  /* XXX probably temporary here */
+
+
+struct pipe_transfer;
+struct pipe_screen;
+struct lp_rasterizer;
+
+
+/**
+ * A tile's color and depth memory.
+ * We can choose whatever layout for the internal tile storage we prefer.
+ */
+struct lp_rast_tile
+{
+   uint8_t *color;
+
+   uint32_t *depth;
+};
+
+
+/**
+ * Per-thread rasterization state
+ */
+struct lp_rasterizer_task
+{
+   struct lp_rast_tile tile;   /** Tile color/z/stencil memory */
+
+   unsigned x, y;          /**< Pos of this tile in framebuffer, in pixels */
+
+   const struct lp_rast_state *current_state;
+
+   /** "back" pointer */
+   struct lp_rasterizer *rast;
+
+   /** "my" index */
+   unsigned thread_index;
+
+   pipe_semaphore work_ready;
+   pipe_semaphore work_done;
+};
+
+
+/**
+ * This is the state required while rasterizing tiles.
+ * Note that this contains per-thread information too.
+ * The tile size is TILE_SIZE x TILE_SIZE pixels.
+ */
+struct lp_rasterizer
+{
+   boolean clipped_tile;
+   boolean check_for_clipped_tiles;
+
+   /* Framebuffer stuff
+    */
+   struct pipe_screen *screen;
+   struct pipe_transfer *cbuf_transfer;
+   struct pipe_transfer *zsbuf_transfer;
+   void *cbuf_map;
+   void *zsbuf_map;
+
+   struct {
+      struct pipe_framebuffer_state fb;
+      boolean write_color;
+      boolean write_zstencil;
+      unsigned clear_color;
+      unsigned clear_depth;
+      char clear_stencil;
+   } state;
+
+   /** The incoming queue of scenes ready to rasterize */
+   struct lp_scene_queue *full_scenes;
+   /** The outgoing queue of processed scenes to return to setup modulee */
+   struct lp_scene_queue *empty_scenes;
+
+   /** The scene currently being rasterized by the threads */
+   struct lp_scene *curr_scene;
+
+   /** A task object for each rasterization thread */
+   struct lp_rasterizer_task tasks[MAX_THREADS];
+
+   unsigned num_threads;
+   pipe_thread threads[MAX_THREADS];
+
+   /** For synchronizing the rasterization threads */
+   pipe_barrier barrier;
+};
+
+
+void lp_rast_shade_quads( struct lp_rasterizer *rast,
+                          unsigned thread_index,
+                          const struct lp_rast_shader_inputs *inputs,
+                          unsigned x, unsigned y,
+                          int32_t c1, int32_t c2, int32_t c3);
+
+#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_rast_tri.c b/src/gallium/drivers/llvmpipe/lp_rast_tri.c
new file mode 100644 (file)
index 0000000..bc7397f
--- /dev/null
@@ -0,0 +1,253 @@
+/**************************************************************************
+ *
+ * Copyright 2007-2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 VMWARE 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.
+ *
+ **************************************************************************/
+
+/*
+ * Rasterization for binned triangles within a tile
+ */
+
+#include <limits.h>
+#include "util/u_math.h"
+#include "lp_debug.h"
+#include "lp_rast_priv.h"
+#include "lp_tile_soa.h"
+
+
+/**
+ * Map an index in [0,15] to an x,y position, multiplied by 4.
+ * This is used to get the position of each subtile in a 4x4
+ * grid of edge step values.
+ */
+static const int pos_table4[16][2] = {
+   { 0, 0 },
+   { 4, 0 },
+   { 0, 4 },
+   { 4, 4 },
+   { 8, 0 },
+   { 12, 0 },
+   { 8, 4 },
+   { 12, 4 },
+   { 0, 8 },
+   { 4, 8 },
+   { 0, 12 },
+   { 4, 12 },
+   { 8, 8 },
+   { 12, 8 },
+   { 8, 12 },
+   { 12, 12 }
+};
+
+
+static const int pos_table16[16][2] = {
+   { 0, 0 },
+   { 16, 0 },
+   { 0, 16 },
+   { 16, 16 },
+   { 32, 0 },
+   { 48, 0 },
+   { 32, 16 },
+   { 48, 16 },
+   { 0, 32 },
+   { 16, 32 },
+   { 0, 48 },
+   { 16, 48 },
+   { 32, 32 },
+   { 48, 32 },
+   { 32, 48 },
+   { 48, 48 }
+};
+
+
+/**
+ * Shade all pixels in a 4x4 block.
+ */
+static void
+block_full_4( struct lp_rasterizer_task *rast_task,
+              const struct lp_rast_triangle *tri,
+              int x, int y )
+{
+   /* Set c1,c2,c3 to large values so the in/out test always passes */
+   const int32_t c1 = INT_MIN, c2 = INT_MIN, c3 = INT_MIN;
+   lp_rast_shade_quads(rast_task->rast,
+                       rast_task->thread_index,
+                       &tri->inputs, 
+                       x, y,
+                       c1, c2, c3);
+}
+
+
+/**
+ * Shade all pixels in a 16x16 block.
+ */
+static void
+block_full_16( struct lp_rasterizer_task *rast_task,
+               const struct lp_rast_triangle *tri,
+               int x, int y )
+{
+   unsigned ix, iy;
+   assert(x % 16 == 0);
+   assert(y % 16 == 0);
+   for (iy = 0; iy < 16; iy += 4)
+      for (ix = 0; ix < 16; ix += 4)
+        block_full_4(rast_task, tri, x + ix, y + iy);
+}
+
+
+/**
+ * Pass the 4x4 pixel block to the shader function.
+ * Determination of which of the 16 pixels lies inside the triangle
+ * will be done as part of the fragment shader.
+ */
+static void
+do_block_4( struct lp_rasterizer_task *rast_task,
+           const struct lp_rast_triangle *tri,
+           int x, int y,
+           int c1,
+           int c2,
+           int c3 )
+{
+   lp_rast_shade_quads(rast_task->rast,
+                       rast_task->thread_index,
+                       &tri->inputs, 
+                       x, y,
+                       -c1, -c2, -c3);
+}
+
+
+/**
+ * Evaluate a 16x16 block of pixels to determine which 4x4 subblocks are in/out
+ * of the triangle's bounds.
+ */
+static void
+do_block_16( struct lp_rasterizer_task *rast_task,
+             const struct lp_rast_triangle *tri,
+             int x, int y,
+             int c1,
+             int c2,
+             int c3 )
+{
+   const int ei1 = tri->ei1 * 4;
+   const int ei2 = tri->ei2 * 4;
+   const int ei3 = tri->ei3 * 4;
+
+   const int eo1 = tri->eo1 * 4;
+   const int eo2 = tri->eo2 * 4;
+   const int eo3 = tri->eo3 * 4;
+
+   int i;
+
+   assert(x % 16 == 0);
+   assert(y % 16 == 0);
+
+   for (i = 0; i < 16; i++) {
+      int cx1 = c1 + (tri->inputs.step[0][i] * 4);
+      int cx2 = c2 + (tri->inputs.step[1][i] * 4);
+      int cx3 = c3 + (tri->inputs.step[2][i] * 4);
+
+      if (cx1 + eo1 < 0 ||
+          cx2 + eo2 < 0 ||
+          cx3 + eo3 < 0) {
+         /* the block is completely outside the triangle - nop */
+      }
+      else {
+         int px = x + pos_table4[i][0];
+         int py = y + pos_table4[i][1];
+         if (cx1 + ei1 > 0 &&
+             cx2 + ei2 > 0 &&
+             cx3 + ei3 > 0) {
+            /* the block is completely inside the triangle */
+            block_full_4(rast_task, tri, px, py);
+         }
+         else {
+            /* the block is partially in/out of the triangle */
+            do_block_4(rast_task, tri, px, py, cx1, cx2, cx3);
+         }
+      }
+   }
+}
+
+
+/**
+ * Scan the tile in chunks and figure out which pixels to rasterize
+ * for this triangle.
+ */
+void
+lp_rast_triangle( struct lp_rasterizer *rast,
+                  unsigned thread_index,
+                  const union lp_rast_cmd_arg arg )
+{
+   struct lp_rasterizer_task *rast_task = &rast->tasks[thread_index];
+   const struct lp_rast_triangle *tri = arg.triangle;
+
+   int x = rast_task->x;
+   int y = rast_task->y;
+   unsigned i;
+
+   int c1 = tri->c1 + tri->dx12 * y - tri->dy12 * x;
+   int c2 = tri->c2 + tri->dx23 * y - tri->dy23 * x;
+   int c3 = tri->c3 + tri->dx31 * y - tri->dy31 * x;
+
+   int ei1 = tri->ei1 * 16;
+   int ei2 = tri->ei2 * 16;
+   int ei3 = tri->ei3 * 16;
+
+   int eo1 = tri->eo1 * 16;
+   int eo2 = tri->eo2 * 16;
+   int eo3 = tri->eo3 * 16;
+
+   LP_DBG(DEBUG_RAST, "lp_rast_triangle\n");
+
+   /* Walk over the tile to build a list of 4x4 pixel blocks which will
+    * be filled/shaded.  We do this at two granularities: 16x16 blocks
+    * and then 4x4 blocks.
+    */
+   for (i = 0; i < 16; i++) {
+      int cx1 = c1 + (tri->inputs.step[0][i] * 16);
+      int cx2 = c2 + (tri->inputs.step[1][i] * 16);
+      int cx3 = c3 + (tri->inputs.step[2][i] * 16);
+
+      if (cx1 + eo1 < 0 ||
+          cx2 + eo2 < 0 ||
+          cx3 + eo3 < 0) {
+         /* the block is completely outside the triangle - nop */
+      }
+      else {
+         int px = x + pos_table16[i][0];
+         int py = y + pos_table16[i][1];
+
+         if (cx1 + ei1 > 0 &&
+             cx2 + ei2 > 0 &&
+             cx3 + ei3 > 0) {
+            /* the block is completely inside the triangle */
+            block_full_16(rast_task, tri, px, py);
+         }
+         else {
+            /* the block is partially in/out of the triangle */
+            do_block_16(rast_task, tri, px, py, cx1, cx2, cx3);
+         }
+      }
+   }
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_scene.c b/src/gallium/drivers/llvmpipe/lp_scene.c
new file mode 100644 (file)
index 0000000..774a1fe
--- /dev/null
@@ -0,0 +1,310 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 VMWARE 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 "util/u_math.h"
+#include "util/u_memory.h"
+#include "lp_scene.h"
+
+
+struct lp_scene *
+lp_scene_create(void)
+{
+   struct lp_scene *scene = CALLOC_STRUCT(lp_scene);
+   if (scene)
+      lp_scene_init(scene);
+   return scene;
+}
+
+
+void
+lp_scene_destroy(struct lp_scene *scene)
+{
+   lp_scene_reset(scene);
+   lp_scene_free_bin_data(scene);
+   FREE(scene);
+}
+
+
+void
+lp_scene_init(struct lp_scene *scene)
+{
+   unsigned i, j;
+   for (i = 0; i < TILES_X; i++)
+      for (j = 0; j < TILES_Y; j++) {
+         struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+         bin->commands.head = bin->commands.tail = CALLOC_STRUCT(cmd_block);
+      }
+
+   scene->data.head =
+      scene->data.tail = CALLOC_STRUCT(data_block);
+
+   pipe_mutex_init(scene->mutex);
+}
+
+
+/**
+ * Set scene to empty state.
+ */
+void
+lp_scene_reset(struct lp_scene *scene )
+{
+   unsigned i, j;
+
+   /* Free all but last binner command lists:
+    */
+   for (i = 0; i < scene->tiles_x; i++) {
+      for (j = 0; j < scene->tiles_y; j++) {
+         struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+         struct cmd_block_list *list = &bin->commands;
+         struct cmd_block *block;
+         struct cmd_block *tmp;
+         
+         for (block = list->head; block != list->tail; block = tmp) {
+            tmp = block->next;
+            FREE(block);
+         }
+         
+         assert(list->tail->next == NULL);
+         list->head = list->tail;
+         list->head->count = 0;
+      }
+   }
+
+   /* Free all but last binned data block:
+    */
+   {
+      struct data_block_list *list = &scene->data;
+      struct data_block *block, *tmp;
+
+      for (block = list->head; block != list->tail; block = tmp) {
+         tmp = block->next;
+         FREE(block);
+      }
+         
+      assert(list->tail->next == NULL);
+      list->head = list->tail;
+      list->head->used = 0;
+   }
+}
+
+
+/**
+ * Free all data associated with the given bin, but don't free(scene).
+ */
+void
+lp_scene_free_bin_data(struct lp_scene *scene)
+{
+   unsigned i, j;
+
+   for (i = 0; i < TILES_X; i++)
+      for (j = 0; j < TILES_Y; j++) {
+         struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+         /* lp_reset_scene() should have been already called */
+         assert(bin->commands.head == bin->commands.tail);
+         FREE(bin->commands.head);
+         bin->commands.head = NULL;
+         bin->commands.tail = NULL;
+      }
+
+   FREE(scene->data.head);
+   scene->data.head = NULL;
+
+   pipe_mutex_destroy(scene->mutex);
+}
+
+
+void
+lp_scene_set_framebuffer_size( struct lp_scene *scene,
+                             unsigned width, unsigned height )
+{
+   scene->tiles_x = align(width, TILE_SIZE) / TILE_SIZE;
+   scene->tiles_y = align(height, TILE_SIZE) / TILE_SIZE;
+}
+
+
+void
+lp_bin_new_cmd_block( struct cmd_block_list *list )
+{
+   struct cmd_block *block = MALLOC_STRUCT(cmd_block);
+   list->tail->next = block;
+   list->tail = block;
+   block->next = NULL;
+   block->count = 0;
+}
+
+
+void
+lp_bin_new_data_block( struct data_block_list *list )
+{
+   struct data_block *block = MALLOC_STRUCT(data_block);
+   list->tail->next = block;
+   list->tail = block;
+   block->next = NULL;
+   block->used = 0;
+}
+
+
+/** Return number of bytes used for all bin data within a scene */
+unsigned
+lp_scene_data_size( const struct lp_scene *scene )
+{
+   unsigned size = 0;
+   const struct data_block *block;
+   for (block = scene->data.head; block; block = block->next) {
+      size += block->used;
+   }
+   return size;
+}
+
+
+/** Return number of bytes used for a single bin */
+unsigned
+lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y )
+{
+   struct cmd_bin *bin = lp_scene_get_bin((struct lp_scene *) scene, x, y);
+   const struct cmd_block *cmd;
+   unsigned size = 0;
+   for (cmd = bin->commands.head; cmd; cmd = cmd->next) {
+      size += (cmd->count *
+               (sizeof(lp_rast_cmd) + sizeof(union lp_rast_cmd_arg)));
+   }
+   return size;
+}
+
+
+/**
+ * Return last command in the bin
+ */
+static lp_rast_cmd
+lp_get_last_command( const struct cmd_bin *bin )
+{
+   const struct cmd_block *tail = bin->commands.tail;
+   const unsigned i = tail->count;
+   if (i > 0)
+      return tail->cmd[i - 1];
+   else
+      return NULL;
+}
+
+
+/**
+ * Replace the arg of the last command in the bin.
+ */
+static void
+lp_replace_last_command_arg( struct cmd_bin *bin,
+                             const union lp_rast_cmd_arg arg )
+{
+   struct cmd_block *tail = bin->commands.tail;
+   const unsigned i = tail->count;
+   assert(i > 0);
+   tail->arg[i - 1] = arg;
+}
+
+
+
+/**
+ * Put a state-change command into all bins.
+ * If we find that the last command in a bin was also a state-change
+ * command, we can simply replace that one with the new one.
+ */
+void
+lp_scene_bin_state_command( struct lp_scene *scene,
+                      lp_rast_cmd cmd,
+                      const union lp_rast_cmd_arg arg )
+{
+   unsigned i, j;
+   for (i = 0; i < scene->tiles_x; i++) {
+      for (j = 0; j < scene->tiles_y; j++) {
+         struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+         lp_rast_cmd last_cmd = lp_get_last_command(bin);
+         if (last_cmd == cmd) {
+            lp_replace_last_command_arg(bin, arg);
+         }
+         else {
+            lp_scene_bin_command( scene, i, j, cmd, arg );
+         }
+      }
+   }
+}
+
+
+/** advance curr_x,y to the next bin */
+static boolean
+next_bin(struct lp_scene *scene)
+{
+   scene->curr_x++;
+   if (scene->curr_x >= scene->tiles_x) {
+      scene->curr_x = 0;
+      scene->curr_y++;
+   }
+   if (scene->curr_y >= scene->tiles_y) {
+      /* no more bins */
+      return FALSE;
+   }
+   return TRUE;
+}
+
+
+void
+lp_scene_bin_iter_begin( struct lp_scene *scene )
+{
+   scene->curr_x = scene->curr_y = -1;
+}
+
+
+/**
+ * Return point to next bin to be rendered.
+ * The lp_scene::curr_x and ::curr_y fields will be advanced.
+ * Multiple rendering threads will call this function to get a chunk
+ * of work (a bin) to work on.
+ */
+struct cmd_bin *
+lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y )
+{
+   struct cmd_bin *bin = NULL;
+
+   pipe_mutex_lock(scene->mutex);
+
+   if (scene->curr_x < 0) {
+      /* first bin */
+      scene->curr_x = 0;
+      scene->curr_y = 0;
+   }
+   else if (!next_bin(scene)) {
+      /* no more bins left */
+      goto end;
+   }
+
+   bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);
+   *bin_x = scene->curr_x;
+   *bin_y = scene->curr_y;
+
+end:
+   /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/
+   pipe_mutex_unlock(scene->mutex);
+   return bin;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_scene.h b/src/gallium/drivers/llvmpipe/lp_scene.h
new file mode 100644 (file)
index 0000000..796fc51
--- /dev/null
@@ -0,0 +1,276 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 VMWARE 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.
+ *
+ **************************************************************************/
+
+
+/**
+ * Binner data structures and bin-related functions.
+ * Note: the "setup" code is concerned with building scenes while
+ * The "rast" code is concerned with consuming/executing scenes.
+ */
+
+#ifndef LP_SCENE_H
+#define LP_SCENE_H
+
+#include "pipe/p_thread.h"
+#include "lp_tile_soa.h"
+#include "lp_rast.h"
+
+
+/* We're limited to 2K by 2K for 32bit fixed point rasterization.
+ * Will need a 64-bit version for larger framebuffers.
+ */
+#define MAXHEIGHT 2048
+#define MAXWIDTH 2048
+#define TILES_X (MAXWIDTH / TILE_SIZE)
+#define TILES_Y (MAXHEIGHT / TILE_SIZE)
+
+
+#define CMD_BLOCK_MAX 128
+#define DATA_BLOCK_SIZE (16 * 1024 - sizeof(unsigned) - sizeof(void *))
+   
+
+
+/* switch to a non-pointer value for this:
+ */
+typedef void (*lp_rast_cmd)( struct lp_rasterizer *,
+                             unsigned thread_index,
+                             const union lp_rast_cmd_arg );
+
+struct cmd_block {
+   lp_rast_cmd cmd[CMD_BLOCK_MAX];
+   union lp_rast_cmd_arg arg[CMD_BLOCK_MAX];
+   unsigned count;
+   struct cmd_block *next;
+};
+
+struct data_block {
+   ubyte data[DATA_BLOCK_SIZE];
+   unsigned used;
+   struct data_block *next;
+};
+
+struct cmd_block_list {
+   struct cmd_block *head;
+   struct cmd_block *tail;
+};
+
+/**
+ * For each screen tile we have one of these bins.
+ */
+struct cmd_bin {
+   struct cmd_block_list commands;
+};
+   
+
+/**
+ * This stores bulk data which is shared by all bins within a scene.
+ * Examples include triangle data and state data.  The commands in
+ * the per-tile bins will point to chunks of data in this structure.
+ */
+struct data_block_list {
+   struct data_block *head;
+   struct data_block *tail;
+};
+
+
+/**
+ * All bins and bin data are contained here.
+ * Per-bin data goes into the 'tile' bins.
+ * Shared data goes into the 'data' buffer.
+ *
+ * When there are multiple threads, will want to double-buffer between
+ * scenes:
+ */
+struct lp_scene {
+   struct cmd_bin tile[TILES_X][TILES_Y];
+   struct data_block_list data;
+
+   /** the framebuffer to render the scene into */
+   struct pipe_framebuffer_state fb;
+
+   boolean write_depth;
+
+   /**
+    * Number of active tiles in each dimension.
+    * This basically the framebuffer size divided by tile size
+    */
+   unsigned tiles_x, tiles_y;
+
+   int curr_x, curr_y;  /**< for iterating over bins */
+   pipe_mutex mutex;
+};
+
+
+
+struct lp_scene *lp_scene_create(void);
+
+void lp_scene_destroy(struct lp_scene *scene);
+
+
+void lp_scene_init(struct lp_scene *scene);
+
+void lp_scene_reset(struct lp_scene *scene );
+
+void lp_scene_free_bin_data(struct lp_scene *scene);
+
+void lp_scene_set_framebuffer_size( struct lp_scene *scene,
+                                  unsigned width, unsigned height );
+
+void lp_bin_new_data_block( struct data_block_list *list );
+
+void lp_bin_new_cmd_block( struct cmd_block_list *list );
+
+unsigned lp_scene_data_size( const struct lp_scene *scene );
+
+unsigned lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y );
+
+
+/**
+ * Allocate space for a command/data in the bin's data buffer.
+ * Grow the block list if needed.
+ */
+static INLINE void *
+lp_scene_alloc( struct lp_scene *scene, unsigned size)
+{
+   struct data_block_list *list = &scene->data;
+
+   if (list->tail->used + size > DATA_BLOCK_SIZE) {
+      lp_bin_new_data_block( list );
+   }
+
+   {
+      struct data_block *tail = list->tail;
+      ubyte *data = tail->data + tail->used;
+      tail->used += size;
+      return data;
+   }
+}
+
+
+/**
+ * As above, but with specific alignment.
+ */
+static INLINE void *
+lp_scene_alloc_aligned( struct lp_scene *scene, unsigned size,
+                       unsigned alignment )
+{
+   struct data_block_list *list = &scene->data;
+
+   if (list->tail->used + size + alignment - 1 > DATA_BLOCK_SIZE) {
+      lp_bin_new_data_block( list );
+   }
+
+   {
+      struct data_block *tail = list->tail;
+      ubyte *data = tail->data + tail->used;
+      unsigned offset = (((uintptr_t)data + alignment - 1) & ~(alignment - 1)) - (uintptr_t)data;
+      tail->used += offset + size;
+      return data + offset;
+   }
+}
+
+
+/* Put back data if we decide not to use it, eg. culled triangles.
+ */
+static INLINE void
+lp_scene_putback_data( struct lp_scene *scene, unsigned size)
+{
+   struct data_block_list *list = &scene->data;
+   assert(list->tail->used >= size);
+   list->tail->used -= size;
+}
+
+
+/** Return pointer to a particular tile's bin. */
+static INLINE struct cmd_bin *
+lp_scene_get_bin(struct lp_scene *scene, unsigned x, unsigned y)
+{
+   return &scene->tile[x][y];
+}
+
+
+
+/* Add a command to bin[x][y].
+ */
+static INLINE void
+lp_scene_bin_command( struct lp_scene *scene,
+                unsigned x, unsigned y,
+                lp_rast_cmd cmd,
+                union lp_rast_cmd_arg arg )
+{
+   struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
+   struct cmd_block_list *list = &bin->commands;
+
+   if (list->tail->count == CMD_BLOCK_MAX) {
+      lp_bin_new_cmd_block( list );
+   }
+
+   {
+      struct cmd_block *tail = list->tail;
+      unsigned i = tail->count;
+      tail->cmd[i] = cmd;
+      tail->arg[i] = arg;
+      tail->count++;
+   }
+}
+
+
+/* Add a command to all active bins.
+ */
+static INLINE void
+lp_scene_bin_everywhere( struct lp_scene *scene,
+                        lp_rast_cmd cmd,
+                        const union lp_rast_cmd_arg arg )
+{
+   unsigned i, j;
+   for (i = 0; i < scene->tiles_x; i++)
+      for (j = 0; j < scene->tiles_y; j++)
+         lp_scene_bin_command( scene, i, j, cmd, arg );
+}
+
+
+void
+lp_scene_bin_state_command( struct lp_scene *scene,
+                           lp_rast_cmd cmd,
+                           const union lp_rast_cmd_arg arg );
+
+
+static INLINE unsigned
+lp_scene_get_num_bins( const struct lp_scene *scene )
+{
+   return scene->tiles_x * scene->tiles_y;
+}
+
+
+void
+lp_scene_bin_iter_begin( struct lp_scene *scene );
+
+struct cmd_bin *
+lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y );
+
+
+#endif /* LP_BIN_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_scene_queue.c b/src/gallium/drivers/llvmpipe/lp_scene_queue.c
new file mode 100644 (file)
index 0000000..8d65a6a
--- /dev/null
@@ -0,0 +1,164 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 VMWARE 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.
+ *
+ **************************************************************************/
+
+
+/**
+ * Scene queue.  We'll use two queues.  One contains "full" scenes which
+ * are produced by the "setup" code.  The other contains "empty" scenes
+ * which are produced by the "rast" code when it finishes rendering a scene.
+ */
+
+
+#include "pipe/p_thread.h"
+#include "util/u_memory.h"
+#include "lp_scene_queue.h"
+
+
+
+#define MAX_SCENE_QUEUE 4
+
+
+/**
+ * A queue of scenes
+ */
+struct lp_scene_queue
+{
+   /** XXX might use a linked list here somedone, but the list will
+    * probably always be pretty short.
+    */
+   struct lp_scene *scenes[MAX_SCENE_QUEUE];
+   unsigned count;
+
+   pipe_condvar count_change;
+   pipe_mutex mutex;
+};
+
+
+
+/** Allocate a new scene queue */
+struct lp_scene_queue *
+lp_scene_queue_create(void)
+{
+   struct lp_scene_queue *queue = CALLOC_STRUCT(lp_scene_queue);
+   if (queue) {
+      pipe_condvar_init(queue->count_change);
+      pipe_mutex_init(queue->mutex);
+   }
+   return queue;
+}
+
+
+/** Delete a scene queue */
+void
+lp_scene_queue_destroy(struct lp_scene_queue *queue)
+{
+   pipe_condvar_destroy(queue->count_change);
+   pipe_mutex_destroy(queue->mutex);
+}
+
+
+/** Remove first lp_scene from head of queue */
+struct lp_scene *
+lp_scene_dequeue(struct lp_scene_queue *queue)
+{
+   struct lp_scene *scene;
+   unsigned i;
+
+   pipe_mutex_lock(queue->mutex);
+   while (queue->count == 0) {
+      pipe_condvar_wait(queue->count_change, queue->mutex);
+   }
+
+   assert(queue->count >= 1);
+
+   /* get head */
+   scene = queue->scenes[0];
+
+   /* shift entries */
+   for (i = 0; i < queue->count - 1; i++) {
+      queue->scenes[i] = queue->scenes[i + 1];
+   }
+
+   queue->count--;
+
+   /* signal size change */
+   pipe_condvar_signal(queue->count_change);
+
+   pipe_mutex_unlock(queue->mutex);
+
+   return scene;
+}
+
+
+/** Add an lp_scene to tail of queue */
+void
+lp_scene_enqueue(struct lp_scene_queue *queue, struct lp_scene *scene)
+{
+   pipe_mutex_lock(queue->mutex);
+
+   assert(queue->count < MAX_SCENE_QUEUE);
+
+   /* debug: check that scene is not already in the queue */
+   if (0) {
+      unsigned i;
+      for (i = 0; i < queue->count; i++) {
+         assert(queue->scenes[i] != scene);
+      }
+   }
+
+   /* add to end */
+   queue->scenes[queue->count++] = scene;
+
+   /* signal size change */
+   pipe_condvar_signal(queue->count_change);
+
+   pipe_mutex_unlock(queue->mutex);
+}
+
+
+/** Return number of entries in the queue */
+unsigned
+lp_scene_queue_count(struct lp_scene_queue *queue)
+{
+   unsigned count;
+   pipe_mutex_lock(queue->mutex);
+   count = queue->count;
+   pipe_mutex_unlock(queue->mutex);
+   return count;
+}
+
+
+/** Wait until the queue has exactly 'count' entries */
+void
+lp_scene_queue_wait_count(struct lp_scene_queue *queue, unsigned count)
+{
+   pipe_mutex_lock(queue->mutex);
+   while (queue->count != count) {
+      pipe_condvar_wait(queue->count_change, queue->mutex);
+   }
+   pipe_mutex_unlock(queue->mutex);
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_scene_queue.h b/src/gallium/drivers/llvmpipe/lp_scene_queue.h
new file mode 100644 (file)
index 0000000..1bd475f
--- /dev/null
@@ -0,0 +1,55 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 VMWARE 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 LP_SCENE_QUEUE
+#define LP_SCENE_QUEUE
+
+struct lp_scene_queue;
+struct lp_scene;
+
+
+struct lp_scene_queue *
+lp_scene_queue_create(void);
+
+void
+lp_scene_queue_destroy(struct lp_scene_queue *queue);
+
+struct lp_scene *
+lp_scene_dequeue(struct lp_scene_queue *queue);
+
+void
+lp_scene_enqueue(struct lp_scene_queue *queue, struct lp_scene *bins);
+
+unsigned
+lp_scene_queue_count(struct lp_scene_queue *queue);
+
+void
+lp_scene_queue_wait_count(struct lp_scene_queue *queue, unsigned size);
+
+
+#endif /* LP_BIN_QUEUE */
index 9b47415f003350c7592894fb6338f50c7943e2b6..a28f6935b68fac8e3817a4c71ffc3b384860d10d 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "lp_texture.h"
 #include "lp_buffer.h"
+#include "lp_fence.h"
 #include "lp_winsys.h"
 #include "lp_jit.h"
 #include "lp_screen.h"
@@ -299,6 +300,7 @@ llvmpipe_create_screen(struct llvmpipe_winsys *winsys)
 
    llvmpipe_init_screen_texture_funcs(&screen->base);
    llvmpipe_init_screen_buffer_funcs(&screen->base);
+   llvmpipe_init_screen_fence_funcs(&screen->base);
 
    lp_jit_screen_init(screen);
 
index b18f17c0cd34a2ef76f1b01e360d0f58b9d612d3..5cdcf4ecc985f0521ddcc9836aa8bc436ee5b5be 100644 (file)
  **************************************************************************/
 
 /**
- * \brief  Primitive rasterization/rendering (points, lines, triangles)
+ * Tiling engine.
  *
- * \author  Keith Whitwell <keith@tungstengraphics.com>
- * \author  Brian Paul
+ * Builds per-tile display lists and executes them on calls to
+ * lp_setup_flush().
  */
 
-#include "lp_context.h"
-#include "lp_quad.h"
-#include "lp_setup.h"
-#include "lp_state.h"
-#include "draw/draw_context.h"
-#include "draw/draw_private.h"
-#include "draw/draw_vertex.h"
-#include "pipe/p_shader_tokens.h"
-#include "pipe/p_thread.h"
-#include "util/u_format.h"
-#include "util/u_math.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_inlines.h"
 #include "util/u_memory.h"
-#include "lp_bld_debug.h"
-#include "lp_tile_cache.h"
-#include "lp_tile_soa.h"
-
-
-#define DEBUG_VERTS 0
-#define DEBUG_FRAGS 0
-
-/**
- * Triangle edge info
- */
-struct edge {
-   float dx;           /**< X(v1) - X(v0), used only during setup */
-   float dy;           /**< Y(v1) - Y(v0), used only during setup */
-   float dxdy;         /**< dx/dy */
-   float sx, sy;       /**< first sample point coord */
-   int lines;          /**< number of lines on this edge */
-};
-
-
-#define MAX_QUADS 16
-
-
-/**
- * Triangle setup info (derived from draw_stage).
- * Also used for line drawing (taking some liberties).
- */
-struct setup_context {
-   struct llvmpipe_context *llvmpipe;
-
-   /* Vertices are just an array of floats making up each attribute in
-    * turn.  Currently fixed at 4 floats, but should change in time.
-    * Codegen will help cope with this.
-    */
-   const float (*vmax)[4];
-   const float (*vmid)[4];
-   const float (*vmin)[4];
-   const float (*vprovoke)[4];
-
-   struct edge ebot;
-   struct edge etop;
-   struct edge emaj;
-
-   float oneoverarea;
-   int facing;
-
-   float pixel_offset;
-
-   struct quad_header quad[MAX_QUADS];
-   struct quad_header *quad_ptrs[MAX_QUADS];
-   unsigned count;
+#include "util/u_pack_color.h"
+#include "util/u_surface.h"
+#include "lp_scene.h"
+#include "lp_scene_queue.h"
+#include "lp_buffer.h"
+#include "lp_texture.h"
+#include "lp_debug.h"
+#include "lp_fence.h"
+#include "lp_rast.h"
+#include "lp_setup_context.h"
 
-   struct quad_interp_coef coef;
+#include "draw/draw_context.h"
+#include "draw/draw_vbuf.h"
 
-   struct {
-      int left[2];   /**< [0] = row0, [1] = row1 */
-      int right[2];
-      int y;
-   } span;
 
-#if DEBUG_FRAGS
-   uint numFragsEmitted;  /**< per primitive */
-   uint numFragsWritten;  /**< per primitive */
-#endif
+/** XXX temporary value, temporary here */
+#define MAX_SCENES 2
 
-   unsigned winding;           /* which winding to cull */
-};
 
+static void set_scene_state( struct setup_context *, unsigned );
 
 
-/**
- * Execute fragment shader for the four fragments in the quad.
- */
-ALIGN_STACK
-static void
-shade_quads(struct llvmpipe_context *llvmpipe,
-            struct quad_header *quads[],
-            unsigned nr)
+struct lp_scene *
+lp_setup_get_current_scene(struct setup_context *setup)
 {
-   struct lp_fragment_shader *fs = llvmpipe->fs;
-   struct quad_header *quad = quads[0];
-   const unsigned x = quad->input.x0;
-   const unsigned y = quad->input.y0;
-   uint8_t *tile;
-   uint8_t *color;
-   void *depth;
-   uint32_t ALIGN16_ATTRIB mask[4][NUM_CHANNELS];
-   unsigned chan_index;
-   unsigned q;
-
-   assert(fs->current);
-   if(!fs->current)
-      return;
+   if (!setup->scene) {
+      /* wait for a free/empty bin */
+      setup->scene = lp_scene_dequeue(setup->empty_scenes);
+      if(0)lp_scene_reset( setup->scene ); /* XXX temporary? */
 
-   /* Sanity checks */
-   assert(nr * QUAD_SIZE == TILE_VECTOR_HEIGHT * TILE_VECTOR_WIDTH);
-   assert(x % TILE_VECTOR_WIDTH == 0);
-   assert(y % TILE_VECTOR_HEIGHT == 0);
-   for (q = 0; q < nr; ++q) {
-      assert(quads[q]->input.x0 == x + q*2);
-      assert(quads[q]->input.y0 == y);
-   }
-
-   /* mask */
-   for (q = 0; q < 4; ++q)
-      for (chan_index = 0; chan_index < NUM_CHANNELS; ++chan_index)
-         mask[q][chan_index] = quads[q]->inout.mask & (1 << chan_index) ? ~0 : 0;
-
-   /* color buffer */
-   if(llvmpipe->framebuffer.nr_cbufs >= 1 &&
-      llvmpipe->framebuffer.cbufs[0]) {
-      tile = lp_get_cached_tile(llvmpipe->cbuf_cache[0], x, y);
-      color = &TILE_PIXEL(tile, x & (TILE_SIZE-1), y & (TILE_SIZE-1), 0);
-   }
-   else
-      color = NULL;
-
-   /* depth buffer */
-   if(llvmpipe->zsbuf_map) {
-      assert((x % 2) == 0);
-      assert((y % 2) == 0);
-      depth = llvmpipe->zsbuf_map +
-              y*llvmpipe->zsbuf_transfer->stride +
-              2*x*util_format_get_blocksize(llvmpipe->zsbuf_transfer->texture->format);
+      lp_scene_set_framebuffer_size(setup->scene,
+                                    setup->fb.width, 
+                                    setup->fb.height);
    }
-   else
-      depth = NULL;
-
-   /* XXX: This will most likely fail on 32bit x86 without -mstackrealign */
-   assert(lp_check_alignment(mask, 16));
-
-   assert(lp_check_alignment(depth, 16));
-   assert(lp_check_alignment(color, 16));
-   assert(lp_check_alignment(llvmpipe->jit_context.blend_color, 16));
-
-   /* run shader */
-   fs->current->jit_function( &llvmpipe->jit_context,
-                              x, y,
-                              quad->coef->a0,
-                              quad->coef->dadx,
-                              quad->coef->dady,
-                              &mask[0][0],
-                              color,
-                              depth);
+   return setup->scene;
 }
 
 
-
-
-/**
- * Do triangle cull test using tri determinant (sign indicates orientation)
- * \return true if triangle is to be culled.
- */
-static INLINE boolean
-cull_tri(const struct setup_context *setup, float det)
+static void
+first_triangle( struct setup_context *setup,
+                const float (*v0)[4],
+                const float (*v1)[4],
+                const float (*v2)[4])
 {
-   if (det != 0) {   
-      /* if (det < 0 then Z points toward camera and triangle is 
-       * counter-clockwise winding.
-       */
-      unsigned winding = (det < 0) ? PIPE_WINDING_CCW : PIPE_WINDING_CW;
-
-      if ((winding & setup->winding) == 0)
-        return FALSE;
-   }
-
-   /* Culled:
-    */
-   return TRUE;
+   set_scene_state( setup, SETUP_ACTIVE );
+   lp_setup_choose_triangle( setup );
+   setup->triangle( setup, v0, v1, v2 );
 }
 
-
-
-/**
- * Clip setup->quad against the scissor/surface bounds.
- */
-static INLINE void
-quad_clip( struct setup_context *setup, struct quad_header *quad )
+static void
+first_line( struct setup_context *setup,
+           const float (*v0)[4],
+           const float (*v1)[4])
 {
-   const struct pipe_scissor_state *cliprect = &setup->llvmpipe->cliprect;
-   const int minx = (int) cliprect->minx;
-   const int maxx = (int) cliprect->maxx;
-   const int miny = (int) cliprect->miny;
-   const int maxy = (int) cliprect->maxy;
-
-   if (quad->input.x0 >= maxx ||
-       quad->input.y0 >= maxy ||
-       quad->input.x0 + 1 < minx ||
-       quad->input.y0 + 1 < miny) {
-      /* totally clipped */
-      quad->inout.mask = 0x0;
-      return;
-   }
-   if (quad->input.x0 < minx)
-      quad->inout.mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
-   if (quad->input.y0 < miny)
-      quad->inout.mask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
-   if (quad->input.x0 == maxx - 1)
-      quad->inout.mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
-   if (quad->input.y0 == maxy - 1)
-      quad->inout.mask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT);
+   set_scene_state( setup, SETUP_ACTIVE );
+   lp_setup_choose_line( setup );
+   setup->line( setup, v0, v1 );
 }
 
-
-
-/**
- * Given an X or Y coordinate, return the block/quad coordinate that it
- * belongs to.
- */
-static INLINE int block( int x )
+static void
+first_point( struct setup_context *setup,
+            const float (*v0)[4])
 {
-   return x & ~(2-1);
+   set_scene_state( setup, SETUP_ACTIVE );
+   lp_setup_choose_point( setup );
+   setup->point( setup, v0 );
 }
 
-static INLINE int block_x( int x )
+static void reset_context( struct setup_context *setup )
 {
-   return x & ~(TILE_VECTOR_WIDTH - 1);
-}
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
+   /* Reset derived state */
+   setup->constants.stored_size = 0;
+   setup->constants.stored_data = NULL;
+   setup->fs.stored = NULL;
+   setup->dirty = ~0;
 
-/**
- * Emit a quad (pass to next stage) with clipping.
- */
-static INLINE void
-clip_emit_quad( struct setup_context *setup, struct quad_header *quad )
-{
-   quad_clip( setup, quad );
-
-   if (quad->inout.mask) {
-      struct llvmpipe_context *lp = setup->llvmpipe;
-
-#if 1
-      /* XXX: The blender expects 4 quads. This is far from efficient, but
-       * until we codegenerate single-quad variants of the fragment pipeline
-       * we need this hack. */
-      const unsigned nr_quads = TILE_VECTOR_HEIGHT*TILE_VECTOR_WIDTH/QUAD_SIZE;
-      struct quad_header quads[4];
-      struct quad_header *quad_ptrs[4];
-      int x0 = block_x(quad->input.x0);
-      unsigned i;
-
-      assert(nr_quads == 4);
-
-      for(i = 0; i < nr_quads; ++i) {
-         int x = x0 + 2*i;
-         if(x == quad->input.x0)
-            memcpy(&quads[i], quad, sizeof quads[i]);
-         else {
-            memset(&quads[i], 0, sizeof quads[i]);
-            quads[i].input.x0 = x;
-            quads[i].input.y0 = quad->input.y0;
-            quads[i].coef = quad->coef;
-         }
-         quad_ptrs[i] = &quads[i];
-      }
+   /* no current bin */
+   setup->scene = NULL;
 
-      shade_quads( lp, quad_ptrs, nr_quads );
-#else
-      shade_quads( lp, &quad, 1 );
-#endif
-   }
+   /* Reset some state:
+    */
+   setup->clear.flags = 0;
+
+   /* Have an explicit "start-binning" call and get rid of this
+    * pointer twiddling?
+    */
+   setup->line = first_line;
+   setup->point = first_point;
+   setup->triangle = first_triangle;
 }
 
 
-/**
- * Render a horizontal span of quads
- */
-static void flush_spans( struct setup_context *setup )
+/** Rasterize all scene's bins */
+static void
+lp_setup_rasterize_scene( struct setup_context *setup,
+                        boolean write_depth )
 {
-   const int step = TILE_VECTOR_WIDTH;
-   const int xleft0 = setup->span.left[0];
-   const int xleft1 = setup->span.left[1];
-   const int xright0 = setup->span.right[0];
-   const int xright1 = setup->span.right[1];
-
-
-   int minleft = block_x(MIN2(xleft0, xleft1));
-   int maxright = MAX2(xright0, xright1);
-   int x;
-
-   for (x = minleft; x < maxright; x += step) {
-      unsigned skip_left0 = CLAMP(xleft0 - x, 0, step);
-      unsigned skip_left1 = CLAMP(xleft1 - x, 0, step);
-      unsigned skip_right0 = CLAMP(x + step - xright0, 0, step);
-      unsigned skip_right1 = CLAMP(x + step - xright1, 0, step);
-      unsigned lx = x;
-      const unsigned nr_quads = TILE_VECTOR_HEIGHT*TILE_VECTOR_WIDTH/QUAD_SIZE;
-      unsigned q = 0;
-
-      unsigned skipmask_left0 = (1U << skip_left0) - 1U;
-      unsigned skipmask_left1 = (1U << skip_left1) - 1U;
-
-      /* These calculations fail when step == 32 and skip_right == 0.
-       */
-      unsigned skipmask_right0 = ~0U << (unsigned)(step - skip_right0);
-      unsigned skipmask_right1 = ~0U << (unsigned)(step - skip_right1);
-
-      unsigned mask0 = ~skipmask_left0 & ~skipmask_right0;
-      unsigned mask1 = ~skipmask_left1 & ~skipmask_right1;
-
-      if (mask0 | mask1) {
-         for(q = 0; q < nr_quads; ++q) {
-            unsigned quadmask = (mask0 & 3) | ((mask1 & 3) << 2);
-            setup->quad[q].input.x0 = lx;
-            setup->quad[q].input.y0 = setup->span.y;
-            setup->quad[q].inout.mask = quadmask;
-            setup->quad_ptrs[q] = &setup->quad[q];
-            mask0 >>= 2;
-            mask1 >>= 2;
-            lx += 2;
-         }
-         assert(!(mask0 | mask1));
+   struct lp_scene *scene = lp_setup_get_current_scene(setup);
 
-         shade_quads(setup->llvmpipe, setup->quad_ptrs, nr_quads );
-      }
-   }
+   lp_rasterize_scene(setup->rast,
+                      scene,
+                      &setup->fb,
+                      write_depth);
 
+   reset_context( setup );
 
-   setup->span.y = 0;
-   setup->span.right[0] = 0;
-   setup->span.right[1] = 0;
-   setup->span.left[0] = 1000000;     /* greater than right[0] */
-   setup->span.left[1] = 1000000;     /* greater than right[1] */
+   LP_DBG(DEBUG_SETUP, "%s done \n", __FUNCTION__);
 }
 
 
-#if DEBUG_VERTS
-static void print_vertex(const struct setup_context *setup,
-                         const float (*v)[4])
-{
-   int i;
-   debug_printf("   Vertex: (%p)\n", v);
-   for (i = 0; i < setup->quad[0].nr_attrs; i++) {
-      debug_printf("     %d: %f %f %f %f\n",  i,
-              v[i][0], v[i][1], v[i][2], v[i][3]);
-      if (util_is_inf_or_nan(v[i][0])) {
-         debug_printf("   NaN!\n");
-      }
-   }
-}
-#endif
 
-/**
- * Sort the vertices from top to bottom order, setting up the triangle
- * edge fields (ebot, emaj, etop).
- * \return FALSE if coords are inf/nan (cull the tri), TRUE otherwise
- */
-static boolean setup_sort_vertices( struct setup_context *setup,
-                                    float det,
-                                    const float (*v0)[4],
-                                    const float (*v1)[4],
-                                    const float (*v2)[4] )
+static void
+begin_binning( struct setup_context *setup )
 {
-   setup->vprovoke = v2;
-
-   /* determine bottom to top order of vertices */
-   {
-      float y0 = v0[0][1];
-      float y1 = v1[0][1];
-      float y2 = v2[0][1];
-      if (y0 <= y1) {
-        if (y1 <= y2) {
-           /* y0<=y1<=y2 */
-           setup->vmin = v0;
-           setup->vmid = v1;
-           setup->vmax = v2;
-        }
-        else if (y2 <= y0) {
-           /* y2<=y0<=y1 */
-           setup->vmin = v2;
-           setup->vmid = v0;
-           setup->vmax = v1;
-        }
-        else {
-           /* y0<=y2<=y1 */
-           setup->vmin = v0;
-           setup->vmid = v2;
-           setup->vmax = v1;
-        }
-      }
-      else {
-        if (y0 <= y2) {
-           /* y1<=y0<=y2 */
-           setup->vmin = v1;
-           setup->vmid = v0;
-           setup->vmax = v2;
-        }
-        else if (y2 <= y1) {
-           /* y2<=y1<=y0 */
-           setup->vmin = v2;
-           setup->vmid = v1;
-           setup->vmax = v0;
-        }
-        else {
-           /* y1<=y2<=y0 */
-           setup->vmin = v1;
-           setup->vmid = v2;
-           setup->vmax = v0;
-        }
-      }
-   }
-
-   setup->ebot.dx = setup->vmid[0][0] - setup->vmin[0][0];
-   setup->ebot.dy = setup->vmid[0][1] - setup->vmin[0][1];
-   setup->emaj.dx = setup->vmax[0][0] - setup->vmin[0][0];
-   setup->emaj.dy = setup->vmax[0][1] - setup->vmin[0][1];
-   setup->etop.dx = setup->vmax[0][0] - setup->vmid[0][0];
-   setup->etop.dy = setup->vmax[0][1] - setup->vmid[0][1];
-
-   /*
-    * Compute triangle's area.  Use 1/area to compute partial
-    * derivatives of attributes later.
-    *
-    * The area will be the same as prim->det, but the sign may be
-    * different depending on how the vertices get sorted above.
-    *
-    * To determine whether the primitive is front or back facing we
-    * use the prim->det value because its sign is correct.
-    */
-   {
-      const float area = (setup->emaj.dx * setup->ebot.dy -
-                           setup->ebot.dx * setup->emaj.dy);
-
-      setup->oneoverarea = 1.0f / area;
-
-      /*
-      debug_printf("%s one-over-area %f  area %f  det %f\n",
-                   __FUNCTION__, setup->oneoverarea, area, det );
-      */
-      if (util_is_inf_or_nan(setup->oneoverarea))
-         return FALSE;
-   }
+   struct lp_scene *scene = lp_setup_get_current_scene(setup);
 
-   /* We need to know if this is a front or back-facing triangle for:
-    *  - the GLSL gl_FrontFacing fragment attribute (bool)
-    *  - two-sided stencil test
-    */
-   setup->facing = 
-      ((det > 0.0) ^ 
-       (setup->llvmpipe->rasterizer->front_winding == PIPE_WINDING_CW));
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-   /* Prepare pixel offset for rasterisation:
-    *  - pixel center (0.5, 0.5) for GL, or
-    *  - assume (0.0, 0.0) for other APIs.
-    */
-   if (setup->llvmpipe->rasterizer->gl_rasterization_rules) {
-      setup->pixel_offset = 0.5f;
-   } else {
-      setup->pixel_offset = 0.0f;
+   if (setup->fb.cbufs[0]) {
+      if (setup->clear.flags & PIPE_CLEAR_COLOR)
+         lp_scene_bin_everywhere( scene, 
+                            lp_rast_clear_color, 
+                            setup->clear.color );
+      else
+         lp_scene_bin_everywhere( scene,
+                            lp_rast_load_color,
+                            lp_rast_arg_null() );
    }
 
-   return TRUE;
-}
-
+   if (setup->fb.zsbuf) {
+      if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL)
+         lp_scene_bin_everywhere( scene, 
+                            lp_rast_clear_zstencil, 
+                            setup->clear.zstencil );
+      else
+         lp_scene_bin_everywhere( scene,
+                            lp_rast_load_zstencil,
+                            lp_rast_arg_null() );
+   }
 
-/**
- * Compute a0, dadx and dady for a linearly interpolated coefficient,
- * for a triangle.
- */
-static void tri_pos_coeff( struct setup_context *setup,
-                           uint vertSlot, unsigned i)
-{
-   float botda = setup->vmid[vertSlot][i] - setup->vmin[vertSlot][i];
-   float majda = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
-   float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
-   float b = setup->emaj.dx * botda - majda * setup->ebot.dx;
-   float dadx = a * setup->oneoverarea;
-   float dady = b * setup->oneoverarea;
-
-   assert(i <= 3);
-
-   setup->coef.dadx[0][i] = dadx;
-   setup->coef.dady[0][i] = dady;
-
-   /* calculate a0 as the value which would be sampled for the
-    * fragment at (0,0), taking into account that we want to sample at
-    * pixel centers, in other words (pixel_offset, pixel_offset).
-    *
-    * this is neat but unfortunately not a good way to do things for
-    * triangles with very large values of dadx or dady as it will
-    * result in the subtraction and re-addition from a0 of a very
-    * large number, which means we'll end up loosing a lot of the
-    * fractional bits and precision from a0.  the way to fix this is
-    * to define a0 as the sample at a pixel center somewhere near vmin
-    * instead - i'll switch to this later.
-    */
-   setup->coef.a0[0][i] = (setup->vmin[vertSlot][i] -
-                           (dadx * (setup->vmin[0][0] - setup->pixel_offset) +
-                            dady * (setup->vmin[0][1] - setup->pixel_offset)));
-
-   /*
-   debug_printf("attr[%d].%c: %f dx:%f dy:%f\n",
-                slot, "xyzw"[i],
-                setup->coef[slot].a0[i],
-                setup->coef[slot].dadx[i],
-                setup->coef[slot].dady[i]);
-   */
+   LP_DBG(DEBUG_SETUP, "%s done\n", __FUNCTION__);
 }
 
 
-/**
- * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
- * The value value comes from vertex[slot][i].
- * The result will be put into setup->coef[slot].a0[i].
- * \param slot  which attribute slot
- * \param i  which component of the slot (0..3)
+/* This basically bins and then flushes any outstanding full-screen
+ * clears.  
+ *
+ * TODO: fast path for fullscreen clears and no triangles.
  */
-static void const_pos_coeff( struct setup_context *setup,
-                             uint vertSlot, unsigned i)
+static void
+execute_clears( struct setup_context *setup )
 {
-   setup->coef.dadx[0][i] = 0;
-   setup->coef.dady[0][i] = 0;
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-   /* need provoking vertex info!
-    */
-   setup->coef.a0[0][i] = setup->vprovoke[vertSlot][i];
+   begin_binning( setup );
+   lp_setup_rasterize_scene( setup, TRUE );
 }
 
 
-/**
- * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
- * The value value comes from vertex[slot][i].
- * The result will be put into setup->coef[slot].a0[i].
- * \param slot  which attribute slot
- * \param i  which component of the slot (0..3)
- */
-static void const_coeff( struct setup_context *setup,
-                         unsigned attrib,
-                         uint vertSlot)
+static void
+set_scene_state( struct setup_context *setup,
+           unsigned new_state )
 {
-   unsigned i;
-   for (i = 0; i < NUM_CHANNELS; ++i) {
-      setup->coef.dadx[1 + attrib][i] = 0;
-      setup->coef.dady[1 + attrib][i] = 0;
+   unsigned old_state = setup->state;
 
-      /* need provoking vertex info!
-       */
-      setup->coef.a0[1 + attrib][i] = setup->vprovoke[vertSlot][i];
-   }
-}
+   if (old_state == new_state)
+      return;
+       
+   LP_DBG(DEBUG_SETUP, "%s old %d new %d\n", __FUNCTION__, old_state, new_state);
 
+   switch (new_state) {
+   case SETUP_ACTIVE:
+      begin_binning( setup );
+      break;
 
-/**
- * Compute a0, dadx and dady for a linearly interpolated coefficient,
- * for a triangle.
- */
-static void tri_linear_coeff( struct setup_context *setup,
-                              unsigned attrib,
-                              uint vertSlot)
-{
-   unsigned i;
-   for (i = 0; i < NUM_CHANNELS; ++i) {
-      float botda = setup->vmid[vertSlot][i] - setup->vmin[vertSlot][i];
-      float majda = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
-      float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
-      float b = setup->emaj.dx * botda - majda * setup->ebot.dx;
-      float dadx = a * setup->oneoverarea;
-      float dady = b * setup->oneoverarea;
-
-      assert(i <= 3);
-
-      setup->coef.dadx[1 + attrib][i] = dadx;
-      setup->coef.dady[1 + attrib][i] = dady;
-
-      /* calculate a0 as the value which would be sampled for the
-       * fragment at (0,0), taking into account that we want to sample at
-       * pixel centers, in other words (0.5, 0.5).
-       *
-       * this is neat but unfortunately not a good way to do things for
-       * triangles with very large values of dadx or dady as it will
-       * result in the subtraction and re-addition from a0 of a very
-       * large number, which means we'll end up loosing a lot of the
-       * fractional bits and precision from a0.  the way to fix this is
-       * to define a0 as the sample at a pixel center somewhere near vmin
-       * instead - i'll switch to this later.
-       */
-      setup->coef.a0[1 + attrib][i] = (setup->vmin[vertSlot][i] -
-                     (dadx * (setup->vmin[0][0] - setup->pixel_offset) +
-                      dady * (setup->vmin[0][1] - setup->pixel_offset)));
-
-      /*
-      debug_printf("attr[%d].%c: %f dx:%f dy:%f\n",
-                   slot, "xyzw"[i],
-                   setup->coef[slot].a0[i],
-                   setup->coef[slot].dadx[i],
-                   setup->coef[slot].dady[i]);
-      */
+   case SETUP_CLEARED:
+      if (old_state == SETUP_ACTIVE) {
+         assert(0);
+         return;
+      }
+      break;
+      
+   case SETUP_FLUSHED:
+      if (old_state == SETUP_CLEARED)
+         execute_clears( setup );
+      else
+         lp_setup_rasterize_scene( setup, TRUE );
+      break;
    }
-}
-
 
-/**
- * Compute a0, dadx and dady for a perspective-corrected interpolant,
- * for a triangle.
- * We basically multiply the vertex value by 1/w before computing
- * the plane coefficients (a0, dadx, dady).
- * Later, when we compute the value at a particular fragment position we'll
- * divide the interpolated value by the interpolated W at that fragment.
- */
-static void tri_persp_coeff( struct setup_context *setup,
-                             unsigned attrib,
-                             uint vertSlot)
-{
-   unsigned i;
-   for (i = 0; i < NUM_CHANNELS; ++i) {
-      /* premultiply by 1/w  (v[0][3] is always W):
-       */
-      float mina = setup->vmin[vertSlot][i] * setup->vmin[0][3];
-      float mida = setup->vmid[vertSlot][i] * setup->vmid[0][3];
-      float maxa = setup->vmax[vertSlot][i] * setup->vmax[0][3];
-      float botda = mida - mina;
-      float majda = maxa - mina;
-      float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
-      float b = setup->emaj.dx * botda - majda * setup->ebot.dx;
-      float dadx = a * setup->oneoverarea;
-      float dady = b * setup->oneoverarea;
-
-      /*
-      debug_printf("tri persp %d,%d: %f %f %f\n", vertSlot, i,
-                   setup->vmin[vertSlot][i],
-                   setup->vmid[vertSlot][i],
-                   setup->vmax[vertSlot][i]
-             );
-      */
-      assert(i <= 3);
-
-      setup->coef.dadx[1 + attrib][i] = dadx;
-      setup->coef.dady[1 + attrib][i] = dady;
-      setup->coef.a0[1 + attrib][i] = (mina -
-                     (dadx * (setup->vmin[0][0] - setup->pixel_offset) +
-                      dady * (setup->vmin[0][1] - setup->pixel_offset)));
-   }
+   setup->state = new_state;
 }
 
 
-/**
- * Special coefficient setup for gl_FragCoord.
- * X and Y are trivial, though Y has to be inverted for OpenGL.
- * Z and W are copied from posCoef which should have already been computed.
- * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
- */
-static void
-setup_fragcoord_coeff(struct setup_context *setup, uint slot)
+void
+lp_setup_flush( struct setup_context *setup,
+                unsigned flags )
 {
-   /*X*/
-   setup->coef.a0[1 + slot][0] = 0;
-   setup->coef.dadx[1 + slot][0] = 1.0;
-   setup->coef.dady[1 + slot][0] = 0.0;
-   /*Y*/
-   setup->coef.a0[1 + slot][1] = 0.0;
-   setup->coef.dadx[1 + slot][1] = 0.0;
-   setup->coef.dady[1 + slot][1] = 1.0;
-   /*Z*/
-   setup->coef.a0[1 + slot][2] = setup->coef.a0[0][2];
-   setup->coef.dadx[1 + slot][2] = setup->coef.dadx[0][2];
-   setup->coef.dady[1 + slot][2] = setup->coef.dady[0][2];
-   /*W*/
-   setup->coef.a0[1 + slot][3] = setup->coef.a0[0][3];
-   setup->coef.dadx[1 + slot][3] = setup->coef.dadx[0][3];
-   setup->coef.dady[1 + slot][3] = setup->coef.dady[0][3];
-}
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
+   set_scene_state( setup, SETUP_FLUSHED );
+}
 
 
-/**
- * Compute the setup->coef[] array dadx, dady, a0 values.
- * Must be called after setup->vmin,vmid,vmax,vprovoke are initialized.
- */
-static void setup_tri_coefficients( struct setup_context *setup )
+void
+lp_setup_bind_framebuffer( struct setup_context *setup,
+                           const struct pipe_framebuffer_state *fb )
 {
-   struct llvmpipe_context *llvmpipe = setup->llvmpipe;
-   const struct lp_fragment_shader *lpfs = llvmpipe->fs;
-   const struct vertex_info *vinfo = llvmpipe_get_vertex_info(llvmpipe);
-   uint fragSlot;
+   struct lp_scene *scene = lp_setup_get_current_scene(setup);
 
-   /* z and w are done by linear interpolation:
-    */
-   tri_pos_coeff(setup, 0, 2);
-   tri_pos_coeff(setup, 0, 3);
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-   /* setup interpolation for all the remaining attributes:
-    */
-   for (fragSlot = 0; fragSlot < lpfs->info.num_inputs; fragSlot++) {
-      const uint vertSlot = vinfo->attrib[fragSlot].src_index;
+   set_scene_state( setup, SETUP_FLUSHED );
 
-      switch (vinfo->attrib[fragSlot].interp_mode) {
-      case INTERP_CONSTANT:
-         const_coeff(setup, fragSlot, vertSlot);
-         break;
-      case INTERP_LINEAR:
-         tri_linear_coeff(setup, fragSlot, vertSlot);
-         break;
-      case INTERP_PERSPECTIVE:
-         tri_persp_coeff(setup, fragSlot, vertSlot);
-         break;
-      case INTERP_POS:
-         setup_fragcoord_coeff(setup, fragSlot);
-         break;
-      default:
-         assert(0);
-      }
+   util_copy_framebuffer_state(&setup->fb, fb);
 
-      if (lpfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
-         setup->coef.a0[1 + fragSlot][0] = 1.0f - setup->facing;
-         setup->coef.dadx[1 + fragSlot][0] = 0.0;
-         setup->coef.dady[1 + fragSlot][0] = 0.0;
-      }
-   }
+   lp_scene_set_framebuffer_size(scene, setup->fb.width, setup->fb.height);
 }
 
 
-
-static void setup_tri_edges( struct setup_context *setup )
+void
+lp_setup_clear( struct setup_context *setup,
+                const float *color,
+                double depth,
+                unsigned stencil,
+                unsigned flags )
 {
-   float vmin_x = setup->vmin[0][0] + setup->pixel_offset;
-   float vmid_x = setup->vmid[0][0] + setup->pixel_offset;
-
-   float vmin_y = setup->vmin[0][1] - setup->pixel_offset;
-   float vmid_y = setup->vmid[0][1] - setup->pixel_offset;
-   float vmax_y = setup->vmax[0][1] - setup->pixel_offset;
-
-   setup->emaj.sy = ceilf(vmin_y);
-   setup->emaj.lines = (int) ceilf(vmax_y - setup->emaj.sy);
-   setup->emaj.dxdy = setup->emaj.dx / setup->emaj.dy;
-   setup->emaj.sx = vmin_x + (setup->emaj.sy - vmin_y) * setup->emaj.dxdy;
-
-   setup->etop.sy = ceilf(vmid_y);
-   setup->etop.lines = (int) ceilf(vmax_y - setup->etop.sy);
-   setup->etop.dxdy = setup->etop.dx / setup->etop.dy;
-   setup->etop.sx = vmid_x + (setup->etop.sy - vmid_y) * setup->etop.dxdy;
-
-   setup->ebot.sy = ceilf(vmin_y);
-   setup->ebot.lines = (int) ceilf(vmid_y - setup->ebot.sy);
-   setup->ebot.dxdy = setup->ebot.dx / setup->ebot.dy;
-   setup->ebot.sx = vmin_x + (setup->ebot.sy - vmin_y) * setup->ebot.dxdy;
-}
+   struct lp_scene *scene = lp_setup_get_current_scene(setup);
+   unsigned i;
 
+   LP_DBG(DEBUG_SETUP, "%s state %d\n", __FUNCTION__, setup->state);
 
-/**
- * Render the upper or lower half of a triangle.
- * Scissoring/cliprect is applied here too.
- */
-static void subtriangle( struct setup_context *setup,
-                        struct edge *eleft,
-                        struct edge *eright,
-                        unsigned lines )
-{
-   const struct pipe_scissor_state *cliprect = &setup->llvmpipe->cliprect;
-   const int minx = (int) cliprect->minx;
-   const int maxx = (int) cliprect->maxx;
-   const int miny = (int) cliprect->miny;
-   const int maxy = (int) cliprect->maxy;
-   int y, start_y, finish_y;
-   int sy = (int)eleft->sy;
-
-   assert((int)eleft->sy == (int) eright->sy);
-
-   /* clip top/bottom */
-   start_y = sy;
-   if (start_y < miny)
-      start_y = miny;
-
-   finish_y = sy + lines;
-   if (finish_y > maxy)
-      finish_y = maxy;
-
-   start_y -= sy;
-   finish_y -= sy;
-
-   /*
-   debug_printf("%s %d %d\n", __FUNCTION__, start_y, finish_y);
-   */
-
-   for (y = start_y; y < finish_y; y++) {
-
-      /* avoid accumulating adds as floats don't have the precision to
-       * accurately iterate large triangle edges that way.  luckily we
-       * can just multiply these days.
-       *
-       * this is all drowned out by the attribute interpolation anyway.
-       */
-      int left = (int)(eleft->sx + y * eleft->dxdy);
-      int right = (int)(eright->sx + y * eright->dxdy);
-
-      /* clip left/right */
-      if (left < minx)
-         left = minx;
-      if (right > maxx)
-         right = maxx;
-
-      if (left < right) {
-         int _y = sy + y;
-         if (block(_y) != setup->span.y) {
-            flush_spans(setup);
-            setup->span.y = block(_y);
-         }
 
-         setup->span.left[_y&1] = left;
-         setup->span.right[_y&1] = right;
-      }
+   if (flags & PIPE_CLEAR_COLOR) {
+      for (i = 0; i < 4; ++i)
+         setup->clear.color.clear_color[i] = float_to_ubyte(color[i]);
    }
 
+   if (flags & PIPE_CLEAR_DEPTHSTENCIL) {
+      setup->clear.zstencil.clear_zstencil = 
+         util_pack_z_stencil(setup->fb.zsbuf->format, 
+                             depth,
+                             stencil);
+   }
 
-   /* save the values so that emaj can be restarted:
-    */
-   eleft->sx += lines * eleft->dxdy;
-   eright->sx += lines * eright->dxdy;
-   eleft->sy += lines;
-   eright->sy += lines;
-}
+   if (setup->state == SETUP_ACTIVE) {
+      /* Add the clear to existing scene.  In the unusual case where
+       * both color and depth-stencil are being cleared when there's
+       * already been some rendering, we could discard the currently
+       * binned scene and start again, but I don't see that as being
+       * a common usage.
+       */
+      if (flags & PIPE_CLEAR_COLOR)
+         lp_scene_bin_everywhere( scene, 
+                            lp_rast_clear_color, 
+                            setup->clear.color );
 
+      if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL)
+         lp_scene_bin_everywhere( scene, 
+                            lp_rast_clear_zstencil, 
+                            setup->clear.zstencil );
+   }
+   else {
+      /* Put ourselves into the 'pre-clear' state, specifically to try
+       * and accumulate multiple clears to color and depth_stencil
+       * buffers which the app or state-tracker might issue
+       * separately.
+       */
+      set_scene_state( setup, SETUP_CLEARED );
 
-/**
- * Recalculate prim's determinant.  This is needed as we don't have
- * get this information through the vbuf_render interface & we must
- * calculate it here.
- */
-static float
-calc_det( const float (*v0)[4],
-          const float (*v1)[4],
-          const float (*v2)[4] )
-{
-   /* edge vectors e = v0 - v2, f = v1 - v2 */
-   const float ex = v0[0][0] - v2[0][0];
-   const float ey = v0[0][1] - v2[0][1];
-   const float fx = v1[0][0] - v2[0][0];
-   const float fy = v1[0][1] - v2[0][1];
-
-   /* det = cross(e,f).z */
-   return ex * fy - ey * fx;
+      setup->clear.flags |= flags;
+   }
 }
 
 
 /**
- * Do setup for triangle rasterization, then render the triangle.
+ * Emit a fence.
  */
-void llvmpipe_setup_tri( struct setup_context *setup,
-                const float (*v0)[4],
-                const float (*v1)[4],
-                const float (*v2)[4] )
+struct pipe_fence_handle *
+lp_setup_fence( struct setup_context *setup )
 {
-   float det;
+   struct lp_scene *scene = lp_setup_get_current_scene(setup);
+   const unsigned rank = lp_scene_get_num_bins( scene ); /* xxx */
+   struct lp_fence *fence = lp_fence_create(rank);
 
-#if DEBUG_VERTS
-   debug_printf("Setup triangle:\n");
-   print_vertex(setup, v0);
-   print_vertex(setup, v1);
-   print_vertex(setup, v2);
-#endif
+   LP_DBG(DEBUG_SETUP, "%s rank %u\n", __FUNCTION__, rank);
 
-   if (setup->llvmpipe->no_rast)
-      return;
-   
-   det = calc_det(v0, v1, v2);
-   /*
-   debug_printf("%s\n", __FUNCTION__ );
-   */
+   set_scene_state( setup, SETUP_ACTIVE );
 
-#if DEBUG_FRAGS
-   setup->numFragsEmitted = 0;
-   setup->numFragsWritten = 0;
-#endif
+   /* insert the fence into all command bins */
+   lp_scene_bin_everywhere( scene,
+                           lp_rast_fence,
+                           lp_rast_arg_fence(fence) );
 
-   if (cull_tri( setup, det ))
-      return;
+   return (struct pipe_fence_handle *) fence;
+}
 
-   if (!setup_sort_vertices( setup, det, v0, v1, v2 ))
-      return;
-   setup_tri_coefficients( setup );
-   setup_tri_edges( setup );
 
-   assert(setup->llvmpipe->reduced_prim == PIPE_PRIM_TRIANGLES);
+void 
+lp_setup_set_triangle_state( struct setup_context *setup,
+                             unsigned cull_mode,
+                             boolean ccw_is_frontface)
+{
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-   setup->span.y = 0;
-   setup->span.right[0] = 0;
-   setup->span.right[1] = 0;
-   /*   setup->span.z_mode = tri_z_mode( setup->ctx ); */
+   setup->ccw_is_frontface = ccw_is_frontface;
+   setup->cullmode = cull_mode;
+   setup->triangle = first_triangle;
+}
 
-   /*   init_constant_attribs( setup ); */
 
-   if (setup->oneoverarea < 0.0) {
-      /* emaj on left:
-       */
-      subtriangle( setup, &setup->emaj, &setup->ebot, setup->ebot.lines );
-      subtriangle( setup, &setup->emaj, &setup->etop, setup->etop.lines );
-   }
-   else {
-      /* emaj on right:
-       */
-      subtriangle( setup, &setup->ebot, &setup->emaj, setup->ebot.lines );
-      subtriangle( setup, &setup->etop, &setup->emaj, setup->etop.lines );
-   }
 
-   flush_spans( setup );
+void
+lp_setup_set_fs_inputs( struct setup_context *setup,
+                        const struct lp_shader_input *input,
+                        unsigned nr )
+{
+   LP_DBG(DEBUG_SETUP, "%s %p %u\n", __FUNCTION__, (void *) input, nr);
 
-#if DEBUG_FRAGS
-   printf("Tri: %u frags emitted, %u written\n",
-          setup->numFragsEmitted,
-          setup->numFragsWritten);
-#endif
+   memcpy( setup->fs.input, input, nr * sizeof input[0] );
+   setup->fs.nr_inputs = nr;
 }
 
+void
+lp_setup_set_fs_function( struct setup_context *setup,
+                          lp_jit_frag_func jit_function )
+{
+   LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) jit_function);
+   /* FIXME: reference count */
 
+   setup->fs.current.jit_function = jit_function;
+   setup->dirty |= LP_SETUP_NEW_FS;
+}
 
-/**
- * Compute a0, dadx and dady for a linearly interpolated coefficient,
- * for a line.
- */
-static void
-linear_pos_coeff(struct setup_context *setup,
-                 uint vertSlot, uint i)
+void
+lp_setup_set_fs_constants(struct setup_context *setup,
+                          struct pipe_buffer *buffer)
 {
-   const float da = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
-   const float dadx = da * setup->emaj.dx * setup->oneoverarea;
-   const float dady = da * setup->emaj.dy * setup->oneoverarea;
-   setup->coef.dadx[0][i] = dadx;
-   setup->coef.dady[0][i] = dady;
-   setup->coef.a0[0][i] = (setup->vmin[vertSlot][i] -
-                           (dadx * (setup->vmin[0][0] - setup->pixel_offset) +
-                            dady * (setup->vmin[0][1] - setup->pixel_offset)));
-}
+   LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) buffer);
 
+   pipe_buffer_reference(&setup->constants.current, buffer);
 
-/**
- * Compute a0, dadx and dady for a linearly interpolated coefficient,
- * for a line.
- */
-static void
-line_linear_coeff(struct setup_context *setup,
-                  unsigned attrib,
-                  uint vertSlot)
-{
-   unsigned i;
-   for (i = 0; i < NUM_CHANNELS; ++i) {
-      const float da = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
-      const float dadx = da * setup->emaj.dx * setup->oneoverarea;
-      const float dady = da * setup->emaj.dy * setup->oneoverarea;
-      setup->coef.dadx[1 + attrib][i] = dadx;
-      setup->coef.dady[1 + attrib][i] = dady;
-      setup->coef.a0[1 + attrib][i] = (setup->vmin[vertSlot][i] -
-                     (dadx * (setup->vmin[0][0] - setup->pixel_offset) +
-                      dady * (setup->vmin[0][1] - setup->pixel_offset)));
-   }
+   setup->dirty |= LP_SETUP_NEW_CONSTANTS;
 }
 
 
-/**
- * Compute a0, dadx and dady for a perspective-corrected interpolant,
- * for a line.
- */
-static void
-line_persp_coeff(struct setup_context *setup,
-                 unsigned attrib,
-                 uint vertSlot)
+void
+lp_setup_set_alpha_ref_value( struct setup_context *setup,
+                              float alpha_ref_value )
 {
-   unsigned i;
-   for (i = 0; i < NUM_CHANNELS; ++i) {
-      /* XXX double-check/verify this arithmetic */
-      const float a0 = setup->vmin[vertSlot][i] * setup->vmin[0][3];
-      const float a1 = setup->vmax[vertSlot][i] * setup->vmax[0][3];
-      const float da = a1 - a0;
-      const float dadx = da * setup->emaj.dx * setup->oneoverarea;
-      const float dady = da * setup->emaj.dy * setup->oneoverarea;
-      setup->coef.dadx[1 + attrib][i] = dadx;
-      setup->coef.dady[1 + attrib][i] = dady;
-      setup->coef.a0[1 + attrib][i] = (setup->vmin[vertSlot][i] -
-                     (dadx * (setup->vmin[0][0] - setup->pixel_offset) +
-                      dady * (setup->vmin[0][1] - setup->pixel_offset)));
+   LP_DBG(DEBUG_SETUP, "%s %f\n", __FUNCTION__, alpha_ref_value);
+
+   if(setup->fs.current.jit_context.alpha_ref_value != alpha_ref_value) {
+      setup->fs.current.jit_context.alpha_ref_value = alpha_ref_value;
+      setup->dirty |= LP_SETUP_NEW_FS;
    }
 }
 
-
-/**
- * Compute the setup->coef[] array dadx, dady, a0 values.
- * Must be called after setup->vmin,vmax are initialized.
- */
-static INLINE boolean
-setup_line_coefficients(struct setup_context *setup,
-                        const float (*v0)[4],
-                        const float (*v1)[4])
+void
+lp_setup_set_blend_color( struct setup_context *setup,
+                          const struct pipe_blend_color *blend_color )
 {
-   struct llvmpipe_context *llvmpipe = setup->llvmpipe;
-   const struct lp_fragment_shader *lpfs = llvmpipe->fs;
-   const struct vertex_info *vinfo = llvmpipe_get_vertex_info(llvmpipe);
-   uint fragSlot;
-   float area;
-
-   /* use setup->vmin, vmax to point to vertices */
-   if (llvmpipe->rasterizer->flatshade_first)
-      setup->vprovoke = v0;
-   else
-      setup->vprovoke = v1;
-   setup->vmin = v0;
-   setup->vmax = v1;
-
-   setup->emaj.dx = setup->vmax[0][0] - setup->vmin[0][0];
-   setup->emaj.dy = setup->vmax[0][1] - setup->vmin[0][1];
-
-   /* NOTE: this is not really area but something proportional to it */
-   area = setup->emaj.dx * setup->emaj.dx + setup->emaj.dy * setup->emaj.dy;
-   if (area == 0.0f || util_is_inf_or_nan(area))
-      return FALSE;
-   setup->oneoverarea = 1.0f / area;
-
-   /* z and w are done by linear interpolation:
-    */
-   linear_pos_coeff(setup, 0, 2);
-   linear_pos_coeff(setup, 0, 3);
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-   /* setup interpolation for all the remaining attributes:
-    */
-   for (fragSlot = 0; fragSlot < lpfs->info.num_inputs; fragSlot++) {
-      const uint vertSlot = vinfo->attrib[fragSlot].src_index;
+   assert(blend_color);
 
-      switch (vinfo->attrib[fragSlot].interp_mode) {
-      case INTERP_CONSTANT:
-         const_coeff(setup, fragSlot, vertSlot);
-         break;
-      case INTERP_LINEAR:
-         line_linear_coeff(setup, fragSlot, vertSlot);
-         break;
-      case INTERP_PERSPECTIVE:
-         line_persp_coeff(setup, fragSlot, vertSlot);
-         break;
-      case INTERP_POS:
-         setup_fragcoord_coeff(setup, fragSlot);
-         break;
-      default:
-         assert(0);
-      }
-
-      if (lpfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
-         setup->coef.a0[1 + fragSlot][0] = 1.0f - setup->facing;
-         setup->coef.dadx[1 + fragSlot][0] = 0.0;
-         setup->coef.dady[1 + fragSlot][0] = 0.0;
-      }
+   if(memcmp(&setup->blend_color.current, blend_color, sizeof *blend_color) != 0) {
+      memcpy(&setup->blend_color.current, blend_color, sizeof *blend_color);
+      setup->dirty |= LP_SETUP_NEW_BLEND_COLOR;
    }
-   return TRUE;
 }
 
 
-/**
- * Plot a pixel in a line segment.
- */
-static INLINE void
-plot(struct setup_context *setup, int x, int y)
+void 
+lp_setup_set_flatshade_first( struct setup_context *setup,
+                              boolean flatshade_first )
 {
-   const int iy = y & 1;
-   const int ix = x & 1;
-   const int quadX = x - ix;
-   const int quadY = y - iy;
-   const int mask = (1 << ix) << (2 * iy);
-
-   if (quadX != setup->quad[0].input.x0 ||
-       quadY != setup->quad[0].input.y0)
-   {
-      /* flush prev quad, start new quad */
-
-      if (setup->quad[0].input.x0 != -1)
-         clip_emit_quad( setup, &setup->quad[0] );
-
-      setup->quad[0].input.x0 = quadX;
-      setup->quad[0].input.y0 = quadY;
-      setup->quad[0].inout.mask = 0x0;
-   }
-
-   setup->quad[0].inout.mask |= mask;
+   setup->flatshade_first = flatshade_first;
 }
 
 
-/**
- * Do setup for line rasterization, then render the line.
- * Single-pixel width, no stipple, etc.  We rely on the 'draw' module
- * to handle stippling and wide lines.
- */
-void
-llvmpipe_setup_line(struct setup_context *setup,
-           const float (*v0)[4],
-           const float (*v1)[4])
+void 
+lp_setup_set_vertex_info( struct setup_context *setup,
+                          struct vertex_info *vertex_info )
 {
-   int x0 = (int) v0[0][0];
-   int x1 = (int) v1[0][0];
-   int y0 = (int) v0[0][1];
-   int y1 = (int) v1[0][1];
-   int dx = x1 - x0;
-   int dy = y1 - y0;
-   int xstep, ystep;
-
-#if DEBUG_VERTS
-   debug_printf("Setup line:\n");
-   print_vertex(setup, v0);
-   print_vertex(setup, v1);
-#endif
-
-   if (setup->llvmpipe->no_rast)
-      return;
+   /* XXX: just silently holding onto the pointer:
+    */
+   setup->vertex_info = vertex_info;
+}
 
-   if (dx == 0 && dy == 0)
-      return;
 
-   if (!setup_line_coefficients(setup, v0, v1))
-      return;
+void
+lp_setup_set_sampler_textures( struct setup_context *setup,
+                               unsigned num, struct pipe_texture **texture)
+{
+   struct pipe_texture *dummy;
+   unsigned i;
 
-   assert(v0[0][0] < 1.0e9);
-   assert(v0[0][1] < 1.0e9);
-   assert(v1[0][0] < 1.0e9);
-   assert(v1[0][1] < 1.0e9);
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-   if (dx < 0) {
-      dx = -dx;   /* make positive */
-      xstep = -1;
-   }
-   else {
-      xstep = 1;
-   }
 
-   if (dy < 0) {
-      dy = -dy;   /* make positive */
-      ystep = -1;
-   }
-   else {
-      ystep = 1;
-   }
+   assert(num <= PIPE_MAX_SAMPLERS);
 
-   assert(dx >= 0);
-   assert(dy >= 0);
-   assert(setup->llvmpipe->reduced_prim == PIPE_PRIM_LINES);
+   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
+      struct pipe_texture *tex = i < num ? texture[i] : NULL;
 
-   setup->quad[0].input.x0 = setup->quad[0].input.y0 = -1;
-   setup->quad[0].inout.mask = 0x0;
+      /* FIXME: hold on to the reference */
+      dummy = NULL;
+      pipe_texture_reference(&dummy, tex);
 
-   /* XXX temporary: set coverage to 1.0 so the line appears
-    * if AA mode happens to be enabled.
-    */
-   setup->quad[0].input.coverage[0] =
-   setup->quad[0].input.coverage[1] =
-   setup->quad[0].input.coverage[2] =
-   setup->quad[0].input.coverage[3] = 1.0;
-
-   if (dx > dy) {
-      /*** X-major line ***/
-      int i;
-      const int errorInc = dy + dy;
-      int error = errorInc - dx;
-      const int errorDec = error - dx;
-
-      for (i = 0; i < dx; i++) {
-         plot(setup, x0, y0);
-
-         x0 += xstep;
-         if (error < 0) {
-            error += errorInc;
-         }
-         else {
-            error += errorDec;
-            y0 += ystep;
-         }
-      }
-   }
-   else {
-      /*** Y-major line ***/
-      int i;
-      const int errorInc = dx + dx;
-      int error = errorInc - dy;
-      const int errorDec = error - dy;
-
-      for (i = 0; i < dy; i++) {
-         plot(setup, x0, y0);
-
-         y0 += ystep;
-         if (error < 0) {
-            error += errorInc;
-         }
-         else {
-            error += errorDec;
-            x0 += xstep;
-         }
+      if(tex) {
+         struct llvmpipe_texture *lp_tex = llvmpipe_texture(tex);
+         struct lp_jit_texture *jit_tex;
+         jit_tex = &setup->fs.current.jit_context.textures[i];
+         jit_tex->width = tex->width0;
+         jit_tex->height = tex->height0;
+         jit_tex->stride = lp_tex->stride[0];
+         if(!lp_tex->dt)
+            jit_tex->data = lp_tex->data;
+         else
+            /* FIXME: map the rendertarget */
+            assert(0);
       }
    }
 
-   /* draw final quad */
-   if (setup->quad[0].inout.mask) {
-      clip_emit_quad( setup, &setup->quad[0] );
-   }
+   setup->dirty |= LP_SETUP_NEW_FS;
 }
 
-
-static void
-point_persp_coeff(struct setup_context *setup,
-                  const float (*vert)[4],
-                  unsigned attrib,
-                  uint vertSlot)
+boolean
+lp_setup_is_texture_referenced( struct setup_context *setup,
+                                const struct pipe_texture *texture )
 {
-   unsigned i;
-   for(i = 0; i < NUM_CHANNELS; ++i) {
-      setup->coef.dadx[1 + attrib][i] = 0.0F;
-      setup->coef.dady[1 + attrib][i] = 0.0F;
-      setup->coef.a0[1 + attrib][i] = vert[vertSlot][i] * vert[0][3];
-   }
+   /* FIXME */
+   return PIPE_UNREFERENCED;
 }
 
 
-/**
- * Do setup for point rasterization, then render the point.
- * Round or square points...
- * XXX could optimize a lot for 1-pixel points.
- */
 void
-llvmpipe_setup_point( struct setup_context *setup,
-             const float (*v0)[4] )
+lp_setup_update_state( struct setup_context *setup )
 {
-   struct llvmpipe_context *llvmpipe = setup->llvmpipe;
-   const struct lp_fragment_shader *lpfs = llvmpipe->fs;
-   const int sizeAttr = setup->llvmpipe->psize_slot;
-   const float size
-      = sizeAttr > 0 ? v0[sizeAttr][0]
-      : setup->llvmpipe->rasterizer->point_size;
-   const float halfSize = 0.5F * size;
-   const boolean round = (boolean) setup->llvmpipe->rasterizer->point_smooth;
-   const float x = v0[0][0];  /* Note: data[0] is always position */
-   const float y = v0[0][1];
-   const struct vertex_info *vinfo = llvmpipe_get_vertex_info(llvmpipe);
-   uint fragSlot;
-
-#if DEBUG_VERTS
-   debug_printf("Setup point:\n");
-   print_vertex(setup, v0);
-#endif
-
-   if (llvmpipe->no_rast)
-      return;
+   struct lp_scene *scene = lp_setup_get_current_scene(setup);
 
-   assert(setup->llvmpipe->reduced_prim == PIPE_PRIM_POINTS);
-
-   /* For points, all interpolants are constant-valued.
-    * However, for point sprites, we'll need to setup texcoords appropriately.
-    * XXX: which coefficients are the texcoords???
-    * We may do point sprites as textured quads...
-    *
-    * KW: We don't know which coefficients are texcoords - ultimately
-    * the choice of what interpolation mode to use for each attribute
-    * should be determined by the fragment program, using
-    * per-attribute declaration statements that include interpolation
-    * mode as a parameter.  So either the fragment program will have
-    * to be adjusted for pointsprite vs normal point behaviour, or
-    * otherwise a special interpolation mode will have to be defined
-    * which matches the required behaviour for point sprites.  But -
-    * the latter is not a feature of normal hardware, and as such
-    * probably should be ruled out on that basis.
-    */
-   setup->vprovoke = v0;
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-   /* setup Z, W */
-   const_pos_coeff(setup, 0, 2);
-   const_pos_coeff(setup, 0, 3);
+   assert(setup->fs.current.jit_function);
 
-   for (fragSlot = 0; fragSlot < lpfs->info.num_inputs; fragSlot++) {
-      const uint vertSlot = vinfo->attrib[fragSlot].src_index;
+   if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) {
+      uint8_t *stored;
+      unsigned i, j;
 
-      switch (vinfo->attrib[fragSlot].interp_mode) {
-      case INTERP_CONSTANT:
-         /* fall-through */
-      case INTERP_LINEAR:
-         const_coeff(setup, fragSlot, vertSlot);
-         break;
-      case INTERP_PERSPECTIVE:
-         point_persp_coeff(setup, setup->vprovoke, fragSlot, vertSlot);
-         break;
-      case INTERP_POS:
-         setup_fragcoord_coeff(setup, fragSlot);
-         break;
-      default:
-         assert(0);
-      }
+      stored = lp_scene_alloc_aligned(scene, 4 * 16, 16);
 
-      if (lpfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
-         setup->coef.a0[1 + fragSlot][0] = 1.0f - setup->facing;
-         setup->coef.dadx[1 + fragSlot][0] = 0.0;
-         setup->coef.dady[1 + fragSlot][0] = 0.0;
+      /* smear each blend color component across 16 ubyte elements */
+      for (i = 0; i < 4; ++i) {
+         uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]);
+         for (j = 0; j < 16; ++j)
+            stored[i*16 + j] = c;
       }
-   }
 
+      setup->blend_color.stored = stored;
 
-   if (halfSize <= 0.5 && !round) {
-      /* special case for 1-pixel points */
-      const int ix = ((int) x) & 1;
-      const int iy = ((int) y) & 1;
-      setup->quad[0].input.x0 = (int) x - ix;
-      setup->quad[0].input.y0 = (int) y - iy;
-      setup->quad[0].inout.mask = (1 << ix) << (2 * iy);
-      clip_emit_quad( setup, &setup->quad[0] );
+      setup->fs.current.jit_context.blend_color = setup->blend_color.stored;
+      setup->dirty |= LP_SETUP_NEW_FS;
    }
-   else {
-      if (round) {
-         /* rounded points */
-         const int ixmin = block((int) (x - halfSize));
-         const int ixmax = block((int) (x + halfSize));
-         const int iymin = block((int) (y - halfSize));
-         const int iymax = block((int) (y + halfSize));
-         const float rmin = halfSize - 0.7071F;  /* 0.7071 = sqrt(2)/2 */
-         const float rmax = halfSize + 0.7071F;
-         const float rmin2 = MAX2(0.0F, rmin * rmin);
-         const float rmax2 = rmax * rmax;
-         const float cscale = 1.0F / (rmax2 - rmin2);
-         int ix, iy;
-
-         for (iy = iymin; iy <= iymax; iy += 2) {
-            for (ix = ixmin; ix <= ixmax; ix += 2) {
-               float dx, dy, dist2, cover;
-
-               setup->quad[0].inout.mask = 0x0;
-
-               dx = (ix + 0.5f) - x;
-               dy = (iy + 0.5f) - y;
-               dist2 = dx * dx + dy * dy;
-               if (dist2 <= rmax2) {
-                  cover = 1.0F - (dist2 - rmin2) * cscale;
-                  setup->quad[0].input.coverage[QUAD_TOP_LEFT] = MIN2(cover, 1.0f);
-                  setup->quad[0].inout.mask |= MASK_TOP_LEFT;
-               }
-
-               dx = (ix + 1.5f) - x;
-               dy = (iy + 0.5f) - y;
-               dist2 = dx * dx + dy * dy;
-               if (dist2 <= rmax2) {
-                  cover = 1.0F - (dist2 - rmin2) * cscale;
-                  setup->quad[0].input.coverage[QUAD_TOP_RIGHT] = MIN2(cover, 1.0f);
-                  setup->quad[0].inout.mask |= MASK_TOP_RIGHT;
-               }
-
-               dx = (ix + 0.5f) - x;
-               dy = (iy + 1.5f) - y;
-               dist2 = dx * dx + dy * dy;
-               if (dist2 <= rmax2) {
-                  cover = 1.0F - (dist2 - rmin2) * cscale;
-                  setup->quad[0].input.coverage[QUAD_BOTTOM_LEFT] = MIN2(cover, 1.0f);
-                  setup->quad[0].inout.mask |= MASK_BOTTOM_LEFT;
-               }
-
-               dx = (ix + 1.5f) - x;
-               dy = (iy + 1.5f) - y;
-               dist2 = dx * dx + dy * dy;
-               if (dist2 <= rmax2) {
-                  cover = 1.0F - (dist2 - rmin2) * cscale;
-                  setup->quad[0].input.coverage[QUAD_BOTTOM_RIGHT] = MIN2(cover, 1.0f);
-                  setup->quad[0].inout.mask |= MASK_BOTTOM_RIGHT;
-               }
-
-               if (setup->quad[0].inout.mask) {
-                  setup->quad[0].input.x0 = ix;
-                  setup->quad[0].input.y0 = iy;
-                  clip_emit_quad( setup, &setup->quad[0] );
-               }
+
+
+   if(setup->dirty & LP_SETUP_NEW_CONSTANTS) {
+      struct pipe_buffer *buffer = setup->constants.current;
+
+      if(buffer) {
+         unsigned current_size = buffer->size;
+         const void *current_data = llvmpipe_buffer(buffer)->data;
+
+         /* TODO: copy only the actually used constants? */
+
+         if(setup->constants.stored_size != current_size ||
+            !setup->constants.stored_data ||
+            memcmp(setup->constants.stored_data,
+                   current_data,
+                   current_size) != 0) {
+            void *stored;
+
+            stored = lp_scene_alloc(scene, current_size);
+            if(stored) {
+               memcpy(stored,
+                      current_data,
+                      current_size);
+               setup->constants.stored_size = current_size;
+               setup->constants.stored_data = stored;
             }
          }
       }
       else {
-         /* square points */
-         const int xmin = (int) (x + 0.75 - halfSize);
-         const int ymin = (int) (y + 0.25 - halfSize);
-         const int xmax = xmin + (int) size;
-         const int ymax = ymin + (int) size;
-         /* XXX could apply scissor to xmin,ymin,xmax,ymax now */
-         const int ixmin = block(xmin);
-         const int ixmax = block(xmax - 1);
-         const int iymin = block(ymin);
-         const int iymax = block(ymax - 1);
-         int ix, iy;
-
-         /*
-         debug_printf("(%f, %f) -> X:%d..%d Y:%d..%d\n", x, y, xmin, xmax,ymin,ymax);
-         */
-         for (iy = iymin; iy <= iymax; iy += 2) {
-            uint rowMask = 0xf;
-            if (iy < ymin) {
-               /* above the top edge */
-               rowMask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
-            }
-            if (iy + 1 >= ymax) {
-               /* below the bottom edge */
-               rowMask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT);
-            }
+         setup->constants.stored_size = 0;
+         setup->constants.stored_data = NULL;
+      }
 
-            for (ix = ixmin; ix <= ixmax; ix += 2) {
-               uint mask = rowMask;
-
-               if (ix < xmin) {
-                  /* fragment is past left edge of point, turn off left bits */
-                  mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
-               }
-               if (ix + 1 >= xmax) {
-                  /* past the right edge */
-                  mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
-               }
-
-               setup->quad[0].inout.mask = mask;
-               setup->quad[0].input.x0 = ix;
-               setup->quad[0].input.y0 = iy;
-               clip_emit_quad( setup, &setup->quad[0] );
-            }
+      setup->fs.current.jit_context.constants = setup->constants.stored_data;
+      setup->dirty |= LP_SETUP_NEW_FS;
+   }
+
+
+   if(setup->dirty & LP_SETUP_NEW_FS) {
+      if(!setup->fs.stored ||
+         memcmp(setup->fs.stored,
+                &setup->fs.current,
+                sizeof setup->fs.current) != 0) {
+         /* The fs state that's been stored in the scene is different from
+          * the new, current state.  So allocate a new lp_rast_state object
+          * and append it to the bin's setup data buffer.
+          */
+         struct lp_rast_state *stored =
+            (struct lp_rast_state *) lp_scene_alloc(scene, sizeof *stored);
+         if(stored) {
+            memcpy(stored,
+                   &setup->fs.current,
+                   sizeof setup->fs.current);
+            setup->fs.stored = stored;
+
+            /* put the state-set command into all bins */
+            lp_scene_bin_state_command( scene,
+                                       lp_rast_set_state, 
+                                       lp_rast_arg_state(setup->fs.stored) );
          }
       }
    }
+
+   setup->dirty = 0;
+
+   assert(setup->fs.stored);
 }
 
-void llvmpipe_setup_prepare( struct setup_context *setup )
+
+
+/* Only caller is lp_setup_vbuf_destroy()
+ */
+void 
+lp_setup_destroy( struct setup_context *setup )
 {
-   struct llvmpipe_context *lp = setup->llvmpipe;
+   reset_context( setup );
 
-   if (lp->dirty) {
-      llvmpipe_update_derived(lp);
-   }
+   pipe_buffer_reference(&setup->constants.current, NULL);
 
-   if (lp->reduced_api_prim == PIPE_PRIM_TRIANGLES &&
-       lp->rasterizer->fill_cw == PIPE_POLYGON_MODE_FILL &&
-       lp->rasterizer->fill_ccw == PIPE_POLYGON_MODE_FILL) {
-      /* we'll do culling */
-      setup->winding = lp->rasterizer->cull_mode;
-   }
-   else {
-      /* 'draw' will do culling */
-      setup->winding = PIPE_WINDING_NONE;
+   /* free the scenes in the 'empty' queue */
+   while (lp_scene_queue_count(setup->empty_scenes) > 0) {
+      struct lp_scene *scene = lp_scene_dequeue(setup->empty_scenes);
+      if (!scene)
+         break;
+      lp_scene_destroy(scene);
    }
-}
-
 
+   lp_rast_destroy( setup->rast );
 
-void llvmpipe_setup_destroy_context( struct setup_context *setup )
-{
-   align_free( setup );
+   FREE( setup );
 }
 
 
 /**
- * Create a new primitive setup/render stage.
+ * Create a new primitive tiling engine.  Plug it into the backend of
+ * the draw module.  Currently also creates a rasterizer to use with
+ * it.
  */
-struct setup_context *llvmpipe_setup_create_context( struct llvmpipe_context *llvmpipe )
+struct setup_context *
+lp_setup_create( struct pipe_screen *screen,
+                 struct draw_context *draw )
 {
-   struct setup_context *setup;
    unsigned i;
+   struct setup_context *setup = CALLOC_STRUCT(setup_context);
 
-   setup = align_malloc(sizeof(struct setup_context), 16);
    if (!setup)
       return NULL;
 
-   memset(setup, 0, sizeof *setup);
-   setup->llvmpipe = llvmpipe;
+   lp_setup_init_vbuf(setup);
+
+   setup->empty_scenes = lp_scene_queue_create();
+   if (!setup->empty_scenes)
+      goto fail;
 
-   for (i = 0; i < MAX_QUADS; i++) {
-      setup->quad[i].coef = &setup->coef;
+   setup->rast = lp_rast_create( screen, setup->empty_scenes );
+   if (!setup->rast) 
+      goto fail;
+
+   setup->vbuf = draw_vbuf_stage(draw, &setup->base);
+   if (!setup->vbuf)
+      goto fail;
+
+   draw_set_rasterize_stage(draw, setup->vbuf);
+   draw_set_render(draw, &setup->base);
+
+   /* create some empty scenes */
+   for (i = 0; i < MAX_SCENES; i++) {
+      struct lp_scene *scene = lp_scene_create();
+      lp_scene_enqueue(setup->empty_scenes, scene);
    }
 
-   setup->span.left[0] = 1000000;     /* greater than right[0] */
-   setup->span.left[1] = 1000000;     /* greater than right[1] */
+   setup->triangle = first_triangle;
+   setup->line     = first_line;
+   setup->point    = first_point;
+   
+   setup->dirty = ~0;
 
    return setup;
+
+fail:
+   if (setup->rast)
+      lp_rast_destroy( setup->rast );
+   
+   if (setup->vbuf)
+      ;
+
+   if (setup->empty_scenes)
+      lp_scene_queue_destroy(setup->empty_scenes);
+
+   FREE(setup);
+   return NULL;
 }
 
index 89c43da04605ec819105803df97fc84e545bae64..bf12cb852717d9ec31d72234e1aa5364886189f1 100644 (file)
 #ifndef LP_SETUP_H
 #define LP_SETUP_H
 
-struct setup_context;
-struct llvmpipe_context;
+#include "pipe/p_compiler.h"
+#include "lp_jit.h"
+
+struct draw_context;
+struct vertex_info;
+
+enum lp_interp {
+   LP_INTERP_CONSTANT,
+   LP_INTERP_LINEAR,
+   LP_INTERP_PERSPECTIVE,
+   LP_INTERP_POSITION,
+   LP_INTERP_FACING
+};
+
+/* Describes how to generate all the fragment shader inputs from the
+ * the vertices passed into our triangle/line/point functions.
+ *
+ * Vertices are treated as an array of float[4] values, indexed by
+ * src_index.
+ */
+struct lp_shader_input {
+   enum lp_interp interp;       /* how to interpolate values */
+   unsigned src_index;          /* where to find values in incoming vertices */
+};
+
+struct pipe_texture;
+struct pipe_surface;
+struct pipe_buffer;
+struct pipe_blend_color;
+struct pipe_screen;
+struct pipe_framebuffer_state;
+struct lp_fragment_shader;
+struct lp_jit_context;
+
+struct setup_context *
+lp_setup_create( struct pipe_screen *screen,
+                 struct draw_context *draw );
+
+void
+lp_setup_clear(struct setup_context *setup,
+               const float *clear_color,
+               double clear_depth,
+               unsigned clear_stencil,
+               unsigned flags);
+
+struct pipe_fence_handle *
+lp_setup_fence( struct setup_context *setup );
+
+
+void
+lp_setup_flush( struct setup_context *setup,
+                unsigned flags );
+
+
+void
+lp_setup_bind_framebuffer( struct setup_context *setup,
+                           const struct pipe_framebuffer_state *fb );
 
 void 
-llvmpipe_setup_tri( struct setup_context *setup,
-          const float (*v0)[4],
-          const float (*v1)[4],
-          const float (*v2)[4] );
+lp_setup_set_triangle_state( struct setup_context *setup,
+                             unsigned cullmode,
+                             boolean front_is_ccw );
+
+void
+lp_setup_set_fs_inputs( struct setup_context *setup,
+                        const struct lp_shader_input *interp,
+                        unsigned nr );
+
+void
+lp_setup_set_fs_function( struct setup_context *setup,
+                          lp_jit_frag_func jit_function );
+
+void
+lp_setup_set_fs_constants(struct setup_context *setup,
+                          struct pipe_buffer *buffer);
+
+
+void
+lp_setup_set_alpha_ref_value( struct setup_context *setup,
+                              float alpha_ref_value );
 
 void
-llvmpipe_setup_line(struct setup_context *setup,
-           const float (*v0)[4],
-           const float (*v1)[4]);
+lp_setup_set_blend_color( struct setup_context *setup,
+                          const struct pipe_blend_color *blend_color );
 
 void
-llvmpipe_setup_point( struct setup_context *setup,
-             const float (*v0)[4] );
+lp_setup_set_sampler_textures( struct setup_context *setup,
+                               unsigned num, struct pipe_texture **texture);
+
+boolean
+lp_setup_is_texture_referenced( struct setup_context *setup,
+                                const struct pipe_texture *texture );
 
+void
+lp_setup_set_flatshade_first( struct setup_context *setup, 
+                              boolean flatshade_first );
+
+void
+lp_setup_set_vertex_info( struct setup_context *setup, 
+                          struct vertex_info *info );
 
-struct setup_context *llvmpipe_setup_create_context( struct llvmpipe_context *llvmpipe );
-void llvmpipe_setup_prepare( struct setup_context *setup );
-void llvmpipe_setup_destroy_context( struct setup_context *setup );
 
 #endif
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_context.h b/src/gallium/drivers/llvmpipe/lp_setup_context.h
new file mode 100644 (file)
index 0000000..a1808fc
--- /dev/null
@@ -0,0 +1,146 @@
+/**************************************************************************
+ *
+ * Copyright 2007-2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 VMWARE 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.
+ *
+ **************************************************************************/
+
+
+/**
+ * The setup code is concerned with point/line/triangle setup and
+ * putting commands/data into the bins.
+ */
+
+
+#ifndef LP_SETUP_CONTEXT_H
+#define LP_SETUP_CONTEXT_H
+
+#include "lp_setup.h"
+#include "lp_rast.h"
+#include "lp_tile_soa.h"        /* for TILE_SIZE */
+#include "lp_scene.h"
+
+#include "draw/draw_vbuf.h"
+
+#define LP_SETUP_NEW_FS          0x01
+#define LP_SETUP_NEW_CONSTANTS   0x02
+#define LP_SETUP_NEW_BLEND_COLOR 0x04
+
+
+struct lp_scene_queue;
+
+
+/**
+ * Point/line/triangle setup context.
+ * Note: "stored" below indicates data which is stored in the bins,
+ * not arbitrary malloc'd memory.
+ *
+ *
+ * Subclass of vbuf_render, plugged directly into the draw module as
+ * the rendering backend.
+ */
+struct setup_context
+{
+   struct vbuf_render base;
+
+   struct vertex_info *vertex_info;
+   uint prim;
+   uint vertex_size;
+   uint nr_vertices;
+   uint vertex_buffer_size;
+   void *vertex_buffer;
+
+   /* Final pipeline stage for draw module.  Draw module should
+    * create/install this itself now.
+    */
+   struct draw_stage *vbuf;
+   struct lp_rasterizer *rast;
+   struct lp_scene *scene;               /**< current scene */
+   struct lp_scene_queue *empty_scenes;  /**< queue of empty scenes */
+
+   boolean flatshade_first;
+   boolean ccw_is_frontface;
+   unsigned cullmode;
+
+   struct pipe_framebuffer_state fb;
+
+   struct {
+      unsigned flags;
+      union lp_rast_cmd_arg color;    /**< lp_rast_clear_color() cmd */
+      union lp_rast_cmd_arg zstencil; /**< lp_rast_clear_zstencil() cmd */
+   } clear;
+
+   enum {
+      SETUP_FLUSHED,
+      SETUP_CLEARED,
+      SETUP_ACTIVE
+   } state;
+   
+   struct {
+      struct lp_shader_input input[PIPE_MAX_ATTRIBS];
+      unsigned nr_inputs;
+
+      const struct lp_rast_state *stored; /**< what's in the scene */
+      struct lp_rast_state current;  /**< currently set state */
+   } fs;
+
+   /** fragment shader constants */
+   struct {
+      struct pipe_buffer *current;
+      unsigned stored_size;
+      const void *stored_data;
+   } constants;
+
+   struct {
+      struct pipe_blend_color current;
+      uint8_t *stored;
+   } blend_color;
+
+   unsigned dirty;   /**< bitmask of LP_SETUP_x bits */
+
+   void (*point)( struct setup_context *,
+                  const float (*v0)[4]);
+
+   void (*line)( struct setup_context *,
+                 const float (*v0)[4],
+                 const float (*v1)[4]);
+
+   void (*triangle)( struct setup_context *,
+                     const float (*v0)[4],
+                     const float (*v1)[4],
+                     const float (*v2)[4]);
+};
+
+void lp_setup_choose_triangle( struct setup_context *setup );
+void lp_setup_choose_line( struct setup_context *setup );
+void lp_setup_choose_point( struct setup_context *setup );
+
+struct lp_scene *lp_setup_get_current_scene(struct setup_context *setup);
+
+void lp_setup_init_vbuf(struct setup_context *setup);
+
+void lp_setup_update_state( struct setup_context *setup );
+
+void lp_setup_destroy( struct setup_context *setup );
+
+#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_line.c b/src/gallium/drivers/llvmpipe/lp_setup_line.c
new file mode 100644 (file)
index 0000000..feea79d
--- /dev/null
@@ -0,0 +1,47 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Binning code for lines
+ */
+
+#include "lp_setup_context.h"
+
+static void line_nop( struct setup_context *setup,
+                      const float (*v0)[4],
+                      const float (*v1)[4] )
+{
+}
+
+
+void 
+lp_setup_choose_line( struct setup_context *setup )
+{
+   setup->line = line_nop;
+}
+
+
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_point.c b/src/gallium/drivers/llvmpipe/lp_setup_point.c
new file mode 100644 (file)
index 0000000..f03ca72
--- /dev/null
@@ -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.
+ *
+ **************************************************************************/
+
+/*
+ * Binning code for points
+ */
+
+#include "lp_setup_context.h"
+
+static void point_nop( struct setup_context *setup,
+                       const float (*v0)[4] )
+{
+}
+
+
+void 
+lp_setup_choose_point( struct setup_context *setup )
+{
+   setup->point = point_nop;
+}
+
+
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_tri.c b/src/gallium/drivers/llvmpipe/lp_setup_tri.c
new file mode 100644 (file)
index 0000000..fe34903
--- /dev/null
@@ -0,0 +1,547 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Binning code for triangles
+ */
+
+#include "lp_setup_context.h"
+#include "lp_rast.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+#define NUM_CHANNELS 4
+
+/**
+ * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
+ */
+static void constant_coef( struct lp_rast_triangle *tri,
+                           unsigned slot,
+                          const float value,
+                           unsigned i )
+{
+   tri->inputs.a0[slot][i] = value;
+   tri->inputs.dadx[slot][i] = 0;
+   tri->inputs.dady[slot][i] = 0;
+}
+
+/**
+ * Compute a0, dadx and dady for a linearly interpolated coefficient,
+ * for a triangle.
+ */
+static void linear_coef( struct lp_rast_triangle *tri,
+                         float oneoverarea,
+                         unsigned slot,
+                         const float (*v1)[4],
+                         const float (*v2)[4],
+                         const float (*v3)[4],
+                         unsigned vert_attr,
+                         unsigned i)
+{
+   float a1 = v1[vert_attr][i];
+   float a2 = v2[vert_attr][i];
+   float a3 = v3[vert_attr][i];
+
+   float da12 = a1 - a2;
+   float da31 = a3 - a1;
+   float dadx = (da12 * tri->dy31 - tri->dy12 * da31) * oneoverarea;
+   float dady = (da31 * tri->dx12 - tri->dx31 * da12) * oneoverarea;
+
+   tri->inputs.dadx[slot][i] = dadx;
+   tri->inputs.dady[slot][i] = dady;
+
+   /* calculate a0 as the value which would be sampled for the
+    * fragment at (0,0), taking into account that we want to sample at
+    * pixel centers, in other words (0.5, 0.5).
+    *
+    * this is neat but unfortunately not a good way to do things for
+    * triangles with very large values of dadx or dady as it will
+    * result in the subtraction and re-addition from a0 of a very
+    * large number, which means we'll end up loosing a lot of the
+    * fractional bits and precision from a0.  the way to fix this is
+    * to define a0 as the sample at a pixel center somewhere near vmin
+    * instead - i'll switch to this later.
+    */
+   tri->inputs.a0[slot][i] = (v1[vert_attr][i] -
+                              (dadx * (v1[0][0] - 0.5f) +
+                               dady * (v1[0][1] - 0.5f)));
+}
+
+
+/**
+ * Compute a0, dadx and dady for a perspective-corrected interpolant,
+ * for a triangle.
+ * We basically multiply the vertex value by 1/w before computing
+ * the plane coefficients (a0, dadx, dady).
+ * Later, when we compute the value at a particular fragment position we'll
+ * divide the interpolated value by the interpolated W at that fragment.
+ */
+static void perspective_coef( struct lp_rast_triangle *tri,
+                              float oneoverarea,
+                              unsigned slot,
+                             const float (*v1)[4],
+                             const float (*v2)[4],
+                             const float (*v3)[4],
+                             unsigned vert_attr,
+                              unsigned i)
+{
+   /* premultiply by 1/w  (v[0][3] is always 1/w):
+    */
+   float a1 = v1[vert_attr][i] * v1[0][3];
+   float a2 = v2[vert_attr][i] * v2[0][3];
+   float a3 = v3[vert_attr][i] * v3[0][3];
+   float da12 = a1 - a2;
+   float da31 = a3 - a1;
+   float dadx = (da12 * tri->dy31 - tri->dy12 * da31) * oneoverarea;
+   float dady = (da31 * tri->dx12 - tri->dx31 * da12) * oneoverarea;
+
+   tri->inputs.dadx[slot][i] = dadx;
+   tri->inputs.dady[slot][i] = dady;
+   tri->inputs.a0[slot][i] = (a1 -
+                              (dadx * (v1[0][0] - 0.5f) +
+                               dady * (v1[0][1] - 0.5f)));
+}
+
+
+/**
+ * Special coefficient setup for gl_FragCoord.
+ * X and Y are trivial, though Y has to be inverted for OpenGL.
+ * Z and W are copied from position_coef which should have already been computed.
+ * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
+ */
+static void
+setup_fragcoord_coef(struct lp_rast_triangle *tri,
+                     float oneoverarea,
+                     unsigned slot,
+                     const float (*v1)[4],
+                     const float (*v2)[4],
+                     const float (*v3)[4])
+{
+   /*X*/
+   tri->inputs.a0[slot][0] = 0.0;
+   tri->inputs.dadx[slot][0] = 1.0;
+   tri->inputs.dady[slot][0] = 0.0;
+   /*Y*/
+   tri->inputs.a0[slot][1] = 0.0;
+   tri->inputs.dadx[slot][1] = 0.0;
+   tri->inputs.dady[slot][1] = 1.0;
+   /*Z*/
+   linear_coef(tri, oneoverarea, slot, v1, v2, v3, 0, 2);
+   /*W*/
+   linear_coef(tri, oneoverarea, slot, v1, v2, v3, 0, 3);
+}
+
+
+static void setup_facing_coef( struct lp_rast_triangle *tri,
+                               unsigned slot,
+                               boolean frontface )
+{
+   constant_coef( tri, slot, 1.0f - frontface, 0 );
+   constant_coef( tri, slot, 0.0f, 1 ); /* wasted */
+   constant_coef( tri, slot, 0.0f, 2 ); /* wasted */
+   constant_coef( tri, slot, 0.0f, 3 ); /* wasted */
+}
+
+
+/**
+ * Compute the tri->coef[] array dadx, dady, a0 values.
+ */
+static void setup_tri_coefficients( struct setup_context *setup,
+                                   struct lp_rast_triangle *tri,
+                                    float oneoverarea,
+                                   const float (*v1)[4],
+                                   const float (*v2)[4],
+                                   const float (*v3)[4],
+                                   boolean frontface)
+{
+   struct lp_scene *scene = lp_setup_get_current_scene(setup);
+   unsigned slot;
+
+   /* Allocate space for the a0, dadx and dady arrays
+    */
+   {
+      unsigned bytes;
+      bytes = (setup->fs.nr_inputs + 1) * 4 * sizeof(float);
+      tri->inputs.a0   = lp_scene_alloc_aligned( scene, bytes, 16 );
+      tri->inputs.dadx = lp_scene_alloc_aligned( scene, bytes, 16 );
+      tri->inputs.dady = lp_scene_alloc_aligned( scene, bytes, 16 );
+   }
+
+   /* The internal position input is in slot zero:
+    */
+   setup_fragcoord_coef(tri, oneoverarea, 0, v1, v2, v3);
+
+   /* setup interpolation for all the remaining attributes:
+    */
+   for (slot = 0; slot < setup->fs.nr_inputs; slot++) {
+      unsigned vert_attr = setup->fs.input[slot].src_index;
+      unsigned i;
+
+      switch (setup->fs.input[slot].interp) {
+      case LP_INTERP_CONSTANT:
+         for (i = 0; i < NUM_CHANNELS; i++)
+            constant_coef(tri, slot+1, v3[vert_attr][i], i);
+         break;
+
+      case LP_INTERP_LINEAR:
+         for (i = 0; i < NUM_CHANNELS; i++)
+            linear_coef(tri, oneoverarea, slot+1, v1, v2, v3, vert_attr, i);
+         break;
+
+      case LP_INTERP_PERSPECTIVE:
+         for (i = 0; i < NUM_CHANNELS; i++)
+            perspective_coef(tri, oneoverarea, slot+1, v1, v2, v3, vert_attr, i);
+         break;
+
+      case LP_INTERP_POSITION:
+         /* XXX: fix me - duplicates the values in slot zero.
+          */
+         setup_fragcoord_coef(tri, oneoverarea, slot+1, v1, v2, v3);
+         break;
+
+      case LP_INTERP_FACING:
+         setup_facing_coef(tri, slot+1, frontface);
+         break;
+
+      default:
+         assert(0);
+      }
+   }
+}
+
+
+
+static inline int subpixel_snap( float a )
+{
+   return util_iround(FIXED_ONE * a);
+}
+
+
+/**
+ * Do basic setup for triangle rasterization and determine which
+ * framebuffer tiles are touched.  Put the triangle in the scene's
+ * bins for the tiles which we overlap.
+ */
+static void 
+do_triangle_ccw(struct setup_context *setup,
+               const float (*v1)[4],
+               const float (*v2)[4],
+               const float (*v3)[4],
+               boolean frontfacing )
+{
+   /* x/y positions in fixed point */
+   const int x1 = subpixel_snap(v1[0][0]);
+   const int x2 = subpixel_snap(v2[0][0]);
+   const int x3 = subpixel_snap(v3[0][0]);
+   const int y1 = subpixel_snap(v1[0][1]);
+   const int y2 = subpixel_snap(v2[0][1]);
+   const int y3 = subpixel_snap(v3[0][1]);
+
+   struct lp_scene *scene = lp_setup_get_current_scene(setup);
+   struct lp_rast_triangle *tri = lp_scene_alloc_aligned( scene, sizeof *tri, 16 );
+   float area, oneoverarea;
+   int minx, maxx, miny, maxy;
+
+   tri->dx12 = x1 - x2;
+   tri->dx23 = x2 - x3;
+   tri->dx31 = x3 - x1;
+
+   tri->dy12 = y1 - y2;
+   tri->dy23 = y2 - y3;
+   tri->dy31 = y3 - y1;
+
+   area = (tri->dx12 * tri->dy31 - 
+          tri->dx31 * tri->dy12);
+
+   /* Cull non-ccw and zero-sized triangles. 
+    *
+    * XXX: subject to overflow??
+    */
+   if (area <= 0) {
+      lp_scene_putback_data( scene, sizeof *tri );
+      return;
+   }
+
+   /* Bounding rectangle (in pixels) */
+   tri->minx = (MIN3(x1, x2, x3) + 0xf) >> FIXED_ORDER;
+   tri->maxx = (MAX3(x1, x2, x3) + 0xf) >> FIXED_ORDER;
+   tri->miny = (MIN3(y1, y2, y3) + 0xf) >> FIXED_ORDER;
+   tri->maxy = (MAX3(y1, y2, y3) + 0xf) >> FIXED_ORDER;
+   
+   if (tri->miny == tri->maxy || 
+       tri->minx == tri->maxx) {
+      lp_scene_putback_data( scene, sizeof *tri );
+      return;
+   }
+
+   /* 
+    */
+   oneoverarea = ((float)FIXED_ONE) / (float)area;
+
+   /* Setup parameter interpolants:
+    */
+   setup_tri_coefficients( setup, tri, oneoverarea, v1, v2, v3, frontfacing );
+
+   /* half-edge constants, will be interated over the whole
+    * rendertarget.
+    */
+   tri->c1 = tri->dy12 * x1 - tri->dx12 * y1;
+   tri->c2 = tri->dy23 * x2 - tri->dx23 * y2;
+   tri->c3 = tri->dy31 * x3 - tri->dx31 * y3;
+
+   /* correct for top-left fill convention:
+    */
+   if (tri->dy12 < 0 || (tri->dy12 == 0 && tri->dx12 > 0)) tri->c1++;
+   if (tri->dy23 < 0 || (tri->dy23 == 0 && tri->dx23 > 0)) tri->c2++;
+   if (tri->dy31 < 0 || (tri->dy31 == 0 && tri->dx31 > 0)) tri->c3++;
+
+   tri->dy12 *= FIXED_ONE;
+   tri->dy23 *= FIXED_ONE;
+   tri->dy31 *= FIXED_ONE;
+
+   tri->dx12 *= FIXED_ONE;
+   tri->dx23 *= FIXED_ONE;
+   tri->dx31 *= FIXED_ONE;
+
+   /* find trivial reject offsets for each edge for a single-pixel
+    * sized block.  These will be scaled up at each recursive level to
+    * match the active blocksize.  Scaling in this way works best if
+    * the blocks are square.
+    */
+   tri->eo1 = 0;
+   if (tri->dy12 < 0) tri->eo1 -= tri->dy12;
+   if (tri->dx12 > 0) tri->eo1 += tri->dx12;
+
+   tri->eo2 = 0;
+   if (tri->dy23 < 0) tri->eo2 -= tri->dy23;
+   if (tri->dx23 > 0) tri->eo2 += tri->dx23;
+
+   tri->eo3 = 0;
+   if (tri->dy31 < 0) tri->eo3 -= tri->dy31;
+   if (tri->dx31 > 0) tri->eo3 += tri->dx31;
+
+   /* Calculate trivial accept offsets from the above.
+    */
+   tri->ei1 = tri->dx12 - tri->dy12 - tri->eo1;
+   tri->ei2 = tri->dx23 - tri->dy23 - tri->eo2;
+   tri->ei3 = tri->dx31 - tri->dy31 - tri->eo3;
+
+   {
+      const int xstep1 = -tri->dy12;
+      const int xstep2 = -tri->dy23;
+      const int xstep3 = -tri->dy31;
+
+      const int ystep1 = tri->dx12;
+      const int ystep2 = tri->dx23;
+      const int ystep3 = tri->dx31;
+      
+      int qx, qy, ix, iy;
+      int i = 0;
+
+      for (qy = 0; qy < 2; qy++) {
+         for (qx = 0; qx < 2; qx++) {
+            for (iy = 0; iy < 2; iy++) {
+               for (ix = 0; ix < 2; ix++, i++) {
+                  int x = qx * 2 + ix;
+                  int y = qy * 2 + iy;
+                  tri->inputs.step[0][i] = x * xstep1 + y * ystep1;
+                  tri->inputs.step[1][i] = x * xstep2 + y * ystep2;
+                  tri->inputs.step[2][i] = x * xstep3 + y * ystep3;
+               }
+            }
+         }
+      }
+   }
+
+   /*
+    * All fields of 'tri' are now set.  The remaining code here is
+    * concerned with binning.
+    */
+
+   /* Convert to tile coordinates:
+    */
+   minx = tri->minx / TILE_SIZE;
+   miny = tri->miny / TILE_SIZE;
+   maxx = tri->maxx / TILE_SIZE;
+   maxy = tri->maxy / TILE_SIZE;
+
+   /* Determine which tile(s) intersect the triangle's bounding box
+    */
+   if (miny == maxy && minx == maxx)
+   {
+      /* Triangle is contained in a single tile:
+       */
+      lp_scene_bin_command( scene, minx, miny, lp_rast_triangle, 
+                           lp_rast_arg_triangle(tri) );
+   }
+   else 
+   {
+      int c1 = (tri->c1 + 
+                tri->dx12 * miny * TILE_SIZE - 
+                tri->dy12 * minx * TILE_SIZE);
+      int c2 = (tri->c2 + 
+                tri->dx23 * miny * TILE_SIZE -
+                tri->dy23 * minx * TILE_SIZE);
+      int c3 = (tri->c3 +
+                tri->dx31 * miny * TILE_SIZE -
+                tri->dy31 * minx * TILE_SIZE);
+
+      int ei1 = tri->ei1 << TILE_ORDER;
+      int ei2 = tri->ei2 << TILE_ORDER;
+      int ei3 = tri->ei3 << TILE_ORDER;
+
+      int eo1 = tri->eo1 << TILE_ORDER;
+      int eo2 = tri->eo2 << TILE_ORDER;
+      int eo3 = tri->eo3 << TILE_ORDER;
+
+      int xstep1 = -(tri->dy12 << TILE_ORDER);
+      int xstep2 = -(tri->dy23 << TILE_ORDER);
+      int xstep3 = -(tri->dy31 << TILE_ORDER);
+
+      int ystep1 = tri->dx12 << TILE_ORDER;
+      int ystep2 = tri->dx23 << TILE_ORDER;
+      int ystep3 = tri->dx31 << TILE_ORDER;
+      int x, y;
+
+
+      /* Trivially accept or reject blocks, else jump to per-pixel
+       * examination above.
+       */
+      for (y = miny; y <= maxy; y++)
+      {
+        int cx1 = c1;
+        int cx2 = c2;
+        int cx3 = c3;
+        int in = 0;
+
+        for (x = minx; x <= maxx; x++)
+        {
+           if (cx1 + eo1 < 0 || 
+               cx2 + eo2 < 0 ||
+               cx3 + eo3 < 0) 
+           {
+              /* do nothing */
+              if (in)
+                 break;
+           }
+           else if (cx1 + ei1 > 0 &&
+                    cx2 + ei2 > 0 &&
+                    cx3 + ei3 > 0) 
+           {
+              in = 1;
+               /* triangle covers the whole tile- shade whole tile */
+               lp_scene_bin_command( scene, x, y,
+                                    lp_rast_shade_tile,
+                                    lp_rast_arg_inputs(&tri->inputs) );
+           }
+           else 
+           { 
+              in = 1;
+               /* shade partial tile */
+               lp_scene_bin_command( scene, x, y,
+                                    lp_rast_triangle, 
+                                    lp_rast_arg_triangle(tri) );
+           }
+
+           /* Iterate cx values across the region:
+            */
+           cx1 += xstep1;
+           cx2 += xstep2;
+           cx3 += xstep3;
+        }
+      
+        /* Iterate c values down the region:
+         */
+        c1 += ystep1;
+        c2 += ystep2;
+        c3 += ystep3;    
+      }
+   }
+}
+
+static void triangle_cw( struct setup_context *setup,
+                        const float (*v0)[4],
+                        const float (*v1)[4],
+                        const float (*v2)[4] )
+{
+   do_triangle_ccw( setup, v1, v0, v2, !setup->ccw_is_frontface );
+}
+
+static void triangle_ccw( struct setup_context *setup,
+                        const float (*v0)[4],
+                        const float (*v1)[4],
+                        const float (*v2)[4] )
+{
+   do_triangle_ccw( setup, v0, v1, v2, setup->ccw_is_frontface );
+}
+
+static void triangle_both( struct setup_context *setup,
+                          const float (*v0)[4],
+                          const float (*v1)[4],
+                          const float (*v2)[4] )
+{
+   /* edge vectors e = v0 - v2, f = v1 - v2 */
+   const float ex = v0[0][0] - v2[0][0];
+   const float ey = v0[0][1] - v2[0][1];
+   const float fx = v1[0][0] - v2[0][0];
+   const float fy = v1[0][1] - v2[0][1];
+
+   /* det = cross(e,f).z */
+   if (ex * fy - ey * fx < 0) 
+      triangle_ccw( setup, v0, v1, v2 );
+   else
+      triangle_cw( setup, v0, v1, v2 );
+}
+
+static void triangle_nop( struct setup_context *setup,
+                         const float (*v0)[4],
+                         const float (*v1)[4],
+                         const float (*v2)[4] )
+{
+}
+
+
+void 
+lp_setup_choose_triangle( struct setup_context *setup )
+{
+   switch (setup->cullmode) {
+   case PIPE_WINDING_NONE:
+      setup->triangle = triangle_both;
+      break;
+   case PIPE_WINDING_CCW:
+      setup->triangle = triangle_cw;
+      break;
+   case PIPE_WINDING_CW:
+      setup->triangle = triangle_ccw;
+      break;
+   default:
+      setup->triangle = triangle_nop;
+      break;
+   }
+}
+
+
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_vbuf.c b/src/gallium/drivers/llvmpipe/lp_setup_vbuf.c
new file mode 100644 (file)
index 0000000..42c30af
--- /dev/null
@@ -0,0 +1,520 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+/**
+ * Interface between 'draw' module's output and the llvmpipe rasterizer/setup
+ * code.  When the 'draw' module has finished filling a vertex buffer, the
+ * draw_arrays() functions below will be called.  Loop over the vertices and
+ * call the point/line/tri setup functions.
+ *
+ * Authors
+ *  Brian Paul
+ */
+
+
+#include "lp_setup_context.h"
+#include "draw/draw_context.h"
+#include "draw/draw_vbuf.h"
+#include "draw/draw_vertex.h"
+#include "util/u_memory.h"
+#include "util/u_prim.h"
+
+
+#define LP_MAX_VBUF_INDEXES 1024
+#define LP_MAX_VBUF_SIZE    4096
+
+  
+
+/** cast wrapper */
+static struct setup_context *
+setup_context(struct vbuf_render *vbr)
+{
+   return (struct setup_context *) vbr;
+}
+
+
+
+static const struct vertex_info *
+lp_setup_get_vertex_info(struct vbuf_render *vbr)
+{
+   struct setup_context *setup = setup_context(vbr);
+   return setup->vertex_info;
+}
+
+
+static boolean
+lp_setup_allocate_vertices(struct vbuf_render *vbr,
+                          ushort vertex_size, ushort nr_vertices)
+{
+   struct setup_context *setup = setup_context(vbr);
+   unsigned size = vertex_size * nr_vertices;
+
+   if (setup->vertex_buffer_size < size) {
+      align_free(setup->vertex_buffer);
+      setup->vertex_buffer = align_malloc(size, 16);
+      setup->vertex_buffer_size = size;
+   }
+
+   setup->vertex_size = vertex_size;
+   setup->nr_vertices = nr_vertices;
+   
+   return setup->vertex_buffer != NULL;
+}
+
+static void
+lp_setup_release_vertices(struct vbuf_render *vbr)
+{
+   /* keep the old allocation for next time */
+}
+
+static void *
+lp_setup_map_vertices(struct vbuf_render *vbr)
+{
+   struct setup_context *setup = setup_context(vbr);
+   return setup->vertex_buffer;
+}
+
+static void 
+lp_setup_unmap_vertices(struct vbuf_render *vbr, 
+                       ushort min_index,
+                       ushort max_index )
+{
+   struct setup_context *setup = setup_context(vbr);
+   assert( setup->vertex_buffer_size >= (max_index+1) * setup->vertex_size );
+   /* do nothing */
+}
+
+
+static boolean
+lp_setup_set_primitive(struct vbuf_render *vbr, unsigned prim)
+{
+   setup_context(vbr)->prim = prim;
+   return TRUE;
+}
+
+typedef const float (*const_float4_ptr)[4];
+
+static INLINE const_float4_ptr get_vert( const void *vertex_buffer,
+                                         int index,
+                                         int stride )
+{
+   return (const_float4_ptr)((char *)vertex_buffer + index * stride);
+}
+
+/**
+ * draw elements / indexed primitives
+ */
+static void
+lp_setup_draw(struct vbuf_render *vbr, const ushort *indices, uint nr)
+{
+   struct setup_context *setup = setup_context(vbr);
+   const unsigned stride = setup->vertex_info->size * sizeof(float);
+   const void *vertex_buffer = setup->vertex_buffer;
+   unsigned i;
+
+   lp_setup_update_state(setup);
+
+   switch (setup->prim) {
+   case PIPE_PRIM_POINTS:
+      for (i = 0; i < nr; i++) {
+         setup->point( setup,
+                       get_vert(vertex_buffer, indices[i-0], stride) );
+      }
+      break;
+
+   case PIPE_PRIM_LINES:
+      for (i = 1; i < nr; i += 2) {
+         setup->line( setup,
+                      get_vert(vertex_buffer, indices[i-1], stride),
+                      get_vert(vertex_buffer, indices[i-0], stride) );
+      }
+      break;
+
+   case PIPE_PRIM_LINE_STRIP:
+      for (i = 1; i < nr; i ++) {
+         setup->line( setup,
+                      get_vert(vertex_buffer, indices[i-1], stride),
+                      get_vert(vertex_buffer, indices[i-0], stride) );
+      }
+      break;
+
+   case PIPE_PRIM_LINE_LOOP:
+      for (i = 1; i < nr; i ++) {
+         setup->line( setup,
+                      get_vert(vertex_buffer, indices[i-1], stride),
+                      get_vert(vertex_buffer, indices[i-0], stride) );
+      }
+      if (nr) {
+         setup->line( setup,
+                      get_vert(vertex_buffer, indices[nr-1], stride),
+                      get_vert(vertex_buffer, indices[0], stride) );
+      }
+      break;
+
+   case PIPE_PRIM_TRIANGLES:
+      if (setup->flatshade_first) {
+         for (i = 2; i < nr; i += 3) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[i-1], stride),
+                             get_vert(vertex_buffer, indices[i-0], stride),
+                             get_vert(vertex_buffer, indices[i-2], stride) );
+         }
+      }
+      else {
+         for (i = 2; i < nr; i += 3) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[i-2], stride),
+                             get_vert(vertex_buffer, indices[i-1], stride),
+                             get_vert(vertex_buffer, indices[i-0], stride) );
+         }
+      }
+      break;
+
+   case PIPE_PRIM_TRIANGLE_STRIP:
+      if (setup->flatshade_first) {
+         for (i = 2; i < nr; i += 1) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[i+(i&1)-1], stride),
+                             get_vert(vertex_buffer, indices[i-(i&1)], stride),
+                             get_vert(vertex_buffer, indices[i-2], stride) );
+         }
+      }
+      else {
+         for (i = 2; i < nr; i += 1) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[i+(i&1)-2], stride),
+                             get_vert(vertex_buffer, indices[i-(i&1)-1], stride),
+                             get_vert(vertex_buffer, indices[i-0], stride) );
+         }
+      }
+      break;
+
+   case PIPE_PRIM_TRIANGLE_FAN:
+      if (setup->flatshade_first) {
+         for (i = 2; i < nr; i += 1) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[i-0], stride),
+                             get_vert(vertex_buffer, indices[0], stride),
+                             get_vert(vertex_buffer, indices[i-1], stride) );
+         }
+      }
+      else {
+         for (i = 2; i < nr; i += 1) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[0], stride),
+                             get_vert(vertex_buffer, indices[i-1], stride),
+                             get_vert(vertex_buffer, indices[i-0], stride) );
+         }
+      }
+      break;
+
+   case PIPE_PRIM_QUADS:
+      if (setup->flatshade_first) {
+         for (i = 3; i < nr; i += 4) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[i-2], stride),
+                             get_vert(vertex_buffer, indices[i-1], stride),
+                             get_vert(vertex_buffer, indices[i-3], stride) );
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[i-1], stride),
+                             get_vert(vertex_buffer, indices[i-0], stride),
+                             get_vert(vertex_buffer, indices[i-3], stride) );
+         }
+      }
+      else {
+         for (i = 3; i < nr; i += 4) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[i-3], stride),
+                             get_vert(vertex_buffer, indices[i-2], stride),
+                             get_vert(vertex_buffer, indices[i-0], stride) );
+
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[i-2], stride),
+                             get_vert(vertex_buffer, indices[i-1], stride),
+                             get_vert(vertex_buffer, indices[i-0], stride) );
+         }
+      }
+      break;
+
+   case PIPE_PRIM_QUAD_STRIP:
+      if (setup->flatshade_first) {
+         for (i = 3; i < nr; i += 2) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[i-0], stride),
+                             get_vert(vertex_buffer, indices[i-1], stride),
+                             get_vert(vertex_buffer, indices[i-3], stride));
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[i-2], stride),
+                             get_vert(vertex_buffer, indices[i-0], stride),
+                             get_vert(vertex_buffer, indices[i-3], stride) );
+         }
+      }
+      else {
+         for (i = 3; i < nr; i += 2) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[i-3], stride),
+                             get_vert(vertex_buffer, indices[i-2], stride),
+                             get_vert(vertex_buffer, indices[i-0], stride) );
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, indices[i-1], stride),
+                             get_vert(vertex_buffer, indices[i-3], stride),
+                             get_vert(vertex_buffer, indices[i-0], stride) );
+         }
+      }
+      break;
+
+   case PIPE_PRIM_POLYGON:
+      /* Almost same as tri fan but the _first_ vertex specifies the flat
+       * shading color.  Note that the first polygon vertex is passed as
+       * the last triangle vertex here.
+       * flatshade_first state makes no difference.
+       */
+      for (i = 2; i < nr; i += 1) {
+         setup->triangle( setup,
+                          get_vert(vertex_buffer, indices[i-0], stride),
+                          get_vert(vertex_buffer, indices[i-1], stride),
+                          get_vert(vertex_buffer, indices[0], stride) );
+      }
+      break;
+
+   default:
+      assert(0);
+   }
+}
+
+
+/**
+ * This function is hit when the draw module is working in pass-through mode.
+ * It's up to us to convert the vertex array into point/line/tri prims.
+ */
+static void
+lp_setup_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
+{
+   struct setup_context *setup = setup_context(vbr);
+   const unsigned stride = setup->vertex_info->size * sizeof(float);
+   const void *vertex_buffer =
+      (void *) get_vert(setup->vertex_buffer, start, stride);
+   unsigned i;
+
+   lp_setup_update_state(setup);
+
+   switch (setup->prim) {
+   case PIPE_PRIM_POINTS:
+      for (i = 0; i < nr; i++) {
+         setup->point( setup,
+                       get_vert(vertex_buffer, i-0, stride) );
+      }
+      break;
+
+   case PIPE_PRIM_LINES:
+      for (i = 1; i < nr; i += 2) {
+         setup->line( setup,
+                      get_vert(vertex_buffer, i-1, stride),
+                      get_vert(vertex_buffer, i-0, stride) );
+      }
+      break;
+
+   case PIPE_PRIM_LINE_STRIP:
+      for (i = 1; i < nr; i ++) {
+         setup->line( setup,
+                      get_vert(vertex_buffer, i-1, stride),
+                      get_vert(vertex_buffer, i-0, stride) );
+      }
+      break;
+
+   case PIPE_PRIM_LINE_LOOP:
+      for (i = 1; i < nr; i ++) {
+         setup->line( setup,
+                      get_vert(vertex_buffer, i-1, stride),
+                      get_vert(vertex_buffer, i-0, stride) );
+      }
+      if (nr) {
+         setup->line( setup,
+                      get_vert(vertex_buffer, nr-1, stride),
+                      get_vert(vertex_buffer, 0, stride) );
+      }
+      break;
+
+   case PIPE_PRIM_TRIANGLES:
+      if (setup->flatshade_first) {
+         for (i = 2; i < nr; i += 3) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, i-1, stride),
+                             get_vert(vertex_buffer, i-0, stride),
+                             get_vert(vertex_buffer, i-2, stride) );
+         }
+      }
+      else {
+         for (i = 2; i < nr; i += 3) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, i-2, stride),
+                             get_vert(vertex_buffer, i-1, stride),
+                             get_vert(vertex_buffer, i-0, stride) );
+         }
+      }
+      break;
+
+   case PIPE_PRIM_TRIANGLE_STRIP:
+      if (setup->flatshade_first) {
+         for (i = 2; i < nr; i++) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, i+(i&1)-1, stride),
+                             get_vert(vertex_buffer, i-(i&1), stride),
+                             get_vert(vertex_buffer, i-2, stride) );
+         }
+      }
+      else {
+         for (i = 2; i < nr; i++) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, i+(i&1)-2, stride),
+                             get_vert(vertex_buffer, i-(i&1)-1, stride),
+                             get_vert(vertex_buffer, i-0, stride) );
+         }
+      }
+      break;
+
+   case PIPE_PRIM_TRIANGLE_FAN:
+      if (setup->flatshade_first) {
+         for (i = 2; i < nr; i += 1) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, i-0, stride),
+                             get_vert(vertex_buffer, 0, stride),
+                             get_vert(vertex_buffer, i-1, stride) );
+         }
+      }
+      else {
+         for (i = 2; i < nr; i += 1) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, 0, stride),
+                             get_vert(vertex_buffer, i-1, stride),
+                             get_vert(vertex_buffer, i-0, stride) );
+         }
+      }
+      break;
+
+   case PIPE_PRIM_QUADS:
+      if (setup->flatshade_first) {
+         for (i = 3; i < nr; i += 4) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, i-2, stride),
+                             get_vert(vertex_buffer, i-1, stride),
+                             get_vert(vertex_buffer, i-3, stride) );
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, i-1, stride),
+                             get_vert(vertex_buffer, i-0, stride),
+                             get_vert(vertex_buffer, i-3, stride) );
+         }
+      }
+      else {
+         for (i = 3; i < nr; i += 4) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, i-3, stride),
+                             get_vert(vertex_buffer, i-2, stride),
+                             get_vert(vertex_buffer, i-0, stride) );
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, i-2, stride),
+                             get_vert(vertex_buffer, i-1, stride),
+                             get_vert(vertex_buffer, i-0, stride) );
+         }
+      }
+      break;
+
+   case PIPE_PRIM_QUAD_STRIP:
+      if (setup->flatshade_first) {
+         for (i = 3; i < nr; i += 2) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, i-0, stride),
+                             get_vert(vertex_buffer, i-1, stride),
+                             get_vert(vertex_buffer, i-3, stride) );
+            setup->triangle( setup,
+
+                             get_vert(vertex_buffer, i-2, stride),
+                             get_vert(vertex_buffer, i-0, stride),
+                             get_vert(vertex_buffer, i-3, stride) );
+         }
+      }
+      else {
+         for (i = 3; i < nr; i += 2) {
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, i-3, stride),
+                             get_vert(vertex_buffer, i-2, stride),
+                             get_vert(vertex_buffer, i-0, stride) );
+            setup->triangle( setup,
+                             get_vert(vertex_buffer, i-1, stride),
+                             get_vert(vertex_buffer, i-3, stride),
+                             get_vert(vertex_buffer, i-0, stride) );
+         }
+      }
+      break;
+
+   case PIPE_PRIM_POLYGON:
+      /* Almost same as tri fan but the _first_ vertex specifies the flat
+       * shading color.  Note that the first polygon vertex is passed as
+       * the last triangle vertex here.
+       * flatshade_first state makes no difference.
+       */
+      for (i = 2; i < nr; i += 1) {
+         setup->triangle( setup,
+                          get_vert(vertex_buffer, i-1, stride),
+                          get_vert(vertex_buffer, i-0, stride),
+                          get_vert(vertex_buffer, 0, stride) );
+      }
+      break;
+
+   default:
+      assert(0);
+   }
+}
+
+
+
+static void
+lp_setup_vbuf_destroy(struct vbuf_render *vbr)
+{
+   lp_setup_destroy(setup_context(vbr));
+}
+
+
+/**
+ * Create the post-transform vertex handler for the given context.
+ */
+void
+lp_setup_init_vbuf(struct setup_context *setup)
+{
+   setup->base.max_indices = LP_MAX_VBUF_INDEXES;
+   setup->base.max_vertex_buffer_bytes = LP_MAX_VBUF_SIZE;
+
+   setup->base.get_vertex_info = lp_setup_get_vertex_info;
+   setup->base.allocate_vertices = lp_setup_allocate_vertices;
+   setup->base.map_vertices = lp_setup_map_vertices;
+   setup->base.unmap_vertices = lp_setup_unmap_vertices;
+   setup->base.set_primitive = lp_setup_set_primitive;
+   setup->base.draw = lp_setup_draw;
+   setup->base.draw_arrays = lp_setup_draw_arrays;
+   setup->base.release_vertices = lp_setup_release_vertices;
+   setup->base.destroy = lp_setup_vbuf_destroy;
+}
index 7020da145f323ff8485f8e243918e6adc4dbcee2..25d135367414b6b4960b5ceb2e67cfa8fbae7c5f 100644 (file)
@@ -54,6 +54,7 @@
 #define LP_NEW_VERTEX        0x1000
 #define LP_NEW_VS            0x2000
 #define LP_NEW_QUERY         0x4000
+#define LP_NEW_BLEND_COLOR   0x8000
 
 
 struct vertex_info;
@@ -211,12 +212,6 @@ llvmpipe_draw_range_elements(struct pipe_context *pipe,
                              unsigned max_index,
                              unsigned mode, unsigned start, unsigned count);
 
-void
-llvmpipe_map_transfers(struct llvmpipe_context *lp);
-
-void
-llvmpipe_unmap_transfers(struct llvmpipe_context *lp);
-
 void
 llvmpipe_map_texture_surfaces(struct llvmpipe_context *lp);
 
@@ -224,11 +219,4 @@ void
 llvmpipe_unmap_texture_surfaces(struct llvmpipe_context *lp);
 
 
-struct vertex_info *
-llvmpipe_get_vertex_info(struct llvmpipe_context *llvmpipe);
-
-struct vertex_info *
-llvmpipe_get_vbuf_vertex_info(struct llvmpipe_context *llvmpipe);
-
-
 #endif
index a94cd05ef20c7a9616dc4dbb6c985c2ce58f30fe..a10c5918df3d0d7a65c7a03e036c6f6fa7340178 100644 (file)
@@ -73,7 +73,12 @@ void llvmpipe_set_blend_color( struct pipe_context *pipe,
                             const struct pipe_blend_color *blend_color )
 {
    struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
-   unsigned i, j;
+
+   if(!blend_color)
+      return;
+
+   if(memcmp(&llvmpipe->blend_color, blend_color, sizeof *blend_color) == 0)
+      return;
 
    if(memcmp(&llvmpipe->blend_color, blend_color, sizeof *blend_color) == 0)
       return;
@@ -82,13 +87,7 @@ void llvmpipe_set_blend_color( struct pipe_context *pipe,
 
    memcpy(&llvmpipe->blend_color, blend_color, sizeof *blend_color);
 
-   if(!llvmpipe->jit_context.blend_color)
-      llvmpipe->jit_context.blend_color = align_malloc(4 * 16, 16);
-   for (i = 0; i < 4; ++i) {
-      uint8_t c = float_to_ubyte(blend_color->color[i]);
-      for (j = 0; j < 16; ++j)
-         llvmpipe->jit_context.blend_color[i*16 + j] = c;
-   }
+   llvmpipe->dirty |= LP_NEW_BLEND_COLOR;
 }
 
 
@@ -117,9 +116,6 @@ llvmpipe_bind_depth_stencil_state(struct pipe_context *pipe,
 
    llvmpipe->depth_stencil = depth_stencil;
 
-   if(llvmpipe->depth_stencil)
-      llvmpipe->jit_context.alpha_ref_value = llvmpipe->depth_stencil->alpha.ref_value;
-
    llvmpipe->dirty |= LP_NEW_DEPTH_STENCIL_ALPHA;
 }
 
index 6c1ef6bc42d827484788e4c4aaf1d4a79c62c8e9..78d046985b9dc50e0426da573483fe1277753e11 100644 (file)
 #include "draw/draw_private.h"
 #include "lp_context.h"
 #include "lp_screen.h"
-#include "lp_tex_cache.h"
+#include "lp_setup.h"
 #include "lp_state.h"
 
 
-/**
- * Mark the current vertex layout as "invalid".
- * We'll validate the vertex layout later, when we start to actually
- * render a point or line or tri.
- */
-static void
-invalidate_vertex_layout(struct llvmpipe_context *llvmpipe)
-{
-   llvmpipe->vertex_info.num_attribs =  0;
-}
-
 
 /**
  * The vertex info describes how to convert the post-transformed vertices
  * (simple float[][4]) used by the 'draw' module into vertices for
  * rasterization.
  *
- * This function validates the vertex layout and returns a pointer to a
- * vertex_info object.
+ * This function validates the vertex layout.
  */
-struct vertex_info *
-llvmpipe_get_vertex_info(struct llvmpipe_context *llvmpipe)
+static void
+compute_vertex_info(struct llvmpipe_context *llvmpipe)
 {
+   const struct lp_fragment_shader *lpfs = llvmpipe->fs;
    struct vertex_info *vinfo = &llvmpipe->vertex_info;
+   const uint num = draw_num_shader_outputs(llvmpipe->draw);
+   uint i;
 
-   if (vinfo->num_attribs == 0) {
-      /* compute vertex layout now */
-      const struct lp_fragment_shader *lpfs = llvmpipe->fs;
-      struct vertex_info *vinfo_vbuf = &llvmpipe->vertex_info_vbuf;
-      const uint num = draw_current_shader_outputs(llvmpipe->draw);
-      uint i;
+   /* Tell setup to tell the draw module to simply emit the whole
+    * post-xform vertex as-is.
+    *
+    * Not really sure if this is the best approach.
+    */
+   vinfo->num_attribs = 0;
+   for (i = 0; i < num; i++) {
+      draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_PERSPECTIVE, i);
+   }
+   draw_compute_vertex_size(vinfo);
 
-      /* Tell draw_vbuf to simply emit the whole post-xform vertex
-       * as-is.  No longer any need to try and emit draw vertex_header
-       * info.
-       */
-      vinfo_vbuf->num_attribs = 0;
-      for (i = 0; i < num; i++) {
-        draw_emit_vertex_attr(vinfo_vbuf, EMIT_4F, INTERP_PERSPECTIVE, i);
-      }
-      draw_compute_vertex_size(vinfo_vbuf);
 
-      /*
-       * Loop over fragment shader inputs, searching for the matching output
-       * from the vertex shader.
-       */
-      vinfo->num_attribs = 0;
-      for (i = 0; i < lpfs->info.num_inputs; i++) {
-         int src;
-         enum interp_mode interp;
+   lp_setup_set_vertex_info(llvmpipe->setup, vinfo);
 
-         switch (lpfs->info.input_interpolate[i]) {
-         case TGSI_INTERPOLATE_CONSTANT:
-            interp = INTERP_CONSTANT;
-            break;
-         case TGSI_INTERPOLATE_LINEAR:
-            interp = INTERP_LINEAR;
-            break;
-         case TGSI_INTERPOLATE_PERSPECTIVE:
-            interp = INTERP_PERSPECTIVE;
-            break;
-         default:
-            assert(0);
-            interp = INTERP_LINEAR;
-         }
+/*
+   llvmpipe->psize_slot = draw_find_vs_output(llvmpipe->draw,
+                                              TGSI_SEMANTIC_PSIZE, 0);
+*/
 
+   /* Now match FS inputs against emitted vertex data.  It's also
+    * entirely possible to just have a fixed layout for FS input,
+    * determined by the fragment shader itself, and adjust the draw
+    * outputs to match that.
+    */
+   {
+      struct lp_shader_input inputs[PIPE_MAX_SHADER_INPUTS];
+
+      for (i = 0; i < lpfs->info.num_inputs; i++) {
+
+         /* This can be precomputed, except for flatshade:
+          */
          switch (lpfs->info.input_semantic_name[i]) {
+         case TGSI_SEMANTIC_FACE:
+            inputs[i].interp = LP_INTERP_FACING;
+            break;
          case TGSI_SEMANTIC_POSITION:
-            interp = INTERP_POS;
+            inputs[i].interp = LP_INTERP_POSITION;
             break;
-
          case TGSI_SEMANTIC_COLOR:
-            if (llvmpipe->rasterizer->flatshade) {
-               interp = INTERP_CONSTANT;
-            }
+            /* Colors are linearly interpolated in the fragment shader
+             * even when flatshading is active.  This just tells the
+             * setup module to use coefficients with ddx==0 and
+             * ddy==0.
+             */
+            if (llvmpipe->rasterizer->flatshade)
+               inputs[i].interp = LP_INTERP_CONSTANT;
+            else
+               inputs[i].interp = LP_INTERP_LINEAR;
             break;
-         }
 
-         /* this includes texcoords and varying vars */
-         src = draw_find_shader_output(llvmpipe->draw,
-                                   lpfs->info.input_semantic_name[i],
-                                   lpfs->info.input_semantic_index[i]);
-         draw_emit_vertex_attr(vinfo, EMIT_4F, interp, src);
-      }
+         default:
+            switch (lpfs->info.input_interpolate[i]) {
+            case TGSI_INTERPOLATE_CONSTANT:
+               inputs[i].interp = LP_INTERP_CONSTANT;
+               break;
+            case TGSI_INTERPOLATE_LINEAR:
+               inputs[i].interp = LP_INTERP_LINEAR;
+               break;
+            case TGSI_INTERPOLATE_PERSPECTIVE:
+               inputs[i].interp = LP_INTERP_PERSPECTIVE;
+               break;
+            default:
+               assert(0);
+               break;
+            }
+         }
 
-      llvmpipe->psize_slot = draw_find_shader_output(llvmpipe->draw,
-                                                 TGSI_SEMANTIC_PSIZE, 0);
-      if (llvmpipe->psize_slot > 0) {
-         draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT,
-                               llvmpipe->psize_slot);
+         /* Search for each input in current vs output:
+          */
+         inputs[i].src_index = 
+            draw_find_shader_output(llvmpipe->draw,
+                                    lpfs->info.input_semantic_name[i],
+                                    lpfs->info.input_semantic_index[i]);
       }
 
-      draw_compute_vertex_size(vinfo);
+      lp_setup_set_fs_inputs(llvmpipe->setup, 
+                             inputs,
+                             lpfs->info.num_inputs);
    }
-
-   return vinfo;
 }
 
 
-/**
- * Called from vbuf module.
- *
- * Note that there's actually two different vertex layouts in llvmpipe.
- *
- * The normal one is computed in llvmpipe_get_vertex_info() above and is
- * used by the point/line/tri "setup" code.
- *
- * The other one (this one) is only used by the vbuf module (which is
- * not normally used by default but used in testing).  For the vbuf module,
- * we basically want to pass-through the draw module's vertex layout as-is.
- * When the llvmpipe vbuf code begins drawing, the normal vertex layout
- * will come into play again.
- */
-struct vertex_info *
-llvmpipe_get_vbuf_vertex_info(struct llvmpipe_context *llvmpipe)
-{
-   (void) llvmpipe_get_vertex_info(llvmpipe);
-   return &llvmpipe->vertex_info_vbuf;
-}
-
 
 /**
  * Recompute cliprect from scissor bounds, scissor enable and surface size.
@@ -206,15 +184,10 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
       llvmpipe->dirty |= LP_NEW_TEXTURE;
    }
       
-   if (llvmpipe->dirty & (LP_NEW_SAMPLER |
-                          LP_NEW_TEXTURE)) {
-      /* TODO */
-   }
-
    if (llvmpipe->dirty & (LP_NEW_RASTERIZER |
                           LP_NEW_FS |
                           LP_NEW_VS))
-      invalidate_vertex_layout( llvmpipe );
+      compute_vertex_info( llvmpipe );
 
    if (llvmpipe->dirty & (LP_NEW_SCISSOR |
                           LP_NEW_RASTERIZER |
@@ -228,6 +201,23 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
                           LP_NEW_TEXTURE))
       llvmpipe_update_fs( llvmpipe );
 
+   if (llvmpipe->dirty & LP_NEW_BLEND_COLOR)
+      lp_setup_set_blend_color(llvmpipe->setup,
+                               &llvmpipe->blend_color);
+
+   if (llvmpipe->dirty & LP_NEW_DEPTH_STENCIL_ALPHA)
+      lp_setup_set_alpha_ref_value(llvmpipe->setup, 
+                                   llvmpipe->depth_stencil->alpha.ref_value);
+
+   if (llvmpipe->dirty & LP_NEW_CONSTANTS)
+      lp_setup_set_fs_constants(llvmpipe->setup, 
+                                llvmpipe->constants[PIPE_SHADER_FRAGMENT].buffer);
+
+   if (llvmpipe->dirty & LP_NEW_TEXTURE)
+      lp_setup_set_sampler_textures(llvmpipe->setup, 
+                                    llvmpipe->num_textures,
+                                    llvmpipe->texture);
 
    llvmpipe->dirty = 0;
 }
+
index b73ca2d41ed2ebea5c064a9aa91e8d1dbbb413e9..3a669ba859ab7b9064ba20a606038852d9c9f28a 100644 (file)
@@ -84,8 +84,8 @@
 #include "lp_screen.h"
 #include "lp_context.h"
 #include "lp_buffer.h"
+#include "lp_setup.h"
 #include "lp_state.h"
-#include "lp_quad.h"
 #include "lp_tex_sample.h"
 #include "lp_debug.h"
 
@@ -186,8 +186,94 @@ generate_depth(LLVMBuilderRef builder,
 }
 
 
+/**
+ * Generate the code to do inside/outside triangle testing for the
+ * four pixels in a 2x2 quad.  This will set the four elements of the
+ * quad mask vector to 0 or ~0.
+ * \param i  which quad of the quad group to test, in [0,3]
+ */
+static void
+generate_tri_edge_mask(LLVMBuilderRef builder,
+                       unsigned i,
+                       LLVMValueRef *mask,      /* ivec4, out */
+                       LLVMValueRef c0,         /* int32 */
+                       LLVMValueRef c1,         /* int32 */
+                       LLVMValueRef c2,         /* int32 */
+                       LLVMValueRef step0_ptr,  /* ivec4 */
+                       LLVMValueRef step1_ptr,  /* ivec4 */
+                       LLVMValueRef step2_ptr)  /* ivec4 */
+{
+   /*
+     c0_vec = splat(c0)
+     c1_vec = splat(c1)
+     c2_vec = splat(c2)
+     m0_vec = step0_ptr[i] > c0_vec
+     m1_vec = step1_ptr[i] > c1_vec
+     m2_vec = step2_ptr[i] > c2_vec
+     mask = m0_vec & m1_vec & m2_vec
+    */
+   struct lp_type i32_type;
+   LLVMTypeRef i32vec4_type;
+
+   LLVMValueRef index;
+   LLVMValueRef c0_vec, c1_vec, c2_vec;
+   LLVMValueRef step0_vec, step1_vec, step2_vec;
+   LLVMValueRef m0_vec, m1_vec, m2_vec;
+   LLVMValueRef m;
+
+   assert(i < 4);
+   
+   /* int32 vector type */
+   memset(&i32_type, 0, sizeof i32_type);
+   i32_type.floating = FALSE; /* values are integers */
+   i32_type.sign = TRUE;      /* values are signed */
+   i32_type.norm = FALSE;     /* values are not normalized */
+   i32_type.width = 32;       /* 32-bit int values */
+   i32_type.length = 4;       /* 4 elements per vector */
+
+   i32vec4_type = lp_build_int32_vec4_type();
+
+   /* c0_vec = {c0, c0, c0, c0}
+    * Note that we emit this code four times but LLVM optimizes away
+    * three instances of it.
+    */
+   c0_vec = lp_build_broadcast(builder, i32vec4_type, c0);
+   c1_vec = lp_build_broadcast(builder, i32vec4_type, c1);
+   c2_vec = lp_build_broadcast(builder, i32vec4_type, c2);
+
+   lp_build_name(c0_vec, "edgeconst0vec");
+   lp_build_name(c1_vec, "edgeconst1vec");
+   lp_build_name(c2_vec, "edgeconst2vec");
+
+   index = LLVMConstInt(LLVMInt32Type(), i, 0);
+   step0_vec = LLVMBuildLoad(builder, LLVMBuildGEP(builder, step0_ptr, &index, 1, ""), "");
+   step1_vec = LLVMBuildLoad(builder, LLVMBuildGEP(builder, step1_ptr, &index, 1, ""), "");
+   step2_vec = LLVMBuildLoad(builder, LLVMBuildGEP(builder, step2_ptr, &index, 1, ""), "");
+
+   lp_build_name(step0_vec, "step0vec");
+   lp_build_name(step1_vec, "step1vec");
+   lp_build_name(step2_vec, "step2vec");
+
+   m0_vec = lp_build_compare(builder, i32_type, PIPE_FUNC_GREATER, step0_vec, c0_vec);
+   m1_vec = lp_build_compare(builder, i32_type, PIPE_FUNC_GREATER, step1_vec, c1_vec);
+   m2_vec = lp_build_compare(builder, i32_type, PIPE_FUNC_GREATER, step2_vec, c2_vec);
+
+   m = LLVMBuildAnd(builder, m0_vec, m1_vec, "");
+   m = LLVMBuildAnd(builder, m, m2_vec, "");
+
+   lp_build_name(m, "inoutmaskvec");
+
+   *mask = m;
+
+   /*
+    * if mask = {0,0,0,0} skip quad
+    */
+}
+
+
 /**
  * Generate the fragment shader, depth/stencil test, and alpha tests.
+ * \param i  which quad in the tile, in range [0,3]
  */
 static void
 generate_fs(struct llvmpipe_context *lp,
@@ -201,7 +287,13 @@ generate_fs(struct llvmpipe_context *lp,
             struct lp_build_sampler_soa *sampler,
             LLVMValueRef *pmask,
             LLVMValueRef *color,
-            LLVMValueRef depth_ptr)
+            LLVMValueRef depth_ptr,
+            LLVMValueRef c0,
+            LLVMValueRef c1,
+            LLVMValueRef c2,
+            LLVMValueRef step0_ptr,
+            LLVMValueRef step1_ptr,
+            LLVMValueRef step2_ptr)
 {
    const struct tgsi_token *tokens = shader->base.tokens;
    LLVMTypeRef elem_type;
@@ -216,6 +308,8 @@ generate_fs(struct llvmpipe_context *lp,
    unsigned attrib;
    unsigned chan;
 
+   assert(i < 4);
+
    elem_type = lp_build_elem_type(type);
    vec_type = lp_build_vec_type(type);
    int_vec_type = lp_build_int_vec_type(type);
@@ -235,8 +329,14 @@ generate_fs(struct llvmpipe_context *lp,
    }
    lp_build_flow_scope_declare(flow, &z);
 
+   /* do triangle edge testing */
+   generate_tri_edge_mask(builder, i, pmask,
+                          c0, c1, c2, step0_ptr, step1_ptr, step2_ptr);
+
+   /* 'mask' will control execution based on quad's pixel alive/killed state */
    lp_build_mask_begin(&mask, flow, type, *pmask);
 
+
    early_depth_test =
       key->depth.enabled &&
       !key->alpha.enabled &&
@@ -369,6 +469,9 @@ generate_blend(const struct pipe_blend_state *blend,
 
 /**
  * Generate the runtime callable function for the whole fragment pipeline.
+ * Note that the function which we generate operates on a block of 16
+ * pixels at at time.  The block contains 2x2 quads.  Each quad contains
+ * 2x2 pixels.
  */
 static struct lp_fragment_shader_variant *
 generate_fragment(struct llvmpipe_context *lp,
@@ -384,17 +487,18 @@ generate_fragment(struct llvmpipe_context *lp,
    LLVMTypeRef fs_int_vec_type;
    LLVMTypeRef blend_vec_type;
    LLVMTypeRef blend_int_vec_type;
-   LLVMTypeRef arg_types[9];
+   LLVMTypeRef arg_types[14];
    LLVMTypeRef func_type;
+   LLVMTypeRef int32_vec4_type = lp_build_int32_vec4_type();
    LLVMValueRef context_ptr;
    LLVMValueRef x;
    LLVMValueRef y;
    LLVMValueRef a0_ptr;
    LLVMValueRef dadx_ptr;
    LLVMValueRef dady_ptr;
-   LLVMValueRef mask_ptr;
    LLVMValueRef color_ptr;
    LLVMValueRef depth_ptr;
+   LLVMValueRef c0, c1, c2, step0_ptr, step1_ptr, step2_ptr;
    LLVMBasicBlockRef block;
    LLVMBuilderRef builder;
    LLVMValueRef x0;
@@ -476,8 +580,8 @@ generate_fragment(struct llvmpipe_context *lp,
    fs_type.sign = TRUE;     /* values are signed */
    fs_type.norm = FALSE;    /* values are not limited to [0,1] or [-1,1] */
    fs_type.width = 32;      /* 32-bit float */
-   fs_type.length = 4;      /* 4 element per vector */
-   num_fs = 4;
+   fs_type.length = 4;      /* 4 elements per vector */
+   num_fs = 4;              /* number of quads per block */
 
    memset(&blend_type, 0, sizeof blend_type);
    blend_type.floating = FALSE; /* values are integers */
@@ -504,9 +608,17 @@ generate_fragment(struct llvmpipe_context *lp,
    arg_types[3] = LLVMPointerType(fs_elem_type, 0);    /* a0 */
    arg_types[4] = LLVMPointerType(fs_elem_type, 0);    /* dadx */
    arg_types[5] = LLVMPointerType(fs_elem_type, 0);    /* dady */
-   arg_types[6] = LLVMPointerType(fs_int_vec_type, 0); /* mask */
-   arg_types[7] = LLVMPointerType(blend_vec_type, 0);  /* color */
-   arg_types[8] = LLVMPointerType(fs_int_vec_type, 0); /* depth */
+   arg_types[6] = LLVMPointerType(blend_vec_type, 0);  /* color */
+   arg_types[7] = LLVMPointerType(fs_int_vec_type, 0); /* depth */
+   arg_types[8] = LLVMInt32Type();                     /* c0 */
+   arg_types[9] = LLVMInt32Type();                    /* c1 */
+   arg_types[10] = LLVMInt32Type();                    /* c2 */
+   /* Note: the step arrays are built as int32[16] but we interpret
+    * them here as int32_vec4[4].
+    */
+   arg_types[11] = LLVMPointerType(int32_vec4_type, 0);/* step0 */
+   arg_types[12] = LLVMPointerType(int32_vec4_type, 0);/* step1 */
+   arg_types[13] = LLVMPointerType(int32_vec4_type, 0);/* step2 */
 
    func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);
 
@@ -522,9 +634,14 @@ generate_fragment(struct llvmpipe_context *lp,
    a0_ptr       = LLVMGetParam(variant->function, 3);
    dadx_ptr     = LLVMGetParam(variant->function, 4);
    dady_ptr     = LLVMGetParam(variant->function, 5);
-   mask_ptr     = LLVMGetParam(variant->function, 6);
-   color_ptr    = LLVMGetParam(variant->function, 7);
-   depth_ptr    = LLVMGetParam(variant->function, 8);
+   color_ptr    = LLVMGetParam(variant->function, 6);
+   depth_ptr    = LLVMGetParam(variant->function, 7);
+   c0           = LLVMGetParam(variant->function, 8);
+   c1           = LLVMGetParam(variant->function, 9);
+   c2           = LLVMGetParam(variant->function, 10);
+   step0_ptr    = LLVMGetParam(variant->function, 11);
+   step1_ptr    = LLVMGetParam(variant->function, 12);
+   step2_ptr    = LLVMGetParam(variant->function, 13);
 
    lp_build_name(context_ptr, "context");
    lp_build_name(x, "x");
@@ -532,9 +649,14 @@ generate_fragment(struct llvmpipe_context *lp,
    lp_build_name(a0_ptr, "a0");
    lp_build_name(dadx_ptr, "dadx");
    lp_build_name(dady_ptr, "dady");
-   lp_build_name(mask_ptr, "mask");
    lp_build_name(color_ptr, "color");
    lp_build_name(depth_ptr, "depth");
+   lp_build_name(c0, "c0");
+   lp_build_name(c1, "c1");
+   lp_build_name(c2, "c2");
+   lp_build_name(step0_ptr, "step0");
+   lp_build_name(step1_ptr, "step1");
+   lp_build_name(step2_ptr, "step2");
 
    /*
     * Function body
@@ -548,20 +670,20 @@ generate_fragment(struct llvmpipe_context *lp,
 
    lp_build_interp_soa_init(&interp, shader->base.tokens, builder, fs_type,
                             a0_ptr, dadx_ptr, dady_ptr,
-                            x0, y0, 2, 0);
+                            x0, y0);
 
    /* code generated texture sampling */
    sampler = lp_llvm_sampler_soa_create(key->sampler, context_ptr);
 
+   /* loop over quads in the block */
    for(i = 0; i < num_fs; ++i) {
       LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
       LLVMValueRef out_color[NUM_CHANNELS];
       LLVMValueRef depth_ptr_i;
 
       if(i != 0)
-         lp_build_interp_soa_update(&interp);
+         lp_build_interp_soa_update(&interp, i);
 
-      fs_mask[i] = LLVMBuildLoad(builder, LLVMBuildGEP(builder, mask_ptr, &index, 1, ""), "");
       depth_ptr_i = LLVMBuildGEP(builder, depth_ptr, &index, 1, "");
 
       generate_fs(lp, shader, key,
@@ -571,9 +693,11 @@ generate_fragment(struct llvmpipe_context *lp,
                   i,
                   &interp,
                   sampler,
-                  &fs_mask[i],
+                  &fs_mask[i], /* output */
                   out_color,
-                  depth_ptr_i);
+                  depth_ptr_i,
+                  c0, c1, c2,
+                  step0_ptr, step1_ptr, step2_ptr);
 
       for(chan = 0; chan < NUM_CHANNELS; ++chan)
          fs_out_color[chan][i] = out_color[chan];
@@ -724,15 +848,14 @@ llvmpipe_set_constant_buffer(struct pipe_context *pipe,
    assert(shader < PIPE_SHADER_TYPES);
    assert(index == 0);
 
+   if(llvmpipe->constants[shader].buffer == buffer)
+      return;
+
    draw_flush(llvmpipe->draw);
 
    /* note: reference counting */
    pipe_buffer_reference(&llvmpipe->constants[shader].buffer, buffer);
 
-   if(shader == PIPE_SHADER_FRAGMENT) {
-      llvmpipe->jit_context.constants = data;
-   }
-
    if(shader == PIPE_SHADER_VERTEX) {
       draw_set_mapped_constant_buffer(llvmpipe->draw, PIPE_SHADER_VERTEX,
                                       data, size);
@@ -814,4 +937,7 @@ llvmpipe_update_fs(struct llvmpipe_context *lp)
       variant = generate_fragment(lp, shader, &key);
 
    shader->current = variant;
+
+   lp_setup_set_fs_function(lp->setup, 
+                            shader->current->jit_function);
 }
index aa3b5a3f91ef1ce7971eccd40f166813109ba27f..7d4c310aae844f7a6458ef38e4d66dbdcf8c5565 100644 (file)
@@ -29,6 +29,7 @@
 #include "util/u_memory.h"
 #include "lp_context.h"
 #include "lp_state.h"
+#include "lp_setup.h"
 #include "draw/draw_context.h"
 
 
@@ -53,6 +54,16 @@ void llvmpipe_bind_rasterizer_state(struct pipe_context *pipe,
 
    llvmpipe->rasterizer = rasterizer;
 
+   /* Note: we can immediately set the triangle state here and
+    * not worry about binning because we handle culling during
+    * triangle setup, not when rasterizing the bins.
+    */
+   if (llvmpipe->rasterizer) {
+      lp_setup_set_triangle_state( llvmpipe->setup,
+                   llvmpipe->rasterizer->cull_mode,
+                   llvmpipe->rasterizer->front_winding == PIPE_WINDING_CCW );
+   }
+
    llvmpipe->dirty |= LP_NEW_RASTERIZER;
 }
 
index d382f9ca87e1cea4563785e21c423cda04bad305..976f81113fd1e4bea5176cb00ae2942168815c85 100644 (file)
@@ -37,7 +37,6 @@
 #include "lp_context.h"
 #include "lp_state.h"
 #include "lp_texture.h"
-#include "lp_tex_cache.h"
 #include "draw/draw_context.h"
 
 
@@ -125,17 +124,6 @@ llvmpipe_set_sampler_textures(struct pipe_context *pipe,
       struct pipe_texture *tex = i < num ? texture[i] : NULL;
 
       pipe_texture_reference(&llvmpipe->texture[i], tex);
-      lp_tex_tile_cache_set_texture(llvmpipe->tex_cache[i], tex);
-
-      if(tex) {
-         struct llvmpipe_texture *lp_tex = llvmpipe_texture(tex);
-         struct lp_jit_texture *jit_tex = &llvmpipe->jit_context.textures[i];
-         jit_tex->width = tex->width0;
-         jit_tex->height = tex->height0;
-         jit_tex->stride = lp_tex->stride[0];
-         if(!lp_tex->dt)
-            jit_tex->data = lp_tex->data;
-      }
    }
 
    llvmpipe->num_textures = num;
@@ -166,7 +154,6 @@ llvmpipe_set_vertex_sampler_textures(struct pipe_context *pipe,
       struct pipe_texture *tex = i < num_textures ? textures[i] : NULL;
 
       pipe_texture_reference(&llvmpipe->vertex_textures[i], tex);
-      lp_tex_tile_cache_set_texture(llvmpipe->vertex_tex_cache[i], tex);
    }
 
    llvmpipe->num_vertex_textures = num_textures;
index e37ff04f3df172aab3e3c764a645f2124c5f715f..0e9f03b90b85b12b6b120eb30bf5fcf23863e8c4 100644 (file)
 /* Authors:  Keith Whitwell <keith@tungstengraphics.com>
  */
 
+#include "pipe/p_state.h"
+#include "util/u_surface.h"
 #include "lp_context.h"
 #include "lp_state.h"
 #include "lp_surface.h"
-#include "lp_tile_cache.h"
+#include "lp_setup.h"
 
 #include "draw/draw_context.h"
 
 
 
 /**
- * XXX this might get moved someday
  * Set the framebuffer surface info: color buffers, zbuffer, stencil buffer.
- * Here, we flush the old surfaces and update the tile cache to point to the new
- * surfaces.
  */
 void
 llvmpipe_set_framebuffer_state(struct pipe_context *pipe,
                                const struct pipe_framebuffer_state *fb)
 {
    struct llvmpipe_context *lp = llvmpipe_context(pipe);
-   uint i;
 
-   draw_flush(lp->draw);
+   boolean changed = !util_framebuffer_state_equal(&lp->framebuffer, fb);
 
-   for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
-      /* check if changing cbuf */
-      if (lp->framebuffer.cbufs[i] != fb->cbufs[i]) {
-         /* flush old */
-         lp_tile_cache_map_transfers(lp->cbuf_cache[i]);
-         lp_flush_tile_cache(lp->cbuf_cache[i]);
+   if (changed) {
 
-         /* assign new */
-         pipe_surface_reference(&lp->framebuffer.cbufs[i], fb->cbufs[i]);
-
-         /* update cache */
-         lp_tile_cache_set_surface(lp->cbuf_cache[i], fb->cbufs[i]);
-      }
-   }
-
-   lp->framebuffer.nr_cbufs = fb->nr_cbufs;
-
-   /* zbuf changing? */
-   if (lp->framebuffer.zsbuf != fb->zsbuf) {
-
-      if(lp->zsbuf_transfer) {
-         struct pipe_screen *screen = pipe->screen;
-
-         if(lp->zsbuf_map) {
-            screen->transfer_unmap(screen, lp->zsbuf_transfer);
-            lp->zsbuf_map = NULL;
-         }
-
-         screen->tex_transfer_destroy(lp->zsbuf_transfer);
-         lp->zsbuf_transfer = NULL;
-      }
-
-      /* assign new */
-      pipe_surface_reference(&lp->framebuffer.zsbuf, fb->zsbuf);
+      util_copy_framebuffer_state(&lp->framebuffer, fb);
 
       /* Tell draw module how deep the Z/depth buffer is */
       if (lp->framebuffer.zsbuf) {
@@ -103,10 +70,9 @@ llvmpipe_set_framebuffer_state(struct pipe_context *pipe,
          }
          draw_set_mrd(lp->draw, mrd);
       }
-   }
 
-   lp->framebuffer.width = fb->width;
-   lp->framebuffer.height = fb->height;
+      lp_setup_bind_framebuffer( lp->setup, &lp->framebuffer );
 
-   lp->dirty |= LP_NEW_FRAMEBUFFER;
+      lp->dirty |= LP_NEW_FRAMEBUFFER;
+   }
 }
diff --git a/src/gallium/drivers/llvmpipe/lp_tex_cache.c b/src/gallium/drivers/llvmpipe/lp_tex_cache.c
deleted file mode 100644 (file)
index a6d9a2c..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-/**************************************************************************
- * 
- * 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 tile caching.
- *
- * Author:
- *    Brian Paul
- */
-
-#include "pipe/p_inlines.h"
-#include "util/u_memory.h"
-#include "util/u_tile.h"
-#include "util/u_format.h"
-#include "util/u_math.h"
-#include "lp_context.h"
-#include "lp_surface.h"
-#include "lp_texture.h"
-#include "lp_tex_cache.h"
-
-
-
-/**
- * Return the position in the cache for the tile that contains win pos (x,y).
- * We currently use a direct mapped cache so this is like a hack key.
- * At some point we should investige something more sophisticated, like
- * a LRU replacement policy.
- */
-#define CACHE_POS(x, y) \
-   (((x) + (y) * 5) % NUM_ENTRIES)
-
-
-
-/**
- * Is the tile at (x,y) in cleared state?
- */
-static INLINE uint
-is_clear_flag_set(const uint *bitvec, union tex_tile_address addr)
-{
-   int pos, bit;
-   pos = addr.bits.y * (MAX_TEX_WIDTH / TEX_TILE_SIZE) + addr.bits.x;
-   assert(pos / 32 < (MAX_TEX_WIDTH / TEX_TILE_SIZE) * (MAX_TEX_HEIGHT / TEX_TILE_SIZE) / 32);
-   bit = bitvec[pos / 32] & (1 << (pos & 31));
-   return bit;
-}
-   
-
-/**
- * Mark the tile at (x,y) as not cleared.
- */
-static INLINE void
-clear_clear_flag(uint *bitvec, union tex_tile_address addr)
-{
-   int pos;
-   pos = addr.bits.y * (MAX_TEX_WIDTH / TEX_TILE_SIZE) + addr.bits.x;
-   assert(pos / 32 < (MAX_TEX_WIDTH / TEX_TILE_SIZE) * (MAX_TEX_HEIGHT / TEX_TILE_SIZE) / 32);
-   bitvec[pos / 32] &= ~(1 << (pos & 31));
-}
-   
-
-struct llvmpipe_tex_tile_cache *
-lp_create_tex_tile_cache( struct pipe_screen *screen )
-{
-   struct llvmpipe_tex_tile_cache *tc;
-   uint pos;
-
-   tc = CALLOC_STRUCT( llvmpipe_tex_tile_cache );
-   if (tc) {
-      tc->screen = screen;
-      for (pos = 0; pos < NUM_ENTRIES; pos++) {
-         tc->entries[pos].addr.bits.invalid = 1;
-      }
-      tc->last_tile = &tc->entries[0]; /* any tile */
-   }
-   return tc;
-}
-
-
-void
-lp_destroy_tex_tile_cache(struct llvmpipe_tex_tile_cache *tc)
-{
-   struct pipe_screen *screen;
-   uint pos;
-
-   for (pos = 0; pos < NUM_ENTRIES; pos++) {
-      /*assert(tc->entries[pos].x < 0);*/
-   }
-   if (tc->transfer) {
-      screen = tc->transfer->texture->screen;
-      screen->tex_transfer_destroy(tc->transfer);
-   }
-   if (tc->tex_trans) {
-      screen = tc->tex_trans->texture->screen;
-      screen->tex_transfer_destroy(tc->tex_trans);
-   }
-
-   FREE( tc );
-}
-
-
-void
-lp_tex_tile_cache_map_transfers(struct llvmpipe_tex_tile_cache *tc)
-{
-   if (tc->transfer && !tc->transfer_map)
-      tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
-
-   if (tc->tex_trans && !tc->tex_trans_map)
-      tc->tex_trans_map = tc->screen->transfer_map(tc->screen, tc->tex_trans);
-}
-
-
-void
-lp_tex_tile_cache_unmap_transfers(struct llvmpipe_tex_tile_cache *tc)
-{
-   if (tc->transfer_map) {
-      tc->screen->transfer_unmap(tc->screen, tc->transfer);
-      tc->transfer_map = NULL;
-   }
-
-   if (tc->tex_trans_map) {
-      tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
-      tc->tex_trans_map = NULL;
-   }
-}
-
-void
-lp_tex_tile_cache_validate_texture(struct llvmpipe_tex_tile_cache *tc)
-{
-   if (tc->texture) {
-      struct llvmpipe_texture *lpt = llvmpipe_texture(tc->texture);
-      if (lpt->timestamp != tc->timestamp) {
-         /* texture was modified, invalidate all cached tiles */
-         uint i;
-         for (i = 0; i < NUM_ENTRIES; i++) {
-            tc->entries[i].addr.bits.invalid = 1;
-         }
-
-         tc->timestamp = lpt->timestamp;
-      }
-   }
-}
-
-/**
- * Specify the texture to cache.
- */
-void
-lp_tex_tile_cache_set_texture(struct llvmpipe_tex_tile_cache *tc,
-                          struct pipe_texture *texture)
-{
-   uint i;
-
-   assert(!tc->transfer);
-
-   if (tc->texture != texture) {
-      pipe_texture_reference(&tc->texture, texture);
-
-      if (tc->tex_trans) {
-         struct pipe_screen *screen = tc->tex_trans->texture->screen;
-         
-         if (tc->tex_trans_map) {
-            screen->transfer_unmap(screen, tc->tex_trans);
-            tc->tex_trans_map = NULL;
-         }
-
-         screen->tex_transfer_destroy(tc->tex_trans);
-         tc->tex_trans = NULL;
-      }
-
-      /* mark as entries as invalid/empty */
-      /* XXX we should try to avoid this when the teximage hasn't changed */
-      for (i = 0; i < NUM_ENTRIES; i++) {
-         tc->entries[i].addr.bits.invalid = 1;
-      }
-
-      tc->tex_face = -1; /* any invalid value here */
-   }
-}
-
-
-/**
- * Given the texture face, level, zslice, x and y values, compute
- * the cache entry position/index where we'd hope to find the
- * cached texture tile.
- * This is basically a direct-map cache.
- * XXX There's probably lots of ways in which we can improve this.
- */
-static INLINE uint
-tex_cache_pos( union tex_tile_address addr )
-{
-   uint entry = (addr.bits.x + 
-                 addr.bits.y * 9 + 
-                 addr.bits.z * 3 + 
-                 addr.bits.face + 
-                 addr.bits.level * 7);
-
-   return entry % NUM_ENTRIES;
-}
-
-/**
- * Similar to lp_get_cached_tile() but for textures.
- * Tiles are read-only and indexed with more params.
- */
-const struct llvmpipe_cached_tex_tile *
-lp_find_cached_tex_tile(struct llvmpipe_tex_tile_cache *tc,
-                        union tex_tile_address addr )
-{
-   struct pipe_screen *screen = tc->screen;
-   struct llvmpipe_cached_tex_tile *tile;
-   
-   tile = tc->entries + tex_cache_pos( addr );
-
-   if (addr.value != tile->addr.value) {
-
-      /* cache miss.  Most misses are because we've invaldiated the
-       * texture cache previously -- most commonly on binding a new
-       * texture.  Currently we effectively flush the cache on texture
-       * bind.
-       */
-#if 0
-      _debug_printf("miss at %u:  x=%d y=%d z=%d face=%d level=%d\n"
-                    "   tile %u:  x=%d y=%d z=%d face=%d level=%d\n",
-                    pos, x/TEX_TILE_SIZE, y/TEX_TILE_SIZE, z, face, level,
-                    pos, tile->addr.bits.x, tile->addr.bits.y, tile->z, tile->face, tile->level);
-#endif
-
-      /* check if we need to get a new transfer */
-      if (!tc->tex_trans ||
-          tc->tex_face != addr.bits.face ||
-          tc->tex_level != addr.bits.level ||
-          tc->tex_z != addr.bits.z) {
-         /* get new transfer (view into texture) */
-
-         if (tc->tex_trans) {
-            if (tc->tex_trans_map) {
-               tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
-               tc->tex_trans_map = NULL;
-            }
-
-            screen->tex_transfer_destroy(tc->tex_trans);
-            tc->tex_trans = NULL;
-         }
-
-         tc->tex_trans = 
-            screen->get_tex_transfer(screen, tc->texture, 
-                                     addr.bits.face, 
-                                     addr.bits.level, 
-                                     addr.bits.z, 
-                                     PIPE_TRANSFER_READ, 0, 0,
-                                     u_minify(tc->texture->width0, addr.bits.level),
-                                     u_minify(tc->texture->height0, addr.bits.level));
-
-         tc->tex_trans_map = screen->transfer_map(screen, tc->tex_trans);
-
-         tc->tex_face = addr.bits.face;
-         tc->tex_level = addr.bits.level;
-         tc->tex_z = addr.bits.z;
-      }
-
-      {
-         unsigned x = addr.bits.x * TEX_TILE_SIZE;
-         unsigned y = addr.bits.y * TEX_TILE_SIZE;
-         unsigned w = TEX_TILE_SIZE;
-         unsigned h = TEX_TILE_SIZE;
-
-         if (pipe_clip_tile(x, y, &w, &h, tc->tex_trans)) {
-            assert(0);
-         }
-
-         util_format_read_4ub(tc->tex_trans->texture->format,
-                              (uint8_t *)tile->color, sizeof tile->color[0],
-                              tc->tex_trans_map, tc->tex_trans->stride,
-                              x, y, w, h);
-      }
-
-      tile->addr = addr;
-   }
-
-   tc->last_tile = tile;
-   return tile;
-}
diff --git a/src/gallium/drivers/llvmpipe/lp_tex_cache.h b/src/gallium/drivers/llvmpipe/lp_tex_cache.h
deleted file mode 100644 (file)
index 05fded7..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/**************************************************************************
- * 
- * 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 LP_TEX_CACHE_H
-#define LP_TEX_CACHE_H
-
-
-#include "pipe/p_compiler.h"
-
-
-struct llvmpipe_context;
-struct llvmpipe_tex_tile_cache;
-
-
-/**
- * Cache tile size (width and height). This needs to be a power of two.
- */
-#define TEX_TILE_SIZE 64
-
-
-/* If we need to support > 4096, just expand this to be a 64 bit
- * union, or consider tiling in Z as well.
- */
-union tex_tile_address {
-   struct {
-      unsigned x:6;             /* 4096 / TEX_TILE_SIZE */
-      unsigned y:6;             /* 4096 / TEX_TILE_SIZE */
-      unsigned z:12;            /* 4096 -- z not tiled */
-      unsigned face:3;
-      unsigned level:4;
-      unsigned invalid:1;
-   } bits;
-   unsigned value;
-};
-
-
-struct llvmpipe_cached_tex_tile
-{
-   union tex_tile_address addr;
-   uint8_t color[TEX_TILE_SIZE][TEX_TILE_SIZE][4];
-};
-
-#define NUM_ENTRIES 50
-
-
-/** XXX move these */
-#define MAX_TEX_WIDTH 2048
-#define MAX_TEX_HEIGHT 2048
-
-
-struct llvmpipe_tex_tile_cache
-{
-   struct pipe_screen *screen;
-   struct pipe_surface *surface;  /**< the surface we're caching */
-   struct pipe_transfer *transfer;
-   void *transfer_map;
-
-   struct pipe_texture *texture;  /**< if caching a texture */
-   unsigned timestamp;
-
-   struct llvmpipe_cached_tex_tile entries[NUM_ENTRIES];
-
-   struct pipe_transfer *tex_trans;
-   void *tex_trans_map;
-   int tex_face, tex_level, tex_z;
-
-   struct llvmpipe_cached_tex_tile *last_tile;  /**< most recently retrieved tile */
-};
-
-
-extern struct llvmpipe_tex_tile_cache *
-lp_create_tex_tile_cache( struct pipe_screen *screen );
-
-extern void
-lp_destroy_tex_tile_cache(struct llvmpipe_tex_tile_cache *tc);
-
-extern void
-lp_tex_tile_cache_map_transfers(struct llvmpipe_tex_tile_cache *tc);
-
-extern void
-lp_tex_tile_cache_unmap_transfers(struct llvmpipe_tex_tile_cache *tc);
-
-extern void
-lp_tex_tile_cache_set_texture(struct llvmpipe_tex_tile_cache *tc,
-                          struct pipe_texture *texture);
-
-void
-lp_tex_tile_cache_validate_texture(struct llvmpipe_tex_tile_cache *tc);
-
-extern const struct llvmpipe_cached_tex_tile *
-lp_find_cached_tex_tile(struct llvmpipe_tex_tile_cache *tc,
-                        union tex_tile_address addr );
-
-static INLINE union tex_tile_address
-tex_tile_address( unsigned x,
-                  unsigned y,
-                  unsigned z,
-                  unsigned face,
-                  unsigned level )
-{
-   union tex_tile_address addr;
-
-   addr.value = 0;
-   addr.bits.x = x / TEX_TILE_SIZE;
-   addr.bits.y = y / TEX_TILE_SIZE;
-   addr.bits.z = z;
-   addr.bits.face = face;
-   addr.bits.level = level;
-      
-   return addr;
-}
-
-/* Quickly retrieve tile if it matches last lookup.
- */
-static INLINE const struct llvmpipe_cached_tex_tile *
-lp_get_cached_tex_tile(struct llvmpipe_tex_tile_cache *tc,
-                       union tex_tile_address addr )
-{
-   if (tc->last_tile->addr.value == addr.value)
-      return tc->last_tile;
-
-   return lp_find_cached_tex_tile( tc, addr );
-}
-
-
-#endif /* LP_TEX_CACHE_H */
-
index d2a6ae21f57ab5670aabe66785a2d42b3915196c..d59d76813987e388dde233fe3af2f9c7d15da2e2 100644 (file)
@@ -47,7 +47,7 @@
 #include "lp_bld_intr.h"
 #include "lp_bld_sample.h"
 #include "lp_bld_tgsi.h"
-#include "lp_state.h"
+#include "lp_jit.h"
 #include "lp_tex_sample.h"
 
 
index 2c135029ea2d1b5bd817c6f6d8ca5485bfe19fe3..2462378152ab9c3000c6a1f19814a88bd72b0ed0 100644 (file)
@@ -42,7 +42,6 @@
 #include "lp_context.h"
 #include "lp_state.h"
 #include "lp_texture.h"
-#include "lp_tex_cache.h"
 #include "lp_screen.h"
 #include "lp_winsys.h"
 
@@ -236,7 +235,7 @@ llvmpipe_get_tex_surface(struct pipe_screen *screen,
 
       if (ps->usage & (PIPE_BUFFER_USAGE_CPU_WRITE |
                        PIPE_BUFFER_USAGE_GPU_WRITE)) {
-         /* Mark the surface as dirty.  The tile cache will look for this. */
+         /* Mark the surface as dirty. */
          lpt->timestamp++;
          llvmpipe_screen(screen)->timestamp++;
       }
@@ -373,7 +372,6 @@ llvmpipe_transfer_map( struct pipe_screen *_screen,
    if (transfer->texture && (transfer->usage & PIPE_TRANSFER_WRITE))
    {
       /* Do something to notify sharing contexts of a texture change.
-       * In llvmpipe, that would mean flushing the texture cache.
        */
       screen->timestamp++;
    }
diff --git a/src/gallium/drivers/llvmpipe/lp_tile_cache.c b/src/gallium/drivers/llvmpipe/lp_tile_cache.c
deleted file mode 100644 (file)
index 7a1ecf5..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-/**************************************************************************
- * 
- * 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 tile caching.
- *
- * Author:
- *    Brian Paul
- */
-
-#include "pipe/p_inlines.h"
-#include "util/u_memory.h"
-#include "util/u_math.h"
-#include "util/u_tile.h"
-#include "util/u_rect.h"
-#include "lp_context.h"
-#include "lp_surface.h"
-#include "lp_texture.h"
-#include "lp_tile_soa.h"
-#include "lp_tile_cache.h"
-
-
-#define MAX_WIDTH 4096
-#define MAX_HEIGHT 4096
-
-
-enum llvmpipe_tile_status
-{
-   LP_TILE_STATUS_UNDEFINED = 0,
-   LP_TILE_STATUS_CLEAR = 1,
-   LP_TILE_STATUS_DEFINED = 2
-};
-
-
-struct llvmpipe_cached_tile
-{
-   enum llvmpipe_tile_status status;
-
-   /** color in SOA format */
-   uint8_t *color;
-};
-
-
-struct llvmpipe_tile_cache
-{
-   struct pipe_screen *screen;
-   struct pipe_surface *surface;  /**< the surface we're caching */
-   struct pipe_transfer *transfer;
-   void *transfer_map;
-
-   struct llvmpipe_cached_tile entries[MAX_WIDTH/TILE_SIZE][MAX_HEIGHT/TILE_SIZE];
-
-   uint8_t clear_color[4];  /**< for color bufs */
-   uint clear_val;        /**< for z+stencil, or packed color clear value */
-
-   struct llvmpipe_cached_tile *last_tile;  /**< most recently retrieved tile */
-};
-
-
-struct llvmpipe_tile_cache *
-lp_create_tile_cache( struct pipe_screen *screen )
-{
-   struct llvmpipe_tile_cache *tc;
-   int maxLevels, maxTexSize;
-
-   /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */
-   maxLevels = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
-   maxTexSize = 1 << (maxLevels - 1);
-   assert(MAX_WIDTH >= maxTexSize);
-
-   tc = CALLOC_STRUCT( llvmpipe_tile_cache );
-   if(!tc)
-      return NULL;
-
-   tc->screen = screen;
-
-   return tc;
-}
-
-
-void
-lp_destroy_tile_cache(struct llvmpipe_tile_cache *tc)
-{
-   struct pipe_screen *screen;
-   unsigned x, y;
-
-   for (y = 0; y < MAX_HEIGHT; y += TILE_SIZE) {
-      for (x = 0; x < MAX_WIDTH; x += TILE_SIZE) {
-         struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
-
-         if(tile->color)
-            align_free(tile->color);
-      }
-   }
-
-   if (tc->transfer) {
-      screen = tc->transfer->texture->screen;
-      screen->tex_transfer_destroy(tc->transfer);
-   }
-
-   FREE( tc );
-}
-
-
-/**
- * Specify the surface to cache.
- */
-void
-lp_tile_cache_set_surface(struct llvmpipe_tile_cache *tc,
-                          struct pipe_surface *ps)
-{
-   if (tc->transfer) {
-      struct pipe_screen *screen = tc->transfer->texture->screen;
-
-      if (ps == tc->surface)
-         return;
-
-      if (tc->transfer_map) {
-         screen->transfer_unmap(screen, tc->transfer);
-         tc->transfer_map = NULL;
-      }
-
-      screen->tex_transfer_destroy(tc->transfer);
-      tc->transfer = NULL;
-   }
-
-   tc->surface = ps;
-
-   if (ps) {
-      struct pipe_screen *screen = ps->texture->screen;
-      unsigned x, y;
-
-      tc->transfer = screen->get_tex_transfer(screen, ps->texture, ps->face,
-                                              ps->level, ps->zslice,
-                                              PIPE_TRANSFER_READ_WRITE,
-                                              0, 0, ps->width, ps->height);
-
-      for (y = 0; y < ps->height; y += TILE_SIZE) {
-         for (x = 0; x < ps->width; x += TILE_SIZE) {
-            struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
-
-            tile->status = LP_TILE_STATUS_UNDEFINED;
-
-            if(!tile->color)
-               tile->color = align_malloc( TILE_SIZE*TILE_SIZE*NUM_CHANNELS, 16 );
-         }
-      }
-   }
-}
-
-
-/**
- * Return the transfer being cached.
- */
-struct pipe_surface *
-lp_tile_cache_get_surface(struct llvmpipe_tile_cache *tc)
-{
-   return tc->surface;
-}
-
-
-void
-lp_tile_cache_map_transfers(struct llvmpipe_tile_cache *tc)
-{
-   if (tc->transfer && !tc->transfer_map)
-      tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
-}
-
-
-void
-lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache *tc)
-{
-   if (tc->transfer_map) {
-      tc->screen->transfer_unmap(tc->screen, tc->transfer);
-      tc->transfer_map = NULL;
-   }
-}
-
-
-/**
- * Set a tile to a solid color.
- */
-static void
-clear_tile(struct llvmpipe_cached_tile *tile,
-           uint8_t clear_color[4])
-{
-   if (clear_color[0] == clear_color[1] &&
-       clear_color[1] == clear_color[2] &&
-       clear_color[2] == clear_color[3]) {
-      memset(tile->color, clear_color[0], TILE_SIZE * TILE_SIZE * 4);
-   }
-   else {
-      uint x, y, chan;
-      for (y = 0; y < TILE_SIZE; y++)
-         for (x = 0; x < TILE_SIZE; x++)
-            for (chan = 0; chan < 4; ++chan)
-               TILE_PIXEL(tile->color, x, y, chan) = clear_color[chan];
-   }
-}
-
-
-/**
- * Flush the tile cache: write all dirty tiles back to the transfer.
- * any tiles "flagged" as cleared will be "really" cleared.
- */
-void
-lp_flush_tile_cache(struct llvmpipe_tile_cache *tc)
-{
-   struct pipe_transfer *pt = tc->transfer;
-   unsigned x, y;
-
-   if(!pt)
-      return;
-
-   assert(tc->transfer_map);
-
-   /* push the tile to all positions marked as clear */
-   for (y = 0; y < pt->height; y += TILE_SIZE) {
-      for (x = 0; x < pt->width; x += TILE_SIZE) {
-         struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
-
-         if(tile->status != LP_TILE_STATUS_UNDEFINED) {
-            unsigned w = TILE_SIZE;
-            unsigned h = TILE_SIZE;
-
-            if (!pipe_clip_tile(x, y, &w, &h, pt)) {
-               switch(tile->status) {
-               case LP_TILE_STATUS_CLEAR:
-                  /* Actually clear the tiles which were flagged as being in a
-                   * clear state. */
-                  util_fill_rect(tc->transfer_map, pt->texture->format, pt->stride,
-                                 x, y, w, h,
-                                 tc->clear_val);
-                  break;
-
-               case LP_TILE_STATUS_DEFINED:
-                  lp_tile_write_4ub(pt->texture->format,
-                                    tile->color,
-                                    tc->transfer_map, pt->stride,
-                                    x, y, w, h);
-                  break;
-
-               default:
-                  assert(0);
-                  break;
-               }
-            }
-
-            tile->status = LP_TILE_STATUS_UNDEFINED;
-         }
-      }
-   }
-}
-
-
-/**
- * Get a tile from the cache.
- * \param x, y  position of tile, in pixels
- */
-void *
-lp_get_cached_tile(struct llvmpipe_tile_cache *tc,
-                   unsigned x, unsigned y )
-{
-   struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
-   struct pipe_transfer *pt = tc->transfer;
-   
-   assert(tc->surface);
-   assert(tc->transfer);
-
-   if(!tc->transfer_map)
-      lp_tile_cache_map_transfers(tc);
-
-   assert(tc->transfer_map);
-
-   switch(tile->status) {
-   case LP_TILE_STATUS_CLEAR:
-      /* don't get tile from framebuffer, just clear it */
-      clear_tile(tile, tc->clear_color);
-      tile->status = LP_TILE_STATUS_DEFINED;
-      break;
-
-   case LP_TILE_STATUS_UNDEFINED: {
-      unsigned w = TILE_SIZE;
-      unsigned h = TILE_SIZE;
-
-      x &= ~(TILE_SIZE - 1);
-      y &= ~(TILE_SIZE - 1);
-
-      if (!pipe_clip_tile(x, y, &w, &h, tc->transfer))
-         lp_tile_read_4ub(pt->texture->format,
-                          tile->color,
-                          tc->transfer_map, tc->transfer->stride,
-                          x, y, w, h);
-
-      tile->status = LP_TILE_STATUS_DEFINED;
-      break;
-   }
-
-   case LP_TILE_STATUS_DEFINED:
-      /* nothing to do */
-      break;
-   }
-
-   return tile->color;
-}
-
-
-/**
- * When a whole surface is being cleared to a value we can avoid
- * fetching tiles above.
- * Save the color and set a 'clearflag' for each tile of the screen.
- */
-void
-lp_tile_cache_clear(struct llvmpipe_tile_cache *tc, const float *rgba,
-                    uint clearValue)
-{
-   struct pipe_transfer *pt = tc->transfer;
-   const unsigned w = pt->width;
-   const unsigned h = pt->height;
-   unsigned x, y, chan;
-
-   for(chan = 0; chan < 4; ++chan)
-      tc->clear_color[chan] = float_to_ubyte(rgba[chan]);
-
-   tc->clear_val = clearValue;
-
-   /* push the tile to all positions marked as clear */
-   for (y = 0; y < h; y += TILE_SIZE) {
-      for (x = 0; x < w; x += TILE_SIZE) {
-         struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
-         tile->status = LP_TILE_STATUS_CLEAR;
-      }
-   }
-}
diff --git a/src/gallium/drivers/llvmpipe/lp_tile_cache.h b/src/gallium/drivers/llvmpipe/lp_tile_cache.h
deleted file mode 100644 (file)
index 161bab3..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/**************************************************************************
- * 
- * 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 LP_TILE_CACHE_H
-#define LP_TILE_CACHE_H
-
-
-#include "pipe/p_compiler.h"
-#include "lp_tile_soa.h"
-
-
-struct llvmpipe_tile_cache;  /* opaque */
-
-
-extern struct llvmpipe_tile_cache *
-lp_create_tile_cache( struct pipe_screen *screen );
-
-extern void
-lp_destroy_tile_cache(struct llvmpipe_tile_cache *tc);
-
-extern void
-lp_tile_cache_set_surface(struct llvmpipe_tile_cache *tc,
-                          struct pipe_surface *lps);
-
-extern struct pipe_surface *
-lp_tile_cache_get_surface(struct llvmpipe_tile_cache *tc);
-
-extern void
-lp_tile_cache_map_transfers(struct llvmpipe_tile_cache *tc);
-
-extern void
-lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache *tc);
-
-extern void
-lp_flush_tile_cache(struct llvmpipe_tile_cache *tc);
-
-extern void
-lp_tile_cache_clear(struct llvmpipe_tile_cache *tc, const float *rgba,
-                    uint clearValue);
-
-extern void *
-lp_get_cached_tile(struct llvmpipe_tile_cache *tc,
-                   unsigned x, unsigned y );
-
-
-#endif /* LP_TILE_CACHE_H */
-
index 19d00b58d37aeb73e5b482a7292c36abce074d54..1b7be3cce0d010d9e76f7016fc92cb342edb15b3 100644 (file)
@@ -43,23 +43,24 @@ struct pipe_transfer;
 /**
  * Cache tile size (width and height). This needs to be a power of two.
  */
-#define TILE_SIZE 64
+#define TILE_ORDER 6
+#define TILE_SIZE (1 << TILE_ORDER)
 
 
-#define TILE_VECTOR_HEIGHT 2
-#define TILE_VECTOR_WIDTH 8
+#define TILE_VECTOR_HEIGHT 4
+#define TILE_VECTOR_WIDTH 4
 
 extern const unsigned char
 tile_offset[TILE_VECTOR_HEIGHT][TILE_VECTOR_WIDTH];
 
-#define TILE_C_STRIDE (TILE_VECTOR_HEIGHT*TILE_VECTOR_WIDTH)
-#define TILE_X_STRIDE (NUM_CHANNELS*TILE_C_STRIDE)
-#define TILE_Y_STRIDE (TILE_VECTOR_HEIGHT*TILE_SIZE*NUM_CHANNELS)
+#define TILE_C_STRIDE (TILE_VECTOR_HEIGHT * TILE_VECTOR_WIDTH)
+#define TILE_X_STRIDE (NUM_CHANNELS * TILE_C_STRIDE)
+#define TILE_Y_STRIDE (TILE_VECTOR_HEIGHT * TILE_SIZE * NUM_CHANNELS)
 
 #define TILE_PIXEL(_p, _x, _y, _c) \
-   ((_p)[((_y)/TILE_VECTOR_HEIGHT)*TILE_Y_STRIDE + \
-         ((_x)/TILE_VECTOR_WIDTH)*TILE_X_STRIDE + \
-         (_c)*TILE_C_STRIDE + \
+   ((_p)[((_y) / TILE_VECTOR_HEIGHT) * TILE_Y_STRIDE + \
+         ((_x) / TILE_VECTOR_WIDTH) * TILE_X_STRIDE + \
+         (_c) * TILE_C_STRIDE + \
          tile_offset[(_y) % TILE_VECTOR_HEIGHT][(_x) % TILE_VECTOR_WIDTH]])
 
 
index 004c5c979e30d848c05e65b023a6959bed2fbc34..a603b7f9f4250a476ade455ae9c719a0de0bbc64 100644 (file)
@@ -259,8 +259,10 @@ def main():
     print
     print 'const unsigned char'
     print 'tile_offset[TILE_VECTOR_HEIGHT][TILE_VECTOR_WIDTH] = {'
-    print '   {  0,  1,  4,  5,  8,  9, 12, 13},'
-    print '   {  2,  3,  6,  7, 10, 11, 14, 15}'
+    print '   {  0,  1,  4,  5},'
+    print '   {  2,  3,  6,  7},'
+    print '   {  8,  9, 12, 13},'
+    print '   { 10, 11, 14, 15}'
     print '};'
     print
 
index 25e414823256d4f41202049acde9630052aed758..8119c1f571c25de8a63254e4b2156850661f0899 100644 (file)
@@ -27,7 +27,8 @@
 /**
  * @file
  * 
- * Thread, mutex, condition var and thread-specific data functions.
+ * Thread, mutex, condition variable, barrier, semaphore and
+ * thread-specific data functions.
  */
 
 
@@ -46,6 +47,8 @@
 
 #define PIPE_THREAD_HAVE_CONDVAR
 
+/* pipe_thread
+ */
 typedef pthread_t pipe_thread;
 
 #define PIPE_THREAD_ROUTINE( name, param ) \
@@ -69,8 +72,10 @@ static INLINE int pipe_thread_destroy( pipe_thread thread )
    return pthread_detach( thread );
 }
 
+
+/* pipe_mutex
+ */
 typedef pthread_mutex_t pipe_mutex;
-typedef pthread_cond_t pipe_condvar;
 
 #define pipe_static_mutex(mutex) \
    static pipe_mutex mutex = PTHREAD_MUTEX_INITIALIZER
@@ -87,6 +92,11 @@ typedef pthread_cond_t pipe_condvar;
 #define pipe_mutex_unlock(mutex) \
    (void) pthread_mutex_unlock(&(mutex))
 
+
+/* pipe_condvar
+ */
+typedef pthread_cond_t pipe_condvar;
+
 #define pipe_static_condvar(mutex) \
    static pipe_condvar mutex = PTHREAD_COND_INITIALIZER
 
@@ -106,10 +116,32 @@ typedef pthread_cond_t pipe_condvar;
   pthread_cond_broadcast(&(cond))
 
 
+/* pipe_barrier
+ */
+typedef pthread_barrier_t pipe_barrier;
+
+static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
+{
+   pthread_barrier_init(barrier, NULL, count);
+}
+
+static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
+{
+   pthread_barrier_destroy(barrier);
+}
+
+static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
+{
+   pthread_barrier_wait(barrier);
+}
+
+
 #elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
 
 #include <windows.h>
 
+/* pipe_thread
+ */
 typedef HANDLE pipe_thread;
 
 #define PIPE_THREAD_ROUTINE( name, param ) \
@@ -135,6 +167,9 @@ static INLINE int pipe_thread_destroy( pipe_thread thread )
    return -1;
 }
 
+
+/* pipe_mutex
+ */
 typedef CRITICAL_SECTION pipe_mutex;
 
 #define pipe_static_mutex(mutex) \
@@ -152,15 +187,48 @@ typedef CRITICAL_SECTION pipe_mutex;
 #define pipe_mutex_unlock(mutex) \
    LeaveCriticalSection(&mutex)
 
-/* XXX: dummy definitions, make it compile */
 
+/* pipe_condvar (XXX FIX THIS)
+ */
 typedef unsigned pipe_condvar;
 
-#define pipe_condvar_init(condvar) \
-   (void) condvar
+#define pipe_condvar_init(cond) \
+   (void) cond
+
+#define pipe_condvar_destroy(cond) \
+   (void) cond
+
+#define pipe_condvar_wait(cond, mutex) \
+   (void) cond; (void) mutex
+
+#define pipe_condvar_signal(cond) \
+   (void) cond
+
+#define pipe_condvar_broadcast(cond) \
+   (void) cond
+
+
+/* pipe_barrier (XXX FIX THIS)
+ */
+typedef unsigned pipe_barrier;
+
+static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
+{
+   /* XXX we could implement barriers with a mutex and condition var */
+   assert(0);
+}
+
+static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
+{
+   assert(0);
+}
+
+static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
+{
+   assert(0);
+}
+
 
-#define pipe_condvar_broadcast(condvar) \
-   (void) condvar
 
 #else
 
@@ -169,6 +237,7 @@ typedef unsigned pipe_condvar;
 typedef unsigned pipe_thread;
 typedef unsigned pipe_mutex;
 typedef unsigned pipe_condvar;
+typedef unsigned pipe_barrier;
 
 #define pipe_static_mutex(mutex) \
    static pipe_mutex mutex = 0
@@ -204,9 +273,77 @@ typedef unsigned pipe_condvar;
    (void) condvar
 
 
+static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
+{
+   /* XXX we could implement barriers with a mutex and condition var */
+   assert(0);
+}
+
+static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
+{
+   assert(0);
+}
+
+static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
+{
+   assert(0);
+}
+
+
+
 #endif  /* PIPE_OS_? */
 
 
+/*
+ * Semaphores
+ */
+
+typedef struct
+{
+   pipe_mutex mutex;
+   pipe_condvar cond;
+   int counter;
+} pipe_semaphore;
+
+
+static INLINE void
+pipe_semaphore_init(pipe_semaphore *sema, int init_val)
+{
+   pipe_mutex_init(sema->mutex);
+   pipe_condvar_init(sema->cond);
+   sema->counter = init_val;
+}
+
+static INLINE void
+pipe_semaphore_destroy(pipe_semaphore *sema)
+{
+   pipe_mutex_destroy(sema->mutex);
+   pipe_condvar_destroy(sema->cond);
+}
+
+/** Signal/increment semaphore counter */
+static INLINE void
+pipe_semaphore_signal(pipe_semaphore *sema)
+{
+   pipe_mutex_lock(sema->mutex);
+   sema->counter++;
+   pipe_condvar_signal(sema->cond);
+   pipe_mutex_unlock(sema->mutex);
+}
+
+/** Wait for semaphore counter to be greater than zero */
+static INLINE void
+pipe_semaphore_wait(pipe_semaphore *sema)
+{
+   pipe_mutex_lock(sema->mutex);
+   while (sema->counter <= 0) {
+      pipe_condvar_wait(sema->cond, sema->mutex);
+   }
+   sema->counter--;
+   pipe_mutex_unlock(sema->mutex);
+}
+
+
 
 /*
  * Thread-specific data.