Merge remote branch 'origin/lp-binning'
authorJosé Fonseca <jfonseca@vmware.com>
Fri, 5 Feb 2010 13:48:35 +0000 (13:48 +0000)
committerJosé Fonseca <jfonseca@vmware.com>
Fri, 5 Feb 2010 13:48:35 +0000 (13:48 +0000)
Conflicts:
src/gallium/auxiliary/util/u_dl.c
src/gallium/auxiliary/util/u_time.h
src/gallium/drivers/llvmpipe/lp_state_derived.c
src/gallium/drivers/llvmpipe/lp_state_surface.c
src/gallium/drivers/llvmpipe/lp_tex_cache.c
src/gallium/drivers/llvmpipe/lp_tile_cache.c

80 files changed:
Makefile
configs/linux-llvm
configs/linux-llvm-debug [new file with mode: 0644]
progs/demos/engine.c
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-scissor-tri.c
progs/trivial/tri-z-eq.c
src/gallium/auxiliary/os/os_thread.h
src/gallium/auxiliary/util/u_debug.c
src/gallium/auxiliary/util/u_debug.h
src/gallium/auxiliary/util/u_ringbuffer.c
src/gallium/auxiliary/util/u_surface.c
src/gallium/auxiliary/util/u_surface.h
src/gallium/auxiliary/util/u_time.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_sample_soa.c
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_debug.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.c
src/gallium/drivers/llvmpipe/lp_jit.h
src/gallium/drivers/llvmpipe/lp_perf.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_perf.h [new file with mode: 0644]
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_texture.h
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_size.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_tile_soa.h
src/gallium/drivers/llvmpipe/lp_tile_soa.py

index 16395bcc8b99f4863a2f5ea717e7683a3c827901..bf8debfd5b37a8aa465ad2f88e4bdd813d8ef4cf 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-opengl-es \
 linux-osmesa \
 linux-osmesa-static \
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 7e485111da7774296c199adde78e3e71d5eda6b4..a4148357d49031a14b0aeeda671729e41727ad77 100644 (file)
@@ -26,6 +26,8 @@
 /* Target engine speed: */
 const int RPM = 100.0;
 
+static int Win = 0;
+
 
 /**
  * Engine description.
@@ -1154,6 +1156,7 @@ OptRotate(void)
 static void
 OptExit(void)
 {
+   glutDestroyWindow(Win);
    exit(0);
 }
 
@@ -1323,7 +1326,7 @@ main(int argc, char *argv[])
    glutInitWindowSize(WinWidth, WinHeight);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
-   glutCreateWindow("OpenGL Engine Demo");
+   Win = glutCreateWindow("OpenGL Engine Demo");
    glewInit();
    glutReshapeFunc(Reshape);
    glutMouseFunc(Mouse);
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 207215dee958511ec3217c1e671572f8ada3aff0..6c78ae90a9689506c302ccc43e5df3fb7f9f9471 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 e9ed1cb71e07c8e6463fc0eb3571cffed0240983..87a4d2164bd114bc69e25198ee6d476f9f9d36e9 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 d65502d91b959688496123b50d2a08cc297bae6e..1bb15501bbd6decc4ee770cc9eb201e6bd243b45 100644 (file)
 #define CI_OFFSET_1 16
 #define CI_OFFSET_2 32
 
-GLint Width = 250, Height = 250;
+GLint Width = 300, Height = 300;
 
 GLenum doubleBuffer;
 
+/* scissor bounds */
+static GLint Left, Right, Bottom, Top;
+
+
 static void Init(void)
 {
    fprintf(stderr, "GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
@@ -47,26 +51,57 @@ static void Init(void)
 
 static void Reshape(int width, int height)
 {
-
     glViewport(0, 0, (GLint)width, (GLint)height);
 
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     glOrtho(-1.0, 1.0, -1.0, 1.0, -0.5, 1000.0);
     glMatrixMode(GL_MODELVIEW);
+
+    Width = width;
+    Height = height;
+
+    Left = Width / 4;
+    Right = Width * 3 / 4;
+    Bottom = Height / 4;
+    Top = Height * 3 / 4;
 }
 
 static void Key(unsigned char key, int x, int y)
 {
+   int step = 2;
+   switch (key) {
+   case 'l':
+      Left -= step;
+      break;
+   case 'L':
+      Left += step;
+      break;
+   case 'r':
+      Right -= step;
+      break;
+   case 'R':
+      Right += step;
+      break;
+   case 'b':
+      Bottom -= step;
+      break;
+   case 'B':
+      Bottom += step;
+      break;
+   case 't':
+      Top -= step;
+      break;
+   case 'T':
+      Top += step;
+      break;
+   case 27:
+      exit(1);
+   default:
+      ;
+   }
 
-    switch (key) {
-      case 27:
-       exit(1);
-      default:
-       break;
-    }
-
-    glutPostRedisplay();
+   glutPostRedisplay();
 }
 
 static void Draw(void)
@@ -82,7 +117,8 @@ static void Draw(void)
    glVertex3f(-0.9,  0.0, -30.0);
    glEnd();
 
-   glScissor(Width / 4, Height / 4, Width / 2, Height / 2);
+   printf("Scissor %d, %d .. %d, %d\n", Left, Bottom, Right, Top);
+   glScissor(Left, Bottom, Right-Left, Top-Bottom);
    glEnable(GL_SCISSOR_TEST);
 
    glBegin(GL_TRIANGLES);
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 2da5fd77386901c07cd2b20875492f1c77e1eeb0..24a2309976a8449f3c3ff53ffa3650bba391b800 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
 
@@ -188,6 +256,7 @@ static INLINE int pipe_thread_destroy( pipe_thread thread )
 
 typedef unsigned pipe_mutex;
 typedef unsigned pipe_condvar;
+typedef unsigned pipe_barrier;
 
 #define pipe_static_mutex(mutex) \
    static pipe_mutex mutex = 0
@@ -223,9 +292,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.
index a8d18333d8999ad140eb8cde7dfc20885dd33097..4821b8a1434f87db2e3ef7c0a04fb8f715d2ce70 100644 (file)
@@ -440,6 +440,14 @@ const char *u_prim_name( unsigned prim )
 
 
 #ifdef DEBUG
+/**
+ * Dump an image to a .raw or .ppm file (depends on OS).
+ * \param format  PIPE_FORMAT_x
+ * \param cpp  bytes per pixel
+ * \param width  width in pixels
+ * \param height height in pixels
+ * \param stride  row stride in bytes
+ */
 void debug_dump_image(const char *prefix,
                       unsigned format, unsigned cpp,
                       unsigned width, unsigned height,
@@ -481,6 +489,52 @@ void debug_dump_image(const char *prefix,
    }
       
    EngUnmapFile(iFile);
+#elif defined(PIPE_OS_UNIX)
+   /* write a ppm file */
+   char filename[256];
+   FILE *f;
+
+   util_snprintf(filename, sizeof(filename), "%s.ppm", prefix);
+
+   f = fopen(filename, "w");
+   if (f) {
+      int i, x, y;
+      int r, g, b;
+      const uint8_t *ptr = (uint8_t *) data;
+
+      /* XXX this is a hack */
+      switch (format) {
+      case PIPE_FORMAT_A8R8G8B8_UNORM:
+         r = 2;
+         g = 1;
+         b = 0;
+         break;
+      default:
+         r = 0;
+         g = 1;
+         b = 1;
+      }
+
+      fprintf(f, "P6\n");
+      fprintf(f, "# ppm-file created by osdemo.c\n");
+      fprintf(f, "%i %i\n", width, height);
+      fprintf(f, "255\n");
+      fclose(f);
+
+      f = fopen(filename, "ab");  /* reopen in binary append mode */
+      for (y = 0; y < height; y++) {
+         for (x = 0; x < width; x++) {
+            i = y * stride + x * cpp;
+            fputc(ptr[i + r], f); /* write red */
+            fputc(ptr[i + g], f); /* write green */
+            fputc(ptr[i + b], f); /* write blue */
+         }
+      }
+      fclose(f);
+   }
+   else {
+      fprintf(stderr, "Can't open %s for writing\n", filename);
+   }
 #endif
 }
 
@@ -521,6 +575,27 @@ error:
 }
 
 
+void debug_dump_texture(const char *prefix,
+                        struct pipe_texture *texture)
+{
+   struct pipe_surface *surface;
+   struct pipe_screen *screen;
+
+   if (!texture)
+      return;
+
+   screen = texture->screen;
+
+   /* XXX for now, just dump image for face=0, level=0 */
+   surface = screen->get_tex_surface(screen, texture, 0, 0, 0,
+                                     PIPE_TEXTURE_USAGE_SAMPLER);
+   if (surface) {
+      debug_dump_surface(prefix, surface);
+      screen->tex_surface_destroy(surface);
+   }
+}
+
+
 #pragma pack(push,2)
 struct bmp_file_header {
    uint16_t bfType;
index eadc08fe2a0ad83bce8a1185a3d1178fef83cfdd..efcf065d276d991c557e84aca540758c55ac3a14 100644 (file)
@@ -314,6 +314,8 @@ debug_memory_end(unsigned long beginning);
 #ifdef DEBUG
 struct pipe_surface;
 struct pipe_transfer;
+struct pipe_texture;
+
 void debug_dump_image(const char *prefix,
                       unsigned format, unsigned cpp,
                       unsigned width, unsigned height,
@@ -321,6 +323,8 @@ void debug_dump_image(const char *prefix,
                       const void *data);
 void debug_dump_surface(const char *prefix,
                         struct pipe_surface *surface);   
+void debug_dump_texture(const char *prefix,
+                        struct pipe_texture *texture);
 void debug_dump_surface_bmp(const char *filename,
                             struct pipe_surface *surface);
 void debug_dump_transfer_bmp(const char *filename,
index 95d45ebb71fd634d2811764a8f60f469093ae921..648b105b137524b3851b1dc3710e8333a79d2dc3 100644 (file)
@@ -53,11 +53,22 @@ void util_ringbuffer_destroy( struct util_ringbuffer *ring )
    FREE(ring);
 }
 
+/**
+ * Return number of free entries in the ring
+ */
 static INLINE unsigned util_ringbuffer_space( const struct util_ringbuffer *ring )
 {
    return (ring->tail - (ring->head + 1)) & ring->mask;
 }
 
+/**
+ * Is the ring buffer empty?
+ */
+static INLINE boolean util_ringbuffer_empty( const struct util_ringbuffer *ring )
+{
+   return util_ringbuffer_space(ring) == ring->mask;
+}
+
 void util_ringbuffer_enqueue( struct util_ringbuffer *ring,
                               const struct util_packet *packet )
 {
@@ -67,6 +78,10 @@ void util_ringbuffer_enqueue( struct util_ringbuffer *ring,
     */
    pipe_mutex_lock(ring->mutex);
 
+   /* make sure we don't request an impossible amount of space
+    */
+   assert(packet->dwords <= ring->mask);
+
    /* Wait for free space:
     */
    while (util_ringbuffer_space(ring) < packet->dwords)
@@ -104,14 +119,14 @@ enum pipe_error util_ringbuffer_dequeue( struct util_ringbuffer *ring,
     */
    pipe_mutex_lock(ring->mutex);
 
-   /* Wait for free space:
+   /* Get next ring entry:
     */
    if (wait) {
-      while (util_ringbuffer_space(ring) == 0)
+      while (util_ringbuffer_empty(ring))
          pipe_condvar_wait(ring->change, ring->mutex);
    }
    else {
-      if (util_ringbuffer_space(ring) == 0) {
+      if (util_ringbuffer_empty(ring)) {
          ret = PIPE_ERROR_OUT_OF_MEMORY;
          goto out;
       }
index 6053c111e340e4ed0c5e970c22c08f01258b60de..c9f1c9c210f7ca342a126cc5ca7a453b77f9a519 100644 (file)
@@ -37,6 +37,7 @@
 #include "pipe/p_defines.h"
 #include "util/u_inlines.h"
 
+#include "util/u_memory.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 7580ac0de4ce468ce77e6d6ff7f3bac5cbada059..15899c2c884064d09ce801b59a38bb3301a42259 100644 (file)
@@ -67,6 +67,9 @@ util_time_get(struct util_time *t)
 }
 
 
+/**
+ * Return t2 = t1 + usecs
+ */
 PIPE_DEPRECATED
 static INLINE void
 util_time_add(const struct util_time *t1,
@@ -77,6 +80,9 @@ util_time_add(const struct util_time *t1,
 }
 
 
+/**
+ * Return difference between times, in microseconds
+ */
 PIPE_DEPRECATED
 static INLINE int64_t
 util_time_diff(const struct util_time *t1, 
@@ -105,6 +111,9 @@ _util_time_compare(const struct util_time *t1,
 }
 
 
+/**
+ * Returns non-zero when the timeout expires.
+ */
 PIPE_DEPRECATED
 static INLINE boolean
 util_time_timeout(const struct util_time *start, 
@@ -115,6 +124,9 @@ util_time_timeout(const struct util_time *start,
 }
 
 
+/**
+ * Return current time in microseconds
+ */
 PIPE_DEPRECATED
 static INLINE int64_t
 util_time_micros(void)
index 7c6e46006b9569736fc31873684cf179aef481ec..899af6acf843459b466ad95278eb29759968b572 100644 (file)
@@ -3,7 +3,7 @@ include $(TOP)/configs/current
 
 LIBNAME = llvmpipe
 
-CFLAGS += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
+DEFINES += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
 
 C_SOURCES = \
        lp_bld_alpha.c \
@@ -33,12 +33,21 @@ 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_setup.c \
+       lp_perf.c \
        lp_query.c \
+       lp_rast.c \
+       lp_rast_tri.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 \
@@ -49,10 +58,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 = \
@@ -62,3 +69,8 @@ include ../../Makefile.template
 
 lp_tile_soa.c: lp_tile_soa.py ../../auxiliary/util/u_format_parse.py ../../auxiliary/util/u_format_access.py ../../auxiliary/util/u_format.csv
        python lp_tile_soa.py ../../auxiliary/util/u_format.csv > $@
+
+
+# to make a .s file to inspect assembly code
+.c.s:
+       $(CC) -S $(INCLUDES) $(DEFINES) $(CFLAGS) $(LIBRARY_DEFINES) $<
index 563220f17fef1c2ca7333d8c4f353f93f0020b2c..840cb0950ec362a90be6863f0a567d26f7ba4c77 100644 (file)
@@ -32,16 +32,16 @@ llvmpipe = env.ConvenienceLibrary(
                'lp_bld_depth.c',
                'lp_bld_flow.c',
                'lp_bld_format_aos.c',
-        'lp_bld_format_query.c',
+               'lp_bld_format_query.c',
                '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_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,21 @@ 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_perf.c',
                'lp_query.c',
+               'lp_rast.c',
+               'lp_rast_tri.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 +74,8 @@ llvmpipe = env.ConvenienceLibrary(
                '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',
        ])
 
index 1aee9b35f31cd5737457f05f812fa5e574817a97..54b31befe6da7a576551c9c2610f8e55645865ee 100644 (file)
@@ -56,6 +56,7 @@
 #include "lp_bld_intr.h"
 #include "lp_bld_logic.h"
 #include "lp_bld_pack.h"
+#include "lp_bld_debug.h"
 #include "lp_bld_arit.h"
 
 
@@ -628,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, "");
@@ -873,6 +874,9 @@ lp_build_iround(struct lp_build_context *bld,
 }
 
 
+/**
+ * Convert float[] to int[] with floor().
+ */
 LLVMValueRef
 lp_build_ifloor(struct lp_build_context *bld,
                 LLVMValueRef a)
@@ -899,6 +903,7 @@ lp_build_ifloor(struct lp_build_context *bld,
       sign = LLVMBuildBitCast(bld->builder, a, int_vec_type, "");
       sign = LLVMBuildAnd(bld->builder, sign, mask, "");
       sign = LLVMBuildAShr(bld->builder, sign, lp_build_int_const_scalar(type, type.width - 1), "");
+      lp_build_name(sign, "floor.sign");
 
       /* offset = -0.99999(9)f */
       offset = lp_build_const_scalar(type, -(double)(((unsigned long long)1 << mantissa) - 1)/((unsigned long long)1 << mantissa));
@@ -907,11 +912,14 @@ lp_build_ifloor(struct lp_build_context *bld,
       /* offset = a < 0 ? -0.99999(9)f : 0.0f */
       offset = LLVMBuildAnd(bld->builder, offset, sign, "");
       offset = LLVMBuildBitCast(bld->builder, offset, vec_type, "");
+      lp_build_name(offset, "floor.offset");
 
       res = LLVMBuildAdd(bld->builder, a, offset, "");
+      lp_build_name(res, "floor.res");
    }
 
    res = LLVMBuildFPToSI(bld->builder, res, int_vec_type, "");
+   lp_build_name(res, "floor");
 
    return res;
 }
index ebf554cd045bafd08fb5a1d85c8b606d8e4ea7c2..f77cf78721315b89c98c80e4ce823fe8f0bc49dc 100644 (file)
@@ -123,6 +123,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..bc831389085fa175923859fc3b375951e7924ad3 100644 (file)
 #define LP_BUILD_FLOW_MAX_VARIABLES 32
 #define LP_BUILD_FLOW_MAX_DEPTH 32
 
-
 /**
  * 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 +73,21 @@ 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;
+
+   LLVMValueRef *phi;  /**< array [num_variables] */
+
+   LLVMValueRef condition;
+   LLVMBasicBlockRef entry_block, true_block, false_block, merge_block;
 };
 
 
@@ -84,6 +98,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 +160,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 +177,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 +197,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 +227,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 +240,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 +268,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 +290,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;
 
@@ -277,27 +304,47 @@ lp_build_flow_scope_end(struct lp_build_flow_context *flow)
 }
 
 
+/**
+ * Note: this function has no dependencies on the flow code and could
+ * be used elsewhere.
+ */
 static LLVMBasicBlockRef
-lp_build_flow_insert_block(struct lp_build_flow_context *flow)
+lp_build_insert_new_block(LLVMBuilderRef builder, const char *name)
 {
    LLVMBasicBlockRef current_block;
    LLVMBasicBlockRef next_block;
    LLVMBasicBlockRef new_block;
 
-   current_block = LLVMGetInsertBlock(flow->builder);
+   /* get current basic block */
+   current_block = LLVMGetInsertBlock(builder);
 
+   /* check if there's another block after this one */
    next_block = LLVMGetNextBasicBlock(current_block);
-   if(next_block) {
-      new_block = LLVMInsertBasicBlock(next_block, "");
+   if (next_block) {
+      /* insert the new block before the next block */
+      new_block = LLVMInsertBasicBlock(next_block, name);
    }
    else {
+      /* append new block after current block */
       LLVMValueRef function = LLVMGetBasicBlockParent(current_block);
-      new_block = LLVMAppendBasicBlock(function, "");
+      new_block = LLVMAppendBasicBlock(function, name);
    }
 
    return new_block;
 }
 
+
+static LLVMBasicBlockRef
+lp_build_flow_insert_block(struct lp_build_flow_context *flow)
+{
+   return lp_build_insert_new_block(flow->builder, "");
+}
+
+
+/**
+ * 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 +356,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 +375,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 +383,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 +404,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 +430,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 +445,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 +493,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 +508,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 +570,188 @@ 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:
+
+     LLVMValueRef x = LLVMGetUndef();  // or something else
+
+     flow = lp_build_flow_create(builder);
+
+        lp_build_flow_scope_begin(flow);
+
+           // x needs a phi node
+           lp_build_flow_scope_declare(flow, &x);
+
+           lp_build_if(ctx, flow, builder, cond);
+              x = LLVMAdd(1, 2);
+           lp_build_else(ctx);
+              x = LLVMAdd(2, 3);
+           lp_build_endif(ctx);
+
+        lp_build_flow_scope_end(flow);
+
+     lp_build_flow_destroy(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);
+   struct lp_build_flow_if *ifthen;
+   unsigned i;
+
+   memset(ctx, 0, sizeof(*ctx));
+   ctx->builder = builder;
+   ctx->flow = flow;
+
+   /* push/create new scope */
+   ifthen = &lp_build_flow_push(flow, LP_BUILD_FLOW_IF)->ifthen;
+   assert(ifthen);
+
+   ifthen->num_variables = flow->num_variables;
+   ifthen->condition = condition;
+   ifthen->entry_block = block;
+
+   /* create a Phi node for each variable in this flow scope */
+   ifthen->phi = MALLOC(ifthen->num_variables * sizeof(*ifthen->phi));
+   if (!ifthen->phi) {
+      ifthen->num_variables = 0;
+      return;
+   }
+
+   /* create endif/merge basic block for the phi functions */
+   ifthen->merge_block = lp_build_insert_new_block(builder, "endif-block");
+   LLVMPositionBuilderAtEnd(builder, ifthen->merge_block);
+
+   /* create a phi node for each variable */
+   for (i = 0; i < flow->num_variables; i++) {
+      ifthen->phi[i] = LLVMBuildPhi(builder, LLVMTypeOf(*flow->variables[i]), "");
+
+      /* add add the initial value of the var from the entry block */
+      LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->entry_block, 1);
+   }
+
+   /* create/insert true_block before merge_block */
+   ifthen->true_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-true-block");
+
+   /* successive code goes into the true block */
+   LLVMPositionBuilderAtEnd(builder, ifthen->true_block);
+}
+
+
+/**
+ * Begin else-part of a conditional
+ */
+void
+lp_build_else(struct lp_build_if_state *ctx)
+{
+   struct lp_build_flow_context *flow = ctx->flow;
+   struct lp_build_flow_if *ifthen;
+   unsigned i;
+
+   ifthen = &lp_build_flow_peek(flow, LP_BUILD_FLOW_IF)->ifthen;
+   assert(ifthen);
+
+   /* for each variable, update the Phi node with a (variable, block) pair */
+   LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
+   for (i = 0; i < flow->num_variables; i++) {
+      assert(*flow->variables[i]);
+      LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->true_block, 1);
+   }
+
+   /* create/insert false_block before the merge block */
+   ifthen->false_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-false-block");
+
+   /* successive code goes into the else block */
+   LLVMPositionBuilderAtEnd(ctx->builder, ifthen->false_block);
+}
+
+
+/**
+ * End a conditional.
+ */
+void
+lp_build_endif(struct lp_build_if_state *ctx)
+{
+   struct lp_build_flow_context *flow = ctx->flow;
+   struct lp_build_flow_if *ifthen;
+   unsigned i;
+
+   ifthen = &lp_build_flow_pop(flow, LP_BUILD_FLOW_IF)->ifthen;
+   assert(ifthen);
+
+   if (ifthen->false_block) {
+      LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
+      /* for each variable, update the Phi node with a (variable, block) pair */
+      for (i = 0; i < flow->num_variables; i++) {
+         assert(*flow->variables[i]);
+         LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->false_block, 1);
+
+         /* replace the variable ref with the phi function */
+         *flow->variables[i] = ifthen->phi[i];
+      }
+   }
+   else {
+      /* no else clause */
+      LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
+      for (i = 0; i < flow->num_variables; i++) {
+         assert(*flow->variables[i]);
+         LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->true_block, 1);
+
+         /* replace the variable ref with the phi function */
+         *flow->variables[i] = ifthen->phi[i];
+      }
+   }
+
+   FREE(ifthen->phi);
+
+   /***
+    *** Now patch in the various branch instructions.
+    ***/
+
+   /* Insert the conditional branch instruction at the end of entry_block */
+   LLVMPositionBuilderAtEnd(ctx->builder, ifthen->entry_block);
+   if (ifthen->false_block) {
+      /* we have an else clause */
+      LLVMBuildCondBr(ctx->builder, ifthen->condition,
+                      ifthen->true_block, ifthen->false_block);
+   }
+   else {
+      /* no else clause */
+      LLVMBuildCondBr(ctx->builder, ifthen->condition,
+                      ifthen->true_block, ifthen->merge_block);
+   }
+
+   /* Append an unconditional Br(anch) instruction on the true_block */
+   LLVMPositionBuilderAtEnd(ctx->builder, ifthen->true_block);
+   LLVMBuildBr(ctx->builder, ifthen->merge_block);
+   if (ifthen->false_block) {
+      /* Append an unconditional Br(anch) instruction on the false_block */
+      LLVMPositionBuilderAtEnd(ctx->builder, ifthen->false_block);
+      LLVMBuildBr(ctx->builder, ifthen->merge_block);
+   }
+
+
+   /* Resume building code at end of the ifthen->merge_block */
+   LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
+}
index e61999ff06be6e1f4d6e8cc88936e697e5fefded..4c225a0d4f91af0b7d3b50fbbf2ce78b9e71ab62 100644 (file)
@@ -126,4 +126,26 @@ lp_build_loop_end(LLVMBuilderRef builder,
 
 
 
+
+struct lp_build_if_state
+{
+   LLVMBuilderRef builder;
+   struct lp_build_flow_context *flow;
+};
+
+
+void
+lp_build_if(struct lp_build_if_state *ctx,
+            struct lp_build_flow_context *flow,
+            LLVMBuilderRef builder,
+            LLVMValueRef condition);
+
+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..a6acaead88766019f984346a061bd07dd35e3841 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,18 +310,20 @@ 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,
+                         boolean flatshade,
                          LLVMBuilderRef builder,
                          struct lp_type type,
                          LLVMValueRef a0_ptr,
                          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;
@@ -309,7 +359,15 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
 
             for( attrib = first; attrib <= last; ++attrib ) {
                bld->mask[1 + attrib] = mask;
-               bld->mode[1 + attrib] = decl->Declaration.Interpolate;
+
+               /* XXX: have mesa set INTERP_CONSTANT in the fragment
+                * shader.
+                */
+               if (decl->Semantic.Name == TGSI_SEMANTIC_COLOR &&
+                   flatshade)
+                  bld->mode[1 + attrib] = TGSI_INTERPOLATE_CONSTANT;
+               else
+                  bld->mode[1 + attrib] = decl->Declaration.Interpolate;
             }
 
             bld->num_attribs = MAX2(bld->num_attribs, 1 + last + 1);
@@ -331,21 +389,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..ca958cdf343cac72e0d509adedb8dd1708ef6194 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];
 
@@ -82,18 +79,18 @@ struct lp_build_interp_soa_context
 void
 lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
                          const struct tgsi_token *tokens,
+                         boolean flatshade,
                          LLVMBuilderRef builder,
                          struct lp_type type,
                          LLVMValueRef a0_ptr,
                          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 15eacb6df48a410430e7e9610ca2084b1b1872c6..d23de4f0ef8ca7fafaf7f557ac9dd380338a6648 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);
@@ -57,6 +61,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)
@@ -69,6 +76,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;
@@ -97,7 +105,7 @@ lp_build_cmp(struct lp_build_context *bld,
             break;
          default:
             assert(0);
-            return bld->undef;
+            return lp_build_undef(type);
          }
 
          if(swap) {
@@ -110,14 +118,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;
@@ -153,7 +162,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
@@ -163,8 +172,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) {
@@ -177,14 +186,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;
       }
