diff --git a/docs/envvars.rst b/docs/envvars.rst index f2b246a15cc..a0c6f6f52a9 100644 --- a/docs/envvars.rst +++ b/docs/envvars.rst @@ -941,8 +941,6 @@ RADV driver environment variables disable NGG for GFX10 and GFX10.3 ``nonggc`` disable NGG culling on GPUs where it's enabled by default (GFX10.3+ only). - ``nooutoforder`` - disable out-of-order rasterization ``notccompatcmask`` disable TC-compat CMASK for MSAA surfaces ``noumr`` diff --git a/src/amd/vulkan/radv_cmd_buffer.c b/src/amd/vulkan/radv_cmd_buffer.c index 194864b6569..ae9f21417b3 100644 --- a/src/amd/vulkan/radv_cmd_buffer.c +++ b/src/amd/vulkan/radv_cmd_buffer.c @@ -2560,22 +2560,6 @@ radv_emit_depth_clamp_enable(struct radv_cmd_buffer *cmd_buffer) S_02800C_DISABLE_VIEWPORT_CLAMP(mode == RADV_DEPTH_CLAMP_MODE_DISABLED)); } -static unsigned -radv_get_pa_sc_mode_cntl_1(struct radv_cmd_buffer *cmd_buffer) -{ - const struct radv_graphics_pipeline *pipeline = cmd_buffer->state.graphics_pipeline; - unsigned rasterization_samples = radv_get_rasterization_samples(cmd_buffer); - unsigned pa_sc_mode_cntl_1 = pipeline->pa_sc_mode_cntl_1; - - if (rasterization_samples) { - unsigned ps_iter_samples = radv_get_ps_iter_samples(cmd_buffer); - - pa_sc_mode_cntl_1 |= S_028A4C_PS_ITER_SAMPLE(ps_iter_samples > 1); - } - - return pa_sc_mode_cntl_1; -} - static void radv_emit_rasterization_samples(struct radv_cmd_buffer *cmd_buffer) { @@ -2583,7 +2567,7 @@ radv_emit_rasterization_samples(struct radv_cmd_buffer *cmd_buffer) const struct radv_physical_device *pdevice = pipeline->base.device->physical_device; unsigned rasterization_samples = radv_get_rasterization_samples(cmd_buffer); const struct radv_rendering_state *render = &cmd_buffer->state.render; - unsigned pa_sc_mode_cntl_1 = radv_get_pa_sc_mode_cntl_1(cmd_buffer); + unsigned pa_sc_mode_cntl_1 = pipeline->pa_sc_mode_cntl_1; const struct radv_dynamic_state *d = &cmd_buffer->state.dynamic; unsigned spi_baryc_cntl = S_0286E0_FRONT_FACE_ALL_BITS(1); unsigned db_render_control = pipeline->db_render_control; @@ -2594,8 +2578,10 @@ radv_emit_rasterization_samples(struct radv_cmd_buffer *cmd_buffer) if (rasterization_samples > 1) { unsigned ps_iter_samples = radv_get_ps_iter_samples(cmd_buffer); - if (ps_iter_samples > 1) + if (ps_iter_samples > 1) { spi_baryc_cntl |= S_0286E0_POS_FLOAT_LOCATION(2); + pa_sc_mode_cntl_1 |= S_028A4C_PS_ITER_SAMPLE(1); + } } if (pdevice->rad_info.gfx_level >= GFX11) { @@ -3583,29 +3569,16 @@ radv_emit_index_buffer(struct radv_cmd_buffer *cmd_buffer, bool indirect) void radv_set_db_count_control(struct radv_cmd_buffer *cmd_buffer, bool enable_occlusion_queries) { - bool has_perfect_queries = cmd_buffer->state.perfect_occlusion_queries_enabled; - struct radv_graphics_pipeline *pipeline = cmd_buffer->state.graphics_pipeline; - uint32_t pa_sc_mode_cntl_1 = pipeline ? radv_get_pa_sc_mode_cntl_1(cmd_buffer) : 0; uint32_t db_count_control; if (!enable_occlusion_queries) { - if (cmd_buffer->device->physical_device->rad_info.gfx_level >= GFX7) { - if (G_028A4C_OUT_OF_ORDER_PRIMITIVE_ENABLE(pa_sc_mode_cntl_1) && - pipeline->disable_out_of_order_rast_for_occlusion && has_perfect_queries) { - /* Re-enable out-of-order rasterization if the - * bound pipeline supports it and if it's has - * been disabled before starting any perfect - * occlusion queries. - */ - radeon_set_context_reg(cmd_buffer->cs, R_028A4C_PA_SC_MODE_CNTL_1, pa_sc_mode_cntl_1); - } - } db_count_control = S_028004_ZPASS_INCREMENT_DISABLE(cmd_buffer->device->physical_device->rad_info.gfx_level < GFX11); } else { uint32_t sample_rate = util_logbase2(cmd_buffer->state.render.max_samples); bool gfx10_perfect = - cmd_buffer->device->physical_device->rad_info.gfx_level >= GFX10 && has_perfect_queries; + cmd_buffer->device->physical_device->rad_info.gfx_level >= GFX10 && + cmd_buffer->state.perfect_occlusion_queries_enabled; if (cmd_buffer->device->physical_device->rad_info.gfx_level >= GFX7) { /* Always enable PERFECT_ZPASS_COUNTS due to issues with partially @@ -3615,18 +3588,6 @@ radv_set_db_count_control(struct radv_cmd_buffer *cmd_buffer, bool enable_occlus S_028004_DISABLE_CONSERVATIVE_ZPASS_COUNTS(gfx10_perfect) | S_028004_SAMPLE_RATE(sample_rate) | S_028004_ZPASS_ENABLE(1) | S_028004_SLICE_EVEN_ENABLE(1) | S_028004_SLICE_ODD_ENABLE(1); - - if (G_028A4C_OUT_OF_ORDER_PRIMITIVE_ENABLE(pa_sc_mode_cntl_1) && - pipeline->disable_out_of_order_rast_for_occlusion && has_perfect_queries) { - /* If the bound pipeline has enabled - * out-of-order rasterization, we should - * disable it before starting any perfect - * occlusion queries. - */ - pa_sc_mode_cntl_1 &= C_028A4C_OUT_OF_ORDER_PRIMITIVE_ENABLE; - - radeon_set_context_reg(cmd_buffer->cs, R_028A4C_PA_SC_MODE_CNTL_1, pa_sc_mode_cntl_1); - } } else { db_count_control = S_028004_PERFECT_ZPASS_COUNTS(1) | S_028004_SAMPLE_RATE(sample_rate); } diff --git a/src/amd/vulkan/radv_debug.h b/src/amd/vulkan/radv_debug.h index 7ac385370b1..8e062908ba0 100644 --- a/src/amd/vulkan/radv_debug.h +++ b/src/amd/vulkan/radv_debug.h @@ -43,31 +43,30 @@ enum { RADV_DEBUG_SYNC_SHADERS = 1ull << 12, RADV_DEBUG_PREOPTIR = 1ull << 13, RADV_DEBUG_NO_DYNAMIC_BOUNDS = 1ull << 14, - RADV_DEBUG_NO_OUT_OF_ORDER = 1ull << 15, - RADV_DEBUG_INFO = 1ull << 16, - RADV_DEBUG_STARTUP = 1ull << 17, - RADV_DEBUG_CHECKIR = 1ull << 18, - RADV_DEBUG_NOBINNING = 1ull << 19, - RADV_DEBUG_NO_NGG = 1ull << 20, - RADV_DEBUG_DUMP_META_SHADERS = 1ull << 21, - RADV_DEBUG_NO_MEMORY_CACHE = 1ull << 22, - RADV_DEBUG_DISCARD_TO_DEMOTE = 1ull << 23, - RADV_DEBUG_LLVM = 1ull << 24, - RADV_DEBUG_FORCE_COMPRESS = 1ull << 25, - RADV_DEBUG_HANG = 1ull << 26, - RADV_DEBUG_IMG = 1ull << 27, - RADV_DEBUG_NO_UMR = 1ull << 28, - RADV_DEBUG_INVARIANT_GEOM = 1ull << 29, - RADV_DEBUG_NO_DISPLAY_DCC = 1ull << 30, - RADV_DEBUG_NO_TC_COMPAT_CMASK = 1ull << 31, - RADV_DEBUG_NO_VRS_FLAT_SHADING = 1ull << 32, - RADV_DEBUG_NO_ATOC_DITHERING = 1ull << 33, - RADV_DEBUG_NO_NGGC = 1ull << 34, - RADV_DEBUG_DUMP_PROLOGS = 1ull << 35, - RADV_DEBUG_NO_DMA_BLIT = 1ull << 36, - RADV_DEBUG_SPLIT_FMA = 1ull << 37, - RADV_DEBUG_DUMP_EPILOGS = 1ull << 38, - RADV_DEBUG_NO_FMASK = 1ull << 39, + RADV_DEBUG_INFO = 1ull << 15, + RADV_DEBUG_STARTUP = 1ull << 16, + RADV_DEBUG_CHECKIR = 1ull << 17, + RADV_DEBUG_NOBINNING = 1ull << 18, + RADV_DEBUG_NO_NGG = 1ull << 19, + RADV_DEBUG_DUMP_META_SHADERS = 1ull << 20, + RADV_DEBUG_NO_MEMORY_CACHE = 1ull << 21, + RADV_DEBUG_DISCARD_TO_DEMOTE = 1ull << 22, + RADV_DEBUG_LLVM = 1ull << 23, + RADV_DEBUG_FORCE_COMPRESS = 1ull << 24, + RADV_DEBUG_HANG = 1ull << 25, + RADV_DEBUG_IMG = 1ull << 26, + RADV_DEBUG_NO_UMR = 1ull << 27, + RADV_DEBUG_INVARIANT_GEOM = 1ull << 28, + RADV_DEBUG_NO_DISPLAY_DCC = 1ull << 29, + RADV_DEBUG_NO_TC_COMPAT_CMASK = 1ull << 30, + RADV_DEBUG_NO_VRS_FLAT_SHADING = 1ull << 31, + RADV_DEBUG_NO_ATOC_DITHERING = 1ull << 32, + RADV_DEBUG_NO_NGGC = 1ull << 33, + RADV_DEBUG_DUMP_PROLOGS = 1ull << 34, + RADV_DEBUG_NO_DMA_BLIT = 1ull << 35, + RADV_DEBUG_SPLIT_FMA = 1ull << 36, + RADV_DEBUG_DUMP_EPILOGS = 1ull << 37, + RADV_DEBUG_NO_FMASK = 1ull << 38, }; enum { diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c index 8486aa94fe7..b255438a863 100644 --- a/src/amd/vulkan/radv_device.c +++ b/src/amd/vulkan/radv_device.c @@ -884,10 +884,6 @@ radv_physical_device_try_create(struct radv_instance *instance, drmDevicePtr drm radv_get_driver_uuid(&device->driver_uuid); radv_get_device_uuid(&device->rad_info, &device->device_uuid); - device->out_of_order_rast_allowed = - device->rad_info.has_out_of_order_rast && - !(device->instance->debug_flags & RADV_DEBUG_NO_OUT_OF_ORDER); - device->dcc_msaa_allowed = (device->instance->perftest_flags & RADV_PERFTEST_DCC_MSAA); device->use_fmask = device->rad_info.gfx_level < GFX11 && @@ -1054,7 +1050,6 @@ static const struct debug_control radv_debug_options[] = { {"syncshaders", RADV_DEBUG_SYNC_SHADERS}, {"preoptir", RADV_DEBUG_PREOPTIR}, {"nodynamicbounds", RADV_DEBUG_NO_DYNAMIC_BOUNDS}, - {"nooutoforder", RADV_DEBUG_NO_OUT_OF_ORDER}, {"info", RADV_DEBUG_INFO}, {"startup", RADV_DEBUG_STARTUP}, {"checkir", RADV_DEBUG_CHECKIR}, diff --git a/src/amd/vulkan/radv_pipeline.c b/src/amd/vulkan/radv_pipeline.c index ccf9cb6f167..74bbc18c5a7 100644 --- a/src/amd/vulkan/radv_pipeline.c +++ b/src/amd/vulkan/radv_pipeline.c @@ -53,32 +53,14 @@ struct radv_blend_state { uint32_t blend_enable_4bit; - uint32_t cb_target_enabled_4bit; - uint32_t spi_shader_col_format; uint32_t cb_shader_mask; - - uint32_t commutative_4bit; - }; struct radv_depth_stencil_state { uint32_t db_shader_control; }; -struct radv_dsa_order_invariance { - /* Whether the final result in Z/S buffers is guaranteed to be - * invariant under changes to the order in which fragments arrive. - */ - bool zs; - - /* Whether the set of fragments that pass the combined Z/S test is - * guaranteed to be invariant under changes to the order in which - * fragments arrive. - */ - bool pass_set; -}; - static bool radv_is_raster_enabled(const struct radv_graphics_pipeline *pipeline, const VkGraphicsPipelineCreateInfo *pCreateInfo) @@ -595,32 +577,6 @@ radv_format_meta_fs_key(struct radv_device *device, VkFormat format) } } -static void -radv_blend_check_commutativity(struct radv_blend_state *blend, VkBlendOp op, VkBlendFactor src, - VkBlendFactor dst, unsigned chanmask) -{ - /* Src factor is allowed when it does not depend on Dst. */ - static const uint32_t src_allowed = - (1u << VK_BLEND_FACTOR_ONE) | (1u << VK_BLEND_FACTOR_SRC_COLOR) | - (1u << VK_BLEND_FACTOR_SRC_ALPHA) | (1u << VK_BLEND_FACTOR_SRC_ALPHA_SATURATE) | - (1u << VK_BLEND_FACTOR_CONSTANT_COLOR) | (1u << VK_BLEND_FACTOR_CONSTANT_ALPHA) | - (1u << VK_BLEND_FACTOR_SRC1_COLOR) | (1u << VK_BLEND_FACTOR_SRC1_ALPHA) | - (1u << VK_BLEND_FACTOR_ZERO) | (1u << VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR) | - (1u << VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA) | - (1u << VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR) | - (1u << VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA) | - (1u << VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) | (1u << VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA); - - if (dst == VK_BLEND_FACTOR_ONE && (src_allowed & (1u << src))) { - /* Addition is commutative, but floating point addition isn't - * associative: subtle changes can be introduced via different - * rounding. Be conservative, only enable for min and max. - */ - if (op == VK_BLEND_OP_MAX || op == VK_BLEND_OP_MIN) - blend->commutative_4bit |= chanmask; - } -} - static bool radv_can_enable_dual_src(const struct vk_color_blend_attachment_state *att) { @@ -672,7 +628,6 @@ radv_pipeline_init_blend_state(struct radv_graphics_pipeline *pipeline, if (i > 0 && key->ps.epilog.mrt0_is_dual_src) continue; - blend.cb_target_enabled_4bit |= 0xfu << (4 * i); if (!(pipeline->dynamic_states & RADV_DYNAMIC_COLOR_BLEND_ENABLE) && !state->cb->attachments[i].blend_enable) { pipeline->cb_blend_control[i] = blend_cntl; @@ -688,9 +643,6 @@ radv_pipeline_init_blend_state(struct radv_graphics_pipeline *pipeline, dstA = VK_BLEND_FACTOR_ONE; } - radv_blend_check_commutativity(&blend, eqRGB, srcRGB, dstRGB, 0x7u << (4 * i)); - radv_blend_check_commutativity(&blend, eqA, srcA, dstA, 0x8u << (4 * i)); - /* Blending optimizations for RB+. * These transformations don't change the behavior. * @@ -771,164 +723,6 @@ radv_pipeline_init_blend_state(struct radv_graphics_pipeline *pipeline, return blend; } -static bool -radv_is_depth_write_enabled(const struct vk_depth_stencil_state *ds) -{ - return ds->depth.test_enable && ds->depth.write_enable && - ds->depth.compare_op != VK_COMPARE_OP_NEVER; -} - -static bool -radv_writes_stencil(const struct vk_stencil_test_face_state *face) -{ - return face->write_mask && - (face->op.fail != VK_STENCIL_OP_KEEP || face->op.pass != VK_STENCIL_OP_KEEP || - face->op.depth_fail != VK_STENCIL_OP_KEEP); -} - -static bool -radv_is_stencil_write_enabled(const struct vk_depth_stencil_state *ds) -{ - return ds->stencil.test_enable && - (radv_writes_stencil(&ds->stencil.front) || radv_writes_stencil(&ds->stencil.back)); -} - -static bool -radv_order_invariant_stencil_op(VkStencilOp op) -{ - /* REPLACE is normally order invariant, except when the stencil - * reference value is written by the fragment shader. Tracking this - * interaction does not seem worth the effort, so be conservative. - */ - return op != VK_STENCIL_OP_INCREMENT_AND_CLAMP && op != VK_STENCIL_OP_DECREMENT_AND_CLAMP && - op != VK_STENCIL_OP_REPLACE; -} - -static bool -radv_order_invariant_stencil_state(const struct vk_stencil_test_face_state *face) -{ - /* Compute whether, assuming Z writes are disabled, this stencil state - * is order invariant in the sense that the set of passing fragments as - * well as the final stencil buffer result does not depend on the order - * of fragments. - */ - return !face->write_mask || - /* The following assumes that Z writes are disabled. */ - (face->op.compare == VK_COMPARE_OP_ALWAYS && - radv_order_invariant_stencil_op(face->op.pass) && - radv_order_invariant_stencil_op(face->op.depth_fail)) || - (face->op.compare == VK_COMPARE_OP_NEVER && - radv_order_invariant_stencil_op(face->op.fail)); -} - -static bool -radv_pipeline_has_dynamic_ds_states(const struct radv_graphics_pipeline *pipeline) -{ - return !!(pipeline->dynamic_states & (RADV_DYNAMIC_DEPTH_TEST_ENABLE | - RADV_DYNAMIC_DEPTH_WRITE_ENABLE | - RADV_DYNAMIC_DEPTH_COMPARE_OP | - RADV_DYNAMIC_STENCIL_TEST_ENABLE | - RADV_DYNAMIC_STENCIL_WRITE_MASK | - RADV_DYNAMIC_STENCIL_OP)); -} - -static bool -radv_pipeline_out_of_order_rast(struct radv_graphics_pipeline *pipeline, - const struct radv_blend_state *blend, - const struct vk_graphics_pipeline_state *state) -{ - unsigned colormask = blend->cb_target_enabled_4bit; - - if (!pipeline->base.device->physical_device->out_of_order_rast_allowed) - return false; - - /* Be conservative if a logic operation is enabled with color buffers. */ - if (colormask && (pipeline->dynamic_states & RADV_DYNAMIC_COLOR_BLEND_ENABLE) && - ((pipeline->dynamic_states & RADV_DYNAMIC_LOGIC_OP_ENABLE) || state->cb->logic_op_enable)) - return false; - - /* Be conservative if an extended dynamic depth/stencil state is - * enabled because the driver can't update out-of-order rasterization - * dynamically. - */ - if (radv_pipeline_has_dynamic_ds_states(pipeline)) - return false; - - /* Default depth/stencil invariance when no attachment is bound. */ - struct radv_dsa_order_invariance dsa_order_invariant = {.zs = true, .pass_set = true}; - - if (state->ds) { - bool has_stencil = state->rp->stencil_attachment_format != VK_FORMAT_UNDEFINED; - struct radv_dsa_order_invariance order_invariance[2]; - struct radv_shader *ps = pipeline->base.shaders[MESA_SHADER_FRAGMENT]; - - /* Compute depth/stencil order invariance in order to know if - * it's safe to enable out-of-order. - */ - bool zfunc_is_ordered = state->ds->depth.compare_op == VK_COMPARE_OP_NEVER || - state->ds->depth.compare_op == VK_COMPARE_OP_LESS || - state->ds->depth.compare_op == VK_COMPARE_OP_LESS_OR_EQUAL || - state->ds->depth.compare_op == VK_COMPARE_OP_GREATER || - state->ds->depth.compare_op == VK_COMPARE_OP_GREATER_OR_EQUAL; - bool depth_write_enabled = radv_is_depth_write_enabled(state->ds); - bool stencil_write_enabled = radv_is_stencil_write_enabled(state->ds); - bool ds_write_enabled = depth_write_enabled || stencil_write_enabled; - - bool nozwrite_and_order_invariant_stencil = - !ds_write_enabled || - (!depth_write_enabled && radv_order_invariant_stencil_state(&state->ds->stencil.front) && - radv_order_invariant_stencil_state(&state->ds->stencil.back)); - - order_invariance[1].zs = nozwrite_and_order_invariant_stencil || - (!stencil_write_enabled && zfunc_is_ordered); - order_invariance[0].zs = !depth_write_enabled || zfunc_is_ordered; - - order_invariance[1].pass_set = - nozwrite_and_order_invariant_stencil || - (!stencil_write_enabled && - (state->ds->depth.compare_op == VK_COMPARE_OP_ALWAYS || - state->ds->depth.compare_op == VK_COMPARE_OP_NEVER)); - order_invariance[0].pass_set = - !depth_write_enabled || - (state->ds->depth.compare_op == VK_COMPARE_OP_ALWAYS || - state->ds->depth.compare_op == VK_COMPARE_OP_NEVER); - - dsa_order_invariant = order_invariance[has_stencil]; - if (!dsa_order_invariant.zs) - return false; - - /* The set of PS invocations is always order invariant, - * except when early Z/S tests are requested. - */ - if (ps && ps->info.ps.writes_memory && ps->info.ps.early_fragment_test && - !dsa_order_invariant.pass_set) - return false; - - /* Determine if out-of-order rasterization should be disabled when occlusion queries are used. */ - pipeline->disable_out_of_order_rast_for_occlusion = !dsa_order_invariant.pass_set; - } - - /* No color buffers are enabled for writing. */ - if (!colormask) - return true; - - unsigned blendmask = colormask & blend->blend_enable_4bit; - - if (blendmask) { - /* Only commutative blending. */ - if (blendmask & ~blend->commutative_4bit) - return false; - - if (!dsa_order_invariant.pass_set) - return false; - } - - if (colormask & ~blendmask) - return false; - - return true; -} - static void radv_pipeline_init_multisample_state(struct radv_graphics_pipeline *pipeline, const struct radv_blend_state *blend, @@ -938,7 +732,8 @@ radv_pipeline_init_multisample_state(struct radv_graphics_pipeline *pipeline, const struct radv_physical_device *pdevice = pipeline->base.device->physical_device; struct radv_multisample_state *ms = &pipeline->ms; unsigned num_tile_pipes = pdevice->rad_info.num_tile_pipes; - bool out_of_order_rast = false; + bool out_of_order_rast = + state->rs->rasterization_order_amd == VK_RASTERIZATION_ORDER_RELAXED_AMD; /* From the Vulkan 1.1.129 spec, 26.7. Sample Shading: * @@ -967,18 +762,6 @@ radv_pipeline_init_multisample_state(struct radv_graphics_pipeline *pipeline, ms->sample_shading_enable = true; } - if (state->rs->rasterization_order_amd == VK_RASTERIZATION_ORDER_RELAXED_AMD) { - /* Out-of-order rasterization is explicitly enabled by the - * application. - */ - out_of_order_rast = true; - } else { - /* Determine if the driver can enable out-of-order - * rasterization internally. - */ - out_of_order_rast = radv_pipeline_out_of_order_rast(pipeline, blend, state); - } - pipeline->pa_sc_mode_cntl_1 = S_028A4C_WALK_FENCE_ENABLE(1) | // TODO linear dst fixes S_028A4C_WALK_FENCE_SIZE(num_tile_pipes == 2 ? 2 : 3) | diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h index 9ad94dfb576..176afe3fea8 100644 --- a/src/amd/vulkan/radv_private.h +++ b/src/amd/vulkan/radv_private.h @@ -276,8 +276,6 @@ struct radv_physical_device { int master_fd; struct wsi_device wsi_device; - bool out_of_order_rast_allowed; - /* Whether DCC should be enabled for MSAA textures. */ bool dcc_msaa_allowed; @@ -2038,7 +2036,6 @@ struct radv_graphics_pipeline { /* Used for rbplus */ uint32_t col_format_non_compacted; - bool disable_out_of_order_rast_for_occlusion; bool uses_drawid; bool uses_baseinstance; bool use_per_attribute_vb_descs;