diff options
Diffstat (limited to 'source/blender/gpu/intern/gpu_material.c')
-rw-r--r-- | source/blender/gpu/intern/gpu_material.c | 145 |
1 files changed, 128 insertions, 17 deletions
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 4d3ea3e0c99..ca2a9f5cf28 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -41,15 +41,21 @@ /* Structs */ #define MAX_COLOR_BAND 128 +#define MAX_GPU_SKIES 8 typedef struct GPUColorBandBuilder { float pixels[MAX_COLOR_BAND][CM_TABLE + 1][4]; int current_layer; } GPUColorBandBuilder; +typedef struct GPUSkyBuilder { + float pixels[MAX_GPU_SKIES][GPU_SKY_WIDTH * GPU_SKY_HEIGHT][4]; + int current_layer; +} GPUSkyBuilder; + struct GPUMaterial { - /* Contains GPUShader and source code for deferred compilation. - * Can be shared between similar material (i.e: sharing same nodetree topology). */ + /* Contains #GPUShader and source code for deferred compilation. + * Can be shared between similar material (i.e: sharing same node-tree topology). */ GPUPass *pass; /** UBOs for this material parameters. */ GPUUniformBuf *ubo; @@ -73,6 +79,10 @@ struct GPUMaterial { GPUTexture *coba_tex; /** Builder for coba_tex. */ GPUColorBandBuilder *coba_builder; + /** 2D Texture array containing all sky textures. */ + GPUTexture *sky_tex; + /** Builder for sky_tex. */ + GPUSkyBuilder *sky_builder; /* Low level node graph(s). Also contains resources needed by the material. */ GPUNodeGraph graph; @@ -91,11 +101,42 @@ struct GPUMaterial { #ifndef NDEBUG char name[64]; +#else + char name[16]; #endif }; /* Functions */ +GPUTexture **gpu_material_sky_texture_layer_set( + GPUMaterial *mat, int width, int height, const float *pixels, float *row) +{ + /* In order to put all sky textures into one 2D array texture, + * we need them to be the same size. */ + BLI_assert(width == GPU_SKY_WIDTH); + BLI_assert(height == GPU_SKY_HEIGHT); + UNUSED_VARS_NDEBUG(width, height); + + if (mat->sky_builder == NULL) { + mat->sky_builder = MEM_mallocN(sizeof(GPUSkyBuilder), "GPUSkyBuilder"); + mat->sky_builder->current_layer = 0; + } + + int layer = mat->sky_builder->current_layer; + *row = (float)layer; + + if (*row == MAX_GPU_SKIES) { + printf("Too many sky textures in shader!\n"); + } + else { + float *dst = (float *)mat->sky_builder->pixels[layer]; + memcpy(dst, pixels, sizeof(float) * GPU_SKY_WIDTH * GPU_SKY_HEIGHT * 4); + mat->sky_builder->current_layer += 1; + } + + return &mat->sky_tex; +} + GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat, int size, float *pixels, @@ -141,7 +182,25 @@ static void gpu_material_ramp_texture_build(GPUMaterial *mat) mat->coba_builder = NULL; } -static void gpu_material_free_single(GPUMaterial *material) +static void gpu_material_sky_texture_build(GPUMaterial *mat) +{ + if (mat->sky_builder == NULL) { + return; + } + + mat->sky_tex = GPU_texture_create_2d_array("mat_sky", + GPU_SKY_WIDTH, + GPU_SKY_HEIGHT, + mat->sky_builder->current_layer, + 1, + GPU_RGBA32F, + (float *)mat->sky_builder->pixels); + + MEM_freeN(mat->sky_builder); + mat->sky_builder = NULL; +} + +void GPU_material_free_single(GPUMaterial *material) { bool do_free = atomic_sub_and_fetch_uint32(&material->refcount, 1) == 0; if (!do_free) { @@ -159,6 +218,9 @@ static void gpu_material_free_single(GPUMaterial *material) if (material->coba_tex != NULL) { GPU_texture_free(material->coba_tex); } + if (material->sky_tex != NULL) { + GPU_texture_free(material->sky_tex); + } if (material->sss_profile != NULL) { GPU_uniformbuf_free(material->sss_profile); } @@ -173,7 +235,7 @@ void GPU_material_free(ListBase *gpumaterial) LISTBASE_FOREACH (LinkData *, link, gpumaterial) { GPUMaterial *material = link->data; DRW_deferred_shader_remove(material); - gpu_material_free_single(material); + GPU_material_free_single(material); } BLI_freelistN(gpumaterial); } @@ -193,6 +255,11 @@ GPUShader *GPU_material_get_shader(GPUMaterial *material) return material->pass ? GPU_pass_shader_get(material->pass) : NULL; } +const char *GPU_material_get_name(GPUMaterial *material) +{ + return material->name; +} + Material *GPU_material_get_material(GPUMaterial *material) { return material->ma; @@ -205,12 +272,7 @@ GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material) void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs) { -#ifndef NDEBUG - const char *name = material->name; -#else - const char *name = "Material"; -#endif - material->ubo = GPU_uniformbuf_create_from_list(inputs, name); + material->ubo = GPU_uniformbuf_create_from_list(inputs, material->name); } ListBase GPU_material_attributes(GPUMaterial *material) @@ -223,12 +285,18 @@ ListBase GPU_material_textures(GPUMaterial *material) return material->graph.textures; } -GPUUniformAttrList *GPU_material_uniform_attributes(GPUMaterial *material) +const GPUUniformAttrList *GPU_material_uniform_attributes(const GPUMaterial *material) { - GPUUniformAttrList *attrs = &material->graph.uniform_attrs; + const GPUUniformAttrList *attrs = &material->graph.uniform_attrs; return attrs->count > 0 ? attrs : NULL; } +const ListBase *GPU_material_layer_attributes(const GPUMaterial *material) +{ + const ListBase *attrs = &material->graph.layer_attrs; + return !BLI_listbase_is_empty(attrs) ? attrs : NULL; +} + #if 1 /* End of life code. */ /* Eevee Subsurface scattering. */ /* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */ @@ -538,6 +606,13 @@ void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, BLI_addtail(&material->graph.outlink_aovs, aov_link); } +void GPU_material_add_output_link_composite(GPUMaterial *material, GPUNodeLink *link) +{ + GPUNodeGraphOutputLink *compositor_link = MEM_callocN(sizeof(GPUNodeGraphOutputLink), __func__); + compositor_link->outlink = link; + BLI_addtail(&material->graph.outlink_compositor, compositor_link); +} + char *GPU_material_split_sub_function(GPUMaterial *material, eGPUType return_type, GPUNodeLink **link) @@ -665,11 +740,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, mat->graph.used_libraries = BLI_gset_new( BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries"); mat->refcount = 1; -#ifndef NDEBUG STRNCPY(mat->name, name); -#else - UNUSED_VARS(name); -#endif if (is_lookdev) { mat->flag |= GPU_MATFLAG_LOOKDEV_HACK; } @@ -679,6 +750,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, ntreeGPUMaterialNodes(localtree, mat); gpu_material_ramp_texture_build(mat); + gpu_material_sky_texture_build(mat); { /* Create source code and search pass cache for an already compiled version. */ @@ -721,7 +793,7 @@ void GPU_material_acquire(GPUMaterial *mat) void GPU_material_release(GPUMaterial *mat) { - gpu_material_free_single(mat); + GPU_material_free_single(mat); } void GPU_material_compile(GPUMaterial *mat) @@ -772,3 +844,42 @@ void GPU_materials_free(Main *bmain) // BKE_world_defaults_free_gpu(); BKE_material_defaults_free_gpu(); } + +GPUMaterial *GPU_material_from_callbacks(ConstructGPUMaterialFn construct_function_cb, + GPUCodegenCallbackFn generate_code_function_cb, + void *thunk) +{ + /* Allocate a new material and its material graph, and initialize its reference count. */ + GPUMaterial *material = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial"); + material->graph.used_libraries = BLI_gset_new( + BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries"); + material->refcount = 1; + + /* Construct the material graph by adding and linking the necessary GPU material nodes. */ + construct_function_cb(thunk, material); + + /* Create and initialize the texture storing color bands used by Ramp and Curve nodes. */ + gpu_material_ramp_texture_build(material); + + /* Lookup an existing pass in the cache or generate a new one. */ + material->pass = GPU_generate_pass(material, &material->graph, generate_code_function_cb, thunk); + + /* The pass already exists in the pass cache but its shader already failed to compile. */ + if (material->pass == NULL) { + material->status = GPU_MAT_FAILED; + gpu_node_graph_free(&material->graph); + return material; + } + + /* The pass already exists in the pass cache and its shader is already compiled. */ + GPUShader *shader = GPU_pass_shader_get(material->pass); + if (shader != NULL) { + material->status = GPU_MAT_SUCCESS; + gpu_node_graph_free_nodes(&material->graph); + return material; + } + + /* The material was created successfully but still needs to be compiled. */ + material->status = GPU_MAT_CREATED; + return material; +} |