Merge remote branch 'origin/7.8'
[mesa.git] / src / gallium / drivers / r300 / r300_state.c
index aacaa4e6afe45b66d56db69893d0fb5214527fe1..9eb8539a655220c7bff4f09d8557e000e588f8c4 100644 (file)
@@ -36,6 +36,7 @@
 #include "r300_reg.h"
 #include "r300_screen.h"
 #include "r300_screen_buffer.h"
+#include "r300_state.h"
 #include "r300_state_inlines.h"
 #include "r300_fs.h"
 #include "r300_texture.h"
@@ -683,22 +684,23 @@ static void* r300_create_fs_state(struct pipe_context* pipe,
     return (void*)fs;
 }
 
-static void r300_mark_fs_code_dirty(struct r300_context *r300)
+void r300_mark_fs_code_dirty(struct r300_context *r300)
 {
     struct r300_fragment_shader* fs = r300_fs(r300);
 
     r300->fs.dirty = TRUE;
     r300->fs_rc_constant_state.dirty = TRUE;
+    r300->fs_constants.dirty = TRUE;
 
     if (r300->screen->caps.is_r500) {
         r300->fs.size = r500_get_fs_atom_size(r300);
         r300->fs_rc_constant_state.size = fs->shader->rc_state_count * 7;
+        r300->fs_constants.size = fs->shader->externals_count * 4 + 3;
     } else {
         r300->fs.size = r300_get_fs_atom_size(r300);
         r300->fs_rc_constant_state.size = fs->shader->rc_state_count * 5;
+        r300->fs_constants.size = fs->shader->externals_count * 4 + 1;
     }
-
-    r300->dirty_state |= R300_NEW_FRAGMENT_SHADER_CONSTANTS;
 }
 
 /* Bind fragment shader state. */
