softpipe: First attempts at multithreaded softpipe.
authorMichal Krol <michal@ubuntu-vbox.(none)>
Fri, 5 Sep 2008 21:21:08 +0000 (23:21 +0200)
committerMichal Krol <michal@ubuntu-vbox.(none)>
Mon, 8 Sep 2008 15:25:46 +0000 (17:25 +0200)
Configured for 2 cores.

src/gallium/drivers/softpipe/sp_context.c
src/gallium/drivers/softpipe/sp_context.h
src/gallium/drivers/softpipe/sp_quad.c
src/gallium/drivers/softpipe/sp_setup.c

index 6f12390..cd1e666 100644 (file)
@@ -92,17 +92,19 @@ static void softpipe_destroy( struct pipe_context *pipe )
    if (softpipe->draw)
       draw_destroy( softpipe->draw );
 
-   softpipe->quad.polygon_stipple->destroy( softpipe->quad.polygon_stipple );
-   softpipe->quad.earlyz->destroy( softpipe->quad.earlyz );
-   softpipe->quad.shade->destroy( softpipe->quad.shade );
-   softpipe->quad.alpha_test->destroy( softpipe->quad.alpha_test );
-   softpipe->quad.depth_test->destroy( softpipe->quad.depth_test );
-   softpipe->quad.stencil_test->destroy( softpipe->quad.stencil_test );
-   softpipe->quad.occlusion->destroy( softpipe->quad.occlusion );
-   softpipe->quad.coverage->destroy( softpipe->quad.coverage );
-   softpipe->quad.blend->destroy( softpipe->quad.blend );
-   softpipe->quad.colormask->destroy( softpipe->quad.colormask );
-   softpipe->quad.output->destroy( softpipe->quad.output );
+   for (i = 0; i < SP_NUM_QUAD_THREADS; i++) {
+      softpipe->quad[i].polygon_stipple->destroy( softpipe->quad[i].polygon_stipple );
+      softpipe->quad[i].earlyz->destroy( softpipe->quad[i].earlyz );
+      softpipe->quad[i].shade->destroy( softpipe->quad[i].shade );
+      softpipe->quad[i].alpha_test->destroy( softpipe->quad[i].alpha_test );
+      softpipe->quad[i].depth_test->destroy( softpipe->quad[i].depth_test );
+      softpipe->quad[i].stencil_test->destroy( softpipe->quad[i].stencil_test );
+      softpipe->quad[i].occlusion->destroy( softpipe->quad[i].occlusion );
+      softpipe->quad[i].coverage->destroy( softpipe->quad[i].coverage );
+      softpipe->quad[i].blend->destroy( softpipe->quad[i].blend );
+      softpipe->quad[i].colormask->destroy( softpipe->quad[i].colormask );
+      softpipe->quad[i].output->destroy( softpipe->quad[i].output );
+   }
 
    for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
       sp_destroy_tile_cache(softpipe->cbuf_cache[i]);
