+
+ memset(&info, 0, sizeof(info));
+ if (vec->ib.hw_resource) {
+ info.vma = ilo_resource_get_vma(vec->ib.hw_resource);
+ info.size = info.vma->vm_size;
+ info.format = ilo_translate_index_size(vec->ib.hw_index_size);
+ }
+
+ ilo_state_index_buffer_set_info(&vec->ib.ib, dev, &info);
+}
+
+static void
+finalize_vertex_elements(struct ilo_context *ilo)
+{
+ const struct ilo_dev *dev = ilo->dev;
+ struct ilo_state_vector *vec = &ilo->state_vector;
+ struct ilo_ve_state *ve = vec->ve;
+ const bool last_element_edge_flag = (vec->vs &&
+ ilo_shader_get_kernel_param(vec->vs, ILO_KERNEL_VS_INPUT_EDGEFLAG));
+ const bool prepend_vertexid = (vec->vs &&
+ ilo_shader_get_kernel_param(vec->vs, ILO_KERNEL_VS_INPUT_VERTEXID));
+ const bool prepend_instanceid = (vec->vs &&
+ ilo_shader_get_kernel_param(vec->vs,
+ ILO_KERNEL_VS_INPUT_INSTANCEID));
+ const enum gen_index_format index_format = (vec->draw->indexed) ?
+ ilo_translate_index_size(vec->ib.state.index_size) : GEN6_INDEX_DWORD;
+
+ /* check for non-orthogonal states */
+ if (ve->vf_params.cv_topology != vec->draw_info.topology ||
+ ve->vf_params.prepend_vertexid != prepend_vertexid ||
+ ve->vf_params.prepend_instanceid != prepend_instanceid ||
+ ve->vf_params.last_element_edge_flag != last_element_edge_flag ||
+ ve->vf_params.cv_index_format != index_format ||
+ ve->vf_params.cut_index_enable != vec->draw->primitive_restart ||
+ ve->vf_params.cut_index != vec->draw->restart_index) {
+ ve->vf_params.cv_topology = vec->draw_info.topology;
+ ve->vf_params.prepend_vertexid = prepend_vertexid;
+ ve->vf_params.prepend_instanceid = prepend_instanceid;
+ ve->vf_params.last_element_edge_flag = last_element_edge_flag;
+ ve->vf_params.cv_index_format = index_format;
+ ve->vf_params.cut_index_enable = vec->draw->primitive_restart;
+ ve->vf_params.cut_index = vec->draw->restart_index;
+
+ ilo_state_vf_set_params(&ve->vf, dev, &ve->vf_params);
+
+ vec->dirty |= ILO_DIRTY_VE;
+ }
+}
+
+static void
+finalize_vertex_buffers(struct ilo_context *ilo)
+{
+ const struct ilo_dev *dev = ilo->dev;
+ struct ilo_state_vector *vec = &ilo->state_vector;
+ struct ilo_state_vertex_buffer_info info;
+ unsigned i;
+
+ if (!(vec->dirty & (ILO_DIRTY_VE | ILO_DIRTY_VB)))
+ return;
+
+ memset(&info, 0, sizeof(info));
+
+ for (i = 0; i < vec->ve->vb_count; i++) {
+ const unsigned pipe_idx = vec->ve->vb_mapping[i];
+ const struct pipe_vertex_buffer *cso = &vec->vb.states[pipe_idx];
+
+ if (cso->buffer) {
+ info.vma = ilo_resource_get_vma(cso->buffer);
+ info.offset = cso->buffer_offset;
+ info.size = info.vma->vm_size - cso->buffer_offset;
+
+ info.stride = cso->stride;
+ } else {
+ memset(&info, 0, sizeof(info));
+ }
+
+ ilo_state_vertex_buffer_set_info(&vec->vb.vb[i], dev, &info);
+ }
+}
+
+static void
+finalize_urb(struct ilo_context *ilo)
+{
+ const uint16_t attr_size = sizeof(uint32_t) * 4;
+ const struct ilo_dev *dev = ilo->dev;
+ struct ilo_state_vector *vec = &ilo->state_vector;
+ struct ilo_state_urb_info info;
+
+ if (!(vec->dirty & (ILO_DIRTY_VE | ILO_DIRTY_VS |
+ ILO_DIRTY_GS | ILO_DIRTY_FS)))
+ return;
+
+ memset(&info, 0, sizeof(info));
+
+ info.ve_entry_size = attr_size * ilo_state_vf_get_attr_count(&vec->ve->vf);
+
+ if (vec->vs) {
+ info.vs_const_data = (bool)
+ (ilo_shader_get_kernel_param(vec->vs, ILO_KERNEL_PCB_CBUF0_SIZE) +
+ ilo_shader_get_kernel_param(vec->vs, ILO_KERNEL_VS_PCB_UCP_SIZE));
+ info.vs_entry_size = attr_size *
+ ilo_shader_get_kernel_param(vec->vs, ILO_KERNEL_OUTPUT_COUNT);
+ }
+
+ if (vec->gs) {
+ info.gs_const_data = (bool)
+ ilo_shader_get_kernel_param(vec->gs, ILO_KERNEL_PCB_CBUF0_SIZE);
+
+ /*
+ * From the Ivy Bridge PRM, volume 2 part 1, page 189:
+ *
+ * "All outputs of a GS thread will be stored in the single GS
+ * thread output URB entry."
+ *
+ * TODO
+ */
+ info.gs_entry_size = attr_size *
+ ilo_shader_get_kernel_param(vec->gs, ILO_KERNEL_OUTPUT_COUNT);
+ }
+
+ if (vec->fs) {
+ info.ps_const_data = (bool)
+ ilo_shader_get_kernel_param(vec->fs, ILO_KERNEL_PCB_CBUF0_SIZE);
+ }
+
+ ilo_state_urb_set_info(&vec->urb, dev, &info);
+}
+
+static void
+finalize_viewport(struct ilo_context *ilo)
+{
+ const struct ilo_dev *dev = ilo->dev;
+ struct ilo_state_vector *vec = &ilo->state_vector;
+
+ if (vec->dirty & ILO_DIRTY_VIEWPORT) {
+ ilo_state_viewport_set_params(&vec->viewport.vp,
+ dev, &vec->viewport.params, false);
+ } else if (vec->dirty & ILO_DIRTY_SCISSOR) {
+ ilo_state_viewport_set_params(&vec->viewport.vp,
+ dev, &vec->viewport.params, true);
+ vec->dirty |= ILO_DIRTY_VIEWPORT;
+ }
+}
+
+static bool
+can_enable_gb_test(const struct ilo_rasterizer_state *rasterizer,
+ const struct ilo_viewport_state *viewport,
+ const struct ilo_fb_state *fb)
+{
+ unsigned i;
+
+ /*
+ * There are several reasons that guard band test should be disabled
+ *
+ * - GL wide points (to avoid partially visibie object)
+ * - GL wide or AA lines (to avoid partially visibie object)
+ * - missing 2D clipping
+ */
+ if (rasterizer->state.point_size_per_vertex ||
+ rasterizer->state.point_size > 1.0f ||
+ rasterizer->state.line_width > 1.0f ||
+ rasterizer->state.line_smooth)
+ return false;
+
+ for (i = 0; i < viewport->params.count; i++) {
+ const struct ilo_state_viewport_matrix_info *mat =
+ &viewport->matrices[i];
+ float min_x, max_x, min_y, max_y;
+
+ min_x = -1.0f * fabsf(mat->scale[0]) + mat->translate[0];
+ max_x = 1.0f * fabsf(mat->scale[0]) + mat->translate[0];
+ min_y = -1.0f * fabsf(mat->scale[1]) + mat->translate[1];
+ max_y = 1.0f * fabsf(mat->scale[1]) + mat->translate[1];
+
+ if (min_x > 0.0f || max_x < fb->state.width ||
+ min_y > 0.0f || max_y < fb->state.height)
+ return false;
+ }
+
+ return true;
+}
+
+static void
+finalize_rasterizer(struct ilo_context *ilo)
+{
+ const struct ilo_dev *dev = ilo->dev;
+ struct ilo_state_vector *vec = &ilo->state_vector;
+ struct ilo_rasterizer_state *rasterizer = vec->rasterizer;
+ struct ilo_state_raster_info *info = &vec->rasterizer->info;
+ const bool gb_test_enable =
+ can_enable_gb_test(rasterizer, &vec->viewport, &vec->fb);
+ const bool multisample =
+ (rasterizer->state.multisample && vec->fb.num_samples > 1);
+ const uint8_t barycentric_interps = ilo_shader_get_kernel_param(vec->fs,
+ ILO_KERNEL_FS_BARYCENTRIC_INTERPOLATIONS);
+
+ /* check for non-orthogonal states */
+ if (info->clip.viewport_count != vec->viewport.params.count ||
+ info->clip.gb_test_enable != gb_test_enable ||
+ info->setup.msaa_enable != multisample ||
+ info->setup.line_msaa_enable != multisample ||
+ info->tri.depth_offset_format != vec->fb.depth_offset_format ||
+ info->scan.sample_count != vec->fb.num_samples ||
+ info->scan.sample_mask != vec->sample_mask ||
+ info->scan.barycentric_interps != barycentric_interps ||
+ info->params.any_integer_rt != vec->fb.has_integer_rt ||
+ info->params.hiz_enable != vec->fb.has_hiz) {
+ info->clip.viewport_count = vec->viewport.params.count;
+ info->clip.gb_test_enable = gb_test_enable;
+ info->setup.msaa_enable = multisample;
+ info->setup.line_msaa_enable = multisample;
+ info->tri.depth_offset_format = vec->fb.depth_offset_format;
+ info->scan.sample_count = vec->fb.num_samples;
+ info->scan.sample_mask = vec->sample_mask;
+ info->scan.barycentric_interps = barycentric_interps;
+ info->params.any_integer_rt = vec->fb.has_integer_rt;
+ info->params.hiz_enable = vec->fb.has_hiz;
+
+ ilo_state_raster_set_info(&rasterizer->rs, dev, &rasterizer->info);
+
+ vec->dirty |= ILO_DIRTY_RASTERIZER;
+ }
+}
+
+static bool
+finalize_blend_rt(struct ilo_context *ilo)
+{
+ struct ilo_state_vector *vec = &ilo->state_vector;
+ const struct ilo_fb_state *fb = &vec->fb;
+ struct ilo_blend_state *blend = vec->blend;
+ struct ilo_state_cc_blend_info *info = &vec->blend->info.blend;
+ bool changed = false;
+ unsigned i;
+
+ if (!(vec->dirty & (ILO_DIRTY_FB | ILO_DIRTY_BLEND)))
+ return false;
+
+ /* set up one for dummy RT writes */
+ if (!fb->state.nr_cbufs) {
+ if (info->rt != &blend->dummy_rt) {
+ info->rt = &blend->dummy_rt;
+ info->rt_count = 1;
+ changed = true;
+ }
+
+ return changed;
+ }
+
+ if (info->rt != blend->effective_rt ||
+ info->rt_count != fb->state.nr_cbufs) {
+ info->rt = blend->effective_rt;
+ info->rt_count = fb->state.nr_cbufs;
+ changed = true;
+ }
+
+ for (i = 0; i < fb->state.nr_cbufs; i++) {
+ const struct ilo_fb_blend_caps *caps = &fb->blend_caps[i];
+ struct ilo_state_cc_blend_rt_info *rt = &blend->effective_rt[i];
+ /* ignore logicop when not UNORM */
+ const bool logicop_enable =
+ (blend->rt[i].logicop_enable && caps->is_unorm);
+
+ if (rt->cv_is_unorm != caps->is_unorm ||
+ rt->cv_is_integer != caps->is_integer ||
+ rt->logicop_enable != logicop_enable ||
+ rt->force_dst_alpha_one != caps->force_dst_alpha_one) {
+ rt->cv_is_unorm = caps->is_unorm;
+ rt->cv_is_integer = caps->is_integer;
+ rt->logicop_enable = logicop_enable;
+ rt->force_dst_alpha_one = caps->force_dst_alpha_one;
+
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+static void
+finalize_blend(struct ilo_context *ilo)
+{
+ const struct ilo_dev *dev = ilo->dev;
+ struct ilo_state_vector *vec = &ilo->state_vector;
+ struct ilo_blend_state *blend = vec->blend;
+ struct ilo_state_cc_info *info = &blend->info;
+ const bool sample_count_one = (vec->fb.num_samples <= 1);
+ const bool float_source0_alpha =
+ (!vec->fb.state.nr_cbufs || !vec->fb.state.cbufs[0] ||
+ !util_format_is_pure_integer(vec->fb.state.cbufs[0]->format));
+
+ /* check for non-orthogonal states */
+ if (finalize_blend_rt(ilo) ||
+ info->alpha.cv_sample_count_one != sample_count_one ||
+ info->alpha.cv_float_source0_alpha != float_source0_alpha ||
+ info->alpha.test_enable != vec->dsa->alpha_test ||
+ info->alpha.test_func != vec->dsa->alpha_func ||
+ memcmp(&info->stencil, &vec->dsa->stencil, sizeof(info->stencil)) ||
+ memcmp(&info->depth, &vec->dsa->depth, sizeof(info->depth)) ||
+ memcmp(&info->params, &vec->cc_params, sizeof(info->params))) {
+ info->alpha.cv_sample_count_one = sample_count_one;
+ info->alpha.cv_float_source0_alpha = float_source0_alpha;
+ info->alpha.test_enable = vec->dsa->alpha_test;
+ info->alpha.test_func = vec->dsa->alpha_func;
+ info->stencil = vec->dsa->stencil;
+ info->depth = vec->dsa->depth;
+ info->params = vec->cc_params;
+
+ ilo_state_cc_set_info(&blend->cc, dev, info);
+
+ blend->alpha_may_kill = (info->alpha.alpha_to_coverage ||
+ info->alpha.test_enable);
+
+ vec->dirty |= ILO_DIRTY_BLEND;
+ }