GPUMaterial: Group all colorband texture together

This lower the use of texture samplers slots and let users use more real
textures in their shaders.

This patch also make the ramp texture 16 bit floating point. Meaning you
can now use value greater than one in your color ramps.

With the limit of 128 colorband per shader (a color band being either a
color ramp, a wavelength node or a curve node (and maybe wavelength node in
the future)).

Only drawback with the current implementation is that it does not remove
colorband from pruned GPUNodes but it shouldn't really matter in practice.

This should fix T56010
This commit is contained in:
Clément Foucault 2018-08-10 15:13:39 +02:00
parent c9bd61b372
commit bf6a22ed6f
Notes: blender-bot 2023-02-14 06:17:17 +01:00
Referenced by issue #56010, Material Nodes break in Eevee
12 changed files with 130 additions and 57 deletions

View File

@ -776,7 +776,9 @@ static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, struct
}
/* Color Ramps */
else if (input->tex) {
DRW_shgroup_uniform_texture(grp, input->shadername, input->tex);
/* HACK : input->tex is a (GPUTexture **) in this case. */
GPUTexture *tex = *((GPUTexture **)input->tex);
DRW_shgroup_uniform_texture(grp, input->shadername, tex);
}
/* Floats */
else {

View File

@ -80,6 +80,7 @@ typedef enum GPUType {
GPU_MAT4 = 16,
/* Values not in GPU_DATATYPE_STR */
GPU_TEX1D_ARRAY = 1001,
GPU_TEX2D = 1002,
GPU_TEX3D = 1003,
GPU_SHADOW2D = 1004,
@ -229,7 +230,7 @@ GPUNodeLink *GPU_uniform_buffer(float *num, GPUType gputype);
GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, bool is_data);
GPUNodeLink *GPU_cube_map(struct Image *ima, struct ImageUser *iuser, bool is_data);
GPUNodeLink *GPU_image_preview(struct PreviewImage *prv);
GPUNodeLink *GPU_texture(int size, float *pixels);
GPUNodeLink *GPU_texture_ramp(GPUMaterial *mat, int size, float *pixels, float *layer);
GPUNodeLink *GPU_dynamic_texture(struct GPUTexture *tex, GPUDynamicType dynamictype, void *data);
GPUNodeLink *GPU_builtin(GPUBuiltin builtin);
GPUNodeLink *GPU_opengl_builtin(GPUOpenGLBuiltin builtin);

View File

@ -163,6 +163,8 @@ GPUTexture *GPU_texture_create_nD(
GPUTexture *GPU_texture_create_1D(
int w, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
GPUTexture *GPU_texture_create_1D_array(
int w, int h, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
GPUTexture *GPU_texture_create_2D(
int w, int h, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
GPUTexture *GPU_texture_create_2D_multisample(

View File

@ -257,6 +257,9 @@ static void gpu_parse_functions_string(GHash *hash, char *code)
if (!type && gpu_str_prefix(code, "sampler2DShadow")) {
type = GPU_SHADOW2D;
}
if (!type && gpu_str_prefix(code, "sampler1DArray")) {
type = GPU_TEX1D_ARRAY;
}
if (!type && gpu_str_prefix(code, "sampler2D")) {
type = GPU_TEX2D;
}
@ -617,6 +620,7 @@ static int codegen_process_uniforms_functions(GPUMaterial *material, DynStr *ds,
if (codegen_input_has_texture(input) && input->bindtex) {
BLI_dynstr_appendf(
ds, "uniform %s samp%d;\n",
(input->textype == GPU_TEX1D_ARRAY) ? "sampler1DArray" :
(input->textype == GPU_TEX2D) ? "sampler2D" :
(input->textype == GPU_TEXCUBE) ? "samplerCube" : "sampler2DShadow",
input->texid);
@ -1330,15 +1334,9 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
/* small texture created on the fly, like for colorbands */
input->type = GPU_VEC4;
input->source = GPU_SOURCE_TEX;
input->textype = type;
#if 0
input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL);
#endif
input->tex = GPU_texture_create_2D(link->texturesize, 1, GPU_RGBA8, link->ptr1, NULL);
input->textarget = GL_TEXTURE_2D;
MEM_freeN(link->ptr1);
input->textype = GPU_TEX1D_ARRAY;
input->tex = link->ptr1; /* HACK ptr1 is actually a (GPUTexture **). */
input->textarget = GL_TEXTURE_1D_ARRAY;
MEM_freeN(link);
}
else if (link->image) {
@ -1687,13 +1685,14 @@ GPUNodeLink *GPU_image_preview(PreviewImage *prv)
}
GPUNodeLink *GPU_texture(int size, float *pixels)
GPUNodeLink *GPU_texture_ramp(GPUMaterial *mat, int size, float *pixels, float *row)
{
GPUNodeLink *link = GPU_node_link_create();
link->texture = true;
link->texturesize = size;
link->ptr1 = pixels;
link->ptr1 = gpu_material_ramp_texture_row_set(mat, size, pixels, row);
MEM_freeN(pixels);
return link;
}

View File

@ -197,6 +197,7 @@ void gpu_codegen_exit(void);
const char *GPU_builtin_name(GPUBuiltin builtin);
void gpu_material_add_node(struct GPUMaterial *material, struct GPUNode *node);
struct GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat, int size, float *pixels, float *row);
int GPU_link_changed(struct GPUNodeLink *link);
#endif

View File

@ -63,6 +63,12 @@
#endif
/* Structs */
#define MAX_COLOR_BAND 128
typedef struct GPUColorBandBuilder {
float pixels[MAX_COLOR_BAND][CM_TABLE + 1][4];
int current_layer;
} GPUColorBandBuilder;
struct GPUMaterial {
Scene *scene; /* DEPRECATED was only usefull for lamps */
@ -125,6 +131,9 @@ struct GPUMaterial {
float sss_sharpness;
bool sss_dirty;
GPUTexture *coba_tex; /* 1D Texture array containing all color bands. */
GPUColorBandBuilder *coba_builder;
#ifndef NDEBUG
char name[64];
#endif
@ -138,6 +147,47 @@ enum {
/* Functions */
/* Returns the adress of the future pointer to coba_tex */
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);
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;
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;
}
static void gpu_material_ramp_texture_build(GPUMaterial *mat)
{
if (mat->coba_builder == NULL)
return;
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);
MEM_freeN(builder);
mat->coba_builder = NULL;
}
static void gpu_material_free_single(GPUMaterial *material)
{
/* Cancel / wait any pending lazy compilation. */
@ -146,20 +196,21 @@ static void gpu_material_free_single(GPUMaterial *material)
GPU_pass_free_nodes(&material->nodes);
GPU_inputs_free(&material->inputs);
if (material->pass)
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)
@ -622,6 +673,8 @@ GPUMaterial *GPU_material_from_nodetree(
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;
}

View File

@ -871,6 +871,13 @@ GPUTexture *GPU_texture_create_1D(
return GPU_texture_create_nD(w, 0, 0, 1, pixels, tex_format, data_format, 0, false, err_out);
}
GPUTexture *GPU_texture_create_1D_array(
int w, int h, GPUTextureFormat tex_format, const float *pixels, char err_out[256])
{
GPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
return GPU_texture_create_nD(w, h, 0, 1, pixels, tex_format, data_format, 0, false, err_out);
}
GPUTexture *GPU_texture_create_2D(
int w, int h, GPUTextureFormat tex_format, const float *pixels, char err_out[256])
{

View File

@ -480,27 +480,26 @@ void normal_new_shading(vec3 dir, vec3 nor, out vec3 outnor, out float outdot)
outdot = dot(normalize(dir), nor);
}
void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec)
void curves_vec(float fac, vec3 vec, sampler1DArray curvemap, float layer, out vec3 outvec)
{
outvec.x = texture(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x;
outvec.y = texture(curvemap, vec2((vec.y + 1.0) * 0.5, 0.0)).y;
outvec.z = texture(curvemap, vec2((vec.z + 1.0) * 0.5, 0.0)).z;
if (fac != 1.0)
outvec = (outvec * fac) + (vec * (1.0 - fac));
vec4 co = vec4(vec * 0.5 + 0.5, layer);
outvec.x = texture(curvemap, co.xw).x;
outvec.y = texture(curvemap, co.yw).y;
outvec.z = texture(curvemap, co.zw).z;
outvec = mix(vec, outvec, fac);
}
void curves_rgb(float fac, vec4 col, sampler2D curvemap, out vec4 outcol)
void curves_rgb(float fac, vec4 col, sampler1DArray curvemap, float layer, out vec4 outcol)
{
outcol.r = texture(curvemap, vec2(texture(curvemap, vec2(col.r, 0.0)).a, 0.0)).r;
outcol.g = texture(curvemap, vec2(texture(curvemap, vec2(col.g, 0.0)).a, 0.0)).g;
outcol.b = texture(curvemap, vec2(texture(curvemap, vec2(col.b, 0.0)).a, 0.0)).b;
if (fac != 1.0)
outcol = (outcol * fac) + (col * (1.0 - fac));
vec4 co = vec4(col.rgb, layer);
co.x = texture(curvemap, co.xw).a;
co.y = texture(curvemap, co.yw).a;
co.z = texture(curvemap, co.zw).a;
outcol.r = texture(curvemap, co.xw).r;
outcol.g = texture(curvemap, co.yw).g;
outcol.b = texture(curvemap, co.zw).b;
outcol.a = col.a;
outcol = mix(col, outcol, fac);
}
void set_value(float val, out float outval)
@ -813,9 +812,9 @@ void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1 + fac * (2.0 * (col2 - vec4(0.5)));
}
void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha)
void valtorgb(float fac, sampler1DArray colormap, float layer, out vec4 outcol, out float outalpha)
{
outcol = texture(colormap, vec2(fac, 0.0));
outcol = texture(colormap, vec2(fac, layer));
outalpha = outcol.a;
}
@ -1464,17 +1463,17 @@ void node_volume_absorption(vec4 color, float density, out Closure result)
#endif
}
void node_blackbody(float temperature, sampler2D spectrummap, out vec4 color)
void node_blackbody(float temperature, sampler1DArray spectrummap, float layer, out vec4 color)
{
if(temperature >= 12000.0) {
if (temperature >= 12000.0) {
color = vec4(0.826270103, 0.994478524, 1.56626022, 1.0);
}
else if(temperature < 965.0) {
else if (temperature < 965.0) {
color = vec4(4.70366907, 0.0, 0.0, 1.0);
}
else {
float t = (temperature - 965.0) / (12000.0 - 965.0);
color = vec4(texture(spectrummap, vec2(t, 0.0)).rgb, 1.0);
color = vec4(texture(spectrummap, vec2(t, layer)).rgb, 1.0);
}
}
@ -1491,7 +1490,8 @@ void node_volume_principled(
float density_attribute,
vec4 color_attribute,
float temperature_attribute,
sampler2D spectrummap,
sampler1DArray spectrummap,
float layer,
out Closure result)
{
#ifdef VOLUMETRICS
@ -1533,7 +1533,7 @@ void node_volume_principled(
if(intensity > 1e-5) {
vec4 bb;
node_blackbody(T, spectrummap, bb);
node_blackbody(T, spectrummap, layer, bb);
emission_coeff += bb.rgb * blackbody_tint.rgb * intensity;
}
}

View File

@ -40,12 +40,15 @@ static bNodeSocketTemplate sh_node_blackbody_out[] = {
static int node_shader_gpu_blackbody(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
const int size = 256;
const int size = CM_TABLE + 1;
float *data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
return GPU_stack_link(mat, node, "node_blackbody", in, out, GPU_texture(size, data));
float layer;
GPUNodeLink *ramp_texture = GPU_texture_ramp(mat, size, data, &layer);
return GPU_stack_link(mat, node, "node_blackbody", in, out, ramp_texture, GPU_uniform(&layer));
}
/* node type definition */

View File

@ -62,11 +62,13 @@ static void node_shader_init_curve_vec(bNodeTree *UNUSED(ntree), bNode *node)
static int gpu_shader_curve_vec(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
float *array;
float *array, layer;
int size;
curvemapping_table_RGBA(node->storage, &array, &size);
return GPU_stack_link(mat, node, "curves_vec", in, out, GPU_texture(size, array));
GPUNodeLink *tex = GPU_texture_ramp(mat, size, array, &layer);
return GPU_stack_link(mat, node, "curves_vec", in, out, tex, GPU_uniform(&layer));
}
void register_node_type_sh_curve_vec(void)
@ -119,12 +121,14 @@ static void node_shader_init_curve_rgb(bNodeTree *UNUSED(ntree), bNode *node)
static int gpu_shader_curve_rgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
float *array;
float *array, layer;
int size;
curvemapping_initialize(node->storage);
curvemapping_table_RGBA(node->storage, &array, &size);
return GPU_stack_link(mat, node, "curves_rgb", in, out, GPU_texture(size, array));
GPUNodeLink *tex = GPU_texture_ramp(mat, size, array, &layer);
return GPU_stack_link(mat, node, "curves_rgb", in, out, tex, GPU_uniform(&layer));
}
void register_node_type_sh_curve_rgb(void)

View File

@ -65,11 +65,12 @@ static void node_shader_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
static int gpu_shader_valtorgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
float *array;
float *array, layer;
int size;
BKE_colorband_evaluate_table_rgba(node->storage, &array, &size);
return GPU_stack_link(mat, node, "valtorgb", in, out, GPU_texture(size, array));
GPUNodeLink *tex = GPU_texture_ramp(mat, size, array, &layer);
return GPU_stack_link(mat, node, "valtorgb", in, out, tex, GPU_uniform(&layer));
}
void register_node_type_sh_valtorgb(void)

View File

@ -132,19 +132,19 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat, bNode *node, bNod
}
/* Create blackbody spectrum. */
GPUNodeLink *spectrummap;
const int size = CM_TABLE + 1;
float *data, layer;
if (use_blackbody) {
const int size = 256;
float *data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
spectrummap = GPU_texture(size, data);
}
else {
float *data = MEM_callocN(sizeof(float) * 4, "blackbody black");
spectrummap = GPU_texture(1, data);
data = MEM_callocN(sizeof(float) * size * 4, "blackbody black");
}
GPUNodeLink *spectrummap = GPU_texture_ramp(mat, size, data, &layer);
return GPU_stack_link(mat, node, "node_volume_principled", in, out, density, color, temperature, spectrummap);
return GPU_stack_link(mat, node, "node_volume_principled", in, out, density, color, temperature, spectrummap,
GPU_uniform(&layer));
}
/* node type definition */