@@ -756,6 +758,7 @@ static void* r300_create_rs_state(struct pipe_context* pipe,
                                   const struct pipe_rasterizer_state* state)
 {
     struct r300_rs_state* rs = CALLOC_STRUCT(r300_rs_state);
+    int i;
 
     /* Copy rasterizer state for Draw. */
     rs->rs = *state;
@@ -850,6 +853,30 @@ static void* r300_create_rs_state(struct pipe_context* pipe,
 
     rs->clip_rule = state->scissor ? 0xAAAA : 0xFFFF;
 
+    /* Point sprites */
+    if (state->sprite_coord_enable) {
+        rs->stuffing_enable = R300_GB_POINT_STUFF_ENABLE;
+       for (i = 0; i < 8; i++) {
+           if (state->sprite_coord_enable & (1 << i))
+               rs->stuffing_enable |=
+                   R300_GB_TEX_STR << (R300_GB_TEX0_SOURCE_SHIFT + (i*2));
+       }
+
+        rs->point_texcoord_left = 0.0f;
+        rs->point_texcoord_right = 1.0f;
+
+        switch (state->sprite_coord_mode) {
+            case PIPE_SPRITE_COORD_UPPER_LEFT:
+                rs->point_texcoord_top = 0.0f;
+                rs->point_texcoord_bottom = 1.0f;
+                break;
+            case PIPE_SPRITE_COORD_LOWER_LEFT:
+                rs->point_texcoord_top = 1.0f;
+                rs->point_texcoord_bottom = 0.0f;
+                break;
+        }
+    }
+
     return (void*)rs;
 }
 
@@ -858,20 +885,27 @@ static void r300_bind_rs_state(struct pipe_context* pipe, void* state)
 {
     struct r300_context* r300 = r300_context(pipe);
     struct r300_rs_state* rs = (struct r300_rs_state*)state;
+    int last_sprite_coord_enable = r300->sprite_coord_enable;
 
     if (r300->draw) {
         draw_flush(r300->draw);
-        draw_set_rasterizer_state(r300->draw, &rs->rs);
+        draw_set_rasterizer_state(r300->draw, &rs->rs, state);
     }
 
     if (rs) {
         r300->polygon_offset_enabled = rs->rs.offset_cw || rs->rs.offset_ccw;
+        r300->sprite_coord_enable = rs->rs.sprite_coord_enable;
     } else {
         r300->polygon_offset_enabled = FALSE;
+        r300->sprite_coord_enable = 0;
     }
 
     UPDATE_STATE(state, r300->rs_state);
-    r300->rs_state.size = 19 + (r300->polygon_offset_enabled ? 5 : 0);
+    r300->rs_state.size = 26 + (r300->polygon_offset_enabled ? 5 : 0);
+
+    if (last_sprite_coord_enable != r300->sprite_coord_enable) {
+        r300->rs_block_state.dirty = TRUE;
+    }
 }
 
 /* Free rasterizer state. */
@@ -949,13 +983,6 @@ static void r300_bind_sampler_states(struct pipe_context* pipe,
     state->sampler_state_count = count;
 
     r300->textures_state.dirty = TRUE;
-
-    /* Pick a fragment shader based on the texture compare state. */
-    if (r300->fs.state && count) {
-        if (r300_pick_fragment_shader(r300)) {
-            r300_mark_fs_code_dirty(r300);
-        }
-    }
 }
 
 static void r300_lacks_vertex_textures(struct pipe_context* pipe,
@@ -979,7 +1006,6 @@ static void r300_set_fragment_sampler_views(struct pipe_context* pipe,
     struct r300_texture *texture;
     unsigned i;
     unsigned tex_units = r300->screen->caps.num_tex_units;
-    boolean is_r500 = r300->screen->caps.is_r500;
     boolean dirty_tex = FALSE;
 
     if (count > tex_units) {
@@ -999,9 +1025,10 @@ static void r300_set_fragment_sampler_views(struct pipe_context* pipe,
             /* A new sampler view (= texture)... */
             dirty_tex = TRUE;
 
-            /* R300-specific - set the texrect factor in the fragment shader */
+            /* Set the texrect factor in the fragment shader.
+             * Needed for RECT and NPOT fallback. */
             texture = r300_texture(views[i]->texture);
-            if (!is_r500 && texture->uses_pitch) {
+            if (texture->uses_pitch) {
                 r300->fs_rc_constant_state.dirty = TRUE;
             }
         }
@@ -1165,14 +1192,13 @@ static void r300_set_vertex_buffers(struct pipe_context* pipe,
         }
 
         if (vbo->max_index == ~0) {
-            /* Bogus value from broken state tracker; hax it. */
-           /* TODO - more hax - fixes doom3 from almos on irc */
-           if (!vbo->stride) {
-               fprintf(stderr, "r300: got a VBO with stride 0 fixing up to stide 4\n");
-               vbo->stride = 4;
-           }
-            vbo->max_index =
-                (vbo->buffer->width0 - vbo->buffer_offset) / vbo->stride;
+           /* if no VBO stride then only one vertex value so max index is 1 */
+           /* should think about converting to VS constants like svga does */
+           if (!vbo->stride)
+               vbo->max_index = 1;
+           else
+               vbo->max_index =
+                                (vbo->buffer->width0 - vbo->buffer_offset) / vbo->stride;
         }
 
         max_index = MIN2(vbo->max_index, max_index);
@@ -1346,11 +1372,18 @@ static void r300_bind_vs_state(struct pipe_context* pipe, void* shader)
 
     if (r300->screen->caps.has_tcl) {
         r300->vs_state.dirty = TRUE;
-        r300->vs_state.size = vs->code.length + 9;
+        r300->vs_state.size =
+                vs->code.length + 9 +
+                (vs->immediates_count ? vs->immediates_count * 4 + 3 : 0);
 
-        r300->pvs_flush.dirty = TRUE;
+        if (vs->externals_count) {
+            r300->vs_constants.dirty = TRUE;
+            r300->vs_constants.size = vs->externals_count * 4 + 3;
+        } else {
+            r300->vs_constants.size = 0;
+        }
 
-        r300->dirty_state |= R300_NEW_VERTEX_SHADER_CONSTANTS;
+        r300->pvs_flush.dirty = TRUE;
     } else {
         draw_flush(r300->draw);
         draw_bind_vertex_shader(r300->draw,
@@ -1379,25 +1412,18 @@ static void r300_set_constant_buffer(struct pipe_context *pipe,
                                      struct pipe_resource *buf)
 {
     struct r300_context* r300 = r300_context(pipe);
+    struct r300_constant_buffer *cbuf;
     struct pipe_transfer *tr;
     void *mapped;
     int max_size = 0;
 
-    if (buf == NULL || buf->width0 == 0 ||
-        (mapped = pipe_buffer_map(pipe, buf, PIPE_TRANSFER_READ, &tr)) == NULL)
-    {
-        r300->shader_constants[shader].count = 0;
-        return;
-    }
-
-    assert((buf->width0 % 4 * sizeof(float)) == 0);
-
-    /* Check the size of the constant buffer. */
     switch (shader) {
         case PIPE_SHADER_VERTEX:
+            cbuf = (struct r300_constant_buffer*)r300->vs_constants.state;
             max_size = 256;
             break;
         case PIPE_SHADER_FRAGMENT:
+            cbuf = (struct r300_constant_buffer*)r300->fs_constants.state;
             if (r300->screen->caps.is_r500) {
                 max_size = 256;
             } else {
@@ -1406,8 +1432,19 @@ static void r300_set_constant_buffer(struct pipe_context *pipe,
             break;
         default:
             assert(0);
+            return;
     }
 
+    if (buf == NULL || buf->width0 == 0 ||
+        (mapped = pipe_buffer_map(pipe, buf, PIPE_TRANSFER_READ, &tr)) == NULL)
+    {
+        cbuf->count = 0;
+        return;
+    }
+
+    assert((buf->width0 % 4 * sizeof(float)) == 0);
+
+    /* Check the size of the constant buffer. */
     /* XXX Subtract immediates and RC_STATE_* variables. */
     if (buf->width0 > (sizeof(float) * 4 * max_size)) {
         fprintf(stderr, "r300: Max size of the constant buffer is "
@@ -1415,21 +1452,23 @@ static void r300_set_constant_buffer(struct pipe_context *pipe,
         abort();
     }
 
-    memcpy(r300->shader_constants[shader].constants, mapped, buf->width0);
-    r300->shader_constants[shader].count = buf->width0 / (4 * sizeof(float));
+    memcpy(cbuf->constants, mapped, buf->width0);
+    cbuf->count = buf->width0 / (4 * sizeof(float));
     pipe_buffer_unmap(pipe, buf, tr);
 
     if (shader == PIPE_SHADER_VERTEX) {
         if (r300->screen->caps.has_tcl) {
-            r300->dirty_state |= R300_NEW_VERTEX_SHADER_CONSTANTS;
+            if (r300->vs_constants.size) {
+                r300->vs_constants.dirty = TRUE;
+            }
             r300->pvs_flush.dirty = TRUE;
         } else if (r300->draw) {
             draw_set_mapped_constant_buffer(r300->draw, PIPE_SHADER_VERTEX,
-                0, r300->shader_constants[PIPE_SHADER_VERTEX].constants,
+                0, cbuf->constants,
                 buf->width0);
         }
     } else if (shader == PIPE_SHADER_FRAGMENT) {
-        r300->dirty_state |= R300_NEW_FRAGMENT_SHADER_CONSTANTS;
+        r300->fs_constants.dirty = TRUE;
     }
 }