@@ -205,17 +207,19 @@ softpipe_create( struct pipe_screen *screen,
 
 
    /* setup quad rendering stages */
-   softpipe->quad.polygon_stipple = sp_quad_polygon_stipple_stage(softpipe);
-   softpipe->quad.earlyz = sp_quad_earlyz_stage(softpipe);
-   softpipe->quad.shade = sp_quad_shade_stage(softpipe);
-   softpipe->quad.alpha_test = sp_quad_alpha_test_stage(softpipe);
-   softpipe->quad.depth_test = sp_quad_depth_test_stage(softpipe);
-   softpipe->quad.stencil_test = sp_quad_stencil_test_stage(softpipe);
-   softpipe->quad.occlusion = sp_quad_occlusion_stage(softpipe);
-   softpipe->quad.coverage = sp_quad_coverage_stage(softpipe);
-   softpipe->quad.blend = sp_quad_blend_stage(softpipe);
-   softpipe->quad.colormask = sp_quad_colormask_stage(softpipe);
-   softpipe->quad.output = sp_quad_output_stage(softpipe);
+   for (i = 0; i < SP_NUM_QUAD_THREADS; i++) {
+      softpipe->quad[i].polygon_stipple = sp_quad_polygon_stipple_stage(softpipe);
+      softpipe->quad[i].earlyz = sp_quad_earlyz_stage(softpipe);
+      softpipe->quad[i].shade = sp_quad_shade_stage(softpipe);
+      softpipe->quad[i].alpha_test = sp_quad_alpha_test_stage(softpipe);
+      softpipe->quad[i].depth_test = sp_quad_depth_test_stage(softpipe);
+      softpipe->quad[i].stencil_test = sp_quad_stencil_test_stage(softpipe);
+      softpipe->quad[i].occlusion = sp_quad_occlusion_stage(softpipe);
+      softpipe->quad[i].coverage = sp_quad_coverage_stage(softpipe);
+      softpipe->quad[i].blend = sp_quad_blend_stage(softpipe);
+      softpipe->quad[i].colormask = sp_quad_colormask_stage(softpipe);
+      softpipe->quad[i].output = sp_quad_output_stage(softpipe);
+   }
 
    /*
     * Create drawing context and plug our rendering stage into it.
@@ -257,3 +261,4 @@ softpipe_create( struct pipe_screen *screen,
    softpipe_destroy(&softpipe->pipe);
    return NULL;
 }
+
index 078886f..e58f7c8 100644 (file)
  */
 #define USE_DRAW_STAGE_PSTIPPLE 1
 
+/* Number of threads working on individual quads.
+ * Setting to 1 disables this feature.
+ */
+#define SP_NUM_QUAD_THREADS 2
 
 struct softpipe_winsys;
 struct softpipe_vbuf_render;
@@ -133,7 +137,7 @@ struct softpipe_context {
       struct quad_stage *output;
 
       struct quad_stage *first; /**< points to one of the above stages */
-   } quad;
+   } quad[SP_NUM_QUAD_THREADS];
 
    /** The primitive drawing context */
    struct draw_context *draw;
@@ -151,13 +155,11 @@ struct softpipe_context {
 };
 
 
-
-
 static INLINE struct softpipe_context *
 softpipe_context( struct pipe_context *pipe )
 {
    return (struct softpipe_context *)pipe;
 }
 
-
 #endif /* SP_CONTEXT_H */
