mesa/src/imagination/csbgen/pvr_packet_helpers.h

231 lines
6.0 KiB
C

/*
* 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 <assert.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#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 */