@@ -220,28 +229,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
    }
@@ -268,28 +277,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
    }
@@ -298,6 +307,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 5ee8d556a687cfc334781dbd1de78d00ff28cd8a..854dd0b28c2384ea4db9671eb81c9dc4afe6240f 100644 (file)
@@ -172,7 +172,7 @@ lp_build_sample_wrap(struct lp_build_sample_context *bld,
    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
       /* FIXME */
-      _debug_printf("warning: failed to translate texture wrap mode %s\n",
+      _debug_printf("llvmpipe: failed to translate texture wrap mode %s\n",
                     debug_dump_tex_wrap(wrap_mode, TRUE));
       coord = lp_build_max(int_coord_bld, coord, int_coord_bld->zero);
       coord = lp_build_min(int_coord_bld, coord, length_minus_one);
@@ -201,9 +201,13 @@ lp_build_sample_2d_nearest_soa(struct lp_build_sample_context *bld,
 
    x = lp_build_ifloor(&bld->coord_bld, s);
    y = lp_build_ifloor(&bld->coord_bld, t);
+   lp_build_name(x, "tex.x.floor");
+   lp_build_name(y, "tex.y.floor");
 
    x = lp_build_sample_wrap(bld, x, width,  bld->static_state->pot_width,  bld->static_state->wrap_s);
    y = lp_build_sample_wrap(bld, y, height, bld->static_state->pot_height, bld->static_state->wrap_t);
+   lp_build_name(x, "tex.x.wrapped");
+   lp_build_name(y, "tex.y.wrapped");
 
    lp_build_sample_texel_soa(bld, x, y, stride, data_ptr, texel);
 }
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 0dfee2a307c40866966c4b69408846303f6bb746..9eda97208184000002bebb0ffb6889677646ed9b 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 d9adf21b6a6f2a7f889c0d9aca0e87d2563ed8cc..a76bde390545b268c43a57312c3340b3b9d566cf 100644 (file)
 #include "lp_clear.h"
 #include "lp_context.h"
 #include "lp_flush.h"
-#include "lp_prim_vbuf.h"
+#include "lp_perf.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 )
@@ -105,22 +56,24 @@ static void llvmpipe_destroy( struct pipe_context *pipe )
    struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
    uint i;
 
+   lp_print_counters();
+
+   /* 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);
    }
 
@@ -139,33 +92,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
@@ -179,7 +107,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)
@@ -243,19 +170,6 @@ llvmpipe_create( struct pipe_screen *screen )
    llvmpipe->pipe.is_buffer_referenced = llvmpipe_is_buffer_referenced;
 
    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.
@@ -269,19 +183,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)
-      goto fail;
-
-   llvmpipe->vbuf = draw_vbuf_stage(llvmpipe->draw, llvmpipe->vbuf_backend);
-   if (!llvmpipe->vbuf)
+   llvmpipe->setup = lp_setup_create( screen,
+                                      llvmpipe->draw );
+   if (!llvmpipe->setup)
       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);
@@ -293,6 +199,8 @@ llvmpipe_create( struct pipe_screen *screen )
 
    lp_init_surface_functions(llvmpipe);
 
+   lp_reset_counters();
+
    return &llvmpipe->pipe;
 
  fail:
index 426d6eb4a12f7a896880fd18b5de3aacf87e5cec..3af7b62a53bd0453e588c337303780cf2aba3b19 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_buffer *constants[PIPE_SHADER_TYPES];
    struct pipe_framebuffer_state framebuffer;
@@ -94,49 +92,19 @@ 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 74b27574942b6b4fb4e605fe1146c24fc417c8de..ee81814361020bceca873a86ad4286eba14100c9 100644 (file)
@@ -45,6 +45,11 @@ st_print_current(void);
 #define DEBUG_QUERY     0x40
 #define DEBUG_SCREEN    0x80
 #define DEBUG_JIT       0x100
+#define DEBUG_SHOW_TILES    0x200
+#define DEBUG_SHOW_SUBTILES 0x400
+#define DEBUG_COUNTERS      0x800
+#define DEBUG_NO_LLVM_OPT  0x1000
+
 
 #ifdef DEBUG
 extern int LP_DEBUG;
index a0316194c6a5c04f16bcef0fab5d6f3233b3fc53..3dd68d5794ee8b295f413e2b3a10ec0a6fd9c81f 100644 (file)
@@ -68,13 +68,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
     */
@@ -116,10 +112,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..525c117
--- /dev/null
@@ -0,0 +1,110 @@
+/**************************************************************************
+ *
+ * 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 "util/u_inlines.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..c90e6de
--- /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 "os/os_thread.h"
+#include "pipe/p_state.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 6c81012e84b0c8e2e4dd2b3f72ebe96edd6a514d..edd480d7ed9a73f73720c3fa2dbbf41a73c470a8 100644 (file)
@@ -35,8 +35,7 @@
 #include "lp_flush.h"
 #include "lp_context.h"
 #include "lp_surface.h"
-#include "lp_state.h"
-#include "lp_tile_cache.h"
+#include "lp_setup.h"
 
 
 void
@@ -45,56 +44,52 @@ 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 */
 #if 0
-   if(flags & PIPE_FLUSH_FRAME) {
+   if (flags & PIPE_FLUSH_FRAME) {
       static unsigned frame_no = 1;
-      static char filename[256];
-      util_snprintf(filename, sizeof(filename), "cbuf_%u.bmp", frame_no);
-      debug_dump_surface_bmp(filename, llvmpipe->framebuffer.cbufs[0]);
-      util_snprintf(filename, sizeof(filename), "zsbuf_%u.bmp", frame_no);
-      debug_dump_surface_bmp(filename, llvmpipe->framebuffer.zsbuf);
+      char filename[256];
+      unsigned i;
+
+      for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++) {
+        util_snprintf(filename, sizeof(filename), "cbuf%u_%u", i, frame_no);
+         debug_dump_surface(filename, llvmpipe->framebuffer.cbufs[i]);
+      }
+
+      if (0) {
+         util_snprintf(filename, sizeof(filename), "zsbuf_%u", frame_no);
+         debug_dump_surface(filename, llvmpipe->framebuffer.zsbuf);
+      }
+
       ++frame_no;
    }
 #endif
-   
-   if (fence)
-      *fence = NULL;
 }
 
index 9e0118c55b6cb34a4309b15a06afb94379c34a22..310fc2b847949b3e2a4411606da78a1bf403e7d1 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "util/u_memory.h"
 #include "util/u_cpu_detect.h"
+#include "lp_debug.h"
 #include "lp_screen.h"
 #include "lp_bld_intr.h"
 #include "lp_jit.h"
@@ -78,13 +79,16 @@ lp_jit_init_globals(struct llvmpipe_screen *screen)
 
    /* struct lp_jit_context */
    {
-      LLVMTypeRef elem_types[4];
+      LLVMTypeRef elem_types[8];
       LLVMTypeRef context_type;
 
       elem_types[0] = LLVMPointerType(LLVMFloatType(), 0); /* constants */
-      elem_types[1] = LLVMFloatType();                     /* alpha_ref_value */
-      elem_types[2] = LLVMPointerType(LLVMInt8Type(), 0);  /* blend_color */
-      elem_types[3] = LLVMArrayType(texture_type, PIPE_MAX_SAMPLERS); /* textures */
+      elem_types[1] = LLVMFloatType();                     /* alpha_ref_value */      elem_types[2] = LLVMFloatType();                     /* scissor_xmin */
+      elem_types[3] = LLVMFloatType();                     /* scissor_ymin */
+      elem_types[4] = LLVMFloatType();                     /* scissor_xmax */
+      elem_types[5] = LLVMFloatType();                     /* scissor_ymax */
+      elem_types[6] = LLVMPointerType(LLVMInt8Type(), 0);  /* blend_color */
+      elem_types[7] = LLVMArrayType(texture_type, PIPE_MAX_SAMPLERS); /* textures */
 
       context_type = LLVMStructType(elem_types, Elements(elem_types), 0);
 
@@ -92,8 +96,16 @@ lp_jit_init_globals(struct llvmpipe_screen *screen)
                              screen->target, context_type, 0);
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, alpha_ref_value,
                              screen->target, context_type, 1);
-      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, blend_color,
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, scissor_xmin,
                              screen->target, context_type, 2);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, scissor_ymin,
+                             screen->target, context_type, 3);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, scissor_xmax,
+                             screen->target, context_type, 4);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, scissor_ymax,
+                             screen->target, context_type, 5);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, blend_color,
+                             screen->target, context_type, 6);
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, textures,
                              screen->target, context_type,
                              LP_JIT_CONTEXT_TEXTURES_INDEX);
@@ -153,20 +165,23 @@ lp_jit_screen_init(struct llvmpipe_screen *screen)
 
    screen->pass = LLVMCreateFunctionPassManager(screen->provider);
    LLVMAddTargetData(screen->target, screen->pass);
-   /* These are the passes currently listed in llvm-c/Transforms/Scalar.h,
-    * but there are more on SVN. */
-   /* TODO: Add more passes */
-   LLVMAddConstantPropagationPass(screen->pass);
-   if(util_cpu_caps.has_sse4_1) {
-      /* FIXME: There is a bug in this pass, whereby the combination of fptosi
-       * and sitofp (necessary for trunc/floor/ceil/round implementation)
-       * somehow becomes invalid code.
-       */
-      LLVMAddInstructionCombiningPass(screen->pass);
+
+   if ((LP_DEBUG & DEBUG_NO_LLVM_OPT) == 0) {
+      /* These are the passes currently listed in llvm-c/Transforms/Scalar.h,
+       * but there are more on SVN. */
+      /* TODO: Add more passes */
+      LLVMAddConstantPropagationPass(screen->pass);
+      if(util_cpu_caps.has_sse4_1) {
+         /* FIXME: There is a bug in this pass, whereby the combination of fptosi
+          * and sitofp (necessary for trunc/floor/ceil/round implementation)
+          * somehow becomes invalid code.
+          */
+         LLVMAddInstructionCombiningPass(screen->pass);
+      }
+      LLVMAddPromoteMemoryToRegisterPass(screen->pass);
+      LLVMAddGVNPass(screen->pass);
+      LLVMAddCFGSimplificationPass(screen->pass);
    }
-   LLVMAddPromoteMemoryToRegisterPass(screen->pass);
-   LLVMAddGVNPass(screen->pass);
-   LLVMAddCFGSimplificationPass(screen->pass);
 
    lp_jit_init_globals(screen);
 }
index 277b690c02ca8d5ba6c31ef7c9a074e8490f45ba..9cbe1bd3b1b7f6c466311d74fa0cf27169ea676c 100644 (file)
@@ -79,6 +79,9 @@ struct lp_jit_context
 
    float alpha_ref_value;
 
+   /** floats, not ints */
+   float scissor_xmin, scissor_ymin, scissor_xmax, scissor_ymax;
+
    /* FIXME: store (also?) in floats */
    uint8_t *blend_color;
 
@@ -92,25 +95,43 @@ struct lp_jit_context
 #define lp_jit_context_alpha_ref_value(_builder, _ptr) \
    lp_build_struct_get(_builder, _ptr, 1, "alpha_ref_value")
 
+#define lp_jit_context_scissor_xmin_value(_builder, _ptr) \
+   lp_build_struct_get(_builder, _ptr, 2, "scissor_xmin")
+
+#define lp_jit_context_scissor_ymin_value(_builder, _ptr) \
+   lp_build_struct_get(_builder, _ptr, 3, "scissor_ymin")
+
+#define lp_jit_context_scissor_xmax_value(_builder, _ptr) \
+   lp_build_struct_get(_builder, _ptr, 4, "scissor_xmax")
+
+#define lp_jit_context_scissor_ymax_value(_builder, _ptr) \
+   lp_build_struct_get(_builder, _ptr, 5, "scissor_ymax")
+
 #define lp_jit_context_blend_color(_builder, _ptr) \
