Skip to content

Commit

Permalink
Merge branch 'xenia-canary:canary_experimental' into Custom
Browse files Browse the repository at this point in the history
  • Loading branch information
backgamon authored Feb 18, 2024
2 parents c578bdd + 9e86750 commit 4c0e168
Show file tree
Hide file tree
Showing 5 changed files with 545 additions and 307 deletions.
86 changes: 70 additions & 16 deletions src/xenia/gpu/dxbc_shader_translator_om.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@
#include <cstdint>

#include "xenia/base/assert.h"
#include "xenia/base/cvar.h"
#include "xenia/base/math.h"
#include "xenia/gpu/draw_util.h"
#include "xenia/gpu/render_target_cache.h"
#include "xenia/gpu/texture_cache.h"

DEFINE_bool(use_fuzzy_alpha_epsilon, false,
"Use approximate compare for alpha values to prevent flickering on "
"NVIDIA graphics cards",
"GPU");

namespace xe {
namespace gpu {
using namespace ucode;
Expand Down Expand Up @@ -2907,6 +2913,10 @@ void DxbcShaderTranslator::CompletePixelShader() {
dxbc::Dest alpha_test_op_dest(dxbc::Dest::R(alpha_test_temp, 0b0010));
dxbc::Src alpha_test_op_src(
dxbc::Src::R(alpha_test_temp, dxbc::Src::kYYYY));
dxbc::Dest alpha_test_fuzzy_diff_dest(
dxbc::Dest::R(alpha_test_temp, 0b0100));
dxbc::Src alpha_test_fuzzy_diff_src(
dxbc::Src::R(alpha_test_temp, dxbc::Src::kZZZZ));
// Extract the comparison mask to check if the test needs to be done at all.
// Don't care about flow control being somewhat dynamic - early Z is forced
// using a special version of the shader anyway.
Expand All @@ -2929,29 +2939,73 @@ void DxbcShaderTranslator::CompletePixelShader() {
dxbc::Src alpha_test_reference_src(LoadSystemConstant(
SystemConstants::Index::kAlphaTestReference,
offsetof(SystemConstants, alpha_test_reference), dxbc::Src::kXXXX));
// Epsilon for alpha checks
dxbc::Src fuzzy_epsilon = dxbc::Src::LF(0.01f);
// Handle "not equal" specially (specifically as "not equal" so it's true
// for NaN, not "less or greater" which is false for NaN).
a_.OpIEq(alpha_test_op_dest, alpha_test_mask_src,
dxbc::Src::LU(uint32_t(xenos::CompareFunction::kNotEqual)));
a_.OpIf(true, alpha_test_op_src);
{ a_.OpNE(alpha_test_mask_dest, alpha_src, alpha_test_reference_src); }
{
if (cvars::use_fuzzy_alpha_epsilon) {
a_.OpAdd(alpha_test_fuzzy_diff_dest, alpha_src,
-alpha_test_reference_src);
// Check if distance to desired value is less then eps (false for NaN)
// and write the negated result
a_.OpLT(alpha_test_mask_dest, alpha_test_fuzzy_diff_src.Abs(),
fuzzy_epsilon);
a_.OpNot(alpha_test_mask_dest, alpha_test_mask_src);
} else {
a_.OpNE(alpha_test_mask_dest, alpha_src, alpha_test_reference_src);
}
}
a_.OpElse();
{
// Less than.
a_.OpLT(alpha_test_op_dest, alpha_src, alpha_test_reference_src);
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
dxbc::Src::LU(~uint32_t(1 << 0)));
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src, alpha_test_op_src);
// Equals to.
a_.OpEq(alpha_test_op_dest, alpha_src, alpha_test_reference_src);
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
dxbc::Src::LU(~uint32_t(1 << 1)));
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src, alpha_test_op_src);
// Greater than.
a_.OpLT(alpha_test_op_dest, alpha_test_reference_src, alpha_src);
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
dxbc::Src::LU(~uint32_t(1 << 2)));
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src, alpha_test_op_src);
if (cvars::use_fuzzy_alpha_epsilon) {
// Less than.
a_.OpAdd(alpha_test_fuzzy_diff_dest, alpha_src, -fuzzy_epsilon);
a_.OpLT(alpha_test_op_dest, alpha_test_fuzzy_diff_src,
alpha_test_reference_src);
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
dxbc::Src::LU(~uint32_t(1 << 0)));
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src,
alpha_test_op_src);
// "Equals" to.
a_.OpAdd(alpha_test_fuzzy_diff_dest, alpha_src,
-alpha_test_reference_src);
a_.OpLT(alpha_test_op_dest, alpha_test_fuzzy_diff_src.Abs(),
fuzzy_epsilon);
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
dxbc::Src::LU(~uint32_t(1 << 1)));
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src,
alpha_test_op_src);
// Greater than.
a_.OpAdd(alpha_test_fuzzy_diff_dest, alpha_src, fuzzy_epsilon);
a_.OpLT(alpha_test_op_dest, alpha_test_reference_src,
alpha_test_fuzzy_diff_src);
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
dxbc::Src::LU(~uint32_t(1 << 2)));
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src,
alpha_test_op_src);
} else {
// Less than.
a_.OpLT(alpha_test_op_dest, alpha_src, alpha_test_reference_src);
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
dxbc::Src::LU(~uint32_t(1 << 0)));
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src,
alpha_test_op_src);
a_.OpEq(alpha_test_op_dest, alpha_src, alpha_test_reference_src);
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
dxbc::Src::LU(~uint32_t(1 << 1)));
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src,
alpha_test_op_src);
// Greater than.
a_.OpLT(alpha_test_op_dest, alpha_test_reference_src, alpha_src);
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
dxbc::Src::LU(~uint32_t(1 << 2)));
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src,
alpha_test_op_src);
}
}
// Close the "not equal" check.
a_.OpEndIf();
Expand Down
234 changes: 234 additions & 0 deletions src/xenia/kernel/util/xuserdata.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2024 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/

