Eevee: World nodetree gpumaterial compatibility.

- Unify GPUMaterial creation (world/mesh).
- Support for multiple shader variations (not used for now).
- Convert GPUInputs to DRWUniforms to be used with the draw manager.
- Nodetree Update is not supported. The only way to refresh the shaders is to change render engine.
- Cleanup in GPUPass.
- Add new temporary Node Compatibility type. Compatibility types should be removed in the future.
This commit is contained in:
2017-04-27 22:27:09 +02:00
parent 2f100c13ee
commit e868b459bb
15 changed files with 333 additions and 30 deletions

View File

@@ -253,6 +253,7 @@ typedef struct bNodeType {
/* nodetype->compatibility */
#define NODE_OLD_SHADING 1
#define NODE_NEW_SHADING 2
#define NODE_NEWER_SHADING 3
/* node resize directions */
#define NODE_RESIZE_TOP 1

View File

@@ -29,6 +29,8 @@
#include "BLI_dynstr.h"
#include "BLI_rand.h"
#include "GPU_material.h"
#include "GPU_glew.h"
#include "eevee_engine.h"
@@ -39,6 +41,8 @@
/* *********** STATIC *********** */
static struct {
char *frag_shader_lib;
struct GPUShader *default_lit;
struct GPUShader *default_world;
struct GPUShader *depth_sh;
@@ -214,6 +218,16 @@ static void EEVEE_engine_init(void *ved)
(int)viewport_size[0], (int)viewport_size[1],
&tex, 1);
if (!e_data.frag_shader_lib) {
DynStr *ds_frag = BLI_dynstr_new();
BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_ltc_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_lit_surface_frag_glsl);
e_data.frag_shader_lib = BLI_dynstr_get_cstring(ds_frag);
BLI_dynstr_free(ds_frag);
}
if (!e_data.depth_sh) {
e_data.depth_sh = DRW_shader_create_3D_depth_only();
}
@@ -222,10 +236,7 @@ static void EEVEE_engine_init(void *ved)
char *frag_str = NULL;
DynStr *ds_frag = BLI_dynstr_new();
BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_ltc_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_lit_surface_frag_glsl);
BLI_dynstr_append(ds_frag, e_data.frag_shader_lib);
BLI_dynstr_append(ds_frag, datatoc_default_frag_glsl);
frag_str = BLI_dynstr_get_cstring(ds_frag);
BLI_dynstr_free(ds_frag);
@@ -345,6 +356,8 @@ static DRWShadingGroup *eevee_cascade_shadow_shgroup(
static void EEVEE_cache_init(void *vedata)
{
static int zero = 0;
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
EEVEE_TextureList *txl = ((EEVEE_Data *)vedata)->txl;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
@@ -373,26 +386,48 @@ static void EEVEE_cache_init(void *vedata)
psl->probe_background = DRW_pass_create("Probe Background Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR);
struct Batch *geom = DRW_cache_fullscreen_quad_get();
DRWShadingGroup *grp;
DRWShadingGroup *grp = NULL;
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
World *wo = scene->world;
if (false) { /* TODO check for world nodetree */
// GPUMaterial *gpumat = GPU_material_from_nodetree(struct bNodeTree *ntree, ListBase *gpumaterials, void *engine_type, int options)
}
else {
float *col = ts.colorBackground;
static int zero = 0;
if (wo) {
col = &wo->horr;
}
grp = eevee_cube_shgroup(e_data.default_world, psl->probe_background, geom);
if (wo && wo->use_nodes && wo->nodetree) {
struct GPUMaterial *gpumat = GPU_material_from_nodetree(
wo->nodetree, &wo->gpumaterial, &DRW_engine_viewport_eevee_type, 0,
datatoc_probe_vert_glsl, datatoc_probe_geom_glsl, e_data.frag_shader_lib,
"#define PROBE_CAPTURE\n"
"#define MAX_LIGHT 128\n"
"#define MAX_SHADOW_CUBE 42\n"
"#define MAX_SHADOW_MAP 64\n"
"#define MAX_SHADOW_CASCADE 8\n"
"#define MAX_CASCADE_NUM 4\n");
grp = DRW_shgroup_material_instance_create(gpumat, psl->probe_background, geom);
if (grp) {
DRW_shgroup_uniform_int(grp, "Layer", &zero, 1);
for (int i = 0; i < 6; ++i)
DRW_shgroup_call_dynamic_add_empty(grp);
}
else {
/* Shader failed : pink background */
static float pink[3] = {1.0f, 0.0f, 1.0f};
col = pink;
}
}
/* Fallback if shader fails or if not using nodetree. */
if (grp == NULL) {
grp = eevee_cube_shgroup(e_data.default_world, psl->probe_background, geom);
DRW_shgroup_uniform_vec3(grp, "color", col, 1);
DRW_shgroup_uniform_int(grp, "Layer", &zero, 1);
}
}
@@ -591,6 +626,7 @@ static void EEVEE_draw_scene(void *vedata)
static void EEVEE_engine_free(void)
{
MEM_SAFE_FREE(e_data.frag_shader_lib);
DRW_SHADER_FREE_SAFE(e_data.default_lit);
DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
DRW_SHADER_FREE_SAFE(e_data.default_world);
@@ -628,7 +664,7 @@ DrawEngineType draw_engine_eevee_type = {
RenderEngineType DRW_engine_viewport_eevee_type = {
NULL, NULL,
EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_OGL_PIPELINE,
EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_OGL_PIPELINE | RE_USE_SHADING_NODES,
NULL, NULL, NULL, NULL, NULL, NULL, &EEVEE_collection_settings_create,
&draw_engine_eevee_type,
{NULL, NULL, NULL}

View File

@@ -54,7 +54,7 @@ struct ShadowMapData {
#define sh_map_bias near_far_bias.z
#ifndef MAX_CASCADE_NUM
#define MAX_CASCADE_NUM 1
#define MAX_CASCADE_NUM 4
#endif
struct ShadowCascadeData {
@@ -94,8 +94,6 @@ vec4 saturate(vec4 a) { return vec4(saturate(a.x), saturate(a.y), saturate(a.z),
float distance_squared(vec2 a, vec2 b) { a -= b; return dot(a, a); }
float distance_squared(vec3 a, vec3 b) { a -= b; return dot(a, a); }
float hypot(float x, float y) { return sqrt(x*x + y*y); }
float inverse_distance(vec3 V) { return max( 1 / length(V), 1e-8); }
float line_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal)

View File

@@ -3,9 +3,11 @@ uniform vec3 diffuse_col;
uniform vec3 specular_col;
uniform int hardness;
out vec4 FragColor;
void main()
{
float roughness = 1.0 - float(hardness) / 511.0;
roughness *= roughness;
fragColor = vec4(eevee_surface_lit(worldNormal, diffuse_col, specular_col, roughness), 1.0);
FragColor = vec4(eevee_surface_lit(worldNormal, diffuse_col, specular_col, roughness), 1.0);
}

View File

@@ -28,8 +28,6 @@ layout(std140) uniform shadow_block {
in vec3 worldPosition;
in vec3 worldNormal;
out vec4 fragColor;
/* type */
#define POINT 0.0
#define SUN 1.0

View File

@@ -8,7 +8,7 @@ in vec4 vPos[];
in int face[];
out vec3 worldPosition;
out vec3 worldNormal;
out vec3 worldNormal; /* Required. otherwise generate linking error on AMD. */
const vec3 maj_axes[6] = vec3[6](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3( 0.0, 0.0, 1.0), vec3( 0.0, 0.0, -1.0));
const vec3 x_axis[6] = vec3[6](vec3(0.0, 0.0, -1.0), vec3( 0.0, 0.0, 1.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3( 1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0));

View File

@@ -56,6 +56,7 @@
struct bContext;
struct GPUFrameBuffer;
struct GPUShader;
struct GPUMaterial;
struct GPUTexture;
struct GPUUniformBuffer;
struct Object;
@@ -245,6 +246,8 @@ typedef enum {
} DRWState;
DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass);
DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPass *pass);
DRWShadingGroup *DRW_shgroup_material_instance_create(struct GPUMaterial *material, DRWPass *pass, struct Batch *geom);
DRWShadingGroup *DRW_shgroup_instance_create(struct GPUShader *shader, DRWPass *pass, struct Batch *geom);
DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass);
DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass);

View File

@@ -47,11 +47,13 @@
#include "ED_space_api.h"
#include "ED_screen.h"
#include "intern/gpu_codegen.h"
#include "GPU_batch.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
#include "GPU_lamp.h"
#include "GPU_material.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
#include "GPU_uniformbuffer.h"
@@ -614,6 +616,80 @@ DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass)
return shgroup;
}
DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPass *pass)
{
double time = 0.0; /* TODO make time variable */
const int max_tex = GPU_max_textures() - 1;
/* TODO : Ideally we should not convert. But since the whole codegen
* is relying on GPUPass we keep it as is for now. */
GPUPass *gpupass = GPU_material_get_pass(material);
if (!gpupass) {
/* Shader compilation error */
return NULL;
}
struct GPUShader *shader = GPU_pass_shader(gpupass);
DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
/* Converting dynamic GPUInput to DRWUniform */
ListBase *inputs = &gpupass->inputs;
for (GPUInput *input = inputs->first; input; input = input->next) {
/* Textures */
if (input->ima) {
GPUTexture *tex = GPU_texture_from_blender(input->ima, input->iuser, input->textarget, input->image_isdata, time, 1);
if (input->bindtex) {
/* TODO maybe track texture slot usage to avoid clash with engine textures */
DRW_shgroup_uniform_texture(grp, input->shadername, tex, max_tex - input->texid);
}
}
/* Floats */
else {
switch (input->type) {
case 1:
DRW_shgroup_uniform_float(grp, input->shadername, (float *)input->dynamicvec, 1);
break;
case 2:
DRW_shgroup_uniform_vec2(grp, input->shadername, (float *)input->dynamicvec, 1);
break;
case 3:
DRW_shgroup_uniform_vec3(grp, input->shadername, (float *)input->dynamicvec, 1);
break;
case 4:
DRW_shgroup_uniform_vec4(grp, input->shadername, (float *)input->dynamicvec, 1);
break;
case 9:
DRW_shgroup_uniform_mat3(grp, input->shadername, (float *)input->dynamicvec);
break;
case 16:
DRW_shgroup_uniform_mat4(grp, input->shadername, (float *)input->dynamicvec);
break;
default:
break;
}
}
}
return grp;
}
DRWShadingGroup *DRW_shgroup_material_instance_create(struct GPUMaterial *material, DRWPass *pass, Batch *geom)
{
DRWShadingGroup *shgroup = DRW_shgroup_material_create(material, pass);
if (shgroup) {
shgroup->type = DRW_SHG_INSTANCE;
shgroup->instance_geom = geom;
}
return shgroup;
}
DRWShadingGroup *DRW_shgroup_instance_create(struct GPUShader *shader, DRWPass *pass, Batch *geom)
{
DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass);

View File

@@ -56,6 +56,7 @@ struct GPUTexture;
struct GPULamp;
struct PreviewImage;
struct World;
struct bNodeTree;
typedef struct GPUNode GPUNode;
typedef struct GPUNodeLink GPUNodeLink;
@@ -218,7 +219,9 @@ GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]);
/* High level functions to create and use GPU materials */
GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo);
GPUMaterial *GPU_material_from_nodetree(
struct bNodeTree *ntree, struct ListBase *gpumaterials, void *engine_type, int options,
const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines);
GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma, bool use_opensubdiv);
GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma, bool use_opensubdiv);
void GPU_material_free(struct ListBase *gpumaterial);
@@ -235,6 +238,7 @@ void GPU_material_unbind(GPUMaterial *material);
bool GPU_material_bound(GPUMaterial *material);
struct Scene *GPU_material_scene(GPUMaterial *material);
GPUMatType GPU_Material_get_type(GPUMaterial *material);
struct GPUPass *GPU_material_get_pass(GPUMaterial *material);
void GPU_material_vertex_attributes(GPUMaterial *material,
struct GPUVertexAttribs *attrib);

