예제 #1
0
파일: lp_screen.c 프로젝트: MaikuMori/mesa
/**
 * Query format support for creating a texture, drawing surface, etc.
 * \param format  the format to test
 * \param type  one of PIPE_TEXTURE, PIPE_SURFACE
 */
static boolean
llvmpipe_is_format_supported( struct pipe_screen *_screen,
                              enum pipe_format format,
                              enum pipe_texture_target target,
                              unsigned sample_count,
                              unsigned bind)
{
   struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
   struct sw_winsys *winsys = screen->winsys;
   const struct util_format_description *format_desc;

   format_desc = util_format_description(format);
   if (!format_desc)
      return FALSE;

   assert(target == PIPE_BUFFER ||
          target == PIPE_TEXTURE_1D ||
          target == PIPE_TEXTURE_1D_ARRAY ||
          target == PIPE_TEXTURE_2D ||
          target == PIPE_TEXTURE_2D_ARRAY ||
          target == PIPE_TEXTURE_RECT ||
          target == PIPE_TEXTURE_3D ||
          target == PIPE_TEXTURE_CUBE);

   if (sample_count > 1)
      return FALSE;

   if (bind & PIPE_BIND_RENDER_TARGET) {
      if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
         if (format_desc->nr_channels < 3)
            return FALSE;
      }
      else if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_RGB)
         return FALSE;

      if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN &&
          format != PIPE_FORMAT_R11G11B10_FLOAT)
         return FALSE;

      assert(format_desc->block.width == 1);
      assert(format_desc->block.height == 1);

      if (format_desc->is_mixed)
         return FALSE;

      if (!format_desc->is_array && !format_desc->is_bitmask &&
          format != PIPE_FORMAT_R11G11B10_FLOAT)
         return FALSE;

      /*
       * XXX refuse formats known to crash in generate_unswizzled_blend().
       * These include all 3-channel 24bit RGB8 variants, plus 48bit
       * (except those using floats) 3-channel RGB16 variants (the latter
       * seems to be more of a llvm bug though).
       * The mesa state tracker only seems to use these for SINT/UINT formats.
       */
      if (format_desc->is_array && format_desc->nr_channels == 3) {
         if (format_desc->block.bits == 24 || (format_desc->block.bits == 48 &&
               !util_format_is_float(format))) {
            return FALSE;
         }
      }
   }

   if (bind & PIPE_BIND_DISPLAY_TARGET) {
      if(!winsys->is_displaytarget_format_supported(winsys, bind, format))
         return FALSE;
   }

   if (bind & PIPE_BIND_DEPTH_STENCIL) {
      if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN)
         return FALSE;

      if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS)
         return FALSE;

      /* TODO: Support stencil-only formats */
      if (format_desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_NONE) {
         return FALSE;
      }
   }

   if (format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC) {
      return util_format_s3tc_enabled;
   }

   /*
    * Everything can be supported by u_format
    * (those without fetch_rgba_float might be not but shouldn't hit that)
    */

   return TRUE;
}
예제 #2
0
/**
 * Called during state validation when LP_NEW_SAMPLER_VIEW is set.
 */
void
lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup,
                                    unsigned num,
                                    struct pipe_sampler_view **views)
{
   unsigned i;

   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);

   assert(num <= PIPE_MAX_SAMPLERS);

   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
      struct pipe_sampler_view *view = i < num ? views[i] : NULL;

      if (view) {
         struct pipe_resource *tex = view->texture;
         struct llvmpipe_resource *lp_tex = llvmpipe_resource(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->depth = tex->depth0;
         jit_tex->first_level = view->u.tex.first_level;
         jit_tex->last_level = tex->last_level;

         /* We're referencing the texture's internal data, so save a
          * reference to it.
          */
         pipe_resource_reference(&setup->fs.current_tex[i], tex);

         if (!lp_tex->dt) {
            /* regular texture - setup array of mipmap level pointers */
            int j;
            for (j = view->u.tex.first_level; j <= tex->last_level; j++) {
               jit_tex->data[j] =
                  llvmpipe_get_texture_image_all(lp_tex, j, LP_TEX_USAGE_READ,
                                                 LP_TEX_LAYOUT_LINEAR);
               jit_tex->row_stride[j] = lp_tex->row_stride[j];
               jit_tex->img_stride[j] = lp_tex->img_stride[j];

               if ((LP_PERF & PERF_TEX_MEM) ||
		   !jit_tex->data[j]) {
                  /* out of memory - use dummy tile memory */
                  jit_tex->data[j] = lp_dummy_tile;
                  jit_tex->width = TILE_SIZE/8;
                  jit_tex->height = TILE_SIZE/8;
                  jit_tex->depth = 1;
                  jit_tex->first_level = 0;
                  jit_tex->last_level = 0;
                  jit_tex->row_stride[j] = 0;
                  jit_tex->img_stride[j] = 0;
               }
            }
         }
         else {
            /* display target texture/surface */
            /*
             * XXX: Where should this be unmapped?
             */
            struct llvmpipe_screen *screen = llvmpipe_screen(tex->screen);
            struct sw_winsys *winsys = screen->winsys;
            jit_tex->data[0] = winsys->displaytarget_map(winsys, lp_tex->dt,
							 PIPE_TRANSFER_READ);
            jit_tex->row_stride[0] = lp_tex->row_stride[0];
            jit_tex->img_stride[0] = lp_tex->img_stride[0];
            assert(jit_tex->data[0]);
         }
      }
   }

   setup->dirty |= LP_SETUP_NEW_FS;
}
예제 #3
0
파일: lp_setup.c 프로젝트: Distrotech/Mesa
/**
 * Called during state validation when LP_NEW_SAMPLER_VIEW is set.
 */
