Skip to content

Commit

Permalink
[graphics] reduce the size of fr3 files (#1175)
Browse files Browse the repository at this point in the history
* first pass

* first pass at shrinking fr3s

* only need to load vertices once

* avx2 detect and switch

* fix build

* another ifx'

* one more

* fix the sky and stupid math bug in size check
  • Loading branch information
water111 authored Feb 17, 2022
1 parent 74d0025 commit 5135ea9
Show file tree
Hide file tree
Showing 20 changed files with 844 additions and 137 deletions.
7 changes: 3 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ if(MSVC AND (CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
"-Xclang -fcxx-exceptions \
-Xclang -fexceptions \
-Xclang -std=c++17 \
-mfma -mavx2 \
-Wno-c++11-narrowing -W3 \
/arch:AVX")
-march=native \
-Wno-c++11-narrowing -W3")

# additional c++ flags for release mode for our projects
if(CMAKE_BUILD_TYPE MATCHES "Release")
Expand Down Expand Up @@ -47,7 +46,7 @@ elseif(UNIX)
-Wshadow \
-Wsign-promo \
-fdiagnostics-color=always \
-march=haswell")
-march=native")

# additional c++ flags for release mode for our projects
if(CMAKE_BUILD_TYPE MATCHES "Release")
Expand Down
143 changes: 137 additions & 6 deletions common/custom_data/TFrag3Data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,31 @@

namespace tfrag3 {

void PackedTieVertices::serialize(Serializer& ser) {
ser.from_pod_vector(&color_indices);
ser.from_pod_vector(&matrices);
ser.from_pod_vector(&matrix_groups);
ser.from_pod_vector(&vertices);
}

void StripDraw::serialize(Serializer& ser) {
ser.from_ptr(&mode);
ser.from_ptr(&tree_tex_id);
ser.from_pod_vector(&vertex_index_stream);
ser.from_pod_vector(&runs);
ser.from_pod_vector(&vis_groups);
ser.from_ptr(&num_triangles);
}

void StripDraw::unpack() {
ASSERT(unpacked.vertex_index_stream.empty());
for (auto& r : runs) {
for (int i = 0; i < r.length; i++) {
unpacked.vertex_index_stream.push_back(r.vertex0 + i);
}
unpacked.vertex_index_stream.push_back(UINT32_MAX);
}
}

void InstancedStripDraw::serialize(Serializer& ser) {
ser.from_ptr(&mode);
ser.from_ptr(&tree_tex_id);
Expand All @@ -37,11 +54,71 @@ void TfragTree::serialize(Serializer& ser) {
draw.serialize(ser);
}

ser.from_pod_vector(&vertices);
// ser.from_pod_vector(&vertices);
ser.from_pod_vector(&packed_vertices.vertices);
ser.from_pod_vector(&packed_vertices.cluster_origins);
ser.from_pod_vector(&colors);
bvh.serialize(ser);
}

void TieTree::unpack() {
unpacked.vertices.resize(packed_vertices.color_indices.size());
size_t i = 0;
for (const auto& grp : packed_vertices.matrix_groups) {
if (grp.matrix_idx == -1) {
for (u32 src_idx = grp.start_vert; src_idx < grp.end_vert; src_idx++) {
auto& vtx = unpacked.vertices[i];
vtx.color_index = packed_vertices.color_indices[i];
const auto& proto_vtx = packed_vertices.vertices[src_idx];
vtx.x = proto_vtx.x;
vtx.y = proto_vtx.y;
vtx.z = proto_vtx.z;
vtx.q = 1.f;
vtx.s = proto_vtx.s;
vtx.t = proto_vtx.t;
i++;
}
} else {
const auto& mat = packed_vertices.matrices[grp.matrix_idx];
for (u32 src_idx = grp.start_vert; src_idx < grp.end_vert; src_idx++) {
auto& vtx = unpacked.vertices[i];
vtx.color_index = packed_vertices.color_indices[i];
const auto& proto_vtx = packed_vertices.vertices[src_idx];
auto temp = mat[0] * proto_vtx.x + mat[1] * proto_vtx.y + mat[2] * proto_vtx.z + mat[3];
vtx.x = temp.x();
vtx.y = temp.y();
vtx.z = temp.z();
vtx.q = 1.f;
vtx.s = proto_vtx.s;
vtx.t = proto_vtx.t;
i++;
}
}
}
}

void TfragTree::unpack() {
unpacked.vertices.resize(packed_vertices.vertices.size());
for (size_t i = 0; i < unpacked.vertices.size(); i++) {
auto& o = unpacked.vertices[i];
auto& in = packed_vertices.vertices[i];
auto& cluster = packed_vertices.cluster_origins.at(in.cluster_idx);
constexpr float kClusterSize = 4096 * 40; // 100 in-game meters
constexpr float kMasterOffset = 12000 * 4096;
constexpr float rescale = kClusterSize / UINT16_MAX;
float cx = -kMasterOffset + kClusterSize * cluster.x();
float cy = -kMasterOffset + kClusterSize * cluster.y();
float cz = -kMasterOffset + kClusterSize * cluster.z();
o.x = cx + in.xoff * rescale;
o.y = cy + in.yoff * rescale;
o.z = cz + in.zoff * rescale;
o.s = in.s / (1024.f);
o.t = in.t / (1024.f);
o.q = 1.f;
o.color_index = in.color_index;
}
}

void TieTree::serialize(Serializer& ser) {
if (ser.is_saving()) {
ser.save<size_t>(static_draws.size());
Expand All @@ -62,15 +139,15 @@ void TieTree::serialize(Serializer& ser) {
}

if (ser.is_saving()) {
ser.save<size_t>(instance_info.size());
ser.save<size_t>(wind_instance_info.size());
} else {
instance_info.resize(ser.load<size_t>());
wind_instance_info.resize(ser.load<size_t>());
}
for (auto& inst : instance_info) {
for (auto& inst : wind_instance_info) {
inst.serialize(ser);
}

ser.from_pod_vector(&vertices);
packed_vertices.serialize(ser);
ser.from_pod_vector(&colors);
bvh.serialize(ser);
}
Expand Down Expand Up @@ -141,4 +218,58 @@ void Level::serialize(Serializer& ser) {
}
}

std::array<int, MemoryUsageCategory::NUM_CATEGORIES> Level::get_memory_usage() const {
std::array<int, MemoryUsageCategory::NUM_CATEGORIES> result;
result.fill(0);

// textures
for (const auto& tex : textures) {
result[TEXTURE] += tex.data.size() * sizeof(u32);
}

// tfrag
for (const auto& tfrag_tree_geoms : tfrag_trees) {
for (const auto& tfrag_tree : tfrag_tree_geoms) {
for (const auto& draw : tfrag_tree.draws) {
result[TFRAG_INDEX] += draw.runs.size() * sizeof(StripDraw::VertexRun);
result[TFRAG_VIS] += draw.vis_groups.size() * sizeof(StripDraw::VisGroup);
}
result[TFRAG_VERTS] +=
tfrag_tree.packed_vertices.vertices.size() * sizeof(PackedTfragVertices::Vertex);
result[TFRAG_CLUSTER] +=
tfrag_tree.packed_vertices.cluster_origins.size() * sizeof(math::Vector<u16, 3>);
result[TFRAG_TIME_OF_DAY] += tfrag_tree.colors.size() * sizeof(TimeOfDayColor);
result[TFRAG_BVH] += tfrag_tree.bvh.vis_nodes.size() * sizeof(VisNode);
}
}

// tie
for (const auto& tie_tree_geoms : tie_trees) {
for (const auto& tie_tree : tie_tree_geoms) {
result[TIE_BVH] += tie_tree.bvh.vis_nodes.size();
for (const auto& draw : tie_tree.static_draws) {
result[TIE_DEINST_INDEX] += draw.runs.size() * sizeof(StripDraw::VertexRun);
result[TIE_DEINST_VIS] += draw.vis_groups.size() * sizeof(StripDraw::VisGroup);
}
result[TIE_VERTS] +=
tie_tree.packed_vertices.vertices.size() * sizeof(PackedTieVertices::Vertex);
result[TIE_CIDX] += tie_tree.packed_vertices.color_indices.size() * sizeof(u16);
result[TIE_MATRICES] += tie_tree.packed_vertices.matrices.size() * 4 * 4 * 4;
result[TIE_GRPS] +=
tie_tree.packed_vertices.matrix_groups.size() * sizeof(PackedTieVertices::MatrixGroup);
result[TIE_TIME_OF_DAY] += tie_tree.colors.size() * sizeof(TimeOfDayColor);

for (const auto& draw : tie_tree.instanced_wind_draws) {
result[TIE_INST_INDEX] += draw.vertex_index_stream.size() * sizeof(u32);
result[TIE_INST_VIS] +=
draw.instance_groups.size() * sizeof(InstancedStripDraw::InstanceGroup);
}
result[TIE_WIND_INSTANCE_INFO] +=
tie_tree.wind_instance_info.size() * sizeof(TieWindInstance);
}
}

return result;
}

} // namespace tfrag3
131 changes: 118 additions & 13 deletions common/custom_data/Tfrag3Data.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,39 @@

namespace tfrag3 {

constexpr int TFRAG3_VERSION = 10;
// NOTE:
// when updating any data structures in this file:
// - change the TFRAG3_VERSION
// - make sure to update the serialize function
// - if changing any large things (vertices, vis, bvh, colors, textures) update get_memory_usage
// - if adding a new category to the memory usage, update extract_level to print it.

enum MemoryUsageCategory {
TEXTURE,

TIE_DEINST_VIS,
TIE_DEINST_INDEX,
TIE_INST_VIS,
TIE_INST_INDEX,
TIE_BVH,
TIE_VERTS,
TIE_TIME_OF_DAY,
TIE_WIND_INSTANCE_INFO,

TIE_CIDX,
TIE_MATRICES,
TIE_GRPS,

TFRAG_VIS,
TFRAG_INDEX,
TFRAG_VERTS,
TFRAG_CLUSTER,
TFRAG_TIME_OF_DAY,
TFRAG_BVH,
NUM_CATEGORIES
};

constexpr int TFRAG3_VERSION = 11;

// These vertices should be uploaded to the GPU at load time and don't change
struct PreloadedVertex {
Expand All @@ -25,6 +57,55 @@ struct PreloadedVertex {
};
static_assert(sizeof(PreloadedVertex) == 32, "PreloadedVertex size");

struct PackedTieVertices {
struct Vertex {
float x, y, z;
float s, t;
};

struct MatrixGroup {
s32 matrix_idx;
u32 start_vert;
u32 end_vert;
};

std::vector<u16> color_indices;
std::vector<std::array<math::Vector4f, 4>> matrices;
std::vector<MatrixGroup> matrix_groups; // todo pack
std::vector<Vertex> vertices;
float cluster_size = 0;
void serialize(Serializer& ser);
};

struct PackedTfragVertices {
struct Vertex {
u16 xoff, yoff, zoff;
u16 cluster_idx;
u16 s, t;
u16 color_index;

/*
bool operator==(const Vertex& other) const {
return xoff == other.xoff && yoff == other.yoff && zoff == other.zoff &&
cluster_idx == other.cluster_idx && s == other.s && t == other.t &&
color_index == other.color_index;
}
struct hash {
auto operator()(const Vertex& x) const {
return std::hash<uint16_t>()(x.xoff) ^ std::hash<uint16_t>()(x.yoff) ^
std::hash<uint16_t>()(x.zoff) ^ std::hash<uint16_t>()(x.cluster_idx) ^
std::hash<uint16_t>()(x.s) ^ std::hash<uint16_t>()(x.t) ^
std::hash<uint16_t>()(x.color_index);
}
};
*/
};

std::vector<Vertex> vertices;
std::vector<math::Vector<u16, 3>> cluster_origins;
};

// Settings for drawing a group of triangle strips.
// This refers to a group of PreloadedVertices that are already uploaded.
// All triangles here are drawn in the same "mode" (blending, texture, etc)
Expand All @@ -35,9 +116,20 @@ struct StripDraw {
DrawMode mode; // the OpenGL draw settings.
u32 tree_tex_id = 0; // the texture that should be bound for the draw

// the list of vertices in the draw. This includes the restart code of UINT32_MAX that OpenGL
// will use to start a new strip.
std::vector<u32> vertex_index_stream;
struct {
// the list of vertices in the draw. This includes the restart code of UINT32_MAX that OpenGL
// will use to start a new strip.
std::vector<u32> vertex_index_stream;
} unpacked;

void unpack();

struct VertexRun {
u32 vertex0;
u16 length;
};

std::vector<VertexRun> runs;

// to do culling, the above vertex stream is grouped.
// by following the visgroups and checking the visibility, you can leave out invisible vertices.
Expand Down Expand Up @@ -129,11 +221,16 @@ constexpr const char* tfrag_tree_names[] = {"normal", "trans", "dirt",

// A tfrag model
struct TfragTree {
TFragmentTreeKind kind; // our tfrag kind
std::vector<StripDraw> draws; // the actual topology and settings
std::vector<PreloadedVertex> vertices; // mesh vertices
std::vector<TimeOfDayColor> colors; // vertex colors (pre-interpolation)
BVH bvh; // the bvh for frustum culling
TFragmentTreeKind kind; // our tfrag kind
std::vector<StripDraw> draws; // the actual topology and settings
PackedTfragVertices packed_vertices;
std::vector<TimeOfDayColor> colors; // vertex colors (pre-interpolation)
BVH bvh; // the bvh for frustum culling

struct {
std::vector<PreloadedVertex> vertices; // mesh vertices
} unpacked;
void unpack();
void serialize(Serializer& ser);
};

Expand All @@ -147,14 +244,20 @@ struct TieWindInstance {
// A tie model
struct TieTree {
BVH bvh;
std::vector<StripDraw> static_draws; // the actual topology and settings
std::vector<PreloadedVertex> vertices; // mesh vertices
std::vector<TimeOfDayColor> colors; // vertex colors (pre-interpolation)
std::vector<StripDraw> static_draws; // the actual topology and settings

PackedTieVertices packed_vertices;
std::vector<TimeOfDayColor> colors; // vertex colors (pre-interpolation)

std::vector<InstancedStripDraw> instanced_wind_draws;
std::vector<TieWindInstance> instance_info;
std::vector<TieWindInstance> wind_instance_info;

struct {
std::vector<PreloadedVertex> vertices; // mesh vertices
} unpacked;

void serialize(Serializer& ser);
void unpack();
};

struct Level {
Expand All @@ -165,6 +268,8 @@ struct Level {
std::array<std::vector<TieTree>, 4> tie_trees;
u16 version2 = TFRAG3_VERSION;
void serialize(Serializer& ser);

std::array<int, MemoryUsageCategory::NUM_CATEGORIES> get_memory_usage() const;
};

} // namespace tfrag3
5 changes: 5 additions & 0 deletions common/util/FileUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@
#include "common/util/BinaryReader.h"
#include "BinaryWriter.h"
#include "common/common_types.h"

// This disables the use of PCLMULQDQ which is probably ok, but let's just be safe and disable it
// because nobody will care if png compression is 10% slower.
#define FPNG_NO_SSE 1
#include "third-party/fpng/fpng.cpp"

#include "third-party/fpng/fpng.h"
#include "third-party/fmt/core.h"
#include "third-party/lzokay/lzokay.hpp"
Expand Down
Loading

0 comments on commit 5135ea9

Please sign in to comment.