View File

@@ -928,6 +928,67 @@ GPUShader *GPU_pass_shader(GPUPass *pass)
return pass->shader;
}
static void gpu_nodes_extract_dynamic_inputs_new(GPUPass *pass, ListBase *nodes)
{
GPUShader *shader = pass->shader;
GPUNode *node;
GPUInput *next, *input;
ListBase *inputs = &pass->inputs;
int extract, z;
memset(inputs, 0, sizeof(*inputs));
if (!shader)
return;
GPU_shader_bind(shader);
for (node = nodes->first; node; node = node->next) {
z = 0;
for (input = node->inputs.first; input; input = next, z++) {
next = input->next;
/* attributes don't need to be bound, they already have
* an id that the drawing functions will use */
if (input->source == GPU_SOURCE_ATTRIB) {
continue;
}
if (input->source == GPU_SOURCE_BUILTIN ||
input->source == GPU_SOURCE_OPENGL_BUILTIN)
{
continue;
}
if (input->ima || input->tex || input->prv)
BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid);
else
BLI_snprintf(input->shadername, sizeof(input->shadername), "unf%d", input->id);
/* pass non-dynamic uniforms to opengl */
extract = 0;
if (input->ima || input->tex || input->prv) {
if (input->bindtex)
extract = 1;
}
else if (input->dynamicvec)
extract = 1;
if (extract)
input->shaderloc = GPU_shader_get_uniform(shader, input->shadername);
/* extract nodes */
if (extract) {
BLI_remlink(&node->inputs, input);
BLI_addtail(inputs, input);
}
}
}
GPU_shader_unbind();
}
static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
{
GPUShader *shader = pass->shader;
@@ -1647,6 +1708,67 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
}
}
GPUPass *GPU_generate_pass_new(ListBase *nodes, struct GPUNodeLink *frag_outlink,
const char *vert_code, const char *geom_code,
const char *frag_lib, const char *defines)
{
GPUShader *shader;
GPUPass *pass;
char *vertexgen, *geometrygen, *fragmentgen, *tmp;
char *vertexcode, *geometrycode, *fragmentcode;
/* prune unused nodes */
gpu_nodes_prune(nodes, frag_outlink);
/* generate code and compile with opengl */
fragmentgen = code_generate_fragment(nodes, frag_outlink->output);
// vertexgen = code_generate_vertex(nodes, GPU_MATERIAL_TYPE_MESH);
// geometrygen = code_generate_geometry(nodes, false);
UNUSED_VARS(vertexgen, geometrygen);
tmp = BLI_strdupcat(frag_lib, glsl_material_library);
fragmentcode = BLI_strdupcat(tmp, fragmentgen);
vertexcode = BLI_strdup(vert_code);
geometrycode = BLI_strdup(geom_code);
shader = GPU_shader_create(vertexcode,
fragmentcode,
geometrycode,
NULL,
defines);
MEM_freeN(tmp);
/* failed? */
if (!shader) {
if (fragmentcode)
MEM_freeN(fragmentcode);
if (vertexcode)
MEM_freeN(vertexcode);
if (geometrycode)
MEM_freeN(geometrycode);
MEM_freeN(fragmentgen);
gpu_nodes_free(nodes);
return NULL;
}
/* create pass */
pass = MEM_callocN(sizeof(GPUPass), "GPUPass");
pass->shader = shader;
pass->fragmentcode = fragmentcode;
pass->geometrycode = geometrycode;
pass->vertexcode = vertexcode;
pass->libcode = glsl_material_library;
/* extract dynamic inputs and throw away nodes */
gpu_nodes_extract_dynamic_inputs_new(pass, nodes);
gpu_nodes_free(nodes);
MEM_freeN(fragmentgen);
return pass;
}
GPUPass *GPU_generate_pass(
ListBase *nodes, GPUNodeLink *outlink,
GPUVertexAttribs *attribs, int *builtins,
@@ -1705,7 +1827,6 @@ GPUPass *GPU_generate_pass(
/* create pass */
pass = MEM_callocN(sizeof(GPUPass), "GPUPass");
pass->output = outlink->output;
pass->shader = shader;
pass->fragmentcode = fragmentcode;
pass->geometrycode = geometrycode;

View File

@@ -156,10 +156,7 @@ typedef struct GPUInput {
} GPUInput;
struct GPUPass {
struct GPUPass *next, *prev;
ListBase inputs;
struct GPUOutput *output;
struct GPUShader *shader;
char *fragmentcode;
char *geometrycode;
@@ -170,6 +167,9 @@ struct GPUPass {
typedef struct GPUPass GPUPass;
GPUPass *GPU_generate_pass_new(ListBase *nodes, struct GPUNodeLink *frag_outlink,
const char *vert_code, const char *geom_code,
const char *frag_lib, const char *defines);
GPUPass *GPU_generate_pass(ListBase *nodes, struct GPUNodeLink *outlink,
struct GPUVertexAttribs *attribs, int *builtin,
const GPUMatType type, const char *name,

View File

@@ -94,12 +94,15 @@ static struct GPUWorld {
} GPUWorld;
struct GPUMaterial {
Scene *scene;
Scene *scene; /* DEPRECATED was only usefull for lamps */
Material *ma;
/* material for mesh surface, worlds or something else.
* some code generation is done differently depending on the use case */
int type;
int type; /* DEPRECATED */
void *engine; /* attached engine type */
int options; /* to identify shader variations (shadow, probe, world background...) */
/* for creating the material */
ListBase nodes;
@@ -436,6 +439,10 @@ GPUMatType GPU_Material_get_type(GPUMaterial *material)
return material->type;
}
GPUPass *GPU_material_get_pass(GPUMaterial *material)
{
return material->pass;
}
void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs)
{
@@ -470,6 +477,10 @@ void gpu_material_add_node(GPUMaterial *material, GPUNode *node)
bool GPU_material_do_color_management(GPUMaterial *mat)
{
/* XXX mat->scene == NULL in that case */
if (mat->engine)
return true;
if (!BKE_scene_check_color_management_enabled(mat->scene))
return false;
@@ -2096,6 +2107,47 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo)
return mat;
}
/* TODO : This is supposed to replace GPU_material_from_blender/_world in the future */
GPUMaterial *GPU_material_from_nodetree(
struct bNodeTree *ntree, ListBase *gpumaterials, void *engine_type, int options,
const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines)
{
GPUMaterial *mat;
GPUNodeLink *outlink;
LinkData *link;
for (link = gpumaterials->first; link; link = link->next) {
GPUMaterial *current_material = (GPUMaterial *)link->data;
if (current_material->engine == engine_type &&
current_material->options == options)
{
return current_material;
}
}
/* allocate material */
mat = GPU_material_construct_begin(NULL); /* TODO remove GPU_material_construct_begin */
mat->engine = engine_type;
mat->options = options;
ntreeGPUMaterialNodes(ntree, mat, NODE_NEWER_SHADING);
/* Let Draw manager finish the construction. */
if (mat->outlink) {
outlink = mat->outlink;
mat->pass = GPU_generate_pass_new(&mat->nodes, outlink, vert_code, geom_code, frag_lib, defines);
}
/* note that even if building the shader fails in some way, we still keep
* it to avoid trying to compile again and again, and simple do not use
* the actual shader on drawing */
link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
link->data = mat;
BLI_addtail(gpumaterials, link);
return mat;
}
GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv)
{

View File

@@ -1,6 +1,8 @@
uniform mat4 ModelViewMatrix;
#ifndef PROBE_CAPTURE
uniform mat4 ProjectionMatrix;
#endif
uniform mat4 ModelViewMatrixInverse;
uniform mat4 ProjectionMatrixInverse;
uniform mat3 NormalMatrix;
@@ -172,7 +174,7 @@ void color_to_blender_normal_new_shading(vec3 color, out vec3 normal)
}
#define M_PI 3.14159265358979323846
#define M_1_PI 0.31830988618379069
#define M_1_PI 0.318309886183790671538
/*********** SHADER NODES ***************/
@@ -2813,6 +2815,13 @@ void background_transform_to_world(vec3 viewvec, out vec3 worldvec)
worldvec = (ModelViewMatrixInverse * co).xyz;
}
#ifdef PROBE_CAPTURE
void environment_default_vector(out vec3 worldvec)
{
worldvec = normalize(worldPosition);
}
#endif
void node_background(vec4 color, float strength, vec3 N, out vec4 result)
{
result = color * strength;

View File

@@ -119,6 +119,7 @@ static void rna_World_use_nodes_update(bContext *C, PointerRNA *ptr)
ED_node_shader_default(C, &wrld->id);
rna_World_update(CTX_data_main(C), CTX_data_scene(C), ptr);
rna_World_draw_update(CTX_data_main(C), CTX_data_scene(C), ptr);
}
#else

View File

@@ -69,8 +69,10 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE
if (type == GPU_MATERIAL_TYPE_MESH)
in[0].link = GPU_builtin(GPU_VIEW_POSITION);
else
else if (type == GPU_MATERIAL_TYPE_WORLD)
GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &in[0].link);
else
GPU_link(mat, "environment_default_vector", &in[0].link);
}
node_shader_gpu_tex_mapping(mat, node, in, out);