void
lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup,
                                    unsigned num,
                                    struct pipe_sampler_view **views)
{
   unsigned i;

   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);

   assert(num <= PIPE_MAX_SHADER_SAMPLER_VIEWS);

   for (i = 0; i < PIPE_MAX_SHADER_SAMPLER_VIEWS; i++) {
      struct pipe_sampler_view *view = i < num ? views[i] : NULL;

      if (view) {
         struct pipe_resource *res = view->texture;
         struct llvmpipe_resource *lp_tex = llvmpipe_resource(res);
         struct lp_jit_texture *jit_tex;
         jit_tex = &setup->fs.current.jit_context.textures[i];

         /* We're referencing the texture's internal data, so save a
          * reference to it.
          */
         pipe_resource_reference(&setup->fs.current_tex[i], res);

         if (!lp_tex->dt) {
            /* regular texture - setup array of mipmap level offsets */
            int j;
            unsigned first_level = 0;
            unsigned last_level = 0;

            if (llvmpipe_resource_is_texture(res)) {
               first_level = view->u.tex.first_level;
               last_level = view->u.tex.last_level;
               assert(first_level <= last_level);
               assert(last_level <= res->last_level);
               jit_tex->base = lp_tex->tex_data;
            }
            else {
              jit_tex->base = lp_tex->data;
            }

            if (LP_PERF & PERF_TEX_MEM) {
               /* use dummy tile memory */
               jit_tex->base = lp_dummy_tile;
               jit_tex->width = TILE_SIZE/8;
               jit_tex->height = TILE_SIZE/8;
               jit_tex->depth = 1;
               jit_tex->first_level = 0;
               jit_tex->last_level = 0;
               jit_tex->mip_offsets[0] = 0;
               jit_tex->row_stride[0] = 0;
               jit_tex->img_stride[0] = 0;
            }
            else {
               jit_tex->width = res->width0;
               jit_tex->height = res->height0;
               jit_tex->depth = res->depth0;
               jit_tex->first_level = first_level;
               jit_tex->last_level = last_level;

               if (llvmpipe_resource_is_texture(res)) {
                  for (j = first_level; j <= last_level; j++) {
                     jit_tex->mip_offsets[j] = lp_tex->mip_offsets[j];
                     jit_tex->row_stride[j] = lp_tex->row_stride[j];
                     jit_tex->img_stride[j] = lp_tex->img_stride[j];
                  }

                  if (res->target == PIPE_TEXTURE_1D_ARRAY ||
                      res->target == PIPE_TEXTURE_2D_ARRAY ||
                      res->target == PIPE_TEXTURE_CUBE ||
                      res->target == PIPE_TEXTURE_CUBE_ARRAY) {
                     /*
                      * For array textures, we don't have first_layer, instead
                      * adjust last_layer (stored as depth) plus the mip level offsets
                      * (as we have mip-first layout can't just adjust base ptr).
                      * XXX For mip levels, could do something similar.
                      */
                     jit_tex->depth = view->u.tex.last_layer - view->u.tex.first_layer + 1;
                     for (j = first_level; j <= last_level; j++) {
                        jit_tex->mip_offsets[j] += view->u.tex.first_layer *
                                                   lp_tex->img_stride[j];
                     }
                     if (view->target == PIPE_TEXTURE_CUBE ||
                         view->target == PIPE_TEXTURE_CUBE_ARRAY) {
                        assert(jit_tex->depth % 6 == 0);
                     }
                     assert(view->u.tex.first_layer <= view->u.tex.last_layer);
                     assert(view->u.tex.last_layer < res->array_size);
                  }
               }
               else {
                  /*
                   * For buffers, we don't have first_element, instead adjust
                   * last_element (stored as width) plus the base pointer.
                   */
                  unsigned view_blocksize = util_format_get_blocksize(view->format);
                  /* probably don't really need to fill that out */
                  jit_tex->mip_offsets[0] = 0;
                  jit_tex->row_stride[0] = 0;
                  jit_tex->img_stride[0] = 0;

                  /* everything specified in number of elements here. */
                  jit_tex->width = view->u.buf.last_element - view->u.buf.first_element + 1;
                  jit_tex->base = (uint8_t *)jit_tex->base + view->u.buf.first_element *
                                  view_blocksize;
                  /* XXX Unsure if we need to sanitize parameters? */
                  assert(view->u.buf.first_element <= view->u.buf.last_element);
                  assert(view->u.buf.last_element * view_blocksize < res->width0);
               }
            }
         }
         else {
            /* display target texture/surface */
            /*
             * XXX: Where should this be unmapped?
             */
            struct llvmpipe_screen *screen = llvmpipe_screen(res->screen);
            struct sw_winsys *winsys = screen->winsys;
            jit_tex->base = winsys->displaytarget_map(winsys, lp_tex->dt,
                                                         PIPE_TRANSFER_READ);
            jit_tex->row_stride[0] = lp_tex->row_stride[0];
            jit_tex->img_stride[0] = lp_tex->img_stride[0];
            jit_tex->mip_offsets[0] = 0;
            jit_tex->width = res->width0;
            jit_tex->height = res->height0;
            jit_tex->depth = res->depth0;
            jit_tex->first_level = jit_tex->last_level = 0;
            assert(jit_tex->base);
         }
      }
   }

   setup->dirty |= LP_SETUP_NEW_FS;
}
예제 #4
0
/**
 * Handle state changes.
 * Called just prior to drawing anything (pipe::draw_arrays(), etc).
 *
 * 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 )
{
   struct llvmpipe_screen *lp_screen = llvmpipe_screen(llvmpipe->pipe.screen);

   /* Check for updated textures.
    */
   if (llvmpipe->tex_timestamp != lp_screen->timestamp) {
      llvmpipe->tex_timestamp = lp_screen->timestamp;
      llvmpipe->dirty |= LP_NEW_SAMPLER_VIEW;
   }
      
   if (llvmpipe->dirty & (LP_NEW_FS |
                          LP_NEW_VS))
      compute_vertex_info(llvmpipe);

   if (llvmpipe->dirty & (LP_NEW_FS |
                          LP_NEW_FRAMEBUFFER |
                          LP_NEW_BLEND |
                          LP_NEW_SCISSOR |
                          LP_NEW_DEPTH_STENCIL_ALPHA |
                          LP_NEW_RASTERIZER |
                          LP_NEW_SAMPLER |
                          LP_NEW_SAMPLER_VIEW |
                          LP_NEW_OCCLUSION_QUERY))
      llvmpipe_update_fs( llvmpipe );

   if (llvmpipe->dirty & (LP_NEW_RASTERIZER)) {
      boolean discard =
         (llvmpipe->sample_mask & 1) == 0 ||
         (llvmpipe->rasterizer ? llvmpipe->rasterizer->rasterizer_discard : FALSE);

      lp_setup_set_rasterizer_discard(llvmpipe->setup, discard);
   }

   if (llvmpipe->dirty & (LP_NEW_FS |
                          LP_NEW_FRAMEBUFFER |
                          LP_NEW_RASTERIZER))
      llvmpipe_update_setup( 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_scissors(llvmpipe->setup, llvmpipe->scissors);

   if (llvmpipe->dirty & LP_NEW_DEPTH_STENCIL_ALPHA) {
      lp_setup_set_alpha_ref_value(llvmpipe->setup, 
                                   llvmpipe->depth_stencil->alpha.ref_value);
      lp_setup_set_stencil_ref_values(llvmpipe->setup,
                                      llvmpipe->stencil_ref.ref_value);
   }

   if (llvmpipe->dirty & LP_NEW_CONSTANTS)
      lp_setup_set_fs_constants(llvmpipe->setup,
                                Elements(llvmpipe->constants[PIPE_SHADER_FRAGMENT]),
                                llvmpipe->constants[PIPE_SHADER_FRAGMENT]);

   if (llvmpipe->dirty & (LP_NEW_SAMPLER_VIEW))
      lp_setup_set_fragment_sampler_views(llvmpipe->setup,
                                          llvmpipe->num_sampler_views[PIPE_SHADER_FRAGMENT],
                                          llvmpipe->sampler_views[PIPE_SHADER_FRAGMENT]);

   if (llvmpipe->dirty & (LP_NEW_SAMPLER))
      lp_setup_set_fragment_sampler_state(llvmpipe->setup,
                                          llvmpipe->num_samplers[PIPE_SHADER_FRAGMENT],
                                          llvmpipe->samplers[PIPE_SHADER_FRAGMENT]);

   if (llvmpipe->dirty & LP_NEW_VIEWPORT) {
      /*
       * Update setup and fragment's view of the active viewport state.
       *
       * XXX TODO: It is possible to only loop over the active viewports
       *           instead of all viewports (PIPE_MAX_VIEWPORTS).
       */
      lp_setup_set_viewports(llvmpipe->setup,
                             PIPE_MAX_VIEWPORTS,
                             llvmpipe->viewports);
   }

   llvmpipe->dirty = 0;
}
예제 #5
0
/**
 * 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 void
generate_fragment(struct llvmpipe_context *lp,
                  struct lp_fragment_shader *shader,
                  struct lp_fragment_shader_variant *variant,
                  unsigned do_tri_test)
{
   struct llvmpipe_screen *screen = llvmpipe_screen(lp->pipe.screen);
   const struct lp_fragment_shader_variant_key *key = &variant->key;
   struct lp_type fs_type;
   struct lp_type blend_type;
   LLVMTypeRef fs_elem_type;
   LLVMTypeRef fs_vec_type;
   LLVMTypeRef fs_int_vec_type;
   LLVMTypeRef blend_vec_type;
   LLVMTypeRef blend_int_vec_type;
   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 color_ptr_ptr;
   LLVMValueRef depth_ptr;
   LLVMValueRef c0, c1, c2, step0_ptr, step1_ptr, step2_ptr;
   LLVMBasicBlockRef block;
   LLVMBuilderRef builder;
   LLVMValueRef x0;
   LLVMValueRef y0;
   struct lp_build_sampler_soa *sampler;
   struct lp_build_interp_soa_context interp;
   LLVMValueRef fs_mask[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;


   /* TODO: actually pick these based on the fs and color buffer
    * characteristics. */

   memset(&fs_type, 0, sizeof fs_type);
   fs_type.floating = TRUE; /* floating point values */
   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 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 */
   blend_type.sign = FALSE;     /* values are unsigned */
   blend_type.norm = TRUE;      /* values are in [0,1] or [-1,1] */
   blend_type.width = 8;        /* 8-bit ubyte values */
   blend_type.length = 16;      /* 16 elements per vector */

   /* 
    * Generate the function prototype. Any change here must be reflected in
    * lp_jit.h's lp_jit_frag_func function pointer type, and vice-versa.
    */

   fs_elem_type = lp_build_elem_type(fs_type);
   fs_vec_type = lp_build_vec_type(fs_type);
   fs_int_vec_type = lp_build_int_vec_type(fs_type);

   blend_vec_type = lp_build_vec_type(blend_type);
   blend_int_vec_type = lp_build_int_vec_type(blend_type);

   arg_types[0] = screen->context_ptr_type;            /* context */
   arg_types[1] = LLVMInt32Type();                     /* x */
   arg_types[2] = LLVMInt32Type();                     /* y */
   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(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);

   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(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");
   lp_build_name(y, "y");
   lp_build_name(a0_ptr, "a0");
   lp_build_name(dadx_ptr, "dadx");
   lp_build_name(dady_ptr, "dady");
   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(function, "entry");
   builder = LLVMCreateBuilder();
   LLVMPositionBuilderAtEnd(builder, block);

   generate_pos0(builder, x, y, &x0, &y0);

   lp_build_interp_soa_init(&interp, 
                            shader->base.tokens,
                            key->flatshade,
                            builder, fs_type,
                            a0_ptr, dadx_ptr, dady_ptr,
                            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[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS];
      LLVMValueRef depth_ptr_i;
      int cbuf;

      if(i != 0)
         lp_build_interp_soa_update(&interp, i);

      depth_ptr_i = LLVMBuildGEP(builder, depth_ptr, &index, 1, "");

      generate_fs(lp, shader, key,
                  builder,
                  fs_type,
                  context_ptr,
                  i,
                  &interp,
                  sampler,
                  &fs_mask[i], /* output */
                  out_color,
                  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);

   /* 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);

      /* 
       * 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);
   }

   LLVMBuildRetVoid(builder);

   LLVMDisposeBuilder(builder);


   /* Verify the LLVM IR.  If invalid, dump and abort */
#ifdef DEBUG
   if(LLVMVerifyFunction(function, LLVMPrintMessageAction)) {
      if (1)
         LLVMDumpValue(function);
      abort();
   }
#endif

   /* Apply optimizations to LLVM IR */
   if (1)
      LLVMRunFunctionPassManager(screen->pass, function);

   if (LP_DEBUG & DEBUG_JIT) {
      /* Print the LLVM IR to stderr */
      LLVMDumpValue(function);
      debug_printf("\n");
   }

   /*
    * 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[do_tri_test]);
}
예제 #6
0
/**
 * Handle state changes.
 * Called just prior to drawing anything (pipe::draw_arrays(), etc).
 *
 * 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 )
{
   struct llvmpipe_screen *lp_screen = llvmpipe_screen(llvmpipe->pipe.screen);

   /* Check for updated textures.
    */
   if (llvmpipe->tex_timestamp != lp_screen->timestamp) {
      llvmpipe->tex_timestamp = lp_screen->timestamp;
      llvmpipe->dirty |= LP_NEW_SAMPLER_VIEW;
   }
      
   if (llvmpipe->dirty & (LP_NEW_RASTERIZER |
                          LP_NEW_FS |
                          LP_NEW_VS))
      compute_vertex_info( llvmpipe );

   if (llvmpipe->dirty & (LP_NEW_FS |
                          LP_NEW_FRAMEBUFFER |
                          LP_NEW_BLEND |
                          LP_NEW_SCISSOR |
                          LP_NEW_DEPTH_STENCIL_ALPHA |
                          LP_NEW_RASTERIZER |
                          LP_NEW_SAMPLER |
                          LP_NEW_SAMPLER_VIEW |
                          LP_NEW_OCCLUSION_QUERY))
      llvmpipe_update_fs( llvmpipe );

   if (llvmpipe->dirty & (LP_NEW_FS |
			  LP_NEW_RASTERIZER))
      llvmpipe_update_setup( 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_scissors(llvmpipe->setup, llvmpipe->scissors);

   if (llvmpipe->dirty & LP_NEW_DEPTH_STENCIL_ALPHA) {
      lp_setup_set_alpha_ref_value(llvmpipe->setup, 
                                   llvmpipe->depth_stencil->alpha.ref_value);
      lp_setup_set_stencil_ref_values(llvmpipe->setup,
                                      llvmpipe->stencil_ref.ref_value);
   }

   if (llvmpipe->dirty & LP_NEW_CONSTANTS)
      lp_setup_set_fs_constants(llvmpipe->setup,
                                Elements(llvmpipe->constants[PIPE_SHADER_FRAGMENT]),
                                llvmpipe->constants[PIPE_SHADER_FRAGMENT]);

   if (llvmpipe->dirty & (LP_NEW_SAMPLER_VIEW))
      lp_setup_set_fragment_sampler_views(llvmpipe->setup,
                                          llvmpipe->num_sampler_views[PIPE_SHADER_FRAGMENT],
                                          llvmpipe->sampler_views[PIPE_SHADER_FRAGMENT]);

   if (llvmpipe->dirty & (LP_NEW_SAMPLER))
      lp_setup_set_fragment_sampler_state(llvmpipe->setup,
                                          llvmpipe->num_samplers[PIPE_SHADER_FRAGMENT],
                                          llvmpipe->samplers[PIPE_SHADER_FRAGMENT]);

   llvmpipe->dirty = 0;
}
예제 #7
0
파일: lp_screen.c 프로젝트: Haifen/mesa
/**
 * Query format support for creating a texture, drawing surface, etc.
 * \param format  the format to test
 * \param type  one of PIPE_TEXTURE, PIPE_SURFACE
 */
static boolean
llvmpipe_is_format_supported( struct pipe_screen *_screen,
                              enum pipe_format format,
                              enum pipe_texture_target target,
                              unsigned sample_count,
                              unsigned bind)
{
   struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
   struct sw_winsys *winsys = screen->winsys;
   const struct util_format_description *format_desc;

   format_desc = util_format_description(format);
   if (!format_desc)
      return FALSE;

   assert(target == PIPE_BUFFER ||
          target == PIPE_TEXTURE_1D ||
          target == PIPE_TEXTURE_1D_ARRAY ||
          target == PIPE_TEXTURE_2D ||
          target == PIPE_TEXTURE_2D_ARRAY ||
          target == PIPE_TEXTURE_RECT ||
          target == PIPE_TEXTURE_3D ||
          target == PIPE_TEXTURE_CUBE ||
          target == PIPE_TEXTURE_CUBE_ARRAY);

   if (sample_count > 1)
      return FALSE;

   if (bind & PIPE_BIND_RENDER_TARGET) {
      if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
         /* this is a lie actually other formats COULD exist where we would fail */
         if (format_desc->nr_channels < 3)
            return FALSE;
      }
      else if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_RGB)
         return FALSE;

      if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN &&
          format != PIPE_FORMAT_R11G11B10_FLOAT)
         return FALSE;

      assert(format_desc->block.width == 1);
      assert(format_desc->block.height == 1);

      if (format_desc->is_mixed)
         return FALSE;

      if (!format_desc->is_array && !format_desc->is_bitmask &&
          format != PIPE_FORMAT_R11G11B10_FLOAT)
         return FALSE;
   }

   if ((bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW)) &&
       ((bind & PIPE_BIND_DISPLAY_TARGET) == 0)) {
      /* Disable all 3-channel formats, where channel size != 32 bits.
       * In some cases we run into crashes (in generate_unswizzled_blend()),
       * for 3-channel RGB16 variants, there was an apparent LLVM bug.
       * In any case, disabling the shallower 3-channel formats avoids a
       * number of issues with GL_ARB_copy_image support.
       */
      if (format_desc->is_array &&
          format_desc->nr_channels == 3 &&
          format_desc->block.bits != 96) {
         return FALSE;
      }
   }

   if (bind & PIPE_BIND_DISPLAY_TARGET) {
      if(!winsys->is_displaytarget_format_supported(winsys, bind, format))
         return FALSE;
   }

   if (bind & PIPE_BIND_DEPTH_STENCIL) {
      if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN)
         return FALSE;

      if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS)
         return FALSE;

      /* TODO: Support stencil-only formats */
      if (format_desc->swizzle[0] == PIPE_SWIZZLE_NONE) {
         return FALSE;
      }
   }

   if (format_desc->layout == UTIL_FORMAT_LAYOUT_BPTC ||
       format_desc->layout == UTIL_FORMAT_LAYOUT_ASTC) {
      /* Software decoding is not hooked up. */
      return FALSE;
   }

   if (format_desc->layout == UTIL_FORMAT_LAYOUT_ETC &&
       format != PIPE_FORMAT_ETC1_RGB8)
      return FALSE;

   if (format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC) {
      return util_format_s3tc_enabled;
   }

   /*
    * Everything can be supported by u_format
    * (those without fetch_rgba_float might be not but shouldn't hit that)
    */

   return TRUE;
}
예제 #8
0
파일: lp_texture.c 프로젝트: DirectFB/mesa
static struct pipe_resource *
llvmpipe_resource_create(struct pipe_screen *_screen,
                         const struct pipe_resource *templat)
{
   struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
   struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
   if (!lpr)
      return NULL;

   lpr->base = *templat;
   pipe_reference_init(&lpr->base.reference, 1);
   lpr->base.screen = &screen->base;

   /* assert(lpr->base.bind); */

   if (llvmpipe_resource_is_texture(&lpr->base)) {
      if (lpr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
                            PIPE_BIND_SCANOUT |
                            PIPE_BIND_SHARED)) {
         /* displayable surface */
         if (!llvmpipe_displaytarget_layout(screen, lpr))
            goto fail;
      }
      else {
         /* texture map */
         if (!llvmpipe_texture_layout(screen, lpr))
            goto fail;
      }
   }
   else {
      /* other data (vertex buffer, const buffer, etc) */
      const uint bytes = templat->width0;
      assert(util_format_get_blocksize(templat->format) == 1);
      assert(templat->height0 == 1);
      assert(templat->depth0 == 1);
      assert(templat->last_level == 0);
      /*
       * Reserve some extra storage since if we'd render to a buffer we
       * read/write always LP_RASTER_BLOCK_SIZE pixels, but the element
       * offset doesn't need to be aligned to LP_RASTER_BLOCK_SIZE.
       */
      lpr->data = align_malloc(bytes + (LP_RASTER_BLOCK_SIZE - 1) * 4 * sizeof(float), 64);
      /*
       * buffers don't really have stride but it's probably safer
       * (for code doing same calculations for buffers and textures)
       * to put something sane in there.
       */
      lpr->row_stride[0] = bytes;
      if (!lpr->data)
         goto fail;
      memset(lpr->data, 0, bytes);
   }

   lpr->id = id_counter++;