-   lp_build_struct_get(_builder, _ptr, 2, "blend_color")
+   lp_build_struct_get(_builder, _ptr, 6, "blend_color")
 
-#define LP_JIT_CONTEXT_TEXTURES_INDEX 3
+#define LP_JIT_CONTEXT_TEXTURES_INDEX 7
 
 #define lp_jit_context_textures(_builder, _ptr) \
    lp_build_struct_get_ptr(_builder, _ptr, LP_JIT_CONTEXT_TEXTURES_INDEX, "textures")
 
 
 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);
+                    uint8_t **color,
+                    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_perf.c b/src/gallium/drivers/llvmpipe/lp_perf.c
new file mode 100644 (file)
index 0000000..042218b
--- /dev/null
@@ -0,0 +1,90 @@
+/**************************************************************************
+ *
+ * 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_debug.h"
+#include "lp_debug.h"
+#include "lp_perf.h"
+
+
+
+struct lp_counters lp_count;
+
+
+void
+lp_reset_counters(void)
+{
+   memset(&lp_count, 0, sizeof(lp_count));
+}
+
+
+void
+lp_print_counters(void)
+{
+   if (LP_DEBUG & DEBUG_COUNTERS) {
+      unsigned total_64, total_16, total_4;
+      float p1, p2, p3;
+
+      debug_printf("llvmpipe: nr_triangles:               %9u\n", lp_count.nr_tris);
+      debug_printf("llvmpipe: nr_culled_triangles:        %9u\n", lp_count.nr_culled_tris);
+
+      total_64 = (lp_count.nr_empty_64 + 
+                  lp_count.nr_fully_covered_64 +
+                  lp_count.nr_partially_covered_64);
+
+      p1 = 100.0 * (float) lp_count.nr_empty_64 / (float) total_64;
+      p2 = 100.0 * (float) lp_count.nr_fully_covered_64 / (float) total_64;
+      p3 = 100.0 * (float) lp_count.nr_partially_covered_64 / (float) total_64;
+
+      debug_printf("llvmpipe: nr_empty_64x64:             %9u (%2.0f%% of %u)\n", lp_count.nr_empty_64, p1, total_64);
+      debug_printf("llvmpipe: nr_fully_covered_64x64:     %9u (%2.0f%% of %u)\n", lp_count.nr_fully_covered_64, p2, total_64);
+      debug_printf("llvmpipe: nr_partially_covered_64x64: %9u (%2.0f%% of %u)\n", lp_count.nr_partially_covered_64, p3, total_64);
+
+      total_16 = (lp_count.nr_empty_16 + 
+                  lp_count.nr_fully_covered_16 +
+                  lp_count.nr_partially_covered_16);
+
+      p1 = 100.0 * (float) lp_count.nr_empty_16 / (float) total_16;
+      p2 = 100.0 * (float) lp_count.nr_fully_covered_16 / (float) total_16;
+      p3 = 100.0 * (float) lp_count.nr_partially_covered_16 / (float) total_16;
+
+      debug_printf("llvmpipe: nr_empty_16x16:             %9u (%2.0f%% of %u)\n", lp_count.nr_empty_16, p1, total_16);
+      debug_printf("llvmpipe: nr_fully_covered_16x16:     %9u (%2.0f%% of %u)\n", lp_count.nr_fully_covered_16, p2, total_16);
+      debug_printf("llvmpipe: nr_partially_covered_16x16: %9u (%2.0f%% of %u)\n", lp_count.nr_partially_covered_16, p3, total_16);
+
+      total_4 = (lp_count.nr_empty_4 + lp_count.nr_non_empty_4);
+
+      p1 = 100.0 * (float) lp_count.nr_empty_4 / (float) total_4;
+      p2 = 100.0 * (float) lp_count.nr_non_empty_4 / (float) total_4;
+
+      debug_printf("llvmpipe: nr_empty_4x4:               %9u (%2.0f%% of %u)\n", lp_count.nr_empty_4, p1, total_4);
+      debug_printf("llvmpipe: nr_non_empty_4x4:           %9u (%2.0f%% of %u)\n", lp_count.nr_non_empty_4, p2, total_4);
+
+      debug_printf("llvmpipe: nr_llvm_compiles:           %u\n", lp_count.nr_llvm_compiles);
+      debug_printf("llvmpipe: total LLVM compile time:    %.2f sec\n", lp_count.llvm_compile_time / 1000000.0);
+      debug_printf("llvmpipe: average LLVM compile time:  %.2f sec\n", lp_count.llvm_compile_time / 1000000.0 / lp_count.nr_llvm_compiles);
+   }
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_perf.h b/src/gallium/drivers/llvmpipe/lp_perf.h
new file mode 100644 (file)
index 0000000..d982bcc
--- /dev/null
@@ -0,0 +1,78 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+/**
+ * Performance / statistic counters, etc.
+ */
+
+
+#ifndef LP_PERF_H
+#define LP_PERF_H
+
+
+/**
+ * Various counters
+ */
+struct lp_counters
+{
+   unsigned nr_tris;
+   unsigned nr_culled_tris;
+   unsigned nr_empty_64;
+   unsigned nr_fully_covered_64;
+   unsigned nr_partially_covered_64;
+   unsigned nr_empty_16;
+   unsigned nr_fully_covered_16;
+   unsigned nr_partially_covered_16;
+   unsigned nr_empty_4;
+   unsigned nr_non_empty_4;
+   unsigned nr_llvm_compiles;
+   int64_t llvm_compile_time;  /**< total, in microseconds */
+};
+
+
+extern struct lp_counters lp_count;
+
+
+/** Increment the named counter (only for debug builds) */
+#ifdef DEBUG
+#define LP_COUNT(counter) lp_count.counter++
+#define LP_COUNT_ADD(counter, incr)  lp_count.counter += (incr)
+#else
+#define LP_COUNT(counter)
+#define LP_COUNT_ADD(counter, incr) (void) incr
+#endif
+
+
+extern void
+lp_reset_counters(void);
+
+
+extern void
+lp_print_counters(void);
+
+
+#endif /* LP_PERF_H */
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 c3a4870..0000000
+++ /dev/null
@@ -1,115 +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_compiler.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) */
-   PIPE_ALIGN_VAR(16) float color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS][QUAD_SIZE];
-};
-
-
-/**
- * Input interpolation coefficients
- */
-struct quad_interp_coef
-{
-   PIPE_ALIGN_VAR(16) float a0[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
-   PIPE_ALIGN_VAR(16) float dadx[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
-   PIPE_ALIGN_VAR(16) float 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..54af850
--- /dev/null
@@ -0,0 +1,1023 @@
+/**************************************************************************
+ *
+ * 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;
+   int i;
+
+   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);
+
+   
+   for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+      cbuf = rast->state.fb.cbufs[i];
+      if (cbuf) {
+        rast->cbuf_transfer[i] = screen->get_tex_transfer(rast->screen,
+                                                          cbuf->texture,
+                                                          cbuf->face,
+                                                          cbuf->level,
+                                                          cbuf->zslice,
+                                                          PIPE_TRANSFER_READ_WRITE,
+                                                          0, 0,
+                                                          cbuf->width, 
+                                                          cbuf->height);
+        if (!rast->cbuf_transfer[i])
+           goto fail;
+
+        rast->cbuf_map[i] = screen->transfer_map(rast->screen, 
+                                                 rast->cbuf_transfer[i]);
+        if (!rast->cbuf_map[i])
+           goto fail;
+      }
+   }
+
+   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,
+                                                      zsbuf->width,
+                                                     zsbuf->height);
+      if (!rast->zsbuf_transfer)
+         goto fail;
+
+      rast->zsbuf_map = screen->transfer_map(rast->screen, 
+                                            rast->zsbuf_transfer);
+      if (!rast->zsbuf_map)
+        goto fail;
+   }
+
+   return TRUE;
+
+fail:
+   /* Unmap and release transfers?
+    */
+   return FALSE;
+}
+
+
+/**
+ * Finish the rasterization phase.
+ * Unmap framebuffer surfaces.
+ */
+static void
+lp_rast_end( struct lp_rasterizer *rast )
+{
+   struct pipe_screen *screen = rast->screen;
+   unsigned i;
+
+   for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+      if (rast->cbuf_map[i]) 
+        screen->transfer_unmap(screen, rast->cbuf_transfer[i]);
+
+      if (rast->cbuf_transfer[i])
+        screen->tex_transfer_destroy(rast->cbuf_transfer[i]);
+
+      rast->cbuf_transfer[i] = NULL;
+      rast->cbuf_map[i] = NULL;
+   }
+
+   if (rast->zsbuf_map) 
+      screen->transfer_unmap(screen, rast->zsbuf_transfer);
+
+   if (rast->zsbuf_transfer)
+      screen->tex_transfer_destroy(rast->zsbuf_transfer);
+
+   rast->zsbuf_transfer = 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;
+   unsigned i;
+
+   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]) {
+      /* clear to grayscale value {x, x, x, x} */
+      for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+        memset(color_tile[i], clear_color[0], TILE_SIZE * TILE_SIZE * 4);
+      }
+   }
+   else {
+      /* Non-gray color.
+       * Note: if the swizzled tile layout changes (see TILE_PIXEL) this code
+       * will need to change.  It'll be pretty obvious when clearing no longer
+       * works.
+       */
+      const unsigned chunk = TILE_SIZE / 4;
+      for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+         uint8_t *c = color_tile[i];
+         unsigned j;
+         for (j = 0; j < 4 * TILE_SIZE; j++) {
+            memset(c, clear_color[0], chunk);
+            c += chunk;
+            memset(c, clear_color[1], chunk);
+            c += chunk;
+            memset(c, clear_color[2], chunk);
+            c += chunk;
+            memset(c, clear_color[3], chunk);
+            c += chunk;
+         }
+         assert(c - color_tile[i] == TILE_SIZE * TILE_SIZE * 4);
+      }
+   }
+}
+
+
+/**
+ * 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;
+   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 * TILE_SIZE; i++)
+      depth_tile[i] = 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;
+   unsigned i;
+
+   LP_DBG(DEBUG_RAST, "%s at %u, %u\n", __FUNCTION__, x, y);
+
+   for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+      struct pipe_transfer *transfer = rast->cbuf_transfer[i];
+      int w = TILE_SIZE;
+      int h = TILE_SIZE;
+
+      if (x >= transfer->width)
+        continue;
+
+      if (y >= transfer->height)
+        continue;
+
+      assert(w >= 0);
+      assert(h >= 0);
+      assert(w <= TILE_SIZE);
+      assert(h <= TILE_SIZE);
+
+      lp_tile_read_4ub(transfer->texture->format,
+                      task->tile.color[i],
+                      rast->cbuf_map[i], 
+                      transfer->stride,
+                      x, y,
+                      w, h);
+   }
+}
+
+
+static void
+lp_tile_read_z32(uint32_t *tile,
+                 const uint8_t *map,
+                 unsigned map_stride,
+                 unsigned x0, unsigned y0, unsigned w, unsigned h)
+{
+   unsigned x, y;
+   const uint8_t *map_row = map + y0*map_stride;
+   for (y = 0; y < h; ++y) {
+      const uint32_t *map_pixel = (uint32_t *)(map_row + x0*4);
+      for (x = 0; x < w; ++x) {
+         *tile++ = *map_pixel++;
+      }
+      map_row += map_stride;
+   }
+}
+
+/**
+ * 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 )
+{
+   struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+   const unsigned x = task->x;
+   const unsigned y = task->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_read_z32(task->tile.depth,
+                    rast->zsbuf_map, 
+                    rast->zsbuf_transfer->stride,
+                    x, y, w, h);
+}
+
+
+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;
+}
+
+
+
+/**
+ * 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 )
+{
+   struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+   const struct lp_rast_state *state = task->current_state;
+   struct lp_rast_tile *tile = &task->tile;
+   const struct lp_rast_shader_inputs *inputs = arg.shade_tile;
+   const unsigned tile_x = task->x;
+   const unsigned tile_y = task->y;
+   unsigned x, y;
+
+   LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+
+   /* render the whole 64x64 tile in 4x4 chunks */
+   for (y = 0; y < TILE_SIZE; y += 4){
+      for (x = 0; x < TILE_SIZE; x += 4) {
+         uint8_t *color[PIPE_MAX_COLOR_BUFS];
+         uint32_t *depth;
+         unsigned block_offset, i;
+
+         /* offset of the 16x16 pixel block within the tile */
+         block_offset = ((y / 4) * (16 * 16) + (x / 4) * 16);
+
+         /* color buffer */
+         for (i = 0; i < rast->state.fb.nr_cbufs; i++)
+            color[i] = tile->color[i] + 4 * block_offset;
+
+         /* depth buffer */
+         depth = tile->depth + block_offset;
+
+         /* run shader */
+         state->jit_function[0]( &state->jit_context,
+                                 tile_x + x, tile_y + y,
+                                 inputs->a0,
+                                 inputs->dadx,
+                                 inputs->dady,
+                                 color,
+                                 depth,
+                                 INT_MIN, INT_MIN, INT_MIN,
+                                 NULL, NULL, NULL );
+      }
+   }
+}
+
+
+/**
+ * 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)
+{
+   struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+   const struct lp_rast_state *state = task->current_state;
+   struct lp_rast_tile *tile = &task->tile;
+   uint8_t *color[PIPE_MAX_COLOR_BUFS];
+   void *depth;
+   unsigned i;
+   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 */
+   for (i = 0; i < rast->state.fb.nr_cbufs; i++)
+      color[i] = tile->color[i] + 4 * block_offset;
+
+   /* depth buffer */
+   depth = tile->depth + block_offset;
+
+
+
+#ifdef DEBUG
+   assert(lp_check_alignment(tile->depth, 16));
+   assert(lp_check_alignment(tile->color[0], 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[1]( &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]);
+}
+
+
+/**
+ * Set top row and left column of the tile's pixels to white.  For debugging.
+ */
+static void
+outline_tile(uint8_t *tile)
+{
+   const uint8_t val = 0xff;
+   unsigned i;
+
+   for (i = 0; i < TILE_SIZE; i++) {
+      TILE_PIXEL(tile, i, 0, 0) = val;
+      TILE_PIXEL(tile, i, 0, 1) = val;
+      TILE_PIXEL(tile, i, 0, 2) = val;
+      TILE_PIXEL(tile, i, 0, 3) = val;
+
+      TILE_PIXEL(tile, 0, i, 0) = val;
+      TILE_PIXEL(tile, 0, i, 1) = val;
+      TILE_PIXEL(tile, 0, i, 2) = val;
+      TILE_PIXEL(tile, 0, i, 3) = val;
+   }
+}
+
+
+/**
+ * Draw grid of gray lines at 16-pixel intervals across the tile to
+ * show the sub-tile boundaries.  For debugging.
+ */
+static void
+outline_subtiles(uint8_t *tile)
+{
+   const uint8_t val = 0x80;
+   const unsigned step = 16;
+   unsigned i, j;
+
+   for (i = 0; i < TILE_SIZE; i += step) {
+      for (j = 0; j < TILE_SIZE; j++) {
+         TILE_PIXEL(tile, i, j, 0) = val;
+         TILE_PIXEL(tile, i, j, 1) = val;
+         TILE_PIXEL(tile, i, j, 2) = val;
+         TILE_PIXEL(tile, i, j, 3) = val;
+
+         TILE_PIXEL(tile, j, i, 0) = val;
+         TILE_PIXEL(tile, j, i, 1) = val;
+         TILE_PIXEL(tile, j, i, 2) = val;
+         TILE_PIXEL(tile, j, i, 3) = val;
+      }
+   }
+
+   outline_tile(tile);
+}
+
+
+
+/**
+ * Write the rasterizer's color tile to the framebuffer.
+ */
+static void lp_rast_store_color( struct lp_rasterizer *rast,
+                                 unsigned thread_index)
+{
+   struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+   const unsigned x = task->x;
+   const unsigned y = task->y;
+   unsigned i;
+
+   for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+      struct pipe_transfer *transfer = rast->cbuf_transfer[i];
+      int w = TILE_SIZE;
+      int h = TILE_SIZE;
+
+      if (x >= transfer->width)
+        continue;
+
+      if (y >= transfer->height)
+        continue;
+
+      LP_DBG(DEBUG_RAST, "%s [%u] %d,%d %dx%d\n", __FUNCTION__,
+            thread_index, x, y, w, h);
+
+      if (LP_DEBUG & DEBUG_SHOW_SUBTILES)
+         outline_subtiles(task->tile.color[i]);
+      else if (LP_DEBUG & DEBUG_SHOW_TILES)
+         outline_tile(task->tile.color[i]);
+
+      lp_tile_write_4ub(transfer->texture->format,
+                       task->tile.color[i],
+                       rast->cbuf_map[i], 
+                       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 )
+{
+   struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+   const unsigned x = task->x;
+   const unsigned y = task->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(task->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 );
+}
+
+
+#define RAST(x) { lp_rast_##x, #x }
+
+static struct {
+   lp_rast_cmd cmd;
+   const char *name;
+} cmd_names[] = 
+{
+   RAST(load_color),
+   RAST(load_zstencil),
+   RAST(clear_color),
+   RAST(clear_zstencil),
+   RAST(triangle),
+   RAST(shade_tile),
+   RAST(set_state),
+   RAST(fence),
+};
+
+static void
+debug_bin( const struct cmd_bin *bin )
+{
+   const struct cmd_block *head = bin->commands.head;
+   int i, j;
+
+   for (i = 0; i < head->count; i++) {
+      debug_printf("%d: ", i);
+      for (j = 0; j < Elements(cmd_names); j++) {
+         if (head->cmd[i] == cmd_names[j].cmd) {
+            debug_printf("%s\n", cmd_names[j].name);
+            break;
+         }
+      }
+      if (j == Elements(cmd_names))
+         debug_printf("...other\n");
+   }
+
+}
+
+/* An empty bin is one that just loads the contents of the tile and
+ * stores them again unchanged.  This typically happens when bins have
+ * been flushed for some reason in the middle of a frame, or when
+ * incremental updates are being made to a render target.
+ * 
+ * Try to avoid doing pointless work in this case.
+ */
+static boolean
+is_empty_bin( const struct cmd_bin *bin )
+{
+   const struct cmd_block *head = bin->commands.head;
+   int i;
+   
+   if (0)
+      debug_bin(bin);
+   
+   /* We emit at most two load-tile commands at the start of the first
+    * command block.  In addition we seem to emit a couple of
+    * set-state commands even in empty bins.
+    *
+    * As a heuristic, if a bin has more than 4 commands, consider it
+    * non-empty.
+    */
+   if (head->next != NULL ||
+       head->count > 4) {
+      return FALSE;
+   }
+
+   for (i = 0; i < head->count; i++)
+      if (head->cmd[i] != lp_rast_load_color &&
+          head->cmd[i] != lp_rast_load_zstencil &&
+          head->cmd[i] != lp_rast_set_state) {
+         return FALSE;
+      }
+
+   return TRUE;
+}
+
+
+
+/**
+ * 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))) {
+         if (!is_empty_bin( bin ))
+            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;
+      debug_printf("rasterize scene:\n");
+      debug_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++) {
+            debug_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->nr_cbufs != 0, /* always write color if cbufs present */
+                     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 PIPE_THREAD_ROUTINE( thread_func, 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, TRUE );
+
+         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->nr_cbufs != 0,
+                        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, cbuf;
+
+   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++) {
+      struct lp_rasterizer_task *task = &rast->tasks[i];
+
+      for (cbuf = 0; cbuf < PIPE_MAX_COLOR_BUFS; cbuf++ )
+        task->tile.color[cbuf] = align_malloc(TILE_SIZE * TILE_SIZE * 4, 16);
+
+      task->tile.depth = align_malloc(TILE_SIZE * TILE_SIZE * 4, 16);
+      task->rast = rast;
+      task->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, cbuf;
+
+   util_unreference_framebuffer_state(&rast->state.fb);
+
+   for (i = 0; i < Elements(rast->tasks); i++) {
+      align_free(rast->tasks[i].tile.depth);
+      for (cbuf = 0; cbuf < PIPE_MAX_COLOR_BUFS; cbuf++ )
+        align_free(rast->tasks[i].tile.color[cbuf]);
+   }
+
+   /* 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..e4c56f1
--- /dev/null
@@ -0,0 +1,236 @@
+/**************************************************************************
+ *
+ * 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:
+    * jit_function[0] skips the triangle in/out test code
+    * jit_function[1] does triangle in/out testing
+     */
+   lp_jit_frag_func jit_function[2];
+
+   boolean opaque;
+};
+
+
+/**
+ * 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 */
+   PIPE_ALIGN_VAR(16) int 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 {
+   /* 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 */
+   PIPE_ALIGN_VAR(16) struct lp_rast_shader_inputs 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..71e3a30
--- /dev/null
@@ -0,0 +1,172 @@
+/**************************************************************************
+ *
+ * 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 "os/os_thread.h"
+#include "lp_rast.h"
+#include "lp_tile_soa.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[PIPE_MAX_COLOR_BUFS];
+
+   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[PIPE_MAX_COLOR_BUFS];
+   struct pipe_transfer *zsbuf_transfer;
+   void *cbuf_map[PIPE_MAX_COLOR_BUFS];
+   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);
+
+
+/**
+ * Shade all pixels in a 4x4 block.  The fragment code omits the
+ * triangle in/out tests.
+ * \param x, y location of 4x4 block in window coords
+ */
+static INLINE void
+lp_rast_shade_quads_all( struct lp_rasterizer *rast,
+                         unsigned thread_index,
+                         const struct lp_rast_shader_inputs *inputs,
+                         unsigned x, unsigned y )
+{
+   const struct lp_rast_state *state = rast->tasks[thread_index].current_state;
+   struct lp_rast_tile *tile = &rast->tasks[thread_index].tile;
+   const unsigned ix = x % TILE_SIZE, iy = y % TILE_SIZE;
+   uint8_t *color[PIPE_MAX_COLOR_BUFS];
+   void *depth;
+   unsigned block_offset, i;
+
+   /* offset of the containing 16x16 pixel block within the tile */
+   block_offset = (iy / 4) * (16 * 16) + (ix / 4) * 16;
+
+   /* color buffer */
+   for (i = 0; i < rast->state.fb.nr_cbufs; i++)
+      color[i] = tile->color[i] + 4 * block_offset;
+
+   /* depth buffer */
+   depth = tile->depth + block_offset;
+
+   /* run shader */
+   state->jit_function[0]( &state->jit_context,
+                           x, y,
+                           inputs->a0,
+                           inputs->dadx,
+                           inputs->dady,
+                           color,
+                           depth,
+                           INT_MIN, INT_MIN, INT_MIN,
+                           NULL, NULL, NULL );
+}
+
+
+#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..3f76f15
--- /dev/null
@@ -0,0 +1,251 @@
+/**************************************************************************
+ *
+ * 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_perf.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.
+ * Note: we can use some bit twiddling to compute these values instead
+ * of using a look-up table, but there's no measurable performance
+ * difference.
+ */
+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 )
+{
+   lp_rast_shade_quads_all(rast_task->rast,
+                           rast_task->thread_index,
+                           &tri->inputs, 
+                           x, y);
+}
+
+
+/**
+ * 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 eo1 = tri->eo1 * 4;
+   const int eo2 = tri->eo2 * 4;
+   const int eo3 = tri->eo3 * 4;
+   const int *step0 = tri->inputs.step[0];
+   const int *step1 = tri->inputs.step[1];
+   const int *step2 = tri->inputs.step[2];
+   int i;
+
+   assert(x % 16 == 0);
+   assert(y % 16 == 0);
+
+   for (i = 0; i < 16; i++) {
+      int cx1 = c1 + step0[i] * 4;
+      int cx2 = c2 + step1[i] * 4;
+      int cx3 = c3 + step2[i] * 4;
+
+      if (cx1 + eo1 < 0 ||
+          cx2 + eo2 < 0 ||
+          cx3 + eo3 < 0) {
+         /* the block is completely outside the triangle - nop */
+         LP_COUNT(nr_empty_4);
+      }
+      else {
+         int px = x + pos_table4[i][0];
+         int py = y + pos_table4[i][1];
+         /* Don't bother testing if the 4x4 block is entirely in/out of
+          * the triangle.  It's a little faster to do it in the jit code.
+          */
+         LP_COUNT(nr_non_empty_4);
+         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 */
+         LP_COUNT(nr_empty_16);
+      }
+      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 */
+            LP_COUNT(nr_fully_covered_16);
+            block_full_16(rast_task, tri, px, py);
+         }
+         else {
+            /* the block is partially in/out of the triangle */
+            LP_COUNT(nr_partially_covered_16);
+            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..0421c50
--- /dev/null
@@ -0,0 +1,392 @@
+/**************************************************************************
+ *
+ * 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 "util/u_inlines.h"
+#include "util/u_simple_list.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);
+
+   make_empty_list(&scene->textures);
+
+   pipe_mutex_init(scene->mutex);
+}
+
+
+/**
+ * Check if the scene's bins are all empty.
+ * For debugging purposes.
+ */
+boolean
+lp_scene_is_empty(struct lp_scene *scene )
+{
+   unsigned x, y;
+
+   for (y = 0; y < TILES_Y; y++) {
+      for (x = 0; x < TILES_X; x++) {
+         const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
+         const struct cmd_block_list *list = &bin->commands;
+         if (list->head != list->tail || list->head->count > 0) {
+            return FALSE;
+         }
+      }
+   }
+   return TRUE;
+}
+
+
+void
+lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y)
+{
+   struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
+   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;
+}
+
+
+/**
+ * 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++) {
+         lp_scene_bin_reset(scene, i, j);
+      }
+   }
+
+   assert(lp_scene_is_empty(scene));
+
+   /* 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;
+   }
+
+   /* Release texture refs
+    */
+   {
+      struct texture_ref *ref, *next, *ref_list = &scene->textures;
+      for (ref = ref_list->next; ref != ref_list; ref = next) {
+         next = next_elem(ref);
+         pipe_texture_reference(&ref->texture, NULL);
+         FREE(ref);
+      }
+      make_empty_list(ref_list);
+   }
+}
+
+
+/**
+ * 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 )
+{
+   assert(lp_scene_is_empty(scene));
+
+   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;
+}
+
+
+/**
+ * Add a reference to a texture by the scene.
+ */
+void
+lp_scene_texture_reference( struct lp_scene *scene,
+                            struct pipe_texture *texture )
+{
+   struct texture_ref *ref = CALLOC_STRUCT(texture_ref);
+   if (ref) {
+      struct texture_ref *ref_list = &scene->textures;
+      pipe_texture_reference(&ref->texture, texture);
+      insert_at_tail(ref_list, ref);
+   }
+}
+
+
+/**
+ * Does this scene have a reference to the given texture?
+ */
+boolean
+lp_scene_is_textured_referenced( const struct lp_scene *scene,
+                                 const struct pipe_texture *texture )
+{
+   const struct texture_ref *ref_list = &scene->textures;
+   const struct texture_ref *ref;
+   foreach (ref, ref_list) {
+      if (ref->texture == texture)
+         return TRUE;
+   }
+   return FALSE;
+}
+
+
+/**
+ * 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 pointer 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..7db2165
--- /dev/null
@@ -0,0 +1,301 @@
+/**************************************************************************
+ *
+ * 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 "os/os_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;
+};
+
+
+/** List of texture references */
+struct texture_ref {
+   struct pipe_texture *texture;
+   struct texture_ref *prev, *next;  /**< linked list w/ u_simple_list.h */
+};
+
+
+/**
+ * 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;
+
+   /** list of textures referenced by the scene commands */
+   struct texture_ref textures;
+
+   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);
+
+boolean lp_scene_is_empty(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 );
+
+void lp_scene_texture_reference( struct lp_scene *scene,
+                                 struct pipe_texture *texture );
+
+boolean lp_scene_is_textured_referenced( const struct lp_scene *scene,
+                                         const struct pipe_texture *texture );
+
+
+/**
+ * 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];
+}
+
+
+/** Remove all commands from a bin */
+void
+lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned 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;
+
+   assert(x < scene->tiles_x);
+   assert(y < scene->tiles_y);
+
+   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..43d74e4
--- /dev/null
@@ -0,0 +1,122 @@
+/**************************************************************************
+ *
+ * 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 "util/u_ringbuffer.h"
+#include "util/u_memory.h"
+#include "lp_scene_queue.h"
+
+
+
+#define MAX_SCENE_QUEUE 4
+
+struct scene_packet {
+   struct util_packet header;
+   struct lp_scene *scene;
+};
+
+/**
+ * A queue of scenes
+ */
+struct lp_scene_queue
+{
+   struct util_ringbuffer *ring;
+};
+
+
+
+/** 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 == NULL)
+      return NULL;
+
+   queue->ring = util_ringbuffer_create( MAX_SCENE_QUEUE * 
+                                         sizeof( struct scene_packet ) / 4);
+   if (queue->ring == NULL)
+      goto fail;
+
+   return queue;
+
+fail:
+   FREE(queue);
+   return NULL;
+}
+
+
+/** Delete a scene queue */
+void
+lp_scene_queue_destroy(struct lp_scene_queue *queue)
+{
+   util_ringbuffer_destroy(queue->ring);
+   FREE(queue);
+}
+
+
+/** Remove first lp_scene from head of queue */
+struct lp_scene *
+lp_scene_dequeue(struct lp_scene_queue *queue, boolean wait)
+{
+   struct scene_packet packet;
+   enum pipe_error ret;
+
+   ret = util_ringbuffer_dequeue(queue->ring,
+                                 &packet.header,
+                                 sizeof packet / 4,
+                                 wait );
+   if (ret != PIPE_OK)
+      return NULL;
+
+   return packet.scene;
+}
+
+
+/** Add an lp_scene to tail of queue */
+void
+lp_scene_enqueue(struct lp_scene_queue *queue, struct lp_scene *scene)
+{
+   struct scene_packet packet;
+
+   packet.header.dwords = sizeof packet / 4;
+   packet.header.data24 = 0;
+   packet.scene = scene;
+
+   util_ringbuffer_enqueue(queue->ring, &packet.header);
+}
+
+
+
+
+
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..fd7c65a
--- /dev/null
@@ -0,0 +1,51 @@
+/**************************************************************************
+ *
+ * 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, boolean wait);
+
+void
+lp_scene_enqueue(struct lp_scene_queue *queue, struct lp_scene *scene);
+
+
+
+
+#endif /* LP_BIN_QUEUE */
index 902009d90b566d984787aa4b44a15b52f65ff36c..ca64c41827614f1448c2fa8c1d165e231a1b3206 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"
@@ -51,6 +52,10 @@ static const struct debug_named_value lp_debug_flags[] = {
    { "query",  DEBUG_QUERY },
    { "screen", DEBUG_SCREEN },
    { "jit",    DEBUG_JIT },
+   { "show_tiles",    DEBUG_SHOW_TILES },
+   { "show_subtiles", DEBUG_SHOW_SUBTILES },
+   { "counters", DEBUG_COUNTERS },
+   { "nopt", DEBUG_NO_LLVM_OPT },
    {NULL, 0}
 };
 #endif