+
index bc83d78..892ef87 100644 (file)
 static void
 sp_push_quad_first(
    struct softpipe_context *sp,
-   struct quad_stage       *quad )
+   struct quad_stage *quad,
+   uint i )
 {
-   quad->next = sp->quad.first;
-   sp->quad.first = quad;
+   quad->next = sp->quad[i].first;
+   sp->quad[i].first = quad;
 }
 
 static void
 sp_build_depth_stencil(
-   struct softpipe_context *sp )
+   struct softpipe_context *sp,
+   uint i )
 {
    if (sp->depth_stencil->stencil[0].enabled ||
        sp->depth_stencil->stencil[1].enabled) {
-      sp_push_quad_first( sp, sp->quad.stencil_test );
+      sp_push_quad_first( sp, sp->quad[i].stencil_test, i );
    }
    else if (sp->depth_stencil->depth.enabled &&
             sp->framebuffer.zsbuf) {
-      sp_push_quad_first( sp, sp->quad.depth_test );
+      sp_push_quad_first( sp, sp->quad[i].depth_test, i );
    }
 }
 
 void
 sp_build_quad_pipeline(struct softpipe_context *sp)
 {
+   uint i;
+
    boolean early_depth_test =
                sp->depth_stencil->depth.enabled &&
                sp->framebuffer.zsbuf &&
@@ -64,49 +68,51 @@ sp_build_quad_pipeline(struct softpipe_context *sp)
                !sp->fs->info.writes_z;
 
    /* build up the pipeline in reverse order... */
-
-   sp->quad.first = sp->quad.output;
-
-   if (sp->blend->colormask != 0xf) {
-      sp_push_quad_first( sp, sp->quad.colormask );
-   }
-
-   if (sp->blend->blend_enable ||
-       sp->blend->logicop_enable) {
-      sp_push_quad_first( sp, sp->quad.blend );
-   }
-
-   if (sp->depth_stencil->depth.occlusion_count) {
-      sp_push_quad_first( sp, sp->quad.occlusion );
-   }
-
-   if (sp->rasterizer->poly_smooth ||
-       sp->rasterizer->line_smooth ||
-       sp->rasterizer->point_smooth) {
-      sp_push_quad_first( sp, sp->quad.coverage );
-   }
-
-   if (!early_depth_test) {
-      sp_build_depth_stencil( sp );
-   }
-
-   if (sp->depth_stencil->alpha.enabled) {
-      sp_push_quad_first( sp, sp->quad.alpha_test );
-   }
-
-   /* XXX always enable shader? */
-   if (1) {
-      sp_push_quad_first( sp, sp->quad.shade );
-   }
-
-   if (early_depth_test) {
-      sp_build_depth_stencil( sp );
-      sp_push_quad_first( sp, sp->quad.earlyz );
-   }
+   for (i = 0; i < SP_NUM_QUAD_THREADS; i++) {
+      sp->quad[i].first = sp->quad[i].output;
+
+      if (sp->blend->colormask != 0xf) {
+         sp_push_quad_first( sp, sp->quad[i].colormask, i );
+      }
+
+      if (sp->blend->blend_enable ||
+          sp->blend->logicop_enable) {
+         sp_push_quad_first( sp, sp->quad[i].blend, i );
+      }
+
+      if (sp->depth_stencil->depth.occlusion_count) {
+         sp_push_quad_first( sp, sp->quad[i].occlusion, i );
+      }
+
+      if (sp->rasterizer->poly_smooth ||
+          sp->rasterizer->line_smooth ||
+          sp->rasterizer->point_smooth) {
+         sp_push_quad_first( sp, sp->quad[i].coverage, i );
+      }
+
+      if (!early_depth_test) {
+         sp_build_depth_stencil( sp, i );
+      }
+
+      if (sp->depth_stencil->alpha.enabled) {
+         sp_push_quad_first( sp, sp->quad[i].alpha_test, i );
+      }
+
+      /* XXX always enable shader? */
+      if (1) {
+         sp_push_quad_first( sp, sp->quad[i].shade, i );
+      }
+
+      if (early_depth_test) {
+         sp_build_depth_stencil( sp, i );
+         sp_push_quad_first( sp, sp->quad[i].earlyz, i );
+      }
 
 #if !USE_DRAW_STAGE_PSTIPPLE
-   if (sp->rasterizer->poly_stipple_enable) {
-      sp_push_quad_first( sp, sp->quad.polygon_stipple );
-   }
+      if (sp->rasterizer->poly_stipple_enable) {
+         sp_push_quad_first( sp, sp->quad[i].polygon_stipple, i );
+      }
 #endif
+   }
 }
+
index 87336ab..706a412 100644 (file)
@@ -43,6 +43,7 @@
 #include "draw/draw_private.h"
 #include "draw/draw_vertex.h"
 #include "pipe/p_shader_tokens.h"
+#include "pipe/p_thread.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
 
@@ -61,6 +62,51 @@ struct edge {
    int lines;          /**< number of lines on this edge */
 };
 
+#if SP_NUM_QUAD_THREADS > 1
+
+struct thread_info
+{
+   struct setup_context *setup;
+   uint id;
+   pipe_thread handle;
+};
+
+struct quad_job;
+
+typedef void (* quad_job_routine)( struct setup_context *setup, uint thread, struct quad_job *job );
+
+struct quad_job
+{
+   int x, y;
+   unsigned mask;
+   struct quad_header quad;
+   quad_job_routine routine;
+};
+
+#define NUM_QUAD_JOBS 64
+
+struct quad_job_que
+{
+   struct quad_job jobs[NUM_QUAD_JOBS];
+   uint first;
+   uint last;
+   pipe_mutex mutex;
+};
+
+static void
+add_quad_job( struct quad_job_que *que, int x, int y, unsigned mask, struct quad_header *quad, quad_job_routine routine )
+{
+   while ((que->last + 1) % NUM_QUAD_JOBS == que->first)
+      usleep( 10 );
+   que->jobs[que->last].x = x;
+   que->jobs[que->last].y = y;
+   que->jobs[que->last].mask = mask;
+   que->jobs[que->last].quad = *quad;
+   que->jobs[que->last].routine = routine;
+   que->last = (que->last + 1) % NUM_QUAD_JOBS;
+}
+
+#endif
 
 /**
  * Triangle setup info (derived from draw_stage).
@@ -88,6 +134,12 @@ struct setup_context {
    struct tgsi_interp_coef posCoef;  /* For Z, W */
    struct quad_header quad;
 