#ifdef DEBUG
   insert_at_tail(&resource_list, lpr);
#endif

   return &lpr->base;

 fail:
   FREE(lpr);
   return NULL;
}
예제 #9
0
/**
 * Query format support for creating a texture, drawing surface, etc.
 * \param format  the format to test
 * \param type  one of PIPE_TEXTURE, PIPE_SURFACE
 */
static boolean
llvmpipe_is_format_supported( struct pipe_screen *_screen,
                              enum pipe_format format,
                              enum pipe_texture_target target,
                              unsigned sample_count,
                              unsigned bind,
                              unsigned geom_flags )
{
   struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
   struct sw_winsys *winsys = screen->winsys;
   const struct util_format_description *format_desc;

   format_desc = util_format_description(format);
   if (!format_desc)
      return FALSE;

   assert(target == PIPE_BUFFER ||
          target == PIPE_TEXTURE_1D ||
          target == PIPE_TEXTURE_2D ||
          target == PIPE_TEXTURE_RECT ||
          target == PIPE_TEXTURE_3D ||
          target == PIPE_TEXTURE_CUBE);

   if (sample_count > 1)
      return FALSE;

   if (bind & PIPE_BIND_RENDER_TARGET) {
      if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS)
         return FALSE;

      if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN)
         return FALSE;

      if (format_desc->block.width != 1 ||
          format_desc->block.height != 1)
         return FALSE;
   }

   if (bind & PIPE_BIND_DISPLAY_TARGET) {
      if(!winsys->is_displaytarget_format_supported(winsys, bind, format))
         return FALSE;
   }

   if (bind & PIPE_BIND_DEPTH_STENCIL) {
      if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN)
         return FALSE;

      if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS)
         return FALSE;

      /* FIXME: Temporary restriction. See lp_state_fs.c. */
      if (format_desc->block.bits != 32)
         return FALSE;
   }

   if (format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC) {
      return util_format_s3tc_enabled;
   }

   /*
    * Everything else should be supported by u_format.
    */
   return TRUE;
}
예제 #10
0
파일: lp_setup.c 프로젝트: NSinopoli/mesa
/**
 * Called during state validation when LP_NEW_SAMPLER_VIEW is set.
 */
