From 58d4749e5683857d57b8b432559c9d837544ad88 Mon Sep 17 00:00:00 2001 From: Nanley Chery Date: Thu, 21 Nov 2019 09:00:02 -0800 Subject: [PATCH] isl: Add a module which manages aux resolves Provide a generic interface which manages aux resolves in ISL. The feature differences between this and what's in iris is: * Support for media compression. ISL_AUX_USAGE_MC behaves differently from many other usages of CCS, so it was useful to implement this support upfront, while designing the interfaces. * Optimizations for full-surface writes. For example, after a full-surface write occurs with ISL_AUX_USAGE_CCS_E in the PARTIAL_CLEAR state, isl_aux_state_transition_write() returns COMPRESSED_NO_CLEAR instead of COMPRESSED_CLEAR. A performance suggestion for main-surface-invalidating/replacing writes is given as a comment instead of adding a boolean to isl_aux_prepare_access(). This avoids extra validation and should be simple enough for the caller to handle. v2. Add assertions. (Jason) v3. Use switches in 2 more functions. (Jason) Store aux metadata in a static table. (Jason) Change prepare and finish function signatures. (Jason) Keep isl_aux_state_transition_* functions separate. v4. (Jason) Assert against resolving in AUX_INVALID. Rename aux_info struct to aux_usage_info. Drop the justification for each aux_usage_info field. Split out the NONE case in write function. Restructure tests to more easily confirm coverage. Rename access_compressed field to compressed. Make write behavior less ambiguous. v5. (Jason) Add more detail above WRITES_RESOLVE_AMBIGUATE. Add ISL_AUX_USAGE_MC to WritesResolveAmbiguate. Reviewed-by: Jason Ekstrand Part-of: --- src/intel/isl/isl.h | 51 +++ src/intel/isl/isl_aux_info.c | 213 +++++++++++ src/intel/isl/meson.build | 12 + src/intel/isl/tests/isl_aux_info_test.cpp | 426 ++++++++++++++++++++++ 4 files changed, 702 insertions(+) create mode 100644 src/intel/isl/isl_aux_info.c create mode 100644 src/intel/isl/tests/isl_aux_info_test.cpp diff --git a/src/intel/isl/isl.h b/src/intel/isl/isl.h index 9b96f7a5281..871e35b4cb8 100644 --- a/src/intel/isl/isl.h +++ b/src/intel/isl/isl.h @@ -1682,6 +1682,57 @@ isl_tiling_to_i915_tiling(enum isl_tiling tiling); enum isl_tiling isl_tiling_from_i915_tiling(uint32_t tiling); +/** + * Return an isl_aux_op needed to enable an access to occur in an + * isl_aux_state suitable for the isl_aux_usage. + * + * NOTE: If the access will invalidate the main surface, this function should + * not be called and the isl_aux_op of NONE should be used instead. + * Otherwise, an extra (but still lossless) ambiguate may occur. + * + * @invariant initial_state is possible with an isl_aux_usage compatible with + * the given usage. Two usages are compatible if it's possible to + * switch between them (e.g. CCS_E <-> CCS_D). + * @invariant fast_clear is false if the aux doesn't support fast clears. + */ +enum isl_aux_op +isl_aux_prepare_access(enum isl_aux_state initial_state, + enum isl_aux_usage usage, + bool fast_clear_supported); + +/** + * Return the isl_aux_state entered after performing an isl_aux_op. + * + * @invariant initial_state is possible with the given usage. + * @invariant op is possible with the given usage. + * @invariant op must not cause HW to read from an invalid aux. + */ +enum isl_aux_state +isl_aux_state_transition_aux_op(enum isl_aux_state initial_state, + enum isl_aux_usage usage, + enum isl_aux_op op); + +/** + * Return the isl_aux_state entered after performing a write. + * + * NOTE: full_surface should be true if the write covers the entire + * slice. Setting it to false in this case will still result in a + * correct (but imprecise) aux state. + * + * @invariant if usage is not ISL_AUX_USAGE_NONE, then initial_state is + * possible with the given usage. + * @invariant usage can be ISL_AUX_USAGE_NONE iff: + * * the main surface is valid, or + * * the main surface is being invalidated/replaced. + */ +enum isl_aux_state +isl_aux_state_transition_write(enum isl_aux_state initial_state, + enum isl_aux_usage usage, + bool full_surface); + +bool +isl_aux_usage_has_fast_clears(enum isl_aux_usage usage); + static inline bool isl_aux_usage_has_hiz(enum isl_aux_usage usage) { diff --git a/src/intel/isl/isl_aux_info.c b/src/intel/isl/isl_aux_info.c new file mode 100644 index 00000000000..4fe6e516fc3 --- /dev/null +++ b/src/intel/isl/isl_aux_info.c @@ -0,0 +1,213 @@ +/* + * Copyright 2019 Intel Corporation + * + * 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 (including the next + * paragraph) 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. + */ + +#include "isl/isl.h" + +/* How writes with an isl_aux_usage behave. */ +enum write_behavior { + /* Writes only touch the main surface. */ + WRITES_ONLY_TOUCH_MAIN = 0, + + /* Writes using the 3D engine are compressed. */ + WRITES_COMPRESS, + + /* Writes implicitly fully resolve the compression block and write the data + * uncompressed into the main surface. The resolved aux blocks are + * ambiguated and left in the pass-through state. + */ + WRITES_RESOLVE_AMBIGUATE, +}; + +/* A set of features supported by an isl_aux_usage. */ +struct aux_usage_info { + + /* How writes affect the surface(s) in use. */ + enum write_behavior write_behavior; + + /* Aux supports "real" compression beyond just fast-clears. */ + bool compressed; + + /* SW can perform ISL_AUX_OP_FAST_CLEAR. */ + bool fast_clear; + + /* SW can perform ISL_AUX_OP_PARTIAL_RESOLVE. */ + bool partial_resolve; + + /* Performing ISL_AUX_OP_FULL_RESOLVE includes ISL_AUX_OP_AMBIGUATE. */ + bool full_resolves_ambiguate; +}; + +#define AUX(wb, c, fc, pr, fra, type) \ + [ISL_AUX_USAGE_ ## type] = { WRITES_ ## wb, c, fc, pr, fra}, +#define Y true +#define x false +static const struct aux_usage_info info[] = { +/* write_behavior c fc pr fra */ + AUX( COMPRESS, Y, Y, x, x, HIZ) + AUX( COMPRESS, Y, Y, x, x, HIZ_CCS) + AUX( COMPRESS, Y, Y, Y, x, MCS) + AUX( COMPRESS, Y, Y, Y, x, MCS_CCS) + AUX( COMPRESS, Y, Y, Y, Y, CCS_E) + AUX(RESOLVE_AMBIGUATE, x, Y, x, Y, CCS_D) + AUX(RESOLVE_AMBIGUATE, Y, x, x, Y, MC) +}; +#undef x +#undef Y +#undef AUX + +ASSERTED static bool +aux_state_possible(enum isl_aux_state state, + enum isl_aux_usage usage) +{ + switch (state) { + case ISL_AUX_STATE_CLEAR: + case ISL_AUX_STATE_PARTIAL_CLEAR: + return info[usage].fast_clear; + case ISL_AUX_STATE_COMPRESSED_CLEAR: + return info[usage].fast_clear && info[usage].compressed; + case ISL_AUX_STATE_COMPRESSED_NO_CLEAR: + return info[usage].compressed; + case ISL_AUX_STATE_RESOLVED: + case ISL_AUX_STATE_PASS_THROUGH: + case ISL_AUX_STATE_AUX_INVALID: + return true; + } + + unreachable("Invalid aux state."); +} + +enum isl_aux_op +isl_aux_prepare_access(enum isl_aux_state initial_state, + enum isl_aux_usage usage, + bool fast_clear_supported) +{ + if (usage != ISL_AUX_USAGE_NONE) { + UNUSED const enum isl_aux_usage state_superset_usage = + usage == ISL_AUX_USAGE_CCS_D ? ISL_AUX_USAGE_CCS_E : usage; + assert(aux_state_possible(initial_state, state_superset_usage)); + } + assert(!fast_clear_supported || info[usage].fast_clear); + + switch (initial_state) { + case ISL_AUX_STATE_COMPRESSED_CLEAR: + if (!info[usage].compressed) + return ISL_AUX_OP_FULL_RESOLVE; + /* Fall-through */ + case ISL_AUX_STATE_CLEAR: + case ISL_AUX_STATE_PARTIAL_CLEAR: + return fast_clear_supported ? + ISL_AUX_OP_NONE : + info[usage].partial_resolve ? + ISL_AUX_OP_PARTIAL_RESOLVE : ISL_AUX_OP_FULL_RESOLVE; + case ISL_AUX_STATE_COMPRESSED_NO_CLEAR: + return info[usage].compressed ? + ISL_AUX_OP_NONE : ISL_AUX_OP_FULL_RESOLVE; + case ISL_AUX_STATE_RESOLVED: + case ISL_AUX_STATE_PASS_THROUGH: + return ISL_AUX_OP_NONE; + case ISL_AUX_STATE_AUX_INVALID: + return info[usage].write_behavior == WRITES_ONLY_TOUCH_MAIN ? + ISL_AUX_OP_NONE : ISL_AUX_OP_AMBIGUATE; + } + + unreachable("Invalid aux state."); +} + +enum isl_aux_state +isl_aux_state_transition_aux_op(enum isl_aux_state initial_state, + enum isl_aux_usage usage, + enum isl_aux_op op) +{ + assert(aux_state_possible(initial_state, usage)); + assert(usage != ISL_AUX_USAGE_NONE || op == ISL_AUX_OP_NONE); + + switch (op) { + case ISL_AUX_OP_NONE: + return initial_state; + case ISL_AUX_OP_FAST_CLEAR: + assert(info[usage].fast_clear); + return ISL_AUX_STATE_CLEAR; + case ISL_AUX_OP_PARTIAL_RESOLVE: + assert(isl_aux_state_has_valid_aux(initial_state)); + assert(info[usage].partial_resolve); + return initial_state == ISL_AUX_STATE_CLEAR || + initial_state == ISL_AUX_STATE_PARTIAL_CLEAR || + initial_state == ISL_AUX_STATE_COMPRESSED_CLEAR ? + ISL_AUX_STATE_COMPRESSED_NO_CLEAR : initial_state; + case ISL_AUX_OP_FULL_RESOLVE: + assert(isl_aux_state_has_valid_aux(initial_state)); + return info[usage].full_resolves_ambiguate || + initial_state == ISL_AUX_STATE_PASS_THROUGH ? + ISL_AUX_STATE_PASS_THROUGH : ISL_AUX_STATE_RESOLVED; + case ISL_AUX_OP_AMBIGUATE: + return ISL_AUX_STATE_PASS_THROUGH; + } + + unreachable("Invalid aux op."); +} + +enum isl_aux_state +isl_aux_state_transition_write(enum isl_aux_state initial_state, + enum isl_aux_usage usage, + bool full_surface) +{ + if (info[usage].write_behavior == WRITES_ONLY_TOUCH_MAIN) { + assert(full_surface || isl_aux_state_has_valid_primary(initial_state)); + + return initial_state == ISL_AUX_STATE_PASS_THROUGH ? + ISL_AUX_STATE_PASS_THROUGH : ISL_AUX_STATE_AUX_INVALID; + } + + assert(isl_aux_state_has_valid_aux(initial_state)); + assert(aux_state_possible(initial_state, usage)); + assert(info[usage].write_behavior == WRITES_COMPRESS || + info[usage].write_behavior == WRITES_RESOLVE_AMBIGUATE); + + if (full_surface) { + return info[usage].write_behavior == WRITES_COMPRESS ? + ISL_AUX_STATE_COMPRESSED_NO_CLEAR : ISL_AUX_STATE_PASS_THROUGH; + } + + switch (initial_state) { + case ISL_AUX_STATE_CLEAR: + case ISL_AUX_STATE_PARTIAL_CLEAR: + return info[usage].write_behavior == WRITES_COMPRESS ? + ISL_AUX_STATE_COMPRESSED_CLEAR : ISL_AUX_STATE_PARTIAL_CLEAR; + case ISL_AUX_STATE_RESOLVED: + case ISL_AUX_STATE_PASS_THROUGH: + return info[usage].write_behavior == WRITES_COMPRESS ? + ISL_AUX_STATE_COMPRESSED_NO_CLEAR : initial_state; + case ISL_AUX_STATE_COMPRESSED_CLEAR: + case ISL_AUX_STATE_COMPRESSED_NO_CLEAR: + case ISL_AUX_STATE_AUX_INVALID: + return initial_state; + } + + unreachable("Invalid aux state."); +} + +bool +isl_aux_usage_has_fast_clears(enum isl_aux_usage usage) +{ + return info[usage].fast_clear; +} diff --git a/src/intel/isl/meson.build b/src/intel/isl/meson.build index d3003ac6a01..7d3e4ffc927 100644 --- a/src/intel/isl/meson.build +++ b/src/intel/isl/meson.build @@ -111,6 +111,7 @@ endif libisl_files = files( 'isl.c', 'isl.h', + 'isl_aux_info.c', 'isl_drm.c', 'isl_genX_priv.h', 'isl_format.c', @@ -138,4 +139,15 @@ if with_tests ), suite : ['intel'], ) + test( + 'isl_aux_info', + executable( + 'isl_aux_info_test', + 'tests/isl_aux_info_test.cpp', + dependencies : [dep_m, idep_gtest, idep_mesautil], + include_directories : [inc_common, inc_intel], + link_with : [libisl], + ), + suite : ['intel'], + ) endif diff --git a/src/intel/isl/tests/isl_aux_info_test.cpp b/src/intel/isl/tests/isl_aux_info_test.cpp new file mode 100644 index 00000000000..c1c4e203e70 --- /dev/null +++ b/src/intel/isl/tests/isl_aux_info_test.cpp @@ -0,0 +1,426 @@ +/* + * Copyright 2019 Intel Corporation + * + * 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 (including the next + * paragraph) 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. + */ + +#include "gtest/gtest.h" +#include "isl/isl.h" + +#define ISL_AUX_OP_ASSERT ((enum isl_aux_op) 100) +#define ISL_AUX_STATE_ASSERT ((enum isl_aux_state) 100) + +#ifndef NDEBUG +#define ASSERTS_ENABLED true +#else +#define ASSERTS_ENABLED false +#endif + +void +PrintTo(const enum isl_aux_op &op, ::std::ostream* os) { + *os << (const char *[]) { + [ISL_AUX_OP_NONE ] = "ISL_AUX_OP_NONE", + [ISL_AUX_OP_FAST_CLEAR ] = "ISL_AUX_OP_FAST_CLEAR", + [ISL_AUX_OP_FULL_RESOLVE ] = "ISL_AUX_OP_FULL_RESOLVE", + [ISL_AUX_OP_PARTIAL_RESOLVE] = "ISL_AUX_OP_PARTIAL_RESOLVE", + [ISL_AUX_OP_AMBIGUATE ] = "ISL_AUX_OP_AMBIGUATE", + }[op]; +} + +#define E(state, usage, fc, op) \ +do { \ + if (ISL_AUX_OP_ ## op != ISL_AUX_OP_ASSERT) { \ + EXPECT_EQ(isl_aux_prepare_access(ISL_AUX_STATE_ ## state, \ + ISL_AUX_USAGE_ ## usage, fc), \ + ISL_AUX_OP_ ## op); \ + } else if (ASSERTS_ENABLED) { \ + EXPECT_DEATH(isl_aux_prepare_access(ISL_AUX_STATE_ ## state, \ + ISL_AUX_USAGE_ ## usage, fc), ""); \ + } \ +} while (0) + +TEST(PrepareAccess, CompressedFalseFastClearFalsePartialResolveFalse) { + E(CLEAR, NONE, false, FULL_RESOLVE); + E(CLEAR, NONE, true, ASSERT); + E(PARTIAL_CLEAR, NONE, false, FULL_RESOLVE); + E(PARTIAL_CLEAR, NONE, true, ASSERT); + E(COMPRESSED_CLEAR, NONE, false, FULL_RESOLVE); + E(COMPRESSED_CLEAR, NONE, true, ASSERT); + E(COMPRESSED_NO_CLEAR, NONE, false, FULL_RESOLVE); + E(COMPRESSED_NO_CLEAR, NONE, true, ASSERT); + E(RESOLVED, NONE, false, NONE); + E(RESOLVED, NONE, true, ASSERT); + E(PASS_THROUGH, NONE, false, NONE); + E(PASS_THROUGH, NONE, true, ASSERT); + E(AUX_INVALID, NONE, false, NONE); + E(AUX_INVALID, NONE, true, ASSERT); +} + +TEST(PrepareAccess, CompressedFalseFastClearTruePartialResolveFalse) { + E(CLEAR, CCS_D, false, FULL_RESOLVE); + E(CLEAR, CCS_D, true, NONE); + E(PARTIAL_CLEAR, CCS_D, false, FULL_RESOLVE); + E(PARTIAL_CLEAR, CCS_D, true, NONE); + E(COMPRESSED_CLEAR, CCS_D, false, FULL_RESOLVE); + E(COMPRESSED_CLEAR, CCS_D, true, FULL_RESOLVE); + E(COMPRESSED_NO_CLEAR, CCS_D, false, FULL_RESOLVE); + E(COMPRESSED_NO_CLEAR, CCS_D, true, FULL_RESOLVE); + E(RESOLVED, CCS_D, false, NONE); + E(RESOLVED, CCS_D, true, NONE); + E(PASS_THROUGH, CCS_D, false, NONE); + E(PASS_THROUGH, CCS_D, true, NONE); + E(AUX_INVALID, CCS_D, false, AMBIGUATE); + E(AUX_INVALID, CCS_D, true, AMBIGUATE); +} + +TEST(PrepareAccess, CompressedTrueFastClearFalsePartialResolveFalse) { + E(CLEAR, MC, false, ASSERT); + E(CLEAR, MC, true, ASSERT); + E(PARTIAL_CLEAR, MC, false, ASSERT); + E(PARTIAL_CLEAR, MC, true, ASSERT); + E(COMPRESSED_CLEAR, MC, false, ASSERT); + E(COMPRESSED_CLEAR, MC, true, ASSERT); + E(COMPRESSED_NO_CLEAR, MC, false, NONE); + E(COMPRESSED_NO_CLEAR, MC, true, ASSERT); + E(RESOLVED, MC, false, NONE); + E(RESOLVED, MC, true, ASSERT); + E(PASS_THROUGH, MC, false, NONE); + E(PASS_THROUGH, MC, true, ASSERT); + E(AUX_INVALID, MC, false, AMBIGUATE); + E(AUX_INVALID, MC, true, ASSERT); +} + +TEST(PrepareAccess, CompressedTrueFastClearTruePartialResolveFalse) { + E(CLEAR, HIZ, false, FULL_RESOLVE); + E(CLEAR, HIZ, true, NONE); + E(PARTIAL_CLEAR, HIZ, false, FULL_RESOLVE); + E(PARTIAL_CLEAR, HIZ, true, NONE); + E(COMPRESSED_CLEAR, HIZ, false, FULL_RESOLVE); + E(COMPRESSED_CLEAR, HIZ, true, NONE); + E(COMPRESSED_NO_CLEAR, HIZ, false, NONE); + E(COMPRESSED_NO_CLEAR, HIZ, true, NONE); + E(RESOLVED, HIZ, false, NONE); + E(RESOLVED, HIZ, true, NONE); + E(PASS_THROUGH, HIZ, false, NONE); + E(PASS_THROUGH, HIZ, true, NONE); + E(AUX_INVALID, HIZ, false, AMBIGUATE); + E(AUX_INVALID, HIZ, true, AMBIGUATE); +} + +TEST(PrepareAccess, CompressedTrueFastClearTruePartialResolveTrue) { + E(CLEAR, MCS, false, PARTIAL_RESOLVE); + E(CLEAR, MCS, true, NONE); + E(PARTIAL_CLEAR, MCS, false, PARTIAL_RESOLVE); + E(PARTIAL_CLEAR, MCS, true, NONE); + E(COMPRESSED_CLEAR, MCS, false, PARTIAL_RESOLVE); + E(COMPRESSED_CLEAR, MCS, true, NONE); + E(COMPRESSED_NO_CLEAR, MCS, false, NONE); + E(COMPRESSED_NO_CLEAR, MCS, true, NONE); + E(RESOLVED, MCS, false, NONE); + E(RESOLVED, MCS, true, NONE); + E(PASS_THROUGH, MCS, false, NONE); + E(PASS_THROUGH, MCS, true, NONE); + E(AUX_INVALID, MCS, false, AMBIGUATE); + E(AUX_INVALID, MCS, true, AMBIGUATE); +} + +void +PrintTo(const enum isl_aux_state &state, ::std::ostream* os) { + *os << (const char *[]) { + [ISL_AUX_STATE_CLEAR ] = "ISL_AUX_STATE_CLEAR", + [ISL_AUX_STATE_PARTIAL_CLEAR ] = "ISL_AUX_STATE_PARTIAL_CLEAR", + [ISL_AUX_STATE_COMPRESSED_CLEAR ] = "ISL_AUX_STATE_COMPRESSED_CLEAR", + [ISL_AUX_STATE_COMPRESSED_NO_CLEAR] = "ISL_AUX_STATE_COMPRESSED_NO_CLEAR", + [ISL_AUX_STATE_RESOLVED ] = "ISL_AUX_STATE_RESOLVED", + [ISL_AUX_STATE_PASS_THROUGH ] = "ISL_AUX_STATE_PASS_THROUGH", + [ISL_AUX_STATE_AUX_INVALID ] = "ISL_AUX_STATE_AUX_INVALID" + }[state]; +} + +#undef E +#define E(state1, usage, op, state2) \ +do { \ + if (ISL_AUX_STATE_ ## state2 != ISL_AUX_STATE_ASSERT) { \ + EXPECT_EQ(isl_aux_state_transition_aux_op(ISL_AUX_STATE_ ## state1, \ + ISL_AUX_USAGE_ ## usage, \ + ISL_AUX_OP_ ## op), \ + ISL_AUX_STATE_ ## state2); \ + } else if (ASSERTS_ENABLED) { \ + EXPECT_DEATH(isl_aux_state_transition_aux_op(ISL_AUX_STATE_ ## state1, \ + ISL_AUX_USAGE_ ## usage, \ + ISL_AUX_OP_ ## op), ""); \ + } \ +} while (0) + +/* The usages used in each test of this suite represent all combinations of + * ::fast_clear and ::full_resolves_ambiguate. + */ +TEST(StateTransitionAuxOp, None) { + E(CLEAR, NONE, NONE, ASSERT); + E(PARTIAL_CLEAR, NONE, NONE, ASSERT); + E(COMPRESSED_CLEAR, NONE, NONE, ASSERT); + E(COMPRESSED_NO_CLEAR, NONE, NONE, ASSERT); + E(RESOLVED, NONE, NONE, RESOLVED); + E(PASS_THROUGH, NONE, NONE, PASS_THROUGH); + E(AUX_INVALID, NONE, NONE, AUX_INVALID); + + E(CLEAR, MC, NONE, ASSERT); + E(PARTIAL_CLEAR, MC, NONE, ASSERT); + E(COMPRESSED_CLEAR, MC, NONE, ASSERT); + E(COMPRESSED_NO_CLEAR, MC, NONE, COMPRESSED_NO_CLEAR); + E(RESOLVED, MC, NONE, RESOLVED); + E(PASS_THROUGH, MC, NONE, PASS_THROUGH); + E(AUX_INVALID, MC, NONE, AUX_INVALID); + + E(CLEAR, HIZ, NONE, CLEAR); + E(PARTIAL_CLEAR, HIZ, NONE, PARTIAL_CLEAR); + E(COMPRESSED_CLEAR, HIZ, NONE, COMPRESSED_CLEAR); + E(COMPRESSED_NO_CLEAR, HIZ, NONE, COMPRESSED_NO_CLEAR); + E(RESOLVED, HIZ, NONE, RESOLVED); + E(PASS_THROUGH, HIZ, NONE, PASS_THROUGH); + E(AUX_INVALID, HIZ, NONE, AUX_INVALID); + + E(CLEAR, CCS_E, NONE, CLEAR); + E(PARTIAL_CLEAR, CCS_E, NONE, PARTIAL_CLEAR); + E(COMPRESSED_CLEAR, CCS_E, NONE, COMPRESSED_CLEAR); + E(COMPRESSED_NO_CLEAR, CCS_E, NONE, COMPRESSED_NO_CLEAR); + E(RESOLVED, CCS_E, NONE, RESOLVED); + E(PASS_THROUGH, CCS_E, NONE, PASS_THROUGH); + E(AUX_INVALID, CCS_E, NONE, AUX_INVALID); +} + +TEST(StateTransitionAuxOp, FastClear) { + E(CLEAR, NONE, FAST_CLEAR, ASSERT); + E(PARTIAL_CLEAR, NONE, FAST_CLEAR, ASSERT); + E(COMPRESSED_CLEAR, NONE, FAST_CLEAR, ASSERT); + E(COMPRESSED_NO_CLEAR, NONE, FAST_CLEAR, ASSERT); + E(RESOLVED, NONE, FAST_CLEAR, ASSERT); + E(PASS_THROUGH, NONE, FAST_CLEAR, ASSERT); + E(AUX_INVALID, NONE, FAST_CLEAR, ASSERT); + + E(CLEAR, MC, FAST_CLEAR, ASSERT); + E(PARTIAL_CLEAR, MC, FAST_CLEAR, ASSERT); + E(COMPRESSED_CLEAR, MC, FAST_CLEAR, ASSERT); + E(COMPRESSED_NO_CLEAR, MC, FAST_CLEAR, ASSERT); + E(RESOLVED, MC, FAST_CLEAR, ASSERT); + E(PASS_THROUGH, MC, FAST_CLEAR, ASSERT); + E(AUX_INVALID, MC, FAST_CLEAR, ASSERT); + + E(CLEAR, HIZ, FAST_CLEAR, CLEAR); + E(PARTIAL_CLEAR, HIZ, FAST_CLEAR, CLEAR); + E(COMPRESSED_CLEAR, HIZ, FAST_CLEAR, CLEAR); + E(COMPRESSED_NO_CLEAR, HIZ, FAST_CLEAR, CLEAR); + E(RESOLVED, HIZ, FAST_CLEAR, CLEAR); + E(PASS_THROUGH, HIZ, FAST_CLEAR, CLEAR); + E(AUX_INVALID, HIZ, FAST_CLEAR, CLEAR); + + E(CLEAR, CCS_E, FAST_CLEAR, CLEAR); + E(PARTIAL_CLEAR, CCS_E, FAST_CLEAR, CLEAR); + E(COMPRESSED_CLEAR, CCS_E, FAST_CLEAR, CLEAR); + E(COMPRESSED_NO_CLEAR, CCS_E, FAST_CLEAR, CLEAR); + E(RESOLVED, CCS_E, FAST_CLEAR, CLEAR); + E(PASS_THROUGH, CCS_E, FAST_CLEAR, CLEAR); + E(AUX_INVALID, CCS_E, FAST_CLEAR, CLEAR); +} + +TEST(StateTransitionAuxOp, PartialResolve) { + E(CLEAR, NONE, PARTIAL_RESOLVE, ASSERT); + E(PARTIAL_CLEAR, NONE, PARTIAL_RESOLVE, ASSERT); + E(COMPRESSED_CLEAR, NONE, PARTIAL_RESOLVE, ASSERT); + E(COMPRESSED_NO_CLEAR, NONE, PARTIAL_RESOLVE, ASSERT); + E(RESOLVED, NONE, PARTIAL_RESOLVE, ASSERT); + E(PASS_THROUGH, NONE, PARTIAL_RESOLVE, ASSERT); + E(AUX_INVALID, NONE, PARTIAL_RESOLVE, ASSERT); + + E(CLEAR, MC, PARTIAL_RESOLVE, ASSERT); + E(PARTIAL_CLEAR, MC, PARTIAL_RESOLVE, ASSERT); + E(COMPRESSED_CLEAR, MC, PARTIAL_RESOLVE, ASSERT); + E(COMPRESSED_NO_CLEAR, MC, PARTIAL_RESOLVE, ASSERT); + E(RESOLVED, MC, PARTIAL_RESOLVE, ASSERT); + E(PASS_THROUGH, MC, PARTIAL_RESOLVE, ASSERT); + E(AUX_INVALID, MC, PARTIAL_RESOLVE, ASSERT); + + E(CLEAR, HIZ, PARTIAL_RESOLVE, ASSERT); + E(PARTIAL_CLEAR, HIZ, PARTIAL_RESOLVE, ASSERT); + E(COMPRESSED_CLEAR, HIZ, PARTIAL_RESOLVE, ASSERT); + E(COMPRESSED_NO_CLEAR, HIZ, PARTIAL_RESOLVE, ASSERT); + E(RESOLVED, HIZ, PARTIAL_RESOLVE, ASSERT); + E(PASS_THROUGH, HIZ, PARTIAL_RESOLVE, ASSERT); + E(AUX_INVALID, HIZ, PARTIAL_RESOLVE, ASSERT); + + E(CLEAR, CCS_E, PARTIAL_RESOLVE, COMPRESSED_NO_CLEAR); + E(PARTIAL_CLEAR, CCS_E, PARTIAL_RESOLVE, COMPRESSED_NO_CLEAR); + E(COMPRESSED_CLEAR, CCS_E, PARTIAL_RESOLVE, COMPRESSED_NO_CLEAR); + E(COMPRESSED_NO_CLEAR, CCS_E, PARTIAL_RESOLVE, COMPRESSED_NO_CLEAR); + E(RESOLVED, CCS_E, PARTIAL_RESOLVE, RESOLVED); + E(PASS_THROUGH, CCS_E, PARTIAL_RESOLVE, PASS_THROUGH); + E(AUX_INVALID, CCS_E, PARTIAL_RESOLVE, ASSERT); +} + +TEST(StateTransitionAuxOp, FullResolve) { + E(CLEAR, NONE, FULL_RESOLVE, ASSERT); + E(PARTIAL_CLEAR, NONE, FULL_RESOLVE, ASSERT); + E(COMPRESSED_CLEAR, NONE, FULL_RESOLVE, ASSERT); + E(COMPRESSED_NO_CLEAR, NONE, FULL_RESOLVE, ASSERT); + E(RESOLVED, NONE, FULL_RESOLVE, ASSERT); + E(PASS_THROUGH, NONE, FULL_RESOLVE, ASSERT); + E(AUX_INVALID, NONE, FULL_RESOLVE, ASSERT); + + E(CLEAR, MC, FULL_RESOLVE, ASSERT); + E(PARTIAL_CLEAR, MC, FULL_RESOLVE, ASSERT); + E(COMPRESSED_CLEAR, MC, FULL_RESOLVE, ASSERT); + E(COMPRESSED_NO_CLEAR, MC, FULL_RESOLVE, PASS_THROUGH); + E(RESOLVED, MC, FULL_RESOLVE, PASS_THROUGH); + E(PASS_THROUGH, MC, FULL_RESOLVE, PASS_THROUGH); + E(AUX_INVALID, MC, FULL_RESOLVE, ASSERT); + + E(CLEAR, HIZ, FULL_RESOLVE, RESOLVED); + E(PARTIAL_CLEAR, HIZ, FULL_RESOLVE, RESOLVED); + E(COMPRESSED_CLEAR, HIZ, FULL_RESOLVE, RESOLVED); + E(COMPRESSED_NO_CLEAR, HIZ, FULL_RESOLVE, RESOLVED); + E(RESOLVED, HIZ, FULL_RESOLVE, RESOLVED); + E(PASS_THROUGH, HIZ, FULL_RESOLVE, PASS_THROUGH); + E(AUX_INVALID, HIZ, FULL_RESOLVE, ASSERT); + + E(CLEAR, CCS_E, FULL_RESOLVE, PASS_THROUGH); + E(PARTIAL_CLEAR, CCS_E, FULL_RESOLVE, PASS_THROUGH); + E(COMPRESSED_CLEAR, CCS_E, FULL_RESOLVE, PASS_THROUGH); + E(COMPRESSED_NO_CLEAR, CCS_E, FULL_RESOLVE, PASS_THROUGH); + E(RESOLVED, CCS_E, FULL_RESOLVE, PASS_THROUGH); + E(PASS_THROUGH, CCS_E, FULL_RESOLVE, PASS_THROUGH); + E(AUX_INVALID, CCS_E, FULL_RESOLVE, ASSERT); +} + +TEST(StateTransitionAuxOp, Ambiguate) { + E(CLEAR, NONE, AMBIGUATE, ASSERT); + E(PARTIAL_CLEAR, NONE, AMBIGUATE, ASSERT); + E(COMPRESSED_CLEAR, NONE, AMBIGUATE, ASSERT); + E(COMPRESSED_NO_CLEAR, NONE, AMBIGUATE, ASSERT); + E(RESOLVED, NONE, AMBIGUATE, ASSERT); + E(PASS_THROUGH, NONE, AMBIGUATE, ASSERT); + E(AUX_INVALID, NONE, AMBIGUATE, ASSERT); + + E(CLEAR, MC, AMBIGUATE, ASSERT); + E(PARTIAL_CLEAR, MC, AMBIGUATE, ASSERT); + E(COMPRESSED_CLEAR, MC, AMBIGUATE, ASSERT); + E(COMPRESSED_NO_CLEAR, MC, AMBIGUATE, PASS_THROUGH); + E(RESOLVED, MC, AMBIGUATE, PASS_THROUGH); + E(PASS_THROUGH, MC, AMBIGUATE, PASS_THROUGH); + E(AUX_INVALID, MC, AMBIGUATE, PASS_THROUGH); + + E(CLEAR, HIZ, AMBIGUATE, PASS_THROUGH); + E(PARTIAL_CLEAR, HIZ, AMBIGUATE, PASS_THROUGH); + E(COMPRESSED_CLEAR, HIZ, AMBIGUATE, PASS_THROUGH); + E(COMPRESSED_NO_CLEAR, HIZ, AMBIGUATE, PASS_THROUGH); + E(RESOLVED, HIZ, AMBIGUATE, PASS_THROUGH); + E(PASS_THROUGH, HIZ, AMBIGUATE, PASS_THROUGH); + E(AUX_INVALID, HIZ, AMBIGUATE, PASS_THROUGH); + + E(CLEAR, CCS_E, AMBIGUATE, PASS_THROUGH); + E(PARTIAL_CLEAR, CCS_E, AMBIGUATE, PASS_THROUGH); + E(COMPRESSED_CLEAR, CCS_E, AMBIGUATE, PASS_THROUGH); + E(COMPRESSED_NO_CLEAR, CCS_E, AMBIGUATE, PASS_THROUGH); + E(RESOLVED, CCS_E, AMBIGUATE, PASS_THROUGH); + E(PASS_THROUGH, CCS_E, AMBIGUATE, PASS_THROUGH); + E(AUX_INVALID, CCS_E, AMBIGUATE, PASS_THROUGH); +} + +#undef E +#define E(state1, usage, full_surface, state2) \ +do { \ + if (ISL_AUX_STATE_ ## state2 != ISL_AUX_STATE_ASSERT) { \ + EXPECT_EQ(isl_aux_state_transition_write(ISL_AUX_STATE_ ## state1, \ + ISL_AUX_USAGE_ ## usage, \ + full_surface), \ + ISL_AUX_STATE_ ## state2); \ + } else if (ASSERTS_ENABLED) { \ + EXPECT_DEATH(isl_aux_state_transition_write(ISL_AUX_STATE_ ## state1, \ + ISL_AUX_USAGE_ ## usage, \ + full_surface), ""); \ + } \ +} while (0) + +TEST(StateTransitionWrite, WritesOnlyTouchMain) { + E(CLEAR, NONE, false, ASSERT); + E(CLEAR, NONE, true, AUX_INVALID); + E(PARTIAL_CLEAR, NONE, false, ASSERT); + E(PARTIAL_CLEAR, NONE, true, AUX_INVALID); + E(COMPRESSED_CLEAR, NONE, false, ASSERT); + E(COMPRESSED_CLEAR, NONE, true, AUX_INVALID); + E(COMPRESSED_NO_CLEAR, NONE, false, ASSERT); + E(COMPRESSED_NO_CLEAR, NONE, true, AUX_INVALID); + E(RESOLVED, NONE, false, AUX_INVALID); + E(RESOLVED, NONE, true, AUX_INVALID); + E(PASS_THROUGH, NONE, false, PASS_THROUGH); + E(PASS_THROUGH, NONE, true, PASS_THROUGH); + E(AUX_INVALID, NONE, false, AUX_INVALID); + E(AUX_INVALID, NONE, true, AUX_INVALID); +} + +TEST(StateTransitionWrite, WritesCompress) { + E(CLEAR, MCS, false, COMPRESSED_CLEAR); + E(CLEAR, MCS, true, COMPRESSED_NO_CLEAR); + E(PARTIAL_CLEAR, MCS, false, COMPRESSED_CLEAR); + E(PARTIAL_CLEAR, MCS, true, COMPRESSED_NO_CLEAR); + E(COMPRESSED_CLEAR, MCS, false, COMPRESSED_CLEAR); + E(COMPRESSED_CLEAR, MCS, true, COMPRESSED_NO_CLEAR); + E(COMPRESSED_NO_CLEAR, MCS, false, COMPRESSED_NO_CLEAR); + E(COMPRESSED_NO_CLEAR, MCS, true, COMPRESSED_NO_CLEAR); + E(RESOLVED, MCS, false, COMPRESSED_NO_CLEAR); + E(RESOLVED, MCS, true, COMPRESSED_NO_CLEAR); + E(PASS_THROUGH, MCS, false, COMPRESSED_NO_CLEAR); + E(PASS_THROUGH, MCS, true, COMPRESSED_NO_CLEAR); + E(AUX_INVALID, MCS, false, ASSERT); + E(AUX_INVALID, MCS, true, ASSERT); +} + +TEST(StateTransitionWrite, WritesResolveAmbiguate) { + E(CLEAR, CCS_D, false, PARTIAL_CLEAR); + E(CLEAR, CCS_D, true, PASS_THROUGH); + E(PARTIAL_CLEAR, CCS_D, false, PARTIAL_CLEAR); + E(PARTIAL_CLEAR, CCS_D, true, PASS_THROUGH); + E(COMPRESSED_CLEAR, CCS_D, false, ASSERT); + E(COMPRESSED_CLEAR, CCS_D, true, ASSERT); + E(COMPRESSED_NO_CLEAR, CCS_D, false, ASSERT); + E(COMPRESSED_NO_CLEAR, CCS_D, true, ASSERT); + E(RESOLVED, CCS_D, false, RESOLVED); + E(RESOLVED, CCS_D, true, PASS_THROUGH); + E(PASS_THROUGH, CCS_D, false, PASS_THROUGH); + E(PASS_THROUGH, CCS_D, true, PASS_THROUGH); + E(AUX_INVALID, CCS_D, false, ASSERT); + E(AUX_INVALID, CCS_D, true, ASSERT); + + E(CLEAR, MC, false, ASSERT); + E(CLEAR, MC, true, ASSERT); + E(PARTIAL_CLEAR, MC, false, ASSERT); + E(PARTIAL_CLEAR, MC, true, ASSERT); + E(COMPRESSED_CLEAR, MC, false, ASSERT); + E(COMPRESSED_CLEAR, MC, true, ASSERT); + E(COMPRESSED_NO_CLEAR, MC, false, COMPRESSED_NO_CLEAR); + E(COMPRESSED_NO_CLEAR, MC, true, PASS_THROUGH); + E(RESOLVED, MC, false, RESOLVED); + E(RESOLVED, MC, true, PASS_THROUGH); + E(PASS_THROUGH, MC, false, PASS_THROUGH); + E(PASS_THROUGH, MC, true, PASS_THROUGH); + E(AUX_INVALID, MC, false, ASSERT); + E(AUX_INVALID, MC, true, ASSERT); +} + +#undef E -- 2.30.2