@@ -309,6 +314,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 92baa980bcc22ea8e12223432738c849f212c9af..2e3ef4ae5cda8bf351a8ccf3515018faa2d5da7a 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_vertex.h"
-#include "pipe/p_shader_tokens.h"
-#include "util/u_format.h"
-#include "util/u_math.h"
+#include "pipe/p_defines.h"
+#include "util/u_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
-
+#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"
 
-/**
- * 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;
+#include "draw/draw_context.h"
+#include "draw/draw_vbuf.h"
 
-   float pixel_offset;
 
-   struct quad_header quad[MAX_QUADS];
-   struct quad_header *quad_ptrs[MAX_QUADS];
-   unsigned count;
+static void set_scene_state( struct setup_context *, unsigned );
 
-   struct quad_interp_coef coef;
 
-   struct {
-      int left[2];   /**< [0] = row0, [1] = row1 */
-      int right[2];
-      int y;
-   } span;
+struct lp_scene *
+lp_setup_get_current_scene(struct setup_context *setup)
+{
+   if (!setup->scene) {
 
-#if DEBUG_FRAGS
-   uint numFragsEmitted;  /**< per primitive */
-   uint numFragsWritten;  /**< per primitive */
-#endif
+      /* wait for a free/empty scene
+       */
+      setup->scene = lp_scene_dequeue(setup->empty_scenes, TRUE);
 
-   unsigned winding;           /* which winding to cull */
-};
+      if(0)lp_scene_reset( setup->scene ); /* XXX temporary? */
 
+      lp_scene_set_framebuffer_size(setup->scene,
+                                    setup->fb.width, 
+                                    setup->fb.height);
+   }
+   return setup->scene;
+}
 
 
-/**
- * Execute fragment shader for the four fragments in the quad.
- */
-PIPE_ALIGN_STACK
 static void
-shade_quads(struct llvmpipe_context *llvmpipe,
-            struct quad_header *quads[],
-            unsigned nr)
+first_triangle( struct setup_context *setup,
+                const float (*v0)[4],
+                const float (*v1)[4],
+                const float (*v2)[4])
 {
-   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;
-   PIPE_ALIGN_VAR(16) uint32_t mask[4][NUM_CHANNELS];
-   unsigned chan_index;
-   unsigned q;
-
-   assert(fs->current);
-   if(!fs->current)
-      return;
-
-   /* 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;
+   set_scene_state( setup, SETUP_ACTIVE );
+   lp_setup_choose_triangle( setup );
+   setup->triangle( setup, v0, v1, v2 );
+}
 
-   /* 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);
-   }
-   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);
+static void
+first_line( struct setup_context *setup,
+           const float (*v0)[4],
+           const float (*v1)[4])
+{
+   set_scene_state( setup, SETUP_ACTIVE );
+   lp_setup_choose_line( setup );
+   setup->line( setup, v0, v1 );
 }
 
+static void
+first_point( struct setup_context *setup,
+            const float (*v0)[4])
+{
+   set_scene_state( setup, SETUP_ACTIVE );
+   lp_setup_choose_point( setup );
+   setup->point( setup, v0 );
+}
 
+static void reset_context( struct setup_context *setup )
+{
+   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;
 
-/**
- * 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)
-{
-   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;
+   /* no current bin */
+   setup->scene = NULL;
 
-      if ((winding & setup->winding) == 0)
-        return FALSE;
-   }
+   /* Reset some state:
+    */
+   setup->clear.flags = 0;
 
-   /* Culled:
+   /* Have an explicit "start-binning" call and get rid of this
+    * pointer twiddling?
     */
-   return TRUE;
+   setup->line = first_line;
+   setup->point = first_point;
+   setup->triangle = first_triangle;
 }
 
 
-
-/**
- * Clip setup->quad against the scissor/surface bounds.
- */
-static INLINE void
-quad_clip( struct setup_context *setup, struct quad_header *quad )
+/** Rasterize all scene's bins */
+static void
+lp_setup_rasterize_scene( struct setup_context *setup,
+                        boolean write_depth )
 {
-   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);
-}
+   struct lp_scene *scene = lp_setup_get_current_scene(setup);
 
+   lp_rasterize_scene(setup->rast,
+                      scene,
+                      &setup->fb,
+                      write_depth);
 
+   reset_context( setup );
 
-/**
- * Given an X or Y coordinate, return the block/quad coordinate that it
- * belongs to.
- */
-static INLINE int block( int x )
-{
-   return x & ~(2-1);
+   LP_DBG(DEBUG_SETUP, "%s done \n", __FUNCTION__);
 }
 
-static INLINE int block_x( int x )
+
+
+static void
+begin_binning( struct setup_context *setup )
 {
-   return x & ~(TILE_VECTOR_WIDTH - 1);
+   struct lp_scene *scene = lp_setup_get_current_scene(setup);
+
+   LP_DBG(DEBUG_SETUP, "%s color: %s depth: %s\n", __FUNCTION__,
+          (setup->clear.flags & PIPE_CLEAR_COLOR) ? "clear": "load",
+          (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) ? "clear": "load");
+
+   if (setup->fb.nr_cbufs) {
+      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() );
+   }
+
+   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() );
+   }
+
+   LP_DBG(DEBUG_SETUP, "%s done\n", __FUNCTION__);
 }
 
 
-/**
- * Emit a quad (pass to next stage) with clipping.
+/* This basically bins and then flushes any outstanding full-screen
+ * clears.  
+ *
+ * TODO: fast path for fullscreen clears and no triangles.
  */
-static INLINE void
-clip_emit_quad( struct setup_context *setup, struct quad_header *quad )
+static void
+execute_clears( struct setup_context *setup )
 {
-   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];
-      }
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-      shade_quads( lp, quad_ptrs, nr_quads );
-#else
-      shade_quads( lp, &quad, 1 );
-#endif
-   }
+   begin_binning( setup );
+   lp_setup_rasterize_scene( setup, TRUE );
 }
 
 
-/**
- * Render a horizontal span of quads
- */
-static void flush_spans( struct setup_context *setup )
+static void
+set_scene_state( struct setup_context *setup,
+           unsigned new_state )
 {
-   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));
+   unsigned old_state = setup->state;
 
-         shade_quads(setup->llvmpipe, setup->quad_ptrs, nr_quads );
+   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;
+
+   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;
    }
 
-
-   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] */
+   setup->state = new_state;
 }
 
 
-#if DEBUG_VERTS
-static void print_vertex(const struct setup_context *setup,
-                         const float (*v)[4])
+void
+lp_setup_flush( struct setup_context *setup,
+                unsigned flags )
 {
-   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");
-      }
-   }
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+
+   set_scene_state( setup, SETUP_FLUSHED );
 }
-#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] )
-{
-   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;
-   }
+void
+lp_setup_bind_framebuffer( struct setup_context *setup,
+                           const struct pipe_framebuffer_state *fb )
+{
+   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;
-   }
+   set_scene_state( setup, SETUP_FLUSHED );
 
-   return TRUE;
-}
+   /* re-get scene pointer, may have a new scene after flushing */
+   scene = lp_setup_get_current_scene(setup);
 
+   util_copy_framebuffer_state(&setup->fb, fb);
 