void
lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup,
                                    unsigned num,
                                    struct pipe_sampler_view **views)
{
   unsigned i;

   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);

   assert(num <= PIPE_MAX_SHADER_SAMPLER_VIEWS);

   for (i = 0; i < PIPE_MAX_SHADER_SAMPLER_VIEWS; i++) {
      struct pipe_sampler_view *view = i < num ? views[i] : NULL;

      if (view) {
         struct pipe_resource *tex = view->texture;
         struct llvmpipe_resource *lp_tex = llvmpipe_resource(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->first_level = view->u.tex.first_level;
         jit_tex->last_level = tex->last_level;

         if (tex->target == PIPE_TEXTURE_3D) {
            jit_tex->depth = tex->depth0;
         }
         else {
            jit_tex->depth = tex->array_size;
         }

         /* We're referencing the texture's internal data, so save a
          * reference to it.
          */
         pipe_resource_reference(&setup->fs.current_tex[i], tex);

         if (!lp_tex->dt) {
            /* regular texture - setup array of mipmap level offsets */
            void *mip_ptr;
            int j;
            /*
             * XXX this is messed up we don't want to accidentally trigger
             * tiled->linear conversion for levels we don't need.
             * So ask for first_level data (which will allocate all levels)
             * then if successful get base ptr.
             */
            mip_ptr = llvmpipe_get_texture_image_all(lp_tex, view->u.tex.first_level,
                                                     LP_TEX_USAGE_READ,
                                                     LP_TEX_LAYOUT_LINEAR);
            if ((LP_PERF & PERF_TEX_MEM) || !mip_ptr) {
               /* out of memory - use dummy tile memory */
               jit_tex->base = lp_dummy_tile;
               jit_tex->width = TILE_SIZE/8;
               jit_tex->height = TILE_SIZE/8;
               jit_tex->depth = 1;
               jit_tex->first_level = 0;
               jit_tex->last_level = 0;
            }
            else {
               jit_tex->base = lp_tex->linear_img.data;
            }
            for (j = view->u.tex.first_level; j <= tex->last_level; j++) {
               mip_ptr = llvmpipe_get_texture_image_all(lp_tex, j,
                                                        LP_TEX_USAGE_READ,
                                                        LP_TEX_LAYOUT_LINEAR);
               jit_tex->mip_offsets[j] = (uint8_t *)mip_ptr - (uint8_t *)jit_tex->base;
               /*
                * could get mip offset directly but need call above to
                * invoke tiled->linear conversion.
                */
               assert(lp_tex->linear_mip_offsets[j] == jit_tex->mip_offsets[j]);
               jit_tex->row_stride[j] = lp_tex->row_stride[j];
               jit_tex->img_stride[j] = lp_tex->img_stride[j];

               if (jit_tex->base == lp_dummy_tile) {
                  /* out of memory - use dummy tile memory */
                  jit_tex->mip_offsets[j] = 0;
                  jit_tex->row_stride[j] = 0;
                  jit_tex->img_stride[j] = 0;
               }
            }
         }
         else {
            /* display target texture/surface */
            /*
             * XXX: Where should this be unmapped?
             */
            struct llvmpipe_screen *screen = llvmpipe_screen(tex->screen);
            struct sw_winsys *winsys = screen->winsys;
            jit_tex->base = winsys->displaytarget_map(winsys, lp_tex->dt,
                                                         PIPE_TRANSFER_READ);
            jit_tex->row_stride[0] = lp_tex->row_stride[0];
            jit_tex->img_stride[0] = lp_tex->img_stride[0];
            jit_tex->mip_offsets[0] = 0;
            assert(jit_tex->base);
         }
      }
   }

   setup->dirty |= LP_SETUP_NEW_FS;
}
예제 #11
0
파일: lp_texture.c 프로젝트: DirectFB/mesa
llvmpipe_resource_data(struct pipe_resource *resource)
{
   struct llvmpipe_resource *lpr = llvmpipe_resource(resource);

   assert(!llvmpipe_resource_is_texture(resource));

   return lpr->data;
}


