Merge remote branch 'origin/master' into pipe-video
[mesa.git] / src / gallium / drivers / r600 / r600_state.c
index bf4ca057d287f5cd7ec32fea1491ca78e607fbb6..8b001e11f4af96f4878fc40641c40a0d92c7b571 100644 (file)
@@ -36,7 +36,6 @@
 #include <util/u_pack_color.h>
 #include <util/u_memory.h>
 #include <util/u_inlines.h>
-#include <util/u_upload_mgr.h>
 #include <util/u_framebuffer.h>
 #include <pipebuffer/pb_buffer.h>
 #include "r600.h"
 #include "r600_pipe.h"
 #include "r600_state_inlines.h"
 
+void r600_polygon_offset_update(struct r600_pipe_context *rctx)
+{
+       struct r600_pipe_state state;
+
+       state.id = R600_PIPE_STATE_POLYGON_OFFSET;
+       state.nregs = 0;
+       if (rctx->rasterizer && rctx->framebuffer.zsbuf) {
+               float offset_units = rctx->rasterizer->offset_units;
+               unsigned offset_db_fmt_cntl = 0, depth;
+
+               switch (rctx->framebuffer.zsbuf->texture->format) {
+               case PIPE_FORMAT_Z24X8_UNORM:
+               case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
+                       depth = -24;
+                       offset_units *= 2.0f;
+                       break;
+               case PIPE_FORMAT_Z32_FLOAT:
+                       depth = -23;
+                       offset_units *= 1.0f;
+                       offset_db_fmt_cntl |= S_028DF8_POLY_OFFSET_DB_IS_FLOAT_FMT(1);
+                       break;
+               case PIPE_FORMAT_Z16_UNORM:
+                       depth = -16;
+                       offset_units *= 4.0f;
+                       break;
+               default:
+                       return;
+               }
+               /* FIXME some of those reg can be computed with cso */
+               offset_db_fmt_cntl |= S_028DF8_POLY_OFFSET_NEG_NUM_DB_BITS(depth);
+               r600_pipe_state_add_reg(&state,
+                               R_028E00_PA_SU_POLY_OFFSET_FRONT_SCALE,
+                               fui(rctx->rasterizer->offset_scale), 0xFFFFFFFF, NULL);
+               r600_pipe_state_add_reg(&state,
+                               R_028E04_PA_SU_POLY_OFFSET_FRONT_OFFSET,
+                               fui(offset_units), 0xFFFFFFFF, NULL);
+               r600_pipe_state_add_reg(&state,
+                               R_028E08_PA_SU_POLY_OFFSET_BACK_SCALE,
+                               fui(rctx->rasterizer->offset_scale), 0xFFFFFFFF, NULL);
+               r600_pipe_state_add_reg(&state,
+                               R_028E0C_PA_SU_POLY_OFFSET_BACK_OFFSET,
+                               fui(offset_units), 0xFFFFFFFF, NULL);
+               r600_pipe_state_add_reg(&state,
+                               R_028DF8_PA_SU_POLY_OFFSET_DB_FMT_CNTL,
+                               offset_db_fmt_cntl, 0xFFFFFFFF, NULL);
+               r600_context_pipe_state_set(&rctx->ctx, &state);
+       }
+}
+
+/* FIXME optimize away spi update when it's not needed */
+static void r600_spi_update(struct r600_pipe_context *rctx)
+{
+       struct r600_pipe_shader *shader = rctx->ps_shader;
+       struct r600_pipe_state rstate;
+       struct r600_shader *rshader = &shader->shader;
+       unsigned i, tmp;
+
+       rstate.nregs = 0;
+       for (i = 0; i < rshader->ninput; i++) {
+               tmp = S_028644_SEMANTIC(r600_find_vs_semantic_index(&rctx->vs_shader->shader, rshader, i));
+               if (rshader->input[i].centroid)
+                       tmp |= S_028644_SEL_CENTROID(1);
+               if (rshader->input[i].interpolate == TGSI_INTERPOLATE_LINEAR)
+                       tmp |= S_028644_SEL_LINEAR(1);
+
+               if (rshader->input[i].name == TGSI_SEMANTIC_COLOR ||
+                   rshader->input[i].name == TGSI_SEMANTIC_BCOLOR ||
+                   rshader->input[i].name == TGSI_SEMANTIC_POSITION) {
+                       tmp |= S_028644_FLAT_SHADE(rctx->flatshade);
+               }
+               if (rshader->input[i].name == TGSI_SEMANTIC_GENERIC &&
+                       rctx->sprite_coord_enable & (1 << rshader->input[i].sid)) {
+                       tmp |= S_028644_PT_SPRITE_TEX(1);
+               }
+               r600_pipe_state_add_reg(&rstate, R_028644_SPI_PS_INPUT_CNTL_0 + i * 4, tmp, 0xFFFFFFFF, NULL);
+       }
+       r600_context_pipe_state_set(&rctx->ctx, &rstate);
+}
+
+void r600_vertex_buffer_update(struct r600_pipe_context *rctx)
+{
+       struct r600_pipe_state *rstate;
+       struct r600_resource *rbuffer;
+       struct pipe_vertex_buffer *vertex_buffer;
+       unsigned i, offset;
+
+       /* we don't update until we know vertex elements */
+       if (rctx->vertex_elements == NULL || !rctx->nvertex_buffer)
+               return;
+
+       if (rctx->vertex_elements->incompatible_layout) {
+               /* translate rebind new vertex elements so
+                * return once translated
+                */
+               r600_begin_vertex_translate(rctx);
+               return;
+       }
+
+       if (rctx->any_user_vbs) {
+               r600_upload_user_buffers(rctx);
+               rctx->any_user_vbs = FALSE;
+       }
+
+       if (rctx->vertex_elements->vbuffer_need_offset) {
+               /* one resource per vertex elements */
+               rctx->nvs_resource = rctx->vertex_elements->count;
+       } else {
+               /* bind vertex buffer once */
+               rctx->nvs_resource = rctx->nvertex_buffer;
+       }
+
+       for (i = 0 ; i < rctx->nvs_resource; i++) {
+               rstate = &rctx->vs_resource[i];
+               rstate->id = R600_PIPE_STATE_RESOURCE;
+               rstate->nregs = 0;
+
+               if (rctx->vertex_elements->vbuffer_need_offset) {
+                       /* one resource per vertex elements */
+                       unsigned vbuffer_index;
+                       vbuffer_index = rctx->vertex_elements->elements[i].vertex_buffer_index;
+                       vertex_buffer = &rctx->vertex_buffer[vbuffer_index];
+                       rbuffer = (struct r600_resource*)vertex_buffer->buffer;
+                       offset = rctx->vertex_elements->vbuffer_offset[i];
+               } else {
+                       /* bind vertex buffer once */
+                       vertex_buffer = &rctx->vertex_buffer[i];
+                       rbuffer = (struct r600_resource*)vertex_buffer->buffer;
+                       offset = 0;
+               }
+               if (vertex_buffer == NULL || rbuffer == NULL)
+                       continue;
+               offset += vertex_buffer->buffer_offset + r600_bo_offset(rbuffer->bo);
+
+               r600_pipe_state_add_reg(rstate, R_038000_RESOURCE0_WORD0,
+                                       offset, 0xFFFFFFFF, rbuffer->bo);
+               r600_pipe_state_add_reg(rstate, R_038004_RESOURCE0_WORD1,
+                                       rbuffer->bo_size - offset - 1, 0xFFFFFFFF, NULL);
+               r600_pipe_state_add_reg(rstate, R_038008_RESOURCE0_WORD2,
+                                       S_038008_STRIDE(vertex_buffer->stride),
+                                       0xFFFFFFFF, NULL);
+               r600_pipe_state_add_reg(rstate, R_03800C_RESOURCE0_WORD3,
+                                       0x00000000, 0xFFFFFFFF, NULL);
+               r600_pipe_state_add_reg(rstate, R_038010_RESOURCE0_WORD4,
+                                       0x00000000, 0xFFFFFFFF, NULL);
+               r600_pipe_state_add_reg(rstate, R_038014_RESOURCE0_WORD5,
+                                       0x00000000, 0xFFFFFFFF, NULL);
+               r600_pipe_state_add_reg(rstate, R_038018_RESOURCE0_WORD6,
+                                       0xC0000000, 0xFFFFFFFF, NULL);
+               r600_context_pipe_state_set_fs_resource(&rctx->ctx, rstate, i);
+       }
+}
+
 static void r600_draw_common(struct r600_drawl *draw)
 {
        struct r600_pipe_context *rctx = (struct r600_pipe_context *)draw->ctx;
-       struct r600_pipe_state *rstate;
        struct r600_resource *rbuffer;
-       unsigned i, j, offset, prim;
+       unsigned prim;
        u32 vgt_dma_index_type, vgt_draw_initiator, mask;
-       struct pipe_vertex_buffer *vertex_buffer;
        struct r600_draw rdraw;
        struct r600_pipe_state vgt;
 
@@ -76,42 +225,23 @@ static void r600_draw_common(struct r600_drawl *draw)
        }
        if (r600_conv_pipe_prim(draw->mode, &prim))
                return;
