paint: raytrace faster
This commit is contained in:
@@ -6,6 +6,207 @@ mat4_t render_path_raytrace_transform;
|
||||
gpu_buffer_t *render_path_raytrace_vb;
|
||||
gpu_buffer_t *render_path_raytrace_ib;
|
||||
|
||||
#define ENV_CDF_W 256
|
||||
#define ENV_CDF_H 128
|
||||
#define ENV_CDF_N (ENV_CDF_W * ENV_CDF_H)
|
||||
|
||||
gpu_texture_t *render_path_raytrace_env_cdf = NULL;
|
||||
static char *render_path_raytrace_env_cdf_file = NULL;
|
||||
|
||||
static float render_path_raytrace_half_to_float(uint16_t h) {
|
||||
uint32_t sign = (uint32_t)(h >> 15) << 31;
|
||||
uint32_t exp = (h >> 10) & 0x1f;
|
||||
uint32_t man = h & 0x3ff;
|
||||
uint32_t bits;
|
||||
if (exp == 0) {
|
||||
if (man == 0) {
|
||||
bits = sign;
|
||||
}
|
||||
else {
|
||||
exp = 127 - 15 + 1;
|
||||
while ((man & 0x400) == 0) {
|
||||
man <<= 1;
|
||||
exp--;
|
||||
}
|
||||
man &= 0x3ff;
|
||||
bits = sign | (exp << 23) | (man << 13);
|
||||
}
|
||||
}
|
||||
else if (exp == 31) {
|
||||
bits = sign | 0x7f800000u | (man << 13);
|
||||
}
|
||||
else {
|
||||
bits = sign | ((exp + 127 - 15) << 23) | (man << 13);
|
||||
}
|
||||
float f;
|
||||
memcpy(&f, &bits, sizeof(f));
|
||||
return f;
|
||||
}
|
||||
|
||||
static bool render_path_raytrace_env_luma(char *file, float *out) {
|
||||
buffer_t *blob = iron_load_blob(data_resolve_path(file));
|
||||
if (blob == NULL) {
|
||||
return false;
|
||||
}
|
||||
int32_t w = iron_read_s32le(blob->buffer);
|
||||
int32_t h = iron_read_s32le(blob->buffer + 4);
|
||||
bool f16 = blob->buffer[11] == 'F';
|
||||
int bpp = f16 ? 8 : 4;
|
||||
size_t size = (size_t)w * h * bpp;
|
||||
uint8_t *px = malloc(size);
|
||||
if (px == NULL) {
|
||||
iron_delete_blob(blob);
|
||||
return false;
|
||||
}
|
||||
int decoded = LZ4_decompress_safe((char *)blob->buffer + 12, (char *)px, blob->length - 12, (int)size);
|
||||
iron_delete_blob(blob);
|
||||
if (decoded != (int)size) {
|
||||
free(px);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int cy = 0; cy < ENV_CDF_H; ++cy) {
|
||||
int y0 = cy * h / ENV_CDF_H;
|
||||
int y1 = (cy + 1) * h / ENV_CDF_H;
|
||||
if (y1 <= y0) {
|
||||
y1 = y0 + 1;
|
||||
}
|
||||
float sin_theta = (float)sin(3.14159265358979 * ((double)cy + 0.5) / ENV_CDF_H);
|
||||
for (int cx = 0; cx < ENV_CDF_W; ++cx) {
|
||||
int x0 = cx * w / ENV_CDF_W;
|
||||
int x1 = (cx + 1) * w / ENV_CDF_W;
|
||||
if (x1 <= x0) {
|
||||
x1 = x0 + 1;
|
||||
}
|
||||
double sum = 0.0;
|
||||
int n = 0;
|
||||
for (int y = y0; y < y1 && y < h; ++y) {
|
||||
for (int x = x0; x < x1 && x < w; ++x) {
|
||||
size_t o = ((size_t)y * w + x) * bpp;
|
||||
float r, g, b;
|
||||
if (f16) {
|
||||
uint16_t *p = (uint16_t *)(px + o);
|
||||
r = render_path_raytrace_half_to_float(p[0]);
|
||||
g = render_path_raytrace_half_to_float(p[1]);
|
||||
b = render_path_raytrace_half_to_float(p[2]);
|
||||
}
|
||||
else {
|
||||
r = px[o + 0] / 255.0f;
|
||||
g = px[o + 1] / 255.0f;
|
||||
b = px[o + 2] / 255.0f;
|
||||
}
|
||||
sum += 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
out[cy * ENV_CDF_W + cx] = n > 0 ? (float)(sum / n) * sin_theta : 0.0f;
|
||||
}
|
||||
}
|
||||
free(px);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void render_path_raytrace_build_env_cdf(char *file) {
|
||||
if (render_path_raytrace_env_cdf_file != NULL && strcmp(render_path_raytrace_env_cdf_file, file) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
float *weight = malloc(sizeof(float) * ENV_CDF_N);
|
||||
if (weight == NULL) {
|
||||
return;
|
||||
}
|
||||
if (!render_path_raytrace_env_luma(file, weight)) {
|
||||
free(weight);
|
||||
return;
|
||||
}
|
||||
|
||||
double total = 0.0;
|
||||
for (int i = 0; i < ENV_CDF_N; ++i) {
|
||||
total += weight[i];
|
||||
}
|
||||
if (total <= 0.0) {
|
||||
free(weight);
|
||||
return;
|
||||
}
|
||||
|
||||
float *prob = malloc(sizeof(float) * ENV_CDF_N);
|
||||
int *alias = malloc(sizeof(int) * ENV_CDF_N);
|
||||
int *stack = malloc(sizeof(int) * ENV_CDF_N);
|
||||
float *pdf = malloc(sizeof(float) * ENV_CDF_N);
|
||||
if (prob == NULL || alias == NULL || stack == NULL || pdf == NULL) {
|
||||
free(weight);
|
||||
free(prob);
|
||||
free(alias);
|
||||
free(stack);
|
||||
free(pdf);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ENV_CDF_N; ++i) {
|
||||
double p = weight[i] / total;
|
||||
pdf[i] = (float)(p * ENV_CDF_N);
|
||||
prob[i] = (float)(p * ENV_CDF_N);
|
||||
alias[i] = i;
|
||||
}
|
||||
|
||||
int small_top = 0;
|
||||
int large_top = ENV_CDF_N;
|
||||
for (int i = 0; i < ENV_CDF_N; ++i) {
|
||||
if (prob[i] < 1.0f) {
|
||||
stack[small_top++] = i;
|
||||
}
|
||||
else {
|
||||
stack[--large_top] = i;
|
||||
}
|
||||
}
|
||||
while (small_top > 0 && large_top < ENV_CDF_N) {
|
||||
int s = stack[--small_top];
|
||||
int l = stack[large_top++];
|
||||
alias[s] = l;
|
||||
prob[l] = (prob[l] + prob[s]) - 1.0f;
|
||||
if (prob[l] < 1.0f) {
|
||||
stack[small_top++] = l;
|
||||
}
|
||||
else {
|
||||
stack[--large_top] = l;
|
||||
}
|
||||
}
|
||||
while (large_top < ENV_CDF_N) {
|
||||
prob[stack[large_top++]] = 1.0f;
|
||||
}
|
||||
while (small_top > 0) {
|
||||
prob[stack[--small_top]] = 1.0f;
|
||||
}
|
||||
|
||||
float *data = malloc(sizeof(float) * 4 * ENV_CDF_N);
|
||||
if (data != NULL) {
|
||||
for (int i = 0; i < ENV_CDF_N; ++i) {
|
||||
data[i * 4 + 0] = prob[i];
|
||||
data[i * 4 + 1] = (float)alias[i];
|
||||
data[i * 4 + 2] = pdf[i];
|
||||
data[i * 4 + 3] = pdf[alias[i]];
|
||||
}
|
||||
if (render_path_raytrace_env_cdf == NULL) {
|
||||
render_path_raytrace_env_cdf = malloc(sizeof(gpu_texture_t));
|
||||
render_path_raytrace_env_cdf->buffer = NULL;
|
||||
}
|
||||
else {
|
||||
gpu_texture_destroy(render_path_raytrace_env_cdf);
|
||||
}
|
||||
gpu_texture_init_from_bytes(render_path_raytrace_env_cdf, data, ENV_CDF_W, ENV_CDF_H, GPU_TEXTURE_FORMAT_RGBA128);
|
||||
free(data);
|
||||
|
||||
free(render_path_raytrace_env_cdf_file);
|
||||
render_path_raytrace_env_cdf_file = string_copy(file);
|
||||
}
|
||||
|
||||
free(weight);
|
||||
free(prob);
|
||||
free(alias);
|
||||
free(stack);
|
||||
free(pdf);
|
||||
}
|
||||
|
||||
void render_path_raytrace_init() {}
|
||||
|
||||
void render_path_raytrace_commands(bool use_live_layer) {
|
||||
@@ -40,8 +241,13 @@ void render_path_raytrace_commands(bool use_live_layer) {
|
||||
gpu_texture_t *bnoise_scramble = data_get_texture("bnoise_scramble.k");
|
||||
gpu_texture_t *bnoise_rank = data_get_texture("bnoise_rank.k");
|
||||
|
||||
if (scene_world->envmap != NULL) {
|
||||
render_path_raytrace_build_env_cdf(scene_world->envmap);
|
||||
}
|
||||
|
||||
slot_layer_t *l = layers_flatten(true, NULL);
|
||||
gpu_raytrace_set_textures(l->texpaint, l->texpaint_nor, l->texpaint_pack, saved_envmap, bnoise_sobol, bnoise_scramble, bnoise_rank);
|
||||
gpu_raytrace_set_textures(l->texpaint, l->texpaint_nor, l->texpaint_pack, saved_envmap, bnoise_sobol, bnoise_scramble, bnoise_rank,
|
||||
render_path_raytrace_env_cdf);
|
||||
}
|
||||
////
|
||||
|
||||
@@ -77,7 +283,7 @@ void render_path_raytrace_commands(bool use_live_layer) {
|
||||
render_path_raytrace_f32a->buffer[2] = transform_world_z(ct);
|
||||
render_path_raytrace_f32a->buffer[3] = render_path_raytrace_frame;
|
||||
render_path_raytrace_frame = (render_path_raytrace_frame % 4) + 1; // _PAINT
|
||||
// render_path_raytrace_frame = render_path_raytrace_frame + 1; // _RENDER
|
||||
// render_path_raytrace_frame = render_path_raytrace_frame + 1; // _RENDER
|
||||
render_path_raytrace_f32a->buffer[4] = render_path_raytrace_help_mat.m00;
|
||||
render_path_raytrace_f32a->buffer[5] = render_path_raytrace_help_mat.m01;
|
||||
render_path_raytrace_f32a->buffer[6] = render_path_raytrace_help_mat.m02;
|
||||
@@ -100,6 +306,7 @@ void render_path_raytrace_commands(bool use_live_layer) {
|
||||
}
|
||||
render_path_raytrace_f32a->buffer[21] = g_context->envmap_angle;
|
||||
render_path_raytrace_f32a->buffer[22] = render_path_raytrace_uv_scale;
|
||||
render_path_raytrace_f32a->buffer[23] = render_path_raytrace_env_cdf != NULL ? 1.0f : 0.0f;
|
||||
|
||||
if (render_path_base_buf_swapped) {
|
||||
render_path_base_swap_buf("buf");
|
||||
|
||||
Reference in New Issue
Block a user