static struct pipe_resource *
llvmpipe_resource_from_handle(struct pipe_screen *screen,
                              const struct pipe_resource *template,
                              struct winsys_handle *whandle)
{
   struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
   struct llvmpipe_resource *lpr;

   /* XXX Seems like from_handled depth textures doesn't work that well */

   lpr = CALLOC_STRUCT(llvmpipe_resource);
   if (!lpr) {
      goto no_lpr;
   }

   lpr->base = *template;
   pipe_reference_init(&lpr->base.reference, 1);
   lpr->base.screen = screen;

   /*
    * Looks like unaligned displaytargets work just fine,
예제 #12
0
static void
prepare_shader_sampling(
   struct llvmpipe_context *lp,
   unsigned num,
   struct pipe_sampler_view **views,
   unsigned shader_type,
   struct pipe_resource *mapped_tex[PIPE_MAX_SHADER_SAMPLER_VIEWS])
{

   unsigned i;
   uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS];
   uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS];
   uint32_t mip_offsets[PIPE_MAX_TEXTURE_LEVELS];
   const void *addr;

   assert(num <= PIPE_MAX_SHADER_SAMPLER_VIEWS);
   if (!num)
      return;

   for (i = 0; i < PIPE_MAX_SHADER_SAMPLER_VIEWS; i++) {
      struct pipe_sampler_view *view = i < num ? views[i] : NULL;

      if (view) {
         struct pipe_resource *tex = view->texture;
         struct llvmpipe_resource *lp_tex = llvmpipe_resource(tex);
         unsigned width0 = tex->width0;
         unsigned num_layers = tex->depth0;
         unsigned first_level = 0;
         unsigned last_level = 0;

         /* We're referencing the texture's internal data, so save a
          * reference to it.
          */
         pipe_resource_reference(&mapped_tex[i], tex);

