optimzie base64

mcp w.i.p.
This commit is contained in:
Syoyo Fujita
2025-07-25 05:11:04 +09:00
parent 0ceb63b0dc
commit 7cd0016526
7 changed files with 1559 additions and 25 deletions

View File

@@ -36,7 +36,7 @@ sleep 1
# remove '\r'
sess_id=`cat sess_id.txt | tr -d '\r'`
sess_header="mcp-session-id: ${sess_id}"
echo $sess_header
#echo $sess_header
curl -v -X POST \
-H "Content-Type: application/json" \

View File

@@ -1,5 +1,10 @@
sess_id=`cat sess_id.txt | tr -d '\r'`
sess_header="mcp-session-id: ${sess_id}"
curl -X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "${sess_header}" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",

View File

@@ -5,6 +5,10 @@
#include "unicode-xid.hh"
#include "common-macros.inc"
#ifdef __SSE2__
#include <emmintrin.h>
#endif
namespace tinyusdz {
std::string buildEscapedAndQuotedStringForUSDA(const std::string &str) {
@@ -749,9 +753,12 @@ double atof(const std::string &s) {
#pragma clang diagnostic ignored "-Wconversion"
#endif
#ifdef __SSE2__
#else
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
#endif
std::string base64_encode(unsigned char const *bytes_to_encode,
unsigned int in_len) {
@@ -798,7 +805,133 @@ std::string base64_encode(unsigned char const *bytes_to_encode,
return ret;
}
// SSE2-optimized base64 decode implementation
#ifdef __SSE2__
static std::string base64_decode_sse(std::string const &encoded_string) {
const size_t input_len = encoded_string.size();
if (input_len == 0) return std::string();
// Lookup table for base64 decoding (256 entries, -1 for invalid chars)
static const int8_t decode_table[256] = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-2,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
};
// Calculate output size (remove padding)
size_t padding = 0;
if (input_len >= 1 && encoded_string[input_len - 1] == '=') padding++;
if (input_len >= 2 && encoded_string[input_len - 2] == '=') padding++;
const size_t output_len = (input_len * 3) / 4 - padding;
std::string result;
result.reserve(output_len);
const uint8_t* input = reinterpret_cast<const uint8_t*>(encoded_string.data());
size_t input_pos = 0;
// Process 16 bytes at a time using SSE2
while (input_pos + 16 <= input_len) {
// Load 16 input bytes
__m128i input_chunk = _mm_loadu_si128(reinterpret_cast<const __m128i*>(input + input_pos));
// Decode using lookup table (split into two 8-byte chunks for table lookup)
alignas(16) uint8_t input_bytes[16];
_mm_store_si128(reinterpret_cast<__m128i*>(input_bytes), input_chunk);
alignas(16) int8_t decoded[16];
bool valid = true;
for (int i = 0; i < 16; i++) {
decoded[i] = decode_table[input_bytes[i]];
if (decoded[i] < 0 && input_bytes[i] != '=') {
valid = false;
break;
}
}
if (!valid) break; // Fall back to scalar processing for invalid chars
// Pack groups of 4 decoded bytes into 3 output bytes
for (int group = 0; group < 4; group++) {
if (input_pos + group * 4 + 3 >= input_len) break;
int base_idx = group * 4;
if (decoded[base_idx] >= 0 && decoded[base_idx + 1] >= 0 &&
decoded[base_idx + 2] >= 0 && decoded[base_idx + 3] >= 0) {
uint32_t combined = (static_cast<uint32_t>(decoded[base_idx]) << 18) |
(static_cast<uint32_t>(decoded[base_idx + 1]) << 12) |
(static_cast<uint32_t>(decoded[base_idx + 2]) << 6) |
static_cast<uint32_t>(decoded[base_idx + 3]);
result.push_back(static_cast<char>((combined >> 16) & 0xFF));
result.push_back(static_cast<char>((combined >> 8) & 0xFF));
result.push_back(static_cast<char>(combined & 0xFF));
}
}
input_pos += 16;
}
// Process remaining bytes with scalar code
while (input_pos + 4 <= input_len) {
uint8_t a = input[input_pos];
uint8_t b = input[input_pos + 1];
uint8_t c = input[input_pos + 2];
uint8_t d = input[input_pos + 3];
if (a == '=' || b == '=') break;
int8_t da = decode_table[a];
int8_t db = decode_table[b];
int8_t dc = decode_table[c];
int8_t dd = decode_table[d];
if (da < 0 || db < 0) break;
uint32_t combined = (static_cast<uint32_t>(da) << 18) |
(static_cast<uint32_t>(db) << 12);
result.push_back(static_cast<char>((combined >> 16) & 0xFF));
if (c != '=' && dc >= 0) {
combined |= static_cast<uint32_t>(dc) << 6;
result.push_back(static_cast<char>((combined >> 8) & 0xFF));
if (d != '=' && dd >= 0) {
combined |= static_cast<uint32_t>(dd);
result.push_back(static_cast<char>(combined & 0xFF));
}
}
input_pos += 4;
}
return result;
}
#endif // __SSE2__
// Fallback implementation (original)
std::string base64_decode(std::string const &encoded_string) {
#ifdef __SSE2__
// Use SSE2 optimized version if available
return base64_decode_sse(encoded_string);
#else
// Original scalar implementation
int in_len = static_cast<int>(encoded_string.size());
int i = 0;
int j = 0;
@@ -847,6 +980,7 @@ std::string base64_decode(std::string const &encoded_string) {
}
return ret;
#endif // __SSE2__
}
#ifdef __clang__
#pragma clang diagnostic pop

View File

@@ -71,7 +71,7 @@ source_group("Source Files" FILES ${SOURCES})
if (EMSCRIPTEN)
if (TINYUSDZ_WASM_DEMODEV)
set(OUTPUT_WASM_DIR ${PROJECT_SOURCE_DIR}/demo/node_modules/tinyusdz/)
set(OUTPUT_WASM_DIR ${PROJECT_SOURCE_DIR}/mcp-server/node_modules/tinyusdz/)
else()
set(OUTPUT_WASM_DIR ${PROJECT_SOURCE_DIR}/js/src/tinyusdz/)
endif()

View File

@@ -6,6 +6,81 @@ import { GUI } from 'https://cdn.jsdelivr.net/npm/dat.gui@0.7.9/build/dat.gui.mo
import { TinyUSDZLoader } from 'tinyusdz/TinyUSDZLoader.js'
import { TinyUSDZLoaderUtils } from 'tinyusdz/TinyUSDZLoaderUtils.js'
// Loading bar elements
const loadingContainer = document.createElement('div');
loadingContainer.id = 'loading-container';
loadingContainer.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.8);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 1000;
font-family: Arial, sans-serif;
color: white;
`;
const loadingText = document.createElement('div');
loadingText.id = 'loading-text';
loadingText.textContent = 'Loading...';
loadingText.style.cssText = `
font-size: 24px;
margin-bottom: 20px;
`;
const progressBarContainer = document.createElement('div');
progressBarContainer.style.cssText = `
width: 300px;
height: 20px;
background: #333;
border-radius: 10px;
overflow: hidden;
margin-bottom: 10px;
`;
const progressBar = document.createElement('div');
progressBar.id = 'progress-bar';
progressBar.style.cssText = `
width: 0%;
height: 100%;
background: linear-gradient(90deg, #4CAF50, #8BC34A);
border-radius: 10px;
transition: width 0.3s ease;
`;
const progressText = document.createElement('div');
progressText.id = 'progress-text';
progressText.textContent = '0%';
progressText.style.cssText = `
font-size: 14px;
color: #ccc;
`;
progressBarContainer.appendChild(progressBar);
loadingContainer.appendChild(loadingText);
loadingContainer.appendChild(progressBarContainer);
loadingContainer.appendChild(progressText);
document.body.appendChild(loadingContainer);
// Function to update loading progress
function updateLoadingProgress(progress, message = 'Loading...') {
loadingText.textContent = message;
progressBar.style.width = `${progress}%`;
progressText.textContent = `${Math.round(progress)}%`;
}
// Function to hide loading screen
function hideLoadingScreen() {
loadingContainer.style.display = 'none';
}
const gui = new GUI();
let ui_state = {}
@@ -17,6 +92,7 @@ ui_state['ambient'] = 0.4;
let ambientLight = new THREE.AmbientLight(0x404040, ui_state['ambient']);
ui_state['camera_z'] = 3.14; // TODO: Compute best fit from scene's bbox.
ui_state['needsMtlUpdate'] = false;
ui_state['renderer'] = null;
// Create a parameters object
@@ -24,6 +100,7 @@ const params = {
envMapIntensity: ui_state['envMapIntensity'],
rotationSpeed: ui_state['rot_scale'],
camera_z: ui_state['camera_z'],
take_screenshot: takeScreenshot
};
// Add controls
@@ -38,31 +115,48 @@ gui.add(params, 'camera_z', 0, 20).name('Camera Z').onChange((value) => {
gui.add(params, 'rotationSpeed', 0, 10).name('Rotation Speed').onChange((value) => {
ui_state['rot_scale'] = value;
});
gui.add(params, 'take_screenshot').name('Take Screenshot');
function takeScreenshot() {
const renderer = ui_state['renderer'];
const quality = 0.92; // JPEG quality, if you want to use JPEG format
const img = renderer.domElement.toDataURL('image/jpeg', quality)
console.log('Screenshot taken:', img);
return img;
}
async function loadScenes() {
updateLoadingProgress(20, 'Initializing TinyUSDZLoader...');
const loader = new TinyUSDZLoader();
// it is recommended to call init() before loadAsync()
// (wait loading/compiling wasm module in the early stage))
//await loader.init();
await loader.init();
// Use zstd compressed tinyusdz.wasm to save the bandwidth.
await loader.init({useZstdCompressedWasm: true});
//await loader.init({useZstdCompressedWasm: true});
const suzanne_filename = "./assets/suzanne-pbr.usda";
const texcat_filename = "./assets/texture-cat-plane.usdz";
const cookie_filename = "./assets/UsdCookie.usdz";
const usd_filename = "./assets/suzanne-pbr.usda";
var threeScenes = []
const usd_scenes = await Promise.all([
//loader.loadAsync(texcat_filename),
loader.loadAsync(cookie_filename),
loader.loadAsync(usd_filename),
//loader.loadAsync(suzanne_filename),
]);
hideLoadingScreen();
const defaultMtl = ui_state['defaultMtl'];
const options = {
@@ -114,8 +208,13 @@ async function initScene() {
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = ui_state['camera_z'];
const renderer = new THREE.WebGLRenderer();
const renderer = new THREE.WebGLRenderer({
preserveDrawingBuffer: true, // for screenshot
alpha: true, // Enable transparency
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
ui_state['renderer'] = renderer; // Store renderer in ui_state
document.body.appendChild(renderer.domElement);
const rootNodes = await loadScenes();

File diff suppressed because it is too large Load Diff

View File

@@ -15,6 +15,7 @@
"vite": "^6.1.6"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.15.1",
"fzstd": "^0.1.1",
"gsap": "^3.13.0",
"lil-gui": "^0.19.2",