/* * Mesa 3-D graphics library * * Copyright (C) 2012-2013 LunarG, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * Authors: * Chia-I Wu */ #include "core/ilo_builder_3d.h" /* for gen6_3d_translate_pipe_prim() */ #include "core/ilo_format.h" #include "core/ilo_state_3d.h" #include "util/u_dual_blend.h" #include "util/u_dynarray.h" #include "util/u_helpers.h" #include "util/u_resource.h" #include "util/u_upload_mgr.h" #include "ilo_context.h" #include "ilo_resource.h" #include "ilo_shader.h" #include "ilo_state.h" static enum gen_mip_filter ilo_translate_mip_filter(unsigned filter) { switch (filter) { case PIPE_TEX_MIPFILTER_NEAREST: return GEN6_MIPFILTER_NEAREST; case PIPE_TEX_MIPFILTER_LINEAR: return GEN6_MIPFILTER_LINEAR; case PIPE_TEX_MIPFILTER_NONE: return GEN6_MIPFILTER_NONE; default: assert(!"unknown mipfilter"); return GEN6_MIPFILTER_NONE; } } static int ilo_translate_img_filter(unsigned filter) { switch (filter) { case PIPE_TEX_FILTER_NEAREST: return GEN6_MAPFILTER_NEAREST; case PIPE_TEX_FILTER_LINEAR: return GEN6_MAPFILTER_LINEAR; default: assert(!"unknown sampler filter"); return GEN6_MAPFILTER_NEAREST; } } static enum gen_texcoord_mode ilo_translate_address_wrap(unsigned wrap) { switch (wrap) { case PIPE_TEX_WRAP_CLAMP: return GEN8_TEXCOORDMODE_HALF_BORDER; case PIPE_TEX_WRAP_REPEAT: return GEN6_TEXCOORDMODE_WRAP; case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return GEN6_TEXCOORDMODE_CLAMP; case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return GEN6_TEXCOORDMODE_CLAMP_BORDER; case PIPE_TEX_WRAP_MIRROR_REPEAT: return GEN6_TEXCOORDMODE_MIRROR; case PIPE_TEX_WRAP_MIRROR_CLAMP: case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: default: assert(!"unknown sampler wrap mode"); return GEN6_TEXCOORDMODE_WRAP; } } static enum gen_aniso_ratio ilo_translate_max_anisotropy(unsigned max_anisotropy) { switch (max_anisotropy) { case 0: case 1: case 2: return GEN6_ANISORATIO_2; case 3: case 4: return GEN6_ANISORATIO_4; case 5: case 6: return GEN6_ANISORATIO_6; case 7: case 8: return GEN6_ANISORATIO_8; case 9: case 10: return GEN6_ANISORATIO_10; case 11: case 12: return GEN6_ANISORATIO_12; case 13: case 14: return GEN6_ANISORATIO_14; default: return GEN6_ANISORATIO_16; } } static enum gen_prefilter_op ilo_translate_shadow_func(unsigned func) { /* * For PIPE_FUNC_x, the reference value is on the left-hand side of the * comparison, and 1.0 is returned when the comparison is true. * * For GEN6_PREFILTEROP_x, the reference value is on the right-hand side of * the comparison, and 0.0 is returned when the comparison is true. */ switch (func) { case PIPE_FUNC_NEVER: return GEN6_PREFILTEROP_ALWAYS; case PIPE_FUNC_LESS: return GEN6_PREFILTEROP_LEQUAL; case PIPE_FUNC_EQUAL: return GEN6_PREFILTEROP_NOTEQUAL; case PIPE_FUNC_LEQUAL: return GEN6_PREFILTEROP_LESS; case PIPE_FUNC_GREATER: return GEN6_PREFILTEROP_GEQUAL; case PIPE_FUNC_NOTEQUAL: return GEN6_PREFILTEROP_EQUAL; case PIPE_FUNC_GEQUAL: return GEN6_PREFILTEROP_GREATER; case PIPE_FUNC_ALWAYS: return GEN6_PREFILTEROP_NEVER; default: assert(!"unknown shadow compare function"); return GEN6_PREFILTEROP_NEVER; } } static enum gen_front_winding ilo_translate_front_ccw(unsigned front_ccw) { return (front_ccw) ? GEN6_FRONTWINDING_CCW : GEN6_FRONTWINDING_CW; } static enum gen_cull_mode ilo_translate_cull_face(unsigned cull_face) { switch (cull_face) { case PIPE_FACE_NONE: return GEN6_CULLMODE_NONE; case PIPE_FACE_FRONT: return GEN6_CULLMODE_FRONT; case PIPE_FACE_BACK: return GEN6_CULLMODE_BACK; case PIPE_FACE_FRONT_AND_BACK: return GEN6_CULLMODE_BOTH; default: assert(!"unknown face culling"); return GEN6_CULLMODE_NONE; } } static enum gen_fill_mode ilo_translate_poly_mode(unsigned poly_mode) { switch (poly_mode) { case PIPE_POLYGON_MODE_FILL: return GEN6_FILLMODE_SOLID; case PIPE_POLYGON_MODE_LINE: return GEN6_FILLMODE_WIREFRAME; case PIPE_POLYGON_MODE_POINT: return GEN6_FILLMODE_POINT; default: assert(!"unknown polygon mode"); return GEN6_FILLMODE_SOLID; } } static enum gen_pixel_location ilo_translate_half_pixel_center(bool half_pixel_center) { return (half_pixel_center) ? GEN6_PIXLOC_CENTER : GEN6_PIXLOC_UL_CORNER; } static enum gen_compare_function ilo_translate_compare_func(unsigned func) { switch (func) { case PIPE_FUNC_NEVER: return GEN6_COMPAREFUNCTION_NEVER; case PIPE_FUNC_LESS: return GEN6_COMPAREFUNCTION_LESS; case PIPE_FUNC_EQUAL: return GEN6_COMPAREFUNCTION_EQUAL; case PIPE_FUNC_LEQUAL: return GEN6_COMPAREFUNCTION_LEQUAL; case PIPE_FUNC_GREATER: return GEN6_COMPAREFUNCTION_GREATER; case PIPE_FUNC_NOTEQUAL: return GEN6_COMPAREFUNCTION_NOTEQUAL; case PIPE_FUNC_GEQUAL: return GEN6_COMPAREFUNCTION_GEQUAL; case PIPE_FUNC_ALWAYS: return GEN6_COMPAREFUNCTION_ALWAYS; default: assert(!"unknown compare function"); return GEN6_COMPAREFUNCTION_NEVER; } } static enum gen_stencil_op ilo_translate_stencil_op(unsigned stencil_op) { switch (stencil_op) { case PIPE_STENCIL_OP_KEEP: return GEN6_STENCILOP_KEEP; case PIPE_STENCIL_OP_ZERO: return GEN6_STENCILOP_ZERO; case PIPE_STENCIL_OP_REPLACE: return GEN6_STENCILOP_REPLACE; case PIPE_STENCIL_OP_INCR: return GEN6_STENCILOP_INCRSAT; case PIPE_STENCIL_OP_DECR: return GEN6_STENCILOP_DECRSAT; case PIPE_STENCIL_OP_INCR_WRAP: return GEN6_STENCILOP_INCR; case PIPE_STENCIL_OP_DECR_WRAP: return GEN6_STENCILOP_DECR; case PIPE_STENCIL_OP_INVERT: return GEN6_STENCILOP_INVERT; default: assert(!"unknown stencil op"); return GEN6_STENCILOP_KEEP; } } static enum gen_logic_op ilo_translate_logicop(unsigned logicop) { switch (logicop) { case PIPE_LOGICOP_CLEAR: return GEN6_LOGICOP_CLEAR; case PIPE_LOGICOP_NOR: return GEN6_LOGICOP_NOR; case PIPE_LOGICOP_AND_INVERTED: return GEN6_LOGICOP_AND_INVERTED; case PIPE_LOGICOP_COPY_INVERTED: return GEN6_LOGICOP_COPY_INVERTED; case PIPE_LOGICOP_AND_REVERSE: return GEN6_LOGICOP_AND_REVERSE; case PIPE_LOGICOP_INVERT: return GEN6_LOGICOP_INVERT; case PIPE_LOGICOP_XOR: return GEN6_LOGICOP_XOR; case PIPE_LOGICOP_NAND: return GEN6_LOGICOP_NAND; case PIPE_LOGICOP_AND: return GEN6_LOGICOP_AND; case PIPE_LOGICOP_EQUIV: return GEN6_LOGICOP_EQUIV; case PIPE_LOGICOP_NOOP: return GEN6_LOGICOP_NOOP; case PIPE_LOGICOP_OR_INVERTED: return GEN6_LOGICOP_OR_INVERTED; case PIPE_LOGICOP_COPY: return GEN6_LOGICOP_COPY; case PIPE_LOGICOP_OR_REVERSE: return GEN6_LOGICOP_OR_REVERSE; case PIPE_LOGICOP_OR: return GEN6_LOGICOP_OR; case PIPE_LOGICOP_SET: return GEN6_LOGICOP_SET; default: assert(!"unknown logicop function"); return GEN6_LOGICOP_CLEAR; } } static int ilo_translate_blend_func(unsigned blend) { switch (blend) { case PIPE_BLEND_ADD: return GEN6_BLENDFUNCTION_ADD; case PIPE_BLEND_SUBTRACT: return GEN6_BLENDFUNCTION_SUBTRACT; case PIPE_BLEND_REVERSE_SUBTRACT: return GEN6_BLENDFUNCTION_REVERSE_SUBTRACT; case PIPE_BLEND_MIN: return GEN6_BLENDFUNCTION_MIN; case PIPE_BLEND_MAX: return GEN6_BLENDFUNCTION_MAX; default: assert(!"unknown blend function"); return GEN6_BLENDFUNCTION_ADD; } } static int ilo_translate_blend_factor(unsigned factor) { switch (factor) { case PIPE_BLENDFACTOR_ONE: return GEN6_BLENDFACTOR_ONE; case PIPE_BLENDFACTOR_SRC_COLOR: return GEN6_BLENDFACTOR_SRC_COLOR; case PIPE_BLENDFACTOR_SRC_ALPHA: return GEN6_BLENDFACTOR_SRC_ALPHA; case PIPE_BLENDFACTOR_DST_ALPHA: return GEN6_BLENDFACTOR_DST_ALPHA; case PIPE_BLENDFACTOR_DST_COLOR: return GEN6_BLENDFACTOR_DST_COLOR; case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: return GEN6_BLENDFACTOR_SRC_ALPHA_SATURATE; case PIPE_BLENDFACTOR_CONST_COLOR: return GEN6_BLENDFACTOR_CONST_COLOR; case PIPE_BLENDFACTOR_CONST_ALPHA: return GEN6_BLENDFACTOR_CONST_ALPHA; case PIPE_BLENDFACTOR_SRC1_COLOR: return GEN6_BLENDFACTOR_SRC1_COLOR; case PIPE_BLENDFACTOR_SRC1_ALPHA: return GEN6_BLENDFACTOR_SRC1_ALPHA; case PIPE_BLENDFACTOR_ZERO: return GEN6_BLENDFACTOR_ZERO; case PIPE_BLENDFACTOR_INV_SRC_COLOR: return GEN6_BLENDFACTOR_INV_SRC_COLOR; case PIPE_BLENDFACTOR_INV_SRC_ALPHA: return GEN6_BLENDFACTOR_INV_SRC_ALPHA; case PIPE_BLENDFACTOR_INV_DST_ALPHA: return GEN6_BLENDFACTOR_INV_DST_ALPHA; case PIPE_BLENDFACTOR_INV_DST_COLOR: return GEN6_BLENDFACTOR_INV_DST_COLOR; case PIPE_BLENDFACTOR_INV_CONST_COLOR: return GEN6_BLENDFACTOR_INV_CONST_COLOR; case PIPE_BLENDFACTOR_INV_CONST_ALPHA: return GEN6_BLENDFACTOR_INV_CONST_ALPHA; case PIPE_BLENDFACTOR_INV_SRC1_COLOR: return GEN6_BLENDFACTOR_INV_SRC1_COLOR; case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: return GEN6_BLENDFACTOR_INV_SRC1_ALPHA; default: assert(!"unknown blend factor"); return GEN6_BLENDFACTOR_ONE; } } static void finalize_shader_states(struct ilo_state_vector *vec) { unsigned type; for (type = 0; type < PIPE_SHADER_TYPES; type++) { struct ilo_shader_state *shader; uint32_t state; switch (type) { case PIPE_SHADER_VERTEX: shader = vec->vs; state = ILO_DIRTY_VS; break; case PIPE_SHADER_GEOMETRY: shader = vec->gs; state = ILO_DIRTY_GS; break; case PIPE_SHADER_FRAGMENT: shader = vec->fs; state = ILO_DIRTY_FS; break; default: shader = NULL; state = 0; break; } if (!shader) continue; /* compile if the shader or the states it depends on changed */ if (vec->dirty & state) { ilo_shader_select_kernel(shader, vec, ILO_DIRTY_ALL); } else if (ilo_shader_select_kernel(shader, vec, vec->dirty)) { /* mark the state dirty if a new kernel is selected */ vec->dirty |= state; } /* need to setup SBE for FS */ if (type == PIPE_SHADER_FRAGMENT && vec->dirty & (state | ILO_DIRTY_GS | ILO_DIRTY_VS | ILO_DIRTY_RASTERIZER)) { if (ilo_shader_select_kernel_routing(shader, (vec->gs) ? vec->gs : vec->vs, vec->rasterizer)) vec->dirty |= state; } } } static void finalize_cbuf_state(struct ilo_context *ilo, struct ilo_cbuf_state *cbuf, const struct ilo_shader_state *sh) { uint32_t upload_mask = cbuf->enabled_mask; /* skip CBUF0 if the kernel does not need it */ upload_mask &= ~ilo_shader_get_kernel_param(sh, ILO_KERNEL_SKIP_CBUF0_UPLOAD); while (upload_mask) { unsigned offset, i; i = u_bit_scan(&upload_mask); /* no need to upload */ if (cbuf->cso[i].resource) continue; u_upload_data(ilo->uploader, 0, cbuf->cso[i].info.size, cbuf->cso[i].user_buffer, &offset, &cbuf->cso[i].resource); cbuf->cso[i].info.buf = ilo_buffer(cbuf->cso[i].resource); cbuf->cso[i].info.offset = offset; memset(&cbuf->cso[i].surface, 0, sizeof(cbuf->cso[i].surface)); ilo_state_surface_init_for_buffer(&cbuf->cso[i].surface, ilo->dev, &cbuf->cso[i].info); cbuf->cso[i].surface.bo = cbuf->cso[i].info.buf->bo; ilo->state_vector.dirty |= ILO_DIRTY_CBUF; } } static void finalize_constant_buffers(struct ilo_context *ilo) { struct ilo_state_vector *vec = &ilo->state_vector; if (vec->dirty & (ILO_DIRTY_CBUF | ILO_DIRTY_VS)) finalize_cbuf_state(ilo, &vec->cbuf[PIPE_SHADER_VERTEX], vec->vs); if (ilo->state_vector.dirty & (ILO_DIRTY_CBUF | ILO_DIRTY_FS)) finalize_cbuf_state(ilo, &vec->cbuf[PIPE_SHADER_FRAGMENT], vec->fs); } static void finalize_index_buffer(struct ilo_context *ilo) { struct ilo_state_vector *vec = &ilo->state_vector; const bool need_upload = (vec->draw->indexed && (vec->ib.user_buffer || vec->ib.offset % vec->ib.index_size)); struct pipe_resource *current_hw_res = NULL; if (!(vec->dirty & ILO_DIRTY_IB) && !need_upload) return; pipe_resource_reference(¤t_hw_res, vec->ib.hw_resource); if (need_upload) { const unsigned offset = vec->ib.index_size * vec->draw->start; const unsigned size = vec->ib.index_size * vec->draw->count; unsigned hw_offset; if (vec->ib.user_buffer) { u_upload_data(ilo->uploader, 0, size, vec->ib.user_buffer + offset, &hw_offset, &vec->ib.hw_resource); } else { u_upload_buffer(ilo->uploader, 0, vec->ib.offset + offset, size, vec->ib.buffer, &hw_offset, &vec->ib.hw_resource); } /* the HW offset should be aligned */ assert(hw_offset % vec->ib.index_size == 0); vec->ib.draw_start_offset = hw_offset / vec->ib.index_size; /* * INDEX[vec->draw->start] in the original buffer is INDEX[0] in the HW * resource */ vec->ib.draw_start_offset -= vec->draw->start; } else { pipe_resource_reference(&vec->ib.hw_resource, vec->ib.buffer); /* note that index size may be zero when the draw is not indexed */ if (vec->draw->indexed) vec->ib.draw_start_offset = vec->ib.offset / vec->ib.index_size; else vec->ib.draw_start_offset = 0; } /* treat the IB as clean if the HW states do not change */ if (vec->ib.hw_resource == current_hw_res && vec->ib.hw_index_size == vec->ib.index_size) vec->dirty &= ~ILO_DIRTY_IB; else vec->ib.hw_index_size = vec->ib.index_size; pipe_resource_reference(¤t_hw_res, NULL); } static void finalize_vertex_elements(struct ilo_context *ilo) { struct ilo_state_vector *vec = &ilo->state_vector; if (!(vec->dirty & (ILO_DIRTY_VE | ILO_DIRTY_VS))) return; vec->dirty |= ILO_DIRTY_VE; vec->ve->last_cso_edgeflag = false; if (vec->ve->count && vec->vs && ilo_shader_get_kernel_param(vec->vs, ILO_KERNEL_VS_INPUT_EDGEFLAG)) { vec->ve->edgeflag_cso = vec->ve->cso[vec->ve->count - 1]; ilo_gpe_set_ve_edgeflag(ilo->dev, &vec->ve->edgeflag_cso); vec->ve->last_cso_edgeflag = true; } vec->ve->prepend_nosrc_cso = false; if (vec->vs && (ilo_shader_get_kernel_param(vec->vs, ILO_KERNEL_VS_INPUT_INSTANCEID) || ilo_shader_get_kernel_param(vec->vs, ILO_KERNEL_VS_INPUT_VERTEXID))) { ilo_gpe_init_ve_nosrc(ilo->dev, GEN6_VFCOMP_STORE_VID, GEN6_VFCOMP_STORE_IID, GEN6_VFCOMP_NOSTORE, GEN6_VFCOMP_NOSTORE, &vec->ve->nosrc_cso); vec->ve->prepend_nosrc_cso = true; } else if (!vec->vs) { /* generate VUE header */ ilo_gpe_init_ve_nosrc(ilo->dev, GEN6_VFCOMP_STORE_0, /* Reserved */ GEN6_VFCOMP_STORE_0, /* Render Target Array Index */ GEN6_VFCOMP_STORE_0, /* Viewport Index */ GEN6_VFCOMP_STORE_0, /* Point Width */ &vec->ve->nosrc_cso); vec->ve->prepend_nosrc_cso = true; } else if (!vec->ve->count) { /* * From the Sandy Bridge PRM, volume 2 part 1, page 92: * * "SW must ensure that at least one vertex element is defined prior * to issuing a 3DPRIMTIVE command, or operation is UNDEFINED." */ ilo_gpe_init_ve_nosrc(ilo->dev, GEN6_VFCOMP_STORE_0, GEN6_VFCOMP_STORE_0, GEN6_VFCOMP_STORE_0, GEN6_VFCOMP_STORE_1_FP, &vec->ve->nosrc_cso); vec->ve->prepend_nosrc_cso = true; } } 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 * (vec->ve->count + vec->ve->prepend_nosrc_cso); 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; } } /** * Finalize states. Some states depend on other states and are * incomplete/invalid until finalized. */ void ilo_finalize_3d_states(struct ilo_context *ilo, const struct pipe_draw_info *draw) { ilo->state_vector.draw = draw; finalize_shader_states(&ilo->state_vector); finalize_constant_buffers(ilo); finalize_index_buffer(ilo); finalize_vertex_elements(ilo); finalize_urb(ilo); finalize_rasterizer(ilo); finalize_viewport(ilo); finalize_blend(ilo); u_upload_unmap(ilo->uploader); } static void finalize_global_binding(struct ilo_state_vector *vec) { struct ilo_shader_state *cs = vec->cs; int base, count, shift; int i; count = ilo_shader_get_kernel_param(cs, ILO_KERNEL_CS_SURFACE_GLOBAL_COUNT); if (!count) return; base = ilo_shader_get_kernel_param(cs, ILO_KERNEL_CS_SURFACE_GLOBAL_BASE); shift = 32 - util_last_bit(base + count - 1); if (count > vec->global_binding.count) count = vec->global_binding.count; for (i = 0; i < count; i++) { struct ilo_global_binding_cso *cso = util_dynarray_element(&vec->global_binding.bindings, struct ilo_global_binding_cso, i); const uint32_t offset = *cso->handle & ((1 << shift) - 1); *cso->handle = ((base + i) << shift) | offset; } } void ilo_finalize_compute_states(struct ilo_context *ilo) { finalize_global_binding(&ilo->state_vector); } static void * ilo_create_blend_state(struct pipe_context *pipe, const struct pipe_blend_state *state) { const struct ilo_dev *dev = ilo_context(pipe)->dev; struct ilo_state_cc_info *info; struct ilo_blend_state *blend; int i; blend = CALLOC_STRUCT(ilo_blend_state); assert(blend); info = &blend->info; info->alpha.cv_float_source0_alpha = true; info->alpha.cv_sample_count_one = true; info->alpha.alpha_to_one = state->alpha_to_one; info->alpha.alpha_to_coverage = state->alpha_to_coverage; info->alpha.test_enable = false; info->alpha.test_func = GEN6_COMPAREFUNCTION_ALWAYS; info->stencil.cv_has_buffer = true; info->depth.cv_has_buffer= true; info->blend.rt = blend->effective_rt; info->blend.rt_count = 1; info->blend.dither_enable = state->dither; for (i = 0; i < ARRAY_SIZE(blend->rt); i++) { const struct pipe_rt_blend_state *rt = &state->rt[i]; struct ilo_state_cc_blend_rt_info *rt_info = &blend->rt[i]; rt_info->cv_has_buffer = true; rt_info->cv_is_unorm = true; rt_info->cv_is_integer = false; /* logic op takes precedence over blending */ if (state->logicop_enable) { rt_info->logicop_enable = true; rt_info->logicop_func = ilo_translate_logicop(state->logicop_func); } else if (rt->blend_enable) { rt_info->blend_enable = true; rt_info->rgb_src = ilo_translate_blend_factor(rt->rgb_src_factor); rt_info->rgb_dst = ilo_translate_blend_factor(rt->rgb_dst_factor); rt_info->rgb_func = ilo_translate_blend_func(rt->rgb_func); rt_info->a_src = ilo_translate_blend_factor(rt->alpha_src_factor); rt_info->a_dst = ilo_translate_blend_factor(rt->alpha_dst_factor); rt_info->a_func = ilo_translate_blend_func(rt->alpha_func); } if (!(rt->colormask & PIPE_MASK_A)) rt_info->argb_write_disables |= (1 << 3); if (!(rt->colormask & PIPE_MASK_R)) rt_info->argb_write_disables |= (1 << 2); if (!(rt->colormask & PIPE_MASK_G)) rt_info->argb_write_disables |= (1 << 1); if (!(rt->colormask & PIPE_MASK_B)) rt_info->argb_write_disables |= (1 << 0); if (!state->independent_blend_enable) { for (i = 1; i < ARRAY_SIZE(blend->rt); i++) blend->rt[i] = *rt_info; break; } } memcpy(blend->effective_rt, blend->rt, sizeof(blend->rt)); blend->dummy_rt.argb_write_disables = 0xf; if (!ilo_state_cc_init(&blend->cc, dev, &blend->info)) { FREE(blend); return NULL; } blend->dual_blend = util_blend_state_is_dual(state, 0); return blend; } static void ilo_bind_blend_state(struct pipe_context *pipe, void *state) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; vec->blend = state; vec->dirty |= ILO_DIRTY_BLEND; } static void ilo_delete_blend_state(struct pipe_context *pipe, void *state) { FREE(state); } static void * ilo_create_sampler_state(struct pipe_context *pipe, const struct pipe_sampler_state *state) { const struct ilo_dev *dev = ilo_context(pipe)->dev; struct ilo_sampler_cso *sampler; struct ilo_state_sampler_info info; struct ilo_state_sampler_border_info border; sampler = CALLOC_STRUCT(ilo_sampler_cso); assert(sampler); memset(&info, 0, sizeof(info)); info.non_normalized = !state->normalized_coords; if (state->normalized_coords) { info.lod_bias = state->lod_bias; info.min_lod = state->min_lod; info.max_lod = state->max_lod; info.mip_filter = ilo_translate_mip_filter(state->min_mip_filter); } else { /* work around a bug in util_blitter */ info.mip_filter = GEN6_MIPFILTER_NONE; } if (state->max_anisotropy) { info.min_filter = GEN6_MAPFILTER_ANISOTROPIC; info.mag_filter = GEN6_MAPFILTER_ANISOTROPIC; } else { info.min_filter = ilo_translate_img_filter(state->min_img_filter); info.mag_filter = ilo_translate_img_filter(state->mag_img_filter); } info.max_anisotropy = ilo_translate_max_anisotropy(state->max_anisotropy); /* use LOD 0 when no mipmapping (see sampler_set_gen6_SAMPLER_STATE()) */ if (info.mip_filter == GEN6_MIPFILTER_NONE && info.min_lod > 0.0f) { info.min_lod = 0.0f; info.mag_filter = info.min_filter; } if (state->seamless_cube_map) { if (state->min_img_filter == PIPE_TEX_FILTER_NEAREST || state->mag_img_filter == PIPE_TEX_FILTER_NEAREST) { info.tcx_ctrl = GEN6_TEXCOORDMODE_CLAMP; info.tcy_ctrl = GEN6_TEXCOORDMODE_CLAMP; info.tcz_ctrl = GEN6_TEXCOORDMODE_CLAMP; } else { info.tcx_ctrl = GEN6_TEXCOORDMODE_CUBE; info.tcy_ctrl = GEN6_TEXCOORDMODE_CUBE; info.tcz_ctrl = GEN6_TEXCOORDMODE_CUBE; } } else { info.tcx_ctrl = ilo_translate_address_wrap(state->wrap_s); info.tcy_ctrl = ilo_translate_address_wrap(state->wrap_t); info.tcz_ctrl = ilo_translate_address_wrap(state->wrap_r); if (ilo_dev_gen(dev) < ILO_GEN(8)) { /* * For nearest filtering, PIPE_TEX_WRAP_CLAMP means * PIPE_TEX_WRAP_CLAMP_TO_EDGE; for linear filtering, * PIPE_TEX_WRAP_CLAMP means PIPE_TEX_WRAP_CLAMP_TO_BORDER while * additionally clamping the texture coordinates to [0.0, 1.0]. * * PIPE_TEX_WRAP_CLAMP is not supported natively until Gen8. The * clamping has to be taken care of in the shaders. There are two * filters here, but let the minification one has a say. */ const bool clamp_is_to_edge = (state->min_img_filter == PIPE_TEX_FILTER_NEAREST); if (clamp_is_to_edge) { if (info.tcx_ctrl == GEN8_TEXCOORDMODE_HALF_BORDER) info.tcx_ctrl = GEN6_TEXCOORDMODE_CLAMP; if (info.tcy_ctrl == GEN8_TEXCOORDMODE_HALF_BORDER) info.tcy_ctrl = GEN6_TEXCOORDMODE_CLAMP; if (info.tcz_ctrl == GEN8_TEXCOORDMODE_HALF_BORDER) info.tcz_ctrl = GEN6_TEXCOORDMODE_CLAMP; } else { if (info.tcx_ctrl == GEN8_TEXCOORDMODE_HALF_BORDER) { info.tcx_ctrl = GEN6_TEXCOORDMODE_CLAMP_BORDER; sampler->saturate_s = true; } if (info.tcy_ctrl == GEN8_TEXCOORDMODE_HALF_BORDER) { info.tcy_ctrl = GEN6_TEXCOORDMODE_CLAMP_BORDER; sampler->saturate_t = true; } if (info.tcz_ctrl == GEN8_TEXCOORDMODE_HALF_BORDER) { info.tcz_ctrl = GEN6_TEXCOORDMODE_CLAMP_BORDER; sampler->saturate_r = true; } } } } if (state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) info.shadow_func = ilo_translate_shadow_func(state->compare_func); ilo_state_sampler_init(&sampler->sampler, dev, &info); memset(&border, 0, sizeof(border)); memcpy(border.rgba.f, state->border_color.f, sizeof(border.rgba.f)); ilo_state_sampler_border_init(&sampler->border, dev, &border); return sampler; } static void ilo_bind_sampler_states(struct pipe_context *pipe, unsigned shader, unsigned start, unsigned count, void **samplers) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; struct ilo_sampler_state *dst = &vec->sampler[shader]; bool changed = false; unsigned i; assert(start + count <= Elements(dst->cso)); if (samplers) { for (i = 0; i < count; i++) { if (dst->cso[start + i] != samplers[i]) { dst->cso[start + i] = samplers[i]; /* * This function is sometimes called to reduce the number of bound * samplers. Do not consider that as a state change (and create a * new array of SAMPLER_STATE). */ if (samplers[i]) changed = true; } } } else { for (i = 0; i < count; i++) dst->cso[start + i] = NULL; } if (changed) { switch (shader) { case PIPE_SHADER_VERTEX: vec->dirty |= ILO_DIRTY_SAMPLER_VS; break; case PIPE_SHADER_GEOMETRY: vec->dirty |= ILO_DIRTY_SAMPLER_GS; break; case PIPE_SHADER_FRAGMENT: vec->dirty |= ILO_DIRTY_SAMPLER_FS; break; case PIPE_SHADER_COMPUTE: vec->dirty |= ILO_DIRTY_SAMPLER_CS; break; } } } static void ilo_delete_sampler_state(struct pipe_context *pipe, void *state) { FREE(state); } static void * ilo_create_rasterizer_state(struct pipe_context *pipe, const struct pipe_rasterizer_state *state) { const struct ilo_dev *dev = ilo_context(pipe)->dev; struct ilo_rasterizer_state *rast; struct ilo_state_raster_info *info; rast = CALLOC_STRUCT(ilo_rasterizer_state); assert(rast); rast->state = *state; info = &rast->info; info->clip.clip_enable = true; info->clip.stats_enable = true; info->clip.viewport_count = 1; info->clip.force_rtaindex_zero = true; info->clip.user_clip_enables = state->clip_plane_enable; info->clip.gb_test_enable = true; info->clip.xy_test_enable = true; info->clip.z_far_enable = state->depth_clip; info->clip.z_near_enable = state->depth_clip; info->clip.z_near_zero = state->clip_halfz; info->setup.first_vertex_provoking = state->flatshade_first; info->setup.viewport_transform = true; info->setup.scissor_enable = state->scissor; info->setup.msaa_enable = false; info->setup.line_msaa_enable = false; info->point.aa_enable = state->point_smooth; info->point.programmable_width = state->point_size_per_vertex; info->line.aa_enable = state->line_smooth; info->line.stipple_enable = state->line_stipple_enable; info->line.giq_enable = true; info->line.giq_last_pixel = state->line_last_pixel; info->tri.front_winding = ilo_translate_front_ccw(state->front_ccw); info->tri.cull_mode = ilo_translate_cull_face(state->cull_face); info->tri.fill_mode_front = ilo_translate_poly_mode(state->fill_front); info->tri.fill_mode_back = ilo_translate_poly_mode(state->fill_back); info->tri.depth_offset_format = GEN6_ZFORMAT_D24_UNORM_X8_UINT; info->tri.depth_offset_solid = state->offset_tri; info->tri.depth_offset_wireframe = state->offset_line; info->tri.depth_offset_point = state->offset_point; info->tri.poly_stipple_enable = state->poly_stipple_enable; info->scan.stats_enable = true; info->scan.sample_count = 1; info->scan.pixloc = ilo_translate_half_pixel_center(state->half_pixel_center); info->scan.sample_mask = ~0u; info->scan.zw_interp = GEN6_ZW_INTERP_PIXEL; info->scan.barycentric_interps = GEN6_INTERP_PERSPECTIVE_PIXEL; info->scan.earlyz_control = GEN7_EDSC_NORMAL; info->scan.earlyz_op = ILO_STATE_RASTER_EARLYZ_NORMAL; info->scan.earlyz_stencil_clear = false; info->params.any_integer_rt = false; info->params.hiz_enable = true; info->params.point_width = (state->point_size == 0.0f) ? 1.0f : state->point_size; info->params.line_width = (state->line_width == 0.0f) ? 1.0f : state->line_width; info->params.depth_offset_scale = state->offset_scale; /* * Scale the constant term. The minimum representable value used by the HW * is not large enouch to be the minimum resolvable difference. */ info->params.depth_offset_const = state->offset_units * 2.0f; info->params.depth_offset_clamp = state->offset_clamp; ilo_state_raster_init(&rast->rs, dev, info); return rast; } static void ilo_bind_rasterizer_state(struct pipe_context *pipe, void *state) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; vec->rasterizer = state; vec->dirty |= ILO_DIRTY_RASTERIZER; } static void ilo_delete_rasterizer_state(struct pipe_context *pipe, void *state) { FREE(state); } static void * ilo_create_depth_stencil_alpha_state(struct pipe_context *pipe, const struct pipe_depth_stencil_alpha_state *state) { struct ilo_dsa_state *dsa; int i; dsa = CALLOC_STRUCT(ilo_dsa_state); assert(dsa); dsa->depth.cv_has_buffer = true; dsa->depth.test_enable = state->depth.enabled; dsa->depth.write_enable = state->depth.writemask; dsa->depth.test_func = ilo_translate_compare_func(state->depth.func); dsa->stencil.cv_has_buffer = true; for (i = 0; i < ARRAY_SIZE(state->stencil); i++) { const struct pipe_stencil_state *stencil = &state->stencil[i]; struct ilo_state_cc_stencil_op_info *op; if (!stencil->enabled) break; if (i == 0) { dsa->stencil.test_enable = true; dsa->stencil_front.test_mask = stencil->valuemask; dsa->stencil_front.write_mask = stencil->writemask; op = &dsa->stencil.front; } else { dsa->stencil.twosided_enable = true; dsa->stencil_back.test_mask = stencil->valuemask; dsa->stencil_back.write_mask = stencil->writemask; op = &dsa->stencil.back; } op->test_func = ilo_translate_compare_func(stencil->func); op->fail_op = ilo_translate_stencil_op(stencil->fail_op); op->zfail_op = ilo_translate_stencil_op(stencil->zfail_op); op->zpass_op = ilo_translate_stencil_op(stencil->zpass_op); } dsa->alpha_test = state->alpha.enabled; dsa->alpha_ref = state->alpha.ref_value; dsa->alpha_func = ilo_translate_compare_func(state->alpha.func); return dsa; } static void ilo_bind_depth_stencil_alpha_state(struct pipe_context *pipe, void *state) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; vec->dsa = state; if (vec->dsa) { vec->cc_params.alpha_ref = vec->dsa->alpha_ref; vec->cc_params.stencil_front.test_mask = vec->dsa->stencil_front.test_mask; vec->cc_params.stencil_front.write_mask = vec->dsa->stencil_front.write_mask; vec->cc_params.stencil_back.test_mask = vec->dsa->stencil_back.test_mask; vec->cc_params.stencil_back.write_mask = vec->dsa->stencil_back.write_mask; } vec->dirty |= ILO_DIRTY_DSA; } static void ilo_delete_depth_stencil_alpha_state(struct pipe_context *pipe, void *state) { FREE(state); } static void * ilo_create_fs_state(struct pipe_context *pipe, const struct pipe_shader_state *state) { struct ilo_context *ilo = ilo_context(pipe); struct ilo_shader_state *shader; shader = ilo_shader_create_fs(ilo->dev, state, &ilo->state_vector); assert(shader); ilo_shader_cache_add(ilo->shader_cache, shader); return shader; } static void ilo_bind_fs_state(struct pipe_context *pipe, void *state) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; vec->fs = state; vec->dirty |= ILO_DIRTY_FS; } static void ilo_delete_fs_state(struct pipe_context *pipe, void *state) { struct ilo_context *ilo = ilo_context(pipe); struct ilo_shader_state *fs = (struct ilo_shader_state *) state; ilo_shader_cache_remove(ilo->shader_cache, fs); ilo_shader_destroy(fs); } static void * ilo_create_vs_state(struct pipe_context *pipe, const struct pipe_shader_state *state) { struct ilo_context *ilo = ilo_context(pipe); struct ilo_shader_state *shader; shader = ilo_shader_create_vs(ilo->dev, state, &ilo->state_vector); assert(shader); ilo_shader_cache_add(ilo->shader_cache, shader); return shader; } static void ilo_bind_vs_state(struct pipe_context *pipe, void *state) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; vec->vs = state; vec->dirty |= ILO_DIRTY_VS; } static void ilo_delete_vs_state(struct pipe_context *pipe, void *state) { struct ilo_context *ilo = ilo_context(pipe); struct ilo_shader_state *vs = (struct ilo_shader_state *) state; ilo_shader_cache_remove(ilo->shader_cache, vs); ilo_shader_destroy(vs); } static void * ilo_create_gs_state(struct pipe_context *pipe, const struct pipe_shader_state *state) { struct ilo_context *ilo = ilo_context(pipe); struct ilo_shader_state *shader; shader = ilo_shader_create_gs(ilo->dev, state, &ilo->state_vector); assert(shader); ilo_shader_cache_add(ilo->shader_cache, shader); return shader; } static void ilo_bind_gs_state(struct pipe_context *pipe, void *state) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; /* util_blitter may set this unnecessarily */ if (vec->gs == state) return; vec->gs = state; vec->dirty |= ILO_DIRTY_GS; } static void ilo_delete_gs_state(struct pipe_context *pipe, void *state) { struct ilo_context *ilo = ilo_context(pipe); struct ilo_shader_state *gs = (struct ilo_shader_state *) state; ilo_shader_cache_remove(ilo->shader_cache, gs); ilo_shader_destroy(gs); } static void * ilo_create_vertex_elements_state(struct pipe_context *pipe, unsigned num_elements, const struct pipe_vertex_element *elements) { const struct ilo_dev *dev = ilo_context(pipe)->dev; struct ilo_ve_state *ve; ve = MALLOC_STRUCT(ilo_ve_state); assert(ve); ilo_gpe_init_ve(dev, num_elements, elements, ve); return ve; } static void ilo_bind_vertex_elements_state(struct pipe_context *pipe, void *state) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; vec->ve = state; vec->dirty |= ILO_DIRTY_VE; } static void ilo_delete_vertex_elements_state(struct pipe_context *pipe, void *state) { struct ilo_ve_state *ve = state; FREE(ve); } static void ilo_set_blend_color(struct pipe_context *pipe, const struct pipe_blend_color *state) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; memcpy(vec->cc_params.blend_rgba, state->color, sizeof(state->color)); vec->dirty |= ILO_DIRTY_BLEND_COLOR; } static void ilo_set_stencil_ref(struct pipe_context *pipe, const struct pipe_stencil_ref *state) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; /* util_blitter may set this unnecessarily */ if (!memcmp(&vec->stencil_ref, state, sizeof(*state))) return; vec->stencil_ref = *state; vec->cc_params.stencil_front.test_ref = state->ref_value[0]; vec->cc_params.stencil_back.test_ref = state->ref_value[1]; vec->dirty |= ILO_DIRTY_STENCIL_REF; } static void ilo_set_sample_mask(struct pipe_context *pipe, unsigned sample_mask) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; /* util_blitter may set this unnecessarily */ if (vec->sample_mask == sample_mask) return; vec->sample_mask = sample_mask; vec->dirty |= ILO_DIRTY_SAMPLE_MASK; } static void ilo_set_clip_state(struct pipe_context *pipe, const struct pipe_clip_state *state) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; vec->clip = *state; vec->dirty |= ILO_DIRTY_CLIP; } static void ilo_set_constant_buffer(struct pipe_context *pipe, uint shader, uint index, struct pipe_constant_buffer *buf) { const struct ilo_dev *dev = ilo_context(pipe)->dev; struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; struct ilo_cbuf_state *cbuf = &vec->cbuf[shader]; const unsigned count = 1; unsigned i; assert(shader < Elements(vec->cbuf)); assert(index + count <= Elements(vec->cbuf[shader].cso)); if (buf) { for (i = 0; i < count; i++) { struct ilo_cbuf_cso *cso = &cbuf->cso[index + i]; pipe_resource_reference(&cso->resource, buf[i].buffer); cso->info.access = ILO_STATE_SURFACE_ACCESS_DP_DATA; cso->info.format = GEN6_FORMAT_R32G32B32A32_FLOAT; cso->info.format_size = 16; cso->info.struct_size = 16; cso->info.readonly = true; cso->info.size = buf[i].buffer_size; if (buf[i].buffer) { cso->info.buf = ilo_buffer(buf[i].buffer); cso->info.offset = buf[i].buffer_offset; memset(&cso->surface, 0, sizeof(cso->surface)); ilo_state_surface_init_for_buffer(&cso->surface, dev, &cso->info); cso->surface.bo = cso->info.buf->bo; cso->user_buffer = NULL; cbuf->enabled_mask |= 1 << (index + i); } else if (buf[i].user_buffer) { cso->info.buf = NULL; /* buffer_offset does not apply for user buffer */ cso->user_buffer = buf[i].user_buffer; cbuf->enabled_mask |= 1 << (index + i); } else { cso->info.buf = NULL; cso->info.size = 0; cso->user_buffer = NULL; cbuf->enabled_mask &= ~(1 << (index + i)); } } } else { for (i = 0; i < count; i++) { struct ilo_cbuf_cso *cso = &cbuf->cso[index + i]; pipe_resource_reference(&cso->resource, NULL); cso->info.buf = NULL; cso->info.size = 0; cso->user_buffer = NULL; cbuf->enabled_mask &= ~(1 << (index + i)); } } vec->dirty |= ILO_DIRTY_CBUF; } static void ilo_set_framebuffer_state(struct pipe_context *pipe, const struct pipe_framebuffer_state *state) { const struct ilo_dev *dev = ilo_context(pipe)->dev; struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; ilo_gpe_set_fb(dev, state, &vec->fb); vec->dirty |= ILO_DIRTY_FB; } static void ilo_set_polygon_stipple(struct pipe_context *pipe, const struct pipe_poly_stipple *state) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; vec->poly_stipple = *state; vec->dirty |= ILO_DIRTY_POLY_STIPPLE; } static void ilo_set_scissor_states(struct pipe_context *pipe, unsigned start_slot, unsigned num_scissors, const struct pipe_scissor_state *scissors) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; unsigned i; for (i = 0; i < num_scissors; i++) { struct ilo_state_viewport_scissor_info *info = &vec->viewport.scissors[start_slot + i]; if (scissors[i].minx < scissors[i].maxx && scissors[i].miny < scissors[i].maxy) { info->min_x = scissors[i].minx; info->min_y = scissors[i].miny; info->max_x = scissors[i].maxx - 1; info->max_y = scissors[i].maxy - 1; } else { info->min_x = 1; info->min_y = 1; info->max_x = 0; info->max_y = 0; } } vec->dirty |= ILO_DIRTY_SCISSOR; } static void ilo_set_viewport_states(struct pipe_context *pipe, unsigned start_slot, unsigned num_viewports, const struct pipe_viewport_state *viewports) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; if (viewports) { unsigned i; for (i = 0; i < num_viewports; i++) { struct ilo_state_viewport_matrix_info *info = &vec->viewport.matrices[start_slot + i]; memcpy(info->scale, viewports[i].scale, sizeof(info->scale)); memcpy(info->translate, viewports[i].translate, sizeof(info->translate)); } if (vec->viewport.params.count < start_slot + num_viewports) vec->viewport.params.count = start_slot + num_viewports; /* need to save viewport 0 for util_blitter */ if (!start_slot && num_viewports) vec->viewport.viewport0 = viewports[0]; } else { if (vec->viewport.params.count <= start_slot + num_viewports && vec->viewport.params.count > start_slot) vec->viewport.params.count = start_slot; } vec->dirty |= ILO_DIRTY_VIEWPORT; } static void ilo_set_sampler_views(struct pipe_context *pipe, unsigned shader, unsigned start, unsigned count, struct pipe_sampler_view **views) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; struct ilo_view_state *dst = &vec->view[shader]; unsigned i; assert(start + count <= Elements(dst->states)); if (views) { for (i = 0; i < count; i++) pipe_sampler_view_reference(&dst->states[start + i], views[i]); } else { for (i = 0; i < count; i++) pipe_sampler_view_reference(&dst->states[start + i], NULL); } if (dst->count <= start + count) { if (views) count += start; else count = start; while (count > 0 && !dst->states[count - 1]) count--; dst->count = count; } switch (shader) { case PIPE_SHADER_VERTEX: vec->dirty |= ILO_DIRTY_VIEW_VS; break; case PIPE_SHADER_GEOMETRY: vec->dirty |= ILO_DIRTY_VIEW_GS; break; case PIPE_SHADER_FRAGMENT: vec->dirty |= ILO_DIRTY_VIEW_FS; break; case PIPE_SHADER_COMPUTE: vec->dirty |= ILO_DIRTY_VIEW_CS; break; } } static void ilo_set_shader_resources(struct pipe_context *pipe, unsigned start, unsigned count, struct pipe_surface **surfaces) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; struct ilo_resource_state *dst = &vec->resource; unsigned i; assert(start + count <= Elements(dst->states)); if (surfaces) { for (i = 0; i < count; i++) pipe_surface_reference(&dst->states[start + i], surfaces[i]); } else { for (i = 0; i < count; i++) pipe_surface_reference(&dst->states[start + i], NULL); } if (dst->count <= start + count) { if (surfaces) count += start; else count = start; while (count > 0 && !dst->states[count - 1]) count--; dst->count = count; } vec->dirty |= ILO_DIRTY_RESOURCE; } static void ilo_set_vertex_buffers(struct pipe_context *pipe, unsigned start_slot, unsigned num_buffers, const struct pipe_vertex_buffer *buffers) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; unsigned i; /* no PIPE_CAP_USER_VERTEX_BUFFERS */ if (buffers) { for (i = 0; i < num_buffers; i++) assert(!buffers[i].user_buffer); } util_set_vertex_buffers_mask(vec->vb.states, &vec->vb.enabled_mask, buffers, start_slot, num_buffers); vec->dirty |= ILO_DIRTY_VB; } static void ilo_set_index_buffer(struct pipe_context *pipe, const struct pipe_index_buffer *state) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; if (state) { pipe_resource_reference(&vec->ib.buffer, state->buffer); vec->ib.user_buffer = state->user_buffer; vec->ib.offset = state->offset; vec->ib.index_size = state->index_size; } else { pipe_resource_reference(&vec->ib.buffer, NULL); vec->ib.user_buffer = NULL; vec->ib.offset = 0; vec->ib.index_size = 0; } vec->dirty |= ILO_DIRTY_IB; } static struct pipe_stream_output_target * ilo_create_stream_output_target(struct pipe_context *pipe, struct pipe_resource *res, unsigned buffer_offset, unsigned buffer_size) { struct pipe_stream_output_target *target; target = MALLOC_STRUCT(pipe_stream_output_target); assert(target); pipe_reference_init(&target->reference, 1); target->buffer = NULL; pipe_resource_reference(&target->buffer, res); target->context = pipe; target->buffer_offset = buffer_offset; target->buffer_size = buffer_size; return target; } static void ilo_set_stream_output_targets(struct pipe_context *pipe, unsigned num_targets, struct pipe_stream_output_target **targets, const unsigned *offset) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; unsigned i; unsigned append_bitmask = 0; if (!targets) num_targets = 0; /* util_blitter may set this unnecessarily */ if (!vec->so.count && !num_targets) return; for (i = 0; i < num_targets; i++) { pipe_so_target_reference(&vec->so.states[i], targets[i]); if (offset[i] == (unsigned)-1) append_bitmask |= 1 << i; } for (; i < vec->so.count; i++) pipe_so_target_reference(&vec->so.states[i], NULL); vec->so.count = num_targets; vec->so.append_bitmask = append_bitmask; vec->so.enabled = (vec->so.count > 0); vec->dirty |= ILO_DIRTY_SO; } static void ilo_stream_output_target_destroy(struct pipe_context *pipe, struct pipe_stream_output_target *target) { pipe_resource_reference(&target->buffer, NULL); FREE(target); } static struct pipe_sampler_view * ilo_create_sampler_view(struct pipe_context *pipe, struct pipe_resource *res, const struct pipe_sampler_view *templ) { const struct ilo_dev *dev = ilo_context(pipe)->dev; struct ilo_view_cso *view; view = CALLOC_STRUCT(ilo_view_cso); assert(view); view->base = *templ; pipe_reference_init(&view->base.reference, 1); view->base.texture = NULL; pipe_resource_reference(&view->base.texture, res); view->base.context = pipe; if (res->target == PIPE_BUFFER) { struct ilo_state_surface_buffer_info info; memset(&info, 0, sizeof(info)); info.buf = ilo_buffer(res); info.access = ILO_STATE_SURFACE_ACCESS_SAMPLER; info.format = ilo_format_translate_color(dev, templ->format); info.format_size = util_format_get_blocksize(templ->format); info.struct_size = info.format_size; info.readonly = true; info.offset = templ->u.buf.first_element * info.struct_size; info.size = (templ->u.buf.last_element - templ->u.buf.first_element + 1) * info.struct_size; ilo_state_surface_init_for_buffer(&view->surface, dev, &info); view->surface.bo = info.buf->bo; } else { struct ilo_texture *tex = ilo_texture(res); struct ilo_state_surface_image_info info; /* warn about degraded performance because of a missing binding flag */ if (tex->image.tiling == GEN6_TILING_NONE && !(tex->base.bind & PIPE_BIND_SAMPLER_VIEW)) { ilo_warn("creating sampler view for a resource " "not created for sampling\n"); } memset(&info, 0, sizeof(info)); info.img = &tex->image; info.access = ILO_STATE_SURFACE_ACCESS_SAMPLER; if (templ->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT && tex->image.separate_stencil) { info.format = ilo_format_translate_texture(dev, PIPE_FORMAT_Z32_FLOAT); } else { info.format = ilo_format_translate_texture(dev, templ->format); } info.is_cube_map = (tex->image.target == PIPE_TEXTURE_CUBE || tex->image.target == PIPE_TEXTURE_CUBE_ARRAY); info.is_array = util_resource_is_array_texture(&tex->base); info.readonly = true; info.level_base = templ->u.tex.first_level; info.level_count = templ->u.tex.last_level - templ->u.tex.first_level + 1; info.slice_base = templ->u.tex.first_layer; info.slice_count = templ->u.tex.last_layer - templ->u.tex.first_layer + 1; ilo_state_surface_init_for_image(&view->surface, dev, &info); view->surface.bo = info.img->bo; } return &view->base; } static void ilo_sampler_view_destroy(struct pipe_context *pipe, struct pipe_sampler_view *view) { pipe_resource_reference(&view->texture, NULL); FREE(view); } static struct pipe_surface * ilo_create_surface(struct pipe_context *pipe, struct pipe_resource *res, const struct pipe_surface *templ) { const struct ilo_dev *dev = ilo_context(pipe)->dev; struct ilo_texture *tex = ilo_texture(res); struct ilo_surface_cso *surf; surf = CALLOC_STRUCT(ilo_surface_cso); assert(surf); surf->base = *templ; pipe_reference_init(&surf->base.reference, 1); surf->base.texture = NULL; pipe_resource_reference(&surf->base.texture, &tex->base); surf->base.context = pipe; surf->base.width = u_minify(tex->base.width0, templ->u.tex.level); surf->base.height = u_minify(tex->base.height0, templ->u.tex.level); surf->is_rt = !util_format_is_depth_or_stencil(templ->format); if (surf->is_rt) { struct ilo_state_surface_image_info info; /* relax this? */ assert(tex->base.target != PIPE_BUFFER); memset(&info, 0, sizeof(info)); info.img = &tex->image; info.access = ILO_STATE_SURFACE_ACCESS_DP_RENDER; info.format = ilo_format_translate_render(dev, templ->format); info.is_array = util_resource_is_array_texture(&tex->base); info.level_base = templ->u.tex.level; info.level_count = 1; info.slice_base = templ->u.tex.first_layer; info.slice_count = templ->u.tex.last_layer - templ->u.tex.first_layer + 1; ilo_state_surface_init_for_image(&surf->u.rt, dev, &info); surf->u.rt.bo = info.img->bo; } else { struct ilo_state_zs_info info; assert(res->target != PIPE_BUFFER); memset(&info, 0, sizeof(info)); if (templ->format == PIPE_FORMAT_S8_UINT) { info.s_img = &tex->image; } else { info.z_img = &tex->image; info.s_img = (tex->separate_s8) ? &tex->separate_s8->image : NULL; info.hiz_enable = ilo_image_can_enable_aux(&tex->image, templ->u.tex.level); } info.level = templ->u.tex.level; info.slice_base = templ->u.tex.first_layer; info.slice_count = templ->u.tex.last_layer - templ->u.tex.first_layer + 1; ilo_state_zs_init(&surf->u.zs, dev, &info); if (info.z_img) { surf->u.zs.depth_bo = info.z_img->bo; if (info.hiz_enable) surf->u.zs.hiz_bo = info.z_img->aux.bo; } if (info.s_img) surf->u.zs.stencil_bo = info.s_img->bo; } return &surf->base; } static void ilo_surface_destroy(struct pipe_context *pipe, struct pipe_surface *surface) { pipe_resource_reference(&surface->texture, NULL); FREE(surface); } static void * ilo_create_compute_state(struct pipe_context *pipe, const struct pipe_compute_state *state) { struct ilo_context *ilo = ilo_context(pipe); struct ilo_shader_state *shader; shader = ilo_shader_create_cs(ilo->dev, state, &ilo->state_vector); assert(shader); ilo_shader_cache_add(ilo->shader_cache, shader); return shader; } static void ilo_bind_compute_state(struct pipe_context *pipe, void *state) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; vec->cs = state; vec->dirty |= ILO_DIRTY_CS; } static void ilo_delete_compute_state(struct pipe_context *pipe, void *state) { struct ilo_context *ilo = ilo_context(pipe); struct ilo_shader_state *cs = (struct ilo_shader_state *) state; ilo_shader_cache_remove(ilo->shader_cache, cs); ilo_shader_destroy(cs); } static void ilo_set_compute_resources(struct pipe_context *pipe, unsigned start, unsigned count, struct pipe_surface **surfaces) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; struct ilo_resource_state *dst = &vec->cs_resource; unsigned i; assert(start + count <= Elements(dst->states)); if (surfaces) { for (i = 0; i < count; i++) pipe_surface_reference(&dst->states[start + i], surfaces[i]); } else { for (i = 0; i < count; i++) pipe_surface_reference(&dst->states[start + i], NULL); } if (dst->count <= start + count) { if (surfaces) count += start; else count = start; while (count > 0 && !dst->states[count - 1]) count--; dst->count = count; } vec->dirty |= ILO_DIRTY_CS_RESOURCE; } static void ilo_set_global_binding(struct pipe_context *pipe, unsigned start, unsigned count, struct pipe_resource **resources, uint32_t **handles) { struct ilo_state_vector *vec = &ilo_context(pipe)->state_vector; struct ilo_global_binding_cso *dst; unsigned i; /* make room */ if (vec->global_binding.count < start + count) { if (resources) { const unsigned old_size = vec->global_binding.bindings.size; const unsigned new_size = sizeof(*dst) * (start + count); if (old_size < new_size) { util_dynarray_resize(&vec->global_binding.bindings, new_size); memset(vec->global_binding.bindings.data + old_size, 0, new_size - old_size); } } else { count = vec->global_binding.count - start; } } dst = util_dynarray_element(&vec->global_binding.bindings, struct ilo_global_binding_cso, start); if (resources) { for (i = 0; i < count; i++) { pipe_resource_reference(&dst[i].resource, resources[i]); dst[i].handle = handles[i]; } } else { for (i = 0; i < count; i++) { pipe_resource_reference(&dst[i].resource, NULL); dst[i].handle = NULL; } } if (vec->global_binding.count <= start + count) { dst = util_dynarray_begin(&vec->global_binding.bindings); if (resources) count += start; else count = start; while (count > 0 && !dst[count - 1].resource) count--; vec->global_binding.count = count; } vec->dirty |= ILO_DIRTY_GLOBAL_BINDING; } /** * Initialize state-related functions. */ void ilo_init_state_functions(struct ilo_context *ilo) { STATIC_ASSERT(ILO_STATE_COUNT <= 32); ilo->base.create_blend_state = ilo_create_blend_state; ilo->base.bind_blend_state = ilo_bind_blend_state; ilo->base.delete_blend_state = ilo_delete_blend_state; ilo->base.create_sampler_state = ilo_create_sampler_state; ilo->base.bind_sampler_states = ilo_bind_sampler_states; ilo->base.delete_sampler_state = ilo_delete_sampler_state; ilo->base.create_rasterizer_state = ilo_create_rasterizer_state; ilo->base.bind_rasterizer_state = ilo_bind_rasterizer_state; ilo->base.delete_rasterizer_state = ilo_delete_rasterizer_state; ilo->base.create_depth_stencil_alpha_state = ilo_create_depth_stencil_alpha_state; ilo->base.bind_depth_stencil_alpha_state = ilo_bind_depth_stencil_alpha_state; ilo->base.delete_depth_stencil_alpha_state = ilo_delete_depth_stencil_alpha_state; ilo->base.create_fs_state = ilo_create_fs_state; ilo->base.bind_fs_state = ilo_bind_fs_state; ilo->base.delete_fs_state = ilo_delete_fs_state; ilo->base.create_vs_state = ilo_create_vs_state; ilo->base.bind_vs_state = ilo_bind_vs_state; ilo->base.delete_vs_state = ilo_delete_vs_state; ilo->base.create_gs_state = ilo_create_gs_state; ilo->base.bind_gs_state = ilo_bind_gs_state; ilo->base.delete_gs_state = ilo_delete_gs_state; ilo->base.create_vertex_elements_state = ilo_create_vertex_elements_state; ilo->base.bind_vertex_elements_state = ilo_bind_vertex_elements_state; ilo->base.delete_vertex_elements_state = ilo_delete_vertex_elements_state; ilo->base.set_blend_color = ilo_set_blend_color; ilo->base.set_stencil_ref = ilo_set_stencil_ref; ilo->base.set_sample_mask = ilo_set_sample_mask; ilo->base.set_clip_state = ilo_set_clip_state; ilo->base.set_constant_buffer = ilo_set_constant_buffer; ilo->base.set_framebuffer_state = ilo_set_framebuffer_state; ilo->base.set_polygon_stipple = ilo_set_polygon_stipple; ilo->base.set_scissor_states = ilo_set_scissor_states; ilo->base.set_viewport_states = ilo_set_viewport_states; ilo->base.set_sampler_views = ilo_set_sampler_views; ilo->base.set_shader_resources = ilo_set_shader_resources; ilo->base.set_vertex_buffers = ilo_set_vertex_buffers; ilo->base.set_index_buffer = ilo_set_index_buffer; ilo->base.create_stream_output_target = ilo_create_stream_output_target; ilo->base.stream_output_target_destroy = ilo_stream_output_target_destroy; ilo->base.set_stream_output_targets = ilo_set_stream_output_targets; ilo->base.create_sampler_view = ilo_create_sampler_view; ilo->base.sampler_view_destroy = ilo_sampler_view_destroy; ilo->base.create_surface = ilo_create_surface; ilo->base.surface_destroy = ilo_surface_destroy; ilo->base.create_compute_state = ilo_create_compute_state; ilo->base.bind_compute_state = ilo_bind_compute_state; ilo->base.delete_compute_state = ilo_delete_compute_state; ilo->base.set_compute_resources = ilo_set_compute_resources; ilo->base.set_global_binding = ilo_set_global_binding; } void ilo_state_vector_init(const struct ilo_dev *dev, struct ilo_state_vector *vec) { struct ilo_state_urb_info urb_info; vec->sample_mask = ~0u; ilo_state_viewport_init_data_only(&vec->viewport.vp, dev, vec->viewport.vp_data, sizeof(vec->viewport.vp_data)); assert(vec->viewport.vp.array_size >= ILO_MAX_VIEWPORTS); vec->viewport.params.matrices = vec->viewport.matrices; vec->viewport.params.scissors = vec->viewport.scissors; ilo_state_surface_init_for_null(&vec->fb.null_rt, dev); ilo_state_zs_init_for_null(&vec->fb.null_zs, dev); ilo_state_sampler_init_disabled(&vec->disabled_sampler, dev); memset(&urb_info, 0, sizeof(urb_info)); ilo_state_urb_init(&vec->urb, dev, &urb_info); util_dynarray_init(&vec->global_binding.bindings); vec->dirty = ILO_DIRTY_ALL; } void ilo_state_vector_cleanup(struct ilo_state_vector *vec) { unsigned i, sh; for (i = 0; i < Elements(vec->vb.states); i++) { if (vec->vb.enabled_mask & (1 << i)) pipe_resource_reference(&vec->vb.states[i].buffer, NULL); } pipe_resource_reference(&vec->ib.buffer, NULL); pipe_resource_reference(&vec->ib.hw_resource, NULL); for (i = 0; i < vec->so.count; i++) pipe_so_target_reference(&vec->so.states[i], NULL); for (sh = 0; sh < PIPE_SHADER_TYPES; sh++) { for (i = 0; i < vec->view[sh].count; i++) { struct pipe_sampler_view *view = vec->view[sh].states[i]; pipe_sampler_view_reference(&view, NULL); } for (i = 0; i < Elements(vec->cbuf[sh].cso); i++) { struct ilo_cbuf_cso *cbuf = &vec->cbuf[sh].cso[i]; pipe_resource_reference(&cbuf->resource, NULL); } } for (i = 0; i < vec->resource.count; i++) pipe_surface_reference(&vec->resource.states[i], NULL); for (i = 0; i < vec->fb.state.nr_cbufs; i++) pipe_surface_reference(&vec->fb.state.cbufs[i], NULL); if (vec->fb.state.zsbuf) pipe_surface_reference(&vec->fb.state.zsbuf, NULL); for (i = 0; i < vec->cs_resource.count; i++) pipe_surface_reference(&vec->cs_resource.states[i], NULL); for (i = 0; i < vec->global_binding.count; i++) { struct ilo_global_binding_cso *cso = util_dynarray_element(&vec->global_binding.bindings, struct ilo_global_binding_cso, i); pipe_resource_reference(&cso->resource, NULL); } util_dynarray_fini(&vec->global_binding.bindings); } /** * Mark all states that have the resource dirty. */ void ilo_state_vector_resource_renamed(struct ilo_state_vector *vec, struct pipe_resource *res) { struct intel_bo *bo = ilo_resource_get_bo(res); uint32_t states = 0; unsigned sh, i; if (res->target == PIPE_BUFFER) { uint32_t vb_mask = vec->vb.enabled_mask; while (vb_mask) { const unsigned idx = u_bit_scan(&vb_mask); if (vec->vb.states[idx].buffer == res) { states |= ILO_DIRTY_VB; break; } } if (vec->ib.buffer == res) { states |= ILO_DIRTY_IB; /* * finalize_index_buffer() has an optimization that clears * ILO_DIRTY_IB when the HW states do not change. However, it fails * to flush the VF cache when the HW states do not change, but the * contents of the IB has changed. Here, we set the index size to an * invalid value to avoid the optimization. */ vec->ib.hw_index_size = 0; } for (i = 0; i < vec->so.count; i++) { if (vec->so.states[i]->buffer == res) { states |= ILO_DIRTY_SO; break; } } } for (sh = 0; sh < PIPE_SHADER_TYPES; sh++) { for (i = 0; i < vec->view[sh].count; i++) { struct ilo_view_cso *cso = (struct ilo_view_cso *) vec->view[sh].states[i]; if (cso->base.texture == res) { static const unsigned view_dirty_bits[PIPE_SHADER_TYPES] = { [PIPE_SHADER_VERTEX] = ILO_DIRTY_VIEW_VS, [PIPE_SHADER_FRAGMENT] = ILO_DIRTY_VIEW_FS, [PIPE_SHADER_GEOMETRY] = ILO_DIRTY_VIEW_GS, [PIPE_SHADER_COMPUTE] = ILO_DIRTY_VIEW_CS, }; cso->surface.bo = bo; states |= view_dirty_bits[sh]; break; } } if (res->target == PIPE_BUFFER) { for (i = 0; i < Elements(vec->cbuf[sh].cso); i++) { struct ilo_cbuf_cso *cbuf = &vec->cbuf[sh].cso[i]; if (cbuf->resource == res) { cbuf->surface.bo = bo; states |= ILO_DIRTY_CBUF; break; } } } } for (i = 0; i < vec->resource.count; i++) { struct ilo_surface_cso *cso = (struct ilo_surface_cso *) vec->resource.states[i]; if (cso->base.texture == res) { cso->u.rt.bo = bo; states |= ILO_DIRTY_RESOURCE; break; } } /* for now? */ if (res->target != PIPE_BUFFER) { for (i = 0; i < vec->fb.state.nr_cbufs; i++) { struct ilo_surface_cso *cso = (struct ilo_surface_cso *) vec->fb.state.cbufs[i]; if (cso && cso->base.texture == res) { cso->u.rt.bo = bo; states |= ILO_DIRTY_FB; break; } } if (vec->fb.state.zsbuf && vec->fb.state.zsbuf->texture == res) { struct ilo_surface_cso *cso = (struct ilo_surface_cso *) vec->fb.state.zsbuf; cso->u.zs.depth_bo = bo; states |= ILO_DIRTY_FB; } } for (i = 0; i < vec->cs_resource.count; i++) { struct ilo_surface_cso *cso = (struct ilo_surface_cso *) vec->cs_resource.states[i]; if (cso->base.texture == res) { cso->u.rt.bo = bo; states |= ILO_DIRTY_CS_RESOURCE; break; } } for (i = 0; i < vec->global_binding.count; i++) { struct ilo_global_binding_cso *cso = util_dynarray_element(&vec->global_binding.bindings, struct ilo_global_binding_cso, i); if (cso->resource == res) { states |= ILO_DIRTY_GLOBAL_BINDING; break; } } vec->dirty |= states; } void ilo_state_vector_dump_dirty(const struct ilo_state_vector *vec) { static const char *state_names[ILO_STATE_COUNT] = { [ILO_STATE_VB] = "VB", [ILO_STATE_VE] = "VE", [ILO_STATE_IB] = "IB", [ILO_STATE_VS] = "VS", [ILO_STATE_GS] = "GS", [ILO_STATE_SO] = "SO", [ILO_STATE_CLIP] = "CLIP", [ILO_STATE_VIEWPORT] = "VIEWPORT", [ILO_STATE_SCISSOR] = "SCISSOR", [ILO_STATE_RASTERIZER] = "RASTERIZER", [ILO_STATE_POLY_STIPPLE] = "POLY_STIPPLE", [ILO_STATE_SAMPLE_MASK] = "SAMPLE_MASK", [ILO_STATE_FS] = "FS", [ILO_STATE_DSA] = "DSA", [ILO_STATE_STENCIL_REF] = "STENCIL_REF", [ILO_STATE_BLEND] = "BLEND", [ILO_STATE_BLEND_COLOR] = "BLEND_COLOR", [ILO_STATE_FB] = "FB", [ILO_STATE_SAMPLER_VS] = "SAMPLER_VS", [ILO_STATE_SAMPLER_GS] = "SAMPLER_GS", [ILO_STATE_SAMPLER_FS] = "SAMPLER_FS", [ILO_STATE_SAMPLER_CS] = "SAMPLER_CS", [ILO_STATE_VIEW_VS] = "VIEW_VS", [ILO_STATE_VIEW_GS] = "VIEW_GS", [ILO_STATE_VIEW_FS] = "VIEW_FS", [ILO_STATE_VIEW_CS] = "VIEW_CS", [ILO_STATE_CBUF] = "CBUF", [ILO_STATE_RESOURCE] = "RESOURCE", [ILO_STATE_CS] = "CS", [ILO_STATE_CS_RESOURCE] = "CS_RESOURCE", [ILO_STATE_GLOBAL_BINDING] = "GLOBAL_BINDING", }; uint32_t dirty = vec->dirty; if (!dirty) { ilo_printf("no state is dirty\n"); return; } dirty &= (1U << ILO_STATE_COUNT) - 1; ilo_printf("%2d states are dirty:", util_bitcount(dirty)); while (dirty) { const enum ilo_state state = u_bit_scan(&dirty); ilo_printf(" %s", state_names[state]); } ilo_printf("\n"); }