         if (!lp_tex->dt) {
            /* regular texture - setup array of mipmap level offsets */
            struct pipe_resource *res = view->texture;
            int j;

            if (llvmpipe_resource_is_texture(res)) {
               first_level = view->u.tex.first_level;
               last_level = view->u.tex.last_level;
               assert(first_level <= last_level);
               assert(last_level <= res->last_level);
               addr = lp_tex->tex_data;

               for (j = first_level; j <= last_level; j++) {
                  mip_offsets[j] = lp_tex->mip_offsets[j];
                  row_stride[j] = lp_tex->row_stride[j];
                  img_stride[j] = lp_tex->img_stride[j];
               }
               if (res->target == PIPE_TEXTURE_1D_ARRAY ||
                   res->target == PIPE_TEXTURE_2D_ARRAY ||
                   res->target == PIPE_TEXTURE_CUBE_ARRAY) {
                  num_layers = view->u.tex.last_layer - view->u.tex.first_layer + 1;
                  for (j = first_level; j <= last_level; j++) {
                     mip_offsets[j] += view->u.tex.first_layer *
                                       lp_tex->img_stride[j];
                  }
                  if (res->target == PIPE_TEXTURE_CUBE_ARRAY) {
                     assert(num_layers % 6 == 0);
                  }
                  assert(view->u.tex.first_layer <= view->u.tex.last_layer);
                  assert(view->u.tex.last_layer < res->array_size);
               }
            }
            else {
               unsigned view_blocksize = util_format_get_blocksize(view->format);
               addr = lp_tex->data;
               /* probably don't really need to fill that out */
               mip_offsets[0] = 0;
               row_stride[0] = 0;
               row_stride[0] = 0;

               /* everything specified in number of elements here. */
               width0 = view->u.buf.last_element - view->u.buf.first_element + 1;
               addr = (uint8_t *)addr + view->u.buf.first_element *
                               view_blocksize;
               assert(view->u.buf.first_element <= view->u.buf.last_element);
               assert(view->u.buf.last_element * view_blocksize < res->width0);
            }
         }
         else {
            /* display target texture/surface */
            /*
             * XXX: Where should this be unmapped?
             */
            struct llvmpipe_screen *screen = llvmpipe_screen(tex->screen);
            struct sw_winsys *winsys = screen->winsys;
            addr = winsys->displaytarget_map(winsys, lp_tex->dt,
                                                PIPE_TRANSFER_READ);
            row_stride[0] = lp_tex->row_stride[0];
            img_stride[0] = lp_tex->img_stride[0];
            mip_offsets[0] = 0;
            assert(addr);
         }
         draw_set_mapped_texture(lp->draw,
                                 shader_type,
                                 i,
                                 width0, tex->height0, num_layers,
                                 first_level, last_level,
                                 addr,
                                 row_stride, img_stride, mip_offsets);
      }
   }
}
예제 #13
0
/**
 * Generate the runtime callable function for the whole fragment pipeline.
 */
static struct lp_fragment_shader_variant *
generate_fragment(struct llvmpipe_context *lp,
                  struct lp_fragment_shader *shader,
                  const struct lp_fragment_shader_variant_key *key)
{
   struct llvmpipe_screen *screen = llvmpipe_screen(lp->pipe.screen);
   struct lp_fragment_shader_variant *variant;
   struct lp_type fs_type;
   struct lp_type blend_type;
   LLVMTypeRef fs_elem_type;
   LLVMTypeRef fs_vec_type;
   LLVMTypeRef fs_int_vec_type;
   LLVMTypeRef blend_vec_type;
   LLVMTypeRef blend_int_vec_type;
   LLVMTypeRef arg_types[9];
   LLVMTypeRef func_type;
   LLVMValueRef context_ptr;
   LLVMValueRef x;
   LLVMValueRef y;
   LLVMValueRef a0_ptr;
   LLVMValueRef dadx_ptr;
   LLVMValueRef dady_ptr;
   LLVMValueRef mask_ptr;
   LLVMValueRef color_ptr;
   LLVMValueRef depth_ptr;
   LLVMBasicBlockRef block;
   LLVMBuilderRef builder;
   LLVMValueRef x0;
   LLVMValueRef y0;
   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 blend_mask;
   LLVMValueRef blend_in_color[NUM_CHANNELS];
   unsigned num_fs;
   unsigned i;
   unsigned chan;

#ifdef DEBUG
   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.blend_enable) {
      debug_printf("blend.rgb_func = %s\n",   debug_dump_blend_func  (key->blend.rgb_func, TRUE));
      debug_printf("rgb_src_factor = %s\n",   debug_dump_blend_factor(key->blend.rgb_src_factor, TRUE));
      debug_printf("rgb_dst_factor = %s\n",   debug_dump_blend_factor(key->blend.rgb_dst_factor, TRUE));
      debug_printf("alpha_func = %s\n",       debug_dump_blend_func  (key->blend.alpha_func, TRUE));
      debug_printf("alpha_src_factor = %s\n", debug_dump_blend_factor(key->blend.alpha_src_factor, TRUE));
      debug_printf("alpha_dst_factor = %s\n", debug_dump_blend_factor(key->blend.alpha_dst_factor, TRUE));
   }
   debug_printf("blend.colormask = 0x%x\n", key->blend.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)
            debug_printf("  .compare_mode = %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);
      }
   }

#endif

   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. */

   memset(&fs_type, 0, sizeof fs_type);
   fs_type.floating = TRUE; /* floating point values */
   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;

   memset(&blend_type, 0, sizeof blend_type);
   blend_type.floating = FALSE; /* values are integers */
   blend_type.sign = FALSE;     /* values are unsigned */
   blend_type.norm = TRUE;      /* values are in [0,1] or [-1,1] */
   blend_type.width = 8;        /* 8-bit ubyte values */
   blend_type.length = 16;      /* 16 elements per vector */

   /* 
    * Generate the function prototype. Any change here must be reflected in
    * lp_jit.h's lp_jit_frag_func function pointer type, and vice-versa.
    */

   fs_elem_type = lp_build_elem_type(fs_type);
   fs_vec_type = lp_build_vec_type(fs_type);
   fs_int_vec_type = lp_build_int_vec_type(fs_type);

   blend_vec_type = lp_build_vec_type(blend_type);
   blend_int_vec_type = lp_build_int_vec_type(blend_type);

   arg_types[0] = screen->context_ptr_type;            /* context */
   arg_types[1] = LLVMInt32Type();                     /* x */
   arg_types[2] = LLVMInt32Type();                     /* y */
   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 */

   func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);

   variant->function = LLVMAddFunction(screen->module, "shader", func_type);
   LLVMSetFunctionCallConv(variant->function, LLVMCCallConv);
   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);

   lp_build_name(context_ptr, "context");
   lp_build_name(x, "x");
   lp_build_name(y, "y");
   lp_build_name(a0_ptr, "a0");
   lp_build_name(dadx_ptr, "dadx");
   lp_build_name(dady_ptr, "dady");
   lp_build_name(mask_ptr, "mask");
   lp_build_name(color_ptr, "color");
   lp_build_name(depth_ptr, "depth");

   /*
    * Function body
    */

   block = LLVMAppendBasicBlock(variant->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,
                            a0_ptr, dadx_ptr, dady_ptr,
                            x0, y0, 2, 0);

#if 0
   /* C texture sampling */
   sampler = lp_c_sampler_soa_create(context_ptr);
#else
   /* code generated texture sampling */
   sampler = lp_llvm_sampler_soa_create(key->sampler, context_ptr);
#endif

   for(i = 0; i < num_fs; ++i) {
      LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
      LLVMValueRef out_color[NUM_CHANNELS];
      LLVMValueRef depth_ptr_i;

      if(i != 0)
         lp_build_interp_soa_update(&interp);

      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,
                  builder,
                  fs_type,
                  context_ptr,
                  i,
                  &interp,
                  sampler,
                  &fs_mask[i],
                  out_color,
                  depth_ptr_i);

      for(chan = 0; chan < NUM_CHANNELS; ++chan)
         fs_out_color[chan][i] = out_color[chan];
   }

   sampler->destroy(sampler);

   /* 
    * 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[chan], num_fs,
                    &blend_in_color[chan], 1);
      lp_build_name(blend_in_color[chan], "color.%c", "rgba"[chan]);

   }

   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.
    */

   if(LLVMVerifyFunction(variant->function, LLVMPrintMessageAction)) {
      LLVMDumpValue(variant->function);
      abort();
   }

   LLVMRunFunctionPassManager(screen->pass, variant->function);

