fixes: texture unit mem access sometimes going to smem, bilinear texture filtering; new: cache req_id,
This commit is contained in:
79
sim/common/bitmanip.h
Normal file
79
sim/common/bitmanip.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
|
||||
constexpr uint32_t count_leading_zeros(uint32_t value) {
|
||||
return value ? __builtin_clz(value) : 32;
|
||||
}
|
||||
|
||||
constexpr uint32_t count_trailing_zeros(uint32_t value) {
|
||||
return value ? __builtin_ctz(value) : 32;
|
||||
}
|
||||
|
||||
constexpr bool ispow2(uint32_t value) {
|
||||
return value && !(value & (value - 1));
|
||||
}
|
||||
|
||||
constexpr uint32_t log2ceil(uint32_t value) {
|
||||
return 32 - count_leading_zeros(value - 1);
|
||||
}
|
||||
|
||||
inline unsigned log2up(uint32_t value) {
|
||||
return std::max<uint32_t>(1, log2ceil(value));
|
||||
}
|
||||
|
||||
constexpr unsigned log2floor(uint32_t value) {
|
||||
return 31 - count_leading_zeros(value);
|
||||
}
|
||||
|
||||
constexpr unsigned ceil2(uint32_t value) {
|
||||
return 32 - count_leading_zeros(value);
|
||||
}
|
||||
|
||||
inline uint64_t bit_clr(uint64_t bits, uint32_t index) {
|
||||
assert(index <= 63);
|
||||
return bits & ~(1ull << index);
|
||||
}
|
||||
|
||||
inline uint64_t bit_set(uint64_t bits, uint32_t index) {
|
||||
assert(index <= 63);
|
||||
return bits | (1ull << index);
|
||||
}
|
||||
|
||||
inline bool bit_get(uint64_t bits, uint32_t index) {
|
||||
assert(index <= 63);
|
||||
return (bits >> index) & 0x1;
|
||||
}
|
||||
|
||||
inline uint64_t bit_clrw(uint64_t bits, uint32_t start, uint32_t end) {
|
||||
assert(end >= start);
|
||||
assert(end <= 63);
|
||||
uint32_t shift = 63 - end;
|
||||
uint64_t mask = (0xffffffffffffffff << (shift + start)) >> shift;
|
||||
return bits & ~mask;
|
||||
}
|
||||
|
||||
inline uint64_t bit_setw(uint64_t bits, uint32_t start, uint32_t end, uint64_t value) {
|
||||
assert(end >= start);
|
||||
assert(end <= 63);
|
||||
uint32_t shift = 63 - end;
|
||||
uint64_t dirty = (value << (shift + start)) >> shift;
|
||||
return bit_clrw(bits, start, end) | dirty;
|
||||
}
|
||||
|
||||
inline uint64_t bit_getw(uint64_t bits, uint32_t start, uint32_t end) {
|
||||
assert(end >= start);
|
||||
assert(end <= 63);
|
||||
uint32_t shift = 63 - end;
|
||||
return (bits << shift) >> (shift + start);
|
||||
}
|
||||
|
||||
// Apply integer sign extension
|
||||
inline uint32_t sext32(uint32_t word, uint32_t width) {
|
||||
assert(width > 1);
|
||||
assert(width <= 32);
|
||||
uint32_t mask = (1 << width) - 1;
|
||||
return ((word >> (width - 1)) & 0x1) ? (word | ~mask) : word;
|
||||
}
|
||||
419
sim/common/fixed.h
Normal file
419
sim/common/fixed.h
Normal file
@@ -0,0 +1,419 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <assert.h>
|
||||
|
||||
template <uint32_t F, typename T = int32_t>
|
||||
class Fixed {
|
||||
private:
|
||||
|
||||
template <uint32_t F2, typename T2>
|
||||
struct Cast {
|
||||
private:
|
||||
template <bool isF2Bigger, bool isT2Bigger> struct Tag {};
|
||||
|
||||
inline static T Convert(T2 value, Tag<false, false>) {
|
||||
return static_cast<T>(value) << (F - F2);
|
||||
}
|
||||
|
||||
inline static T Convert(T2 value, Tag<false, true>) {
|
||||
return static_cast<T>(value) >> (F2 - F);
|
||||
}
|
||||
|
||||
inline static T Convert(T2 value, Tag<true, false>) {
|
||||
return static_cast<T>(value << (F - F2));
|
||||
}
|
||||
|
||||
inline static T Convert(T2 value, Tag<true, true>) {
|
||||
return static_cast<T>(value >> (F2 - F));
|
||||
}
|
||||
|
||||
public:
|
||||
inline static T Convert(T2 value) {
|
||||
return Convert(value, Tag<(sizeof(T2) > sizeof(T)), (F2 > F)>{});
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using data_type = T;
|
||||
|
||||
static constexpr uint32_t FRAC = F;
|
||||
static constexpr uint32_t INT = sizeof(T) * 8 - FRAC;
|
||||
static constexpr uint32_t HFRAC = FRAC >> 1;
|
||||
static constexpr T ONE = static_cast<T>(1) << FRAC;
|
||||
static constexpr T MASK = ONE - 1;
|
||||
static constexpr T IMASK = ~MASK;
|
||||
static constexpr T HALF = ONE >> 1;
|
||||
static constexpr T TWO = ONE << 1;
|
||||
|
||||
Fixed() {}
|
||||
|
||||
explicit Fixed(int64_t rhs)
|
||||
: data_(static_cast<T>(rhs << FRAC)) {
|
||||
assert((static_cast<int64_t>(rhs) << FRAC) == data_);
|
||||
}
|
||||
|
||||
explicit Fixed(uint64_t rhs)
|
||||
: data_(static_cast<T>(rhs << FRAC)) {
|
||||
assert((static_cast<int64_t>(rhs) << FRAC) == data_);
|
||||
}
|
||||
|
||||
explicit Fixed(int32_t rhs)
|
||||
: data_(static_cast<T>(rhs << FRAC)) {
|
||||
assert((static_cast<int64_t>(rhs) << FRAC) == data_);
|
||||
}
|
||||
|
||||
explicit Fixed(uint32_t rhs)
|
||||
: data_(static_cast<T>(rhs << FRAC)) {
|
||||
assert((static_cast<int64_t>(rhs) << FRAC) == data_);
|
||||
}
|
||||
|
||||
explicit Fixed(int16_t rhs)
|
||||
: data_(static_cast<T>(rhs << FRAC)) {
|
||||
assert((static_cast<int64_t>(rhs) << FRAC) == data_);
|
||||
}
|
||||
|
||||
explicit Fixed(uint16_t rhs)
|
||||
: data_(static_cast<T>(rhs << FRAC)) {
|
||||
assert((static_cast<int64_t>(rhs) << FRAC) == data_);
|
||||
}
|
||||
|
||||
explicit Fixed(int8_t rhs)
|
||||
: data_(static_cast<T>(rhs << FRAC)) {
|
||||
assert((static_cast<int64_t>(rhs) << FRAC) == data_);
|
||||
}
|
||||
|
||||
explicit Fixed(uint8_t rhs)
|
||||
: data_(static_cast<T>(rhs << FRAC)) {
|
||||
assert((static_cast<int64_t>(rhs) << FRAC) == data_);
|
||||
}
|
||||
|
||||
template <uint32_t F2, typename T2>
|
||||
explicit Fixed(Fixed<F2, T2> rhs)
|
||||
: data_(Cast<F2, T2>::Convert(rhs.data()))
|
||||
{}
|
||||
|
||||
explicit Fixed(float rhs)
|
||||
: data_(static_cast<T>(rhs * ONE)) {
|
||||
assert(data_ == static_cast<T>(rhs * ONE));
|
||||
}
|
||||
|
||||
bool operator==(Fixed rhs) const {
|
||||
return (data_ == rhs.data_);
|
||||
}
|
||||
|
||||
bool operator!=(Fixed rhs) const {
|
||||
return (data_ != rhs.data_);
|
||||
}
|
||||
|
||||
bool operator<(Fixed rhs) const {
|
||||
return (data_ < rhs.data_);
|
||||
}
|
||||
|
||||
bool operator<=(Fixed rhs) const {
|
||||
return (data_ <= rhs.data_);
|
||||
}
|
||||
|
||||
bool operator>(Fixed rhs) const {
|
||||
return (data_ > rhs.data_);
|
||||
}
|
||||
|
||||
bool operator>=(Fixed rhs) const {
|
||||
return (data_ >= rhs.data_);
|
||||
}
|
||||
|
||||
Fixed operator-() const {
|
||||
return make(-data_);
|
||||
}
|
||||
|
||||
Fixed operator+=(Fixed rhs) {
|
||||
*this = (*this) + rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Fixed operator-=(Fixed rhs) {
|
||||
*this = (*this) - rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Fixed operator*=(Fixed rhs) {
|
||||
*this = (*this) * rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Fixed operator/=(Fixed rhs) {
|
||||
*this = (*this) / rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <uint32_t F2, typename T2>
|
||||
Fixed operator*=(Fixed<F2, T2> rhs) {
|
||||
*this = (*this) * rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <uint32_t F2, typename T2>
|
||||
Fixed operator/=(Fixed<F2, T2> rhs) {
|
||||
*this = (*this) / rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Fixed operator*=(int32_t rhs) {
|
||||
*this = (*this) * rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Fixed operator*=(uint32_t rhs) {
|
||||
*this = (*this) * rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Fixed operator*=(float rhs) {
|
||||
*this = (*this) * rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Fixed operator/=(int32_t rhs) {
|
||||
*this = (*this) / rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Fixed operator/=(uint32_t rhs) {
|
||||
*this = (*this) / rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Fixed operator/=(float rhs) {
|
||||
*this = (*this) / rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend Fixed operator+(Fixed lhs, Fixed rhs) {
|
||||
assert((static_cast<int64_t>(lhs.data_) + rhs.data_) ==
|
||||
(lhs.data_ + rhs.data_));
|
||||
return Fixed::make(lhs.data_ + rhs.data_);
|
||||
}
|
||||
|
||||
friend Fixed operator-(Fixed lhs, Fixed rhs) {
|
||||
assert((static_cast<int64_t>(lhs.data_) - rhs.data_) ==
|
||||
(lhs.data_ - rhs.data_));
|
||||
return Fixed::make(lhs.data_ - rhs.data_);
|
||||
}
|
||||
|
||||
friend Fixed operator*(Fixed lhs, Fixed rhs) {
|
||||
return Fixed::make((static_cast<int64_t>(lhs.data_) * rhs.data_) >> FRAC);
|
||||
}
|
||||
|
||||
template <uint32_t F2, typename T2>
|
||||
friend Fixed operator*(Fixed lhs, Fixed<F2, T2> rhs) {
|
||||
return Fixed::make((static_cast<int64_t>(lhs.data_) * rhs.data()) >> F2);
|
||||
}
|
||||
|
||||
friend Fixed operator/(Fixed lhs, Fixed rhs) {
|
||||
assert(rhs.data_ != 0);
|
||||
return Fixed::make((static_cast<int64_t>(lhs.data_) << FRAC) / rhs.data_);
|
||||
}
|
||||
|
||||
template <uint32_t F2, typename T2>
|
||||
friend Fixed operator/(Fixed lhs, Fixed<F2, T2> rhs) {
|
||||
assert(rhs.data() != 0);
|
||||
return Fixed::make((static_cast<int64_t>(lhs.data_) << F2) / rhs.data());
|
||||
}
|
||||
|
||||
friend Fixed operator*(Fixed lhs, float rhs) {
|
||||
return static_cast<float>(lhs) * rhs;
|
||||
}
|
||||
|
||||
friend Fixed operator*(float lhs, Fixed rhs) {
|
||||
return lhs * static_cast<float>(rhs);
|
||||
}
|
||||
|
||||
friend Fixed operator/(Fixed lhs, float rhs) {
|
||||
return static_cast<float>(lhs) / rhs;
|
||||
}
|
||||
|
||||
friend Fixed operator/(float lhs, Fixed rhs) {
|
||||
return lhs / static_cast<float>(rhs);
|
||||
}
|
||||
|
||||
friend Fixed operator*(Fixed lhs, char rhs) {
|
||||
return lhs * static_cast<int32_t>(rhs);
|
||||
}
|
||||
|
||||
friend Fixed operator*(char lhs, Fixed rhs) {
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
friend Fixed operator/(Fixed lhs, char rhs) {
|
||||
return lhs / static_cast<int32_t>(rhs);
|
||||
}
|
||||
|
||||
friend Fixed operator/(char lhs, Fixed rhs) {
|
||||
return rhs / lhs;
|
||||
}
|
||||
|
||||
friend Fixed operator*(Fixed lhs, uint8_t rhs) {
|
||||
return lhs * static_cast<int32_t>(rhs);
|
||||
}
|
||||
|
||||
friend Fixed operator*(uint8_t lhs, Fixed rhs) {
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
friend Fixed operator/(Fixed lhs, uint8_t rhs) {
|
||||
return lhs / static_cast<int32_t>(rhs);
|
||||
}
|
||||
|
||||
friend Fixed operator/(uint8_t lhs, Fixed rhs) {
|
||||
return rhs / lhs;
|
||||
}
|
||||
|
||||
friend Fixed operator*(Fixed lhs, short rhs) {
|
||||
return lhs * static_cast<int32_t>(rhs);
|
||||
}
|
||||
|
||||
friend Fixed operator*(short lhs, Fixed rhs) {
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
friend Fixed operator/(Fixed lhs, short rhs) {
|
||||
return lhs / static_cast<int32_t>(rhs);
|
||||
}
|
||||
|
||||
friend Fixed operator/(short lhs, Fixed rhs) {
|
||||
return rhs / lhs;
|
||||
}
|
||||
|
||||
friend Fixed operator*(Fixed lhs, uint16_t rhs) {
|
||||
return lhs * static_cast<int32_t>(rhs);
|
||||
}
|
||||
|
||||
friend Fixed operator*(uint16_t lhs, Fixed rhs) {
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
friend Fixed operator/(Fixed lhs, uint16_t rhs) {
|
||||
return lhs / static_cast<int32_t>(rhs);
|
||||
}
|
||||
|
||||
friend Fixed operator/(uint16_t lhs, Fixed rhs) {
|
||||
return rhs / lhs;
|
||||
}
|
||||
|
||||
friend Fixed operator*(Fixed lhs, int32_t rhs) {
|
||||
auto value = static_cast<T>(lhs.data_ * rhs);
|
||||
assert((lhs.data_ * static_cast<int64_t>(rhs)) == value);
|
||||
return Fixed::make(value);
|
||||
}
|
||||
|
||||
friend Fixed operator*(int32_t lhs, Fixed rhs) {
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
friend Fixed operator/(Fixed lhs, int32_t rhs) {
|
||||
assert(rhs);
|
||||
auto value = static_cast<T>(lhs.data_ / rhs);
|
||||
return Fixed::make(value);
|
||||
}
|
||||
|
||||
friend Fixed operator/(int32_t lhs, Fixed rhs) {
|
||||
return rhs / lhs;
|
||||
}
|
||||
|
||||
friend Fixed operator*(Fixed lhs, uint32_t rhs) {
|
||||
auto value = static_cast<T>(lhs.data_ << rhs);
|
||||
assert((lhs.data_ << static_cast<int64_t>(rhs)) == value);
|
||||
return Fixed::make(value);
|
||||
}
|
||||
|
||||
friend Fixed operator*(uint32_t lhs, Fixed rhs) {
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
friend Fixed operator/(Fixed lhs, uint32_t rhs) {
|
||||
assert(rhs);
|
||||
auto value = static_cast<T>(lhs.data_ / rhs);
|
||||
return Fixed::make(value);
|
||||
}
|
||||
|
||||
friend Fixed operator/(uint32_t lhs, Fixed rhs) {
|
||||
return rhs / lhs;
|
||||
}
|
||||
|
||||
friend Fixed operator<<(Fixed lhs, int32_t rhs) {
|
||||
auto value = static_cast<T>(lhs.data_ << rhs);
|
||||
assert((lhs.data_ << static_cast<int64_t>(rhs)) == value);
|
||||
return Fixed::make(value);
|
||||
}
|
||||
|
||||
friend Fixed operator>>(Fixed lhs, int32_t rhs) {
|
||||
auto value = static_cast<T>(lhs.data_ >> rhs);
|
||||
return Fixed::make(value);
|
||||
}
|
||||
|
||||
friend Fixed operator<<(Fixed lhs, uint32_t rhs) {
|
||||
auto value = static_cast<T>(lhs.data_ << rhs);
|
||||
assert((lhs.data_ << static_cast<int64_t>(rhs)) == value);
|
||||
return Fixed::make(value);
|
||||
}
|
||||
|
||||
friend Fixed operator>>(Fixed lhs, uint32_t rhs) {
|
||||
auto value = static_cast<T>(lhs.data_ >> rhs);
|
||||
return Fixed::make(value);
|
||||
}
|
||||
|
||||
static Fixed make(T value) {
|
||||
Fixed ret;
|
||||
ret.data_ = value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
explicit operator int64_t() const {
|
||||
return static_cast<int64_t>(data_ >> F);
|
||||
}
|
||||
|
||||
explicit operator uint64_t() const {
|
||||
return static_cast<uint64_t>(data_ >> F);
|
||||
}
|
||||
|
||||
explicit operator int32_t() const {
|
||||
return static_cast<int32_t>(data_ >> F);
|
||||
}
|
||||
|
||||
explicit operator uint32_t() const {
|
||||
return static_cast<uint32_t>(data_ >> F);
|
||||
}
|
||||
|
||||
explicit operator int16_t() const {
|
||||
return static_cast<int16_t>(data_ >> F);
|
||||
}
|
||||
|
||||
explicit operator uint16_t() const {
|
||||
return static_cast<uint16_t>(data_ >> F);
|
||||
}
|
||||
|
||||
explicit operator int8_t() const {
|
||||
return static_cast<int8_t>(data_ >> F);
|
||||
}
|
||||
|
||||
explicit operator uint8_t() const {
|
||||
return static_cast<uint8_t>(data_ >> F);
|
||||
}
|
||||
|
||||
template <uint32_t F2, typename T2>
|
||||
explicit operator Fixed<F2, T2>() const {
|
||||
return Fixed<F2, T2>(*this);
|
||||
}
|
||||
|
||||
explicit operator float() const {
|
||||
return static_cast<float>(data_) / (static_cast<T>(1) << F);
|
||||
}
|
||||
|
||||
T data() const {
|
||||
return data_;
|
||||
}
|
||||
|
||||
private:
|
||||
T data_;
|
||||
};
|
||||
@@ -5,10 +5,9 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <assert.h>
|
||||
|
||||
namespace vortex {
|
||||
|
||||
class SimObjectBase;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -59,32 +58,44 @@ protected:
|
||||
template <typename Pkt>
|
||||
class SimPort : public SimPortBase {
|
||||
public:
|
||||
void send(const Pkt& pkt, uint64_t delay) const;
|
||||
void send(const Pkt& pkt, uint64_t delay) const;
|
||||
|
||||
bool read(Pkt* out) {
|
||||
if (!valid_)
|
||||
return false;
|
||||
*out = data_;
|
||||
valid_ = false;
|
||||
return true;
|
||||
void bind(SimPort<Pkt>* peer) {
|
||||
this->connect(peer);
|
||||
}
|
||||
|
||||
void unbind() {
|
||||
this->disconnect();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return queue_.empty();
|
||||
}
|
||||
|
||||
const Pkt& top() const {
|
||||
return queue_.front();
|
||||
}
|
||||
|
||||
Pkt& top() {
|
||||
return queue_.front();
|
||||
}
|
||||
|
||||
void pop() {
|
||||
queue_.pop();
|
||||
}
|
||||
|
||||
protected:
|
||||
SimPort(SimObjectBase* module)
|
||||
: SimPortBase(module)
|
||||
, valid_(false)
|
||||
{}
|
||||
|
||||
void write(const Pkt& data) {
|
||||
assert(!valid_);
|
||||
data_ = data;
|
||||
valid_ = true;
|
||||
void push(const Pkt& data) {
|
||||
queue_.push(data);
|
||||
}
|
||||
|
||||
SimPort& operator=(const SimPort&) = delete;
|
||||
|
||||
Pkt data_;
|
||||
bool valid_;
|
||||
std::queue<Pkt> queue_;
|
||||
|
||||
template <typename U> friend class SimPortEvent;
|
||||
};
|
||||
@@ -94,15 +105,7 @@ protected:
|
||||
template <typename Pkt>
|
||||
class SlavePort : public SimPort<Pkt> {
|
||||
public:
|
||||
SlavePort(SimObjectBase* module) : SimPort<Pkt>(module) {}
|
||||
|
||||
void bind(SlavePort<Pkt>* peer) {
|
||||
this->connect(peer);
|
||||
}
|
||||
|
||||
void unbind() {
|
||||
this->disconnect();
|
||||
}
|
||||
SlavePort(SimObjectBase* module) : SimPort<Pkt>(module) {}
|
||||
|
||||
protected:
|
||||
SlavePort& operator=(const SlavePort&) = delete;
|
||||
@@ -115,18 +118,6 @@ class MasterPort : public SimPort<Pkt> {
|
||||
public:
|
||||
MasterPort(SimObjectBase* module) : SimPort<Pkt>(module) {}
|
||||
|
||||
void bind(SlavePort<Pkt>* peer) {
|
||||
this->connect(peer);
|
||||
}
|
||||
|
||||
void bind(MasterPort<Pkt>* peer) {
|
||||
this->connect(peer);
|
||||
}
|
||||
|
||||
void unbind() {
|
||||
this->disconnect();
|
||||
}
|
||||
|
||||
protected:
|
||||
MasterPort& operator=(const MasterPort&) = delete;
|
||||
};
|
||||
@@ -194,7 +185,7 @@ public:
|
||||
{}
|
||||
|
||||
void fire() const override {
|
||||
const_cast<SimPort<Pkt>*>(port_)->write(pkt_);
|
||||
const_cast<SimPort<Pkt>*>(port_)->push(pkt_);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -382,6 +373,4 @@ template <typename T, typename Pkt>
|
||||
void SimObjectBase::schedule(T *obj, void (T::*entry)(const Pkt&), const Pkt& pkt, uint64_t delay) {
|
||||
auto callback = std::bind(entry, obj, std::placeholders::_1);
|
||||
SimPlatform::instance().schedule(callback, pkt, delay);
|
||||
}
|
||||
|
||||
}
|
||||
221
sim/common/texturing.h
Normal file
221
sim/common/texturing.h
Normal file
@@ -0,0 +1,221 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <fixed.h>
|
||||
#include <bitmanip.h>
|
||||
|
||||
enum class WrapMode {
|
||||
Clamp,
|
||||
Repeat,
|
||||
Mirror,
|
||||
};
|
||||
|
||||
enum class TexFormat {
|
||||
R8G8B8A8,
|
||||
R5G6B5,
|
||||
R4G4B4A4,
|
||||
L8A8,
|
||||
L8,
|
||||
A8,
|
||||
};
|
||||
|
||||
template <uint32_t F, typename T = int32_t>
|
||||
T Clamp(Fixed<F,T> fx, WrapMode mode) {
|
||||
switch (mode) {
|
||||
case WrapMode::Clamp: return (fx.data() < 0) ? 0 : ((fx.data() > Fixed<F,T>::MASK) ? Fixed<F,T>::MASK : fx.data());
|
||||
case WrapMode::Repeat: return (fx.data() & Fixed<F,T>::MASK);
|
||||
case WrapMode::Mirror: return (bit_get(fx.data(), Fixed<F,T>::FRAC) ? ~fx.data() : fx.data());
|
||||
default:
|
||||
std::abort();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32_t Stride(TexFormat format) {
|
||||
switch (format) {
|
||||
case TexFormat::R8G8B8A8:
|
||||
return 4;
|
||||
case TexFormat::R5G6B5:
|
||||
case TexFormat::R4G4B4A4:
|
||||
case TexFormat::L8A8:
|
||||
return 2;
|
||||
case TexFormat::L8:
|
||||
case TexFormat::A8:
|
||||
return 1;
|
||||
default:
|
||||
std::abort();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Unpack8888(TexFormat format,
|
||||
uint32_t texel,
|
||||
uint32_t* lo,
|
||||
uint32_t* hi) {
|
||||
switch (format) {
|
||||
case TexFormat::R8G8B8A8:
|
||||
*lo = texel & 0x00ff00ff;
|
||||
*hi = (texel >> 8) & 0x00ff00ff;
|
||||
break;
|
||||
case TexFormat::R5G6B5:
|
||||
case TexFormat::R4G4B4A4:
|
||||
*lo = texel;
|
||||
*hi= 0;
|
||||
break;
|
||||
case TexFormat::L8A8:
|
||||
*lo = (texel | (texel << 8)) & 0x00ff00ff;
|
||||
*hi = 0;
|
||||
break;
|
||||
case TexFormat::L8:
|
||||
*lo = (texel | (texel << 16)) & 0x07e0f81f;
|
||||
*hi = 0;
|
||||
break;
|
||||
case TexFormat::A8:
|
||||
*lo = (texel | (texel << 12)) & 0x0f0f0f0f;
|
||||
*hi = 0;
|
||||
break;
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32_t Pack8888(TexFormat format, uint32_t lo, uint32_t hi) {
|
||||
switch (format) {
|
||||
case TexFormat::R8G8B8A8:
|
||||
return (hi << 8) | lo;
|
||||
case TexFormat::R5G6B5:
|
||||
case TexFormat::R4G4B4A4:
|
||||
return lo;
|
||||
case TexFormat::L8A8:
|
||||
return (lo | (lo >> 8)) & 0xffff;
|
||||
case TexFormat::L8:
|
||||
return (lo | (lo >> 16)) & 0xffff;
|
||||
case TexFormat::A8:
|
||||
return (lo | (lo >> 12)) & 0xffff;
|
||||
default:
|
||||
std::abort();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Lerp8888(uint32_t al,
|
||||
uint32_t ah,
|
||||
uint32_t bl,
|
||||
uint32_t bh,
|
||||
uint32_t frac,
|
||||
uint32_t* lo,
|
||||
uint32_t* hi) {
|
||||
*lo = (al + (((bl - al) * frac) >> 8)) & 0x00ff00ff;
|
||||
*hi = (ah + (((bh - ah) * frac) >> 8)) & 0x00ff00ff;
|
||||
}
|
||||
|
||||
template <uint32_t F, typename T = int32_t>
|
||||
void TexAddressLinear(Fixed<F,T> fu,
|
||||
Fixed<F,T> fv,
|
||||
uint32_t log_width,
|
||||
uint32_t log_height,
|
||||
WrapMode wrapu,
|
||||
WrapMode wrapv,
|
||||
uint32_t* addr00,
|
||||
uint32_t* addr01,
|
||||
uint32_t* addr10,
|
||||
uint32_t* addr11,
|
||||
uint32_t* alpha,
|
||||
uint32_t* beta
|
||||
) {
|
||||
auto delta_x = Fixed<F,T>::make(Fixed<F,T>::HALF >> log_width);
|
||||
auto delta_y = Fixed<F,T>::make(Fixed<F,T>::HALF >> log_height);
|
||||
|
||||
uint32_t u0 = Clamp(fu - delta_x, wrapu);
|
||||
uint32_t u1 = Clamp(fu + delta_x, wrapu);
|
||||
uint32_t v0 = Clamp(fv - delta_y, wrapv);
|
||||
uint32_t v1 = Clamp(fv + delta_y, wrapv);
|
||||
|
||||
uint32_t shift_u = (Fixed<F,T>::FRAC - log_width);
|
||||
uint32_t shift_v = (Fixed<F,T>::FRAC - log_height);
|
||||
|
||||
uint32_t x0s = (u0 << 8) >> shift_u;
|
||||
uint32_t y0s = (v0 << 8) >> shift_v;
|
||||
|
||||
uint32_t x0 = x0s >> 8;
|
||||
uint32_t y0 = y0s >> 8;
|
||||
uint32_t x1 = u1 >> shift_u;
|
||||
uint32_t y1 = v1 >> shift_v;
|
||||
|
||||
*addr00 = x0 + (y0 << log_width);
|
||||
*addr01 = x1 + (y0 << log_width);
|
||||
*addr10 = x0 + (y1 << log_width);
|
||||
*addr11 = x1 + (y1 << log_width);
|
||||
|
||||
*alpha = x0s & 0xff;
|
||||
*beta = y0s & 0xff;
|
||||
|
||||
//printf("*** fu=0x%x, fv=0x%x, u0=0x%x, u1=0x%x, v0=0x%x, v1=0x%x, x0=0x%x, x1=0x%x, y0=0x%x, y1=0x%x, addr00=0x%x, addr01=0x%x, addr10=0x%x, addr11=0x%x\n", fu.data(), fv.data(), u0, u1, v0, v1, x0, x1, y0, y1, *addr00, *addr01, *addr10, *addr11);
|
||||
}
|
||||
|
||||
template <uint32_t F, typename T = int32_t>
|
||||
void TexAddressPoint(Fixed<F,T> fu,
|
||||
Fixed<F,T> fv,
|
||||
uint32_t log_width,
|
||||
uint32_t log_height,
|
||||
WrapMode wrapu,
|
||||
WrapMode wrapv,
|
||||
uint32_t* addr
|
||||
) {
|
||||
uint32_t u = Clamp(fu, wrapu);
|
||||
uint32_t v = Clamp(fv, wrapv);
|
||||
|
||||
uint32_t x = u >> (Fixed<F,T>::FRAC - log_width);
|
||||
uint32_t y = v >> (Fixed<F,T>::FRAC - log_height);
|
||||
|
||||
*addr = x + (y << log_width);
|
||||
|
||||
//printf("*** fu=0x%x, fv=0x%x, u=0x%x, v=0x%x, x=0x%x, y=0x%x, addr=0x%x\n", fu.data(), fv.data(), u, v, x, y, *addr);
|
||||
}
|
||||
|
||||
inline uint32_t TexFilterLinear(
|
||||
TexFormat format,
|
||||
uint32_t texel00,
|
||||
uint32_t texel01,
|
||||
uint32_t texel10,
|
||||
uint32_t texel11,
|
||||
uint32_t alpha,
|
||||
uint32_t beta
|
||||
) {
|
||||
uint32_t c01l, c01h;
|
||||
{
|
||||
uint32_t c0l, c0h;
|
||||
uint32_t c1l, c1h;
|
||||
Unpack8888(format, texel00, &c0l, &c0h);
|
||||
Unpack8888(format, texel01, &c1l, &c1h);
|
||||
Lerp8888(c0l, c0h, c1l, c1h, alpha, &c01l, &c01h);
|
||||
}
|
||||
|
||||
uint32_t c23l, c23h;
|
||||
{
|
||||
uint32_t c2l, c2h;
|
||||
uint32_t c3l, c3h;
|
||||
Unpack8888(format, texel10, &c2l, &c2h);
|
||||
Unpack8888(format, texel11, &c3l, &c3h);
|
||||
Lerp8888(c2l, c2h, c3l, c3h, alpha, &c23l, &c23h);
|
||||
}
|
||||
|
||||
uint32_t cl, ch;
|
||||
Lerp8888(c01l, c01h, c23l, c23h, beta, &cl, &ch);
|
||||
uint32_t color = Pack8888(TexFormat::R8G8B8A8, cl, ch);
|
||||
|
||||
//printf("*** texel00=0x%x, texel01=0x%x, texel10=0x%x, texel11=0x%x, color=0x%x\n", texel00, texel01, texel10, texel11, color);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
inline uint32_t TexFilterPoint(TexFormat format, uint32_t texel) {
|
||||
uint32_t cl, ch;
|
||||
Unpack8888(format, texel, &cl, &ch);
|
||||
uint32_t color = Pack8888(TexFormat::R8G8B8A8, cl, ch);
|
||||
|
||||
//printf("*** texel=0x%x, color=0x%x\n", texel, color);
|
||||
|
||||
return color;
|
||||
}
|
||||
@@ -3,85 +3,12 @@
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <bitmanip.h>
|
||||
|
||||
template <typename... Args>
|
||||
void unused(Args&&...) {}
|
||||
|
||||
#define __unused(...) unused(__VA_ARGS__)
|
||||
|
||||
constexpr uint32_t count_leading_zeros(uint32_t value) {
|
||||
return value ? __builtin_clz(value) : 32;
|
||||
}
|
||||
|
||||
constexpr uint32_t count_trailing_zeros(uint32_t value) {
|
||||
return value ? __builtin_ctz(value) : 32;
|
||||
}
|
||||
|
||||
constexpr bool ispow2(uint32_t value) {
|
||||
return value && !(value & (value - 1));
|
||||
}
|
||||
|
||||
constexpr uint32_t log2ceil(uint32_t value) {
|
||||
return 32 - count_leading_zeros(value - 1);
|
||||
}
|
||||
|
||||
inline unsigned log2up(uint32_t value) {
|
||||
return std::max<uint32_t>(1, log2ceil(value));
|
||||
}
|
||||
|
||||
constexpr unsigned log2floor(uint32_t value) {
|
||||
return 31 - count_leading_zeros(value);
|
||||
}
|
||||
|
||||
constexpr unsigned ceil2(uint32_t value) {
|
||||
return 32 - count_leading_zeros(value);
|
||||
}
|
||||
|
||||
inline uint64_t bit_clr(uint64_t bits, uint32_t index) {
|
||||
assert(index <= 63);
|
||||
return bits & ~(1ull << index);
|
||||
}
|
||||
|
||||
inline uint64_t bit_set(uint64_t bits, uint32_t index) {
|
||||
assert(index <= 63);
|
||||
return bits | (1ull << index);
|
||||
}
|
||||
|
||||
inline bool bit_get(uint64_t bits, uint32_t index) {
|
||||
assert(index <= 63);
|
||||
return (bits >> index) & 0x1;
|
||||
}
|
||||
|
||||
inline uint64_t bit_clrw(uint64_t bits, uint32_t start, uint32_t end) {
|
||||
assert(end >= start);
|
||||
assert(end <= 63);
|
||||
uint32_t shift = 63 - end;
|
||||
uint64_t mask = (0xffffffffffffffff << (shift + start)) >> shift;
|
||||
return bits & ~mask;
|
||||
}
|
||||
|
||||
inline uint64_t bit_setw(uint64_t bits, uint32_t start, uint32_t end, uint64_t value) {
|
||||
assert(end >= start);
|
||||
assert(end <= 63);
|
||||
uint32_t shift = 63 - end;
|
||||
uint64_t dirty = (value << (shift + start)) >> shift;
|
||||
return bit_clrw(bits, start, end) | dirty;
|
||||
}
|
||||
|
||||
inline uint64_t bit_getw(uint64_t bits, uint32_t start, uint32_t end) {
|
||||
assert(end >= start);
|
||||
assert(end <= 63);
|
||||
uint32_t shift = 63 - end;
|
||||
return (bits << shift) >> (shift + start);
|
||||
}
|
||||
|
||||
// Apply integer sign extension
|
||||
inline uint32_t sext32(uint32_t word, uint32_t width) {
|
||||
assert(width > 1);
|
||||
assert(width <= 32);
|
||||
uint32_t mask = (1 << width) - 1;
|
||||
return ((word >> (width - 1)) & 0x1) ? (word | ~mask) : word;
|
||||
}
|
||||
|
||||
// return file extension
|
||||
const char* fileExtension(const char* filepath);
|
||||
Reference in New Issue
Block a user