-/**
- * 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_scene_set_framebuffer_size(scene, setup->fb.width, setup->fb.height);
 }
 
 
-/**
- * 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_pos_coeff( struct setup_context *setup,
-                             uint vertSlot, unsigned i)
+void
+lp_setup_clear( struct setup_context *setup,
+                const float *color,
+                double depth,
+                unsigned stencil,
+                unsigned flags )
 {
-   setup->coef.dadx[0][i] = 0;
-   setup->coef.dady[0][i] = 0;
-
-   /* need provoking vertex info!
-    */
-   setup->coef.a0[0][i] = setup->vprovoke[vertSlot][i];
-}
+   struct lp_scene *scene = lp_setup_get_current_scene(setup);
+   unsigned i;
 
+   LP_DBG(DEBUG_SETUP, "%s state %d\n", __FUNCTION__, setup->state);
 
-/**
- * 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)
-{
-   unsigned i;
-   for (i = 0; i < NUM_CHANNELS; ++i) {
-      setup->coef.dadx[1 + attrib][i] = 0;
-      setup->coef.dady[1 + attrib][i] = 0;
 
-      /* need provoking vertex info!
-       */
-      setup->coef.a0[1 + attrib][i] = setup->vprovoke[vertSlot][i];
+   if (flags & PIPE_CLEAR_COLOR) {
+      for (i = 0; i < 4; ++i)
+         setup->clear.color.clear_color[i] = float_to_ubyte(color[i]);
    }
-}
 
-
-/**
- * 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]);
-      */
+   if (flags & PIPE_CLEAR_DEPTHSTENCIL) {
+      setup->clear.zstencil.clear_zstencil = 
+         util_pack_z_stencil(setup->fb.zsbuf->format, 
+                             depth,
+                             stencil);
    }
-}
 
+   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 );
 
-/**
- * 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):
+      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.
        */
-      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)));
+      set_scene_state( setup, SETUP_CLEARED );
+
+      setup->clear.flags |= flags;
    }
 }
 
 
 /**
- * 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.
+ * Emit a fence.
  */
-static void
-setup_fragcoord_coeff(struct setup_context *setup, uint slot)
+struct pipe_fence_handle *
+lp_setup_fence( struct setup_context *setup )
 {
-   /*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];
-}
+   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);
 
+   LP_DBG(DEBUG_SETUP, "%s rank %u\n", __FUNCTION__, rank);
 
+   set_scene_state( setup, SETUP_ACTIVE );
 
-/**
- * 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 )
-{
-   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;
+   /* insert the fence into all command bins */
+   lp_scene_bin_everywhere( scene,
+                           lp_rast_fence,
+                           lp_rast_arg_fence(fence) );
 
-   /* z and w are done by linear interpolation:
-    */
-   tri_pos_coeff(setup, 0, 2);
-   tri_pos_coeff(setup, 0, 3);
+   return (struct pipe_fence_handle *) fence;
+}
 
-   /* setup interpolation for all the remaining attributes:
-    */
-   for (fragSlot = 0; fragSlot < lpfs->info.num_inputs; fragSlot++) {
-      const uint vertSlot = vinfo->attrib[fragSlot].src_index;
 
-      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);
-      }
+void 
+lp_setup_set_triangle_state( struct setup_context *setup,
+                             unsigned cull_mode,
+                             boolean ccw_is_frontface,
+                             boolean scissor )
+{
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-      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;
-      }
-   }
+   setup->ccw_is_frontface = ccw_is_frontface;
+   setup->cullmode = cull_mode;
+   setup->triangle = first_triangle;
+   setup->scissor_test = scissor;
 }
 
 
 
-static void setup_tri_edges( struct setup_context *setup )
+void
+lp_setup_set_fs_inputs( struct setup_context *setup,
+                        const struct lp_shader_input *input,
+                        unsigned nr )
 {
-   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;
-}
+   LP_DBG(DEBUG_SETUP, "%s %p %u\n", __FUNCTION__, (void *) input, nr);
 
+   memcpy( setup->fs.input, input, nr * sizeof input[0] );
+   setup->fs.nr_inputs = nr;
+}
 
-/**
- * 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 )
+void
+lp_setup_set_fs_functions( struct setup_context *setup,
+                           lp_jit_frag_func jit_function0,
+                           lp_jit_frag_func jit_function1,
+                           boolean opaque )
 {
-   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);
-         }
+   LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) jit_function0);
+   /* FIXME: reference count */
 
-         setup->span.left[_y&1] = left;
-         setup->span.right[_y&1] = right;
-      }
-   }
-
-
-   /* 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;
+   setup->fs.current.jit_function[0] = jit_function0;
+   setup->fs.current.jit_function[1] = jit_function1;
+   setup->fs.current.opaque = opaque;
+   setup->dirty |= LP_SETUP_NEW_FS;
 }
 
-
-/**
- * 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] )
+void
+lp_setup_set_fs_constants(struct setup_context *setup,
+                          struct pipe_buffer *buffer)
 {
-   /* 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;
+   LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) buffer);
+
+   pipe_buffer_reference(&setup->constants.current, buffer);
+
+   setup->dirty |= LP_SETUP_NEW_CONSTANTS;
 }
 
 
-/**
- * Do setup for triangle rasterization, then render the triangle.
- */
-void llvmpipe_setup_tri( struct setup_context *setup,
-                const float (*v0)[4],
-                const float (*v1)[4],
-                const float (*v2)[4] )
+void
+lp_setup_set_alpha_ref_value( struct setup_context *setup,
+                              float alpha_ref_value )
 {
-   float det;
-
-#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 %f\n", __FUNCTION__, alpha_ref_value);
 
-   if (setup->llvmpipe->no_rast)
-      return;
-   
-   det = calc_det(v0, v1, v2);
-   /*
-   debug_printf("%s\n", __FUNCTION__ );
-   */
+   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;
+   }
+}
 
-#if DEBUG_FRAGS
-   setup->numFragsEmitted = 0;
-   setup->numFragsWritten = 0;
-#endif
+void
+lp_setup_set_blend_color( struct setup_context *setup,
+                          const struct pipe_blend_color *blend_color )
+{
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-   if (cull_tri( setup, det ))
-      return;
+   assert(blend_color);
 
-   if (!setup_sort_vertices( setup, det, v0, v1, v2 ))
-      return;
-   setup_tri_coefficients( setup );
-   setup_tri_edges( setup );
+   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;
+   }
+}
 
-   assert(setup->llvmpipe->reduced_prim == PIPE_PRIM_TRIANGLES);
 
-   setup->span.y = 0;
-   setup->span.right[0] = 0;
-   setup->span.right[1] = 0;
-   /*   setup->span.z_mode = tri_z_mode( setup->ctx ); */
+void
+lp_setup_set_scissor( struct setup_context *setup,
+                      const struct pipe_scissor_state *scissor )
+{
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-   /*   init_constant_attribs( setup ); */
+   assert(scissor);
 
-   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 );
+   if (memcmp(&setup->scissor.current, scissor, sizeof(*scissor)) != 0) {
+      setup->scissor.current = *scissor; /* struct copy */
+      setup->dirty |= LP_SETUP_NEW_SCISSOR;
    }
-
-   flush_spans( setup );
-
-#if DEBUG_FRAGS
-   printf("Tri: %u frags emitted, %u written\n",
-          setup->numFragsEmitted,
-          setup->numFragsWritten);
-#endif
 }
 
 
-
-/**
- * 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_flatshade_first( struct setup_context *setup,
+                              boolean flatshade_first )
 {
-   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)));
+   setup->flatshade_first = flatshade_first;
 }
 
 
-/**
- * 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)
+void 
+lp_setup_set_vertex_info( struct setup_context *setup,
+                          struct vertex_info *vertex_info )
 {
-   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)));
-   }
+   /* XXX: just silently holding onto the pointer:
+    */
+   setup->vertex_info = vertex_info;
 }
 
 
 /**
- * Compute a0, dadx and dady for a perspective-corrected interpolant,
- * for a line.
+ * Called during state validation when LP_NEW_TEXTURE is set.
  */
-static void
-line_persp_coeff(struct setup_context *setup,
-                 unsigned attrib,
-                 uint vertSlot)
+void
+lp_setup_set_sampler_textures( struct setup_context *setup,
+                               unsigned num, struct pipe_texture **texture)
 {
    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\n", __FUNCTION__);
+
+   assert(num <= PIPE_MAX_SAMPLERS);
+
+   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
+      struct pipe_texture *tex = i < num ? texture[i] : NULL;
+
+      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);
+
+         /* the scene references this texture */
+         {
+            struct lp_scene *scene = lp_setup_get_current_scene(setup);
+            lp_scene_texture_reference(scene, tex);
+         }
+      }
    }
+
+   setup->dirty |= LP_SETUP_NEW_FS;
 }
 
 
 /**
- * Compute the setup->coef[] array dadx, dady, a0 values.
- * Must be called after setup->vmin,vmax are initialized.
+ * Is the given texture referenced by any scene?
+ * Note: we have to check all scenes including any scenes currently
+ * being rendered and the current scene being built.
  */
-static INLINE boolean
-setup_line_coefficients(struct setup_context *setup,
-                        const float (*v0)[4],
-                        const float (*v1)[4])
+unsigned
+lp_setup_is_texture_referenced( const struct setup_context *setup,
+                                const struct pipe_texture *texture )
 {
-   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);
-
-   /* setup interpolation for all the remaining attributes:
-    */
-   for (fragSlot = 0; fragSlot < lpfs->info.num_inputs; fragSlot++) {
-      const uint vertSlot = vinfo->attrib[fragSlot].src_index;
-
-      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);
-      }
+   unsigned i;
 
-      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;
-      }
+   /* check the render targets */
+   for (i = 0; i < setup->fb.nr_cbufs; i++) {
+      if (setup->fb.cbufs[i]->texture == texture)
+         return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+   }
+   if (setup->fb.zsbuf && setup->fb.zsbuf->texture == texture) {
+      return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
    }
-   return TRUE;
-}
-
 
-/**
- * Plot a pixel in a line segment.
- */
-static INLINE void
-plot(struct setup_context *setup, int x, int y)
-{
-   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;
+   /* check textures referenced by the scene */
+   for (i = 0; i < Elements(setup->scenes); i++) {
+      if (lp_scene_is_textured_referenced(setup->scenes[i], texture)) {
+         return PIPE_REFERENCED_FOR_READ;
+      }
    }
 
-   setup->quad[0].inout.mask |= mask;
+   return PIPE_UNREFERENCED;
 }
 
 
 /**
- * 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.
+ * Called by vbuf code when we're about to draw something.
  */
 void
-llvmpipe_setup_line(struct setup_context *setup,
-           const float (*v0)[4],
-           const float (*v1)[4])
+lp_setup_update_state( struct setup_context *setup )
 {
-   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;
-
-   if (dx == 0 && dy == 0)
-      return;
+   struct lp_scene *scene = lp_setup_get_current_scene(setup);
 
-   if (!setup_line_coefficients(setup, v0, v1))
-      return;
-
-   assert(v0[0][0] < 1.0e9);
-   assert(v0[0][1] < 1.0e9);
-   assert(v1[0][0] < 1.0e9);
-   assert(v1[0][1] < 1.0e9);
-
-   if (dx < 0) {
-      dx = -dx;   /* make positive */
-      xstep = -1;
-   }
-   else {
-      xstep = 1;
-   }
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-   if (dy < 0) {
-      dy = -dy;   /* make positive */
-      ystep = -1;
-   }
-   else {
-      ystep = 1;
-   }
+   assert(setup->fs.current.jit_function);
 
-   assert(dx >= 0);
-   assert(dy >= 0);
-   assert(setup->llvmpipe->reduced_prim == PIPE_PRIM_LINES);
+   if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) {
+      uint8_t *stored;
+      unsigned i, j;
 
-   setup->quad[0].input.x0 = setup->quad[0].input.y0 = -1;
-   setup->quad[0].inout.mask = 0x0;
+      stored = lp_scene_alloc_aligned(scene, 4 * 16, 16);
 
-   /* 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;
-         }
+      /* 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;
       }
-   }
 
-   /* draw final quad */
-   if (setup->quad[0].inout.mask) {
-      clip_emit_quad( setup, &setup->quad[0] );
+      setup->blend_color.stored = stored;
+
+      setup->fs.current.jit_context.blend_color = setup->blend_color.stored;
+      setup->dirty |= LP_SETUP_NEW_FS;
    }
-}
 
+   if (setup->dirty & LP_SETUP_NEW_SCISSOR) {
+      float *stored;
 
-static void
-point_persp_coeff(struct setup_context *setup,
-                  const float (*vert)[4],
-                  unsigned attrib,
-                  uint vertSlot)
-{
-   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];
-   }
-}
+      stored = lp_scene_alloc_aligned(scene, 4 * sizeof(int32_t), 16);
 
+      stored[0] = (float) setup->scissor.current.minx;
+      stored[1] = (float) setup->scissor.current.miny;
+      stored[2] = (float) setup->scissor.current.maxx;
+      stored[3] = (float) setup->scissor.current.maxy;
 
-/**
- * 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] )
-{
-   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;
+      setup->scissor.stored = stored;
 
-   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;
+      setup->fs.current.jit_context.scissor_xmin = stored[0];
+      setup->fs.current.jit_context.scissor_ymin = stored[1];
+      setup->fs.current.jit_context.scissor_xmax = stored[2];
+      setup->fs.current.jit_context.scissor_ymax = stored[3];
 
-   /* setup Z, W */
-   const_pos_coeff(setup, 0, 2);
-   const_pos_coeff(setup, 0, 3);
+      setup->dirty |= LP_SETUP_NEW_FS;
+   }
 
