1049 lines
34 KiB
C++
1049 lines
34 KiB
C++
#include <atomic>
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
#include <mutex>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <switch.h>
|
|
#include <thread>
|
|
#include <vector>
|
|
|
|
#include "sates.h"
|
|
#include "vec23.h"
|
|
#include <EGL/egl.h>
|
|
#include <EGL/eglext.h>
|
|
#include <arm_neon.h>
|
|
#include <condition_variable>
|
|
#include <glad/glad.h>
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
#include <glm/mat4x4.hpp>
|
|
|
|
#ifndef ENABLE_NXLINK
|
|
#define TRACE(fmt, ...) ((void)0)
|
|
#else
|
|
#include <unistd.h>
|
|
#define TRACE(fmt, ...) printf("%s: " fmt "\n", __PRETTY_FUNCTION__, ##__VA_ARGS__)
|
|
|
|
static int s_nxlinkSock = -1;
|
|
|
|
static void initNxLink() {
|
|
if (R_FAILED(socketInitializeDefault()))
|
|
return;
|
|
|
|
s_nxlinkSock = nxlinkStdio();
|
|
if (s_nxlinkSock >= 0)
|
|
TRACE("printf output now goes to nxlink server");
|
|
else
|
|
socketExit();
|
|
}
|
|
|
|
static void deinitNxLink() {
|
|
if (s_nxlinkSock >= 0) {
|
|
close(s_nxlinkSock);
|
|
socketExit();
|
|
s_nxlinkSock = -1;
|
|
}
|
|
}
|
|
|
|
extern "C" void userAppInit() {
|
|
initNxLink();
|
|
}
|
|
|
|
extern "C" void userAppExit() {
|
|
deinitNxLink();
|
|
}
|
|
|
|
#endif
|
|
|
|
static EGLDisplay s_display;
|
|
static EGLContext s_context;
|
|
static EGLSurface s_surface;
|
|
|
|
static bool initEgl(NWindow *win) {
|
|
|
|
s_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
|
if (!s_display) {
|
|
TRACE("Could not connect to display! error: %d", eglGetError());
|
|
goto _fail0;
|
|
}
|
|
|
|
eglInitialize(s_display, nullptr, nullptr);
|
|
|
|
if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
|
|
TRACE("Could not set API! error: %d", eglGetError());
|
|
goto _fail1;
|
|
}
|
|
|
|
EGLConfig config;
|
|
EGLint numConfigs;
|
|
static const EGLint framebufferAttributeList[] = { EGL_RENDERABLE_TYPE,
|
|
EGL_OPENGL_BIT,
|
|
EGL_RED_SIZE,
|
|
8,
|
|
EGL_GREEN_SIZE,
|
|
8,
|
|
EGL_BLUE_SIZE,
|
|
8,
|
|
EGL_ALPHA_SIZE,
|
|
8,
|
|
EGL_DEPTH_SIZE,
|
|
24,
|
|
EGL_STENCIL_SIZE,
|
|
8,
|
|
EGL_NONE };
|
|
eglChooseConfig(s_display, framebufferAttributeList, &config, 1, &numConfigs);
|
|
if (numConfigs == 0) {
|
|
TRACE("No config found! error: %d", eglGetError());
|
|
goto _fail1;
|
|
}
|
|
|
|
s_surface = eglCreateWindowSurface(s_display, config, win, nullptr);
|
|
if (!s_surface) {
|
|
TRACE("Surface creation failed! error: %d", eglGetError());
|
|
goto _fail1;
|
|
}
|
|
|
|
static const EGLint contextAttributeList[] = { EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
|
|
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
|
|
EGL_CONTEXT_MAJOR_VERSION_KHR,
|
|
4,
|
|
EGL_CONTEXT_MINOR_VERSION_KHR,
|
|
3,
|
|
EGL_NONE };
|
|
s_context = eglCreateContext(s_display, config, EGL_NO_CONTEXT, contextAttributeList);
|
|
if (!s_context) {
|
|
TRACE("Context creation failed! error: %d", eglGetError());
|
|
goto _fail2;
|
|
}
|
|
|
|
eglMakeCurrent(s_display, s_surface, s_surface, s_context);
|
|
return true;
|
|
|
|
_fail2:
|
|
eglDestroySurface(s_display, s_surface);
|
|
s_surface = nullptr;
|
|
_fail1:
|
|
eglTerminate(s_display);
|
|
s_display = nullptr;
|
|
_fail0:
|
|
return false;
|
|
}
|
|
|
|
static void deinitEgl() {
|
|
if (s_display) {
|
|
eglMakeCurrent(s_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
if (s_context) {
|
|
eglDestroyContext(s_display, s_context);
|
|
s_context = nullptr;
|
|
}
|
|
if (s_surface) {
|
|
eglDestroySurface(s_display, s_surface);
|
|
s_surface = nullptr;
|
|
}
|
|
eglTerminate(s_display);
|
|
s_display = nullptr;
|
|
}
|
|
}
|
|
|
|
static const char *const text_vs = R"text(
|
|
#version 330 core
|
|
layout(location=0) in vec2 inPos;
|
|
layout(location=1) in vec3 inColor;
|
|
out vec3 color;
|
|
void main() {
|
|
color = inColor;
|
|
gl_Position = vec4(inPos, 0.0, 1.0);
|
|
}
|
|
)text";
|
|
|
|
static const char *const text_fs = R"text(
|
|
#version 330 core
|
|
in vec3 color;
|
|
out vec4 fragColor;
|
|
void main() {
|
|
fragColor = vec4(color, 1.0);
|
|
}
|
|
)text";
|
|
|
|
static GLuint s_textProgram = 0;
|
|
static GLuint s_textVao = 0;
|
|
static GLuint s_textVbo = 0;
|
|
|
|
static float *s_textVertexData = nullptr;
|
|
static const int TEXT_BUFFER_FLOATS = 100 * 64 * 6 * 5;
|
|
|
|
static const unsigned char font8x8[11][8] = { { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00 }, { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00 },
|
|
{ 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00 }, { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00 },
|
|
{ 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00 }, { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00 },
|
|
{ 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00 }, { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00 },
|
|
{ 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00 }, { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00 },
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00 } };
|
|
|
|
static GLuint createAndCompileShader(GLenum type, const char *source);
|
|
|
|
static void initTextRenderer() {
|
|
GLuint vsh = createAndCompileShader(GL_VERTEX_SHADER, text_vs);
|
|
GLuint fsh = createAndCompileShader(GL_FRAGMENT_SHADER, text_fs);
|
|
|
|
s_textProgram = glCreateProgram();
|
|
glAttachShader(s_textProgram, vsh);
|
|
glAttachShader(s_textProgram, fsh);
|
|
glLinkProgram(s_textProgram);
|
|
glDeleteShader(vsh);
|
|
glDeleteShader(fsh);
|
|
|
|
glGenVertexArrays(1, &s_textVao);
|
|
glGenBuffers(1, &s_textVbo);
|
|
|
|
s_textVertexData = (float *)aligned_alloc(64, TEXT_BUFFER_FLOATS * sizeof(float));
|
|
}
|
|
|
|
static void drawTextPixel(float x, float y, float size, float r, float g, float b, float *vertexData, int *offset) {
|
|
float verts[] = { x, y, r, g, b, x + size, y, r, g, b, x + size, y + size, r, g, b,
|
|
x, y, r, g, b, x + size, y + size, r, g, b, x, y + size, r, g, b };
|
|
memcpy(&vertexData[*offset], verts, sizeof(verts));
|
|
*offset += 30;
|
|
}
|
|
|
|
static void drawChar(char c, float x, float y, float scale, float r, float g, float b, float *vertexData, int *offset) {
|
|
int idx = -1;
|
|
if (c >= '0' && c <= '9')
|
|
idx = c - '0';
|
|
else if (c == '.')
|
|
idx = 10;
|
|
else
|
|
return;
|
|
|
|
const unsigned char *glyph = font8x8[idx];
|
|
for (int row = 0; row < 8; row++) {
|
|
for (int col = 0; col < 8; col++) {
|
|
if (glyph[row] & (1 << col)) {
|
|
float px = x + col * scale;
|
|
float py = y - row * scale;
|
|
drawTextPixel(px, py, scale, r, g, b, vertexData, offset);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void drawText(const char *text, float x, float y, float scale, float r, float g, float b) {
|
|
float *vertexData = s_textVertexData;
|
|
int offset = 0;
|
|
float cx = x;
|
|
|
|
while (*text) {
|
|
drawChar(*text, cx, y, scale, r, g, b, vertexData, &offset);
|
|
cx += 8 * scale;
|
|
text++;
|
|
}
|
|
|
|
if (offset > 0) {
|
|
glUseProgram(s_textProgram);
|
|
glBindVertexArray(s_textVao);
|
|
glBindBuffer(GL_ARRAY_BUFFER, s_textVbo);
|
|
glBufferData(GL_ARRAY_BUFFER, offset * sizeof(float), vertexData, GL_DYNAMIC_DRAW);
|
|
|
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0);
|
|
glEnableVertexAttribArray(0);
|
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(2 * sizeof(float)));
|
|
glEnableVertexAttribArray(1);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, offset / 5);
|
|
}
|
|
}
|
|
|
|
static void cleanupTextRenderer() {
|
|
if (s_textVbo) {
|
|
glDeleteBuffers(1, &s_textVbo);
|
|
s_textVbo = 0;
|
|
}
|
|
if (s_textVao) {
|
|
glDeleteVertexArrays(1, &s_textVao);
|
|
s_textVao = 0;
|
|
}
|
|
if (s_textProgram) {
|
|
glDeleteProgram(s_textProgram);
|
|
s_textProgram = 0;
|
|
}
|
|
if (s_textVertexData) {
|
|
free(s_textVertexData);
|
|
s_textVertexData = nullptr;
|
|
}
|
|
}
|
|
|
|
static void setMesaConfig() {
|
|
|
|
setenv("MESA_NO_ERROR", "1", 1);
|
|
}
|
|
|
|
static u64 s_startTicks = 0;
|
|
static u64 s_lastFrameTime = 0;
|
|
static float s_fps = 0.0f;
|
|
static int s_frameCount = 0;
|
|
static u64 s_fpsUpdateTime = 0;
|
|
|
|
static int frame = 0;
|
|
|
|
static const char *const rt_vs = R"text(
|
|
#version 330 core
|
|
out vec2 uv;
|
|
|
|
void main()
|
|
{
|
|
vec2 pos = vec2(
|
|
(gl_VertexID == 2) ? 3.0 : -1.0,
|
|
(gl_VertexID == 1) ? 3.0 : -1.0
|
|
);
|
|
|
|
uv = 0.5 * (pos + 1.0);
|
|
gl_Position = vec4(pos, 0.0, 1.0);
|
|
}
|
|
)text";
|
|
|
|
static const char *const rt_fs = R"text(
|
|
#version 330 core
|
|
|
|
in vec2 uv;
|
|
out vec4 fragColor;
|
|
|
|
uniform sampler2D screenTex;
|
|
|
|
void main(){
|
|
fragColor = texture(screenTex, uv);
|
|
}
|
|
)text";
|
|
|
|
static GLuint s_program;
|
|
static GLuint s_vao, s_vbo;
|
|
|
|
static GLint resolutionLoc;
|
|
|
|
static GLint loc_mdlvMtx, loc_projMtx;
|
|
static GLint loc_time;
|
|
|
|
static GLuint tex[2], fbo[2];
|
|
|
|
static GLuint createAndCompileShader(GLenum type, const char *source) {
|
|
GLint success;
|
|
GLchar msg[512];
|
|
|
|
GLuint handle = glCreateShader(type);
|
|
if (!handle) {
|
|
TRACE("%u: cannot create shader", type);
|
|
return 0;
|
|
}
|
|
glShaderSource(handle, 1, &source, nullptr);
|
|
glCompileShader(handle);
|
|
glGetShaderiv(handle, GL_COMPILE_STATUS, &success);
|
|
|
|
if (!success) {
|
|
glGetShaderInfoLog(handle, sizeof(msg), nullptr, msg);
|
|
TRACE("%u: %s\n", type, msg);
|
|
glDeleteShader(handle);
|
|
return 0;
|
|
}
|
|
|
|
return handle;
|
|
}
|
|
|
|
int width = 1280;
|
|
int height = 720;
|
|
|
|
static GLuint screenTex;
|
|
|
|
float u_time;
|
|
|
|
static const int THREAD_COUNT = 2;
|
|
alignas(64) static std::atomic<int> nextTile(0);
|
|
|
|
static std::thread workers[THREAD_COUNT];
|
|
alignas(64) static std::atomic<bool> running(true);
|
|
alignas(64) static std::atomic<int> tilesDone(0);
|
|
|
|
static std::mutex workMutex;
|
|
static std::condition_variable workCV;
|
|
|
|
alignas(64) static bool workReady = false;
|
|
alignas(64) static int currentFrame = 0;
|
|
|
|
alignas(64) std::atomic<bool> cpuRenderRunning(false);
|
|
|
|
enum Material { WHITE, RED, GREEN, LIGHT, MIRROR };
|
|
|
|
struct alignas(16) PixelData {
|
|
float r, g, b, a;
|
|
};
|
|
|
|
alignas(64) static PixelData *frameBuffers[2] = { nullptr, nullptr };
|
|
alignas(64) static int currentRenderBuf = 0;
|
|
alignas(64) static float currentScale = 1.0f;
|
|
|
|
inline void intersectScene4(const vec3x4 &ro, const vec3x4 &rd, float32x4_t &t, uint32x4_t &mat, vec3x4 &normal) {
|
|
const float32x4_t INF = vdupq_n_f32(1e30f);
|
|
const float32x4_t ZERO = vdupq_n_f32(0.0f);
|
|
const float32x4_t EPS = vdupq_n_f32(1e-4f);
|
|
|
|
t = INF;
|
|
mat = vdupq_n_u32(WHITE);
|
|
normal.x = normal.y = normal.z = ZERO;
|
|
|
|
{
|
|
const float32x4_t cx = vdupq_n_f32(0.0f);
|
|
const float32x4_t cy = vdupq_n_f32(1.0f);
|
|
const float32x4_t cz = vdupq_n_f32(-0.5f);
|
|
|
|
vec3x4 oc;
|
|
oc.x = vsubq_f32(ro.x, cx);
|
|
oc.y = vsubq_f32(ro.y, cy);
|
|
oc.z = vsubq_f32(ro.z, cz);
|
|
|
|
float32x4_t b = dot(oc, rd);
|
|
float32x4_t c = vsubq_f32(dot(oc, oc), vdupq_n_f32(1.0f));
|
|
float32x4_t h = vsubq_f32(vmulq_f32(b, b), c);
|
|
|
|
uint32x4_t hasHit = vcgtq_f32(h, ZERO);
|
|
float32x4_t sqH = vsqrtq_f32(vmaxq_f32(h, ZERO));
|
|
|
|
float32x4_t t0 = vsubq_f32(vnegq_f32(b), sqH);
|
|
float32x4_t t1 = vaddq_f32(vnegq_f32(b), sqH);
|
|
|
|
uint32x4_t useNear = vcgtq_f32(t0, EPS);
|
|
float32x4_t tS = vbslq_f32(useNear, t0, t1);
|
|
|
|
uint32x4_t valid = vandq_u32(hasHit, vcgtq_f32(tS, EPS));
|
|
uint32x4_t closer = vcltq_f32(tS, t);
|
|
uint32x4_t mask = vandq_u32(valid, closer);
|
|
|
|
vec3x4 hp;
|
|
hp.x = vmlaq_f32(ro.x, rd.x, tS);
|
|
hp.y = vmlaq_f32(ro.y, rd.y, tS);
|
|
hp.z = vmlaq_f32(ro.z, rd.z, tS);
|
|
|
|
vec3x4 n;
|
|
n.x = vsubq_f32(hp.x, cx);
|
|
n.y = vsubq_f32(hp.y, cy);
|
|
n.z = vsubq_f32(hp.z, cz);
|
|
n = normalizeFast(n);
|
|
|
|
t = vbslq_f32(mask, tS, t);
|
|
mat = vbslq_u32(mask, vdupq_n_u32(MIRROR), mat);
|
|
normal.x = vbslq_f32(mask, n.x, normal.x);
|
|
normal.y = vbslq_f32(mask, n.y, normal.y);
|
|
normal.z = vbslq_f32(mask, n.z, normal.z);
|
|
}
|
|
|
|
auto testPlane = [&](float32x4_t roAxis, float32x4_t rdAxis, float target, float nx, float ny, float nz, uint32_t material) {
|
|
float32x4_t denom = rdAxis;
|
|
float32x4_t num = vsubq_f32(vdupq_n_f32(target), roAxis);
|
|
float32x4_t tP = vmulq_f32(num, fastRecip(denom));
|
|
|
|
uint32x4_t notParallel = vcgtq_f32(vabsq_f32(denom), EPS);
|
|
uint32x4_t ahead = vcgtq_f32(tP, EPS);
|
|
uint32x4_t closer = vcltq_f32(tP, t);
|
|
uint32x4_t mask = vandq_u32(notParallel, vandq_u32(ahead, closer));
|
|
|
|
t = vbslq_f32(mask, tP, t);
|
|
mat = vbslq_u32(mask, vdupq_n_u32(material), mat);
|
|
normal.x = vbslq_f32(mask, vdupq_n_f32(nx), normal.x);
|
|
normal.y = vbslq_f32(mask, vdupq_n_f32(ny), normal.y);
|
|
normal.z = vbslq_f32(mask, vdupq_n_f32(nz), normal.z);
|
|
};
|
|
|
|
testPlane(ro.y, rd.y, 0.0f, 0, 1, 0, WHITE);
|
|
|
|
{
|
|
float32x4_t denom = rd.y;
|
|
float32x4_t num = vsubq_f32(vdupq_n_f32(4.0f), ro.y);
|
|
float32x4_t tP = vmulq_f32(num, fastRecip(denom));
|
|
|
|
uint32x4_t notParallel = vcgtq_f32(vabsq_f32(denom), EPS);
|
|
uint32x4_t ahead = vcgtq_f32(tP, EPS);
|
|
uint32x4_t closer = vcltq_f32(tP, t);
|
|
uint32x4_t mask = vandq_u32(notParallel, vandq_u32(ahead, closer));
|
|
|
|
float32x4_t hx = vmlaq_f32(ro.x, rd.x, tP);
|
|
float32x4_t hz = vmlaq_f32(ro.z, rd.z, tP);
|
|
uint32x4_t inX = vcltq_f32(vabsq_f32(hx), vdupq_n_f32(1.0f));
|
|
uint32x4_t inZ = vcltq_f32(vabsq_f32(hz), vdupq_n_f32(1.0f));
|
|
uint32x4_t isLightPanel = vandq_u32(inX, inZ);
|
|
uint32x4_t ceilMat = vbslq_u32(isLightPanel, vdupq_n_u32(LIGHT), vdupq_n_u32(WHITE));
|
|
|
|
t = vbslq_f32(mask, tP, t);
|
|
mat = vbslq_u32(mask, ceilMat, mat);
|
|
normal.x = vbslq_f32(mask, vdupq_n_f32(0.0f), normal.x);
|
|
normal.y = vbslq_f32(mask, vdupq_n_f32(-1.0f), normal.y);
|
|
normal.z = vbslq_f32(mask, vdupq_n_f32(0.0f), normal.z);
|
|
}
|
|
|
|
testPlane(ro.x, rd.x, -2.0f, +1, 0, 0, RED);
|
|
|
|
testPlane(ro.x, rd.x, +2.0f, -1, 0, 0, GREEN);
|
|
|
|
testPlane(ro.z, rd.z, +2.0f, 0, 0, -1, WHITE);
|
|
}
|
|
|
|
inline void trace8(vec3x4 ro0, vec3x4 rd0, vec3x4 ro1, vec3x4 rd1, vec3f out0[4], vec3f out1[4], uint32x4_t rng0, uint32x4_t rng1) {
|
|
vec3x4 color0, color1;
|
|
color0.x = color0.y = color0.z = vdupq_n_f32(0.0f);
|
|
color1.x = color1.y = color1.z = vdupq_n_f32(0.0f);
|
|
|
|
vec3x4 tput0, tput1;
|
|
tput0.x = tput0.y = tput0.z = vdupq_n_f32(1.0f);
|
|
tput1.x = tput1.y = tput1.z = vdupq_n_f32(1.0f);
|
|
|
|
uint32x4_t alive0 = vdupq_n_u32(0xFFFFFFFF);
|
|
uint32x4_t alive1 = vdupq_n_u32(0xFFFFFFFF);
|
|
|
|
const float32x4_t BIAS = vdupq_n_f32(0.001f);
|
|
|
|
for (int bounce = 0; bounce < 3; bounce++) {
|
|
if (vaddvq_u32(vorrq_u32(alive0, alive1)) == 0)
|
|
break;
|
|
|
|
float32x4_t t0, t1;
|
|
uint32x4_t mat0, mat1;
|
|
vec3x4 n0, n1;
|
|
|
|
intersectScene4(ro0, rd0, t0, mat0, n0);
|
|
intersectScene4(ro1, rd1, t1, mat1, n1);
|
|
|
|
uint32x4_t hit0 = vcltq_f32(t0, vdupq_n_f32(1e29f));
|
|
uint32x4_t hit1 = vcltq_f32(t1, vdupq_n_f32(1e29f));
|
|
uint32x4_t miss0 = vandq_u32(alive0, vmvnq_u32(hit0));
|
|
uint32x4_t miss1 = vandq_u32(alive1, vmvnq_u32(hit1));
|
|
|
|
color0.x = vbslq_f32(miss0, vaddq_f32(color0.x, vmulq_f32(tput0.x, vdupq_n_f32(0.7f))), color0.x);
|
|
color1.x = vbslq_f32(miss1, vaddq_f32(color1.x, vmulq_f32(tput1.x, vdupq_n_f32(0.7f))), color1.x);
|
|
color0.y = vbslq_f32(miss0, vaddq_f32(color0.y, vmulq_f32(tput0.y, vdupq_n_f32(0.8f))), color0.y);
|
|
color1.y = vbslq_f32(miss1, vaddq_f32(color1.y, vmulq_f32(tput1.y, vdupq_n_f32(0.8f))), color1.y);
|
|
color0.z = vbslq_f32(miss0, vaddq_f32(color0.z, vmulq_f32(tput0.z, vdupq_n_f32(1.0f))), color0.z);
|
|
color1.z = vbslq_f32(miss1, vaddq_f32(color1.z, vmulq_f32(tput1.z, vdupq_n_f32(1.0f))), color1.z);
|
|
|
|
alive0 = vandq_u32(alive0, hit0);
|
|
alive1 = vandq_u32(alive1, hit1);
|
|
|
|
vec3x4 pos0, pos1;
|
|
pos0.x = vmlaq_f32(ro0.x, rd0.x, t0);
|
|
pos0.y = vmlaq_f32(ro0.y, rd0.y, t0);
|
|
pos0.z = vmlaq_f32(ro0.z, rd0.z, t0);
|
|
pos1.x = vmlaq_f32(ro1.x, rd1.x, t1);
|
|
pos1.y = vmlaq_f32(ro1.y, rd1.y, t1);
|
|
pos1.z = vmlaq_f32(ro1.z, rd1.z, t1);
|
|
|
|
uint32x4_t isLight0 = vandq_u32(alive0, vceqq_u32(mat0, vdupq_n_u32(LIGHT)));
|
|
uint32x4_t isLight1 = vandq_u32(alive1, vceqq_u32(mat1, vdupq_n_u32(LIGHT)));
|
|
uint32x4_t isMirror0 = vandq_u32(alive0, vceqq_u32(mat0, vdupq_n_u32(MIRROR)));
|
|
uint32x4_t isMirror1 = vandq_u32(alive1, vceqq_u32(mat1, vdupq_n_u32(MIRROR)));
|
|
|
|
uint32x4_t notLM0 = vmvnq_u32(vorrq_u32(vceqq_u32(mat0, vdupq_n_u32(LIGHT)), vceqq_u32(mat0, vdupq_n_u32(MIRROR))));
|
|
uint32x4_t notLM1 = vmvnq_u32(vorrq_u32(vceqq_u32(mat1, vdupq_n_u32(LIGHT)), vceqq_u32(mat1, vdupq_n_u32(MIRROR))));
|
|
uint32x4_t isDiff0 = vandq_u32(alive0, notLM0);
|
|
uint32x4_t isDiff1 = vandq_u32(alive1, notLM1);
|
|
|
|
color0.x = vbslq_f32(isLight0, vaddq_f32(color0.x, vmulq_f32(tput0.x, vdupq_n_f32(6.0f))), color0.x);
|
|
color1.x = vbslq_f32(isLight1, vaddq_f32(color1.x, vmulq_f32(tput1.x, vdupq_n_f32(6.0f))), color1.x);
|
|
color0.y = vbslq_f32(isLight0, vaddq_f32(color0.y, vmulq_f32(tput0.y, vdupq_n_f32(6.0f))), color0.y);
|
|
color1.y = vbslq_f32(isLight1, vaddq_f32(color1.y, vmulq_f32(tput1.y, vdupq_n_f32(6.0f))), color1.y);
|
|
color0.z = vbslq_f32(isLight0, vaddq_f32(color0.z, vmulq_f32(tput0.z, vdupq_n_f32(6.0f))), color0.z);
|
|
color1.z = vbslq_f32(isLight1, vaddq_f32(color1.z, vmulq_f32(tput1.z, vdupq_n_f32(6.0f))), color1.z);
|
|
|
|
alive0 = vandq_u32(alive0, vmvnq_u32(isLight0));
|
|
alive1 = vandq_u32(alive1, vmvnq_u32(isLight1));
|
|
|
|
vec3x4 refl0 = reflect(rd0, n0);
|
|
vec3x4 refl1 = reflect(rd1, n1);
|
|
rd0.x = vbslq_f32(isMirror0, refl0.x, rd0.x);
|
|
rd1.x = vbslq_f32(isMirror1, refl1.x, rd1.x);
|
|
rd0.y = vbslq_f32(isMirror0, refl0.y, rd0.y);
|
|
rd1.y = vbslq_f32(isMirror1, refl1.y, rd1.y);
|
|
rd0.z = vbslq_f32(isMirror0, refl0.z, rd0.z);
|
|
rd1.z = vbslq_f32(isMirror1, refl1.z, rd1.z);
|
|
|
|
uint32x4_t isWhite0 = vceqq_u32(mat0, vdupq_n_u32(WHITE));
|
|
uint32x4_t isWhite1 = vceqq_u32(mat1, vdupq_n_u32(WHITE));
|
|
uint32x4_t isRed0 = vceqq_u32(mat0, vdupq_n_u32(RED));
|
|
uint32x4_t isRed1 = vceqq_u32(mat1, vdupq_n_u32(RED));
|
|
|
|
float32x4_t w = vdupq_n_f32(0.9f), hi = vdupq_n_f32(1.0f), lo = vdupq_n_f32(0.2f);
|
|
float32x4_t aR0 = vbslq_f32(isWhite0, w, vbslq_f32(isRed0, hi, lo));
|
|
float32x4_t aR1 = vbslq_f32(isWhite1, w, vbslq_f32(isRed1, hi, lo));
|
|
float32x4_t aG0 = vbslq_f32(isWhite0, w, vbslq_f32(isRed0, lo, hi));
|
|
float32x4_t aG1 = vbslq_f32(isWhite1, w, vbslq_f32(isRed1, lo, hi));
|
|
float32x4_t aB0 = vbslq_f32(isWhite0, w, lo);
|
|
float32x4_t aB1 = vbslq_f32(isWhite1, w, lo);
|
|
|
|
tput0.x = vbslq_f32(isDiff0, vmulq_f32(tput0.x, aR0), tput0.x);
|
|
tput1.x = vbslq_f32(isDiff1, vmulq_f32(tput1.x, aR1), tput1.x);
|
|
tput0.y = vbslq_f32(isDiff0, vmulq_f32(tput0.y, aG0), tput0.y);
|
|
tput1.y = vbslq_f32(isDiff1, vmulq_f32(tput1.y, aG1), tput1.y);
|
|
tput0.z = vbslq_f32(isDiff0, vmulq_f32(tput0.z, aB0), tput0.z);
|
|
tput1.z = vbslq_f32(isDiff1, vmulq_f32(tput1.z, aB1), tput1.z);
|
|
|
|
vec3x4 bounce0 = cosineSampleHemisphere4(n0, rng0);
|
|
vec3x4 bounce1 = cosineSampleHemisphere4(n1, rng1);
|
|
|
|
rd0.x = vbslq_f32(isDiff0, bounce0.x, rd0.x);
|
|
rd1.x = vbslq_f32(isDiff1, bounce1.x, rd1.x);
|
|
rd0.y = vbslq_f32(isDiff0, bounce0.y, rd0.y);
|
|
rd1.y = vbslq_f32(isDiff1, bounce1.y, rd1.y);
|
|
rd0.z = vbslq_f32(isDiff0, bounce0.z, rd0.z);
|
|
rd1.z = vbslq_f32(isDiff1, bounce1.z, rd1.z);
|
|
|
|
ro0.x = vmlaq_f32(pos0.x, n0.x, BIAS);
|
|
ro1.x = vmlaq_f32(pos1.x, n1.x, BIAS);
|
|
ro0.y = vmlaq_f32(pos0.y, n0.y, BIAS);
|
|
ro1.y = vmlaq_f32(pos1.y, n1.y, BIAS);
|
|
ro0.z = vmlaq_f32(pos0.z, n0.z, BIAS);
|
|
ro1.z = vmlaq_f32(pos1.z, n1.z, BIAS);
|
|
}
|
|
|
|
float cr0[4], cg0[4], cb0[4];
|
|
float cr1[4], cg1[4], cb1[4];
|
|
vst1q_f32(cr0, color0.x);
|
|
vst1q_f32(cg0, color0.y);
|
|
vst1q_f32(cb0, color0.z);
|
|
vst1q_f32(cr1, color1.x);
|
|
vst1q_f32(cg1, color1.y);
|
|
vst1q_f32(cb1, color1.z);
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
out0[i] = { cr0[i], cg0[i], cb0[i] };
|
|
out1[i] = { cr1[i], cg1[i], cb1[i] };
|
|
}
|
|
}
|
|
|
|
static vec3f camForward;
|
|
static vec3f camRight;
|
|
static vec3f camUp;
|
|
static vec3f camPos;
|
|
|
|
void pinThread(int core) {
|
|
Handle thread = CUR_THREAD_HANDLE;
|
|
svcSetThreadCoreMask(thread, core, 1ULL << core);
|
|
}
|
|
|
|
int frameIndex = frame;
|
|
|
|
void renderTile(int startY, int endY, int frameIndex) {
|
|
|
|
const float32x4_t invW = vdupq_n_f32(1.0f / width);
|
|
const float32x4_t invH = vdupq_n_f32(1.0f / height);
|
|
const float aspect = float(width) / float(height);
|
|
|
|
const float32x4_t half = vdupq_n_f32(0.5f);
|
|
const float32x4_t two = vdupq_n_f32(2.0f);
|
|
const float32x4_t one = vdupq_n_f32(1.0f);
|
|
|
|
const uint32x4_t vA = vdupq_n_u32(1664525);
|
|
const uint32x4_t vC = vdupq_n_u32(1013904223);
|
|
|
|
float32x4_t vScale = vdupq_n_f32(currentScale);
|
|
float32x4_t vOne = vdupq_n_f32(1.0f);
|
|
|
|
for (int y = startY; y < endY; y++) {
|
|
|
|
float32x4_t py = vdupq_n_f32(float(y));
|
|
py = vaddq_f32(py, half);
|
|
float32x4_t uvy = vmulq_f32(py, invH);
|
|
float32x4_t sy = vsubq_f32(vmulq_f32(uvy, two), one);
|
|
|
|
for (int x = 0; x <= width - 8; x += 8) {
|
|
int base0 = y * width + x;
|
|
int base1 = base0 + 4;
|
|
|
|
int prefetchIdx = base0 + 32;
|
|
if (prefetchIdx < width * height)
|
|
__builtin_prefetch(&frameBuffers[currentRenderBuf][prefetchIdx], 1, 0);
|
|
|
|
float32x4_t px0 = { float(x) + 0.5f, float(x + 1) + 0.5f, float(x + 2) + 0.5f, float(x + 3) + 0.5f };
|
|
float32x4_t px1 = { float(x + 4) + 0.5f, float(x + 5) + 0.5f, float(x + 6) + 0.5f, float(x + 7) + 0.5f };
|
|
|
|
float32x4_t uvx0 = vmulq_f32(px0, invW);
|
|
float32x4_t uvx1 = vmulq_f32(px1, invW);
|
|
|
|
float32x4_t sx0 = vmulq_n_f32(vsubq_f32(vmulq_f32(uvx0, two), one), aspect);
|
|
float32x4_t sx1 = vmulq_n_f32(vsubq_f32(vmulq_f32(uvx1, two), one), aspect);
|
|
|
|
vec3x4 ro0, rd0, ro1, rd1;
|
|
ro0.x = ro1.x = vdupq_n_f32(camPos.x);
|
|
ro0.y = ro1.y = vdupq_n_f32(camPos.y);
|
|
ro0.z = ro1.z = vdupq_n_f32(camPos.z);
|
|
|
|
rd0.x = vaddq_f32(vdupq_n_f32(camForward.x), vaddq_f32(vmulq_n_f32(sx0, camRight.x), vmulq_n_f32(sy, camUp.x)));
|
|
rd0.y = vaddq_f32(vdupq_n_f32(camForward.y), vaddq_f32(vmulq_n_f32(sx0, camRight.y), vmulq_n_f32(sy, camUp.y)));
|
|
rd0.z = vaddq_f32(vdupq_n_f32(camForward.z), vaddq_f32(vmulq_n_f32(sx0, camRight.z), vmulq_n_f32(sy, camUp.z)));
|
|
|
|
rd1.x = vaddq_f32(vdupq_n_f32(camForward.x), vaddq_f32(vmulq_n_f32(sx1, camRight.x), vmulq_n_f32(sy, camUp.x)));
|
|
rd1.y = vaddq_f32(vdupq_n_f32(camForward.y), vaddq_f32(vmulq_n_f32(sx1, camRight.y), vmulq_n_f32(sy, camUp.y)));
|
|
rd1.z = vaddq_f32(vdupq_n_f32(camForward.z), vaddq_f32(vmulq_n_f32(sx1, camRight.z), vmulq_n_f32(sy, camUp.z)));
|
|
|
|
rd0 = normalizeFast(rd0);
|
|
rd1 = normalizeFast(rd1);
|
|
|
|
uint32_t baseIdx = (y * 9277 + currentFrame * 26699) | 1;
|
|
uint32x4_t vBase = vdupq_n_u32(baseIdx);
|
|
|
|
const uint32_t xOff0[4] = { (uint32_t)x * 1973, (uint32_t)(x + 1) * 1973, (uint32_t)(x + 2) * 1973, (uint32_t)(x + 3) * 1973 };
|
|
const uint32_t xOff1[4] = { (uint32_t)(x + 4) * 1973, (uint32_t)(x + 5) * 1973, (uint32_t)(x + 6) * 1973, (uint32_t)(x + 7) * 1973 };
|
|
|
|
uint32x4_t rng0 = vaddq_u32(vBase, vld1q_u32(xOff0));
|
|
uint32x4_t rng1 = vaddq_u32(vBase, vld1q_u32(xOff1));
|
|
|
|
rng0 = vmlaq_u32(vC, rng0, vA);
|
|
rng1 = vmlaq_u32(vC, rng1, vA);
|
|
|
|
vec3f col0[4], col1[4];
|
|
trace8(ro0, rd0, ro1, rd1, col0, col1, rng0, rng1);
|
|
|
|
float *fbPtr0 = (float *)&frameBuffers[0][base0];
|
|
float *fbPtr1 = (float *)&frameBuffers[0][base1];
|
|
|
|
float32x4x4_t vFB0 = vld4q_f32(fbPtr0);
|
|
float32x4x4_t vFB1 = vld4q_f32(fbPtr1);
|
|
|
|
float32x4_t vNewR0 = { col0[0].x, col0[1].x, col0[2].x, col0[3].x };
|
|
float32x4_t vNewG0 = { col0[0].y, col0[1].y, col0[2].y, col0[3].y };
|
|
float32x4_t vNewB0 = { col0[0].z, col0[1].z, col0[2].z, col0[3].z };
|
|
float32x4_t vNewR1 = { col1[0].x, col1[1].x, col1[2].x, col1[3].x };
|
|
float32x4_t vNewG1 = { col1[0].y, col1[1].y, col1[2].y, col1[3].y };
|
|
float32x4_t vNewB1 = { col1[0].z, col1[1].z, col1[2].z, col1[3].z };
|
|
|
|
vFB0.val[0] = vfmaq_f32(vFB0.val[0], vsubq_f32(vNewR0, vFB0.val[0]), vScale);
|
|
vFB0.val[1] = vfmaq_f32(vFB0.val[1], vsubq_f32(vNewG0, vFB0.val[1]), vScale);
|
|
vFB0.val[2] = vfmaq_f32(vFB0.val[2], vsubq_f32(vNewB0, vFB0.val[2]), vScale);
|
|
vFB0.val[3] = vOne;
|
|
|
|
vFB1.val[0] = vfmaq_f32(vFB1.val[0], vsubq_f32(vNewR1, vFB1.val[0]), vScale);
|
|
vFB1.val[1] = vfmaq_f32(vFB1.val[1], vsubq_f32(vNewG1, vFB1.val[1]), vScale);
|
|
vFB1.val[2] = vfmaq_f32(vFB1.val[2], vsubq_f32(vNewB1, vFB1.val[2]), vScale);
|
|
vFB1.val[3] = vOne;
|
|
|
|
vst4q_f32(fbPtr0, vFB0);
|
|
vst4q_f32(fbPtr1, vFB1);
|
|
}
|
|
}
|
|
}
|
|
|
|
const int TILE_H = 34;
|
|
|
|
void workerThread(int id) {
|
|
|
|
int core = id;
|
|
pinThread(core);
|
|
|
|
constexpr int tnum = 14;
|
|
|
|
while (running) {
|
|
std::unique_lock<std::mutex> lock(workMutex);
|
|
workCV.wait(lock, [] { return workReady || !running; });
|
|
lock.unlock();
|
|
|
|
if (!running)
|
|
return;
|
|
|
|
while (true) {
|
|
int tileBase = nextTile.fetch_add(tnum, std::memory_order_relaxed);
|
|
|
|
for (int t = 0; t < tnum; t++) {
|
|
int tile = tileBase + t;
|
|
int startY = tile * TILE_H;
|
|
|
|
if (startY >= height)
|
|
goto worker_done;
|
|
|
|
int endY = std::min(startY + TILE_H, height);
|
|
endY = std::min(endY, height);
|
|
|
|
renderTile(startY, endY, currentFrame);
|
|
}
|
|
}
|
|
worker_done:
|
|
tilesDone.fetch_add(1, std::memory_order_release);
|
|
}
|
|
}
|
|
|
|
void CPURTSceneinit() {
|
|
pinThread(2);
|
|
vec2f u_resolution(width, height);
|
|
GLint vsh = createAndCompileShader(GL_VERTEX_SHADER, rt_vs);
|
|
GLint fsh = createAndCompileShader(GL_FRAGMENT_SHADER, rt_fs);
|
|
if (!vsh || !fsh) {
|
|
TRACE("Shader compile failed — aborting");
|
|
return;
|
|
}
|
|
|
|
s_program = glCreateProgram();
|
|
glViewport(0, 0, 1280, 720);
|
|
glAttachShader(s_program, vsh);
|
|
glAttachShader(s_program, fsh);
|
|
glBindFragDataLocation(s_program, 0, "fragColor");
|
|
glLinkProgram(s_program);
|
|
|
|
resolutionLoc = glGetUniformLocation(s_program, "u_resolution");
|
|
loc_time = glGetUniformLocation(s_program, "u_time");
|
|
|
|
GLint success;
|
|
glGetProgramiv(s_program, GL_LINK_STATUS, &success);
|
|
if (!success) {
|
|
char buf[512];
|
|
glGetProgramInfoLog(s_program, sizeof(buf), nullptr, buf);
|
|
TRACE("Link error: %s", buf);
|
|
}
|
|
glDeleteShader(vsh);
|
|
glDeleteShader(fsh);
|
|
|
|
loc_mdlvMtx = glGetUniformLocation(s_program, "mdlvMtx");
|
|
loc_projMtx = glGetUniformLocation(s_program, "projMtx");
|
|
loc_time = glGetUniformLocation(s_program, "u_time");
|
|
|
|
static float vertices[] = {
|
|
-1.0f, -1.0f, 3.0f, -1.0f, -1.0f, 3.0f,
|
|
};
|
|
|
|
glGenTextures(2, tex);
|
|
glGenFramebuffers(2, fbo);
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex[i]);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo[i]);
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex[i], 0);
|
|
|
|
glClearColor(0, 0, 0, 1);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
}
|
|
|
|
glGenVertexArrays(1, &s_vao);
|
|
glGenBuffers(1, &s_vbo);
|
|
|
|
glBindVertexArray(s_vao);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, s_vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
|
|
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0);
|
|
glEnableVertexAttribArray(0);
|
|
|
|
glEnable(GL_FRAMEBUFFER_SRGB);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
glBindVertexArray(0);
|
|
|
|
glUseProgram(s_program);
|
|
auto projMtx = glm::perspective(glm::radians(40.0f), 1280.0f / 720.0f, 0.01f, 1000.0f);
|
|
glUniformMatrix4fv(loc_projMtx, 1, GL_FALSE, glm::value_ptr(projMtx));
|
|
|
|
s_startTicks = armGetSystemTick();
|
|
|
|
camPos = vec3f(0, 2, -6);
|
|
vec3f target = vec3f(0, 2, 0);
|
|
|
|
camForward = normalize(target - camPos);
|
|
camRight = normalize(cross(camForward, vec3f(0, 1, 0)));
|
|
camUp = cross(camRight, camForward);
|
|
|
|
s_lastFrameTime = s_startTicks;
|
|
s_fpsUpdateTime = s_startTicks;
|
|
s_frameCount = 0;
|
|
|
|
initTextRenderer();
|
|
|
|
nextTile = 0;
|
|
running = true;
|
|
cpuRenderRunning = false;
|
|
tilesDone = 0;
|
|
workReady = false;
|
|
|
|
for (int i = 0; i < THREAD_COUNT; i++) {
|
|
workers[i] = std::thread(workerThread, i);
|
|
}
|
|
|
|
int total = width * height;
|
|
|
|
frameBuffers[0] = (PixelData *)aligned_alloc(64, total * sizeof(PixelData));
|
|
frameBuffers[1] = (PixelData *)aligned_alloc(64, total * sizeof(PixelData));
|
|
|
|
memset(frameBuffers[0], 0, total * sizeof(PixelData));
|
|
memset(frameBuffers[1], 0, total * sizeof(PixelData));
|
|
|
|
glUniform1i(glGetUniformLocation(s_program, "screenTex"), 0);
|
|
|
|
glGenTextures(1, &screenTex);
|
|
glBindTexture(GL_TEXTURE_2D, screenTex);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
}
|
|
|
|
void startCPURender() {
|
|
currentRenderBuf = 0;
|
|
currentScale = 1.0f / float(frame + 1);
|
|
tilesDone = 0;
|
|
currentFrame = frame;
|
|
nextTile = 0;
|
|
{
|
|
std::lock_guard<std::mutex> lock(workMutex);
|
|
workReady = true;
|
|
}
|
|
workCV.notify_all();
|
|
}
|
|
|
|
void waitForRender() {
|
|
while (tilesDone.load(std::memory_order_acquire) < THREAD_COUNT)
|
|
__asm__("yield");
|
|
{
|
|
std::lock_guard<std::mutex> lock(workMutex);
|
|
workReady = false;
|
|
}
|
|
workCV.notify_all();
|
|
}
|
|
|
|
float getTime3() {
|
|
u64 elapsed = armGetSystemTick() - s_startTicks;
|
|
return (elapsed * 625 / 12) / 2000000000.0;
|
|
}
|
|
|
|
void CPURTRender() {
|
|
|
|
u64 currentTime = armGetSystemTick();
|
|
s_frameCount++;
|
|
u64 timeSinceUpdate = currentTime - s_fpsUpdateTime;
|
|
float secondsSinceUpdate = (timeSinceUpdate * 625.0f / 12.0f) / 1000000000.0f;
|
|
|
|
if (secondsSinceUpdate >= 0.01f) {
|
|
s_fps = s_frameCount / secondsSinceUpdate;
|
|
s_frameCount = 0;
|
|
s_fpsUpdateTime = currentTime;
|
|
}
|
|
|
|
memcpy(frameBuffers[1], frameBuffers[0], width * height * sizeof(PixelData));
|
|
|
|
currentRenderBuf = 0;
|
|
currentScale = 1.0f / float(frame + 1);
|
|
tilesDone = 0;
|
|
currentFrame = frame;
|
|
nextTile = 0;
|
|
{
|
|
std::lock_guard<std::mutex> lock(workMutex);
|
|
workReady = true;
|
|
}
|
|
workCV.notify_all();
|
|
|
|
while (true) {
|
|
int tnum = 6;
|
|
int tileBase = nextTile.fetch_add(tnum, std::memory_order_relaxed);
|
|
|
|
for (int t = 0; t < tnum; t++) {
|
|
int startY = (tileBase + t) * TILE_H;
|
|
if (startY >= height)
|
|
goto main_done;
|
|
renderTile(startY, std::min(startY + TILE_H, height), currentFrame);
|
|
}
|
|
}
|
|
main_done:
|
|
|
|
while (tilesDone.load(std::memory_order_acquire) < THREAD_COUNT)
|
|
__asm__("yield");
|
|
{
|
|
std::lock_guard<std::mutex> lock(workMutex);
|
|
workReady = false;
|
|
}
|
|
workCV.notify_all();
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
glViewport(0, 0, width, height);
|
|
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
glUseProgram(s_program);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, screenTex);
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, frameBuffers[1]);
|
|
glBindVertexArray(s_vao);
|
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
|
|
|
glUniform1f(loc_time, getTime3());
|
|
glUniform2f(resolutionLoc, width, height);
|
|
|
|
glBindVertexArray(0);
|
|
char fpsText[32];
|
|
snprintf(fpsText, sizeof(fpsText), "%.3f", s_fps);
|
|
drawText(fpsText, -0.95f, 0.90f, 0.02f, 1.0f, 0.0f, 0.0f);
|
|
char sampleText[64];
|
|
snprintf(sampleText, sizeof(sampleText), "Samples: %d", frame);
|
|
drawText(sampleText, -0.95f, 0.85f, 0.02f, 1.0f, 0.0f, 0.0f);
|
|
|
|
eglSwapBuffers(s_display, s_surface);
|
|
frame++;
|
|
}
|
|
|
|
void CPURTExit() {
|
|
cpuRenderRunning = false;
|
|
running = false;
|
|
nextTile = 0;
|
|
workCV.notify_all();
|
|
|
|
for (int i = 0; i < THREAD_COUNT; i++) {
|
|
if (workers[i].joinable())
|
|
workers[i].join();
|
|
}
|
|
cleanupTextRenderer();
|
|
glDeleteBuffers(1, &s_vbo);
|
|
glDeleteVertexArrays(1, &s_vao);
|
|
glDeleteProgram(s_program);
|
|
|
|
free(frameBuffers[0]);
|
|
free(frameBuffers[1]);
|
|
frameBuffers[0] = frameBuffers[1] = nullptr;
|
|
|
|
frame = 0;
|
|
}
|
|
|
|
int CPURTMain(int argc, char *argv[]) {
|
|
|
|
setMesaConfig();
|
|
|
|
if (!initEgl(nwindowGetDefault()))
|
|
return EXIT_FAILURE;
|
|
|
|
gladLoadGLLoader((GLADloadproc)eglGetProcAddress);
|
|
|
|
CPURTSceneinit();
|
|
|
|
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
|
|
|
|
PadState pad;
|
|
padInitializeDefault(&pad);
|
|
|
|
while (appletMainLoop()) {
|
|
|
|
padUpdate(&pad);
|
|
u32 kDown = padGetButtonsDown(&pad);
|
|
if (kDown & HidNpadButton_B) {
|
|
CPURTExit();
|
|
deinitEgl();
|
|
state = STATE_MENU;
|
|
return 0;
|
|
}
|
|
|
|
CPURTRender();
|
|
eglSwapBuffers(s_display, s_surface);
|
|
}
|
|
|
|
CPURTExit();
|
|
|
|
deinitEgl();
|
|
return EXIT_SUCCESS;
|
|
}
|