vc4: Add support for 16-bit signed/unsigned norm/scaled vertex attrs.
[mesa.git] / src / gallium / drivers / r600 / r600_state_common.c
index 207f07ec9c98571f3d5a4ee54e6f503b0b7e756a..09d8952844fa5b9c6351b3ec9fd6ec83b83a1a6d 100644 (file)
@@ -28,7 +28,6 @@
 #include "r600_shader.h"
 #include "r600d.h"
 
-#include "util/u_draw_quad.h"
 #include "util/u_format_s3tc.h"
 #include "util/u_index_modify.h"
 #include "util/u_memory.h"
@@ -36,8 +35,6 @@
 #include "util/u_math.h"
 #include "tgsi/tgsi_parse.h"
 
-#define R600_PRIM_RECTANGLE_LIST PIPE_PRIM_MAX
-
 void r600_init_command_buffer(struct r600_command_buffer *cb, unsigned num_dw)
 {
        assert(!cb->buf);
@@ -161,8 +158,10 @@ static void r600_bind_blend_state(struct pipe_context *ctx, void *state)
        struct r600_context *rctx = (struct r600_context *)ctx;
        struct r600_blend_state *blend = (struct r600_blend_state *)state;
 
-       if (blend == NULL)
+       if (blend == NULL) {
+               r600_set_cso_state_with_cb(&rctx->blend_state, NULL, NULL);
                return;
+       }
 
        r600_bind_blend_state_internal(rctx, blend, rctx->force_blend_disable);
 }