#ifdef DEBUG
   LLVMDumpValue(variant->function);
   debug_printf("\n");
#endif

   variant->jit_function = (lp_jit_frag_func)LLVMGetPointerToGlobal(screen->engine, variant->function);

#ifdef DEBUG
   lp_disassemble(variant->jit_function);
#endif

   variant->next = shader->variants;
   shader->variants = variant;

   return variant;
}
예제 #14
0
/**
 * 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 void
generate_fragment(struct llvmpipe_context *lp,
                  struct lp_fragment_shader *shader,
                  struct lp_fragment_shader_variant *variant,
                  unsigned partial_mask)
{
   struct llvmpipe_screen *screen = llvmpipe_screen(lp->pipe.screen);
   const struct lp_fragment_shader_variant_key *key = &variant->key;
   char func_name[256];
   struct lp_type fs_type;
   struct lp_type blend_type;
   LLVMTypeRef fs_elem_type;
   LLVMTypeRef fs_int_vec_type;
   LLVMTypeRef blend_vec_type;
   LLVMTypeRef arg_types[11];
   LLVMTypeRef func_type;
   LLVMValueRef context_ptr;
   LLVMValueRef x;
   LLVMValueRef y;
   LLVMValueRef a0_ptr;
   LLVMValueRef dadx_ptr;
   LLVMValueRef dady_ptr;
   LLVMValueRef color_ptr_ptr;
   LLVMValueRef depth_ptr;
   LLVMValueRef mask_input;
   LLVMValueRef counter = NULL;
   LLVMBasicBlockRef block;
   LLVMBuilderRef builder;
   struct lp_build_sampler_soa *sampler;
   struct lp_build_interp_soa_context interp;
   LLVMValueRef fs_mask[LP_MAX_VECTOR_LENGTH];
   LLVMValueRef fs_out_color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS][LP_MAX_VECTOR_LENGTH];
   LLVMValueRef blend_mask;
   LLVMValueRef function;
   LLVMValueRef facing;
   unsigned num_fs;
   unsigned i;
   unsigned chan;
   unsigned cbuf;


   /* TODO: actually pick these based on the fs and color buffer
    * characteristics. */

   memset(&fs_type, 0, sizeof fs_type);
   fs_type.floating = TRUE; /* floating point values */
   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 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 */
   blend_type.sign = FALSE;     /* values are unsigned */
   blend_type.norm = TRUE;      /* values are in [0,1] or [-1,1] */
   blend_type.width = 8;        /* 8-bit ubyte values */
   blend_type.length = 16;      /* 16 elements per vector */

   /* 
    * Generate the function prototype. Any change here must be reflected in
    * lp_jit.h's lp_jit_frag_func function pointer type, and vice-versa.
    */

   fs_elem_type = lp_build_elem_type(fs_type);
   fs_int_vec_type = lp_build_int_vec_type(fs_type);

   blend_vec_type = lp_build_vec_type(blend_type);

   util_snprintf(func_name, sizeof(func_name), "fs%u_variant%u_%s", 
		 shader->no, variant->no, partial_mask ? "partial" : "whole");

   arg_types[0] = screen->context_ptr_type;            /* context */
   arg_types[1] = LLVMInt32Type();                     /* x */
   arg_types[2] = LLVMInt32Type();                     /* y */
   arg_types[3] = LLVMFloatType();                     /* facing */
   arg_types[4] = LLVMPointerType(fs_elem_type, 0);    /* a0 */
   arg_types[5] = LLVMPointerType(fs_elem_type, 0);    /* dadx */
   arg_types[6] = LLVMPointerType(fs_elem_type, 0);    /* dady */
   arg_types[7] = LLVMPointerType(LLVMPointerType(blend_vec_type, 0), 0);  /* color */
   arg_types[8] = LLVMPointerType(fs_int_vec_type, 0); /* depth */
   arg_types[9] = LLVMInt32Type();                     /* mask_input */
   arg_types[10] = LLVMPointerType(LLVMInt32Type(), 0);/* counter */

   func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);

   function = LLVMAddFunction(screen->module, func_name, func_type);
   LLVMSetFunctionCallConv(function, LLVMCCallConv);

   variant->function[partial_mask] = 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(function, i), LLVMNoAliasAttribute);

   context_ptr  = LLVMGetParam(function, 0);
   x            = LLVMGetParam(function, 1);
   y            = LLVMGetParam(function, 2);
   facing       = LLVMGetParam(function, 3);
   a0_ptr       = LLVMGetParam(function, 4);
   dadx_ptr     = LLVMGetParam(function, 5);
   dady_ptr     = LLVMGetParam(function, 6);
   color_ptr_ptr = LLVMGetParam(function, 7);
   depth_ptr    = LLVMGetParam(function, 8);
   mask_input   = LLVMGetParam(function, 9);

   lp_build_name(context_ptr, "context");
   lp_build_name(x, "x");
   lp_build_name(y, "y");
   lp_build_name(a0_ptr, "a0");
   lp_build_name(dadx_ptr, "dadx");
   lp_build_name(dady_ptr, "dady");
   lp_build_name(color_ptr_ptr, "color_ptr_ptr");
   lp_build_name(depth_ptr, "depth");
   lp_build_name(mask_input, "mask_input");

   if (key->occlusion_count) {
      counter = LLVMGetParam(function, 10);
      lp_build_name(counter, "counter");
   }

   /*
    * Function body
    */

   block = LLVMAppendBasicBlock(function, "entry");
   builder = LLVMCreateBuilder();
   LLVMPositionBuilderAtEnd(builder, block);

   /*
    * The shader input interpolation info is not explicitely baked in the
    * shader key, but everything it derives from (TGSI, and flatshade) is
    * already included in the shader key.
    */
   lp_build_interp_soa_init(&interp, 
                            lp->num_inputs,
                            lp->inputs,
                            builder, fs_type,
                            a0_ptr, dadx_ptr, dady_ptr,
                            x, y);

   /* 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[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS];
      LLVMValueRef depth_ptr_i;

      if(i != 0)
         lp_build_interp_soa_update(&interp, i);

      depth_ptr_i = LLVMBuildGEP(builder, depth_ptr, &index, 1, "");

      generate_fs(lp, shader, key,
                  builder,
                  fs_type,
                  context_ptr,
                  i,
                  &interp,
                  sampler,
                  &fs_mask[i], /* output */
                  out_color,
                  depth_ptr_i,
                  facing,
                  partial_mask,
                  mask_input,
                  counter);

      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);

   /* 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);
      LLVMValueRef blend_in_color[NUM_CHANNELS];
      unsigned rt;

      /* 
       * 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]);
      }

      if (partial_mask || !variant->opaque) {
         lp_build_conv_mask(builder, fs_type, blend_type,
                            fs_mask, num_fs,
                            &blend_mask, 1);
      } else {
         blend_mask = lp_build_const_int_vec(blend_type, ~0);
      }

      color_ptr = LLVMBuildLoad(builder, 
				LLVMBuildGEP(builder, color_ptr_ptr, &index, 1, ""),
				"");
      lp_build_name(color_ptr, "color_ptr%d", cbuf);

      /* which blend/colormask state to use */
      rt = key->blend.independent_blend_enable ? cbuf : 0;

      /*
       * Blending.
       */
      generate_blend(&key->blend,
                     rt,
		     builder,
		     blend_type,
		     context_ptr,
		     blend_mask,
		     blend_in_color,
		     color_ptr);
   }