+#if SP_NUM_QUAD_THREADS > 1
+   struct quad_job_que que;
+   struct thread_info threads[SP_NUM_QUAD_THREADS];
+   
+#endif
+
    struct {
       int left[2];   /**< [0] = row0, [1] = row1 */
       int right[2];
@@ -104,7 +156,36 @@ struct setup_context {
    unsigned winding;           /* which winding to cull */
 };
 
+#if SP_NUM_QUAD_THREADS > 1
 
+static PIPE_THREAD_ROUTINE( quad_thread, param )
+{
+   struct thread_info *info = (struct thread_info *) param;
+
+   for (;;) {
+      struct quad_job *job;
+
+      while (info->setup->que.last == info->setup->que.first)
+         usleep( 10 );
+      pipe_mutex_lock( info->setup->que.mutex );
+      job = &info->setup->que.jobs[info->setup->que.first];
+      info->setup->que.first = (info->setup->que.first + 1) % NUM_QUAD_JOBS;
+      job->routine( info->setup, info->id, job );
+      pipe_mutex_unlock( info->setup->que.mutex );
+   }
+}
+
+#define WAIT_FOR_COMPLETION(setup) \
+   do {\
+      while (setup->que.last != setup->que.first)\
+         usleep( 10 );\
+   } while (0)
+
+#else
+
+#define WAIT_FOR_COMPLETION(setup) ((void) 0)
+
+#endif
 
 /**
  * Test if x is NaN or +/- infinity.
@@ -143,7 +224,7 @@ static boolean cull_tri( struct setup_context *setup,
  * Clip setup->quad against the scissor/surface bounds.
  */
 static INLINE void
-quad_clip(struct setup_context *setup)
+quad_clip( struct setup_context *setup, struct quad_header *quad )
 {
    const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect;
    const int minx = (int) cliprect->minx;
@@ -151,22 +232,22 @@ quad_clip(struct setup_context *setup)
    const int miny = (int) cliprect->miny;
    const int maxy = (int) cliprect->maxy;
 
-   if (setup->quad.x0 >= maxx ||
-       setup->quad.y0 >= maxy ||
-       setup->quad.x0 + 1 < minx ||
-       setup->quad.y0 + 1 < miny) {
+   if (quad->x0 >= maxx ||
+       quad->y0 >= maxy ||
+       quad->x0 + 1 < minx ||
+       quad->y0 + 1 < miny) {
       /* totally clipped */
-      setup->quad.mask = 0x0;
+      quad->mask = 0x0;
       return;
    }
-   if (setup->quad.x0 < minx)
-      setup->quad.mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
-   if (setup->quad.y0 < miny)
-      setup->quad.mask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
-   if (setup->quad.x0 == maxx - 1)
-      setup->quad.mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
-   if (setup->quad.y0 == maxy - 1)
-      setup->quad.mask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT);
+   if (quad->x0 < minx)
+      quad->mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
+   if (quad->y0 < miny)
+      quad->mask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
+   if (quad->x0 == maxx - 1)
+      quad->mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
+   if (quad->y0 == maxy - 1)
+      quad->mask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT);
 }
 
 
@@ -174,35 +255,52 @@ quad_clip(struct setup_context *setup)
  * Emit a quad (pass to next stage) with clipping.
  */
 static INLINE void