-   for (fragSlot = 0; fragSlot < lpfs->info.num_inputs; fragSlot++) {
-      const uint vertSlot = vinfo->attrib[fragSlot].src_index;
+   if(setup->dirty & LP_SETUP_NEW_CONSTANTS) {
+      struct pipe_buffer *buffer = setup->constants.current;
 
-      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);
-      }
+      if(buffer) {
+         unsigned current_size = buffer->size;
+         const void *current_data = llvmpipe_buffer(buffer)->data;
 
-      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;
-      }
-   }
+         /* 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;
 
-   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] );
-   }
-   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] );
-               }
+            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 (1) {
+      struct lp_scene *scene = lp_scene_dequeue(setup->empty_scenes, FALSE);
+      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++) {
+      setup->scenes[i] = lp_scene_create();
+      lp_scene_enqueue(setup->empty_scenes, setup->scenes[i]);
    }
 
-   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..0e155a7dc313bdef5ae7d32e5c2a5e2d2d549374 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,
+                             boolean scissor );
 
 void
-llvmpipe_setup_line(struct setup_context *setup,
-           const float (*v0)[4],
-           const float (*v1)[4]);
+lp_setup_set_fs_inputs( struct setup_context *setup,
+                        const struct lp_shader_input *interp,
+                        unsigned nr );
 
 void
-llvmpipe_setup_point( struct setup_context *setup,
-             const float (*v0)[4] );
+lp_setup_set_fs_functions( struct setup_context *setup,
+                           lp_jit_frag_func jit_function0,
+                           lp_jit_frag_func jit_function1,
+                           boolean opaque );
 
+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
+lp_setup_set_blend_color( struct setup_context *setup,
+                          const struct pipe_blend_color *blend_color );
+
+void
+lp_setup_set_scissor( struct setup_context *setup,
+                      const struct pipe_scissor_state *scissor );
+
+void
+lp_setup_set_sampler_textures( struct setup_context *setup,
+                               unsigned num, struct pipe_texture **texture);
+
+unsigned
+lp_setup_is_texture_referenced( const 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..a5fc34e
--- /dev/null
@@ -0,0 +1,159 @@
+/**************************************************************************
+ *
+ * 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
+#define LP_SETUP_NEW_SCISSOR     0x08
+
+
+struct lp_scene_queue;
+
+
+/** Max number of scenes */
+#define MAX_SCENES 2
+
+
+
+/**
+ * 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 *scenes[MAX_SCENES];  /**< all the scenes */
+   struct lp_scene *scene;               /**< current scene being built */
+   struct lp_scene_queue *empty_scenes;  /**< queue of empty scenes */
+
+   boolean flatshade_first;
+   boolean ccw_is_frontface;
+   boolean scissor_test;
+   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;
+
+   struct {
+      struct pipe_scissor_state current;
+      const void *stored;
+   } scissor;
+
+   unsigned dirty;   /**< bitmask of LP_SETUP_NEW_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..9e59a66
--- /dev/null
@@ -0,0 +1,618 @@
+/**************************************************************************
+ *
+ * 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 "util/u_math.h"
+#include "util/u_memory.h"
+#include "lp_perf.h"
+#include "lp_setup_context.h"
+#include "lp_rast.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.0f;
+   tri->inputs.dady[slot][i] = 0.0f;
+}
+
+
+/**
+ * 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] = (a1 -
+                              (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
+ * 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)
+{
+   unsigned slot;
+
+   /* 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 - (FIXED_ONE / 2));
+}
+
+
+
+/**
+ * Alloc space for a new triangle plus the input.a0/dadx/dady arrays
+ * immediately after it.
+ * The memory is allocated from the per-scene pool, not per-tile.
+ * \param tri_size  returns number of bytes allocated
+ * \param nr_inputs  number of fragment shader inputs
+ * \return pointer to triangle space
+ */
+static INLINE struct lp_rast_triangle *
+alloc_triangle(struct lp_scene *scene, unsigned nr_inputs, unsigned *tri_size)
+{
+   unsigned input_array_sz = NUM_CHANNELS * (nr_inputs + 1) * sizeof(float);
+   struct lp_rast_triangle *tri;
+   unsigned bytes;
+   char *inputs;
+
+   assert(sizeof(*tri) % 16 == 0);
+
+   bytes = sizeof(*tri) + (3 * input_array_sz);
+
+   tri = lp_scene_alloc_aligned( scene, bytes, 16 );
+
+   inputs = (char *) (tri + 1);
+   tri->inputs.a0   = (float (*)[4]) inputs;
+   tri->inputs.dadx = (float (*)[4]) (inputs + input_array_sz);
+   tri->inputs.dady = (float (*)[4]) (inputs + 2 * input_array_sz);
+
+   *tri_size = bytes;
+
+   return tri;
+}
+
+
+
+/**
+ * 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;
+   int area;
+   float oneoverarea;
+   int minx, maxx, miny, maxy;
+   unsigned tri_bytes;
+
+   tri = alloc_triangle(scene, setup->fs.nr_inputs, &tri_bytes);
+
+   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);
+
+   LP_COUNT(nr_tris);
+
+   /* Cull non-ccw and zero-sized triangles. 
+    *
+    * XXX: subject to overflow??
+    */
+   if (area <= 0) {
+      lp_scene_putback_data( scene, tri_bytes );
+      LP_COUNT(nr_culled_tris);
+      return;
+   }
+
+   /* Bounding rectangle (in pixels) */
+   minx = (MIN3(x1, x2, x3) + (FIXED_ONE-1)) >> FIXED_ORDER;
+   maxx = (MAX3(x1, x2, x3) + (FIXED_ONE-1)) >> FIXED_ORDER;
+   miny = (MIN3(y1, y2, y3) + (FIXED_ONE-1)) >> FIXED_ORDER;
+   maxy = (MAX3(y1, y2, y3) + (FIXED_ONE-1)) >> FIXED_ORDER;
+   
+   if (setup->scissor_test) {
+      minx = MAX2(minx, setup->scissor.current.minx);
+      maxx = MIN2(maxx, setup->scissor.current.maxx);
+      miny = MAX2(miny, setup->scissor.current.miny);
+      maxy = MIN2(maxy, setup->scissor.current.maxy);
+   }
+
+   if (miny == maxy || 
+       minx == maxx) {
+      lp_scene_putback_data( scene, tri_bytes );
+      LP_COUNT(nr_culled_tris);
+      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 render target.
+    */
+   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;
+
+   /* Fill in the inputs.step[][] arrays.
+    * We've manually unrolled some loops here.
+    */
+   {
+      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;
+
+#define SETUP_STEP(i, x, y)                                \
+      do {                                                 \
+         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; \
+      } while (0)
+
+      SETUP_STEP(0, 0, 0);
+      SETUP_STEP(1, 1, 0);
+      SETUP_STEP(2, 0, 1);
+      SETUP_STEP(3, 1, 1);
+
+      SETUP_STEP(4, 2, 0);
+      SETUP_STEP(5, 3, 0);
+      SETUP_STEP(6, 2, 1);
+      SETUP_STEP(7, 3, 1);
+
+      SETUP_STEP(8, 0, 2);
+      SETUP_STEP(9, 1, 2);
+      SETUP_STEP(10, 0, 3);
+      SETUP_STEP(11, 1, 3);
+
+      SETUP_STEP(12, 2, 2);
+      SETUP_STEP(13, 3, 2);
+      SETUP_STEP(14, 2, 3);
+      SETUP_STEP(15, 3, 3);
+#undef STEP
+   }
+
+   /*
+    * All fields of 'tri' are now set.  The remaining code here is
+    * concerned with binning.
+    */
+
+   /* Convert to tile coordinates:
+    */
+   minx = minx / TILE_SIZE;
+   miny = miny / TILE_SIZE;
+   maxx = maxx / TILE_SIZE;
+   maxy = maxy / TILE_SIZE;
+
+   /* Clamp maxx, maxy to framebuffer size
+    */
+   maxx = MIN2(maxx, scene->tiles_x - 1);
+   maxy = MIN2(maxy, scene->tiles_y - 1);
+
+   /* 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;
+
+
+      /* Test tile-sized blocks against the triangle.
+       * Discard blocks fully outside the tri.  If the block is fully
+       * contained inside the tri, bin an lp_rast_shade_tile command.
+       * Else, bin a lp_rast_triangle command.
+       */
+      for (y = miny; y <= maxy; y++)
+      {
+        int cx1 = c1;
+        int cx2 = c2;
+        int cx3 = c3;
+        boolean in = FALSE;  /* are we inside the triangle? */
+
+        for (x = minx; x <= maxx; x++)
+        {
+           if (cx1 + eo1 < 0 || 
+               cx2 + eo2 < 0 ||
+               cx3 + eo3 < 0) 
+           {
+              /* do nothing */
+               LP_COUNT(nr_empty_64);
+              if (in)
+                 break;  /* exiting triangle, all done with this row */
+           }
+           else if (cx1 + ei1 > 0 &&
+                    cx2 + ei2 > 0 &&
+                    cx3 + ei3 > 0) 
+           {
+               /* triangle covers the whole tile- shade whole tile */
+               LP_COUNT(nr_fully_covered_64);
+              in = TRUE;
+              if(setup->fs.current.opaque) {
+                 lp_scene_bin_reset( scene, x, y );
+                 lp_scene_bin_command( scene, x, y,
+                                       lp_rast_set_state,
+                                       lp_rast_arg_state(setup->fs.stored) );
+              }
+               lp_scene_bin_command( scene, x, y,
+                                    lp_rast_shade_tile,
+                                    lp_rast_arg_inputs(&tri->inputs) );
+           }
+           else 
+           { 
+               /* rasterizer/shade partial tile */
+               LP_COUNT(nr_partially_covered_64);
+              in = TRUE;
+               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.0f) 
+      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 e16793186be6f9ce49261322e4d0d7aa4f7332df..4242653c909ffa1a1dcd63f9ff8881b19495832d 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;
@@ -65,11 +66,18 @@ struct lp_fragment_shader;
 
 struct lp_fragment_shader_variant_key
 {
-   enum pipe_format zsbuf_format;
    struct pipe_depth_state depth;
    struct pipe_alpha_state alpha;
    struct pipe_blend_state blend;
-
+   enum pipe_format zsbuf_format;
+   unsigned nr_cbufs:8;
+   unsigned flatshade:1;
+   unsigned scissor:1;
+
+   struct {
+      ubyte colormask;
+   } cbuf_blend[PIPE_MAX_COLOR_BUFS];
+   
    struct lp_sampler_static_state sampler[PIPE_MAX_SAMPLERS];
 };
 
@@ -80,9 +88,9 @@ struct lp_fragment_shader_variant
 
    struct lp_fragment_shader_variant_key key;
 
-   LLVMValueRef function;
+   LLVMValueRef function[2];
 
-   lp_jit_frag_func jit_function;
+   lp_jit_frag_func jit_function[2];
 
    struct lp_fragment_shader_variant *next;
 };
@@ -211,12 +219,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 +226,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..9b950e82d897394976d4e71dc109c72cb5e370cd 100644 (file)
@@ -73,7 +73,9 @@ 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;
@@ -82,13 +84,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 +113,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 353ae176fdb33bb9e3f45441ab152a4fafeaf811..bdd906e1a73922c9291bb2cd6d354b2e04d0bb17 100644 (file)
 #include "draw/draw_private.h"
 #include "lp_context.h"
 #include "lp_screen.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_num_shader_outputs(llvmpipe->draw);
-      uint i;
-
-      /* 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);
+   /* 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);
 
-      /*
-       * 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;
 
-         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;
-         }
+   lp_setup_set_vertex_info(llvmpipe->setup, vinfo);
+
+/*
+   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.
+ * Handle state changes.
+ * Called just prior to drawing anything (pipe::draw_arrays(), etc).
  *
- * 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.
- */
-static void
-compute_cliprect(struct llvmpipe_context *lp)
-{
-   /* LP_NEW_FRAMEBUFFER
-    */
-   uint surfWidth = lp->framebuffer.width;
-   uint surfHeight = lp->framebuffer.height;
-
-   /* LP_NEW_RASTERIZER
-    */
-   if (lp->rasterizer->scissor) {
-
-      /* LP_NEW_SCISSOR
-       *
-       * clip to scissor rect:
-       */
-      lp->cliprect.minx = MAX2(lp->scissor.minx, 0);
-      lp->cliprect.miny = MAX2(lp->scissor.miny, 0);
-      lp->cliprect.maxx = MIN2(lp->scissor.maxx, surfWidth);
-      lp->cliprect.maxy = MIN2(lp->scissor.maxy, surfHeight);
-   }
-   else {
-      /* clip to surface bounds */
-      lp->cliprect.minx = 0;
-      lp->cliprect.miny = 0;
-      lp->cliprect.maxx = surfWidth;
-      lp->cliprect.maxy = surfHeight;
-   }
-}
-
-
-/* Hopefully this will remain quite simple, otherwise need to pull in
+ * Hopefully this will remain quite simple, otherwise need to pull in
  * something like the state tracker mechanism.
  */
 void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
@@ -205,28 +153,40 @@ 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 );
-
-   if (llvmpipe->dirty & (LP_NEW_SCISSOR |
-                          LP_NEW_RASTERIZER |
-                          LP_NEW_FRAMEBUFFER))
-      compute_cliprect(llvmpipe);
+      compute_vertex_info( llvmpipe );
 
    if (llvmpipe->dirty & (LP_NEW_FS |
                           LP_NEW_BLEND |
+                          LP_NEW_SCISSOR |
                           LP_NEW_DEPTH_STENCIL_ALPHA |
+                          LP_NEW_RASTERIZER |
                           LP_NEW_SAMPLER |
                           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_SCISSOR)
+      lp_setup_set_scissor(llvmpipe->setup, &llvmpipe->scissor);
+
+   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]);
+
+   if (llvmpipe->dirty & LP_NEW_TEXTURE)
+      lp_setup_set_sampler_textures(llvmpipe->setup, 
+                                    llvmpipe->num_textures,
+                                    llvmpipe->texture);
 
    llvmpipe->dirty = 0;
 }
+
index f3263cf37700610e438b12a45389021b0c7239cb..c5f6df23a1693b6a133eacfe07158ccb791d93e6 100644 (file)
@@ -31,6 +31,8 @@
  * Code generate the whole fragment pipeline.
  *
  * The fragment pipeline consists of the following stages:
+ * - triangle edge in/out testing
+ * - scissor test
  * - stipple (TBI)
  * - early depth test
  * - fragment shader
  * @author Jose Fonseca <jfonseca@vmware.com>
  */
 
+#include <limits.h>
 #include "pipe/p_defines.h"
 #include "util/u_inlines.h"
 #include "util/u_memory.h"
 #include "util/u_format.h"
 #include "util/u_debug_dump.h"
+#include "util/u_time.h"
 #include "pipe/p_shader_tokens.h"
 #include "draw/draw_context.h"
 #include "tgsi/tgsi_dump.h"
 #include "lp_bld_swizzle.h"
 #include "lp_bld_flow.h"
 #include "lp_bld_debug.h"
-#include "lp_screen.h"
-#include "lp_context.h"
 #include "lp_buffer.h"
+#include "lp_context.h"
+#include "lp_debug.h"
+#include "lp_perf.h"
+#include "lp_screen.h"
+#include "lp_setup.h"
 #include "lp_state.h"
 #include "lp_tex_sample.h"
-#include "lp_debug.h"
 
 
 static const unsigned char quad_offset_x[4] = {0, 1, 0, 1};
@@ -185,8 +191,188 @@ 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 */
+{
+#define OPTIMIZE_IN_OUT_TEST 0
+#if OPTIMIZE_IN_OUT_TEST
+   struct lp_build_if_state ifctx;
+   LLVMValueRef not_draw_all;
+#endif
+   struct lp_build_flow_context *flow;
+   struct lp_type i32_type;
+   LLVMTypeRef i32vec4_type, mask_type;
+   LLVMValueRef c0_vec, c1_vec, c2_vec;
+   LLVMValueRef in_out_mask;
+
+   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();
+
+   mask_type = LLVMIntType(32 * 4);
+
+   /*
+    * Use a conditional here to do detailed pixel in/out testing.
+    * We only have to do this if c0 != INT_MIN.
+    */
+   flow = lp_build_flow_create(builder);
+   lp_build_flow_scope_begin(flow);
+
+   {
+#if OPTIMIZE_IN_OUT_TEST
+      /* not_draw_all = (c0 != INT_MIN) */
+      not_draw_all = LLVMBuildICmp(builder,
+                                   LLVMIntNE,
+                                   c0,
+                                   LLVMConstInt(LLVMInt32Type(), INT_MIN, 0),
+                                   "");
+
+      in_out_mask = lp_build_int_const_scalar(i32_type, ~0);
+
+
+      lp_build_flow_scope_declare(flow, &in_out_mask);
+
+      /* if (not_draw_all) {... */
+      lp_build_if(&ifctx, flow, builder, not_draw_all);
+#endif
+      {
+         LLVMValueRef step0_vec, step1_vec, step2_vec;
+         LLVMValueRef m0_vec, m1_vec, m2_vec;
+         LLVMValueRef index, m;
+
+         /* 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");
+
+         /* load step0vec, step1, step2 vec from memory */
+         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 = step0_ptr[i] > c0_vec */
+         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);
+
+         /* in_out_mask = m0_vec & m1_vec & m2_vec */
+         m = LLVMBuildAnd(builder, m0_vec, m1_vec, "");
+         in_out_mask = LLVMBuildAnd(builder, m, m2_vec, "");
+         lp_build_name(in_out_mask, "inoutmaskvec");
+      }
+#if OPTIMIZE_IN_OUT_TEST
+      lp_build_endif(&ifctx);
+#endif
+
+   }
+   lp_build_flow_scope_end(flow);
+   lp_build_flow_destroy(flow);
+
+   /* This is the initial alive/dead pixel mask for a quad of four pixels.
+    * It's an int[4] vector with each word set to 0 or ~0.
+    * Words will get cleared when pixels faile the Z test, etc.
+    */
+   *mask = in_out_mask;
+}
+
+
+static LLVMValueRef
+generate_scissor_test(LLVMBuilderRef builder,
+                      LLVMValueRef context_ptr,
+                      const struct lp_build_interp_soa_context *interp,
+                      struct lp_type type)
+{
+   LLVMTypeRef vec_type = lp_build_vec_type(type);
+   LLVMValueRef xpos = interp->pos[0], ypos = interp->pos[1];
+   LLVMValueRef xmin, ymin, xmax, ymax;
+   LLVMValueRef m0, m1, m2, m3, m;
+
+   /* xpos, ypos contain the window coords for the four pixels in the quad */
+   assert(xpos);
+   assert(ypos);
+
+   /* get the current scissor bounds, convert to vectors */
+   xmin = lp_jit_context_scissor_xmin_value(builder, context_ptr);
+   xmin = lp_build_broadcast(builder, vec_type, xmin);
+
+   ymin = lp_jit_context_scissor_ymin_value(builder, context_ptr);
+   ymin = lp_build_broadcast(builder, vec_type, ymin);
+
+   xmax = lp_jit_context_scissor_xmax_value(builder, context_ptr);
+   xmax = lp_build_broadcast(builder, vec_type, xmax);
+
+   ymax = lp_jit_context_scissor_ymax_value(builder, context_ptr);
+   ymax = lp_build_broadcast(builder, vec_type, ymax);
+
+   /* compare the fragment's position coordinates against the scissor bounds */
+   m0 = lp_build_compare(builder, type, PIPE_FUNC_GEQUAL, xpos, xmin);
+   m1 = lp_build_compare(builder, type, PIPE_FUNC_GEQUAL, ypos, ymin);
+   m2 = lp_build_compare(builder, type, PIPE_FUNC_LESS, xpos, xmax);
+   m3 = lp_build_compare(builder, type, PIPE_FUNC_LESS, ypos, ymax);
+
+   /* AND all the masks together */
+   m = LLVMBuildAnd(builder, m0, m1, "");
+   m = LLVMBuildAnd(builder, m, m2, "");
+   m = LLVMBuildAnd(builder, m, m3, "");
+
+   lp_build_name(m, "scissormask");
+
+   return m;
+}
+
+
+static LLVMValueRef
+build_int32_vec_const(int value)
+{
+   struct lp_type i32_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 */
+   return lp_build_int_const_scalar(i32_type, value);
+}
+
+
+
 /**
  * Generate the fragment shader, depth/stencil test, and alpha tests.
+ * \param i  which quad in the tile, in range [0,3]
+ * \param do_tri_test  if 1, do triangle edge in/out testing
  */
 static void
 generate_fs(struct llvmpipe_context *lp,
@@ -199,8 +385,15 @@ generate_fs(struct llvmpipe_context *lp,
             const struct lp_build_interp_soa_context *interp,
             struct lp_build_sampler_soa *sampler,
             LLVMValueRef *pmask,
-            LLVMValueRef *color,
-            LLVMValueRef depth_ptr)
+            LLVMValueRef (*color)[4],
+            LLVMValueRef depth_ptr,
+            unsigned do_tri_test,
+            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;
@@ -214,6 +407,9 @@ generate_fs(struct llvmpipe_context *lp,
    boolean early_depth_test;
    unsigned attrib;
    unsigned chan;
+   unsigned cbuf;
+
+   assert(i < 4);
 
    elem_type = lp_build_elem_type(type);
    vec_type = lp_build_vec_type(type);
@@ -228,14 +424,32 @@ generate_fs(struct llvmpipe_context *lp,
    lp_build_flow_scope_begin(flow);
 
    /* Declare the color and z variables */
-   for(chan = 0; chan < NUM_CHANNELS; ++chan) {
-      color[chan] = LLVMGetUndef(vec_type);
-      lp_build_flow_scope_declare(flow, &color[chan]);
+   for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++) {
+      for(chan = 0; chan < NUM_CHANNELS; ++chan) {
+        color[cbuf][chan] = LLVMGetUndef(vec_type);
+        lp_build_flow_scope_declare(flow, &color[cbuf][chan]);
+      }
    }
    lp_build_flow_scope_declare(flow, &z);
 
+   /* do triangle edge testing */
+   if (do_tri_test) {
+      generate_tri_edge_mask(builder, i, pmask,
+                             c0, c1, c2, step0_ptr, step1_ptr, step2_ptr);
+   }
+   else {
+      *pmask = build_int32_vec_const(~0);
+   }
+
+   /* 'mask' will control execution based on quad's pixel alive/killed state */
    lp_build_mask_begin(&mask, flow, type, *pmask);
 
+   if (key->scissor) {
+      LLVMValueRef smask =
+         generate_scissor_test(builder, context_ptr, interp, type);
+      lp_build_mask_update(&mask, smask);
+   }
+
    early_depth_test =
       key->depth.enabled &&
       !key->alpha.enabled &&
@@ -265,6 +479,7 @@ generate_fs(struct llvmpipe_context *lp,
 
                   /* Alpha test */
                   /* XXX: should the alpha reference value be passed separately? */
+                 /* XXX: should only test the final assignment to alpha */
                   if(cbuf == 0 && chan == 3) {
                      LLVMValueRef alpha = outputs[attrib][chan];
                      LLVMValueRef alpha_ref_value;
@@ -274,9 +489,7 @@ generate_fs(struct llvmpipe_context *lp,
                                          &mask, alpha, alpha_ref_value);
                   }
 
-                  if(cbuf == 0)
-                     color[chan] = outputs[attrib][chan];
-
+                 color[cbuf][chan] = outputs[attrib][chan];
                   break;
                }
 
@@ -331,6 +544,8 @@ generate_blend(const struct pipe_blend_state *blend,
    lp_build_context_init(&bld, builder, type);
 
    flow = lp_build_flow_create(builder);
+
+   /* we'll use this mask context to skip blending if all pixels are dead */
    lp_build_mask_begin(&mask_ctx, flow, type, mask);
 
    vec_type = lp_build_vec_type(type);
@@ -368,14 +583,18 @@ 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 *
+static void
 generate_fragment(struct llvmpipe_context *lp,
                   struct lp_fragment_shader *shader,
-                  const struct lp_fragment_shader_variant_key *key)
+                  struct lp_fragment_shader_variant *variant,
+                  unsigned do_tri_test)
 {
    struct llvmpipe_screen *screen = llvmpipe_screen(lp->pipe.screen);
-   struct lp_fragment_shader_variant *variant;
+   const struct lp_fragment_shader_variant_key *key = &variant->key;
    struct lp_type fs_type;
    struct lp_type blend_type;
    LLVMTypeRef fs_elem_type;
@@ -383,17 +602,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 color_ptr_ptr;
    LLVMValueRef depth_ptr;
+   LLVMValueRef c0, c1, c2, step0_ptr, step1_ptr, step2_ptr;
    LLVMBasicBlockRef block;
    LLVMBuilderRef builder;
    LLVMValueRef x0;
@@ -401,71 +621,15 @@ generate_fragment(struct llvmpipe_context *lp,
    struct lp_build_sampler_soa *sampler;
    struct lp_build_interp_soa_context interp;
    LLVMValueRef fs_mask[LP_MAX_VECTOR_LENGTH];
-   LLVMValueRef fs_out_color[NUM_CHANNELS][LP_MAX_VECTOR_LENGTH];
+   LLVMValueRef fs_out_color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS][LP_MAX_VECTOR_LENGTH];
    LLVMValueRef blend_mask;
    LLVMValueRef blend_in_color[NUM_CHANNELS];
+   LLVMValueRef function;
    unsigned num_fs;
    unsigned i;
    unsigned chan;
+   unsigned cbuf;
 
-   if (LP_DEBUG & DEBUG_JIT) {
-      tgsi_dump(shader->base.tokens, 0);
-      if(key->depth.enabled) {
-         debug_printf("depth.format = %s\n", pf_name(key->zsbuf_format));
-         debug_printf("depth.func = %s\n", debug_dump_func(key->depth.func, TRUE));
-         debug_printf("depth.writemask = %u\n", key->depth.writemask);
-      }
-      if(key->alpha.enabled) {
-         debug_printf("alpha.func = %s\n", debug_dump_func(key->alpha.func, TRUE));
-         debug_printf("alpha.ref_value = %f\n", key->alpha.ref_value);
-      }
-      if(key->blend.logicop_enable) {
-         debug_printf("blend.logicop_func = %u\n", key->blend.logicop_func);
-      }
-      else if(key->blend.rt[0].blend_enable) {
-         debug_printf("blend.rgb_func = %s\n",   debug_dump_blend_func  (key->blend.rt[0].rgb_func, TRUE));
-         debug_printf("rgb_src_factor = %s\n",   debug_dump_blend_factor(key->blend.rt[0].rgb_src_factor, TRUE));
-         debug_printf("rgb_dst_factor = %s\n",   debug_dump_blend_factor(key->blend.rt[0].rgb_dst_factor, TRUE));
-         debug_printf("alpha_func = %s\n",       debug_dump_blend_func  (key->blend.rt[0].alpha_func, TRUE));
-         debug_printf("alpha_src_factor = %s\n", debug_dump_blend_factor(key->blend.rt[0].alpha_src_factor, TRUE));
-         debug_printf("alpha_dst_factor = %s\n", debug_dump_blend_factor(key->blend.rt[0].alpha_dst_factor, TRUE));
-      }
-      debug_printf("blend.colormask = 0x%x\n", key->blend.rt[0].colormask);
-      for(i = 0; i < PIPE_MAX_SAMPLERS; ++i) {
-         if(key->sampler[i].format) {
-            debug_printf("sampler[%u] = \n", i);
-            debug_printf("  .format = %s\n",
-                         pf_name(key->sampler[i].format));
-            debug_printf("  .target = %s\n",
-                         debug_dump_tex_target(key->sampler[i].target, TRUE));
-            debug_printf("  .pot = %u %u %u\n",
-                         key->sampler[i].pot_width,
-                         key->sampler[i].pot_height,
-                         key->sampler[i].pot_depth);
-            debug_printf("  .wrap = %s %s %s\n",
-                         debug_dump_tex_wrap(key->sampler[i].wrap_s, TRUE),
-                         debug_dump_tex_wrap(key->sampler[i].wrap_t, TRUE),
-                         debug_dump_tex_wrap(key->sampler[i].wrap_r, TRUE));
-            debug_printf("  .min_img_filter = %s\n",
-                         debug_dump_tex_filter(key->sampler[i].min_img_filter, TRUE));
-            debug_printf("  .min_mip_filter = %s\n",
-                         debug_dump_tex_mipfilter(key->sampler[i].min_mip_filter, TRUE));
-            debug_printf("  .mag_img_filter = %s\n",
-                         debug_dump_tex_filter(key->sampler[i].mag_img_filter, TRUE));
-            if(key->sampler[i].compare_mode != PIPE_TEX_COMPARE_NONE)
-               debug_printf("  .compare_func = %s\n", debug_dump_func(key->sampler[i].compare_func, TRUE));
-            debug_printf("  .normalized_coords = %u\n", key->sampler[i].normalized_coords);
-            debug_printf("  .prefilter = %u\n", key->sampler[i].prefilter);
-         }
-      }
-   }
-
-   variant = CALLOC_STRUCT(lp_fragment_shader_variant);
-   if(!variant)
-      return NULL;
-
-   variant->shader = shader;
-   memcpy(&variant->key, key, sizeof *key);
 
    /* TODO: actually pick these based on the fs and color buffer
     * characteristics. */
@@ -475,8 +639,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 */
@@ -503,27 +667,47 @@ 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(LLVMPointerType(blend_vec_type, 0), 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);
 
-   variant->function = LLVMAddFunction(screen->module, "shader", func_type);
-   LLVMSetFunctionCallConv(variant->function, LLVMCCallConv);
+   function = LLVMAddFunction(screen->module, "shader", func_type);
+   LLVMSetFunctionCallConv(function, LLVMCCallConv);
+
+   variant->function[do_tri_test] = function;
+
+
+   /* XXX: need to propagate noalias down into color param now we are
+    * passing a pointer-to-pointer?
+    */
    for(i = 0; i < Elements(arg_types); ++i)
       if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
-         LLVMAddAttribute(LLVMGetParam(variant->function, i), LLVMNoAliasAttribute);
-
-   context_ptr  = LLVMGetParam(variant->function, 0);
-   x            = LLVMGetParam(variant->function, 1);
-   y            = LLVMGetParam(variant->function, 2);
-   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);
+         LLVMAddAttribute(LLVMGetParam(function, i), LLVMNoAliasAttribute);
+
+   context_ptr  = LLVMGetParam(function, 0);
+   x            = LLVMGetParam(function, 1);
+   y            = LLVMGetParam(function, 2);
+   a0_ptr       = LLVMGetParam(function, 3);
+   dadx_ptr     = LLVMGetParam(function, 4);
+   dady_ptr     = LLVMGetParam(function, 5);
+   color_ptr_ptr = LLVMGetParam(function, 6);
+   depth_ptr    = LLVMGetParam(function, 7);
+   c0           = LLVMGetParam(function, 8);
+   c1           = LLVMGetParam(function, 9);
+   c2           = LLVMGetParam(function, 10);
+   step0_ptr    = LLVMGetParam(function, 11);
+   step1_ptr    = LLVMGetParam(function, 12);
+   step2_ptr    = LLVMGetParam(function, 13);
 
    lp_build_name(context_ptr, "context");
    lp_build_name(x, "x");
@@ -531,36 +715,45 @@ 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(color_ptr_ptr, "color_ptr");
    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
     */
 
-   block = LLVMAppendBasicBlock(variant->function, "entry");
+   block = LLVMAppendBasicBlock(function, "entry");
    builder = LLVMCreateBuilder();
    LLVMPositionBuilderAtEnd(builder, block);
 
    generate_pos0(builder, x, y, &x0, &y0);
 
-   lp_build_interp_soa_init(&interp, shader->base.tokens, builder, fs_type,
+   lp_build_interp_soa_init(&interp, 
+                            shader->base.tokens,
+                            key->flatshade,
+                            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 out_color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS];
       LLVMValueRef depth_ptr_i;
+      int cbuf;
 
       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,
@@ -570,71 +763,163 @@ generate_fragment(struct llvmpipe_context *lp,
                   i,
                   &interp,
                   sampler,
-                  &fs_mask[i],
+                  &fs_mask[i], /* output */
                   out_color,
-                  depth_ptr_i);
-
-      for(chan = 0; chan < NUM_CHANNELS; ++chan)
-         fs_out_color[chan][i] = out_color[chan];
+                  depth_ptr_i,
+                  do_tri_test,
+                  c0, c1, c2,
+                  step0_ptr, step1_ptr, step2_ptr);
+
+      for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++)
+        for(chan = 0; chan < NUM_CHANNELS; ++chan)
+           fs_out_color[cbuf][chan][i] = out_color[cbuf][chan];
    }
 
    sampler->destroy(sampler);
 
-   /* 
-    * Convert the fs's output color and mask to fit to the blending type. 
+   /* Loop over color outputs / color buffers to do blending.
     */
+   for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++) {
+      LLVMValueRef color_ptr;
+      LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), cbuf, 0);
 
