diff options
Diffstat (limited to 'platform/wavelet3d/host_sw')
| -rw-r--r-- | platform/wavelet3d/host_sw/demo.c | 423 | ||||
| -rw-r--r-- | platform/wavelet3d/host_sw/gfx_boot.c | 1 | ||||
| -rw-r--r-- | platform/wavelet3d/host_sw/main.c | 4 | ||||
| -rw-r--r-- | platform/wavelet3d/host_sw/mod.mk | 5 | ||||
| -rw-r--r-- | platform/wavelet3d/host_sw/vdc.c | 54 | ||||
| -rw-r--r-- | platform/wavelet3d/host_sw/vdc.h | 6 | ||||
| -rw-r--r-- | platform/wavelet3d/host_sw/vdc_rayas.c | 100 |
7 files changed, 590 insertions, 3 deletions
diff --git a/platform/wavelet3d/host_sw/demo.c b/platform/wavelet3d/host_sw/demo.c new file mode 100644 index 0000000..32e8e0e --- /dev/null +++ b/platform/wavelet3d/host_sw/demo.c @@ -0,0 +1,423 @@ +#define MOD_NAME "demo" + +#include <math.h> +#include <string.h> + +#include "log.h" + +#define W 640 +#define H 480 + +#define FB_BASE ((void *)0x1d000000) + +typedef float mat4[4][4]; +typedef float vec4[4]; + +typedef struct vec2i +{ + int x, y; +} vec2i; + +typedef struct vertex +{ + vec4 pos; + vec2i grid; + vec4 color; +} vertex; + +static mat4 mvp; +static unsigned short z_buff[1024 * H]; + +static inline int min(int x, int y) +{ + return x < y ? x : y; +} + +static inline int max(int x, int y) +{ + return x > y ? x : y; +} + +void mat_vec(mat4 *a, vec4 *b, vec4 *out) +{ + vec4 v; + for (int i = 0; i < 4; ++i) { + v[i] = 0.0; + for (int k = 0; k < 4; ++k) + v[i] += (*a)[i][k] * (*b)[k]; + } + + memcpy(out, v, sizeof v); +} + +void mat_mat(mat4 *a, mat4 *b, mat4 *out) +{ + mat4 c; + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) { + c[i][j] = 0.0; + for (int k = 0; k < 4; ++k) + c[i][j] += (*a)[i][k] * (*b)[k][j]; + } + + memcpy(out, c, sizeof c); +} + +void mat_translate(float x, float y, float z, mat4 *out) +{ + mat4 m = + { + {1, 0, 0, x}, + {0, 1, 0, y}, + {0, 0, 1, z}, + {0, 0, 0, 1}, + }; + + memcpy(out, m, sizeof m); +}; + +void mat_scale(float x, float y, float z, mat4 *out) +{ + mat4 m = + { + {x, 0, 0, 0}, + {0, y, 0, 0}, + {0, 0, z, 0}, + {0, 0, 0, 1}, + }; + + memcpy(out, m, sizeof m); +} + +void mat_rotate(float x, float y, float z, float angle, mat4 *out) +{ + float xx = x * x, yy = y * y, zz = z * z; + float mag = sqrt(xx + yy + zz); + x /= mag; + y /= mag; + z /= mag; + + angle = angle * M_PI / 180; + float c = cosf(angle), s = sinf(angle); + + mat4 m = + { + {x * x * (1 - c) + c, x * y * (1 - c) - z * s, x * z * (1 - c) + y * s, 0}, + {y * x * (1 - c) + z * s, y * y * (1 - c) + c, y * z * (1 - c) - x * s, 0}, + {x * z * (1 - c) - y * s, y * z * (1 - c) + x * s, z * z * (1 - c) + c, 0}, + {0, 0, 0, 1}, + }; + + memcpy(out, m, sizeof m); +} + +void mat_frustum(float left, float right, float bottom, float top, float near, float far, mat4 *out) +{ + // https://docs.gl/gl3/glFrustum + + float l = left, r = right, b = bottom, t = top, n = near, f = far; + + mat4 m = + { + {2 * n / (r - l), 0, (r + l) / (r - l), 0}, + {0, 2 * n / (t - b), (t + b) / (t - b), 0}, + {0, 0, -(f + n) / (f - n), -2 * f * n / (f - n)}, + {0, 0, -1 , 0}, + }; + + memcpy(out, m, sizeof m); +} + +void fixed(vec4 *p, vec2i *out) +{ + out->x = (int)ldexpf((*p)[0] / (*p)[3], 13); + out->y = (int)ldexpf((*p)[1] / (*p)[3], 13); +} + +void edge_fn(vec2i *p, vec2i *q, int sx, int sy, int *base_x, int *base_y, int *add_x, int *add_y) +{ + // https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/rasterization-stage.html + int a = p->y - q->y, b = -(p->x - q->x); + int r = (sx - q->x) * a + (sy - q->y) * b; + + *base_x = r; + *base_y = r; + *add_x = a; + *add_y = b; +} + +void bounding(vec2i *p0, vec2i *p1, vec2i *p2, int *minx, int *miny, int *maxx, int *maxy) +{ + *minx = max(min(p0->x, min(p1->x, p2->x)), (-W / 2) << 4); + *maxx = min(max(p0->x, max(p1->x, p2->x)), ( W / 2) << 4); + *miny = max(min(p0->y, min(p1->y, p2->y)), (-H / 2) << 4); + *maxy = min(max(p0->y, max(p1->y, p2->y)), ( H / 2) << 4); +} + +unsigned char clamp_color(float color) +{ + color = ldexpf(color, 8); + if (color < 0.0) + return 0; + else if (color >= 256.0) + return 255; + + return (unsigned char)(int)color; +} + +float area(vec2i *a, vec2i *b, vec2i *c) +{ + float a_x = a->x; + float a_y = a->y; + float b_x = b->x; + float b_y = b->y; + float c_x = c->x; + float c_y = c->y; + + + return (a_x * (b_y - c_y) + b_x * (c_y - a_y) + c_x * (a_y - b_y)) / 2; +} + +void raster(vertex *v0, vertex *v1, vertex *v2) +{ + // https://math.stackexchange.com/questions/1324179/how-to-tell-if-3-connected-points-are-connected-clockwise-or-counter-clockwise + + int A = v1->grid.x * v0->grid.y + v2->grid.x * v1->grid.y + v0->grid.x * v2->grid.y; + int B = v0->grid.x * v1->grid.y + v1->grid.x * v2->grid.y + v2->grid.x * v0->grid.y; + + if (A > B) { + vertex *tmp = v2; + v2 = v1; + v1 = tmp; + } + + vec2i *p0 = &v0->grid; + vec2i *p1 = &v1->grid; + vec2i *p2 = &v2->grid; + + int msaa = 0; //TODO + + int minx, miny, maxx, maxy; + bounding(p0, p1, p2, &minx, &miny, &maxx, &maxy); + + int sx = minx / 16 * 16, sy = miny / 16 * 16; + + int base_x_a, base_y_a, add_x_a, add_y_a; + edge_fn(p0, p1, sx, sy, &base_x_a, &base_y_a, &add_x_a, &add_y_a); + + int base_x_b, base_y_b, add_x_b, add_y_b; + edge_fn(p1, p2, sx, sy, &base_x_b, &base_y_b, &add_x_b, &add_y_b); + + int base_x_c, base_y_c, add_x_c, add_y_c; + edge_fn(p2, p0, sx, sy, &base_x_c, &base_y_c, &add_x_c, &add_y_c); + + int int_x_a = add_x_a << 4; + int int_x_b = add_x_b << 4; + int int_x_c = add_x_c << 4; + int int_y_a = add_y_a << 4; + int int_y_b = add_y_b << 4; + int int_y_c = add_y_c << 4; + + for (int x = minx / 16 * 16; x < maxx + 16; x += 16) { + for (int y = miny / 16 * 16; y < maxy + 16; y += 16) { + int count = 0; + + if (base_y_a >= 0 && base_y_b >= 0 && base_y_c >= 0) + ++count; + + base_y_a += int_y_a; + base_y_b += int_y_b; + base_y_c += int_y_c; + + if (!count > 0) + continue; + + int yield_x = x >> 4, yield_y = y >> 4, yield_c = msaa ? count : 3; + if (!(-W / 2 <= yield_x && yield_x < W / 2 && -H / 2 <= yield_y && yield_y < H / 2)) + continue; + + yield_x += W / 2; + yield_y = H / 2 - yield_y - 1; + + vec2i p = {.x = x, .y = y}; + // https://stackoverflow.com/questions/24441631/how-exactly-does-opengl-do-perspectively-correct-linear-interpolation + float b0 = area(&p, p1, p2) / v0->pos[3]; + float b1 = area(p0, &p, p2) / v1->pos[3]; + float b2 = area(p0, p1, &p) / v2->pos[3]; + + float b_sum = b0 + b1 + b2; + b0 /= b_sum; + b1 /= b_sum; + b2 /= b_sum; + + float z = v0->pos[2] * b0 + v1->pos[2] * b1 + v2->pos[2] * b2; + if (z < -1.0 || z >= 1.0) + continue; + + unsigned short z_int = (unsigned short)(int)ldexpf(1.0 + z, 16 - 1); + unsigned short *z_cell = &z_buff[yield_y * 1024 + yield_x]; + + if (*z_cell > z_int) + continue; + + *z_cell = z_int; + + unsigned char r = clamp_color(v0->color[0] * b0 + v1->color[0] * b1 + v2->color[0] * b2); + unsigned char g = clamp_color(v0->color[1] * b0 + v1->color[1] * b1 + v2->color[1] * b2); + unsigned char b = clamp_color(v0->color[2] * b0 + v1->color[2] * b1 + v2->color[2] * b2); + + volatile unsigned char *ptr = + (unsigned char *)FB_BASE + + yield_y * 2048 + + yield_x * 3; + + *ptr++ = b; + *ptr++ = g; + *ptr++ = r; + } + + base_x_a += int_x_a; + base_x_b += int_x_b; + base_x_c += int_x_c; + + base_y_a = base_x_a; + base_y_b = base_x_b; + base_y_c = base_x_c; + } +} + +void persp_div(vec4 *pos) +{ + float w_inv = 1.0f / (*pos)[3]; + (*pos)[0] = (*pos)[0] * w_inv; + (*pos)[1] = (*pos)[1] * w_inv; + (*pos)[2] = (*pos)[2] * w_inv; + (*pos)[3] = w_inv; +} + +void tri +( + float x1, float y1, float z1, + float x2, float y2, float z2, + float x3, float y3, float z3 +) +{ + vertex v0 = {.pos = {x1, y1, z1, 1.0}, .color = {1.0, 0.0, 0.0, 0.0}}; + vertex v1 = {.pos = {x2, y2, z2, 1.0}, .color = {0.0, 1.0, 0.0, 0.0}}; + vertex v2 = {.pos = {x3, y3, z3, 1.0}, .color = {0.0, 0.0, 1.0, 0.0}}; + + mat_vec(&mvp, &v0.pos, &v0.pos); + mat_vec(&mvp, &v1.pos, &v1.pos); + mat_vec(&mvp, &v2.pos, &v2.pos); + + persp_div(&v0.pos); + persp_div(&v1.pos); + persp_div(&v2.pos); + + fixed(&v0.pos, &v0.grid); + fixed(&v1.pos, &v1.grid); + fixed(&v2.pos, &v2.grid); + + raster(&v0, &v1, &v2); +} + +// v2-v3 debe ser una diagonal, sino no sirve +void quad +( + float x1, float y1, float z1, + float x2, float y2, float z2, + float x3, float y3, float z3, + float x4, float y4, float z4 +) +{ + tri(x2, y2, z2, x1, y1, z1, x3, y3, z3); + tri(x2, y2, z2, x4, y4, z4, x3, y3, z3); +} + +void demo(void) +{ + //memset(FB_BASE, 0, 2048 * H); + //memset(z_buff, 0, sizeof z_buff); + + float a = -50; + float f = 1; + float w = 1; + + mat4 trans_z, trans_center, rot, scal; + mat_translate(0, 0, -5, &trans_z); + mat_rotate(1, 1, 1, a, &rot); + mat_translate(-0.5, -0.5, -0.5, &trans_center); + mat_scale(f, f, f, &scal); + + // https://stackoverflow.com/questions/16398463/getting-coordinates-for-glfrustum + float fov = 120; + float back = 1000.0; + float front = 1.0; + float aspect = 1.0; + + // transform from horizontal fov to vertical fov + fov = ldexpf(atanf(tanf(fov * M_PI_2 / 180) / aspect), 1); + + float tangent = tanf(fov / 2.0f); // tangent of half vertical fov + float height = front * tangent; // half height of near plane + float width = height * aspect; // half width of near plane + + // Escalar, luego rotar, luego frustum + mat_frustum(-width, width, -height, height, front, back, &mvp); + mat_mat(&mvp, &trans_z, &mvp); + mat_mat(&mvp, &rot, &mvp); + mat_mat(&mvp, &trans_center, &mvp); + mat_mat(&mvp, &scal, &mvp); + + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) + log("mvp[%d][%d] = %f", i, j, mvp[i][j]); + + quad + ( + 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 1.0, 0.0, 0.0, + 1.0, 1.0, 0.0 + ); + + quad + ( + 0.0, 0.0, 1.0, + 0.0, 1.0, 1.0, + 1.0, 0.0, 1.0, + 1.0, 1.0, 1.0 + ); + + quad + ( + 0.0, 0.0, 1.0, + 0.0, 1.0, 1.0, + 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0 + ); + + quad + ( + 1.0, 0.0, 1.0, + 1.0, 1.0, 1.0, + 1.0, 0.0, 0.0, + 1.0, 1.0, 0.0 + ); + + quad + ( + 0.0, 0.0, 0.0, + 0.0, 0.0, 1.0, + 1.0, 0.0, 0.0, + 1.0, 0.0, 1.0 + ); + + quad + ( + 0.0, 1.0, 0.0, + 0.0, 1.0, 1.0, + 1.0, 1.0, 0.0, + 1.0, 1.0, 1.0 + ); +} diff --git a/platform/wavelet3d/host_sw/gfx_boot.c b/platform/wavelet3d/host_sw/gfx_boot.c index 2a7071f..69335ef 100644 --- a/platform/wavelet3d/host_sw/gfx_boot.c +++ b/platform/wavelet3d/host_sw/gfx_boot.c @@ -40,7 +40,6 @@ enum gfx_probe_result gfx_probe(void) switch (hostif_rev) { case 0: - log("scheduler is in bootloader rom"); return GFX_PROBE_BOOTROM; case 1: diff --git a/platform/wavelet3d/host_sw/main.c b/platform/wavelet3d/host_sw/main.c index 7513c4c..5df035e 100644 --- a/platform/wavelet3d/host_sw/main.c +++ b/platform/wavelet3d/host_sw/main.c @@ -1,7 +1,11 @@ #include "init.h" +#include "vdc.h" int main() { + void demo(void); + demo(); + vdc_init(); init(); return 0; } diff --git a/platform/wavelet3d/host_sw/mod.mk b/platform/wavelet3d/host_sw/mod.mk index 2563f9e..8ca7dbd 100644 --- a/platform/wavelet3d/host_sw/mod.mk +++ b/platform/wavelet3d/host_sw/mod.mk @@ -7,8 +7,9 @@ define core/w3d_host_sw $(this)/obj_deps := picolibc/picolibc.specs - $(this)/cc_files := main.c gfx_boot.c init.c sgdma.c - $(this)/cc_flags = -g -march=rv32imafc -mabi=ilp32f --specs=$$(obj)/picolibc/picolibc.specs + $(this)/cc_files := demo.c main.c gfx_boot.c init.c sgdma.c vdc.c + $(this)/cc_flags = $$(if $$(enable_opt),-O3 -ffast-math) -g -march=rv32imafc \ + -mabi=ilp32f --specs=$$(obj)/picolibc/picolibc.specs $(this)/ld_extra := gfx_fw_payload.o $(this)/ld_flags := --oslib=semihost $(this)/ld_binary := w3d_host_flash diff --git a/platform/wavelet3d/host_sw/vdc.c b/platform/wavelet3d/host_sw/vdc.c new file mode 100644 index 0000000..f31f0db --- /dev/null +++ b/platform/wavelet3d/host_sw/vdc.c @@ -0,0 +1,54 @@ +#define MOD_NAME "vdc" + +#include "log.h" +#include "vdc.h" + +struct vdc_ctrl +{ + unsigned dacen : 1; + unsigned dacon : 1; + unsigned doublebuff : 1; + unsigned rsvd3 : 29; +}; + +struct vdc_geometry +{ + unsigned lines : 16; + unsigned length : 16; +}; + +struct vdc_stream +{ + unsigned hstride : 16; + unsigned rsvd16 : 16; +}; + +struct vdc_fb +{ + unsigned rsvd0 : 2; + unsigned addr : 30; +}; + +#define VDC_BASE 0x24000000 +#define VDC_CTRL (*(volatile struct vdc_ctrl *) (VDC_BASE + 0x00)) +#define VDC_GEOMETRY (*(volatile struct vdc_geometry *)(VDC_BASE + 0x04)) +#define VDC_STREAM (*(volatile struct vdc_stream *) (VDC_BASE + 0x08)) +#define VDC_FRONT (*(volatile struct vdc_fb *) (VDC_BASE + 0x0c)) +#define VDC_BACK (*(volatile struct vdc_fb *) (VDC_BASE + 0x10)) +#define VDC_RETIRE (*(volatile struct vdc_fb *) (VDC_BASE + 0x14)) + +#define FB_BASE ((void *)0x1d000000) + +void vdc_init(void) +{ + log("fb init, vdc_on=%u", VDC_CTRL.dacon); + + log("fb done"); + + VDC_FRONT = (struct vdc_fb){ .addr = (unsigned)FB_BASE >> 2, .rsvd0 = 0, }; + VDC_STREAM = (struct vdc_stream){ .hstride = 512, .rsvd16 = 0, }; + VDC_GEOMETRY = (struct vdc_geometry){ .length = 479, .lines = 479, }; + VDC_CTRL = (struct vdc_ctrl){ .dacen = 1, .dacon = 0, .doublebuff = 0, }; + + log("init done, vdc_on=%u", VDC_CTRL.dacon); +} diff --git a/platform/wavelet3d/host_sw/vdc.h b/platform/wavelet3d/host_sw/vdc.h new file mode 100644 index 0000000..eb5867a --- /dev/null +++ b/platform/wavelet3d/host_sw/vdc.h @@ -0,0 +1,6 @@ +#ifndef VDC_H +#define VDC_H + +void vdc_init(void); + +#endif diff --git a/platform/wavelet3d/host_sw/vdc_rayas.c b/platform/wavelet3d/host_sw/vdc_rayas.c new file mode 100644 index 0000000..5a583b6 --- /dev/null +++ b/platform/wavelet3d/host_sw/vdc_rayas.c @@ -0,0 +1,100 @@ +#define MOD_NAME "vdc" + +#include "log.h" +#include "vdc.h" + +struct vdc_ctrl +{ + unsigned dacen : 1; + unsigned dacon : 1; + unsigned doublebuff : 1; + unsigned rsvd3 : 29; +}; + +struct vdc_geometry +{ + unsigned lines : 16; + unsigned length : 16; +}; + +struct vdc_stream +{ + unsigned hstride : 16; + unsigned rsvd16 : 16; +}; + +struct vdc_fb +{ + unsigned rsvd0 : 2; + unsigned addr : 30; +}; + +#define VDC_BASE 0x24000000 +#define VDC_CTRL (*(volatile struct vdc_ctrl *) (VDC_BASE + 0x00)) +#define VDC_GEOMETRY (*(volatile struct vdc_geometry *)(VDC_BASE + 0x04)) +#define VDC_STREAM (*(volatile struct vdc_stream *) (VDC_BASE + 0x08)) +#define VDC_FRONT (*(volatile struct vdc_fb *) (VDC_BASE + 0x0c)) +#define VDC_BACK (*(volatile struct vdc_fb *) (VDC_BASE + 0x10)) +#define VDC_RETIRE (*(volatile struct vdc_fb *) (VDC_BASE + 0x14)) + +#define FB_BASE ((void *)0x1d000000) + +void vdc_init(void) +{ + log("fb init, vdc_on=%u", VDC_CTRL.dacon); + + unsigned r[] = { 0x00ff0000, 0x0000ff00, 0xff0000ff }; + unsigned g[] = { 0x0000ff00, 0xff0000ff, 0x00ff0000 }; + unsigned b[] = { 0xff0000ff, 0x00ff0000, 0x0000ff00 }; + + unsigned *p = (unsigned *)FB_BASE; + + for (unsigned n = 0; n < 120; ++n) { + unsigned *porig = p; + for (unsigned i = 0; i < 480; i += 3, p += 3) { + p[0] = r[0]; + p[1] = r[1]; + p[2] = r[2]; + } + p = porig + 512; + } + + for (unsigned n = 0; n < 120; ++n) { + unsigned *porig = p; + for (unsigned i = 0; i < 480; i += 3, p += 3) { + p[0] = g[0]; + p[1] = g[1]; + p[2] = g[2]; + } + p = porig + 512; + } + + for (unsigned n = 0; n < 120; ++n) { + unsigned *porig = p; + for (unsigned i = 0; i < 480; i += 3, p += 3) { + p[0] = b[0]; + p[1] = b[1]; + p[2] = b[2]; + } + p = porig + 512; + } + + for (unsigned n = 0; n < 120; ++n) { + unsigned *porig = p; + for (unsigned i = 0; i < 480; i += 3, p += 3) { + p[0] = r[0]; + p[1] = r[1]; + p[2] = r[2]; + } + p = porig + 512; + } + + log("fb done"); + + VDC_FRONT = (struct vdc_fb){ .addr = (unsigned)FB_BASE >> 2, .rsvd0 = 0, }; + VDC_STREAM = (struct vdc_stream){ .hstride = 512, .rsvd16 = 0, }; + VDC_GEOMETRY = (struct vdc_geometry){ .length = 479, .lines = 479, }; + VDC_CTRL = (struct vdc_ctrl){ .dacen = 1, .dacon = 0, .doublebuff = 0, }; + + log("init done, vdc_on=%u", VDC_CTRL.dacon); +} |