-clip_emit_quad(struct setup_context *setup)
+clip_emit_quad( struct setup_context *setup, struct quad_header *quad, uint thread )
 {
-   quad_clip(setup);
-   if (setup->quad.mask) {
+   quad_clip( setup, quad );
+   if (quad->mask) {
       struct softpipe_context *sp = setup->softpipe;
-      sp->quad.first->run(sp->quad.first, &setup->quad);
+
+      sp->quad[thread].first->run( sp->quad[thread].first, quad );
    }
 }
 
+#if SP_NUM_QUAD_THREADS > 1
+
+static void
+clip_emit_quad_job( struct setup_context *setup, uint thread, struct quad_job *job )
+{
+   clip_emit_quad( setup, &job->quad, thread );
+}
+
+#define CLIP_EMIT_QUAD(setup) add_quad_job( &setup->que, 0, 0, 0, &setup->quad, clip_emit_quad_job )
+
+#else
+
+#define CLIP_EMIT_QUAD(setup) clip_emit_quad( setup, &setup->quad, 0 )
+
+#endif
 
 /**
  * Emit a quad (pass to next stage).  No clipping is done.
  */
 static INLINE void
-emit_quad( struct setup_context *setup, int x, int y, unsigned mask )
+emit_quad( struct setup_context *setup, int x, int y, unsigned mask, struct quad_header *quad, uint thread )
 {
    struct softpipe_context *sp = setup->softpipe;
-   setup->quad.x0 = x;
-   setup->quad.y0 = y;
-   setup->quad.mask = mask;
+
+   quad->x0 = x;
+   quad->y0 = y;
+   quad->mask = mask;
 #if DEBUG_FRAGS
    if (mask & 1) setup->numFragsEmitted++;
    if (mask & 2) setup->numFragsEmitted++;
    if (mask & 4) setup->numFragsEmitted++;
    if (mask & 8) setup->numFragsEmitted++;
 #endif
-   sp->quad.first->run(sp->quad.first, &setup->quad);
+   sp->quad[thread].first->run( sp->quad[thread].first, quad );
 #if DEBUG_FRAGS
-   mask = setup->quad.mask;
+   mask = quad->mask;
    if (mask & 1) setup->numFragsWritten++;
    if (mask & 2) setup->numFragsWritten++;
    if (mask & 4) setup->numFragsWritten++;
@@ -210,6 +308,21 @@ emit_quad( struct setup_context *setup, int x, int y, unsigned mask )
 #endif
 }
 
+#if SP_NUM_QUAD_THREADS > 1
+
+static void
+emit_quad_job( struct setup_context *setup, uint thread, struct quad_job *job )
+{
+   emit_quad( setup, job->x, job->y, job->mask, &job->quad, thread );
+}
+
+#define EMIT_QUAD(setup,x,y,mask) add_quad_job( &setup->que, x, y, mask, &setup->quad, emit_quad_job )
+
+#else
+
+#define EMIT_QUAD(setup,x,y,mask) emit_quad( setup, x, y, mask, &setup->quad, 0 )
+
+#endif
 
 /**
  * Given an X or Y coordinate, return the block/quad coordinate that it
@@ -249,7 +362,7 @@ static void flush_spans( struct setup_context *setup )
             mask |= MASK_TOP_RIGHT;
          if (x+1 >= xleft1 && x+1 < xright1)
             mask |= MASK_BOTTOM_RIGHT;
-         emit_quad( setup, x, setup->span.y, mask );
+         EMIT_QUAD( setup, x, setup->span.y, mask );
       }
       break;
 
@@ -263,7 +376,7 @@ static void flush_spans( struct setup_context *setup )
             mask |= MASK_TOP_LEFT;
          if (x+1 >= xleft0 && x+1 < xright0)
             mask |= MASK_TOP_RIGHT;
-         emit_quad( setup, x, setup->span.y, mask );
+         EMIT_QUAD( setup, x, setup->span.y, mask );
       }
       break;
 
@@ -277,7 +390,7 @@ static void flush_spans( struct setup_context *setup )
             mask |= MASK_BOTTOM_LEFT;
          if (x+1 >= xleft1 && x+1 < xright1)
             mask |= MASK_BOTTOM_RIGHT;
-         emit_quad( setup, x, setup->span.y, mask );
+         EMIT_QUAD( setup, x, setup->span.y, mask );
       }
       break;
 
@@ -790,6 +903,8 @@ void setup_tri( struct setup_context *setup,
 
    flush_spans( setup );
 
+   WAIT_FOR_COMPLETION(setup);
+
 #if DEBUG_FRAGS
    printf("Tri: %u frags emitted, %u written\n",
           setup->numFragsEmitted,
@@ -931,7 +1046,7 @@ plot(struct setup_context *setup, int x, int y)
       /* flush prev quad, start new quad */
 
       if (setup->quad.x0 != -1)
-         clip_emit_quad(setup);
+         CLIP_EMIT_QUAD(setup);
 
       setup->quad.x0 = quadX;
       setup->quad.y0 = quadY;
@@ -1053,8 +1168,10 @@ setup_line(struct setup_context *setup,
 
    /* draw final quad */
    if (setup->quad.mask) {
-      clip_emit_quad(setup);
+      CLIP_EMIT_QUAD(setup);
    }
+
+   WAIT_FOR_COMPLETION(setup);
 }
 
 
@@ -1163,7 +1280,7 @@ setup_point( struct setup_context *setup,
       setup->quad.x0 = (int) x - ix;
       setup->quad.y0 = (int) y - iy;
       setup->quad.mask = (1 << ix) << (2 * iy);
-      clip_emit_quad(setup);
+      CLIP_EMIT_QUAD(setup);
    }
    else {
       if (round) {
@@ -1224,7 +1341,7 @@ setup_point( struct setup_context *setup,
                if (setup->quad.mask) {
                   setup->quad.x0 = ix;
                   setup->quad.y0 = iy;
-                  clip_emit_quad(setup);
+                  CLIP_EMIT_QUAD(setup);
                }
             }
          }
@@ -1271,11 +1388,13 @@ setup_point( struct setup_context *setup,
                setup->quad.mask = mask;
                setup->quad.x0 = ix;
                setup->quad.y0 = iy;
-               clip_emit_quad(setup);
+               CLIP_EMIT_QUAD(setup);
             }
          }
       }
    }