-   for(chan = 0; chan < NUM_CHANNELS; ++chan) {
-      lp_build_conv(builder, fs_type, blend_type,
-                    fs_out_color[chan], num_fs,
-                    &blend_in_color[chan], 1);
-      lp_build_name(blend_in_color[chan], "color.%c", "rgba"[chan]);
+      /* 
+       * Convert the fs's output color and mask to fit to the blending type. 
+       */
+      for(chan = 0; chan < NUM_CHANNELS; ++chan) {
+        lp_build_conv(builder, fs_type, blend_type,
+                      fs_out_color[cbuf][chan], num_fs,
+                      &blend_in_color[chan], 1);
+        lp_build_name(blend_in_color[chan], "color%d.%c", cbuf, "rgba"[chan]);
+      }
 
+      lp_build_conv_mask(builder, fs_type, blend_type,
+                        fs_mask, num_fs,
+                        &blend_mask, 1);
+
+      color_ptr = LLVMBuildLoad(builder, 
+                               LLVMBuildGEP(builder, color_ptr_ptr, &index, 1, ""),
+                               "");
+      lp_build_name(color_ptr, "color_ptr%d", cbuf);
+
+      /*
+       * Blending.
+       */
+      generate_blend(&key->blend,
+                    builder,
+                    blend_type,
+                    context_ptr,
+                    blend_mask,
+                    blend_in_color,
+                    color_ptr);
    }
 
-   lp_build_conv_mask(builder, fs_type, blend_type,
-                      fs_mask, num_fs,
-                      &blend_mask, 1);
-
-   /*
-    * Blending.
-    */
-
-   generate_blend(&key->blend,
-                  builder,
-                  blend_type,
-                  context_ptr,
-                  blend_mask,
-                  blend_in_color,
-                  color_ptr);
-
    LLVMBuildRetVoid(builder);
 
    LLVMDisposeBuilder(builder);
 
-   /*
-    * Translate the LLVM IR into machine code.
-    */
 
+   /* Verify the LLVM IR.  If invalid, dump and abort */
 #ifdef DEBUG
-   if(LLVMVerifyFunction(variant->function, LLVMPrintMessageAction)) {
-      LLVMDumpValue(variant->function);
-      assert(0);
+   if(LLVMVerifyFunction(function, LLVMPrintMessageAction)) {
+      if (1)
+         LLVMDumpValue(function);
+      abort();
    }
 #endif
 
-   LLVMRunFunctionPassManager(screen->pass, variant->function);
+   /* Apply optimizations to LLVM IR */
+   if (1)
+      LLVMRunFunctionPassManager(screen->pass, function);
 
    if (LP_DEBUG & DEBUG_JIT) {
-      LLVMDumpValue(variant->function);
+      /* Print the LLVM IR to stderr */
+      LLVMDumpValue(function);
       debug_printf("\n");
    }
 
-   variant->jit_function = (lp_jit_frag_func)LLVMGetPointerToGlobal(screen->engine, variant->function);
+   /*
+    * Translate the LLVM IR into machine code.
+    */
+   variant->jit_function[do_tri_test] = (lp_jit_frag_func)LLVMGetPointerToGlobal(screen->engine, function);
 
    if (LP_DEBUG & DEBUG_ASM)
-      lp_disassemble(variant->jit_function);
+      lp_disassemble(variant->jit_function[do_tri_test]);
+}
+
+
+static struct lp_fragment_shader_variant *
+generate_variant(struct llvmpipe_context *lp,
+                 struct lp_fragment_shader *shader,
+                 const struct lp_fragment_shader_variant_key *key)
+{
+   struct lp_fragment_shader_variant *variant;
+
+   if (LP_DEBUG & DEBUG_JIT) {
+      unsigned i;
+
+      tgsi_dump(shader->base.tokens, 0);
+      if(key->depth.enabled) {
+         debug_printf("depth.format = %s\n", pf_name(key->zsbuf_format));
+         debug_printf("depth.func = %s\n", debug_dump_func(key->depth.func, TRUE));
+         debug_printf("depth.writemask = %u\n", key->depth.writemask);
+      }
+      if(key->alpha.enabled) {
+         debug_printf("alpha.func = %s\n", debug_dump_func(key->alpha.func, TRUE));
+         debug_printf("alpha.ref_value = %f\n", key->alpha.ref_value);
+      }
+      if(key->blend.logicop_enable) {
+         debug_printf("blend.logicop_func = %u\n", key->blend.logicop_func);
+      }
+      else if(key->blend.rt[0].blend_enable) {
+         debug_printf("blend.rgb_func = %s\n",   debug_dump_blend_func  (key->blend.rt[0].rgb_func, TRUE));
+         debug_printf("rgb_src_factor = %s\n",   debug_dump_blend_factor(key->blend.rt[0].rgb_src_factor, TRUE));
+         debug_printf("rgb_dst_factor = %s\n",   debug_dump_blend_factor(key->blend.rt[0].rgb_dst_factor, TRUE));
+         debug_printf("alpha_func = %s\n",       debug_dump_blend_func  (key->blend.rt[0].alpha_func, TRUE));
+         debug_printf("alpha_src_factor = %s\n", debug_dump_blend_factor(key->blend.rt[0].alpha_src_factor, TRUE));
+         debug_printf("alpha_dst_factor = %s\n", debug_dump_blend_factor(key->blend.rt[0].alpha_dst_factor, TRUE));
+      }
+      debug_printf("blend.colormask = 0x%x\n", key->blend.rt[0].colormask);
+      for(i = 0; i < PIPE_MAX_SAMPLERS; ++i) {
+         if(key->sampler[i].format) {
+            debug_printf("sampler[%u] = \n", i);
+            debug_printf("  .format = %s\n",
+                         pf_name(key->sampler[i].format));
+            debug_printf("  .target = %s\n",
+                         debug_dump_tex_target(key->sampler[i].target, TRUE));
+            debug_printf("  .pot = %u %u %u\n",
+                         key->sampler[i].pot_width,
+                         key->sampler[i].pot_height,
+                         key->sampler[i].pot_depth);
+            debug_printf("  .wrap = %s %s %s\n",
+                         debug_dump_tex_wrap(key->sampler[i].wrap_s, TRUE),
+                         debug_dump_tex_wrap(key->sampler[i].wrap_t, TRUE),
+                         debug_dump_tex_wrap(key->sampler[i].wrap_r, TRUE));
+            debug_printf("  .min_img_filter = %s\n",
+                         debug_dump_tex_filter(key->sampler[i].min_img_filter, TRUE));
+            debug_printf("  .min_mip_filter = %s\n",
+                         debug_dump_tex_mipfilter(key->sampler[i].min_mip_filter, TRUE));
+            debug_printf("  .mag_img_filter = %s\n",
+                         debug_dump_tex_filter(key->sampler[i].mag_img_filter, TRUE));
+            if(key->sampler[i].compare_mode != PIPE_TEX_COMPARE_NONE)
+               debug_printf("  .compare_func = %s\n", debug_dump_func(key->sampler[i].compare_func, TRUE));
+            debug_printf("  .normalized_coords = %u\n", key->sampler[i].normalized_coords);
+            debug_printf("  .prefilter = %u\n", key->sampler[i].prefilter);
+         }
+      }
+   }
+
+   variant = CALLOC_STRUCT(lp_fragment_shader_variant);
+   if(!variant)
+      return NULL;
+
+   variant->shader = shader;
+   memcpy(&variant->key, key, sizeof *key);
 
+   generate_fragment(lp, shader, variant, 0);
+   generate_fragment(lp, shader, variant, 1);
+
+   /* insert new variant into linked list */
    variant->next = shader->variants;
    shader->variants = variant;
 
@@ -692,11 +977,15 @@ llvmpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
    variant = shader->variants;
    while(variant) {
       struct lp_fragment_shader_variant *next = variant->next;
-
-      if(variant->function) {
-         if(variant->jit_function)
-            LLVMFreeMachineCodeForFunction(screen->engine, variant->function);
-         LLVMDeleteFunction(variant->function);
+      unsigned i;
+
+      for (i = 0; i < Elements(variant->function); i++) {
+         if (variant->function[i]) {
+            if (variant->jit_function[i])
+               LLVMFreeMachineCodeForFunction(screen->engine,
+                                              variant->function[i]);
+            LLVMDeleteFunction(variant->function[i]);
+         }
       }
 
       FREE(variant);
@@ -722,15 +1011,14 @@ llvmpipe_set_constant_buffer(struct pipe_context *pipe,
    assert(shader < PIPE_SHADER_TYPES);
    assert(index == 0);
 
+   if(llvmpipe->constants[shader] == constants)
+      return;
+
    draw_flush(llvmpipe->draw);
 
    /* note: reference counting */
    pipe_buffer_reference(&llvmpipe->constants[shader], constants);
 
-   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, 0,
                                       data, size);
@@ -767,21 +1055,30 @@ make_variant_key(struct llvmpipe_context *lp,
       key->alpha.func = lp->depth_stencil->alpha.func;
    /* alpha.ref_value is passed in jit_context */
 
-   if(lp->framebuffer.cbufs[0]) {
-      const struct util_format_description *format_desc;
-      unsigned chan;
+   key->flatshade = lp->rasterizer->flatshade;
+   key->scissor = lp->rasterizer->scissor;
 
+   if (lp->framebuffer.nr_cbufs) {
       memcpy(&key->blend, lp->blend, sizeof key->blend);
+   }
 
-      format_desc = util_format_description(lp->framebuffer.cbufs[0]->format);
+   key->nr_cbufs = lp->framebuffer.nr_cbufs;
+   for (i = 0; i < lp->framebuffer.nr_cbufs; i++) {
+      const struct util_format_description *format_desc;
+      unsigned chan;
+
+      format_desc = util_format_description(lp->framebuffer.cbufs[i]->format);
       assert(format_desc->layout == UTIL_FORMAT_COLORSPACE_RGB ||
              format_desc->layout == UTIL_FORMAT_COLORSPACE_SRGB);
 
-      /* mask out color channels not present in the color buffer */
+      /* mask out color channels not present in the color buffer.
+       * Should be simple to incorporate per-cbuf writemasks:
+       */
       for(chan = 0; chan < 4; ++chan) {
          enum util_format_swizzle swizzle = format_desc->swizzle[chan];
-         if(swizzle > 4)
-            key->blend.rt[0].colormask &= ~(1 << chan);
+
+         if(swizzle <= UTIL_FORMAT_SWIZZLE_W)
+            key->blend.rt[0].colormask |= (1 << chan);
       }
    }
 
@@ -791,12 +1088,17 @@ make_variant_key(struct llvmpipe_context *lp,
 }
 
 
+/**
+ * Update fragment state.  This is called just prior to drawing
+ * something when some fragment-related state has changed.
+ */
 void 
 llvmpipe_update_fs(struct llvmpipe_context *lp)
 {
    struct lp_fragment_shader *shader = lp->fs;
    struct lp_fragment_shader_variant_key key;
    struct lp_fragment_shader_variant *variant;
+   boolean opaque;
 
    make_variant_key(lp, shader, &key);
 
@@ -808,8 +1110,34 @@ llvmpipe_update_fs(struct llvmpipe_context *lp)
       variant = variant->next;
    }
 
-   if(!variant)
-      variant = generate_fragment(lp, shader, &key);
+   if (!variant) {
+      struct util_time t0, t1;
+      int64_t dt;
+      util_time_get(&t0);
+
+      variant = generate_variant(lp, shader, &key);
+
+      util_time_get(&t1);
+      dt = util_time_diff(&t0, &t1);
+      LP_COUNT_ADD(llvm_compile_time, dt);
+      LP_COUNT_ADD(nr_llvm_compiles, 2);  /* emit vs. omit in/out test */
+   }
 
    shader->current = variant;
+
+   /* TODO: put this in the variant */
+   /* TODO: most of these can be relaxed, in particular the colormask */
+   opaque = !key.blend.logicop_enable &&
+            !key.blend.rt[0].blend_enable &&
+            key.blend.rt[0].colormask == 0xf &&
+            !key.alpha.enabled &&
+            !key.depth.enabled &&
+            !key.scissor &&
+            !shader->info.uses_kill
+            ? TRUE : FALSE;
+
+   lp_setup_set_fs_functions(lp->setup, 
+                             shader->current->jit_function[0],
+                             shader->current->jit_function[1],
+                             opaque);
 }
index aa3b5a3f91ef1ce7971eccd40f166813109ba27f..feb012816c96ab435f602f53d5226f409086cf6c 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,17 @@ 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->rasterizer->scissor);
+   }
+
    llvmpipe->dirty |= LP_NEW_RASTERIZER;
 }
 
index bda9c138d52291e21975271154f3ee992bffa07b..43649febf27d40b553a80b9daaeb3863fb7990e8 100644 (file)
@@ -38,7 +38,6 @@
 #include "lp_context.h"
 #include "lp_state.h"
 #include "lp_texture.h"
-#include "lp_tex_cache.h"
 #include "draw/draw_context.h"
 
 
@@ -126,17 +125,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;
@@ -167,7 +155,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 0afa49d0b758edb25fa03027c982673b3f779e7f..048ac5b968b315e4d7692602b40beab37aa59150 100644 (file)
 /* Authors:  Keith Whitwell <keith@tungstengraphics.com>
  */
 
+#include "pipe/p_state.h"
 #include "util/u_inlines.h"
-
+#include "util/u_surface.h"
 #include "lp_context.h"
 #include "lp_state.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);
-
-   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]);
-
-         /* 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;
+   boolean changed = !util_framebuffer_state_equal(&lp->framebuffer, fb);
 
-   /* zbuf changing? */
-   if (lp->framebuffer.zsbuf != fb->zsbuf) {
+   if (changed) {
 
-      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) {
@@ -104,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 e9f7d90..0000000
+++ /dev/null
@@ -1,303 +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 "util/u_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_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 5138ccf7c93aaf4d7aaa79aec815f354f91f1198..7f55f1ae83f0b184c5ea0d9190851b659d1d98cd 100644 (file)
@@ -46,7 +46,7 @@
 #include "lp_bld_type.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 8c20625430c61c3b3f3e2b6ef0e1a52c56c92813..605200396b225e59c4117780effc5b87e1e6f14b 100644 (file)
 #include "util/u_memory.h"
 
 #include "lp_context.h"
+#include "lp_screen.h"
 #include "lp_state.h"
 #include "lp_texture.h"
-#include "lp_screen.h"
+#include "lp_tile_size.h"
 #include "lp_winsys.h"
 
 
-/* Simple, maximally packed layout.
- */
-
-/* Conventional allocation path for non-display textures:
+/**
+ * Conventional allocation path for non-display textures:
+ * Simple, maximally packed layout.
  */
 static boolean
 llvmpipe_texture_layout(struct llvmpipe_screen *screen,
-                        struct llvmpipe_texture * lpt)
+                        struct llvmpipe_texture *lpt)
 {
    struct pipe_texture *pt = &lpt->base;
    unsigned level;
    unsigned width = pt->width0;
    unsigned height = pt->height0;
    unsigned depth = pt->depth0;
-
    unsigned buffer_size = 0;
 
    for (level = 0; level <= pt->last_level; level++) {
       unsigned nblocksx, nblocksy;
 
       /* Allocate storage for whole quads. This is particularly important
-       * for depth surfaces, which are currently stored in a swizzled format. */
-      nblocksx = util_format_get_nblocksx(pt->format, align(width, 2));
-      nblocksy = util_format_get_nblocksy(pt->format, align(height, 2));
+       * for depth surfaces, which are currently stored in a swizzled format.
+       */
+      nblocksx = util_format_get_nblocksx(pt->format, align(width, TILE_SIZE));
+      nblocksy = util_format_get_nblocksy(pt->format, align(height, TILE_SIZE));
 
       lpt->stride[level] = align(nblocksx * util_format_get_blocksize(pt->format), 16);
 
@@ -78,7 +78,7 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen,
                       ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) *
                       lpt->stride[level]);
 
-      width  = u_minify(width, 1);
+      width = u_minify(width, 1);
       height = u_minify(height, 1);
       depth = u_minify(depth, 1);
    }
