/* * Copyright © 2022 Imagination Technologies Ltd. * * based in part on anv driver which is: * Copyright © 2016 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. */ #ifndef PVR_PACKET_HELPERS_H #define PVR_PACKET_HELPERS_H #include #include #include #include #include #ifndef __pvr_validate_value # define __pvr_validate_value(x) #endif #ifdef NDEBUG # define NDEBUG_UNUSED __attribute__((unused)) #else # define NDEBUG_UNUSED #endif #ifndef __pvr_address_type # error #define __pvr_address_type before including this file #endif #ifndef __pvr_get_address # error #define __pvr_get_address before including this file #endif #ifndef __pvr_make_address # error #define __pvr_make_address before including this file #endif union __pvr_value { float f; uint32_t dw; }; static inline __attribute__((always_inline)) uint64_t __pvr_mbo(uint32_t start, uint32_t end) { return (~0ull >> (64 - (end - start + 1))) << start; } static inline __attribute__((always_inline)) uint64_t __pvr_uint(uint64_t v, uint32_t start, NDEBUG_UNUSED uint32_t end) { __pvr_validate_value(v); #ifndef NDEBUG const int width = end - start + 1; if (width < 64) { const uint64_t max = (1ull << width) - 1; assert(v <= max); } #endif return v << start; } static inline __attribute__((always_inline)) uint64_t __pvr_uint_unpack(uint64_t packed, uint32_t start, uint32_t end) { const int width = end - start + 1; const uint64_t mask = ~0ull >> (64 - width); return (packed >> start) & mask; } static inline __attribute__((always_inline)) uint64_t __pvr_sint(int64_t v, uint32_t start, uint32_t end) { const int width = end - start + 1; __pvr_validate_value(v); #ifndef NDEBUG if (width < 64) { const int64_t max = (1ll << (width - 1)) - 1; const int64_t min = -(1ll << (width - 1)); assert(min <= v && v <= max); } #endif const uint64_t mask = ~0ull >> (64 - width); return (v & mask) << start; } static inline __attribute__((always_inline)) int64_t __pvr_sint_unpack(uint64_t packed, uint32_t start, uint32_t end) { const int width = end - start + 1; const uint64_t mask = ~0ull >> (64 - width); return (int64_t)((packed >> start) & mask); } static inline __attribute__((always_inline)) uint64_t __pvr_offset(uint64_t v, NDEBUG_UNUSED uint32_t start, NDEBUG_UNUSED uint32_t end) { __pvr_validate_value(v); #ifndef NDEBUG uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start; assert((v & ~mask) == 0); #endif return v; } static inline __attribute__((always_inline)) uint64_t __pvr_offset_unpack(uint64_t packed, NDEBUG_UNUSED uint32_t start, NDEBUG_UNUSED uint32_t end) { #ifndef NDEBUG uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start; assert((packed & ~mask) == 0); #endif return packed; } static inline __attribute__((always_inline)) uint64_t __pvr_address(__pvr_address_type address, uint32_t shift, uint32_t start, uint32_t end) { uint64_t addr_u64 = __pvr_get_address(address); uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start; return ((addr_u64 >> shift) << start) & mask; } static inline __attribute__((always_inline)) __pvr_address_type __pvr_address_unpack(uint64_t packed, uint32_t shift, uint32_t start, uint32_t end) { uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start; uint64_t addr_u64 = ((packed & mask) >> start) << shift; return __pvr_make_address(addr_u64); } static inline __attribute__((always_inline)) uint32_t __pvr_float(float v) { __pvr_validate_value(v); return ((union __pvr_value){ .f = (v) }).dw; } static inline __attribute__((always_inline)) float __pvr_float_unpack(uint32_t packed) { return ((union __pvr_value){ .dw = (packed) }).f; } static inline __attribute__((always_inline)) uint64_t __pvr_sfixed(float v, uint32_t start, uint32_t end, uint32_t fract_bits) { __pvr_validate_value(v); const float factor = (1 << fract_bits); #ifndef NDEBUG const float max = ((1 << (end - start)) - 1) / factor; const float min = -(1 << (end - start)) / factor; assert(min <= v && v <= max); #endif const int64_t int_val = llroundf(v * factor); const uint64_t mask = ~0ull >> (64 - (end - start + 1)); return (int_val & mask) << start; } static inline __attribute__((always_inline)) uint64_t __pvr_ufixed(float v, uint32_t start, NDEBUG_UNUSED uint32_t end, uint32_t fract_bits) { __pvr_validate_value(v); const float factor = (1 << fract_bits); #ifndef NDEBUG const float max = ((1 << (end - start + 1)) - 1) / factor; const float min = 0.0f; assert(min <= v && v <= max); #endif const uint64_t uint_val = llroundf(v * factor); return uint_val << start; } #undef NDEBUG_UNUSED #endif /* PVR_PACKET_HELPERS_H */