#ifndef XENIA_KERNEL_UTIL_XUSERDATA_H_
#define XENIA_KERNEL_UTIL_XUSERDATA_H_

#include "xenia/base/byte_stream.h"
#include "xenia/xbox.h"

namespace xe {
namespace kernel {

enum class X_USER_DATA_TYPE : uint8_t {
CONTENT = 0,
INT32 = 1,
INT64 = 2,
DOUBLE = 3,
WSTRING = 4,
FLOAT = 5,
BINARY = 6,
DATETIME = 7,
UNSET = 0xFF,
};

struct X_USER_DATA {
X_USER_DATA_TYPE type;

union {
be<int32_t> s32;
be<int64_t> s64;
be<uint32_t> u32;
be<double> f64;
struct {
be<uint32_t> size;
be<uint32_t> ptr;
} unicode;
be<float> f32;
struct {
be<uint32_t> size;
be<uint32_t> ptr;
} binary;
be<uint64_t> filetime;
};
};
static_assert_size(X_USER_DATA, 16);

class DataByteStream : public ByteStream {
public:
DataByteStream(uint32_t ptr, uint8_t* data, size_t data_length,
size_t offset = 0)
: ByteStream(data, data_length, offset), ptr_(ptr) {}

uint32_t ptr() const { return static_cast<uint32_t>(ptr_ + offset()); }

private:
uint32_t ptr_;
};

class UserData {
public:
union Key {
uint32_t value;
struct {
uint32_t id : 14;
uint32_t unk : 2;
uint32_t size : 12;
uint32_t type : 4;
};
};

UserData(){};
UserData(X_USER_DATA_TYPE type) { data_.type = type; }

virtual void Append(X_USER_DATA* data, DataByteStream* stream) {
data->type = data_.type;
}

virtual std::vector<uint8_t> Serialize() const {
return std::vector<uint8_t>();
}
virtual void Deserialize(std::vector<uint8_t>) {}

private:
X_USER_DATA data_ = {};
};

class Int32UserData : public UserData {
public:
Int32UserData(int32_t value)
: UserData(X_USER_DATA_TYPE::INT32), value_(value) {}
void Append(X_USER_DATA* data, DataByteStream* stream) override {
UserData::Append(data, stream);
data->s32 = value_;
}

private:
int32_t value_;
};

class Uint32UserData : public UserData {
public:
Uint32UserData(uint32_t value)
: UserData(X_USER_DATA_TYPE::INT32), value_(value) {}
void Append(X_USER_DATA* data, DataByteStream* stream) override {
UserData::Append(data, stream);
data->u32 = value_;
}

private:
uint32_t value_;
};

class Int64UserData : public UserData {
public:
Int64UserData(int64_t value)
: UserData(X_USER_DATA_TYPE::INT64), value_(value) {}
void Append(X_USER_DATA* data, DataByteStream* stream) override {
UserData::Append(data, stream);
data->s64 = value_;
}

private:
int64_t value_;
};

class FloatUserData : public UserData {
public:
FloatUserData(float value)
: UserData(X_USER_DATA_TYPE::FLOAT), value_(value) {}

void Append(X_USER_DATA* data, DataByteStream* stream) override {
UserData::Append(data, stream);
data->f32 = value_;
}

private:
float value_;
};

class DoubleUserData : public UserData {
public:
DoubleUserData(double value)
: UserData(X_USER_DATA_TYPE::DOUBLE), value_(value) {}
void Append(X_USER_DATA* data, DataByteStream* stream) override {
UserData::Append(data, stream);
data->f64 = value_;
}

private:
double value_;
};

class UnicodeUserData : public UserData {
public:
UnicodeUserData(const std::u16string& value)
: UserData(X_USER_DATA_TYPE::WSTRING), value_(value) {}
void Append(X_USER_DATA* data, DataByteStream* stream) override {
UserData::Append(data, stream);

if (value_.empty()) {
data->unicode.size = 0;
data->unicode.ptr = 0;
return;
}

size_t count = value_.size() + 1;
size_t size = 2 * count;
assert_true(size <= std::numeric_limits<uint32_t>::max());
data->unicode.size = static_cast<uint32_t>(size);
data->unicode.ptr = stream->ptr();
auto buffer =
reinterpret_cast<uint16_t*>(&stream->data()[stream->offset()]);
stream->Advance(size);
copy_and_swap(buffer, (uint16_t*)value_.data(), count);
}

private:
std::u16string value_;
};

class BinaryUserData : public UserData {
public:
BinaryUserData(const std::vector<uint8_t>& value)
: UserData(X_USER_DATA_TYPE::BINARY), value_(value) {}
void Append(X_USER_DATA* data, DataByteStream* stream) override {
UserData::Append(data, stream);

if (value_.empty()) {
data->binary.size = 0;
data->binary.ptr = 0;
return;
}

size_t size = value_.size();
assert_true(size <= std::numeric_limits<uint32_t>::max());
data->binary.size = static_cast<uint32_t>(size);
data->binary.ptr = stream->ptr();
stream->Write(value_.data(), size);
}

std::vector<uint8_t> Serialize() const override {
return std::vector<uint8_t>(value_.data(), value_.data() + value_.size());
}

void Deserialize(std::vector<uint8_t> data) override { value_ = data; }

private:
std::vector<uint8_t> value_;
};

class DateTimeUserData : public UserData {
public:
DateTimeUserData(int64_t value)
: UserData(X_USER_DATA_TYPE::DATETIME), value_(value) {}

void Append(X_USER_DATA* data, DataByteStream* stream) override {
UserData::Append(data, stream);
data->filetime = value_;
}

private:
int64_t value_;
};

} // namespace kernel
} // namespace xe

#endif
Loading

0 comments on commit 4c0e168

Please sign in to comment.