#ifdef PIPE_ARCH_X86
   /* Avoid corrupting the FPU stack on 32bit OSes. */
   lp_build_intrinsic(builder, "llvm.x86.mmx.emms", LLVMVoidType(), NULL, 0);
#endif

   LLVMBuildRetVoid(builder);

   LLVMDisposeBuilder(builder);


   /* Verify the LLVM IR.  If invalid, dump and abort */
#ifdef DEBUG
   if(LLVMVerifyFunction(function, LLVMPrintMessageAction)) {
      if (1)
         lp_debug_dump_value(function);
      abort();
   }
#endif

   /* Apply optimizations to LLVM IR */
   LLVMRunFunctionPassManager(screen->pass, function);

   if (gallivm_debug & GALLIVM_DEBUG_IR) {
      /* Print the LLVM IR to stderr */
      lp_debug_dump_value(function);
      debug_printf("\n");
   }

   /*
    * Translate the LLVM IR into machine code.
    */
   {
      void *f = LLVMGetPointerToGlobal(screen->engine, function);

      variant->jit_function[partial_mask] = (lp_jit_frag_func)pointer_to_func(f);

      if (gallivm_debug & GALLIVM_DEBUG_ASM) {
         lp_disassemble(f);
      }
      lp_func_delete_body(function);
   }
}
예제 #15
0
파일: lp_texture.c 프로젝트: UIKit0/mesa
/**
 * Map a resource for read/write.
 */
void *
llvmpipe_resource_map(struct pipe_resource *resource,
                      unsigned level,
                      unsigned layer,
                      enum lp_texture_usage tex_usage,
                      enum lp_texture_layout layout)
{
   struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
   uint8_t *map;

   assert(level < LP_MAX_TEXTURE_LEVELS);
   assert(layer < (u_minify(resource->depth0, level) + resource->array_size - 1));

   assert(tex_usage == LP_TEX_USAGE_READ ||
          tex_usage == LP_TEX_USAGE_READ_WRITE ||
          tex_usage == LP_TEX_USAGE_WRITE_ALL);

   assert(layout == LP_TEX_LAYOUT_NONE ||
          layout == LP_TEX_LAYOUT_TILED ||
          layout == LP_TEX_LAYOUT_LINEAR);

   if (lpr->dt) {
      /* display target */
      struct llvmpipe_screen *screen = llvmpipe_screen(resource->screen);
      struct sw_winsys *winsys = screen->winsys;
      unsigned dt_usage;
      uint8_t *map2;

      if (tex_usage == LP_TEX_USAGE_READ) {
         dt_usage = PIPE_TRANSFER_READ;
      }
      else {
         dt_usage = PIPE_TRANSFER_READ_WRITE;
      }

      assert(level == 0);
      assert(layer == 0);

      /* FIXME: keep map count? */
      map = winsys->displaytarget_map(winsys, lpr->dt, dt_usage);

      /* install this linear image in texture data structure */
      lpr->linear[level].data = map;

      /* make sure tiled data gets converted to linear data */
      map2 = llvmpipe_get_texture_image(lpr, 0, 0, tex_usage, layout);
      if (layout == LP_TEX_LAYOUT_LINEAR)
         assert(map == map2);

      return map2;
   }
   else if (resource_is_texture(resource)) {

      map = llvmpipe_get_texture_image(lpr, layer, level,
                                       tex_usage, layout);
      return map;
   }
   else {
      return lpr->data;
   }
}
예제 #16
0
파일: lp_query.c 프로젝트: DirectFB/mesa
static boolean
llvmpipe_get_query_result(struct pipe_context *pipe, 
                          struct pipe_query *q,
                          boolean wait,
                          union pipe_query_result *vresult)
{
   struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
   unsigned num_threads = MAX2(1, screen->num_threads);
   struct llvmpipe_query *pq = llvmpipe_query(q);
   uint64_t *result = (uint64_t *)vresult;
   int i;

   if (pq->fence) {
      /* only have a fence if there was a scene */
      if (!lp_fence_signalled(pq->fence)) {
         if (!lp_fence_issued(pq->fence))
            llvmpipe_flush(pipe, NULL, __FUNCTION__);

         if (!wait)
            return FALSE;

         lp_fence_wait(pq->fence);
      }
   }

   /* Sum the results from each of the threads:
    */
   *result = 0;

   switch (pq->type) {
   case PIPE_QUERY_OCCLUSION_COUNTER:
      for (i = 0; i < num_threads; i++) {
         *result += pq->end[i];
      }
      break;
   case PIPE_QUERY_OCCLUSION_PREDICATE:
      for (i = 0; i < num_threads; i++) {
         /* safer (still not guaranteed) when there's an overflow */
         vresult->b = vresult->b || pq->end[i];
      }
      break;
   case PIPE_QUERY_TIMESTAMP:
      for (i = 0; i < num_threads; i++) {
         if (pq->end[i] > *result) {
            *result = pq->end[i];
         }
      }
      break;
   case PIPE_QUERY_TIMESTAMP_DISJOINT: {
      struct pipe_query_data_timestamp_disjoint *td =
         (struct pipe_query_data_timestamp_disjoint *)vresult;
      /* os_get_time_nano return nanoseconds */
      td->frequency = UINT64_C(1000000000);
      td->disjoint = FALSE;
   }
      break;
   case PIPE_QUERY_GPU_FINISHED:
      vresult->b = TRUE;
      break;
   case PIPE_QUERY_PRIMITIVES_GENERATED:
      *result = pq->num_primitives_generated;
      break;
   case PIPE_QUERY_PRIMITIVES_EMITTED:
      *result = pq->num_primitives_written;
      break;
   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
      vresult->b = pq->num_primitives_generated > pq->num_primitives_written;
      break;
   case PIPE_QUERY_SO_STATISTICS: {
      struct pipe_query_data_so_statistics *stats =
         (struct pipe_query_data_so_statistics *)vresult;
      stats->num_primitives_written = pq->num_primitives_written;
      stats->primitives_storage_needed = pq->num_primitives_generated;
   }
      break;
   case PIPE_QUERY_PIPELINE_STATISTICS: {
      struct pipe_query_data_pipeline_statistics *stats =
         (struct pipe_query_data_pipeline_statistics *)vresult;
      /* only ps_invocations come from binned query */
      for (i = 0; i < num_threads; i++) {
         pq->stats.ps_invocations += pq->end[i];
      }
      pq->stats.ps_invocations *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE;
      *stats = pq->stats;
   }
      break;
   default:
      assert(0);
      break;
   }

   return TRUE;
}