+
+   WAIT_FOR_COMPLETION(setup);
 }
 
 void setup_prepare( struct setup_context *setup )
@@ -1300,7 +1419,9 @@ void setup_prepare( struct setup_context *setup )
    /* Note: nr_attrs is only used for debugging (vertex printing) */
    setup->quad.nr_attrs = draw_num_vs_outputs(sp->draw);
 
-   sp->quad.first->begin(sp->quad.first);
+   for (i = 0; i < SP_NUM_QUAD_THREADS; i++) {
+      sp->quad[i].first->begin( sp->quad[i].first );
+   }
 
    if (sp->reduced_api_prim == PIPE_PRIM_TRIANGLES &&
        sp->rasterizer->fill_cw == PIPE_POLYGON_MODE_FILL &&
@@ -1328,11 +1449,24 @@ void setup_destroy_context( struct setup_context *setup )
 struct setup_context *setup_create_context( struct softpipe_context *softpipe )
 {
    struct setup_context *setup = CALLOC_STRUCT(setup_context);
+   uint i;
 
    setup->softpipe = softpipe;
 
    setup->quad.coef = setup->coef;
    setup->quad.posCoef = &setup->posCoef;
 
+#if SP_NUM_QUAD_THREADS > 1
+   setup->que.first = 0;
+   setup->que.last = 0;
+   pipe_mutex_init( setup->que.mutex );
+   for (i = 0; i < SP_NUM_QUAD_THREADS; i++) {
+      setup->threads[i].setup = setup;
+      setup->threads[i].id = i;
+      setup->threads[i].handle = pipe_thread_create( quad_thread, &setup->threads[i] );
+   }
+#endif
+
    return setup;
 }
+