Skip to content

Commit bb5acc1

Browse files
committed
TBR: Use SoA vertex layout to improve cache locality
Signed-off-by: ZhouFANG <indevn@outlook.com>
1 parent 8a74379 commit bb5acc1

5 files changed

Lines changed: 328 additions & 330 deletions

File tree

src/include/rasterizer.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "config.h"
55
#include "shader.hpp"
6+
#include "vertex_soa.hpp"
67

78
namespace simple_renderer {
89

@@ -27,6 +28,11 @@ class Rasterizer {
2728
int x0, int y0, int x1, int y1,
2829
std::vector<Fragment>& out);
2930

31+
// SoA 版本:按顶点索引从 SoA 读取三角形三顶点
32+
void RasterizeTo(const VertexSoA& soa, size_t i0, size_t i1, size_t i2,
33+
int x0, int y0, int x1, int y1,
34+
std::vector<Fragment>& out);
35+
3036
private:
3137
size_t width_, height_;
3238

src/include/renderer.h

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,12 @@ enum class RenderingMode {
3838
DEFERRED // 延迟渲染模式 - 经典GPU管线教学模拟
3939
};
4040

41-
// Face 只包含顶点索引,不包含实际的顶点数据;
42-
// Vertex 包含3D坐标,但没有屏幕坐标
43-
// Fragment 包含屏幕坐标,但它是光栅化的结果,不是输入
44-
struct TriangleInfo {
45-
Vertex v0, v1, v2;
46-
const Material *material;
47-
size_t face_index;
48-
TriangleInfo(const Vertex& vertex0, const Vertex& vertex1, const Vertex& vertex2,
49-
const Material* mat, size_t face_idx = 0)
50-
: v0(vertex0), v1(vertex1), v2(vertex2), material(mat), face_index(face_idx) {}
51-
52-
TriangleInfo() = default;
41+
42+
// SoA 版 tile 列表中的三角形引用(仅存索引与材质指针)
43+
struct TriangleRef {
44+
size_t i0, i1, i2;
45+
const Material* material = nullptr;
46+
size_t face_index = 0;
5347
};
5448

5549
class SimpleRenderer {
@@ -158,10 +152,9 @@ class SimpleRenderer {
158152
double deferred_shading_ms;
159153
double total_ms;
160154
};
161-
162155
TileRenderStats ExecuteTileBasedPipeline(const Model &model,
163-
const std::vector<Vertex> &processedVertices,
164-
uint32_t *buffer);
156+
const VertexSoA &soa,
157+
uint32_t *buffer);
165158

166159
/**
167160
* 延迟渲染管线
@@ -177,19 +170,24 @@ class SimpleRenderer {
177170

178171
private:
179172

173+
174+
// SoA 版本的 Triangle-Tile binning(两遍计数 + reserve)
180175
void TriangleTileBinning(
181-
const Model &model,
182-
const std::vector<Vertex> &screenVertices,
183-
std::vector<std::vector<TriangleInfo>> &tile_triangles,
176+
const Model &model,
177+
const VertexSoA &soa,
178+
std::vector<std::vector<TriangleRef>> &tile_triangles,
184179
size_t tiles_x, size_t tiles_y, size_t tile_size);
185180

181+
182+
// SoA 版本的 tile 光栅化
186183
void RasterizeTile(
187184
size_t tile_id,
188-
const std::vector<TriangleInfo> &triangles,
185+
const std::vector<TriangleRef> &triangles,
189186
size_t tiles_x, size_t tiles_y, size_t tile_size,
190187
float* tile_depth_buffer, uint32_t* tile_color_buffer,
191188
std::unique_ptr<float[]> &global_depth_buffer,
192189
std::unique_ptr<uint32_t[]> &global_color_buffer,
190+
const VertexSoA &soa,
193191
bool use_early_z = false,
194192
std::vector<Fragment>* scratch_fragments = nullptr);
195193

src/include/vertex_soa.hpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Minimal SoA layout for TBR pipeline (Phase 1)
2+
#ifndef SIMPLERENDER_SRC_INCLUDE_VERTEX_SOA_HPP_
3+
#define SIMPLERENDER_SRC_INCLUDE_VERTEX_SOA_HPP_
4+
5+
#include <vector>
6+
7+
#include "math.hpp"
8+
#include "color.h"
9+
10+
namespace simple_renderer {
11+
12+
struct VertexSoA {
13+
// 屏幕空间坐标(视口变换后)
14+
std::vector<Vector4f> pos_screen; // screen space position (x,y,z,w)
15+
// 裁剪空间坐标(用于视锥体剔除):clip = MVP * pos
16+
std::vector<Vector4f> pos_clip;
17+
std::vector<Vector3f> normal;
18+
std::vector<Vector2f> uv;
19+
std::vector<Color> color;
20+
21+
inline size_t size() const { return pos_screen.size(); }
22+
inline void resize(size_t n) {
23+
pos_screen.resize(n);
24+
pos_clip.resize(n);
25+
normal.resize(n);
26+
uv.resize(n);
27+
color.resize(n);
28+
}
29+
};
30+
31+
} // namespace simple_renderer
32+
33+
#endif // SIMPLERENDER_SRC_INCLUDE_VERTEX_SOA_HPP_

src/rasterizer.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,67 @@ void Rasterizer::RasterizeTo(const Vertex& v0, const Vertex& v1, const Vertex& v
158158
}
159159
}
160160

161+
void Rasterizer::RasterizeTo(const VertexSoA& soa, size_t i0, size_t i1, size_t i2,
162+
int x0, int y0, int x1, int y1,
163+
std::vector<Fragment>& out) {
164+
// 读取三顶点的屏幕空间位置
165+
const Vector4f& p0 = soa.pos_screen[i0];
166+
const Vector4f& p1 = soa.pos_screen[i1];
167+
const Vector4f& p2 = soa.pos_screen[i2];
168+
169+
Vector2f a = Vector2f(p0.x, p0.y);
170+
Vector2f b = Vector2f(p1.x, p1.y);
171+
Vector2f c = Vector2f(p2.x, p2.y);
172+
173+
Vector2f bboxMin = Vector2f{std::min({a.x, b.x, c.x}), std::min({a.y, b.y, c.y})};
174+
Vector2f bboxMax = Vector2f{std::max({a.x, b.x, c.x}), std::max({a.y, b.y, c.y})};
175+
176+
// Clamp 到屏幕尺寸
177+
float minx = std::max(0.0f, bboxMin.x);
178+
float miny = std::max(0.0f, bboxMin.y);
179+
float maxx = std::min(float(width_ - 1), bboxMax.x);
180+
float maxy = std::min(float(height_ - 1), bboxMax.y);
181+
182+
// 与外部提供的裁剪区域相交(半开区间) -> 闭区间扫描
183+
int sx = std::max(x0, int(std::floor(minx)));
184+
int sy = std::max(y0, int(std::floor(miny)));
185+
int ex = std::min(x1 - 1, int(std::floor(maxx)));
186+
int ey = std::min(y1 - 1, int(std::floor(maxy)));
187+
if (sx > ex || sy > ey) return;
188+
189+
// 透视矫正插值依赖 w
190+
float w0_inv = p0.w;
191+
float w1_inv = p1.w;
192+
float w2_inv = p2.w;
193+
194+
for (int x = sx; x <= ex; ++x) {
195+
for (int y = sy; y <= ey; ++y) {
196+
auto [is_inside, bary] = GetBarycentricCoord(
197+
Vector3f(p0.x, p0.y, p0.z), Vector3f(p1.x, p1.y, p1.z), Vector3f(p2.x, p2.y, p2.z),
198+
Vector3f(static_cast<float>(x), static_cast<float>(y), 0));
199+
if (!is_inside) continue;
200+
201+
float w_inv_interp = Interpolate(w0_inv, w1_inv, w2_inv, bary);
202+
Vector3f cb(
203+
bary.x * w0_inv / w_inv_interp,
204+
bary.y * w1_inv / w_inv_interp,
205+
bary.z * w2_inv / w_inv_interp);
206+
207+
float z = Interpolate(p0.z, p1.z, p2.z, cb);
208+
209+
Fragment frag;
210+
frag.screen_coord = {x, y};
211+
frag.normal = Interpolate(soa.normal[i0], soa.normal[i1], soa.normal[i2], cb);
212+
frag.uv = Interpolate(soa.uv[i0], soa.uv[i1], soa.uv[i2], cb);
213+
frag.color = InterpolateColor(soa.color[i0], soa.color[i1], soa.color[i2], cb);
214+
frag.depth = z;
215+
// material 指针由调用方填写
216+
217+
out.push_back(frag);
218+
}
219+
}
220+
}
221+
161222
std::pair<bool, Vector3f> Rasterizer::GetBarycentricCoord(const Vector3f& p0,
162223
const Vector3f& p1,
163224
const Vector3f& p2,

0 commit comments

Comments
 (0)