-
-
-       /* rebuild vertex shader if input format changed */
-       if (r600_pipe_shader_update(&rctx->context, rctx->vs_shader))
+       if (unlikely(rctx->ps_shader == NULL)) {
+               R600_ERR("missing vertex shader\n");
                return;
-       if (r600_pipe_shader_update(&rctx->context, rctx->ps_shader))
+       }
+       if (unlikely(rctx->vs_shader == NULL)) {
+               R600_ERR("missing vertex shader\n");
+               return;
+       }
+       /* there should be enough input */
+       if (rctx->vertex_elements->count < rctx->vs_shader->shader.bc.nresource) {
+               R600_ERR("%d resources provided, expecting %d\n",
+                       rctx->vertex_elements->count, rctx->vs_shader->shader.bc.nresource);
                return;
-
-       for (i = 0 ; i < rctx->vertex_elements->count; i++) {
-               uint32_t word2, format;
-
-               rstate = &rctx->vs_resource[i];
-               rstate->id = R600_PIPE_STATE_RESOURCE;
-               rstate->nregs = 0;
-
-               j = rctx->vertex_elements->elements[i].vertex_buffer_index;
-               vertex_buffer = &rctx->vertex_buffer[j];
-               rbuffer = (struct r600_resource*)vertex_buffer->buffer;
-               offset = rctx->vertex_elements->elements[i].src_offset +
-                       vertex_buffer->buffer_offset +
-                       r600_bo_offset(rbuffer->bo);
-
-               format = r600_translate_vertex_data_type(rctx->vertex_elements->hw_format[i]);
-
-               word2 = format | S_038008_STRIDE(vertex_buffer->stride);
-
-               r600_pipe_state_add_reg(rstate, R_038000_RESOURCE0_WORD0, offset, 0xFFFFFFFF, rbuffer->bo);
-               r600_pipe_state_add_reg(rstate, R_038004_RESOURCE0_WORD1, rbuffer->size - offset - 1, 0xFFFFFFFF, NULL);
-               r600_pipe_state_add_reg(rstate, R_038008_RESOURCE0_WORD2, word2, 0xFFFFFFFF, NULL);
-               r600_pipe_state_add_reg(rstate, R_03800C_RESOURCE0_WORD3, 0x00000000, 0xFFFFFFFF, NULL);
-               r600_pipe_state_add_reg(rstate, R_038010_RESOURCE0_WORD4, 0x00000000, 0xFFFFFFFF, NULL);
-               r600_pipe_state_add_reg(rstate, R_038014_RESOURCE0_WORD5, 0x00000000, 0xFFFFFFFF, NULL);
-               r600_pipe_state_add_reg(rstate, R_038018_RESOURCE0_WORD6, 0xC0000000, 0xFFFFFFFF, NULL);
-               r600_context_pipe_state_set_fs_resource(&rctx->ctx, rstate, i);
        }
 
+       r600_spi_update(rctx);
+
        mask = 0;
        for (int i = 0; i < rctx->framebuffer.nr_cbufs; i++) {
                mask |= (0xF << (i * 4));
@@ -126,46 +256,6 @@ static void r600_draw_common(struct r600_drawl *draw)
        r600_pipe_state_add_reg(&vgt, R_028238_CB_TARGET_MASK, rctx->cb_target_mask & mask, 0xFFFFFFFF, NULL);
        r600_pipe_state_add_reg(&vgt, R_03CFF0_SQ_VTX_BASE_VTX_LOC, 0, 0xFFFFFFFF, NULL);
        r600_pipe_state_add_reg(&vgt, R_03CFF4_SQ_VTX_START_INST_LOC, 0, 0xFFFFFFFF, NULL);
-       /* build late state */
-       if (rctx->rasterizer && rctx->framebuffer.zsbuf) {
-               float offset_units = rctx->rasterizer->offset_units;
-               unsigned offset_db_fmt_cntl = 0, depth;
-
-               switch (rctx->framebuffer.zsbuf->texture->format) {
-               case PIPE_FORMAT_Z24X8_UNORM:
-               case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
-                       depth = -24;
-                       offset_units *= 2.0f;
-                       break;
-               case PIPE_FORMAT_Z32_FLOAT:
-                       depth = -23;
-                       offset_units *= 1.0f;
-                       offset_db_fmt_cntl |= S_028DF8_POLY_OFFSET_DB_IS_FLOAT_FMT(1);
-                       break;
-               case PIPE_FORMAT_Z16_UNORM:
-                       depth = -16;
-                       offset_units *= 4.0f;
-                       break;
-               default:
-                       return;
-               }
-               offset_db_fmt_cntl |= S_028DF8_POLY_OFFSET_NEG_NUM_DB_BITS(depth);
-               r600_pipe_state_add_reg(&vgt,
-                               R_028E00_PA_SU_POLY_OFFSET_FRONT_SCALE,
-                               fui(rctx->rasterizer->offset_scale), 0xFFFFFFFF, NULL);
-               r600_pipe_state_add_reg(&vgt,
-                               R_028E04_PA_SU_POLY_OFFSET_FRONT_OFFSET,
-                               fui(offset_units), 0xFFFFFFFF, NULL);
-               r600_pipe_state_add_reg(&vgt,
-                               R_028E08_PA_SU_POLY_OFFSET_BACK_SCALE,
-                               fui(rctx->rasterizer->offset_scale), 0xFFFFFFFF, NULL);
-               r600_pipe_state_add_reg(&vgt,
-                               R_028E0C_PA_SU_POLY_OFFSET_BACK_OFFSET,
-                               fui(offset_units), 0xFFFFFFFF, NULL);
-               r600_pipe_state_add_reg(&vgt,
-                               R_028DF8_PA_SU_POLY_OFFSET_DB_FMT_CNTL,
-                               offset_db_fmt_cntl, 0xFFFFFFFF, NULL);
-       }
        r600_context_pipe_state_set(&rctx->ctx, &vgt);
 
        rdraw.vgt_num_indices = draw->count;
@@ -185,17 +275,7 @@ void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
 {
        struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx;
        struct r600_drawl draw;
-       boolean translate = FALSE;
 
-       if (rctx->vertex_elements->incompatible_layout) {
-               r600_begin_vertex_translate(rctx);
-               translate = TRUE;
-       }
-
-       if (rctx->any_user_vbs) {
-               r600_upload_user_buffers(rctx);
-               rctx->any_user_vbs = FALSE;
-       }
        memset(&draw, 0, sizeof(struct r600_drawl));
        draw.ctx = ctx;
        draw.mode = info->mode;
@@ -226,9 +306,6 @@ void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
        }
        r600_draw_common(&draw);
 
-       if (translate)
-               r600_end_vertex_translate(rctx);
-
        pipe_resource_reference(&draw.index_buffer, NULL);
 }
 
@@ -603,9 +680,9 @@ static struct pipe_sampler_view *r600_create_sampler_view(struct pipe_context *c
                                word4 | S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_NORM) |
                                S_038010_SRF_MODE_ALL(V_038010_SFR_MODE_NO_ZERO) |
                                S_038010_REQUEST_SIZE(1) |
-                               S_038010_BASE_LEVEL(state->first_level), 0xFFFFFFFF, NULL);
+                               S_038010_BASE_LEVEL(state->u.tex.first_level), 0xFFFFFFFF, NULL);
        r600_pipe_state_add_reg(rstate, R_038014_RESOURCE0_WORD5,
-                               S_038014_LAST_LEVEL(state->last_level) |
+                               S_038014_LAST_LEVEL(state->u.tex.last_level) |
                                S_038014_BASE_ARRAY(0) |
                                S_038014_LAST_ARRAY(0), 0xFFFFFFFF, NULL);
        r600_pipe_state_add_reg(rstate, R_038018_RESOURCE0_WORD6,
@@ -824,10 +901,11 @@ static void r600_cb(struct r600_pipe_context *rctx, struct r600_pipe_state *rsta
        struct r600_resource_texture *rtex;
        struct r600_resource *rbuffer;
        struct r600_surface *surf;
-       unsigned level = state->cbufs[cb]->level;
+       unsigned level = state->cbufs[cb]->u.tex.level;
        unsigned pitch, slice;
        unsigned color_info;
        unsigned format, swap, ntype;
+       unsigned offset;
        const struct util_format_description *desc;
        struct r600_bo *bo[3];
 
@@ -838,12 +916,26 @@ static void r600_cb(struct r600_pipe_context *rctx, struct r600_pipe_state *rsta
        bo[1] = rbuffer->bo;
        bo[2] = rbuffer->bo;
 
+       /* XXX quite sure for dx10+ hw don't need any offset hacks */
+       offset = r600_texture_get_offset((struct r600_resource_texture *)state->cbufs[cb]->texture,
+                                        level, state->cbufs[cb]->u.tex.first_layer);
        pitch = rtex->pitch_in_pixels[level] / 8 - 1;
        slice = rtex->pitch_in_pixels[level] * surf->aligned_height / 64 - 1;
        ntype = 0;
        desc = util_format_description(rtex->resource.base.b.format);
        if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB)
                ntype = V_0280A0_NUMBER_SRGB;
+        else if (desc->layout == UTIL_FORMAT_LAYOUT_PLAIN) {
+               switch(desc->channel[0].type) {
+               case UTIL_FORMAT_TYPE_UNSIGNED:
+                       ntype = V_0280A0_NUMBER_UNORM;
+                       break;
+
+               case UTIL_FORMAT_TYPE_SIGNED:
+                       ntype = V_0280A0_NUMBER_SNORM;
+                       break;
+               }
+       }
 
        format = r600_translate_colorformat(rtex->resource.base.b.format);
        swap = r600_translate_colorswap(rtex->resource.base.b.format);
@@ -857,7 +949,7 @@ static void r600_cb(struct r600_pipe_context *rctx, struct r600_pipe_state *rsta
 
        r600_pipe_state_add_reg(rstate,
                                R_028040_CB_COLOR0_BASE + cb * 4,
-                               (state->cbufs[cb]->offset + r600_bo_offset(bo[0])) >> 8, 0xFFFFFFFF, bo[0]);
+                               (offset + r600_bo_offset(bo[0])) >> 8, 0xFFFFFFFF, bo[0]);
        r600_pipe_state_add_reg(rstate,
                                R_0280A0_CB_COLOR0_INFO + cb * 4,
                                color_info, 0xFFFFFFFF, bo[0]);
@@ -888,11 +980,12 @@ static void r600_db(struct r600_pipe_context *rctx, struct r600_pipe_state *rsta
        struct r600_surface *surf;
        unsigned level;
        unsigned pitch, slice, format;
+       unsigned offset;
 
        if (state->zsbuf == NULL)
                return;
 
-       level = state->zsbuf->level;
+       level = state->zsbuf->u.tex.level;
 
        surf = (struct r600_surface *)state->zsbuf;
        rtex = (struct r600_resource_texture*)state->zsbuf->texture;
@@ -902,12 +995,15 @@ static void r600_db(struct r600_pipe_context *rctx, struct r600_pipe_state *rsta
        rtex->depth = 1;
        rbuffer = &rtex->resource;
 
+       /* XXX quite sure for dx10+ hw don't need any offset hacks */
+       offset = r600_texture_get_offset((struct r600_resource_texture *)state->zsbuf->texture,
+                                        level, state->zsbuf->u.tex.first_layer);
        pitch = rtex->pitch_in_pixels[level] / 8 - 1;
        slice = rtex->pitch_in_pixels[level] * surf->aligned_height / 64 - 1;
        format = r600_translate_dbformat(state->zsbuf->texture->format);
 
        r600_pipe_state_add_reg(rstate, R_02800C_DB_DEPTH_BASE,
-                               (state->zsbuf->offset + r600_bo_offset(rbuffer->bo)) >> 8, 0xFFFFFFFF, rbuffer->bo);
+                               (offset + r600_bo_offset(rbuffer->bo)) >> 8, 0xFFFFFFFF, rbuffer->bo);
        r600_pipe_state_add_reg(rstate, R_028000_DB_DEPTH_SIZE,
                                S_028000_PITCH_TILE_MAX(pitch) | S_028000_SLICE_TILE_MAX(slice),
                                0xFFFFFFFF, NULL);
@@ -934,8 +1030,6 @@ static void r600_set_framebuffer_state(struct pipe_context *ctx,
 
        util_copy_framebuffer_state(&rctx->framebuffer, state);
 
-       rctx->pframebuffer = &rctx->framebuffer;
-
        /* build states */
        for (int i = 0; i < state->nr_cbufs; i++) {
                r600_cb(rctx, rstate, state, i);
@@ -1015,6 +1109,10 @@ static void r600_set_framebuffer_state(struct pipe_context *ctx,
        free(rctx->states[R600_PIPE_STATE_FRAMEBUFFER]);
        rctx->states[R600_PIPE_STATE_FRAMEBUFFER] = rstate;
        r600_context_pipe_state_set(&rctx->ctx, rstate);
+
+       if (state->zsbuf) {
+               r600_polygon_offset_update(rctx);
+       }
 }
 
 static void r600_set_constant_buffer(struct pipe_context *ctx, uint shader, uint index,