Merge branch 'no-validate' into gallium-0.1
[mesa.git] / src / gallium / auxiliary / draw / draw_pipe_aaline.c
index e8d2a45102c85185de0fefc86efb73744b19b305..20841bb5d69b0abda50c61354e803f399ad72cb0 100644 (file)
  */
 
 
-#include "pipe/p_util.h"
 #include "pipe/p_inlines.h"
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
 #include "pipe/p_shader_tokens.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
 
-#include "tgsi/util/tgsi_transform.h"
-#include "tgsi/util/tgsi_dump.h"
+#include "tgsi/tgsi_transform.h"
+#include "tgsi/tgsi_dump.h"
 
 #include "draw_context.h"
 #include "draw_private.h"
+#include "draw_pipe.h"
 
 
 /**
@@ -77,6 +79,8 @@ struct aaline_stage
 
    /** For AA lines, this is the vertex attrib slot for the new texcoords */
    uint tex_slot;
+   /** position, not necessarily output zero */
+   uint pos_slot;
 
    void *sampler_cso;
    struct pipe_texture *texture;
@@ -140,18 +144,18 @@ aa_transform_decl(struct tgsi_transform_context *ctx,
    if (decl->Declaration.File == TGSI_FILE_OUTPUT &&
        decl->Semantic.SemanticName == TGSI_SEMANTIC_COLOR &&
        decl->Semantic.SemanticIndex == 0) {
-      aactx->colorOutput = decl->u.DeclarationRange.First;
+      aactx->colorOutput = decl->DeclarationRange.First;
    }
    else if (decl->Declaration.File == TGSI_FILE_SAMPLER) {
       uint i;
-      for (i = decl->u.DeclarationRange.First;
-           i <= decl->u.DeclarationRange.Last; i++) {
+      for (i = decl->DeclarationRange.First;
+           i <= decl->DeclarationRange.Last; i++) {
          aactx->samplersUsed |= 1 << i;
       }
    }
    else if (decl->Declaration.File == TGSI_FILE_INPUT) {
-      if ((int) decl->u.DeclarationRange.Last > aactx->maxInput)
-         aactx->maxInput = decl->u.DeclarationRange.Last;
+      if ((int) decl->DeclarationRange.Last > aactx->maxInput)
+         aactx->maxInput = decl->DeclarationRange.Last;
       if (decl->Semantic.SemanticName == TGSI_SEMANTIC_GENERIC &&
            (int) decl->Semantic.SemanticIndex > aactx->maxGeneric) {
          aactx->maxGeneric = decl->Semantic.SemanticIndex;
@@ -159,8 +163,8 @@ aa_transform_decl(struct tgsi_transform_context *ctx,
    }
    else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {
       uint i;
-      for (i = decl->u.DeclarationRange.First;
-           i <= decl->u.DeclarationRange.Last; i++) {
+      for (i = decl->DeclarationRange.First;
+           i <= decl->DeclarationRange.Last; i++) {
          aactx->tempsUsed |= (1 << i);
       }
    }
@@ -224,34 +228,33 @@ aa_transform_inst(struct tgsi_transform_context *ctx,
       /* declare new generic input/texcoord */
       decl = tgsi_default_full_declaration();
       decl.Declaration.File = TGSI_FILE_INPUT;
+      /* XXX this could be linear... */
+      decl.Declaration.Interpolate = TGSI_INTERPOLATE_PERSPECTIVE;
       decl.Declaration.Semantic = 1;
       decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC;
       decl.Semantic.SemanticIndex = aactx->maxGeneric + 1;
-      decl.Declaration.Interpolate = 1;
-      /* XXX this could be linear... */
-      decl.Interpolation.Interpolate = TGSI_INTERPOLATE_PERSPECTIVE;
-      decl.u.DeclarationRange.First = 
-      decl.u.DeclarationRange.Last = aactx->maxInput + 1;
+      decl.DeclarationRange.First = 
+      decl.DeclarationRange.Last = aactx->maxInput + 1;
       ctx->emit_declaration(ctx, &decl);
 
       /* declare new sampler */
       decl = tgsi_default_full_declaration();
       decl.Declaration.File = TGSI_FILE_SAMPLER;
-      decl.u.DeclarationRange.First = 
-      decl.u.DeclarationRange.Last = aactx->freeSampler;
+      decl.DeclarationRange.First = 
+      decl.DeclarationRange.Last = aactx->freeSampler;
       ctx->emit_declaration(ctx, &decl);
 
       /* declare new temp regs */
       decl = tgsi_default_full_declaration();
       decl.Declaration.File = TGSI_FILE_TEMPORARY;
-      decl.u.DeclarationRange.First = 
-      decl.u.DeclarationRange.Last = aactx->texTemp;
+      decl.DeclarationRange.First = 
+      decl.DeclarationRange.Last = aactx->texTemp;
       ctx->emit_declaration(ctx, &decl);
 
       decl = tgsi_default_full_declaration();
       decl.Declaration.File = TGSI_FILE_TEMPORARY;
-      decl.u.DeclarationRange.First = 
-      decl.u.DeclarationRange.Last = aactx->colorTemp;
+      decl.DeclarationRange.First = 
+      decl.DeclarationRange.Last = aactx->colorTemp;
       ctx->emit_declaration(ctx, &decl);
 
       aactx->firstInstruction = FALSE;
@@ -333,11 +336,10 @@ aa_transform_inst(struct tgsi_transform_context *ctx,
  * Generate the frag shader we'll use for drawing AA lines.
  * This will be the user's shader plus some texture/modulate instructions.
  */
-static void
+static boolean
 generate_aaline_fs(struct aaline_stage *aaline)
 {
    const struct pipe_shader_state *orig_fs = &aaline->fs->state;
-   //struct draw_context *draw = aaline->stage.draw;
    struct pipe_shader_state aaline_fs;
    struct aa_transform_context transform;
 
@@ -345,6 +347,8 @@ generate_aaline_fs(struct aaline_stage *aaline)
 
    aaline_fs = *orig_fs; /* copy to init */
    aaline_fs.tokens = MALLOC(sizeof(struct tgsi_token) * MAX);
+   if (aaline_fs.tokens == NULL)
+      return FALSE;
 
    memset(&transform, 0, sizeof(transform));
    transform.colorOutput = -1;
@@ -369,15 +373,18 @@ generate_aaline_fs(struct aaline_stage *aaline)
 
    aaline->fs->aaline_fs
       = aaline->driver_create_fs_state(aaline->pipe, &aaline_fs);
+   if (aaline->fs->aaline_fs == NULL)
+      return FALSE;
 
    aaline->fs->generic_attrib = transform.maxGeneric + 1;
+   return TRUE;
 }
 
 
 /**
  * Create the texture map we'll use for antialiasing the lines.
  */
-static void
+static boolean
 aaline_create_texture(struct aaline_stage *aaline)
 {
    struct pipe_context *pipe = aaline->pipe;
@@ -387,14 +394,16 @@ aaline_create_texture(struct aaline_stage *aaline)
 
    memset(&texTemp, 0, sizeof(texTemp));
    texTemp.target = PIPE_TEXTURE_2D;
-   texTemp.format = PIPE_FORMAT_U_A8; /* XXX verify supported by driver! */
+   texTemp.format = PIPE_FORMAT_A8_UNORM; /* XXX verify supported by driver! */
    texTemp.last_level = MAX_TEXTURE_LEVEL;
    texTemp.width[0] = 1 << MAX_TEXTURE_LEVEL;
    texTemp.height[0] = 1 << MAX_TEXTURE_LEVEL;
    texTemp.depth[0] = 1;
-   texTemp.cpp = 1;
+   pf_get_block(texTemp.format, &texTemp.block);
 
    aaline->texture = screen->texture_create(screen, &texTemp);
+   if (!aaline->texture)
+      return FALSE;
 
    /* Fill in mipmap images.
     * Basically each level is solid opaque, except for the outermost
@@ -408,8 +417,13 @@ aaline_create_texture(struct aaline_stage *aaline)
 
       assert(aaline->texture->width[level] == aaline->texture->height[level]);
 
-      surface = screen->get_tex_surface(screen, aaline->texture, 0, level, 0);
-      data = pipe_surface_map(surface);
+      /* This texture is new, no need to flush. 
+       */
+      surface = screen->get_tex_surface(screen, aaline->texture, 0, level, 0,
+                                        PIPE_BUFFER_USAGE_CPU_WRITE);
+      data = screen->surface_map(screen, surface, PIPE_BUFFER_USAGE_CPU_WRITE);
+      if (data == NULL)
+         return FALSE;
 
       for (i = 0; i < size; i++) {
          for (j = 0; j < size; j++) {
@@ -426,15 +440,15 @@ aaline_create_texture(struct aaline_stage *aaline)
             else {
                d = 255;
             }
-            data[i * surface->pitch + j] = d;
+            data[i * surface->stride + j] = d;
          }
       }
 
       /* unmap */
-      pipe_surface_unmap(surface);
-      pipe_surface_reference(&surface, NULL);
-      pipe->texture_update(pipe, aaline->texture, 0, (1 << level));
+      screen->surface_unmap(screen, surface);
+      screen->tex_surface_release(screen, &surface);
    }
+   return TRUE;
 }
 
 
@@ -443,7 +457,7 @@ aaline_create_texture(struct aaline_stage *aaline)
  * By using a mipmapped texture, we don't have to generate a different
  * texture image for each line size.
  */
-static void
+static boolean
 aaline_create_sampler(struct aaline_stage *aaline)
 {
    struct pipe_sampler_state sampler;
@@ -461,6 +475,10 @@ aaline_create_sampler(struct aaline_stage *aaline)
    sampler.max_lod = MAX_TEXTURE_LEVEL;
 
    aaline->sampler_cso = pipe->create_sampler_state(pipe, &sampler);
+   if (aaline->sampler_cso == NULL)
+      return FALSE;
+
+   return TRUE;
 }
 
 
@@ -468,13 +486,20 @@ aaline_create_sampler(struct aaline_stage *aaline)
  * When we're about to draw our first AA line in a batch, this function is
  * called to tell the driver to bind our modified fragment shader.
  */
-static void
+static boolean
 bind_aaline_fragment_shader(struct aaline_stage *aaline)
 {
-   if (!aaline->fs->aaline_fs) {
-      generate_aaline_fs(aaline);
-   }
+   struct draw_context *draw = aaline->stage.draw;
+
+   if (!aaline->fs->aaline_fs && 
+       !generate_aaline_fs(aaline))
+      return FALSE;
+
+   draw->suspend_flushing = TRUE;
    aaline->driver_bind_fs_state(aaline->pipe, aaline->fs->aaline_fs);
+   draw->suspend_flushing = FALSE;
+
+   return TRUE;
 }
 
 
@@ -486,20 +511,6 @@ aaline_stage( struct draw_stage *stage )
 }
 
 
-static void
-passthrough_point(struct draw_stage *stage, struct prim_header *header)
-{
-   stage->next->point(stage->next, header);
-}
-
-
-static void
-passthrough_tri(struct draw_stage *stage, struct prim_header *header)
-{
-   stage->next->tri(stage->next, header);
-}
-
-
 /**
  * Draw a wide line by drawing a quad, using geometry which will
  * fullfill GL's antialiased line requirements.
@@ -512,9 +523,10 @@ aaline_line(struct draw_stage *stage, struct prim_header *header)
    struct prim_header tri;
    struct vertex_header *v[8];
    uint texPos = aaline->tex_slot;
+   uint posPos = aaline->pos_slot;
    float *pos, *tex;
-   float dx = header->v[1]->data[0][0] - header->v[0]->data[0][0];
-   float dy = header->v[1]->data[0][1] - header->v[0]->data[0][1];
+   float dx = header->v[1]->data[posPos][0] - header->v[0]->data[posPos][0];
+   float dy = header->v[1]->data[posPos][1] - header->v[0]->data[posPos][1];
    double a = atan2(dy, dx);
    float c_a = (float) cos(a), s_a = (float) sin(a);
    uint i;
@@ -541,35 +553,35 @@ aaline_line(struct draw_stage *stage, struct prim_header *header)
     */
 
    /* new verts */
-   pos = v[0]->data[0];
+   pos = v[0]->data[posPos];
    pos[0] += (-dx * c_a -  dy * s_a);
    pos[1] += (-dx * s_a +  dy * c_a);
 
-   pos = v[1]->data[0];
+   pos = v[1]->data[posPos];
    pos[0] += (-dx * c_a - -dy * s_a);
    pos[1] += (-dx * s_a + -dy * c_a);
 
-   pos = v[2]->data[0];
+   pos = v[2]->data[posPos];
    pos[0] += ( dx * c_a -  dy * s_a);
    pos[1] += ( dx * s_a +  dy * c_a);
 
-   pos = v[3]->data[0];
+   pos = v[3]->data[posPos];
    pos[0] += ( dx * c_a - -dy * s_a);
    pos[1] += ( dx * s_a + -dy * c_a);
 
-   pos = v[4]->data[0];
+   pos = v[4]->data[posPos];
    pos[0] += (-dx * c_a -  dy * s_a);
    pos[1] += (-dx * s_a +  dy * c_a);
 
-   pos = v[5]->data[0];
+   pos = v[5]->data[posPos];
    pos[0] += (-dx * c_a - -dy * s_a);
    pos[1] += (-dx * s_a + -dy * c_a);
 
-   pos = v[6]->data[0];
+   pos = v[6]->data[posPos];
    pos[0] += ( dx * c_a -  dy * s_a);
    pos[1] += ( dx * s_a +  dy * c_a);
 
-   pos = v[7]->data[0];
+   pos = v[7]->data[posPos];
    pos[0] += ( dx * c_a - -dy * s_a);
    pos[1] += ( dx * s_a + -dy * c_a);
 
@@ -637,11 +649,15 @@ aaline_first_line(struct draw_stage *stage, struct prim_header *header)
    /*
     * Bind (generate) our fragprog, sampler and texture
     */
-   bind_aaline_fragment_shader(aaline);
+   if (!bind_aaline_fragment_shader(aaline)) {
+      stage->line = draw_pipe_passthrough_line;
+      stage->line(stage, header);
+      return;
+   }
 
    /* update vertex attrib info */
-   aaline->tex_slot = draw->num_vs_outputs;
-   assert(aaline->tex_slot > 0); /* output[0] is vertex pos */
+   aaline->tex_slot = draw->vs.num_vs_outputs;
+   aaline->pos_slot = draw->vs.position_output;
 
    /* advertise the extra post-transformed vertex attribute */
    draw->extra_vp_outputs.semantic_name = TGSI_SEMANTIC_GENERIC;
@@ -657,8 +673,10 @@ aaline_first_line(struct draw_stage *stage, struct prim_header *header)
    pipe_texture_reference(&aaline->state.texture[aaline->fs->sampler_unit],
                           aaline->texture);
 
+   draw->suspend_flushing = TRUE;
    aaline->driver_bind_sampler_states(pipe, num_samplers, aaline->state.sampler);
    aaline->driver_set_sampler_textures(pipe, num_samplers, aaline->state.texture);
+   draw->suspend_flushing = FALSE;
 
    /* now really draw first line */
    stage->line = aaline_line;
@@ -676,14 +694,14 @@ aaline_flush(struct draw_stage *stage, unsigned flags)
    stage->line = aaline_first_line;
    stage->next->flush( stage->next, flags );
 
-   /* restore original frag shader */
+   /* restore original frag shader, texture, sampler state */
+   draw->suspend_flushing = TRUE;
    aaline->driver_bind_fs_state(pipe, aaline->fs->driver_fs);
-
-   /* XXX restore original texture, sampler state */
    aaline->driver_bind_sampler_states(pipe, aaline->num_samplers,
                                       aaline->state.sampler);
    aaline->driver_set_sampler_textures(pipe, aaline->num_textures,
                                        aaline->state.texture);
+   draw->suspend_flushing = FALSE;
 
    draw->extra_vp_outputs.slot = 0;
 }
@@ -700,10 +718,17 @@ static void
 aaline_destroy(struct draw_stage *stage)
 {
    struct aaline_stage *aaline = aaline_stage(stage);
+   uint i;
+
+   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
+      pipe_texture_reference(&aaline->state.texture[i], NULL);
+   }
 
-   aaline->pipe->delete_sampler_state(aaline->pipe, aaline->sampler_cso);
+   if (aaline->sampler_cso)
+      aaline->pipe->delete_sampler_state(aaline->pipe, aaline->sampler_cso);
 
-   pipe_texture_release(&aaline->texture);
+   if (aaline->texture)
+      pipe_texture_release(&aaline->texture);
 
    draw_free_temp_verts( stage );
 
@@ -715,19 +740,28 @@ static struct aaline_stage *
 draw_aaline_stage(struct draw_context *draw)
 {
    struct aaline_stage *aaline = CALLOC_STRUCT(aaline_stage);
+   if (aaline == NULL)
+      return NULL;
 
-   draw_alloc_temp_verts( &aaline->stage, 8 );
+   if (!draw_alloc_temp_verts( &aaline->stage, 8 ))
+      goto fail;
 
    aaline->stage.draw = draw;
    aaline->stage.next = NULL;
-   aaline->stage.point = passthrough_point;
+   aaline->stage.point = draw_pipe_passthrough_point;
    aaline->stage.line = aaline_first_line;
-   aaline->stage.tri = passthrough_tri;
+   aaline->stage.tri = draw_pipe_passthrough_tri;
    aaline->stage.flush = aaline_flush;
    aaline->stage.reset_stipple_counter = aaline_reset_stipple_counter;
    aaline->stage.destroy = aaline_destroy;
 
    return aaline;
+
+ fail:
+   if (aaline)
+      aaline_destroy(&aaline->stage);
+
+   return NULL;
 }
 
 
@@ -749,13 +783,13 @@ aaline_create_fs_state(struct pipe_context *pipe,
 {
    struct aaline_stage *aaline = aaline_stage_from_pipe(pipe);
    struct aaline_fragment_shader *aafs = CALLOC_STRUCT(aaline_fragment_shader);
+   if (aafs == NULL)
+      return NULL;
 
-   if (aafs) {
-      aafs->state = *fs;
+   aafs->state = *fs;
 
-      /* pass-through */
-      aafs->driver_fs = aaline->driver_create_fs_state(aaline->pipe, fs);
-   }
+   /* pass-through */
+   aafs->driver_fs = aaline->driver_create_fs_state(aaline->pipe, fs);
 
    return aafs;
 }
@@ -766,6 +800,7 @@ aaline_bind_fs_state(struct pipe_context *pipe, void *fs)
 {
    struct aaline_stage *aaline = aaline_stage_from_pipe(pipe);
    struct aaline_fragment_shader *aafs = (struct aaline_fragment_shader *) fs;
+
    /* save current */
    aaline->fs = aafs;
    /* pass-through */
@@ -790,9 +825,11 @@ aaline_bind_sampler_states(struct pipe_context *pipe,
                            unsigned num, void **sampler)
 {
    struct aaline_stage *aaline = aaline_stage_from_pipe(pipe);
+
    /* save current */
    memcpy(aaline->state.sampler, sampler, num * sizeof(void *));
    aaline->num_samplers = num;
+
    /* pass-through */
    aaline->driver_bind_sampler_states(aaline->pipe, num, sampler);
 }
@@ -809,6 +846,9 @@ aaline_set_sampler_textures(struct pipe_context *pipe,
    for (i = 0; i < num; i++) {
       pipe_texture_reference(&aaline->state.texture[i], texture[i]);
    }
+   for ( ; i < PIPE_MAX_SAMPLERS; i++) {
+      pipe_texture_reference(&aaline->state.texture[i], NULL);
+   }
    aaline->num_textures = num;
 
    /* pass-through */
@@ -821,7 +861,7 @@ aaline_set_sampler_textures(struct pipe_context *pipe,
  * into the draw module's pipeline.  This will not be used if the
  * hardware has native support for AA lines.
  */
-void
+boolean
 draw_install_aaline_stage(struct draw_context *draw, struct pipe_context *pipe)
 {
    struct aaline_stage *aaline;
@@ -832,14 +872,17 @@ draw_install_aaline_stage(struct draw_context *draw, struct pipe_context *pipe)
     * Create / install AA line drawing / prim stage
     */
    aaline = draw_aaline_stage( draw );
-   assert(aaline);
-   draw->pipeline.aaline = &aaline->stage;
+   if (!aaline)
+      goto fail;
 
    aaline->pipe = pipe;
 
    /* create special texture, sampler state */
-   aaline_create_texture(aaline);
-   aaline_create_sampler(aaline);
+   if (!aaline_create_texture(aaline))
+      goto fail;
+
+   if (!aaline_create_sampler(aaline))
+      goto fail;
 
    /* save original driver functions */
    aaline->driver_create_fs_state = pipe->create_fs_state;
@@ -856,4 +899,16 @@ draw_install_aaline_stage(struct draw_context *draw, struct pipe_context *pipe)
 
    pipe->bind_sampler_states = aaline_bind_sampler_states;
    pipe->set_sampler_textures = aaline_set_sampler_textures;
+   
+   /* Install once everything is known to be OK:
+    */
+   draw->pipeline.aaline = &aaline->stage;
+
+   return TRUE;
+
+ fail:
+   if (aaline)
+      aaline->stage.destroy( &aaline->stage );
+   
+   return FALSE;
 }