benchmark-toolbox: add benchmark-toolbox
a unified benchmarking tool
This commit is contained in:
2105
Source/Benchmark-Toolbox/source/furmark/BHRT.cpp
Normal file
2105
Source/Benchmark-Toolbox/source/furmark/BHRT.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3
Source/Benchmark-Toolbox/source/furmark/BHRT.h
Normal file
3
Source/Benchmark-Toolbox/source/furmark/BHRT.h
Normal file
@@ -0,0 +1,3 @@
|
||||
void BHRTSceneInit();
|
||||
void BHRTRender();
|
||||
void BHRTExit();
|
||||
1089
Source/Benchmark-Toolbox/source/furmark/CPURB.cpp
Normal file
1089
Source/Benchmark-Toolbox/source/furmark/CPURB.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3
Source/Benchmark-Toolbox/source/furmark/CPURB.h
Normal file
3
Source/Benchmark-Toolbox/source/furmark/CPURB.h
Normal file
@@ -0,0 +1,3 @@
|
||||
void CPURBSceneinit();
|
||||
void CPURBRender();
|
||||
void CPURBExit();
|
||||
1048
Source/Benchmark-Toolbox/source/furmark/CPURT.cpp
Normal file
1048
Source/Benchmark-Toolbox/source/furmark/CPURT.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3
Source/Benchmark-Toolbox/source/furmark/CPURT.h
Normal file
3
Source/Benchmark-Toolbox/source/furmark/CPURT.h
Normal file
@@ -0,0 +1,3 @@
|
||||
void CPURTSceneinit();
|
||||
void CPURTRender();
|
||||
void CPURTExit();
|
||||
770
Source/Benchmark-Toolbox/source/furmark/GPUPT.cpp
Normal file
770
Source/Benchmark-Toolbox/source/furmark/GPUPT.cpp
Normal file
@@ -0,0 +1,770 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <switch.h>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
#define GLM_FORCE_PURE
|
||||
#include "sates.h"
|
||||
#include "stb_image.h"
|
||||
#include <glm/gtc/constants.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.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 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);
|
||||
}
|
||||
|
||||
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 = (float *)malloc(100 * 64 * 6 * 5 * sizeof(float));
|
||||
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);
|
||||
}
|
||||
|
||||
free(vertexData);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void setMesaConfig() {
|
||||
|
||||
setenv("EGL_LOG_LEVEL", "debug", 1);
|
||||
setenv("MESA_VERBOSE", "all", 1);
|
||||
setenv("NOUVEAU_MESA_DEBUG", "1", 1);
|
||||
|
||||
setenv("NV50_PROG_OPTIMIZE", "0", 1);
|
||||
setenv("NV50_PROG_DEBUG", "1", 1);
|
||||
setenv("NV50_PROG_CHIPSET", "0x120", 1);
|
||||
}
|
||||
|
||||
static const char *const vertexShaderSource = 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 fragmentShaderSource = R"text(
|
||||
#version 330 core
|
||||
// Alright so originally this was supposed to be a way more complex shader
|
||||
// It was supposed to be a proceduraly generated path tracing scene
|
||||
// Unfortunately, my stupidity knows no bounds, and well over 5000 lines in I decided that I was better off waterboarding myself
|
||||
// To anyone who even wants to ask, no you don't want to see the original, it was a fucking war crime
|
||||
// Ask Adam why he thought it was a good idea to copy entire libraries into this shit, and then acted surprised when it didn't work
|
||||
// so, have a cornel box instead, because I cannot be fucked to make a proper shader file loader, despite needing one soon anyway.
|
||||
|
||||
in vec2 uv;
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform float u_time;
|
||||
|
||||
// Sampler variables
|
||||
uniform int u_frame;
|
||||
uniform sampler2D u_prevFrame;
|
||||
|
||||
#define WHITE 0
|
||||
#define RED 1
|
||||
#define GREEN 2
|
||||
#define LIGHT 3
|
||||
#define MIRROR 4
|
||||
|
||||
struct Hit {
|
||||
float dist;
|
||||
int material;
|
||||
vec3 normal;
|
||||
};
|
||||
|
||||
float hash(vec2 p){
|
||||
return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);
|
||||
}
|
||||
|
||||
vec3 rand3(vec3 p){
|
||||
float f = float(u_frame);
|
||||
|
||||
return vec3(
|
||||
hash(p.xy + f),
|
||||
hash(p.yz + f*1.37),
|
||||
hash(p.zx + f*2.17)
|
||||
) * 2.0 - 1.0;
|
||||
}
|
||||
|
||||
float sdSphere(vec3 p, float r){
|
||||
return length(p) - r;
|
||||
}
|
||||
|
||||
Hit map(vec3 p)
|
||||
{
|
||||
Hit h;
|
||||
h.dist = 1e9;
|
||||
h.material = WHITE;
|
||||
|
||||
// ---------- mirror sphere ----------
|
||||
float s = sdSphere(p - vec3(0,1.0,-0.5), 1.0);
|
||||
if(s < h.dist){
|
||||
h.dist = s;
|
||||
h.material = MIRROR;
|
||||
h.normal = normalize(p - vec3(0,1.0,-0.5));
|
||||
}
|
||||
|
||||
// ---------- room walls (inward planes) ----------
|
||||
|
||||
// left (red)
|
||||
float left = p.x + 2.0;
|
||||
if(left < h.dist){
|
||||
h.dist = left;
|
||||
h.material = RED;
|
||||
h.normal = vec3(1, 0, 0);
|
||||
}
|
||||
|
||||
// right (green)
|
||||
float right = 2.0 - p.x;
|
||||
if(right < h.dist){
|
||||
h.dist = right;
|
||||
h.material = GREEN;
|
||||
h.normal = vec3(-1, 0, 0);
|
||||
}
|
||||
|
||||
// floor
|
||||
float floor = p.y;
|
||||
if(floor < h.dist){
|
||||
h.dist = floor;
|
||||
h.material = WHITE;
|
||||
h.normal = vec3(0, 1, 0);
|
||||
}
|
||||
|
||||
// ceiling
|
||||
float ceil = 4.0 - p.y;
|
||||
if(ceil < h.dist){
|
||||
h.dist = ceil;
|
||||
h.material = WHITE;
|
||||
h.normal = vec3(0, -1, 0);
|
||||
}
|
||||
|
||||
// back wall
|
||||
float back = 2.0 - p.z;
|
||||
if(back < h.dist){
|
||||
h.dist = back;
|
||||
h.material = WHITE;
|
||||
h.normal = vec3(0, 0, -1);
|
||||
}
|
||||
|
||||
vec3 lCenter = vec3(0.0, 3.98, -1.2);
|
||||
vec3 lSize = vec3(0.9, 0.01, 0.9);
|
||||
|
||||
vec3 d = abs(p - lCenter) - lSize;
|
||||
float light = length(max(d,0.0)) + min(max(d.x,max(d.y,d.z)),0.0);
|
||||
|
||||
if(light < h.dist){
|
||||
h.dist = light;
|
||||
h.material = LIGHT;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
Hit raymarch(vec3 ro, vec3 rd)
|
||||
{
|
||||
float t = 0.0;
|
||||
|
||||
// 80 steps, lower values give better performance, while higher values increase load
|
||||
// increasing load beyond this only decreases power draw, while lowering results in graphical glitches
|
||||
for(int i=0;i<80;i++){
|
||||
vec3 p = ro + rd*t;
|
||||
Hit h = map(p);
|
||||
|
||||
if(h.dist < 0.001){
|
||||
h.dist = t;
|
||||
return h;
|
||||
}
|
||||
|
||||
t += h.dist;
|
||||
if(t > 50.0) break;
|
||||
}
|
||||
|
||||
Hit miss;
|
||||
miss.dist = -1.0;
|
||||
return miss;
|
||||
}
|
||||
|
||||
vec3 getColor(int m){
|
||||
if(m==RED) return vec3(1,0.2,0.2);
|
||||
if(m==GREEN) return vec3(0.2,1,0.2);
|
||||
return vec3(0.9);
|
||||
}
|
||||
|
||||
bool isLight(int m){ return m==LIGHT; }
|
||||
bool isMirror(int m){ return m==MIRROR; }
|
||||
|
||||
vec3 trace(vec3 ro, vec3 rd)
|
||||
{
|
||||
vec3 color = vec3(0);
|
||||
vec3 throughput = vec3(1);
|
||||
|
||||
// Controls the amount of bounces made by rays in the scene
|
||||
// reduced to 3 for parody with CPU mode
|
||||
for(int bounce=0; bounce<3; bounce++)
|
||||
{
|
||||
Hit h = raymarch(ro, rd);
|
||||
|
||||
// sky fallback
|
||||
if(h.dist < 0.0){
|
||||
color += throughput * vec3(0.7,0.8,1.0);
|
||||
break;
|
||||
}
|
||||
|
||||
vec3 pos = ro + rd*h.dist;
|
||||
vec3 n = h.normal;
|
||||
|
||||
// hit light
|
||||
if(isLight(h.material)){
|
||||
color += throughput * vec3(12.0);
|
||||
break;
|
||||
}
|
||||
|
||||
// mirror bounce
|
||||
if(isMirror(h.material)){
|
||||
rd = reflect(rd, n);
|
||||
}
|
||||
else{
|
||||
// diffuse bounce (hemisphere)
|
||||
vec3 r = rand3(pos + float(bounce) + float(u_frame));
|
||||
rd = normalize(n + r);
|
||||
// cosine weighting (energy can only be transfered)
|
||||
// I mean if you want to change this sure, but you'll get flashbanged.
|
||||
|
||||
float cosTheta = max(dot(rd, n), 0.0);
|
||||
|
||||
throughput *= getColor(h.material) * cosTheta;
|
||||
}
|
||||
|
||||
ro = pos + n*0.001;
|
||||
}
|
||||
|
||||
// Clamp color values so we don't get a concussion simulator
|
||||
return color;
|
||||
}
|
||||
|
||||
vec3 pathTrace(vec2 uv)
|
||||
{
|
||||
// convert uv to screen space values
|
||||
vec2 p = uv * 2.0 - 1.0;
|
||||
p.x *= u_resolution.x / u_resolution.y;
|
||||
|
||||
// Camera setup
|
||||
vec3 ro = vec3(0,2,-6);
|
||||
vec3 target = vec3(0,2,0);
|
||||
|
||||
vec3 forward = normalize(target - ro);
|
||||
vec3 right = normalize(cross(forward, vec3(0,1,0)));
|
||||
vec3 up = cross(right, forward);
|
||||
|
||||
vec3 rd = normalize(forward + p.x*right + p.y*up);
|
||||
|
||||
// Add pixel jittering to reduce noise
|
||||
vec2 jitter = vec2(
|
||||
hash(gl_FragCoord.xy + float(u_frame)),
|
||||
hash(gl_FragCoord.yx + float(u_frame))
|
||||
) / u_resolution;
|
||||
|
||||
return trace(ro, rd + vec3(jitter, 00));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
//setup output
|
||||
vec2 uv = gl_FragCoord.xy / u_resolution;
|
||||
vec3 newSample = pathTrace(uv);
|
||||
|
||||
// Accumulation
|
||||
vec3 prev = texture(u_prevFrame, gl_FragCoord.xy / u_resolution).rgb;
|
||||
vec3 accumulated;
|
||||
|
||||
if(u_frame == 0)
|
||||
accumulated = newSample;
|
||||
else
|
||||
accumulated = (prev *float(u_frame) + newSample) / float(u_frame + 1);
|
||||
|
||||
// Output final pixels, send to vertex
|
||||
fragColor = vec4(accumulated, 1.0);
|
||||
}
|
||||
)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 u64 s_startTicks;
|
||||
|
||||
static u64 s_lastFrameTime = 0;
|
||||
static float s_fps = 0.0f;
|
||||
static int s_frameCount = 0;
|
||||
static u64 s_fpsUpdateTime = 0;
|
||||
|
||||
static GLuint tex[2], fbo[2];
|
||||
static GLuint frameLoc, prevframeLoc;
|
||||
static int frame = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void GPUPTSceneInit() {
|
||||
GLint vsh = createAndCompileShader(GL_VERTEX_SHADER, vertexShaderSource);
|
||||
GLint fsh = createAndCompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
|
||||
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);
|
||||
|
||||
frameLoc = glGetUniformLocation(s_program, "u_frame");
|
||||
prevframeLoc = glGetUniformLocation(s_program, "u_prevFrame");
|
||||
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, 1280, 720, 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();
|
||||
|
||||
s_lastFrameTime = s_startTicks;
|
||||
s_fpsUpdateTime = s_startTicks;
|
||||
s_frameCount = 0;
|
||||
|
||||
initTextRenderer();
|
||||
}
|
||||
float getTime2() {
|
||||
u64 elapsed = armGetSystemTick() - s_startTicks;
|
||||
return (elapsed * 625 / 12) / 2000000000.0;
|
||||
}
|
||||
|
||||
void GPUPTRender() {
|
||||
static int X = 0;
|
||||
static int Y = 1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
glUniform1f(loc_time, getTime2());
|
||||
glUniform2f(resolutionLoc, 1280.0f, 720.0f);
|
||||
glBindVertexArray(s_vao);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, tex[X]);
|
||||
glUniform1i(prevframeLoc, 0);
|
||||
glUniform1i(frameLoc, frame);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo[Y]);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[Y]);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glBlitFramebuffer(0, 0, 1280, 720, 0, 0, 1280, 720, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
if (frame == 0) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo[X]);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
std::swap(X, Y);
|
||||
frame++;
|
||||
|
||||
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.90f, 0.02f, 1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
void GPUPTExit() {
|
||||
cleanupTextRenderer();
|
||||
glDeleteBuffers(1, &s_vbo);
|
||||
glDeleteVertexArrays(1, &s_vao);
|
||||
glDeleteProgram(s_program);
|
||||
frame = 0;
|
||||
}
|
||||
|
||||
int GPUPTMain(int argc, char *argv[]) {
|
||||
|
||||
setMesaConfig();
|
||||
|
||||
if (!initEgl(nwindowGetDefault()))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
gladLoadGLLoader((GLADloadproc)eglGetProcAddress);
|
||||
|
||||
GPUPTSceneInit();
|
||||
|
||||
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
|
||||
|
||||
PadState pad;
|
||||
padInitializeDefault(&pad);
|
||||
|
||||
while (appletMainLoop()) {
|
||||
|
||||
padUpdate(&pad);
|
||||
u32 kDown = padGetButtonsDown(&pad);
|
||||
if (kDown & HidNpadButton_B) {
|
||||
GPUPTExit();
|
||||
deinitEgl();
|
||||
state = STATE_MENU;
|
||||
return 0;
|
||||
}
|
||||
|
||||
GPUPTRender();
|
||||
eglSwapBuffers(s_display, s_surface);
|
||||
}
|
||||
|
||||
GPUPTExit();
|
||||
|
||||
deinitEgl();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
4
Source/Benchmark-Toolbox/source/furmark/GPUPT.h
Normal file
4
Source/Benchmark-Toolbox/source/furmark/GPUPT.h
Normal file
@@ -0,0 +1,4 @@
|
||||
void GPUPTSceneInit();
|
||||
void GPUPTRender();
|
||||
void GPUPTExit();
|
||||
void getTime2();
|
||||
691
Source/Benchmark-Toolbox/source/furmark/fmrkRAM.cpp
Normal file
691
Source/Benchmark-Toolbox/source/furmark/fmrkRAM.cpp
Normal file
@@ -0,0 +1,691 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <switch.h>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
#define GLM_FORCE_PURE
|
||||
#include "fur_png.h"
|
||||
#include "noise_png.h"
|
||||
#include "sates.h"
|
||||
#include "stb_image.h"
|
||||
#include "wall_png.h"
|
||||
#include "wunk_png.h"
|
||||
#include <glm/gtc/constants.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.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 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);
|
||||
}
|
||||
|
||||
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 = (float *)malloc(100 * 64 * 6 * 5 * sizeof(float));
|
||||
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);
|
||||
}
|
||||
|
||||
free(vertexData);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void setMesaConfig() {
|
||||
}
|
||||
|
||||
static const char *const vertexShaderSource = R"text(
|
||||
#version 330 core
|
||||
|
||||
out vec2 v_uv;
|
||||
|
||||
void main() {
|
||||
vec2 pos = vec2(
|
||||
(gl_VertexID == 1) ? 3.0 : -1.0,
|
||||
(gl_VertexID == 2) ? 3.0 : -1.0
|
||||
);
|
||||
v_uv = pos * 0.5 + 0.5;
|
||||
gl_Position = vec4(pos, 0.0, 1.0);
|
||||
}
|
||||
)text";
|
||||
|
||||
static const char *const fragmentShaderSource = R"text(
|
||||
#version 330 core
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform float u_time;
|
||||
uniform sampler2D u_texture1;
|
||||
uniform sampler2D u_texture2;
|
||||
uniform sampler2D u_texture3;
|
||||
uniform sampler2D u_texture4;
|
||||
|
||||
const float PI = 3.1416;
|
||||
const float TAU = 2 * PI;
|
||||
|
||||
float displace(vec3 p, sampler2D tex) {
|
||||
float s = 4.5;
|
||||
float u = s / TAU * atan(p.y / p.x);
|
||||
float v = sign(p.z) / TAU *
|
||||
acos((p.z * p.z * sqrt(s * s + 1) + sqrt(1 - p.z * p.z * s * s)) / (p.z * p.z + 1));
|
||||
vec2 uv = 2.0 * vec2(u, v);
|
||||
float disp = texture(tex, uv).r;
|
||||
return disp * 0.06;
|
||||
}
|
||||
|
||||
mat2 rot2D(float a) {
|
||||
float sa = sin(a);
|
||||
float ca = cos(a);
|
||||
return mat2(ca, sa, -sa, ca);
|
||||
}
|
||||
|
||||
void rotate(inout vec3 p) {
|
||||
p.xy *= rot2D(sin(u_time * 0.8) * 0.25);
|
||||
p.yz *= rot2D(sin(u_time * 0.7) * 0.2);
|
||||
}
|
||||
|
||||
float map(vec3 p) {
|
||||
float dist = length(vec2(length(p.xy) - 0.6, p.z)) - 0.22;
|
||||
return dist * 0.7;
|
||||
}
|
||||
|
||||
vec3 getNormal(vec3 p) {
|
||||
vec2 e = vec2(0.01, 0.0);
|
||||
vec3 n = vec3(map(p)) - vec3(map(p - e.xyy), map(p - e.yxy), map(p - e.yyx));
|
||||
return normalize(n);
|
||||
}
|
||||
|
||||
float rayMarch(vec3 ro, vec3 rd) {
|
||||
float dist = 0.0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
vec3 p = ro + dist * rd;
|
||||
|
||||
rotate(p);
|
||||
float hit = map(p);
|
||||
dist += hit;
|
||||
|
||||
// displace
|
||||
dist -= displace(0.5 * p, u_texture2);
|
||||
|
||||
vec2 uv = fract(p.xy * 0.317);
|
||||
float t39 = texture(u_texture1, uv.yx).r;
|
||||
float texNoise = texture(u_texture2, uv).r;
|
||||
float t3 = texture(u_texture3, uv * 0.73).r;
|
||||
float car = texture(u_texture4, uv * 0.37).r;
|
||||
|
||||
dist += (texNoise + t39 + t3 + car) * 1e-4;
|
||||
dist += (texNoise + t39 + t3 + car) * 1e-5;
|
||||
dist += (texNoise + t39 + t3 + car) * 1e-6;
|
||||
|
||||
if (dist > 100.0 || abs(hit) < 0.0001) break;
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
vec3 triPlanar(sampler2D tex, vec3 p, vec3 normal) {
|
||||
normal = abs(normal);
|
||||
normal = pow(normal, vec3(15));
|
||||
normal /= normal.x + normal.y + normal.z;
|
||||
p = p * 0.5 + 0.5;
|
||||
return (texture(tex, p.xy) * normal.z +
|
||||
texture(tex, p.xz) * normal.y +
|
||||
texture(tex, p.yz) * normal.x).rgb;
|
||||
}
|
||||
|
||||
vec3 render(vec2 offset) {
|
||||
vec2 uv = (4.0 * (gl_FragCoord.xy + offset) - u_resolution.xy) / u_resolution.y;
|
||||
vec3 col = vec3(0);
|
||||
|
||||
vec3 ro = vec3(0, 0, -1.0);
|
||||
vec3 rd = normalize(vec3(uv, 1.0));
|
||||
|
||||
// return to normal rendering path
|
||||
float dist = rayMarch(ro, rd);
|
||||
|
||||
if (dist < 100.0) {
|
||||
vec3 p = ro + dist * rd;
|
||||
rotate(p);
|
||||
col += triPlanar(u_texture1, p * 1.0, getNormal(p));
|
||||
} else {
|
||||
float phi = atan(uv.y, uv.x);
|
||||
float rho = length(uv) + 0.2;
|
||||
|
||||
phi += sin(0.3 * rho - 0.5 * u_time);
|
||||
|
||||
float h = sin(8.0 * phi) * 0.5 + 0.5;
|
||||
|
||||
vec2 st;
|
||||
st.x = 3.0 * phi / PI;
|
||||
st.y = u_time * 0.5 + PI / (rho + 0.1 * smoothstep(0.45, 0.5, h));
|
||||
|
||||
col += texture(u_texture3, st).rgb;
|
||||
|
||||
float occ = smoothstep(0.0, 0.45, h) - smoothstep(0.5, 1.0, h);
|
||||
col *= 1.0 - 0.45 * occ * rho;
|
||||
col *= rho;
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
vec3 renderAAx4() {
|
||||
vec4 e = vec4(0.125, -0.125, 0.375, -0.375);
|
||||
vec3 colAA = render(e.xz) + render(e.yw) + render(e.wx) + render(e.zy);
|
||||
return colAA /= 4.0;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 color = renderAAx4();
|
||||
|
||||
fragColor = vec4(color, 1.0);
|
||||
}
|
||||
)text";
|
||||
|
||||
static GLuint s_program;
|
||||
static GLuint s_vao, s_vbo;
|
||||
|
||||
static GLint resolutionLoc;
|
||||
static GLuint tex1;
|
||||
static GLuint tex2;
|
||||
static GLuint tex3;
|
||||
static GLuint tex4;
|
||||
|
||||
static GLint loc_mdlvMtx, loc_projMtx;
|
||||
static GLint loc_lightPos, loc_ambient, loc_diffuse, loc_specular, loc_tex_diffuse;
|
||||
static GLint loc_time;
|
||||
|
||||
static u64 s_startTicks;
|
||||
|
||||
static u64 s_lastFrameTime = 0;
|
||||
static float s_fps = 0.0f;
|
||||
static int s_frameCount = 0;
|
||||
static u64 s_fpsUpdateTime = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void frRamSceneInit() {
|
||||
GLint vsh = createAndCompileShader(GL_VERTEX_SHADER, vertexShaderSource);
|
||||
GLint fsh = createAndCompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
|
||||
|
||||
s_program = glCreateProgram();
|
||||
glAttachShader(s_program, vsh);
|
||||
glAttachShader(s_program, fsh);
|
||||
glLinkProgram(s_program);
|
||||
resolutionLoc = glGetUniformLocation(s_program, "u_resolution");
|
||||
GLuint tex1Loc = glGetUniformLocation(s_program, "u_texture1");
|
||||
GLuint tex2Loc = glGetUniformLocation(s_program, "u_texture2");
|
||||
GLuint tex3Loc = glGetUniformLocation(s_program, "u_texture3");
|
||||
GLuint tex4Loc = glGetUniformLocation(s_program, "u_texture4");
|
||||
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_lightPos = glGetUniformLocation(s_program, "lightPos");
|
||||
loc_ambient = glGetUniformLocation(s_program, "ambient");
|
||||
loc_diffuse = glGetUniformLocation(s_program, "diffuse");
|
||||
loc_specular = glGetUniformLocation(s_program, "specular");
|
||||
loc_tex_diffuse = glGetUniformLocation(s_program, "tex_diffuse");
|
||||
loc_time = glGetUniformLocation(s_program, "u_time");
|
||||
|
||||
struct Vertex {
|
||||
float position[3];
|
||||
float color[3];
|
||||
glm::vec2 texcoord;
|
||||
glm::vec3 normal;
|
||||
};
|
||||
|
||||
static const Vertex vertices[] = {
|
||||
{ { -0.5f, -0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f } },
|
||||
{ { 0.5f, -0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f } },
|
||||
{ { 0.0f, 0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f } },
|
||||
};
|
||||
|
||||
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, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, position));
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, color));
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, texcoord));
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, normal));
|
||||
glEnableVertexAttribArray(3);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
int width, height, nchan;
|
||||
stbi_set_flip_vertically_on_load(true);
|
||||
|
||||
glGenTextures(1, &tex1);
|
||||
glBindTexture(GL_TEXTURE_2D, tex1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
stbi_uc *img = stbi_load_from_memory((const stbi_uc *)fur_png, fur_png_size, &width, &height, &nchan, 4);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
|
||||
stbi_image_free(img);
|
||||
|
||||
glGenTextures(1, &tex2);
|
||||
glBindTexture(GL_TEXTURE_2D, tex2);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
img = stbi_load_from_memory((const stbi_uc *)noise_png, noise_png_size, &width, &height, &nchan, 4);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
|
||||
stbi_image_free(img);
|
||||
|
||||
glGenTextures(1, &tex3);
|
||||
glBindTexture(GL_TEXTURE_2D, tex3);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
img = stbi_load_from_memory((const stbi_uc *)wall_png, wall_png_size, &width, &height, &nchan, 4);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
|
||||
stbi_image_free(img);
|
||||
|
||||
glGenTextures(1, &tex4);
|
||||
glBindTexture(GL_TEXTURE_2D, tex4);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
img = stbi_load_from_memory((const stbi_uc *)wunk_png, wunk_png_size, &width, &height, &nchan, 4);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
|
||||
stbi_image_free(img);
|
||||
|
||||
glUseProgram(s_program);
|
||||
auto projMtx = glm::perspective(glm::radians(40.0f), 1280.0f / 720.0f, 0.01f, 500.0f);
|
||||
glUniformMatrix4fv(loc_projMtx, 1, GL_FALSE, glm::value_ptr(projMtx));
|
||||
glUniform4f(loc_lightPos, 0.0f, 0.0f, 0.5f, 1.0f);
|
||||
glUniform3f(loc_ambient, 0.1f, 0.1f, 0.1f);
|
||||
glUniform3f(loc_diffuse, 0.4f, 0.4f, 0.4f);
|
||||
glUniform4f(loc_specular, 0.5f, 0.5f, 0.5f, 20.0f);
|
||||
|
||||
s_startTicks = armGetSystemTick();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, tex1);
|
||||
glUniform1i(tex1Loc, 0);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, tex2);
|
||||
glUniform1i(tex2Loc, 1);
|
||||
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, tex3);
|
||||
glUniform1i(tex3Loc, 2);
|
||||
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
glBindTexture(GL_TEXTURE_2D, tex4);
|
||||
glUniform1i(tex4Loc, 3);
|
||||
|
||||
s_lastFrameTime = s_startTicks;
|
||||
s_fpsUpdateTime = s_startTicks;
|
||||
s_frameCount = 0;
|
||||
|
||||
initTextRenderer();
|
||||
}
|
||||
float getTime1() {
|
||||
u64 elapsed = armGetSystemTick() - s_startTicks;
|
||||
return (elapsed * 625 / 12) / 2000000000.0;
|
||||
}
|
||||
|
||||
void frRamRender() {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
glViewport(0, 0, 1280, 720);
|
||||
glUniform1f(loc_time, getTime1());
|
||||
glUniform2f(resolutionLoc, 640.0f, 360.0f);
|
||||
glBindVertexArray(s_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void frRamExit() {
|
||||
cleanupTextRenderer();
|
||||
glDeleteBuffers(1, &s_vbo);
|
||||
glDeleteVertexArrays(1, &s_vao);
|
||||
glDeleteProgram(s_program);
|
||||
}
|
||||
|
||||
int frRamMain(int argc, char *argv[]) {
|
||||
|
||||
setMesaConfig();
|
||||
|
||||
if (!initEgl(nwindowGetDefault()))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
gladLoadGLLoader((GLADloadproc)eglGetProcAddress);
|
||||
|
||||
frRamSceneInit();
|
||||
|
||||
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
|
||||
|
||||
PadState pad;
|
||||
padInitializeDefault(&pad);
|
||||
|
||||
while (appletMainLoop()) {
|
||||
|
||||
padUpdate(&pad);
|
||||
u32 kDown = padGetButtonsDown(&pad);
|
||||
if (kDown & HidNpadButton_B) {
|
||||
frRamExit();
|
||||
deinitEgl();
|
||||
state = STATE_MENU;
|
||||
return 0;
|
||||
}
|
||||
|
||||
frRamRender();
|
||||
eglSwapBuffers(s_display, s_surface);
|
||||
}
|
||||
|
||||
frRamExit();
|
||||
|
||||
deinitEgl();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
4
Source/Benchmark-Toolbox/source/furmark/fmrkRAM.h
Normal file
4
Source/Benchmark-Toolbox/source/furmark/fmrkRAM.h
Normal file
@@ -0,0 +1,4 @@
|
||||
void frRamSceneInit();
|
||||
void frRamRender();
|
||||
void frRamExit();
|
||||
void getTime1();
|
||||
682
Source/Benchmark-Toolbox/source/furmark/furmark.cpp
Normal file
682
Source/Benchmark-Toolbox/source/furmark/furmark.cpp
Normal file
@@ -0,0 +1,682 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <switch.h>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
#define GLM_FORCE_PURE
|
||||
#include "fur_png.h"
|
||||
#include "noise_png.h"
|
||||
#include "sates.h"
|
||||
#include "stb_image.h"
|
||||
#include "wall_png.h"
|
||||
#include <glm/gtc/constants.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.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);
|
||||
|
||||
eglSwapInterval(s_display, 0);
|
||||
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 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 } };
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 = (float *)malloc(100 * 64 * 6 * 5 * sizeof(float));
|
||||
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);
|
||||
}
|
||||
|
||||
free(vertexData);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void setMesaConfig() {
|
||||
|
||||
setenv("MESA_NO_ERROR", "1", 1);
|
||||
|
||||
setenv("NV50_PROG_CHIPSET", "0", 1);
|
||||
}
|
||||
|
||||
static const char *const vertexShaderSource = R"text(
|
||||
#version 330 core
|
||||
|
||||
out vec2 v_uv;
|
||||
|
||||
void main() {
|
||||
vec2 pos = vec2(
|
||||
(gl_VertexID == 1) ? 3.0 : -1.0,
|
||||
(gl_VertexID == 2) ? 3.0 : -1.0
|
||||
);
|
||||
v_uv = pos * 0.5 + 0.5;
|
||||
gl_Position = vec4(pos, 0.0, 1.0);
|
||||
}
|
||||
)text";
|
||||
|
||||
static const char *const fragmentShaderSource = R"text(
|
||||
#version 330 core
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform float u_time;
|
||||
uniform sampler2D u_texture1;
|
||||
uniform sampler2D u_texture2;
|
||||
uniform sampler2D u_texture3;
|
||||
|
||||
const float PI = 3.1416;
|
||||
const float TAU = 2 * PI;
|
||||
|
||||
float displace(vec3 p, sampler2D tex) {
|
||||
float s = 4.5;
|
||||
float u = s / TAU * atan(p.y / p.x);
|
||||
float v = sign(p.z) / TAU *
|
||||
acos((p.z * p.z * sqrt(s * s + 1) + sqrt(1 - p.z * p.z * s * s)) / (p.z * p.z + 1));
|
||||
vec2 uv = 2.0 * vec2(u, v);
|
||||
float disp = texture(tex, uv).r;
|
||||
return disp * 0.06;
|
||||
}
|
||||
|
||||
mat2 rot2D(float a) {
|
||||
float sa = sin(a);
|
||||
float ca = cos(a);
|
||||
return mat2(ca, sa, -sa, ca);
|
||||
}
|
||||
|
||||
void rotate(inout vec3 p) {
|
||||
p.xy *= rot2D(sin(u_time * 0.8) * 0.25);
|
||||
p.yz *= rot2D(sin(u_time * 0.7) * 0.2);
|
||||
}
|
||||
|
||||
float map(vec3 p) {
|
||||
float dist = length(vec2(length(p.xy) - 0.6, p.z)) - 0.22;
|
||||
return dist * 0.7;
|
||||
}
|
||||
|
||||
vec3 getNormal(vec3 p) {
|
||||
vec2 e = vec2(0.01, 0.0);
|
||||
vec3 n = vec3(map(p)) - vec3(map(p - e.xyy), map(p - e.yxy), map(p - e.yyx));
|
||||
return normalize(n);
|
||||
}
|
||||
|
||||
float rayMarch(vec3 ro, vec3 rd) {
|
||||
float dist = 0.0;
|
||||
for (int i = 0; i < 48; i++) {
|
||||
vec3 p = ro + dist * rd;
|
||||
|
||||
rotate(p);
|
||||
float hit = map(p);
|
||||
dist += hit;
|
||||
|
||||
// displace
|
||||
dist -= displace(0.5 * p, u_texture2);
|
||||
|
||||
// Saturate FP32
|
||||
vec3 q = p;
|
||||
q = q * 1.37 + 0.13;
|
||||
q = q * q - 0.17;
|
||||
q = q * 0.91 + q.yzx * 0.09;
|
||||
dist += dot(q, q) * 1e-5;
|
||||
|
||||
// Register stress
|
||||
vec4 r0 = vec4(p, dist);
|
||||
vec4 r1 = sin(r0 * 3.1);
|
||||
vec4 r2 = cos(r1 * 2.7);
|
||||
vec4 r3 = r2 * r1;
|
||||
vec4 r4 = normalize(r3);
|
||||
dist += dot(r4, vec4(1e-5));
|
||||
|
||||
if (dist > 100.0 || abs(hit) < 0.0001) break;
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
vec3 triPlanar(sampler2D tex, vec3 p, vec3 normal) {
|
||||
normal = abs(normal);
|
||||
normal = pow(normal, vec3(15));
|
||||
normal /= normal.x + normal.y + normal.z;
|
||||
p = p * 0.5 + 0.5;
|
||||
return (texture(tex, p.xy) * normal.z +
|
||||
texture(tex, p.xz) * normal.y +
|
||||
texture(tex, p.yz) * normal.x).rgb;
|
||||
}
|
||||
|
||||
vec3 render(vec2 offset) {
|
||||
vec2 uv = (2.0 * (gl_FragCoord.xy + offset) - u_resolution.xy) / u_resolution.y;
|
||||
vec3 col = vec3(0);
|
||||
|
||||
vec3 ro = vec3(0, 0, -1.0);
|
||||
vec3 rd = normalize(vec3(uv, 1.0));
|
||||
|
||||
// return to normal rendering path
|
||||
float dist = rayMarch(ro, rd);
|
||||
|
||||
if (dist < 100.0) {
|
||||
vec3 p = ro + dist * rd;
|
||||
rotate(p);
|
||||
col += triPlanar(u_texture1, p * 1.0, getNormal(p));
|
||||
} else {
|
||||
float phi = atan(uv.y, uv.x);
|
||||
float rho = length(uv) + 0.2;
|
||||
|
||||
phi += sin(0.3 * rho - 0.5 * u_time);
|
||||
|
||||
float h = sin(8.0 * phi) * 0.5 + 0.5;
|
||||
|
||||
vec2 st;
|
||||
st.x = 3.0 * phi / PI;
|
||||
st.y = u_time * 0.5 + PI / (rho + 0.1 * smoothstep(0.45, 0.5, h));
|
||||
|
||||
col += texture(u_texture3, st).rgb;
|
||||
|
||||
float occ = smoothstep(0.0, 0.45, h) - smoothstep(0.5, 1.0, h);
|
||||
col *= 1.0 - 0.45 * occ * rho;
|
||||
col *= rho;
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
vec3 renderAAx4() {
|
||||
vec4 e = vec4(0.125, -0.125, 0.375, -0.375);
|
||||
vec3 colAA = render(e.xz) + render(e.yw) + render(e.wx) + render(e.zy);
|
||||
return colAA /= 4.0;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 color = renderAAx4();
|
||||
|
||||
fragColor = vec4(color, 1.0);
|
||||
}
|
||||
)text";
|
||||
|
||||
static GLuint s_program;
|
||||
static GLuint s_vao, s_vbo;
|
||||
|
||||
static GLint resolutionLoc;
|
||||
static GLuint tex1;
|
||||
static GLuint tex2;
|
||||
static GLuint tex3;
|
||||
|
||||
static GLint loc_mdlvMtx, loc_projMtx;
|
||||
static GLint loc_lightPos, loc_ambient, loc_diffuse, loc_specular, loc_tex_diffuse;
|
||||
static GLint loc_time;
|
||||
|
||||
static u64 s_startTicks;
|
||||
|
||||
static u64 s_lastFrameTime = 0;
|
||||
static float s_fps = 0.0f;
|
||||
static int s_frameCount = 0;
|
||||
static u64 s_fpsUpdateTime = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void frSceneInit() {
|
||||
GLint vsh = createAndCompileShader(GL_VERTEX_SHADER, vertexShaderSource);
|
||||
GLint fsh = createAndCompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
|
||||
|
||||
s_program = glCreateProgram();
|
||||
glAttachShader(s_program, vsh);
|
||||
glAttachShader(s_program, fsh);
|
||||
glLinkProgram(s_program);
|
||||
resolutionLoc = glGetUniformLocation(s_program, "u_resolution");
|
||||
GLuint tex1Loc = glGetUniformLocation(s_program, "u_texture1");
|
||||
GLuint tex2Loc = glGetUniformLocation(s_program, "u_texture2");
|
||||
GLuint tex3Loc = glGetUniformLocation(s_program, "u_texture3");
|
||||
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_lightPos = glGetUniformLocation(s_program, "lightPos");
|
||||
loc_ambient = glGetUniformLocation(s_program, "ambient");
|
||||
loc_diffuse = glGetUniformLocation(s_program, "diffuse");
|
||||
loc_specular = glGetUniformLocation(s_program, "specular");
|
||||
loc_tex_diffuse = glGetUniformLocation(s_program, "tex_diffuse");
|
||||
loc_time = glGetUniformLocation(s_program, "u_time");
|
||||
|
||||
struct Vertex {
|
||||
float position[3];
|
||||
float color[3];
|
||||
glm::vec2 texcoord;
|
||||
glm::vec3 normal;
|
||||
};
|
||||
|
||||
static const Vertex vertices[] = {
|
||||
{ { -0.5f, -0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f } },
|
||||
{ { 0.5f, -0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f } },
|
||||
{ { 0.0f, 0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f } },
|
||||
};
|
||||
|
||||
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, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, position));
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, color));
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, texcoord));
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, normal));
|
||||
glEnableVertexAttribArray(3);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
int width, height, nchan;
|
||||
stbi_set_flip_vertically_on_load(true);
|
||||
|
||||
glGenTextures(1, &tex1);
|
||||
glBindTexture(GL_TEXTURE_2D, tex1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
stbi_uc *img = stbi_load_from_memory((const stbi_uc *)fur_png, fur_png_size, &width, &height, &nchan, 4);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
|
||||
stbi_image_free(img);
|
||||
|
||||
glGenTextures(1, &tex2);
|
||||
glBindTexture(GL_TEXTURE_2D, tex2);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
img = stbi_load_from_memory((const stbi_uc *)noise_png, noise_png_size, &width, &height, &nchan, 4);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
|
||||
stbi_image_free(img);
|
||||
|
||||
glGenTextures(1, &tex3);
|
||||
glBindTexture(GL_TEXTURE_2D, tex3);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
img = stbi_load_from_memory((const stbi_uc *)wall_png, wall_png_size, &width, &height, &nchan, 4);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
|
||||
stbi_image_free(img);
|
||||
|
||||
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));
|
||||
glUniform4f(loc_lightPos, 0.0f, 0.0f, 0.5f, 1.0f);
|
||||
glUniform3f(loc_ambient, 0.1f, 0.1f, 0.1f);
|
||||
glUniform3f(loc_diffuse, 0.4f, 0.4f, 0.4f);
|
||||
glUniform4f(loc_specular, 0.5f, 0.5f, 0.5f, 20.0f);
|
||||
|
||||
s_startTicks = armGetSystemTick();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, tex1);
|
||||
glUniform1i(tex1Loc, 0);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, tex2);
|
||||
glUniform1i(tex2Loc, 1);
|
||||
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, tex3);
|
||||
glUniform1i(tex3Loc, 2);
|
||||
|
||||
s_lastFrameTime = s_startTicks;
|
||||
s_fpsUpdateTime = s_startTicks;
|
||||
s_frameCount = 0;
|
||||
|
||||
initTextRenderer();
|
||||
}
|
||||
float getTime() {
|
||||
u64 elapsed = armGetSystemTick() - s_startTicks;
|
||||
return (elapsed * 625 / 12) / 2000000000.0;
|
||||
}
|
||||
|
||||
void frRender() {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
glUniform1f(loc_time, getTime());
|
||||
glUniform2f(resolutionLoc, 1280.0f, 720.0f);
|
||||
glBindVertexArray(s_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void frExit() {
|
||||
cleanupTextRenderer();
|
||||
glDeleteBuffers(1, &s_vbo);
|
||||
glDeleteVertexArrays(1, &s_vao);
|
||||
glDeleteProgram(s_program);
|
||||
}
|
||||
|
||||
int frMain(int argc, char *argv[]) {
|
||||
|
||||
setMesaConfig();
|
||||
|
||||
if (!initEgl(nwindowGetDefault()))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
gladLoadGLLoader((GLADloadproc)eglGetProcAddress);
|
||||
|
||||
frSceneInit();
|
||||
|
||||
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
|
||||
|
||||
PadState pad;
|
||||
padInitializeDefault(&pad);
|
||||
|
||||
while (appletMainLoop()) {
|
||||
|
||||
padUpdate(&pad);
|
||||
u32 kDown = padGetButtonsDown(&pad);
|
||||
if (kDown & HidNpadButton_B) {
|
||||
frExit();
|
||||
deinitEgl();
|
||||
state = STATE_MENU;
|
||||
return 0;
|
||||
}
|
||||
|
||||
frRender();
|
||||
eglSwapBuffers(s_display, s_surface);
|
||||
}
|
||||
|
||||
frExit();
|
||||
|
||||
deinitEgl();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
4
Source/Benchmark-Toolbox/source/furmark/furmark.h
Normal file
4
Source/Benchmark-Toolbox/source/furmark/furmark.h
Normal file
@@ -0,0 +1,4 @@
|
||||
void frSceneInit();
|
||||
void frRender();
|
||||
void frExit();
|
||||
void getTime();
|
||||
239
Source/Benchmark-Toolbox/source/furmark/run_furmark.cpp
Normal file
239
Source/Benchmark-Toolbox/source/furmark/run_furmark.cpp
Normal file
@@ -0,0 +1,239 @@
|
||||
#include <atomic>
|
||||
#include <switch.h>
|
||||
#include <thread>
|
||||
|
||||
#include "run_furmark.h"
|
||||
#include "sates.h"
|
||||
#include <EGL/egl.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
extern void frSceneInit();
|
||||
extern void frRender();
|
||||
extern void frExit();
|
||||
extern void frRamSceneInit();
|
||||
extern void frRamRender();
|
||||
extern void frRamExit();
|
||||
extern void GPUPTSceneInit();
|
||||
extern void GPUPTRender();
|
||||
extern void GPUPTExit();
|
||||
extern void BHRTSceneInit();
|
||||
extern void BHRTRender();
|
||||
extern void BHRTExit();
|
||||
extern void CPURTSceneinit();
|
||||
extern void CPURTRender();
|
||||
extern void CPURTExit();
|
||||
extern void CPURBSceneinit();
|
||||
extern void CPURBRender();
|
||||
extern void CPURBExit();
|
||||
|
||||
AppState state = STATE_MENU;
|
||||
|
||||
namespace {
|
||||
|
||||
std::thread g_thread;
|
||||
std::atomic<bool> g_stop{ false };
|
||||
std::atomic<bool> g_running{ false };
|
||||
|
||||
EGLDisplay s_dpy = EGL_NO_DISPLAY;
|
||||
EGLContext s_ctx = EGL_NO_CONTEXT;
|
||||
EGLSurface s_surf = EGL_NO_SURFACE;
|
||||
|
||||
bool eglUp() {
|
||||
s_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
if (s_dpy == EGL_NO_DISPLAY)
|
||||
return false;
|
||||
if (!eglInitialize(s_dpy, nullptr, nullptr))
|
||||
return false;
|
||||
if (!eglBindAPI(EGL_OPENGL_API))
|
||||
return false;
|
||||
|
||||
const EGLint cfgAttr[] = { 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 };
|
||||
EGLConfig cfg;
|
||||
EGLint n = 0;
|
||||
if (!eglChooseConfig(s_dpy, cfgAttr, &cfg, 1, &n) || n == 0)
|
||||
return false;
|
||||
|
||||
const EGLint ctxAttr[] = { EGL_CONTEXT_MAJOR_VERSION, 4, EGL_CONTEXT_MINOR_VERSION, 3, EGL_NONE };
|
||||
s_ctx = eglCreateContext(s_dpy, cfg, EGL_NO_CONTEXT, ctxAttr);
|
||||
if (s_ctx == EGL_NO_CONTEXT)
|
||||
return false;
|
||||
|
||||
s_surf = EGL_NO_SURFACE;
|
||||
if (eglMakeCurrent(s_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, s_ctx) != EGL_TRUE)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void eglDown() {
|
||||
if (s_dpy) {
|
||||
eglMakeCurrent(s_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
if (s_ctx)
|
||||
eglDestroyContext(s_dpy, s_ctx);
|
||||
if (s_surf != EGL_NO_SURFACE)
|
||||
eglDestroySurface(s_dpy, s_surf);
|
||||
eglTerminate(s_dpy);
|
||||
}
|
||||
s_ctx = EGL_NO_CONTEXT;
|
||||
s_surf = EGL_NO_SURFACE;
|
||||
s_dpy = EGL_NO_DISPLAY;
|
||||
eglReleaseThread();
|
||||
}
|
||||
|
||||
void sceneInit(int which) {
|
||||
switch (which) {
|
||||
case 0:
|
||||
frSceneInit();
|
||||
break;
|
||||
case 1:
|
||||
frRamSceneInit();
|
||||
break;
|
||||
case 2:
|
||||
GPUPTSceneInit();
|
||||
break;
|
||||
case 3:
|
||||
BHRTSceneInit();
|
||||
break;
|
||||
case 4:
|
||||
CPURTSceneinit();
|
||||
break;
|
||||
case 5:
|
||||
CPURBSceneinit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
void sceneRender(int which) {
|
||||
switch (which) {
|
||||
case 0:
|
||||
frRender();
|
||||
break;
|
||||
case 1:
|
||||
frRamRender();
|
||||
break;
|
||||
case 2:
|
||||
GPUPTRender();
|
||||
break;
|
||||
case 3:
|
||||
BHRTRender();
|
||||
break;
|
||||
case 4:
|
||||
CPURTRender();
|
||||
break;
|
||||
case 5:
|
||||
CPURBRender();
|
||||
break;
|
||||
}
|
||||
}
|
||||
void sceneExit(int which) {
|
||||
switch (which) {
|
||||
case 0:
|
||||
frExit();
|
||||
break;
|
||||
case 1:
|
||||
frRamExit();
|
||||
break;
|
||||
case 2:
|
||||
GPUPTExit();
|
||||
break;
|
||||
case 3:
|
||||
BHRTExit();
|
||||
break;
|
||||
case 4:
|
||||
CPURTExit();
|
||||
break;
|
||||
case 5:
|
||||
CPURBExit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void worker(int which) {
|
||||
if (!eglUp()) {
|
||||
eglDown();
|
||||
g_running.store(false);
|
||||
return;
|
||||
}
|
||||
gladLoadGLLoader((GLADloadproc)eglGetProcAddress);
|
||||
|
||||
GLuint fbo = 0, rbColor = 0, rbDepth = 0;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glGenRenderbuffers(1, &rbColor);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbColor);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1280, 720);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbColor);
|
||||
glGenRenderbuffers(1, &rbDepth);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbDepth);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 1280, 720);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbDepth);
|
||||
glViewport(0, 0, 1280, 720);
|
||||
|
||||
sceneInit(which);
|
||||
|
||||
const u64 frameNs = 16666666ULL;
|
||||
while (!g_stop.load()) {
|
||||
u64 t0 = armGetSystemTick();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glViewport(0, 0, 1280, 720);
|
||||
sceneRender(which);
|
||||
|
||||
GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
glFlush();
|
||||
while (!g_stop.load()) {
|
||||
GLenum r = glClientWaitSync(fence, 0, 0);
|
||||
if (r != GL_TIMEOUT_EXPIRED)
|
||||
break;
|
||||
svcSleepThread(500000ULL);
|
||||
}
|
||||
glDeleteSync(fence);
|
||||
|
||||
u64 dt = armTicksToNs(armGetSystemTick() - t0);
|
||||
if (dt < frameNs)
|
||||
svcSleepThread(frameNs - dt);
|
||||
}
|
||||
sceneExit(which);
|
||||
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
glDeleteRenderbuffers(1, &rbColor);
|
||||
glDeleteRenderbuffers(1, &rbDepth);
|
||||
eglDown();
|
||||
g_running.store(false);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" void run_furmark_start(int which) {
|
||||
if (g_running.load())
|
||||
return;
|
||||
if (g_thread.joinable())
|
||||
g_thread.join();
|
||||
g_stop.store(false);
|
||||
g_running.store(true);
|
||||
appletSetAutoSleepDisabled(true);
|
||||
g_thread = std::thread(worker, which);
|
||||
}
|
||||
|
||||
extern "C" void run_furmark_stop(void) {
|
||||
g_stop.store(true);
|
||||
if (g_thread.joinable())
|
||||
g_thread.join();
|
||||
g_running.store(false);
|
||||
appletSetAutoSleepDisabled(false);
|
||||
}
|
||||
|
||||
extern "C" int run_furmark_running(void) {
|
||||
return g_running.load() ? 1 : 0;
|
||||
}
|
||||
13
Source/Benchmark-Toolbox/source/furmark/run_furmark.h
Normal file
13
Source/Benchmark-Toolbox/source/furmark/run_furmark.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void run_furmark_start(int which);
|
||||
void run_furmark_stop(void);
|
||||
int run_furmark_running(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
3
Source/Benchmark-Toolbox/source/furmark/sates.h
Normal file
3
Source/Benchmark-Toolbox/source/furmark/sates.h
Normal file
@@ -0,0 +1,3 @@
|
||||
enum AppState { STATE_MENU, STATE_FURMARK, STATE_FURMARK_RB, STATE_GPU_PT, STATE_BH_RT, STATE_CPU_RT, STATE_CPU_RB };
|
||||
|
||||
extern AppState state;
|
||||
6751
Source/Benchmark-Toolbox/source/furmark/stb_image.h
Normal file
6751
Source/Benchmark-Toolbox/source/furmark/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
314
Source/Benchmark-Toolbox/source/furmark/vec23.h
Normal file
314
Source/Benchmark-Toolbox/source/furmark/vec23.h
Normal file
@@ -0,0 +1,314 @@
|
||||
#pragma once
|
||||
#include <arm_neon.h>
|
||||
|
||||
struct vec2f {
|
||||
float x, y;
|
||||
|
||||
inline vec2f() {
|
||||
}
|
||||
inline vec2f(float x_, float y_) : x(x_), y(y_) {
|
||||
}
|
||||
};
|
||||
|
||||
struct vec3x4 {
|
||||
float32x4_t x, y, z;
|
||||
};
|
||||
|
||||
inline float32x4_t dot(const vec3x4 &a, const vec3x4 &b) {
|
||||
float32x4_t acc = vmulq_f32(a.x, b.x);
|
||||
acc = vfmaq_f32(acc, a.y, b.y);
|
||||
acc = vfmaq_f32(acc, a.z, b.z);
|
||||
return acc;
|
||||
}
|
||||
|
||||
inline vec3x4 normalize(vec3x4 v) {
|
||||
float32x4_t len2 = vfmaq_f32(vfmaq_f32(vmulq_f32(v.x, v.x), v.y, v.y), v.z, v.z);
|
||||
|
||||
float32x4_t invLen = vrsqrteq_f32(len2);
|
||||
|
||||
invLen = vmulq_f32(vrsqrtsq_f32(vmulq_f32(len2, invLen), invLen), invLen);
|
||||
|
||||
return { vmulq_f32(v.x, invLen), vmulq_f32(v.y, invLen), vmulq_f32(v.z, invLen) };
|
||||
}
|
||||
|
||||
inline vec3x4 reflect(const vec3x4 &v, const vec3x4 &n) {
|
||||
float32x4_t two_d = vmulq_n_f32(dot(v, n), 2.0f);
|
||||
vec3x4 r;
|
||||
r.x = vfmsq_f32(v.x, n.x, two_d);
|
||||
r.y = vfmsq_f32(v.y, n.y, two_d);
|
||||
r.z = vfmsq_f32(v.z, n.z, two_d);
|
||||
return r;
|
||||
}
|
||||
|
||||
struct vec3f {
|
||||
float x, y, z;
|
||||
|
||||
inline vec3f() {
|
||||
}
|
||||
inline vec3f(float v) : x(v), y(v), z(v) {
|
||||
}
|
||||
inline vec3f(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {
|
||||
}
|
||||
};
|
||||
|
||||
inline vec3f operator+(const vec3f &a, const vec3f &b) {
|
||||
return vec3f(a.x + b.x, a.y + b.y, a.z + b.z);
|
||||
}
|
||||
|
||||
inline vec3f operator-(const vec3f &a, const vec3f &b) {
|
||||
return vec3f(a.x - b.x, a.y - b.y, a.z - b.z);
|
||||
}
|
||||
|
||||
inline vec3f operator-(const vec3f &v) {
|
||||
return vec3f(-v.x, -v.y, -v.z);
|
||||
}
|
||||
|
||||
inline vec3f &operator*=(vec3f &a, const vec3f &b) {
|
||||
a.x *= b.x;
|
||||
a.y *= b.y;
|
||||
a.z *= b.z;
|
||||
return a;
|
||||
}
|
||||
|
||||
inline vec3f &operator*=(vec3f &a, float b) {
|
||||
a.x *= b;
|
||||
a.y *= b;
|
||||
a.z *= b;
|
||||
return a;
|
||||
}
|
||||
|
||||
inline vec3f operator*(const vec3f &a, float b) {
|
||||
return vec3f(a.x * b, a.y * b, a.z * b);
|
||||
}
|
||||
|
||||
inline vec3f operator*(float b, const vec3f &a) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
inline vec3f operator*(const vec3f &a, const vec3f &b) {
|
||||
return vec3f(a.x * b.x, a.y * b.y, a.z * b.z);
|
||||
}
|
||||
|
||||
inline vec3f &operator+=(vec3f &a, const vec3f &b) {
|
||||
a.x += b.x;
|
||||
a.y += b.y;
|
||||
a.z += b.z;
|
||||
return a;
|
||||
}
|
||||
|
||||
inline vec3f operator/(const vec3f &a, float b) {
|
||||
float inv = 1.0f / b;
|
||||
return vec3f(a.x * inv, a.y * inv, a.z * inv);
|
||||
}
|
||||
|
||||
inline vec3f &operator/=(vec3f &a, float b) {
|
||||
float inv = 1.0f / b;
|
||||
a.x *= inv;
|
||||
a.y *= inv;
|
||||
a.z *= inv;
|
||||
return a;
|
||||
}
|
||||
|
||||
inline float dot(const vec3f &a, const vec3f &b) {
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z;
|
||||
}
|
||||
|
||||
inline vec3f normalize(const vec3f &v) {
|
||||
float len2 = dot(v, v);
|
||||
float invLen = 1.0f / sqrtf(len2 + 1e-20f);
|
||||
return v * invLen;
|
||||
}
|
||||
|
||||
inline vec3f cross(const vec3f &a, const vec3f &b) {
|
||||
return vec3f(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
|
||||
}
|
||||
|
||||
static inline float32x4_t fastRecip(float32x4_t x) {
|
||||
float32x4_t r = vrecpeq_f32(x);
|
||||
r = vmulq_f32(vrecpsq_f32(x, r), r);
|
||||
r = vmulq_f32(vrecpsq_f32(x, r), r);
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline float32x4_t fastRsqrt(float32x4_t x) {
|
||||
float32x4_t r = vrsqrteq_f32(x);
|
||||
r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(x, r), r));
|
||||
r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(x, r), r));
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline vec3x4 normalizeFast(const vec3x4 &v) {
|
||||
float32x4_t len2 = vfmaq_f32(vmulq_f32(v.z, v.z), v.y, v.y);
|
||||
|
||||
len2 = vfmaq_f32(len2, v.x, v.x);
|
||||
|
||||
float32x4_t invLen = fastRsqrt(len2);
|
||||
|
||||
vec3x4 out;
|
||||
out.x = vmulq_f32(v.x, invLen);
|
||||
out.y = vmulq_f32(v.y, invLen);
|
||||
out.z = vmulq_f32(v.z, invLen);
|
||||
return out;
|
||||
}
|
||||
|
||||
inline uint32x4_t xorshift4(uint32x4_t &s) {
|
||||
s = veorq_u32(s, vshlq_n_u32(s, 13));
|
||||
s = veorq_u32(s, vshrq_n_u32(s, 17));
|
||||
s = veorq_u32(s, vshlq_n_u32(s, 5));
|
||||
return s;
|
||||
}
|
||||
|
||||
inline float32x4_t toFloat01(uint32x4_t x) {
|
||||
uint32x4_t m = vandq_u32(x, vdupq_n_u32(0xFFFFFF));
|
||||
return vmulq_n_f32(vcvtq_f32_u32(m), 1.0f / float(0xFFFFFF));
|
||||
}
|
||||
|
||||
inline float32x4_t sin4(float32x4_t phi) {
|
||||
|
||||
const float32x4_t pi = vdupq_n_f32(3.14159265f);
|
||||
const float32x4_t pi_2 = vdupq_n_f32(1.57079633f);
|
||||
// const float32x4_t two_pi = vdupq_n_f32(6.28318531f);
|
||||
|
||||
uint32x4_t neg = vcgeq_f32(phi, pi);
|
||||
float32x4_t xr = vbslq_f32(neg, vsubq_f32(phi, pi), phi);
|
||||
|
||||
uint32x4_t fold = vcgtq_f32(xr, pi_2);
|
||||
xr = vbslq_f32(fold, vsubq_f32(pi, xr), xr);
|
||||
|
||||
float32x4_t x2 = vmulq_f32(xr, xr);
|
||||
float32x4_t r = vfmsq_f32(vdupq_n_f32(1.0f / 120.0f), x2, vdupq_n_f32(1.0f / 5040.0f));
|
||||
r = vfmsq_f32(vdupq_n_f32(1.0f / 6.0f), x2, r);
|
||||
r = vfmsq_f32(vdupq_n_f32(1.0f), x2, r);
|
||||
r = vmulq_f32(xr, r);
|
||||
|
||||
uint32x4_t signBit = vshlq_n_u32(neg, 31);
|
||||
return vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(r), signBit));
|
||||
}
|
||||
|
||||
inline float32x4_t cos4(float32x4_t phi) {
|
||||
|
||||
float32x4_t shifted = vaddq_f32(phi, vdupq_n_f32(1.57079633f));
|
||||
float32x4_t two_pi = vdupq_n_f32(6.28318531f);
|
||||
uint32x4_t wrap = vcgeq_f32(shifted, two_pi);
|
||||
shifted = vbslq_f32(wrap, vsubq_f32(shifted, two_pi), shifted);
|
||||
return sin4(shifted);
|
||||
}
|
||||
|
||||
inline void buildONB4(const vec3x4 &n, vec3x4 &t, vec3x4 &b) {
|
||||
const float32x4_t one = vdupq_n_f32(1.0f);
|
||||
const float32x4_t neg = vdupq_n_f32(-1.0f);
|
||||
|
||||
uint32x4_t pos = vcgeq_f32(n.z, vdupq_n_f32(0.0f));
|
||||
float32x4_t sgn = vbslq_f32(pos, one, neg);
|
||||
|
||||
float32x4_t denom = vaddq_f32(sgn, n.z);
|
||||
float32x4_t r = vrecpeq_f32(denom);
|
||||
r = vmulq_f32(vrecpsq_f32(denom, r), r);
|
||||
r = vmulq_f32(vrecpsq_f32(denom, r), r);
|
||||
float32x4_t a = vnegq_f32(r);
|
||||
|
||||
float32x4_t bc = vmulq_f32(vmulq_f32(n.x, n.y), a);
|
||||
|
||||
t.x = vaddq_f32(one, vmulq_f32(sgn, vmulq_f32(vmulq_f32(n.x, n.y), a)));
|
||||
t.y = vmulq_f32(sgn, bc);
|
||||
t.z = vnegq_f32(vmulq_f32(sgn, n.x));
|
||||
|
||||
b.x = bc;
|
||||
b.y = vaddq_f32(sgn, vmulq_f32(vmulq_f32(n.y, n.y), a));
|
||||
b.z = vnegq_f32(n.y);
|
||||
}
|
||||
|
||||
inline vec3x4 cosineSampleHemisphere4(const vec3x4 &n, uint32x4_t &rng) {
|
||||
|
||||
float32x4_t u1 = toFloat01(xorshift4(rng));
|
||||
float32x4_t u2 = toFloat01(xorshift4(rng));
|
||||
|
||||
float32x4_t r = vsqrtq_f32(u1);
|
||||
float32x4_t phi = vmulq_n_f32(u2, 6.28318531f);
|
||||
|
||||
float32x4_t lx = vmulq_f32(r, cos4(phi));
|
||||
float32x4_t ly = vmulq_f32(r, sin4(phi));
|
||||
float32x4_t lz = vsqrtq_f32(vmaxq_f32(vsubq_f32(vdupq_n_f32(1.0f), u1), vdupq_n_f32(0.0)));
|
||||
|
||||
vec3x4 t, b;
|
||||
buildONB4(n, t, b);
|
||||
|
||||
vec3x4 d;
|
||||
d.x = vaddq_f32(vaddq_f32(vmulq_f32(lx, t.x), vmulq_f32(ly, b.x)), vmulq_f32(lz, n.x));
|
||||
d.y = vaddq_f32(vaddq_f32(vmulq_f32(lx, t.y), vmulq_f32(ly, b.y)), vmulq_f32(lz, n.y));
|
||||
d.z = vaddq_f32(vaddq_f32(vmulq_f32(lx, t.z), vmulq_f32(ly, b.z)), vmulq_f32(lz, n.z));
|
||||
return d;
|
||||
}
|
||||
|
||||
inline float neon_dot3(float32x4_t a, float32x4_t b) {
|
||||
float32x4_t mul = vmulq_f32(a, b);
|
||||
float32x2_t lo = vget_low_f32(mul);
|
||||
float32x2_t hi = vget_high_f32(mul);
|
||||
float32x2_t sum = vpadd_f32(lo, lo);
|
||||
return vget_lane_f32(vadd_f32(sum, hi), 0);
|
||||
}
|
||||
|
||||
inline float32x4_t neon_cross3(float32x4_t a, float32x4_t b) {
|
||||
float32x4_t a_yzx = __builtin_shufflevector(a, a, 1, 2, 0, 3);
|
||||
float32x4_t a_zxy = __builtin_shufflevector(a, a, 2, 0, 1, 3);
|
||||
float32x4_t b_yzx = __builtin_shufflevector(b, b, 1, 2, 0, 3);
|
||||
float32x4_t b_zxy = __builtin_shufflevector(b, b, 2, 0, 1, 3);
|
||||
return vsubq_f32(vmulq_f32(a_yzx, b_zxy), vmulq_f32(a_zxy, b_yzx));
|
||||
}
|
||||
|
||||
inline float32x4_t neon_normalize3(float32x4_t v) {
|
||||
float32x2_t lenSq = vdup_n_f32(neon_dot3(v, v));
|
||||
float32x2_t est = vrsqrte_f32(lenSq);
|
||||
est = vmul_f32(est, vrsqrts_f32(vmul_f32(lenSq, est), est));
|
||||
return vmulq_f32(v, vcombine_f32(est, est));
|
||||
}
|
||||
|
||||
inline void neon_store3(float *p, float32x4_t v) {
|
||||
vst1q_lane_f32(p + 0, v, 0);
|
||||
vst1q_lane_f32(p + 1, v, 1);
|
||||
vst1q_lane_f32(p + 2, v, 2);
|
||||
}
|
||||
|
||||
inline float32x4_t vpermute(float32x4_t x) {
|
||||
float32x4_t v34 = vdupq_n_f32(34.0f);
|
||||
float32x4_t v1 = vdupq_n_f32(1.0f);
|
||||
float32x4_t v289 = vdupq_n_f32(289.0f);
|
||||
float32x4_t inv289 = vdupq_n_f32(1.0f / 289.0f);
|
||||
|
||||
float32x4_t res = vmlaq_f32(v1, x, v34);
|
||||
res = vmulq_f32(res, x);
|
||||
|
||||
float32x4_t quotient = vmulq_f32(res, inv289);
|
||||
|
||||
float32x4_t floored = vrndmq_f32(quotient);
|
||||
res = vmlsq_f32(res, floored, v289);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
inline float32x4_t vtaylorInvSqrt(float32x4_t x) {
|
||||
float32x4_t c1 = vdupq_n_f32(1.79284291400159f);
|
||||
float32x4_t c2 = vdupq_n_f32(0.85373472095314f);
|
||||
return vmlsq_f32(c1, x, c2);
|
||||
}
|
||||
|
||||
static inline void fastSinCos(float angle, float *s, float *c) {
|
||||
|
||||
const float INV_TWO_PI = 0.15915494309f;
|
||||
const float TWO_PI = 6.28318530718f;
|
||||
// const float PI = 3.14159265359f;
|
||||
|
||||
float x = angle - TWO_PI * floorf(angle * INV_TWO_PI + 0.5f);
|
||||
|
||||
float x2 = x * x;
|
||||
float x3 = x2 * x;
|
||||
float x5 = x3 * x2;
|
||||
float x7 = x5 * x3;
|
||||
|
||||
*s = x + x3 * (-0.16666667163f) + x5 * (0.00833333842f) + x7 * (-0.00019840680f);
|
||||
|
||||
float x4 = x2 * x2;
|
||||
float x6 = x4 * x2;
|
||||
|
||||
*c = 1.0f + x2 * (-0.49999997020f) + x4 * (0.04166664556f) + x6 * (-0.00138873165f);
|
||||
}
|
||||
Reference in New Issue
Block a user