From e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 17 Apr 2019 06:17:24 +0200 Subject: ClangFormat: apply to source, most of intern Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat --- source/blender/gpu/intern/gpu_material.c | 1004 +++++++++++++++--------------- 1 file changed, 509 insertions(+), 495 deletions(-) (limited to 'source/blender/gpu/intern/gpu_material.c') diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index af8fcf6164e..cae60351bd5 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -54,182 +54,185 @@ #define MAX_COLOR_BAND 128 typedef struct GPUColorBandBuilder { - float pixels[MAX_COLOR_BAND][CM_TABLE + 1][4]; - int current_layer; + float pixels[MAX_COLOR_BAND][CM_TABLE + 1][4]; + int current_layer; } GPUColorBandBuilder; struct GPUMaterial { - Scene *scene; /* DEPRECATED was only useful for lights. */ - Material *ma; - - eGPUMaterialStatus status; - - const void *engine_type; /* attached engine type */ - int options; /* to identify shader variations (shadow, probe, world background...) */ - - /* for creating the material */ - ListBase nodes; - GPUNodeLink *outlink; - - /* for binding the material */ - GPUPass *pass; - ListBase inputs; /* GPUInput */ - GPUVertAttrLayers attrs; - int builtins; - int alpha, obcolalpha; - int dynproperty; - - /* for passing uniforms */ - int viewmatloc, invviewmatloc; - int obmatloc, invobmatloc; - int localtoviewmatloc, invlocaltoviewmatloc; - int obcolloc, obautobumpscaleloc; - int cameratexcofacloc; - - int partscalarpropsloc; - int partcoloc; - int partvel; - int partangvel; - - int objectinfoloc; - - /* XXX: Should be in Material. But it depends on the output node - * used and since the output selection is difference for GPUMaterial... - */ - int domain; - - /* Only used by Eevee to know which bsdf are used. */ - int flag; - - /* Used by 2.8 pipeline */ - GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */ - - /* Eevee SSS */ - GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */ - GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */ - float sss_enabled; - float sss_radii[3]; - int sss_samples; - short int sss_falloff; - float sss_sharpness; - bool sss_dirty; - - GPUTexture *coba_tex; /* 1D Texture array containing all color bands. */ - GPUColorBandBuilder *coba_builder; + Scene *scene; /* DEPRECATED was only useful for lights. */ + Material *ma; + + eGPUMaterialStatus status; + + const void *engine_type; /* attached engine type */ + int options; /* to identify shader variations (shadow, probe, world background...) */ + + /* for creating the material */ + ListBase nodes; + GPUNodeLink *outlink; + + /* for binding the material */ + GPUPass *pass; + ListBase inputs; /* GPUInput */ + GPUVertAttrLayers attrs; + int builtins; + int alpha, obcolalpha; + int dynproperty; + + /* for passing uniforms */ + int viewmatloc, invviewmatloc; + int obmatloc, invobmatloc; + int localtoviewmatloc, invlocaltoviewmatloc; + int obcolloc, obautobumpscaleloc; + int cameratexcofacloc; + + int partscalarpropsloc; + int partcoloc; + int partvel; + int partangvel; + + int objectinfoloc; + + /* XXX: Should be in Material. But it depends on the output node + * used and since the output selection is difference for GPUMaterial... + */ + int domain; + + /* Only used by Eevee to know which bsdf are used. */ + int flag; + + /* Used by 2.8 pipeline */ + GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */ + + /* Eevee SSS */ + GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */ + GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */ + float sss_enabled; + float sss_radii[3]; + int sss_samples; + short int sss_falloff; + float sss_sharpness; + bool sss_dirty; + + GPUTexture *coba_tex; /* 1D Texture array containing all color bands. */ + GPUColorBandBuilder *coba_builder; #ifndef NDEBUG - char name[64]; + char name[64]; #endif }; enum { - GPU_DOMAIN_SURFACE = (1 << 0), - GPU_DOMAIN_VOLUME = (1 << 1), - GPU_DOMAIN_SSS = (1 << 2), + GPU_DOMAIN_SURFACE = (1 << 0), + GPU_DOMAIN_VOLUME = (1 << 1), + GPU_DOMAIN_SSS = (1 << 2), }; /* Functions */ /* Returns the address of the future pointer to coba_tex */ -GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat, int size, float *pixels, float *row) +GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat, + int size, + float *pixels, + float *row) { - /* In order to put all the colorbands into one 1D array texture, - * we need them to be the same size. */ - BLI_assert(size == CM_TABLE + 1); - UNUSED_VARS_NDEBUG(size); + /* In order to put all the colorbands into one 1D array texture, + * we need them to be the same size. */ + BLI_assert(size == CM_TABLE + 1); + UNUSED_VARS_NDEBUG(size); - if (mat->coba_builder == NULL) { - mat->coba_builder = MEM_mallocN(sizeof(GPUColorBandBuilder), "GPUColorBandBuilder"); - mat->coba_builder->current_layer = 0; - } + if (mat->coba_builder == NULL) { + mat->coba_builder = MEM_mallocN(sizeof(GPUColorBandBuilder), "GPUColorBandBuilder"); + mat->coba_builder->current_layer = 0; + } - int layer = mat->coba_builder->current_layer; - *row = (float)layer; + int layer = mat->coba_builder->current_layer; + *row = (float)layer; - if (*row == MAX_COLOR_BAND) { - printf("Too many color band in shader! Remove some Curve, Black Body or Color Ramp Node.\n"); - } - else { - float *dst = (float *)mat->coba_builder->pixels[layer]; - memcpy(dst, pixels, sizeof(float) * (CM_TABLE + 1) * 4); - mat->coba_builder->current_layer += 1; - } + if (*row == MAX_COLOR_BAND) { + printf("Too many color band in shader! Remove some Curve, Black Body or Color Ramp Node.\n"); + } + else { + float *dst = (float *)mat->coba_builder->pixels[layer]; + memcpy(dst, pixels, sizeof(float) * (CM_TABLE + 1) * 4); + mat->coba_builder->current_layer += 1; + } - return &mat->coba_tex; + return &mat->coba_tex; } static void gpu_material_ramp_texture_build(GPUMaterial *mat) { - if (mat->coba_builder == NULL) - return; + if (mat->coba_builder == NULL) + return; - GPUColorBandBuilder *builder = mat->coba_builder; + GPUColorBandBuilder *builder = mat->coba_builder; - mat->coba_tex = GPU_texture_create_1d_array(CM_TABLE + 1, builder->current_layer, GPU_RGBA16F, - (float *)builder->pixels, NULL); + mat->coba_tex = GPU_texture_create_1d_array( + CM_TABLE + 1, builder->current_layer, GPU_RGBA16F, (float *)builder->pixels, NULL); - MEM_freeN(builder); - mat->coba_builder = NULL; + MEM_freeN(builder); + mat->coba_builder = NULL; } static void gpu_material_free_single(GPUMaterial *material) { - /* Cancel / wait any pending lazy compilation. */ - DRW_deferred_shader_remove(material); - - GPU_pass_free_nodes(&material->nodes); - GPU_inputs_free(&material->inputs); - - if (material->pass != NULL) { - GPU_pass_release(material->pass); - } - if (material->ubo != NULL) { - GPU_uniformbuffer_free(material->ubo); - } - if (material->sss_tex_profile != NULL) { - GPU_texture_free(material->sss_tex_profile); - } - if (material->sss_profile != NULL) { - GPU_uniformbuffer_free(material->sss_profile); - } - if (material->coba_tex != NULL) { - GPU_texture_free(material->coba_tex); - } + /* Cancel / wait any pending lazy compilation. */ + DRW_deferred_shader_remove(material); + + GPU_pass_free_nodes(&material->nodes); + GPU_inputs_free(&material->inputs); + + if (material->pass != NULL) { + GPU_pass_release(material->pass); + } + if (material->ubo != NULL) { + GPU_uniformbuffer_free(material->ubo); + } + if (material->sss_tex_profile != NULL) { + GPU_texture_free(material->sss_tex_profile); + } + if (material->sss_profile != NULL) { + GPU_uniformbuffer_free(material->sss_profile); + } + if (material->coba_tex != NULL) { + GPU_texture_free(material->coba_tex); + } } void GPU_material_free(ListBase *gpumaterial) { - for (LinkData *link = gpumaterial->first; link; link = link->next) { - GPUMaterial *material = link->data; - gpu_material_free_single(material); - MEM_freeN(material); - } - BLI_freelistN(gpumaterial); + for (LinkData *link = gpumaterial->first; link; link = link->next) { + GPUMaterial *material = link->data; + gpu_material_free_single(material); + MEM_freeN(material); + } + BLI_freelistN(gpumaterial); } eGPUBuiltin GPU_get_material_builtins(GPUMaterial *material) { - return material->builtins; + return material->builtins; } Scene *GPU_material_scene(GPUMaterial *material) { - return material->scene; + return material->scene; } GPUPass *GPU_material_get_pass(GPUMaterial *material) { - return material->pass; + return material->pass; } ListBase *GPU_material_get_inputs(GPUMaterial *material) { - return &material->inputs; + return &material->inputs; } GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material) { - return material->ubo; + return material->ubo; } /** @@ -239,7 +242,7 @@ GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material) */ void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs) { - material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL); + material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL); } /* Eevee Subsurface scattering. */ @@ -249,313 +252,319 @@ void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs) #define SSS_EXPONENT 2.0f /* Importance sampling exponent */ typedef struct GPUSssKernelData { - float kernel[SSS_SAMPLES][4]; - float param[3], max_radius; - int samples; + float kernel[SSS_SAMPLES][4]; + float param[3], max_radius; + int samples; } GPUSssKernelData; static void sss_calculate_offsets(GPUSssKernelData *kd, int count, float exponent) { - float step = 2.0f / (float)(count - 1); - for (int i = 0; i < count; i++) { - float o = ((float)i) * step - 1.0f; - float sign = (o < 0.0f) ? -1.0f : 1.0f; - float ofs = sign * fabsf(powf(o, exponent)); - kd->kernel[i][3] = ofs; - } + float step = 2.0f / (float)(count - 1); + for (int i = 0; i < count; i++) { + float o = ((float)i) * step - 1.0f; + float sign = (o < 0.0f) ? -1.0f : 1.0f; + float ofs = sign * fabsf(powf(o, exponent)); + kd->kernel[i][3] = ofs; + } } #define GAUSS_TRUNCATE 12.46f static float gaussian_profile(float r, float radius) { - const float v = radius * radius * (0.25f * 0.25f); - const float Rm = sqrtf(v * GAUSS_TRUNCATE); + const float v = radius * radius * (0.25f * 0.25f); + const float Rm = sqrtf(v * GAUSS_TRUNCATE); - if (r >= Rm) { - return 0.0f; - } - return expf(-r * r / (2.0f * v)) / (2.0f * M_PI * v); + if (r >= Rm) { + return 0.0f; + } + return expf(-r * r / (2.0f * v)) / (2.0f * M_PI * v); } -#define BURLEY_TRUNCATE 16.0f -#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE) +#define BURLEY_TRUNCATE 16.0f +#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE) static float burley_profile(float r, float d) { - float exp_r_3_d = expf(-r / (3.0f * d)); - float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d; - return (exp_r_d + exp_r_3_d) / (4.0f * d); + float exp_r_3_d = expf(-r / (3.0f * d)); + float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d; + return (exp_r_d + exp_r_3_d) / (4.0f * d); } static float cubic_profile(float r, float radius, float sharpness) { - float Rm = radius * (1.0f + sharpness); + float Rm = radius * (1.0f + sharpness); - if (r >= Rm) { - return 0.0f; - } - /* custom variation with extra sharpness, to match the previous code */ - const float y = 1.0f / (1.0f + sharpness); - float Rmy, ry, ryinv; + if (r >= Rm) { + return 0.0f; + } + /* custom variation with extra sharpness, to match the previous code */ + const float y = 1.0f / (1.0f + sharpness); + float Rmy, ry, ryinv; - Rmy = powf(Rm, y); - ry = powf(r, y); - ryinv = (r > 0.0f) ? powf(r, y - 1.0f) : 0.0f; + Rmy = powf(Rm, y); + ry = powf(r, y); + ryinv = (r > 0.0f) ? powf(r, y - 1.0f) : 0.0f; - const float Rmy5 = (Rmy * Rmy) * (Rmy * Rmy) * Rmy; - const float f = Rmy - ry; - const float num = f * (f * f) * (y * ryinv); + const float Rmy5 = (Rmy * Rmy) * (Rmy * Rmy) * Rmy; + const float f = Rmy - ry; + const float num = f * (f * f) * (y * ryinv); - return (10.0f * num) / (Rmy5 * M_PI); + return (10.0f * num) / (Rmy5 * M_PI); } static float eval_profile(float r, short falloff_type, float sharpness, float param) { - r = fabsf(r); + r = fabsf(r); - if (falloff_type == SHD_SUBSURFACE_BURLEY || - falloff_type == SHD_SUBSURFACE_RANDOM_WALK) - { - return burley_profile(r, param) / BURLEY_TRUNCATE_CDF; - } - else if (falloff_type == SHD_SUBSURFACE_CUBIC) { - return cubic_profile(r, param, sharpness); - } - else { - return gaussian_profile(r, param); - } + if (falloff_type == SHD_SUBSURFACE_BURLEY || falloff_type == SHD_SUBSURFACE_RANDOM_WALK) { + return burley_profile(r, param) / BURLEY_TRUNCATE_CDF; + } + else if (falloff_type == SHD_SUBSURFACE_CUBIC) { + return cubic_profile(r, param, sharpness); + } + else { + return gaussian_profile(r, param); + } } /* Resolution for each sample of the precomputed kernel profile */ #define INTEGRAL_RESOLUTION 32 static float eval_integral(float x0, float x1, short falloff_type, float sharpness, float param) { - const float range = x1 - x0; - const float step = range / INTEGRAL_RESOLUTION; - float integral = 0.0f; + const float range = x1 - x0; + const float step = range / INTEGRAL_RESOLUTION; + float integral = 0.0f; - for (int i = 0; i < INTEGRAL_RESOLUTION; ++i) { - float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION; - float y = eval_profile(x, falloff_type, sharpness, param); - integral += y * step; - } + for (int i = 0; i < INTEGRAL_RESOLUTION; ++i) { + float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION; + float y = eval_profile(x, falloff_type, sharpness, param); + integral += y * step; + } - return integral; + return integral; } #undef INTEGRAL_RESOLUTION static void compute_sss_kernel( - GPUSssKernelData *kd, float radii[3], int sample_len, int falloff_type, float sharpness) -{ - float rad[3]; - /* Minimum radius */ - rad[0] = MAX2(radii[0], 1e-15f); - rad[1] = MAX2(radii[1], 1e-15f); - rad[2] = MAX2(radii[2], 1e-15f); - - /* Christensen-Burley fitting */ - float l[3], d[3]; - - if (falloff_type == SHD_SUBSURFACE_BURLEY || - falloff_type == SHD_SUBSURFACE_RANDOM_WALK) - { - mul_v3_v3fl(l, rad, 0.25f * M_1_PI); - const float A = 1.0f; - const float s = 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f); - /* XXX 0.6f Out of nowhere to match cycles! Empirical! Can be tweak better. */ - mul_v3_v3fl(d, l, 0.6f / s); - mul_v3_v3fl(rad, d, BURLEY_TRUNCATE); - kd->max_radius = MAX3(rad[0], rad[1], rad[2]); - - copy_v3_v3(kd->param, d); - } - else if (falloff_type == SHD_SUBSURFACE_CUBIC) { - copy_v3_v3(kd->param, rad); - mul_v3_fl(rad, 1.0f + sharpness); - kd->max_radius = MAX3(rad[0], rad[1], rad[2]); - } - else { - kd->max_radius = MAX3(rad[0], rad[1], rad[2]); - - copy_v3_v3(kd->param, rad); - } - - /* Compute samples locations on the 1d kernel [-1..1] */ - sss_calculate_offsets(kd, sample_len, SSS_EXPONENT); - - /* Weights sum for normalization */ - float sum[3] = {0.0f, 0.0f, 0.0f}; - - /* Compute integral of each sample footprint */ - for (int i = 0; i < sample_len; i++) { - float x0, x1; - - if (i == 0) { - x0 = kd->kernel[0][3] - fabsf(kd->kernel[0][3] - kd->kernel[1][3]) / 2.0f; - } - else { - x0 = (kd->kernel[i - 1][3] + kd->kernel[i][3]) / 2.0f; - } - - if (i == sample_len - 1) { - x1 = kd->kernel[sample_len - 1][3] + fabsf(kd->kernel[sample_len - 2][3] - kd->kernel[sample_len - 1][3]) / 2.0f; - } - else { - x1 = (kd->kernel[i][3] + kd->kernel[i + 1][3]) / 2.0f; - } - - x0 *= kd->max_radius; - x1 *= kd->max_radius; - - kd->kernel[i][0] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[0]); - kd->kernel[i][1] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[1]); - kd->kernel[i][2] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[2]); - - sum[0] += kd->kernel[i][0]; - sum[1] += kd->kernel[i][1]; - sum[2] += kd->kernel[i][2]; - } - - for (int i = 0; i < 3; ++i) { - if (sum[i] > 0.0f) { - /* Normalize */ - for (int j = 0; j < sample_len; j++) { - kd->kernel[j][i] /= sum[i]; - } - } - else { - /* Avoid 0 kernel sum. */ - kd->kernel[sample_len / 2][i] = 1.0f; - } - } - - /* Put center sample at the start of the array (to sample first) */ - float tmpv[4]; - copy_v4_v4(tmpv, kd->kernel[sample_len / 2]); - for (int i = sample_len / 2; i > 0; i--) { - copy_v4_v4(kd->kernel[i], kd->kernel[i - 1]); - } - copy_v4_v4(kd->kernel[0], tmpv); - - kd->samples = sample_len; + GPUSssKernelData *kd, float radii[3], int sample_len, int falloff_type, float sharpness) +{ + float rad[3]; + /* Minimum radius */ + rad[0] = MAX2(radii[0], 1e-15f); + rad[1] = MAX2(radii[1], 1e-15f); + rad[2] = MAX2(radii[2], 1e-15f); + + /* Christensen-Burley fitting */ + float l[3], d[3]; + + if (falloff_type == SHD_SUBSURFACE_BURLEY || falloff_type == SHD_SUBSURFACE_RANDOM_WALK) { + mul_v3_v3fl(l, rad, 0.25f * M_1_PI); + const float A = 1.0f; + const float s = 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f); + /* XXX 0.6f Out of nowhere to match cycles! Empirical! Can be tweak better. */ + mul_v3_v3fl(d, l, 0.6f / s); + mul_v3_v3fl(rad, d, BURLEY_TRUNCATE); + kd->max_radius = MAX3(rad[0], rad[1], rad[2]); + + copy_v3_v3(kd->param, d); + } + else if (falloff_type == SHD_SUBSURFACE_CUBIC) { + copy_v3_v3(kd->param, rad); + mul_v3_fl(rad, 1.0f + sharpness); + kd->max_radius = MAX3(rad[0], rad[1], rad[2]); + } + else { + kd->max_radius = MAX3(rad[0], rad[1], rad[2]); + + copy_v3_v3(kd->param, rad); + } + + /* Compute samples locations on the 1d kernel [-1..1] */ + sss_calculate_offsets(kd, sample_len, SSS_EXPONENT); + + /* Weights sum for normalization */ + float sum[3] = {0.0f, 0.0f, 0.0f}; + + /* Compute integral of each sample footprint */ + for (int i = 0; i < sample_len; i++) { + float x0, x1; + + if (i == 0) { + x0 = kd->kernel[0][3] - fabsf(kd->kernel[0][3] - kd->kernel[1][3]) / 2.0f; + } + else { + x0 = (kd->kernel[i - 1][3] + kd->kernel[i][3]) / 2.0f; + } + + if (i == sample_len - 1) { + x1 = kd->kernel[sample_len - 1][3] + + fabsf(kd->kernel[sample_len - 2][3] - kd->kernel[sample_len - 1][3]) / 2.0f; + } + else { + x1 = (kd->kernel[i][3] + kd->kernel[i + 1][3]) / 2.0f; + } + + x0 *= kd->max_radius; + x1 *= kd->max_radius; + + kd->kernel[i][0] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[0]); + kd->kernel[i][1] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[1]); + kd->kernel[i][2] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[2]); + + sum[0] += kd->kernel[i][0]; + sum[1] += kd->kernel[i][1]; + sum[2] += kd->kernel[i][2]; + } + + for (int i = 0; i < 3; ++i) { + if (sum[i] > 0.0f) { + /* Normalize */ + for (int j = 0; j < sample_len; j++) { + kd->kernel[j][i] /= sum[i]; + } + } + else { + /* Avoid 0 kernel sum. */ + kd->kernel[sample_len / 2][i] = 1.0f; + } + } + + /* Put center sample at the start of the array (to sample first) */ + float tmpv[4]; + copy_v4_v4(tmpv, kd->kernel[sample_len / 2]); + for (int i = sample_len / 2; i > 0; i--) { + copy_v4_v4(kd->kernel[i], kd->kernel[i - 1]); + } + copy_v4_v4(kd->kernel[0], tmpv); + + kd->samples = sample_len; } #define INTEGRAL_RESOLUTION 512 -static void compute_sss_translucence_kernel( - const GPUSssKernelData *kd, int resolution, short falloff_type, float sharpness, float **output) -{ - float (*texels)[4]; - texels = MEM_callocN(sizeof(float) * 4 * resolution, "compute_sss_translucence_kernel"); - *output = (float *)texels; - - /* Last texel should be black, hence the - 1. */ - for (int i = 0; i < resolution - 1; ++i) { - /* Distance from surface. */ - float d = kd->max_radius * ((float)i + 0.00001f) / ((float)resolution); - - /* For each distance d we compute the radiance incoming from an hypothetic parallel plane. */ - /* Compute radius of the footprint on the hypothetic plane */ - float r_fp = sqrtf(kd->max_radius * kd->max_radius - d * d); - float r_step = r_fp / INTEGRAL_RESOLUTION; - float area_accum = 0.0f; - for (float r = 0.0f; r < r_fp; r += r_step) { - /* Compute distance to the "shading" point through the medium. */ - /* r_step * 0.5f to put sample between the area borders */ - float dist = hypotf(r + r_step * 0.5f, d); - - float profile[3]; - profile[0] = eval_profile(dist, falloff_type, sharpness, kd->param[0]); - profile[1] = eval_profile(dist, falloff_type, sharpness, kd->param[1]); - profile[2] = eval_profile(dist, falloff_type, sharpness, kd->param[2]); - - /* Since the profile and configuration are radially symmetrical we - * can just evaluate it once and weight it accordingly */ - float r_next = r + r_step; - float disk_area = (M_PI * r_next * r_next) - (M_PI * r * r); - - mul_v3_fl(profile, disk_area); - add_v3_v3(texels[i], profile); - area_accum += disk_area; - } - /* Normalize over the disk. */ - mul_v3_fl(texels[i], 1.0f / (area_accum)); - } - - /* Normalize */ - for (int j = resolution - 2; j > 0; j--) { - texels[j][0] /= (texels[0][0] > 0.0f) ? texels[0][0] : 1.0f; - texels[j][1] /= (texels[0][1] > 0.0f) ? texels[0][1] : 1.0f; - texels[j][2] /= (texels[0][2] > 0.0f) ? texels[0][2] : 1.0f; - } - - /* First texel should be white */ - texels[0][0] = (texels[0][0] > 0.0f) ? 1.0f : 0.0f; - texels[0][1] = (texels[0][1] > 0.0f) ? 1.0f : 0.0f; - texels[0][2] = (texels[0][2] > 0.0f) ? 1.0f : 0.0f; - - /* dim the last few texels for smoother transition */ - mul_v3_fl(texels[resolution - 2], 0.25f); - mul_v3_fl(texels[resolution - 3], 0.5f); - mul_v3_fl(texels[resolution - 4], 0.75f); +static void compute_sss_translucence_kernel(const GPUSssKernelData *kd, + int resolution, + short falloff_type, + float sharpness, + float **output) +{ + float(*texels)[4]; + texels = MEM_callocN(sizeof(float) * 4 * resolution, "compute_sss_translucence_kernel"); + *output = (float *)texels; + + /* Last texel should be black, hence the - 1. */ + for (int i = 0; i < resolution - 1; ++i) { + /* Distance from surface. */ + float d = kd->max_radius * ((float)i + 0.00001f) / ((float)resolution); + + /* For each distance d we compute the radiance incoming from an hypothetic parallel plane. */ + /* Compute radius of the footprint on the hypothetic plane */ + float r_fp = sqrtf(kd->max_radius * kd->max_radius - d * d); + float r_step = r_fp / INTEGRAL_RESOLUTION; + float area_accum = 0.0f; + for (float r = 0.0f; r < r_fp; r += r_step) { + /* Compute distance to the "shading" point through the medium. */ + /* r_step * 0.5f to put sample between the area borders */ + float dist = hypotf(r + r_step * 0.5f, d); + + float profile[3]; + profile[0] = eval_profile(dist, falloff_type, sharpness, kd->param[0]); + profile[1] = eval_profile(dist, falloff_type, sharpness, kd->param[1]); + profile[2] = eval_profile(dist, falloff_type, sharpness, kd->param[2]); + + /* Since the profile and configuration are radially symmetrical we + * can just evaluate it once and weight it accordingly */ + float r_next = r + r_step; + float disk_area = (M_PI * r_next * r_next) - (M_PI * r * r); + + mul_v3_fl(profile, disk_area); + add_v3_v3(texels[i], profile); + area_accum += disk_area; + } + /* Normalize over the disk. */ + mul_v3_fl(texels[i], 1.0f / (area_accum)); + } + + /* Normalize */ + for (int j = resolution - 2; j > 0; j--) { + texels[j][0] /= (texels[0][0] > 0.0f) ? texels[0][0] : 1.0f; + texels[j][1] /= (texels[0][1] > 0.0f) ? texels[0][1] : 1.0f; + texels[j][2] /= (texels[0][2] > 0.0f) ? texels[0][2] : 1.0f; + } + + /* First texel should be white */ + texels[0][0] = (texels[0][0] > 0.0f) ? 1.0f : 0.0f; + texels[0][1] = (texels[0][1] > 0.0f) ? 1.0f : 0.0f; + texels[0][2] = (texels[0][2] > 0.0f) ? 1.0f : 0.0f; + + /* dim the last few texels for smoother transition */ + mul_v3_fl(texels[resolution - 2], 0.25f); + mul_v3_fl(texels[resolution - 3], 0.5f); + mul_v3_fl(texels[resolution - 4], 0.75f); } #undef INTEGRAL_RESOLUTION -void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3], short *falloff_type, float *sharpness) +void GPU_material_sss_profile_create(GPUMaterial *material, + float radii[3], + short *falloff_type, + float *sharpness) { - copy_v3_v3(material->sss_radii, radii); - material->sss_falloff = (falloff_type) ? *falloff_type : 0.0; - material->sss_sharpness = (sharpness) ? *sharpness : 0.0; - material->sss_dirty = true; - material->sss_enabled = true; + copy_v3_v3(material->sss_radii, radii); + material->sss_falloff = (falloff_type) ? *falloff_type : 0.0; + material->sss_sharpness = (sharpness) ? *sharpness : 0.0; + material->sss_dirty = true; + material->sss_enabled = true; - /* Update / Create UBO */ - if (material->sss_profile == NULL) { - material->sss_profile = GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL); - } + /* Update / Create UBO */ + if (material->sss_profile == NULL) { + material->sss_profile = GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL); + } } -struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, int sample_len, GPUTexture **tex_profile) +struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, + int sample_len, + GPUTexture **tex_profile) { - if (!material->sss_enabled) - return NULL; + if (!material->sss_enabled) + return NULL; - if (material->sss_dirty || (material->sss_samples != sample_len)) { - GPUSssKernelData kd; + if (material->sss_dirty || (material->sss_samples != sample_len)) { + GPUSssKernelData kd; - float sharpness = material->sss_sharpness; + float sharpness = material->sss_sharpness; - /* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */ - sharpness *= 0.5f; + /* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */ + sharpness *= 0.5f; - compute_sss_kernel(&kd, material->sss_radii, sample_len, material->sss_falloff, sharpness); + compute_sss_kernel(&kd, material->sss_radii, sample_len, material->sss_falloff, sharpness); - /* Update / Create UBO */ - GPU_uniformbuffer_update(material->sss_profile, &kd); + /* Update / Create UBO */ + GPU_uniformbuffer_update(material->sss_profile, &kd); - /* Update / Create Tex */ - float *translucence_profile; - compute_sss_translucence_kernel(&kd, 64, material->sss_falloff, sharpness, &translucence_profile); + /* Update / Create Tex */ + float *translucence_profile; + compute_sss_translucence_kernel( + &kd, 64, material->sss_falloff, sharpness, &translucence_profile); - if (material->sss_tex_profile != NULL) { - GPU_texture_free(material->sss_tex_profile); - } + if (material->sss_tex_profile != NULL) { + GPU_texture_free(material->sss_tex_profile); + } - material->sss_tex_profile = GPU_texture_create_1d(64, GPU_RGBA16F, translucence_profile, NULL); + material->sss_tex_profile = GPU_texture_create_1d(64, GPU_RGBA16F, translucence_profile, NULL); - MEM_freeN(translucence_profile); + MEM_freeN(translucence_profile); - material->sss_samples = sample_len; - material->sss_dirty = false; - } + material->sss_samples = sample_len; + material->sss_dirty = false; + } - if (tex_profile != NULL) { - *tex_profile = material->sss_tex_profile; - } - return material->sss_profile; + if (tex_profile != NULL) { + *tex_profile = material->sss_tex_profile; + } + return material->sss_profile; } struct GPUUniformBuffer *GPU_material_create_sss_profile_ubo(void) { - return GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL); + return GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL); } #undef SSS_EXPONENT @@ -563,69 +572,68 @@ struct GPUUniformBuffer *GPU_material_create_sss_profile_ubo(void) void GPU_material_vertex_attrs(GPUMaterial *material, GPUVertAttrLayers *r_attrs) { - *r_attrs = material->attrs; + *r_attrs = material->attrs; } void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link) { - if (!material->outlink) - material->outlink = link; + if (!material->outlink) + material->outlink = link; } void gpu_material_add_node(GPUMaterial *material, GPUNode *node) { - BLI_addtail(&material->nodes, node); + BLI_addtail(&material->nodes, node); } /* Return true if the material compilation has not yet begin or begin. */ eGPUMaterialStatus GPU_material_status(GPUMaterial *mat) { - return mat->status; + return mat->status; } /* Code generation */ bool GPU_material_do_color_management(GPUMaterial *mat) { - if (!BKE_scene_check_color_management_enabled(mat->scene)) - return false; + if (!BKE_scene_check_color_management_enabled(mat->scene)) + return false; - return true; + return true; } bool GPU_material_use_domain_surface(GPUMaterial *mat) { - return (mat->domain & GPU_DOMAIN_SURFACE); + return (mat->domain & GPU_DOMAIN_SURFACE); } bool GPU_material_use_domain_volume(GPUMaterial *mat) { - return (mat->domain & GPU_DOMAIN_VOLUME); + return (mat->domain & GPU_DOMAIN_VOLUME); } void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag) { - mat->flag |= flag; + mat->flag |= flag; } bool GPU_material_flag_get(GPUMaterial *mat, eGPUMatFlag flag) { - return (mat->flag & flag); + return (mat->flag & flag); } -GPUMaterial *GPU_material_from_nodetree_find( - ListBase *gpumaterials, const void *engine_type, int options) +GPUMaterial *GPU_material_from_nodetree_find(ListBase *gpumaterials, + const void *engine_type, + int options) { - for (LinkData *link = gpumaterials->first; link; link = link->next) { - GPUMaterial *current_material = (GPUMaterial *)link->data; - if (current_material->engine_type == engine_type && - current_material->options == options) - { - return current_material; - } - } + for (LinkData *link = gpumaterials->first; link; link = link->next) { + GPUMaterial *current_material = (GPUMaterial *)link->data; + if (current_material->engine_type == engine_type && current_material->options == options) { + return current_material; + } + } - return NULL; + return NULL; } /** @@ -633,132 +641,138 @@ GPUMaterial *GPU_material_from_nodetree_find( * This is enforced since constructing other arguments to this function may be expensive * so only do this when they are needed. */ -GPUMaterial *GPU_material_from_nodetree( - Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options, - const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines, const char *name) -{ - LinkData *link; - bool has_volume_output, has_surface_output; - - /* Caller must re-use materials. */ - BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL); - - /* allocate material */ - GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial"); - mat->scene = scene; - mat->engine_type = engine_type; - mat->options = options; +GPUMaterial *GPU_material_from_nodetree(Scene *scene, + struct bNodeTree *ntree, + ListBase *gpumaterials, + const void *engine_type, + int options, + const char *vert_code, + const char *geom_code, + const char *frag_lib, + const char *defines, + const char *name) +{ + LinkData *link; + bool has_volume_output, has_surface_output; + + /* Caller must re-use materials. */ + BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL); + + /* allocate material */ + GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial"); + mat->scene = scene; + mat->engine_type = engine_type; + mat->options = options; #ifndef NDEBUG - BLI_snprintf(mat->name, sizeof(mat->name), "%s", name); + BLI_snprintf(mat->name, sizeof(mat->name), "%s", name); #else - UNUSED_VARS(name); + UNUSED_VARS(name); #endif - /* localize tree to create links for reroute and mute */ - bNodeTree *localtree = ntreeLocalize(ntree); - ntreeGPUMaterialNodes(localtree, mat, &has_surface_output, &has_volume_output); - - gpu_material_ramp_texture_build(mat); - - if (has_surface_output) { - mat->domain |= GPU_DOMAIN_SURFACE; - } - if (has_volume_output) { - mat->domain |= GPU_DOMAIN_VOLUME; - } - - if (mat->outlink) { - /* Prune the unused nodes and extract attributes before compiling so the - * generated VBOs are ready to accept the future shader. */ - GPU_nodes_prune(&mat->nodes, mat->outlink); - GPU_nodes_get_vertex_attrs(&mat->nodes, &mat->attrs); - /* Create source code and search pass cache for an already compiled version. */ - mat->pass = GPU_generate_pass( - mat, - mat->outlink, - &mat->attrs, - &mat->nodes, - &mat->builtins, - vert_code, - geom_code, - frag_lib, - defines); - - if (mat->pass == NULL) { - /* We had a cache hit and the shader has already failed to compile. */ - mat->status = GPU_MAT_FAILED; - } - else { - GPUShader *sh = GPU_pass_shader_get(mat->pass); - if (sh != NULL) { - /* We had a cache hit and the shader is already compiled. */ - mat->status = GPU_MAT_SUCCESS; - GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes); - } - else { - mat->status = GPU_MAT_QUEUED; - } - } - } - else { - mat->status = GPU_MAT_FAILED; - } - - /* Only free after GPU_pass_shader_get where GPUUniformBuffer - * read data from the local tree. */ - ntreeFreeLocalTree(localtree); - MEM_freeN(localtree); - - /* note that even if building the shader fails in some way, we still keep - * it to avoid trying to compile again and again, and simply do not use - * the actual shader on drawing */ - - link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); - link->data = mat; - BLI_addtail(gpumaterials, link); - - return mat; + /* localize tree to create links for reroute and mute */ + bNodeTree *localtree = ntreeLocalize(ntree); + ntreeGPUMaterialNodes(localtree, mat, &has_surface_output, &has_volume_output); + + gpu_material_ramp_texture_build(mat); + + if (has_surface_output) { + mat->domain |= GPU_DOMAIN_SURFACE; + } + if (has_volume_output) { + mat->domain |= GPU_DOMAIN_VOLUME; + } + + if (mat->outlink) { + /* Prune the unused nodes and extract attributes before compiling so the + * generated VBOs are ready to accept the future shader. */ + GPU_nodes_prune(&mat->nodes, mat->outlink); + GPU_nodes_get_vertex_attrs(&mat->nodes, &mat->attrs); + /* Create source code and search pass cache for an already compiled version. */ + mat->pass = GPU_generate_pass(mat, + mat->outlink, + &mat->attrs, + &mat->nodes, + &mat->builtins, + vert_code, + geom_code, + frag_lib, + defines); + + if (mat->pass == NULL) { + /* We had a cache hit and the shader has already failed to compile. */ + mat->status = GPU_MAT_FAILED; + } + else { + GPUShader *sh = GPU_pass_shader_get(mat->pass); + if (sh != NULL) { + /* We had a cache hit and the shader is already compiled. */ + mat->status = GPU_MAT_SUCCESS; + GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes); + } + else { + mat->status = GPU_MAT_QUEUED; + } + } + } + else { + mat->status = GPU_MAT_FAILED; + } + + /* Only free after GPU_pass_shader_get where GPUUniformBuffer + * read data from the local tree. */ + ntreeFreeLocalTree(localtree); + MEM_freeN(localtree); + + /* note that even if building the shader fails in some way, we still keep + * it to avoid trying to compile again and again, and simply do not use + * the actual shader on drawing */ + + link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); + link->data = mat; + BLI_addtail(gpumaterials, link); + + return mat; } void GPU_material_compile(GPUMaterial *mat) { - /* Only run once! */ - BLI_assert(mat->status == GPU_MAT_QUEUED); - BLI_assert(mat->pass); + /* Only run once! */ + BLI_assert(mat->status == GPU_MAT_QUEUED); + BLI_assert(mat->pass); - /* NOTE: The shader may have already been compiled here since we are - * sharing GPUShader across GPUMaterials. In this case it's a no-op. */ + /* NOTE: The shader may have already been compiled here since we are + * sharing GPUShader across GPUMaterials. In this case it's a no-op. */ #ifndef NDEBUG - GPU_pass_compile(mat->pass, mat->name); + GPU_pass_compile(mat->pass, mat->name); #else - GPU_pass_compile(mat->pass, __func__); + GPU_pass_compile(mat->pass, __func__); #endif - GPUShader *sh = GPU_pass_shader_get(mat->pass); + GPUShader *sh = GPU_pass_shader_get(mat->pass); - if (sh != NULL) { - mat->status = GPU_MAT_SUCCESS; - GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes); - } - else { - mat->status = GPU_MAT_FAILED; - GPU_pass_free_nodes(&mat->nodes); - GPU_pass_release(mat->pass); - mat->pass = NULL; - } + if (sh != NULL) { + mat->status = GPU_MAT_SUCCESS; + GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes); + } + else { + mat->status = GPU_MAT_FAILED; + GPU_pass_free_nodes(&mat->nodes); + GPU_pass_release(mat->pass); + mat->pass = NULL; + } } void GPU_materials_free(Main *bmain) { - Material *ma; - World *wo; - extern Material defmaterial; + Material *ma; + World *wo; + extern Material defmaterial; - for (ma = bmain->materials.first; ma; ma = ma->id.next) - GPU_material_free(&ma->gpumaterial); + for (ma = bmain->materials.first; ma; ma = ma->id.next) + GPU_material_free(&ma->gpumaterial); - for (wo = bmain->worlds.first; wo; wo = wo->id.next) - GPU_material_free(&wo->gpumaterial); + for (wo = bmain->worlds.first; wo; wo = wo->id.next) + GPU_material_free(&wo->gpumaterial); - GPU_material_free(&defmaterial.gpumaterial); + GPU_material_free(&defmaterial.gpumaterial); } -- cgit v1.2.3