@@ -354,10 +353,14 @@ static void r600_delete_rs_state(struct pipe_context *ctx, void *state)
 static void r600_sampler_view_destroy(struct pipe_context *ctx,
                                      struct pipe_sampler_view *state)
 {
-       struct r600_pipe_sampler_view *resource = (struct r600_pipe_sampler_view *)state;
+       struct r600_pipe_sampler_view *view = (struct r600_pipe_sampler_view *)state;
+
+       if (view->tex_resource->gpu_address &&
+           view->tex_resource->b.b.target == PIPE_BUFFER)
+               LIST_DELINIT(&view->list);
 
        pipe_resource_reference(&state->texture, NULL);
-       FREE(resource);
+       FREE(view);
 }
 
 void r600_sampler_states_dirty(struct r600_context *rctx,
@@ -446,8 +449,13 @@ static void r600_delete_sampler_state(struct pipe_context *ctx, void *state)
 
 static void r600_delete_blend_state(struct pipe_context *ctx, void *state)
 {
+       struct r600_context *rctx = (struct r600_context *)ctx;
        struct r600_blend_state *blend = (struct r600_blend_state*)state;
 
+       if (rctx->blend_state.cso == state) {
+               ctx->bind_blend_state(ctx, NULL);
+       }
+
        r600_release_command_buffer(&blend->buffer);
        r600_release_command_buffer(&blend->buffer_no_blend);
        FREE(blend);
@@ -641,7 +649,6 @@ static void r600_set_sampler_views(struct pipe_context *pipe, unsigned shader,
        dst->views.dirty_mask |= new_mask;
        dst->views.compressed_depthtex_mask &= dst->views.enabled_mask;
        dst->views.compressed_colortex_mask &= dst->views.enabled_mask;
-       dst->views.dirty_txq_constants = TRUE;
        dst->views.dirty_buffer_constants = TRUE;
        r600_sampler_views_dirty(rctx, &dst->views);
 
@@ -976,6 +983,7 @@ static void r600_set_sample_mask(struct pipe_context *pipe, unsigned sample_mask
  * then in the shader, we AND the 4 components with 0xffffffff or 0,
  * then OR the alpha with the value given here.
  * We use a 6th constant to store the txq buffer size in
+ * we use 7th slot for number of cube layers in a cube map array.
  */
 static void r600_setup_buffer_constants(struct r600_context *rctx, int shader_type)
 {
@@ -1014,6 +1022,7 @@ static void r600_setup_buffer_constants(struct r600_context *rctx, int shader_ty
                                samplers->buffer_constants[offset + 4] = 0;
 
                        samplers->buffer_constants[offset + 5] = samplers->views.views[i]->base.texture->width0 / util_format_get_blocksize(samplers->views.views[i]->base.format);
+                       samplers->buffer_constants[offset + 6] = samplers->views.views[i]->base.texture->array_size / 6;
                }
        }
 
@@ -1025,7 +1034,10 @@ static void r600_setup_buffer_constants(struct r600_context *rctx, int shader_ty
        pipe_resource_reference(&cb.buffer, NULL);
 }
 
-/* On evergreen we only need to store the buffer size for TXQ */
+/* On evergreen we store two values
+ * 1. buffer size for TXQ
+ * 2. number of cube layers in a cube map array.
+ */
 static void eg_setup_buffer_constants(struct r600_context *rctx, int shader_type)
 {
        struct r600_textures_info *samplers = &rctx->samplers[shader_type];
@@ -1040,12 +1052,16 @@ static void eg_setup_buffer_constants(struct r600_context *rctx, int shader_type
        samplers->views.dirty_buffer_constants = FALSE;
 
        bits = util_last_bit(samplers->views.enabled_mask);
-       array_size = bits * sizeof(uint32_t) * 4;
+       array_size = bits * 2 * sizeof(uint32_t) * 4;
        samplers->buffer_constants = realloc(samplers->buffer_constants, array_size);
        memset(samplers->buffer_constants, 0, array_size);
-       for (i = 0; i < bits; i++)
-               if (samplers->views.enabled_mask & (1 << i))
-                  samplers->buffer_constants[i] = samplers->views.views[i]->base.texture->width0 / util_format_get_blocksize(samplers->views.views[i]->base.format);
+       for (i = 0; i < bits; i++) {
+               if (samplers->views.enabled_mask & (1 << i)) {
+                       uint32_t offset = i * 2;
+                       samplers->buffer_constants[offset] = samplers->views.views[i]->base.texture->width0 / util_format_get_blocksize(samplers->views.views[i]->base.format);
+                       samplers->buffer_constants[offset + 1] = samplers->views.views[i]->base.texture->array_size / 6;
+               }
+       }
 
        cb.buffer = NULL;
        cb.user_buffer = samplers->buffer_constants;
@@ -1055,33 +1071,27 @@ static void eg_setup_buffer_constants(struct r600_context *rctx, int shader_type
        pipe_resource_reference(&cb.buffer, NULL);
 }
 
-static void r600_setup_txq_cube_array_constants(struct r600_context *rctx, int shader_type)
+/* set sample xy locations as array of fragment shader constants */
+void r600_set_sample_locations_constant_buffer(struct r600_context *rctx)
 {
-       struct r600_textures_info *samplers = &rctx->samplers[shader_type];
-       int bits;
-       uint32_t array_size;
-       struct pipe_constant_buffer cb;
+       struct pipe_constant_buffer constbuf = {0};
+       float values[4*16] = {0.0f};
        int i;
+       struct pipe_context *ctx = &rctx->b.b;
 
-       if (!samplers->views.dirty_txq_constants)
-               return;
-
-       samplers->views.dirty_txq_constants = FALSE;
-
-       bits = util_last_bit(samplers->views.enabled_mask);
-       array_size = bits * sizeof(uint32_t) * 4;
-       samplers->txq_constants = realloc(samplers->txq_constants, array_size);
-       memset(samplers->txq_constants, 0, array_size);
-       for (i = 0; i < bits; i++)
-               if (samplers->views.enabled_mask & (1 << i))
-                       samplers->txq_constants[i] = samplers->views.views[i]->base.texture->array_size / 6;
+       assert(rctx->framebuffer.nr_samples <= Elements(values)/4);
+       for (i = 0; i < rctx->framebuffer.nr_samples; i++) {
+               ctx->get_sample_position(ctx, rctx->framebuffer.nr_samples, i, &values[4*i]);
+               /* Also fill in center-zeroed positions used for interpolateAtSample */
+               values[4*i + 2] = values[4*i + 0] - 0.5f;
+               values[4*i + 3] = values[4*i + 1] - 0.5f;
+       }
 
-       cb.buffer = NULL;
-       cb.user_buffer = samplers->txq_constants;
-       cb.buffer_offset = 0;
-       cb.buffer_size = array_size;
-       rctx->b.b.set_constant_buffer(&rctx->b.b, shader_type, R600_TXQ_CONST_BUFFER, &cb);
-       pipe_resource_reference(&cb.buffer, NULL);
+       constbuf.user_buffer = values;
+       constbuf.buffer_size = rctx->framebuffer.nr_samples * 4 * 4;
+       ctx->set_constant_buffer(ctx, PIPE_SHADER_FRAGMENT,
+               R600_SAMPLE_POSITIONS_CONST_BUFFER, &constbuf);
+       pipe_resource_reference(&constbuf.buffer, NULL);
 }
 
 static void update_shader_atom(struct pipe_context *ctx,
@@ -1144,7 +1154,7 @@ static bool r600_update_derived_state(struct r600_context *rctx)
        struct pipe_context * ctx = (struct pipe_context*)rctx;
        bool ps_dirty = false, vs_dirty = false, gs_dirty = false;
        bool blend_disable;
-
+       bool need_buf_const;
        if (!rctx->blitter->running) {
                unsigned i;
 
@@ -1226,7 +1236,9 @@ static bool r600_update_derived_state(struct r600_context *rctx)
        if (unlikely(!rctx->ps_shader->current))
                return false;
 
-       if (unlikely(ps_dirty || rctx->pixel_shader.shader != rctx->ps_shader->current)) {
+       if (unlikely(ps_dirty || rctx->pixel_shader.shader != rctx->ps_shader->current ||
+               rctx->rasterizer->sprite_coord_enable != rctx->ps_shader->current->sprite_coord_enable ||
+               rctx->rasterizer->flatshade != rctx->ps_shader->current->flatshade)) {
 
                if (rctx->cb_misc_state.nr_ps_color_outputs != rctx->ps_shader->current->nr_ps_color_outputs) {
                        rctx->cb_misc_state.nr_ps_color_outputs = rctx->ps_shader->current->nr_ps_color_outputs;
@@ -1242,12 +1254,6 @@ static bool r600_update_derived_state(struct r600_context *rctx)
                        }
                }
 
-               if (rctx->b.chip_class >= EVERGREEN) {
-                       evergreen_update_db_shader_control(rctx);
-               } else {
-                       r600_update_db_shader_control(rctx);
-               }
-
                if (unlikely(!ps_dirty && rctx->ps_shader && rctx->rasterizer &&
                                ((rctx->rasterizer->sprite_coord_enable != rctx->ps_shader->current->sprite_coord_enable) ||
                                                (rctx->rasterizer->flatshade != rctx->ps_shader->current->flatshade)))) {
@@ -1261,31 +1267,43 @@ static bool r600_update_derived_state(struct r600_context *rctx)
                update_shader_atom(ctx, &rctx->pixel_shader, rctx->ps_shader->current);
        }
 
+       if (rctx->b.chip_class >= EVERGREEN) {
+               evergreen_update_db_shader_control(rctx);
+       } else {
+               r600_update_db_shader_control(rctx);
+       }
+
        /* on R600 we stuff masks + txq info into one constant buffer */
        /* on evergreen we only need a txq info one */
-       if (rctx->b.chip_class < EVERGREEN) {
-               if (rctx->ps_shader && rctx->ps_shader->current->shader.uses_tex_buffers)
-                       r600_setup_buffer_constants(rctx, PIPE_SHADER_FRAGMENT);
-               if (rctx->vs_shader && rctx->vs_shader->current->shader.uses_tex_buffers)
-                       r600_setup_buffer_constants(rctx, PIPE_SHADER_VERTEX);
-               if (rctx->gs_shader && rctx->gs_shader->current->shader.uses_tex_buffers)
-                       r600_setup_buffer_constants(rctx, PIPE_SHADER_GEOMETRY);
-       } else {
-               if (rctx->ps_shader && rctx->ps_shader->current->shader.uses_tex_buffers)
-                       eg_setup_buffer_constants(rctx, PIPE_SHADER_FRAGMENT);
-               if (rctx->vs_shader && rctx->vs_shader->current->shader.uses_tex_buffers)
-                       eg_setup_buffer_constants(rctx, PIPE_SHADER_VERTEX);
-               if (rctx->gs_shader && rctx->gs_shader->current->shader.uses_tex_buffers)
-                       eg_setup_buffer_constants(rctx, PIPE_SHADER_GEOMETRY);
+       if (rctx->ps_shader) {
+               need_buf_const = rctx->ps_shader->current->shader.uses_tex_buffers || rctx->ps_shader->current->shader.has_txq_cube_array_z_comp;
+               if (need_buf_const) {
+                       if (rctx->b.chip_class < EVERGREEN)
+                               r600_setup_buffer_constants(rctx, PIPE_SHADER_FRAGMENT);
+                       else
+                               eg_setup_buffer_constants(rctx, PIPE_SHADER_FRAGMENT);
+               }
        }
 
+       if (rctx->vs_shader) {
+               need_buf_const = rctx->vs_shader->current->shader.uses_tex_buffers || rctx->vs_shader->current->shader.has_txq_cube_array_z_comp;
+               if (need_buf_const) {
+                       if (rctx->b.chip_class < EVERGREEN)
+                               r600_setup_buffer_constants(rctx, PIPE_SHADER_VERTEX);
+                       else
+                               eg_setup_buffer_constants(rctx, PIPE_SHADER_VERTEX);
+               }
+       }
 
-       if (rctx->ps_shader && rctx->ps_shader->current->shader.has_txq_cube_array_z_comp)
-               r600_setup_txq_cube_array_constants(rctx, PIPE_SHADER_FRAGMENT);
-       if (rctx->vs_shader && rctx->vs_shader->current->shader.has_txq_cube_array_z_comp)
-               r600_setup_txq_cube_array_constants(rctx, PIPE_SHADER_VERTEX);
-       if (rctx->gs_shader && rctx->gs_shader->current->shader.has_txq_cube_array_z_comp)
-               r600_setup_txq_cube_array_constants(rctx, PIPE_SHADER_GEOMETRY);
+       if (rctx->gs_shader) {
+               need_buf_const = rctx->gs_shader->current->shader.uses_tex_buffers || rctx->gs_shader->current->shader.has_txq_cube_array_z_comp;
+               if (need_buf_const) {
+                       if (rctx->b.chip_class < EVERGREEN)
+                               r600_setup_buffer_constants(rctx, PIPE_SHADER_GEOMETRY);
+                       else
+                               eg_setup_buffer_constants(rctx, PIPE_SHADER_GEOMETRY);
+               }
+       }
 
        if (rctx->b.chip_class < EVERGREEN && rctx->ps_shader && rctx->vs_shader) {
                if (!r600_adjust_gprs(rctx)) {
@@ -1417,6 +1435,30 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info
                r600_emit_atom(rctx, rctx->atoms[i]);
        }
 
+       if (rctx->b.chip_class == CAYMAN) {
+               /* Copied from radeonsi. */
+               unsigned primgroup_size = 128; /* recommended without a GS */
+               bool ia_switch_on_eop = false;
+               bool partial_vs_wave = false;
+
+               if (rctx->gs_shader)
+                       primgroup_size = 64; /* recommended with a GS */
+
+               if ((rctx->rasterizer && rctx->rasterizer->pa_sc_line_stipple) ||
+                   (rctx->b.screen->debug_flags & DBG_SWITCH_ON_EOP)) {
+                       ia_switch_on_eop = true;
+               }
+
+               if (rctx->b.streamout.streamout_enabled ||
+                   rctx->b.streamout.prims_gen_query_enabled)
+                       partial_vs_wave = true;
+
+               r600_write_context_reg(cs, CM_R_028AA8_IA_MULTI_VGT_PARAM,
+                                      S_028AA8_SWITCH_ON_EOP(ia_switch_on_eop) |
+                                      S_028AA8_PARTIAL_VS_WAVE_ON(partial_vs_wave) |
+                                      S_028AA8_PRIMGROUP_SIZE(primgroup_size - 1));
+       }
+
        /* On R6xx, CULL_FRONT=1 culls all points, lines, and rectangles,
         * even though it should have no effect on those. */
        if (rctx->b.chip_class == R600 && rctx->rasterizer) {
@@ -1546,67 +1588,6 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info
        rctx->b.num_draw_calls++;
 }
 
-void r600_draw_rectangle(struct blitter_context *blitter,
-                        int x1, int y1, int x2, int y2, float depth,
-                        enum blitter_attrib_type type, const union pipe_color_union *attrib)
-{
-       struct r600_context *rctx = (struct r600_context*)util_blitter_get_pipe(blitter);
-       struct pipe_viewport_state viewport;
-       struct pipe_resource *buf = NULL;
-       unsigned offset = 0;
-       float *vb;
-
-       if (type == UTIL_BLITTER_ATTRIB_TEXCOORD) {
-               util_blitter_draw_rectangle(blitter, x1, y1, x2, y2, depth, type, attrib);
-               return;
-       }
-
-       /* Some operations (like color resolve on r6xx) don't work
-        * with the conventional primitive types.
-        * One that works is PT_RECTLIST, which we use here. */
-
-       /* setup viewport */
-       viewport.scale[0] = 1.0f;
-       viewport.scale[1] = 1.0f;
-       viewport.scale[2] = 1.0f;
-       viewport.scale[3] = 1.0f;
-       viewport.translate[0] = 0.0f;
-       viewport.translate[1] = 0.0f;
-       viewport.translate[2] = 0.0f;
-       viewport.translate[3] = 0.0f;
-       rctx->b.b.set_viewport_states(&rctx->b.b, 0, 1, &viewport);
-
-       /* Upload vertices. The hw rectangle has only 3 vertices,
-        * I guess the 4th one is derived from the first 3.
-        * The vertex specification should match u_blitter's vertex element state. */
-       u_upload_alloc(rctx->b.uploader, 0, sizeof(float) * 24, &offset, &buf, (void**)&vb);
-       vb[0] = x1;
-       vb[1] = y1;
-       vb[2] = depth;
-       vb[3] = 1;
-
-       vb[8] = x1;
-       vb[9] = y2;
-       vb[10] = depth;
-       vb[11] = 1;
-
-       vb[16] = x2;
-       vb[17] = y1;
-       vb[18] = depth;
-       vb[19] = 1;
-
-       if (attrib) {
-               memcpy(vb+4, attrib->f, sizeof(float)*4);
-               memcpy(vb+12, attrib->f, sizeof(float)*4);
-               memcpy(vb+20, attrib->f, sizeof(float)*4);
-       }
-
-       /* draw */
-       util_draw_vertex_buffer(&rctx->b.b, NULL, buf, rctx->blitter->vb_slot, offset,
-                               R600_PRIM_RECTANGLE_LIST, 3, 2);
-       pipe_resource_reference(&buf, NULL);
-}
-
 uint32_t r600_translate_stencil_op(int s_op)
 {
        switch (s_op) {
@@ -1967,6 +1948,30 @@ uint32_t r600_translate_texformat(struct pipe_screen *screen,
                }
        }
 
+       if (desc->layout == UTIL_FORMAT_LAYOUT_BPTC) {
+               if (!enable_s3tc)
+                       goto out_unknown;
+
+               if (rscreen->b.chip_class < EVERGREEN)
+                       goto out_unknown;
+
+               switch (format) {
+                       case PIPE_FORMAT_BPTC_RGBA_UNORM:
+                       case PIPE_FORMAT_BPTC_SRGBA:
+                               result = FMT_BC7;
+                               is_srgb_valid = TRUE;
+                               goto out_word4;
+                       case PIPE_FORMAT_BPTC_RGB_FLOAT:
+                               word4 |= sign_bit[0] | sign_bit[1] | sign_bit[2];
+                               /* fall through */
+                       case PIPE_FORMAT_BPTC_RGB_UFLOAT:
+                               result = FMT_BC6;
+                               goto out_word4;
+                       default:
+                               goto out_unknown;
+               }
+       }
+
        if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) {
                switch (format) {
                case PIPE_FORMAT_R8G8_B8G8_UNORM:
@@ -2314,6 +2319,7 @@ static void r600_invalidate_buffer(struct pipe_context *ctx, struct pipe_resourc
        struct r600_context *rctx = (struct r600_context*)ctx;
        struct r600_resource *rbuffer = r600_resource(buf);
        unsigned i, shader, mask, alignment = rbuffer->buf->alignment;
+       struct r600_pipe_sampler_view *view;
 
        /* Reallocate the buffer in the same pipe_resource. */
        r600_init_resource(&rctx->screen->b, rbuffer, rbuffer->b.b.width0,
@@ -2358,7 +2364,35 @@ static void r600_invalidate_buffer(struct pipe_context *ctx, struct pipe_resourc
                }
        }
 
-       /* XXX TODO: texture buffer objects */
+       /* Texture buffer objects - update the virtual addresses in descriptors. */
+       LIST_FOR_EACH_ENTRY(view, &rctx->b.texture_buffers, list) {
+               if (view->base.texture == &rbuffer->b.b) {
+                       unsigned stride = util_format_get_blocksize(view->base.format);
+                       uint64_t offset = (uint64_t)view->base.u.buf.first_element * stride;
+                       uint64_t va = rbuffer->gpu_address + offset;
+
+                       view->tex_resource_words[0] = va;
+                       view->tex_resource_words[2] &= C_038008_BASE_ADDRESS_HI;
+                       view->tex_resource_words[2] |= S_038008_BASE_ADDRESS_HI(va >> 32);
+               }
+       }
+       /* Texture buffer objects - make bindings dirty if needed. */
+       for (shader = 0; shader < PIPE_SHADER_TYPES; shader++) {
+               struct r600_samplerview_state *state = &rctx->samplers[shader].views;
+               bool found = false;
+               uint32_t mask = state->enabled_mask;
+
+               while (mask) {
+                       unsigned i = u_bit_scan(&mask);
+                       if (state->views[i]->base.texture == &rbuffer->b.b) {
+                               found = true;
+                               state->dirty_mask |= 1 << i;
+                       }
+               }
+               if (found) {
+                       r600_sampler_views_dirty(rctx, state);
+               }
+       }
 }
 
 static void r600_set_occlusion_query_state(struct pipe_context *ctx, bool enable)