@@ -88,16 +88,23 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen,
    return lpt->data != NULL;
 }
 
+
+
 static boolean
 llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
-                              struct llvmpipe_texture * lpt)
+                              struct llvmpipe_texture *lpt)
 {
    struct llvmpipe_winsys *winsys = screen->winsys;
 
+   /* Round up the surface size to a multiple of the tile size to
+    * avoid tile clipping.
+    */
+   unsigned width = align(lpt->base.width0, TILE_SIZE);
+   unsigned height = align(lpt->base.height0, TILE_SIZE);
+
    lpt->dt = winsys->displaytarget_create(winsys,
                                           lpt->base.format,
-                                          lpt->base.width0,
-                                          lpt->base.height0,
+                                          width, height,
                                           16,
                                           &lpt->stride[0] );
 
@@ -105,9 +112,6 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
 }
 
 
-
-
-
 static struct pipe_texture *
 llvmpipe_texture_create(struct pipe_screen *_screen,
                         const struct pipe_texture *templat)
@@ -124,7 +128,7 @@ llvmpipe_texture_create(struct pipe_screen *_screen,
    /* XXX: The xlib state tracker is brain-dead and will request
     * PIPE_FORMAT_Z16_UNORM no matter how much we tell it we don't support it.
     */
-   if(lpt->base.format == PIPE_FORMAT_Z16_UNORM)
+   if (lpt->base.format == PIPE_FORMAT_Z16_UNORM)
       lpt->base.format = PIPE_FORMAT_Z32_UNORM;
 
    if (lpt->base.tex_usage & (PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
@@ -176,6 +180,7 @@ llvmpipe_texture_blanket(struct pipe_screen * screen,
 
    return &lpt->base;
 #else
+   debug_printf("llvmpipe_texture_blanket() not implemented!");
    return NULL;
 #endif
 }
@@ -187,12 +192,15 @@ llvmpipe_texture_destroy(struct pipe_texture *pt)
    struct llvmpipe_screen *screen = llvmpipe_screen(pt->screen);
    struct llvmpipe_texture *lpt = llvmpipe_texture(pt);
 
-   if(lpt->dt) {
+   if (lpt->dt) {
+      /* display target */
       struct llvmpipe_winsys *winsys = screen->winsys;
       winsys->displaytarget_destroy(winsys, lpt->dt);
    }
-   else
+   else {
+      /* regular texture */
       align_free(lpt->data);
+   }
 
    FREE(lpt);
 }
@@ -234,7 +242,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++;
       }
@@ -296,8 +304,8 @@ llvmpipe_get_tex_transfer(struct pipe_screen *screen,
       pipe_texture_reference(&pt->texture, texture);
       pt->x = x;
       pt->y = y;
-      pt->width = w;
-      pt->height = h;
+      pt->width = align(w, TILE_SIZE);
+      pt->height = align(h, TILE_SIZE);
       pt->stride = lptex->stride[level];
       pt->usage = usage;
       pt->face = face;
@@ -354,7 +362,8 @@ llvmpipe_transfer_map( struct pipe_screen *_screen,
    lpt = llvmpipe_texture(transfer->texture);
    format = lpt->base.format;
 
-   if(lpt->dt) {
+   if (lpt->dt) {
+      /* display target */
       struct llvmpipe_winsys *winsys = screen->winsys;
 
       map = winsys->displaytarget_map(winsys, lpt->dt,
@@ -362,16 +371,16 @@ llvmpipe_transfer_map( struct pipe_screen *_screen,
       if (map == NULL)
          return NULL;
    }
-   else
+   else {
+      /* regular texture */
       map = lpt->data;
+   }
 
    /* May want to different things here depending on read/write nature
     * of the map:
     */
-   if (transfer->texture && (transfer->usage & PIPE_TRANSFER_WRITE))
-   {
+   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++;
    }
@@ -385,28 +394,23 @@ llvmpipe_transfer_map( struct pipe_screen *_screen,
 
 
 static void
-llvmpipe_transfer_unmap(struct pipe_screen *_screen,
+llvmpipe_transfer_unmap(struct pipe_screen *screen,
                        struct pipe_transfer *transfer)
 {
-   struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
+   struct llvmpipe_screen *lp_screen = llvmpipe_screen(screen);
    struct llvmpipe_texture *lpt;
 
    assert(transfer->texture);
    lpt = llvmpipe_texture(transfer->texture);
 
-   if(lpt->dt) {
-      struct llvmpipe_winsys *winsys = screen->winsys;
+   if (lpt->dt) {
+      /* display target */
+      struct llvmpipe_winsys *winsys = lp_screen->winsys;
       winsys->displaytarget_unmap(winsys, lpt->dt);
    }
 }
 
 
-void
-llvmpipe_init_texture_funcs(struct llvmpipe_context *lp)
-{
-}
-
-
 void
 llvmpipe_init_screen_texture_funcs(struct pipe_screen *screen)
 {
index 00a20763e43f1c642b80222ef8f7b6c1d6451497..87c905bc027028cdd69fd9b9cf1bc8c9b0ab9d13 100644 (file)
@@ -37,6 +37,7 @@ struct pipe_screen;
 struct llvmpipe_context;
 struct llvmpipe_displaytarget;
 
+
 struct llvmpipe_texture
 {
    struct pipe_texture base;
@@ -58,6 +59,7 @@ struct llvmpipe_texture
    unsigned timestamp;
 };
 
+
 struct llvmpipe_transfer
 {
    struct pipe_transfer base;
@@ -73,6 +75,14 @@ llvmpipe_texture(struct pipe_texture *pt)
    return (struct llvmpipe_texture *) pt;
 }
 
+
+static INLINE const struct llvmpipe_texture *
+llvmpipe_texture_const(const struct pipe_texture *pt)
+{
+   return (const struct llvmpipe_texture *) pt;
+}
+
+
 static INLINE struct llvmpipe_transfer *
 llvmpipe_transfer(struct pipe_transfer *pt)
 {
@@ -80,11 +90,8 @@ llvmpipe_transfer(struct pipe_transfer *pt)
 }
 
 
-extern void
-llvmpipe_init_texture_funcs( struct llvmpipe_context *llvmpipe );
-
 extern void
 llvmpipe_init_screen_texture_funcs(struct pipe_screen *screen);
 
 
-#endif /* LP_TEXTURE */
+#endif /* LP_TEXTURE_H */
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 1968268..0000000
+++ /dev/null
@@ -1,356 +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 "util/u_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_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 */
-
diff --git a/src/gallium/drivers/llvmpipe/lp_tile_size.h b/src/gallium/drivers/llvmpipe/lp_tile_size.h
new file mode 100644 (file)
index 0000000..f0b983c
--- /dev/null
@@ -0,0 +1,39 @@
+/**************************************************************************
+ * 
+ * Copyright 2010 VMware, Inc.
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 THE AUTHORS 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_SIZE_H
+#define LP_TILE_SIZE_H
+
+
+/**
+ * Tile size (width and height). This needs to be a power of two.
+ */
+#define TILE_ORDER 6
+#define TILE_SIZE (1 << TILE_ORDER)
+
+
+#endif
index 19d00b58d37aeb73e5b482a7292c36abce074d54..eea3ab84990985e4b54f6d9f95abe9f154e29a37 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "pipe/p_compiler.h"
 #include "tgsi/tgsi_exec.h" /* for NUM_CHANNELS */
-
+#include "lp_tile_size.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -40,26 +40,20 @@ extern "C" {
 struct pipe_transfer;
 
 
-/**
- * Cache tile size (width and height). This needs to be a power of two.
- */
-#define TILE_SIZE 64
-
-
-#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) //16
+#define TILE_X_STRIDE (NUM_CHANNELS * TILE_C_STRIDE) //64
+#define TILE_Y_STRIDE (TILE_VECTOR_HEIGHT * TILE_SIZE * NUM_CHANNELS) //1024
 
 #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..5d53689a3dbc068a4c466af0a6021683a82d465d 100644 (file)
@@ -129,22 +129,8 @@ def generate_format_read(format, dst_type, dst_native_type, dst_suffix):
     print
     
 
-def generate_format_write(format, src_type, src_native_type, src_suffix):
-    '''Generate the function to write pixels to a particular format'''
-
-    name = short_name(format)
-
-    dst_native_type = native_type(format)
-
-    print 'static void'
-    print 'lp_tile_%s_write_%s(const %s *src, uint8_t *dst, unsigned dst_stride, unsigned x0, unsigned y0, unsigned w, unsigned h)' % (name, src_suffix, src_native_type)
-    print '{'
-    print '   unsigned x, y;'
-    print '   uint8_t *dst_row = dst + y0*dst_stride;'
-    print '   for (y = 0; y < h; ++y) {'
-    print '      %s *dst_pixel = (%s *)(dst_row + x0*%u);' % (dst_native_type, dst_native_type, format.stride())
-    print '      for (x = 0; x < w; ++x) {'
-
+def compute_inverse_swizzle(format):
+    '''Return an array[4] of inverse swizzle terms'''
     inv_swizzle = [None]*4
     if format.colorspace == 'rgb':
         for i in range(4):
@@ -155,8 +141,86 @@ def generate_format_write(format, src_type, src_native_type, src_suffix):
         swizzle = format.out_swizzle[0]
         if swizzle < 4:
             inv_swizzle[swizzle] = 0
-    else:
-        assert False
+    return inv_swizzle
+
+
+def pack_rgba(format, src_type, r, g, b, a):
+    """Return an expression for packing r, g, b, a into a pixel of the
+    given format.  Ex: '(b << 24) | (g << 16) | (r << 8) | (a << 0)'
+    """
+    assert format.colorspace == 'rgb'
+    inv_swizzle = compute_inverse_swizzle(format)
+    shift = 0
+    expr = None
+    for i in range(4):
+               # choose r, g, b, or a depending on the inverse swizzle term
+        if inv_swizzle[i] == 0:
+            value = r
+        elif inv_swizzle[i] == 1:
+            value = g
+        elif inv_swizzle[i] == 2:
+            value = b
+        elif inv_swizzle[i] == 3:
+            value = a
+        else:
+            value = None
+
+        if value:
+            dst_type = format.in_types[i]
+            dst_native_type = native_type(format)
+            value = conversion_expr(src_type, dst_type, dst_native_type, value)
+            term = "((%s) << %d)" % (value, shift)
+            if expr:
+                expr = expr + " | " + term
+            else:
+                expr = term
+
+        width = format.in_types[i].size
+        shift = shift + width
+    return expr
+
+
+def emit_unrolled_write_code(format, src_type):
+    '''Emit code for writing a block based on unrolled loops.
+    This is considerably faster than the TILE_PIXEL-based code below.
+    '''
+    dst_native_type = native_type(format)
+    print '   const unsigned dstpix_stride = dst_stride / %d;' % format.stride()
+    print '   %s *dstpix = (%s *) dst;' % (dst_native_type, dst_native_type)
+    print '   unsigned int qx, qy, i;'
+    print
+    print '   for (qy = 0; qy < h; qy += TILE_VECTOR_HEIGHT) {'
+    print '      const unsigned py = y0 + qy;'
+    print '      for (qx = 0; qx < w; qx += TILE_VECTOR_WIDTH) {'
+    print '         const unsigned px = x0 + qx;'
+    print '         const uint8_t *r = src + 0 * TILE_C_STRIDE;'
+    print '         const uint8_t *g = src + 1 * TILE_C_STRIDE;'
+    print '         const uint8_t *b = src + 2 * TILE_C_STRIDE;'
+    print '         const uint8_t *a = src + 3 * TILE_C_STRIDE;'
+    print '         (void) r; (void) g; (void) b; (void) a; /* silence warnings */'
+    print '         for (i = 0; i < TILE_C_STRIDE; i += 2) {'
+    print '            const uint32_t pixel0 = %s;' % pack_rgba(format, src_type, "r[i+0]", "g[i+0]", "b[i+0]", "a[i+0]")
+    print '            const uint32_t pixel1 = %s;' % pack_rgba(format, src_type, "r[i+1]", "g[i+1]", "b[i+1]", "a[i+1]")
+    print '            const unsigned offset = (py + tile_y_offset[i]) * dstpix_stride + (px + tile_x_offset[i]);'
+    print '            dstpix[offset + 0] = pixel0;'
+    print '            dstpix[offset + 1] = pixel1;'
+    print '         }'
+    print '         src += TILE_X_STRIDE;'
+    print '      }'
+    print '   }'
+
+
+def emit_tile_pixel_write_code(format, src_type):
+    '''Emit code for writing a block based on the TILE_PIXEL macro.'''
+    dst_native_type = native_type(format)
+
+    inv_swizzle = compute_inverse_swizzle(format)
+
+    print '   unsigned x, y;'
+    print '   uint8_t *dst_row = dst + y0*dst_stride;'
+    print '   for (y = 0; y < h; ++y) {'
+    print '      %s *dst_pixel = (%s *)(dst_row + x0*%u);' % (dst_native_type, dst_native_type, format.stride())
+    print '      for (x = 0; x < w; ++x) {'
 
     if format.layout == ARITH:
         print '         %s pixel = 0;' % dst_native_type
@@ -185,6 +249,20 @@ def generate_format_write(format, src_type, src_native_type, src_suffix):
     print '      }'
     print '      dst_row += dst_stride;'
     print '   }'
+
+
+def generate_format_write(format, src_type, src_native_type, src_suffix):
+    '''Generate the function to write pixels to a particular format'''
+
+    name = short_name(format)
+
+    print 'static void'
+    print 'lp_tile_%s_write_%s(const %s *src, uint8_t *dst, unsigned dst_stride, unsigned x0, unsigned y0, unsigned w, unsigned h)' % (name, src_suffix, src_native_type)
+    print '{'
+    if format.layout == ARITH and format.colorspace == 'rgb':
+        emit_unrolled_write_code(format, src_type)
+    else:
+        emit_tile_pixel_write_code(format, src_type)
     print '}'
     print
     
@@ -259,8 +337,23 @@ 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
+    print '/* Note: these lookup tables could be replaced with some'
+    print ' * bit-twiddling code, but this is a little faster.'
+    print ' */'
+    print 'static unsigned tile_x_offset[TILE_VECTOR_WIDTH * TILE_VECTOR_HEIGHT] = {'
+    print '   0, 1, 0, 1, 2, 3, 2, 3,'
+    print '   0, 1, 0, 1, 2, 3, 2, 3'
+    print '};'
+    print
+    print 'static unsigned tile_y_offset[TILE_VECTOR_WIDTH * TILE_VECTOR_HEIGHT] = {'
+    print '   0, 0, 1, 1, 0, 0, 1, 1,'
+    print '   2, 2, 3, 3, 2, 2, 3, 3'
     print '};'
     print