Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py34
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c4
-rw-r--r--source/blender/blenkernel/BKE_world.h6
-rw-r--r--source/blender/blenkernel/intern/object.c10
-rw-r--r--source/blender/blenkernel/intern/scene.c15
-rw-r--r--source/blender/blenkernel/intern/studiolight.c4
-rw-r--r--source/blender/blenkernel/intern/world.c11
-rw-r--r--source/blender/blenloader/CMakeLists.txt1
-rw-r--r--source/blender/blenloader/intern/readblenentry.c6
-rw-r--r--source/blender/blenloader/intern/readfile.c96
-rw-r--r--source/blender/blenloader/intern/readfile.h3
-rw-r--r--source/blender/blenloader/intern/versioning_280.c7
-rw-r--r--source/blender/blenloader/intern/writefile.c36
-rw-r--r--source/blender/depsgraph/CMakeLists.txt1
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc4
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc22
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc10
-rw-r--r--source/blender/draw/CMakeLists.txt2
-rw-r--r--source/blender/draw/DRW_engine.h8
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c99
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c43
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c1134
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.h59
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c1883
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c57
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c39
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h166
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c34
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c3
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl17
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl49
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_frag.glsl14
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl35
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl1
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl11
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c12
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c8
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h8
-rw-r--r--source/blender/draw/intern/DRW_render.h43
-rw-r--r--source/blender/draw/intern/draw_manager.c257
-rw-r--r--source/blender/draw/intern/draw_manager.h2
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c20
-rw-r--r--source/blender/draw/modes/object_mode.c20
-rw-r--r--source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl13
-rw-r--r--source/blender/editors/render/render_intern.h3
-rw-r--r--source/blender/editors/render/render_ops.c3
-rw-r--r--source/blender/editors/render/render_shading.c182
-rw-r--r--source/blender/editors/render/render_update.c3
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c23
-rw-r--r--source/blender/gpu/GPU_texture.h26
-rw-r--r--source/blender/gpu/intern/gpu_texture.c513
-rw-r--r--source/blender/makesdna/DNA_ID.h21
-rw-r--r--source/blender/makesdna/DNA_lightprobe_types.h72
-rw-r--r--source/blender/makesdna/DNA_object_types.h18
-rw-r--r--source/blender/makesdna/DNA_scene_types.h9
-rw-r--r--source/blender/makesdna/DNA_world_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_scene.c32
-rw-r--r--source/blender/windowmanager/WM_api.h1
-rw-r--r--source/blender/windowmanager/WM_types.h1
61 files changed, 3518 insertions, 1705 deletions
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 580c31465b3..ff36d2494ea 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -712,15 +712,49 @@ class RENDER_PT_eevee_indirect_lighting(RenderButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
scene = context.scene
props = scene.eevee
col = layout.column()
+ col.operator("scene.light_cache_bake", text="Bake Indirect Lighting", icon='RENDER_STILL')
+ col.operator("scene.light_cache_bake", text="Bake Cubemap Only", icon='LIGHTPROBE_CUBEMAP').subset = "CUBEMAPS"
+ col.operator("scene.light_cache_free", text="Free Lighting Cache")
+
+ cache_info = scene.eevee.gi_cache_info
+ if cache_info:
+ col.label(text=cache_info)
+
+ col.prop(props, "gi_auto_bake")
+
col.prop(props, "gi_diffuse_bounces")
col.prop(props, "gi_cubemap_resolution")
col.prop(props, "gi_visibility_resolution", text="Diffuse Occlusion")
+ layout.use_property_split = False
+ row = layout.split(percentage=0.5)
+ row.alignment = 'RIGHT'
+ row.label("Cubemap Display")
+
+ sub = row.row(align=True)
+ sub.prop(props, "gi_cubemap_draw_size", text="Size")
+ if props.gi_show_cubemaps :
+ sub.prop(props, "gi_show_cubemaps", text="", toggle=True, icon='HIDE_OFF')
+ else:
+ sub.prop(props, "gi_show_cubemaps", text="", toggle=True, icon='HIDE_ON')
+
+ row = layout.split(percentage=0.5)
+ row.alignment = 'RIGHT'
+ row.label("Irradiance Display")
+
+ sub = row.row(align=True)
+ sub.prop(props, "gi_irradiance_draw_size", text="Size")
+ if props.gi_show_irradiance :
+ sub.prop(props, "gi_show_irradiance", text="", toggle=True, icon='HIDE_OFF')
+ else:
+ sub.prop(props, "gi_show_irradiance", text="", toggle=True, icon='HIDE_ON')
+
class RENDER_PT_eevee_film(RenderButtonsPanel, Panel):
bl_label = "Film"
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 84388bedb7b..8dc11443124 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -239,7 +239,7 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc)
}
unsigned char *pixels = MEM_callocN((size_t)gc->p2_width * (size_t)gc->p2_height, "BLF texture init");
- GPUTexture *tex = GPU_texture_create_2D(gc->p2_width, gc->p2_height, GPU_R8, (const float *)pixels, error);
+ GPUTexture *tex = GPU_texture_create_nD(gc->p2_width, gc->p2_height, 0, 2, pixels, GPU_R8, GPU_DATA_UNSIGNED_BYTE, 0, false, error);
MEM_freeN(pixels);
gc->textures[gc->texture_current] = tex;
GPU_texture_bind(tex, 0);
@@ -476,7 +476,7 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
BLI_assert(g->height > 0);
}
- GPU_texture_update_sub(g->tex, g->bitmap, g->offset_x, g->offset_y, 0, g->width, g->height, 0);
+ GPU_texture_update_sub(g->tex, GPU_DATA_UNSIGNED_BYTE, g->bitmap, g->offset_x, g->offset_y, 0, g->width, g->height, 0);
g->uv[0][0] = ((float)g->offset_x) / ((float)gc->p2_width);
g->uv[0][1] = ((float)g->offset_y) / ((float)gc->p2_height);
diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h
index f703fefec97..6a9a75828e5 100644
--- a/source/blender/blenkernel/BKE_world.h
+++ b/source/blender/blenkernel/BKE_world.h
@@ -44,10 +44,4 @@ struct World *BKE_world_copy(struct Main *bmain, const struct World *wrld);
struct World *BKE_world_localize(struct World *wrld);
void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local);
-/* Evaluation. */
-
-struct Depsgraph;
-
-void BKE_world_eval(struct Depsgraph *depsgraph, struct World *world);
-
#endif
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index a7c13ab2a81..275e215e71a 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -424,6 +424,8 @@ void BKE_object_free(Object *ob)
{
BKE_animdata_free((ID *)ob, false);
+ DRW_drawdata_free((ID *)ob);
+
/* BKE_<id>_free shall never touch to ID->us. Never ever. */
BKE_object_free_modifiers(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
@@ -451,13 +453,6 @@ void BKE_object_free(Object *ob)
sbFree(ob);
- for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) {
- if (oed->free != NULL) {
- oed->free(oed);
- }
- }
- BLI_freelistN(&ob->drawdata);
-
BKE_sculptsession_free(ob);
BLI_freelistN(&ob->pc_ids);
@@ -1210,7 +1205,6 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
ob_dst->derivedFinal = NULL;
BLI_listbase_clear(&ob_dst->gpulamp);
- BLI_listbase_clear(&ob_dst->drawdata);
BLI_listbase_clear(&ob_dst->pc_ids);
ob_dst->avs = ob_src->avs;
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 1b309d76f61..8886fae1707 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -102,6 +102,9 @@
#include "DEG_depsgraph_query.h"
#include "RE_engine.h"
+#include "RE_engine.h"
+
+#include "engines/eevee/eevee_lightcache.h"
#include "PIL_time.h"
@@ -316,6 +319,9 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
else {
sce_dst->preview = NULL;
}
+
+ sce_dst->eevee.light_cache = NULL;
+ /* TODO Copy the cache. */
}
Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
@@ -511,6 +517,11 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
sce->master_collection = NULL;
}
+ if (sce->eevee.light_cache) {
+ EEVEE_lightcache_free(sce->eevee.light_cache);
+ sce->eevee.light_cache = NULL;
+ }
+
/* These are freed on doversion. */
BLI_assert(sce->layer_properties == NULL);
}
@@ -814,6 +825,8 @@ void BKE_scene_init(Scene *sce)
sce->eevee.gi_diffuse_bounces = 3;
sce->eevee.gi_cubemap_resolution = 512;
sce->eevee.gi_visibility_resolution = 32;
+ sce->eevee.gi_cubemap_draw_size = 0.2f;
+ sce->eevee.gi_irradiance_draw_size = 1.0f;
sce->eevee.taa_samples = 16;
sce->eevee.taa_render_samples = 64;
@@ -856,6 +869,8 @@ void BKE_scene_init(Scene *sce)
sce->eevee.shadow_cube_size = 512;
sce->eevee.shadow_cascade_size = 1024;
+ sce->eevee.light_cache = NULL;
+
sce->eevee.flag =
SCE_EEVEE_VOLUMETRIC_LIGHTS |
SCE_EEVEE_VOLUMETRIC_COLORED |
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 468a961627e..255afeb5af3 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -239,8 +239,8 @@ static void studiolight_create_equirectangular_radiance_gputexture(StudioLight *
offset3 += 3;
offset4 += 4;
}
- sl->equirectangular_radiance_gputexture = GPU_texture_create_2D(
- ibuf->x, ibuf->y, GPU_R11F_G11F_B10F, sl->gpu_matcap_3components, error);
+ sl->equirectangular_radiance_gputexture = GPU_texture_create_nD(
+ ibuf->x, ibuf->y, 0, 2, sl->gpu_matcap_3components, GPU_R11F_G11F_B10F, GPU_DATA_FLOAT, 0, false, error);
}
else {
sl->equirectangular_radiance_gputexture = GPU_texture_create_2D(
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 69096ad7a08..66390631a55 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -53,6 +53,8 @@
#include "BKE_node.h"
#include "BKE_world.h"
+#include "DRW_engine.h"
+
#include "DEG_depsgraph.h"
#include "GPU_material.h"
@@ -62,6 +64,8 @@ void BKE_world_free(World *wrld)
{
BKE_animdata_free((ID *)wrld, false);
+ DRW_drawdata_free((ID *)wrld);
+
/* is no lib link block, but world extension */
if (wrld->nodetree) {
ntreeFreeTree(wrld->nodetree);
@@ -163,10 +167,3 @@ void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local)
BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local);
}
-void BKE_world_eval(struct Depsgraph *depsgraph, World *world)
-{
- DEG_debug_print_eval(depsgraph, __func__, world->id.name, world);
- if (!BLI_listbase_is_empty(&world->gpumaterial)) {
- world->update_flag = 1;
- }
-}
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index b340aa28324..72fa155553d 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../blenlib
../blentranslation
../depsgraph
+ ../draw
../imbuf
../makesdna
../makesrna
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index 7488d62bb3c..6fd77c34977 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -393,6 +393,9 @@ BlendFileData *BLO_read_from_memfile(
/* makes lookup of existing images in old main */
blo_make_image_pointer_map(fd, oldmain);
+ /* makes lookup of existing light caches in old main */
+ blo_make_scene_pointer_map(fd, oldmain);
+
/* makes lookup of existing video clips in old main */
blo_make_movieclip_pointer_map(fd, oldmain);
@@ -403,6 +406,9 @@ BlendFileData *BLO_read_from_memfile(
bfd = blo_read_file_internal(fd, filename);
+ /* ensures relinked light caches are not freed */
+ blo_end_scene_pointer_map(fd, oldmain);
+
/* ensures relinked images are not freed */
blo_end_image_pointer_map(fd, oldmain);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index effaa592080..7ebd7d09812 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -158,6 +158,8 @@
#include "BKE_colortools.h"
#include "BKE_workspace.h"
+#include "DRW_engine.h"
+
#include "DEG_depsgraph.h"
#include "NOD_common.h"
@@ -1339,6 +1341,8 @@ void blo_freefiledata(FileData *fd)
oldnewmap_free(fd->imamap);
if (fd->movieclipmap)
oldnewmap_free(fd->movieclipmap);
+ if (fd->scenemap)
+ oldnewmap_free(fd->scenemap);
if (fd->soundmap)
oldnewmap_free(fd->soundmap);
if (fd->packedmap)
@@ -1526,6 +1530,13 @@ static void *newimaadr(FileData *fd, const void *adr) /* used to restore im
return NULL;
}
+static void *newsceadr(FileData *fd, const void *adr) /* used to restore scene data after undo */
+{
+ if (fd->scenemap && adr)
+ return oldnewmap_lookup_and_inc(fd->scenemap, adr, true);
+ return NULL;
+}
+
static void *newmclipadr(FileData *fd, const void *adr) /* used to restore movie clip data after undo */
{
if (fd->movieclipmap && adr)
@@ -1631,6 +1642,37 @@ void blo_clear_proxy_pointers_from_lib(Main *oldmain)
}
}
+void blo_make_scene_pointer_map(FileData *fd, Main *oldmain)
+{
+ Scene *sce = oldmain->scene.first;
+
+ fd->scenemap = oldnewmap_new();
+
+ for (; sce; sce = sce->id.next) {
+ if (sce->eevee.light_cache) {
+ struct LightCache *light_cache = sce->eevee.light_cache;
+ oldnewmap_insert(fd->scenemap, light_cache, light_cache, 0);
+ }
+ }
+}
+
+void blo_end_scene_pointer_map(FileData *fd, Main *oldmain)
+{
+ OldNew *entry = fd->scenemap->entries;
+ Scene *sce = oldmain->scene.first;
+ int i;
+
+ /* used entries were restored, so we put them to zero */
+ for (i = 0; i < fd->scenemap->nentries; i++, entry++) {
+ if (entry->nr > 0)
+ entry->newp = NULL;
+ }
+
+ for (; sce; sce = sce->id.next) {
+ sce->eevee.light_cache = newsceadr(fd, sce->eevee.light_cache);
+ }
+}
+
void blo_make_image_pointer_map(FileData *fd, Main *oldmain)
{
Image *ima = oldmain->image.first;
@@ -2301,6 +2343,11 @@ static void direct_link_id(FileData *fd, ID *id)
id->override_static = newdataadr(fd, id->override_static);
link_list_ex(fd, &id->override_static->properties, direct_link_id_override_property_cb);
}
+
+ DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
+ if (drawdata) {
+ BLI_listbase_clear((ListBase *)drawdata);
+ }
}
/* ************ READ CurveMapping *************** */
@@ -5493,7 +5540,6 @@ static void direct_link_object(FileData *fd, Object *ob)
ob->derivedFinal = NULL;
BKE_object_runtime_reset(ob);
BLI_listbase_clear(&ob->gpulamp);
- BLI_listbase_clear(&ob->drawdata);
link_list(fd, &ob->pc_ids);
/* Runtime curve data */
@@ -5740,6 +5786,41 @@ static void lib_link_sequence_modifiers(FileData *fd, Scene *scene, ListBase *lb
}
}
+static void direct_link_lightcache_texture(FileData *fd, LightCacheTexture *lctex)
+{
+ lctex->tex = NULL;
+
+ if (lctex->data) {
+ lctex->data = newdataadr(fd, lctex->data);
+ if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ int data_size = lctex->components * lctex->tex_size[0] * lctex->tex_size[1] * lctex->tex_size[2];
+
+ if (lctex->data_type == LIGHTCACHETEX_FLOAT) {
+ BLI_endian_switch_float_array((float *)lctex->data, data_size * sizeof(float));
+ }
+ else if (lctex->data_type == LIGHTCACHETEX_UINT) {
+ BLI_endian_switch_uint32_array((unsigned int *)lctex->data, data_size * sizeof(unsigned int));
+ }
+ }
+ }
+}
+
+static void direct_link_lightcache(FileData *fd, LightCache *cache)
+{
+ direct_link_lightcache_texture(fd, &cache->cube_tx);
+ direct_link_lightcache_texture(fd, &cache->grid_tx);
+
+ if (cache->cube_mips) {
+ cache->cube_mips = newdataadr(fd, cache->cube_mips);
+ for (int i = 0; i < cache->mips_len; ++i) {
+ direct_link_lightcache_texture(fd, &cache->cube_mips[i]);
+ }
+ }
+
+ cache->cube_data = newdataadr(fd, cache->cube_data);
+ cache->grid_data = newdataadr(fd, cache->grid_data);
+}
+
/* check for cyclic set-scene,
* libs can cause this case which is normally prevented, see (T#####) */
#define USE_SETSCENE_CHECK
@@ -6300,6 +6381,19 @@ static void direct_link_scene(FileData *fd, Scene *sce)
direct_link_view_layer(fd, view_layer);
}
+ if (fd->memfile) {
+ /* If it's undo try to recover the cache. */
+ if (fd->scenemap) sce->eevee.light_cache = newsceadr(fd, sce->eevee.light_cache);
+ else sce->eevee.light_cache = NULL;
+ }
+ else {
+ /* else read the cache from file. */
+ if (sce->eevee.light_cache) {
+ sce->eevee.light_cache = newdataadr(fd, sce->eevee.light_cache);
+ direct_link_lightcache(fd, sce->eevee.light_cache);
+ }
+ }
+
sce->layer_properties = newdataadr(fd, sce->layer_properties);
IDP_DirectLinkGroup_OrFree(&sce->layer_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 9c699db5583..10f0c7a2942 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -90,6 +90,7 @@ typedef struct FileData {
struct OldNewMap *libmap;
struct OldNewMap *imamap;
struct OldNewMap *movieclipmap;
+ struct OldNewMap *scenemap;
struct OldNewMap *soundmap;
struct OldNewMap *packedmap;
@@ -140,6 +141,8 @@ FileData *blo_openblendermemfile(struct MemFile *memfile, struct ReportList *rep
void blo_clear_proxy_pointers_from_lib(Main *oldmain);
void blo_make_image_pointer_map(FileData *fd, Main *oldmain);
void blo_end_image_pointer_map(FileData *fd, Main *oldmain);
+void blo_make_scene_pointer_map(FileData *fd, Main *oldmain);
+void blo_end_scene_pointer_map(FileData *fd, Main *oldmain);
void blo_make_movieclip_pointer_map(FileData *fd, Main *oldmain);
void blo_end_movieclip_pointer_map(FileData *fd, Main *oldmain);
void blo_make_sound_pointer_map(FileData *fd, Main *oldmain);
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 3bdd4db3b94..d88d4748c7f 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -1530,6 +1530,13 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "gi_cubemap_draw_size")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ scene->eevee.gi_irradiance_draw_size = 0.2f;
+ scene->eevee.gi_cubemap_draw_size = 1.0f;
+ }
+ }
+
for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
if (scene->toolsettings->manipulator_flag == 0) {
scene->toolsettings->manipulator_flag = SCE_MANIP_TRANSLATE | SCE_MANIP_ROTATE | SCE_MANIP_SCALE;
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 0a2d09d0c86..049b2e8617c 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -2479,6 +2479,36 @@ static void write_view_layer(WriteData *wd, ViewLayer *view_layer)
write_layer_collections(wd, &view_layer->layer_collections);
}
+static void write_lightcache_texture(WriteData *wd, LightCacheTexture *tex)
+{
+ if (tex->data) {
+ size_t data_size = tex->components * tex->tex_size[0] * tex->tex_size[1] * tex->tex_size[2];
+ if (tex->data_type == LIGHTCACHETEX_FLOAT) {
+ data_size *= sizeof(float);
+ }
+ else if (tex->data_type == LIGHTCACHETEX_UINT) {
+ data_size *= sizeof(unsigned int);
+ }
+ writedata(wd, DATA, data_size, tex->data);
+ }
+}
+
+static void write_lightcache(WriteData *wd, LightCache *cache)
+{
+ write_lightcache_texture(wd, &cache->grid_tx);
+ write_lightcache_texture(wd, &cache->cube_tx);
+
+ if (cache->cube_mips) {
+ writestruct(wd, DATA, LightCacheTexture, cache->mips_len, cache->cube_mips);
+ for (int i = 0; i < cache->mips_len; ++i) {
+ write_lightcache_texture(wd, &cache->cube_mips[i]);
+ }
+ }
+
+ writestruct(wd, DATA, LightGridCache, cache->grid_len, cache->grid_data);
+ writestruct(wd, DATA, LightProbeCache, cache->cube_len, cache->cube_data);
+}
+
static void write_scene(WriteData *wd, Scene *sce)
{
/* write LibData */
@@ -2679,6 +2709,12 @@ static void write_scene(WriteData *wd, Scene *sce)
write_collection_nolib(wd, sce->master_collection);
}
+ /* Eevee Lightcache */
+ if (sce->eevee.light_cache && !wd->use_memfile) {
+ writestruct(wd, DATA, LightCache, 1, sce->eevee.light_cache);
+ write_lightcache(wd, sce->eevee.light_cache);
+ }
+
/* Freed on doversion. */
BLI_assert(sce->layer_properties == NULL);
}
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index 0673a3177b7..185a98f2a2b 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../blenkernel
../blenlib
../bmesh
+ ../draw
../makesdna
../makesrna
../modifiers
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index cb455130d4c..ab7ddb507a0 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -873,9 +873,7 @@ void DepsgraphNodeBuilder::build_world(World *world)
/* world itself */
add_operation_node(&world->id,
DEG_NODE_TYPE_SHADING,
- function_bind(BKE_world_eval,
- _1,
- get_cow_datablock(world)),
+ NULL,
DEG_OPCODE_WORLD_UPDATE);
/* world's nodetree */
if (world->nodetree != NULL) {
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
index 447a8af6235..3414a5ef63f 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -553,6 +553,13 @@ void update_special_pointers(const Depsgraph *depsgraph,
update_particle_system_orig_pointers(object_orig, object_cow);
break;
}
+ case ID_SCE:
+ {
+ Scene *scene_cow = (Scene *)id_cow;
+ const Scene *scene_orig = (const Scene *)id_orig;
+ scene_cow->eevee.light_cache = scene_orig->eevee.light_cache;
+ break;
+ }
default:
break;
}
@@ -713,7 +720,7 @@ typedef struct ObjectRuntimeBackup {
CurveCache *curve_cache;
Object_Runtime runtime;
short base_flag;
- ListBase drawdata;
+ DrawDataList drawdata;
} ObjectRuntimeBackup;
/* Make a backup of object's evaluation runtime data, additionally
@@ -742,7 +749,7 @@ static void deg_backup_object_runtime(
object_runtime_backup->base_flag = object->base_flag;
/* Make backup of object draw data.*/
object_runtime_backup->drawdata = object->drawdata;
- BLI_listbase_clear(&object->drawdata);
+ BLI_listbase_clear((ListBase *)&object->drawdata);
}
static void deg_restore_object_runtime(
@@ -917,6 +924,12 @@ void discard_mesh_edit_mode_pointers(ID *id_cow)
mesh_cow->edit_btmesh = NULL;
}
+void discard_scene_pointers(ID *id_cow)
+{
+ Scene *scene_cow = (Scene *)id_cow;
+ scene_cow->eevee.light_cache = NULL;
+}
+
/* NULL-ify all edit mode pointers which points to data from
* original object.
*/
@@ -939,6 +952,11 @@ void discard_edit_mode_pointers(ID *id_cow)
case ID_LT:
discard_lattice_edit_mode_pointers(id_cow);
break;
+ case ID_SCE:
+ /* Not really edit mode but still needs to run before
+ * BKE_libblock_free_datablock() */
+ discard_scene_pointers(id_cow);
+ break;
default:
break;
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index bd31931d0a9..16cb1b394f6 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -46,6 +46,8 @@
extern "C" {
#include "DNA_object_types.h"
+
+#include "DRW_engine.h"
} /* extern "C" */
#include "DEG_depsgraph.h"
@@ -219,12 +221,12 @@ BLI_INLINE OperationDepsNode *flush_schedule_children(
void flush_engine_data_update(ID *id)
{
- if (GS(id->name) != ID_OB) {
+ DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
+ if (drawdata == NULL) {
return;
}
- Object *object = (Object *)id;
- LISTBASE_FOREACH(ObjectEngineData *, engine_data, &object->drawdata) {
- engine_data->recalc |= id->recalc;
+ LISTBASE_FOREACH(DrawData *, dd, drawdata) {
+ dd->recalc |= id->recalc;
}
}
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index d7b7129114e..2183bc26755 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -96,6 +96,7 @@ set(SRC
engines/eevee/eevee_depth_of_field.c
engines/eevee/eevee_effects.c
engines/eevee/eevee_engine.c
+ engines/eevee/eevee_lightcache.c
engines/eevee/eevee_lightprobes.c
engines/eevee/eevee_lights.c
engines/eevee/eevee_lookdev.c
@@ -137,6 +138,7 @@ set(SRC
modes/edit_mesh_mode_intern.h
engines/basic/basic_engine.h
engines/eevee/eevee_engine.h
+ engines/eevee/eevee_lightcache.h
engines/eevee/eevee_lut.h
engines/eevee/eevee_private.h
engines/external/external_engine.h
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index d126dcb71aa..ab2001dcb6a 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -136,6 +136,14 @@ void DRW_opengl_context_destroy(void);
void DRW_opengl_context_enable(void);
void DRW_opengl_context_disable(void);
+void DRW_opengl_render_context_enable(void *re_gl_context);
+void DRW_opengl_render_context_disable(void *re_gl_context);
+void DRW_gawain_render_context_enable(void *re_gwn_context);
+void DRW_gawain_render_context_disable(void *re_gwn_context);
+
void DRW_deferred_shader_remove(struct GPUMaterial *mat);
+struct DrawDataList *DRW_drawdatalist_from_id(struct ID *id);
+void DRW_drawdata_free(struct ID *id);
+
#endif /* __DRW_ENGINE_H__ */
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index e9883cc3054..96e784b524c 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -28,6 +28,7 @@
#include "DRW_render.h"
#include "eevee_private.h"
+#include "eevee_lightcache.h"
static void eevee_view_layer_data_free(void *storage)
{
@@ -53,6 +54,11 @@ static void eevee_view_layer_data_free(void *storage)
MEM_SAFE_FREE(sldata->shcasters_buffers[1].shadow_casters);
MEM_SAFE_FREE(sldata->shcasters_buffers[1].flags);
+ if (sldata->fallback_lightcache) {
+ EEVEE_lightcache_free(sldata->fallback_lightcache);
+ sldata->fallback_lightcache = NULL;
+ }
+
/* Probes */
MEM_SAFE_FREE(sldata->probes);
DRW_UBO_FREE_SAFE(sldata->probe_ubo);
@@ -60,15 +66,6 @@ static void eevee_view_layer_data_free(void *storage)
DRW_UBO_FREE_SAFE(sldata->planar_ubo);
DRW_UBO_FREE_SAFE(sldata->common_ubo);
DRW_UBO_FREE_SAFE(sldata->clip_ubo);
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb);
- for (int i = 0; i < 6; ++i) {
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->probe_face_fb[i]);
- }
- DRW_TEXTURE_FREE_SAFE(sldata->probe_rt);
- DRW_TEXTURE_FREE_SAFE(sldata->probe_depth_rt);
- DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
- DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool);
- DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt);
}
EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void)
@@ -77,6 +74,18 @@ EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void)
&draw_engine_eevee_type);
}
+EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure_ex(struct ViewLayer *view_layer)
+{
+ EEVEE_ViewLayerData **sldata = (EEVEE_ViewLayerData **)DRW_view_layer_engine_data_ensure_ex(
+ view_layer, &draw_engine_eevee_type, &eevee_view_layer_data_free);
+
+ if (*sldata == NULL) {
+ *sldata = MEM_callocN(sizeof(**sldata), "EEVEE_ViewLayerData");
+ }
+
+ return *sldata;
+}
+
EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void)
{
EEVEE_ViewLayerData **sldata = (EEVEE_ViewLayerData **)DRW_view_layer_engine_data_ensure(
@@ -91,9 +100,9 @@ EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void)
/* Object data. */
-static void eevee_object_data_init(ObjectEngineData *engine_data)
+static void eevee_object_data_init(DrawData *dd)
{
- EEVEE_ObjectEngineData *eevee_data = (EEVEE_ObjectEngineData *)engine_data;
+ EEVEE_ObjectEngineData *eevee_data = (EEVEE_ObjectEngineData *)dd;
eevee_data->shadow_caster_id = -1;
}
@@ -102,15 +111,15 @@ EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob)
if (ELEM(ob->type, OB_LIGHTPROBE, OB_LAMP)) {
return NULL;
}
- return (EEVEE_ObjectEngineData *)DRW_object_engine_data_get(
- ob, &draw_engine_eevee_type);
+ return (EEVEE_ObjectEngineData *)DRW_drawdata_get(
+ &ob->id, &draw_engine_eevee_type);
}
EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob)
{
BLI_assert(!ELEM(ob->type, OB_LIGHTPROBE, OB_LAMP));
- return (EEVEE_ObjectEngineData *)DRW_object_engine_data_ensure(
- ob,
+ return (EEVEE_ObjectEngineData *)DRW_drawdata_ensure(
+ &ob->id,
&draw_engine_eevee_type,
sizeof(EEVEE_ObjectEngineData),
eevee_object_data_init,
@@ -119,18 +128,10 @@ EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob)
/* Light probe data. */
-static void eevee_lightprobe_data_init(ObjectEngineData *engine_data)
+static void eevee_lightprobe_data_init(DrawData *dd)
{
- EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)engine_data;
- ped->need_full_update = true;
- ped->need_update = true;
-}
-
-static void eevee_lightprobe_data_free(ObjectEngineData *engine_data)
-{
- EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)engine_data;
-
- BLI_freelistN(&ped->captured_object_list);
+ EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)dd;
+ ped->need_update = false;
}
EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob)
@@ -138,26 +139,26 @@ EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob)
if (ob->type != OB_LIGHTPROBE) {
return NULL;
}
- return (EEVEE_LightProbeEngineData *)DRW_object_engine_data_get(
- ob, &draw_engine_eevee_type);
+ return (EEVEE_LightProbeEngineData *)DRW_drawdata_get(
+ &ob->id, &draw_engine_eevee_type);
}
EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob)
{
BLI_assert(ob->type == OB_LIGHTPROBE);
- return (EEVEE_LightProbeEngineData *)DRW_object_engine_data_ensure(
- ob,
+ return (EEVEE_LightProbeEngineData *)DRW_drawdata_ensure(
+ &ob->id,
&draw_engine_eevee_type,
sizeof(EEVEE_LightProbeEngineData),
eevee_lightprobe_data_init,
- eevee_lightprobe_data_free);
+ NULL);
}
/* Lamp data. */
-static void eevee_lamp_data_init(ObjectEngineData *engine_data)
+static void eevee_lamp_data_init(DrawData *dd)
{
- EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)engine_data;
+ EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)dd;
led->need_update = true;
led->prev_cube_shadow_id = -1;
}
@@ -167,17 +168,41 @@ EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob)
if (ob->type != OB_LAMP) {
return NULL;
}
- return (EEVEE_LampEngineData *)DRW_object_engine_data_get(
- ob, &draw_engine_eevee_type);
+ return (EEVEE_LampEngineData *)DRW_drawdata_get(
+ &ob->id, &draw_engine_eevee_type);
}
EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob)
{
BLI_assert(ob->type == OB_LAMP);
- return (EEVEE_LampEngineData *)DRW_object_engine_data_ensure(
- ob,
+ return (EEVEE_LampEngineData *)DRW_drawdata_ensure(
+ &ob->id,
&draw_engine_eevee_type,
sizeof(EEVEE_LampEngineData),
eevee_lamp_data_init,
NULL);
}
+
+/* World data. */
+
+static void eevee_world_data_init(DrawData *dd)
+{
+ EEVEE_WorldEngineData *wed = (EEVEE_WorldEngineData *)dd;
+ wed->dd.recalc |= 1;
+}
+
+EEVEE_WorldEngineData *EEVEE_world_data_get(World *wo)
+{
+ return (EEVEE_WorldEngineData *)DRW_drawdata_get(
+ &wo->id, &draw_engine_eevee_type);
+}
+
+EEVEE_WorldEngineData *EEVEE_world_data_ensure(World *wo)
+{
+ return (EEVEE_WorldEngineData *)DRW_drawdata_ensure(
+ &wo->id,
+ &draw_engine_eevee_type,
+ sizeof(EEVEE_WorldEngineData),
+ eevee_world_data_init,
+ NULL);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index 99adc21bf56..adbe165354a 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -123,7 +123,7 @@ static void eevee_cache_init(void *vedata)
EEVEE_volumes_cache_init(sldata, vedata);
}
-static void eevee_cache_populate(void *vedata, Object *ob)
+void EEVEE_cache_populate(void *vedata, Object *ob)
{
EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
@@ -146,7 +146,7 @@ static void eevee_cache_populate(void *vedata, Object *ob)
/* TODO: Special case for dupli objects because we cannot save the object pointer. */
}
else {
- EEVEE_lightprobes_cache_add(sldata, ob);
+ EEVEE_lightprobes_cache_add(sldata, vedata, ob);
}
}
else if (ob->type == OB_LAMP) {
@@ -282,7 +282,9 @@ static void eevee_draw_background(void *vedata)
EEVEE_subsurface_compute(sldata, vedata);
EEVEE_reflection_compute(sldata, vedata);
EEVEE_occlusion_draw_debug(sldata, vedata);
- DRW_draw_pass(psl->probe_display);
+ if (psl->probe_display) {
+ DRW_draw_pass(psl->probe_display);
+ }
EEVEE_refraction_compute(sldata, vedata);
/* Opaque refraction */
@@ -365,21 +367,35 @@ static void eevee_view_update(void *vedata)
static void eevee_id_object_update(void *UNUSED(vedata), Object *object)
{
- /* This is a bit mask of components which update is to be ignored. */
EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(object);
- if (ped != NULL && ped->engine_data.recalc != 0) {
- ped->need_full_update = true;
- ped->engine_data.recalc = 0;
+ if (ped != NULL && ped->dd.recalc != 0) {
+ ped->need_update = (ped->dd.recalc & (ID_RECALC_TRANSFORM | ID_RECALC_COPY_ON_WRITE)) != 0;
+ ped->dd.recalc = 0;
}
EEVEE_LampEngineData *led = EEVEE_lamp_data_get(object);
- if (led != NULL && led->engine_data.recalc != 0) {
+ if (led != NULL && led->dd.recalc != 0) {
led->need_update = true;
- led->engine_data.recalc = 0;
+ led->dd.recalc = 0;
}
EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(object);
- if (oedata != NULL && oedata->engine_data.recalc != 0) {
+ if (oedata != NULL && oedata->dd.recalc != 0) {
oedata->need_update = true;
- oedata->engine_data.recalc = 0;
+ oedata->dd.recalc = 0;
+ }
+}
+
+static void eevee_id_world_update(void *vedata, World *wo)
+{
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+ LightCache *lcache = stl->g_data->light_cache;
+
+ EEVEE_WorldEngineData *wedata = EEVEE_world_data_ensure(wo);
+
+ if (wedata != NULL && wedata->dd.recalc != 0) {
+ if ((lcache->flag & (LIGHTCACHE_BAKED | LIGHTCACHE_BAKING)) == 0) {
+ lcache->flag |= LIGHTCACHE_UPDATE_WORLD;
+ }
+ wedata->dd.recalc = 0;
}
}
@@ -387,6 +403,9 @@ static void eevee_id_update(void *vedata, ID *id)
{
/* Handle updates based on ID type. */
switch (GS(id->name)) {
+ case ID_WO:
+ eevee_id_world_update(vedata, (World *)id);
+ break;
case ID_OB:
eevee_id_object_update(vedata, (Object *)id);
break;
@@ -433,7 +452,7 @@ DrawEngineType draw_engine_eevee_type = {
&eevee_engine_init,
&eevee_engine_free,
&eevee_cache_init,
- &eevee_cache_populate,
+ &EEVEE_cache_populate,
&eevee_cache_finish,
&eevee_draw_background,
NULL, /* Everything is drawn in the background pass (see comment on function) */
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
new file mode 100644
index 00000000000..8ae18c8deb8
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -0,0 +1,1134 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_lightcache.c
+ * \ingroup draw_engine
+ *
+ * Eevee's indirect lighting cache.
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_global.h"
+#include "BKE_blender.h"
+
+#include "BLI_threads.h"
+
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "BKE_object.h"
+
+#include "DNA_lightprobe_types.h"
+#include "DNA_group_types.h"
+
+#include "PIL_time.h"
+
+#include "eevee_lightcache.h"
+#include "eevee_private.h"
+
+#include "../../../intern/gawain/gawain/gwn_context.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "wm_window.h"
+
+/* Rounded to nearest PowerOfTwo */
+#if defined(IRRADIANCE_SH_L2)
+#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */
+#define IRRADIANCE_SAMPLE_SIZE_Y 4 /* 3 in reality */
+#elif defined(IRRADIANCE_CUBEMAP)
+#define IRRADIANCE_SAMPLE_SIZE_X 8
+#define IRRADIANCE_SAMPLE_SIZE_Y 8
+#elif defined(IRRADIANCE_HL2)
+#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */
+#define IRRADIANCE_SAMPLE_SIZE_Y 2
+#endif
+
+#ifdef IRRADIANCE_SH_L2
+/* we need a signed format for Spherical Harmonics */
+# define IRRADIANCE_FORMAT GPU_RGBA16F
+#else
+# define IRRADIANCE_FORMAT GPU_RGBA8
+#endif
+
+#define IRRADIANCE_MAX_POOL_LAYER 256 /* OpenGL 3.3 core requirement, can be extended but it's already very big */
+#define IRRADIANCE_MAX_POOL_SIZE 1024
+#define MAX_IRRADIANCE_SAMPLES \
+ (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_X) * \
+ (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_Y)
+
+/* TODO should be replace by a more elegant alternative. */
+extern void DRW_opengl_context_enable(void);
+extern void DRW_opengl_context_disable(void);
+
+extern void DRW_opengl_render_context_enable(void *re_gl_context);
+extern void DRW_opengl_render_context_disable(void *re_gl_context);
+extern void DRW_gawain_render_context_enable(void *re_gwn_context);
+extern void DRW_gawain_render_context_disable(void *re_gwn_context);
+
+typedef struct EEVEE_LightBake {
+ Depsgraph *depsgraph;
+ ViewLayer *view_layer;
+ ViewLayer *view_layer_input;
+ LightCache *lcache;
+ Scene *scene;
+ struct Main *bmain;
+
+ LightProbe **probe; /* Current probe being rendered. */
+ GPUTexture *rt_color; /* Target cube color texture. */
+ GPUTexture *rt_depth; /* Target cube depth texture. */
+ GPUFrameBuffer *rt_fb[6]; /* Target cube framebuffers. */
+ GPUFrameBuffer *store_fb; /* Storage framebuffer. */
+ int rt_res; /* Cube render target resolution. */
+
+ /* Shared */
+ int layer; /* Target layer to store the data to. */
+ float samples_ct, invsamples_ct; /* Sample count for the convolution. */
+ float lod_factor; /* Sampling bias during convolution step. */
+ float lod_max; /* Max cubemap LOD to sample when convolving. */
+ int cube_len, grid_len; /* Number of probes to render + world probe. */
+
+ /* Irradiance grid */
+ EEVEE_LightGrid *grid; /* Current probe being rendered (UBO data). */
+ int irr_cube_res; /* Target cubemap at MIP 0. */
+ int irr_size[3]; /* Size of the irradiance texture. */
+ int total_irr_samples; /* Total for all grids */
+ int grid_sample; /* Nth sample of the current grid being rendered. */
+ int grid_sample_len; /* Total number of samples for the current grid. */
+ int grid_curr; /* Nth grid in the cache being rendered. */
+ int bounce_curr, bounce_len; /* The current light bounce being evaluated. */
+ float vis_range, vis_blur; /* Sample Visibility compression and bluring. */
+ float vis_res; /* Resolution of the Visibility shadowmap. */
+ GPUTexture *grid_prev; /* Result of previous light bounce. */
+ LightProbe **grid_prb; /* Pointer to the id.data of the probe object. */
+
+ /* Reflection probe */
+ EEVEE_LightProbe *cube; /* Current probe being rendered (UBO data). */
+ int ref_cube_res; /* Target cubemap at MIP 0. */
+ int cube_offset; /* Index of the current cube. */
+ float probemat[6][4][4]; /* ViewProjection matrix for each cube face. */
+ float texel_size, padding_size; /* Texel and padding size for the final octahedral map. */
+ float roughness; /* Roughness level of the current mipmap. */
+ LightProbe **cube_prb; /* Pointer to the id.data of the probe object. */
+
+ /* Dummy Textures */
+ struct GPUTexture *dummy_color, *dummy_depth;
+ struct GPUTexture *dummy_layer_color;
+
+ int total, done; /* to compute progress */
+ short *stop, *do_update;
+ float *progress;
+
+ bool resource_only; /* For only handling the resources. */
+ bool own_resources;
+ bool own_light_cache; /* If the lightcache was created for baking, it's first owned by the baker. */
+ int delay; /* ms. delay the start of the baking to not slowdown interactions (TODO remove) */
+
+ void *gl_context, *gwn_context; /* If running in parallel (in a separate thread), use this context. */
+} EEVEE_LightBake;
+
+/* -------------------------------------------------------------------- */
+
+/** \name Light Cache
+ * \{ */
+
+/* Return memory footprint in bytes. */
+static unsigned int eevee_lightcache_memsize_get(LightCache *lcache)
+{
+ unsigned int size = 0;
+ if (lcache->grid_tx.data) {
+ size += MEM_allocN_len(lcache->grid_tx.data);
+ }
+ if (lcache->cube_tx.data) {
+ size += MEM_allocN_len(lcache->cube_tx.data);
+ for (int mip = 0; mip < lcache->mips_len; ++mip) {
+ size += MEM_allocN_len(lcache->cube_mips[mip].data);
+ }
+ }
+ return size;
+}
+
+static int eevee_lightcache_irradiance_sample_count(LightCache *lcache)
+{
+ int total_irr_samples = 0;
+
+ for (int i = 1; i < lcache->grid_len; ++i) {
+ EEVEE_LightGrid *egrid = lcache->grid_data + i;
+ total_irr_samples += egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2];
+ }
+ return total_irr_samples;
+}
+
+void EEVEE_lightcache_info_update(SceneEEVEE *eevee)
+{
+ LightCache *lcache = eevee->light_cache;
+
+ if (lcache != NULL) {
+ char formatted_mem[15];
+ BLI_str_format_byte_unit(formatted_mem, eevee_lightcache_memsize_get(lcache), true);
+
+ int irr_samples = eevee_lightcache_irradiance_sample_count(lcache);
+
+ BLI_snprintf(eevee->light_cache_info, sizeof(eevee->light_cache_info), IFACE_("%d Ref. Cubemaps, %d Irr. Samples (%s in memory)"), lcache->cube_len - 1, irr_samples, formatted_mem);
+ }
+ else {
+ BLI_strncpy(eevee->light_cache_info, IFACE_("No light cache in this scene."), sizeof(eevee->light_cache_info));
+ }
+}
+
+static void irradiance_pool_size_get(int visibility_size, int total_samples, int r_size[3])
+{
+ /* Compute how many irradiance samples we can store per visibility sample. */
+ int irr_per_vis = (visibility_size / IRRADIANCE_SAMPLE_SIZE_X) *
+ (visibility_size / IRRADIANCE_SAMPLE_SIZE_Y);
+
+ /* The irradiance itself take one layer, hence the +1 */
+ int layer_ct = MIN2(irr_per_vis + 1, IRRADIANCE_MAX_POOL_LAYER);
+
+ int texel_ct = (int)ceilf((float)total_samples / (float)(layer_ct - 1));
+ r_size[0] = visibility_size * max_ii(1, min_ii(texel_ct, (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
+ r_size[1] = visibility_size * max_ii(1, (texel_ct / (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
+ r_size[2] = layer_ct;
+}
+
+static bool EEVEE_lightcache_validate(
+ const LightCache *light_cache,
+ const int cube_len,
+ const int cube_res,
+ const int grid_len,
+ const int irr_size[3])
+{
+ if (light_cache) {
+ /* See if we need the same amount of texture space. */
+ if ((irr_size[0] == light_cache->grid_tx.tex_size[0]) &&
+ (irr_size[1] == light_cache->grid_tx.tex_size[1]) &&
+ (irr_size[2] == light_cache->grid_tx.tex_size[2]) &&
+ (grid_len != light_cache->grid_len))
+ {
+ int mip_len = (int)(floorf(log2f(cube_res)) - MIN_CUBE_LOD_LEVEL);
+ if ((cube_res == light_cache->cube_tx.tex_size[0]) &&
+ (cube_len == light_cache->cube_tx.tex_size[2]) &&
+ (mip_len == light_cache->mips_len))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+LightCache *EEVEE_lightcache_create(
+ const int grid_len,
+ const int cube_len,
+ const int cube_size,
+ const int vis_size,
+ const int irr_size[3])
+{
+ LightCache *light_cache = MEM_callocN(sizeof(LightCache), "LightCache");
+
+ light_cache->cube_data = MEM_callocN(sizeof(EEVEE_LightProbe) * cube_len, "EEVEE_LightProbe");
+ light_cache->grid_data = MEM_callocN(sizeof(EEVEE_LightGrid) * grid_len, "EEVEE_LightGrid");
+
+ light_cache->grid_tx.tex = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2], IRRADIANCE_FORMAT, DRW_TEX_FILTER, NULL);
+ light_cache->grid_tx.tex_size[0] = irr_size[0];
+ light_cache->grid_tx.tex_size[1] = irr_size[1];
+ light_cache->grid_tx.tex_size[2] = irr_size[2];
+
+ light_cache->cube_tx.tex = DRW_texture_create_2D_array(cube_size, cube_size, cube_len, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+ light_cache->cube_tx.tex_size[0] = cube_size;
+ light_cache->cube_tx.tex_size[1] = cube_size;
+ light_cache->cube_tx.tex_size[2] = cube_len;
+
+ light_cache->mips_len = (int)(floorf(log2f(cube_size)) - MIN_CUBE_LOD_LEVEL);
+ light_cache->vis_res = vis_size;
+ light_cache->ref_res = cube_size;
+
+ light_cache->cube_mips = MEM_callocN(sizeof(LightCacheTexture) * light_cache->mips_len, "LightCacheTexture");
+
+ for (int mip = 0; mip < light_cache->mips_len; ++mip) {
+ GPU_texture_get_mipmap_size(light_cache->cube_tx.tex, mip + 1, light_cache->cube_mips[mip].tex_size);
+ }
+
+ light_cache->flag = LIGHTCACHE_UPDATE_WORLD | LIGHTCACHE_UPDATE_CUBE | LIGHTCACHE_UPDATE_GRID;
+
+ return light_cache;
+}
+
+void EEVEE_lightcache_load(LightCache *lcache)
+{
+ if (lcache->grid_tx.tex == NULL && lcache->grid_tx.data) {
+ lcache->grid_tx.tex = GPU_texture_create_nD(lcache->grid_tx.tex_size[0],
+ lcache->grid_tx.tex_size[1],
+ lcache->grid_tx.tex_size[2],
+ 2,
+ lcache->grid_tx.data,
+ IRRADIANCE_FORMAT,
+ GPU_DATA_UNSIGNED_BYTE,
+ 0,
+ false,
+ NULL);
+ GPU_texture_bind(lcache->grid_tx.tex, 0);
+ GPU_texture_filter_mode(lcache->grid_tx.tex, true);
+ GPU_texture_unbind(lcache->grid_tx.tex);
+ }
+
+ if (lcache->cube_tx.tex == NULL && lcache->cube_tx.data) {
+ lcache->cube_tx.tex = GPU_texture_create_nD(lcache->cube_tx.tex_size[0],
+ lcache->cube_tx.tex_size[1],
+ lcache->cube_tx.tex_size[2],
+ 2,
+ lcache->cube_tx.data,
+ GPU_R11F_G11F_B10F,
+ GPU_DATA_10_11_11_REV,
+ 0,
+ false,
+ NULL);
+ GPU_texture_bind(lcache->cube_tx.tex, 0);
+ GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true);
+ for (int mip = 0; mip < lcache->mips_len; ++mip) {
+ GPU_texture_add_mipmap(lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, mip + 1, lcache->cube_mips[mip].data);
+ }
+ GPU_texture_unbind(lcache->cube_tx.tex);
+ }
+}
+
+static void eevee_lightbake_readback_irradiance(LightCache *lcache)
+{
+ MEM_SAFE_FREE(lcache->grid_tx.data);
+ lcache->grid_tx.data = GPU_texture_read(lcache->grid_tx.tex, GPU_DATA_UNSIGNED_BYTE, 0);
+ lcache->grid_tx.data_type = LIGHTCACHETEX_BYTE;
+ lcache->grid_tx.components = 4;
+}
+
+static void eevee_lightbake_readback_reflections(LightCache *lcache)
+{
+ MEM_SAFE_FREE(lcache->cube_tx.data);
+ lcache->cube_tx.data = GPU_texture_read(lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, 0);
+ lcache->cube_tx.data_type = LIGHTCACHETEX_UINT;
+ lcache->cube_tx.components = 1;
+
+ for (int mip = 0; mip < lcache->mips_len; ++mip) {
+ LightCacheTexture *cube_mip = lcache->cube_mips + mip;
+ MEM_SAFE_FREE(cube_mip->data);
+ GPU_texture_get_mipmap_size(lcache->cube_tx.tex, mip + 1, cube_mip->tex_size);
+
+ cube_mip->data = GPU_texture_read(lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, mip + 1);
+ cube_mip->data_type = LIGHTCACHETEX_UINT;
+ cube_mip->components = 1;
+ }
+}
+
+void EEVEE_lightcache_free(LightCache *lcache)
+{
+ DRW_TEXTURE_FREE_SAFE(lcache->cube_tx.tex);
+ MEM_SAFE_FREE(lcache->cube_tx.data);
+ DRW_TEXTURE_FREE_SAFE(lcache->grid_tx.tex);
+ MEM_SAFE_FREE(lcache->grid_tx.data);
+
+ if (lcache->cube_mips) {
+ for (int i = 0; i < lcache->mips_len; ++i) {
+ MEM_SAFE_FREE(lcache->cube_mips[i].data);
+ }
+ MEM_SAFE_FREE(lcache->cube_mips);
+ }
+
+ MEM_SAFE_FREE(lcache->cube_data);
+ MEM_SAFE_FREE(lcache->grid_data);
+ MEM_freeN(lcache);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Light Bake Context
+ * \{ */
+
+static void eevee_lightbake_context_enable(EEVEE_LightBake *lbake)
+{
+ if (lbake->gl_context) {
+ DRW_opengl_render_context_enable(lbake->gl_context);
+ if (lbake->gwn_context == NULL) {
+ lbake->gwn_context = GWN_context_create();
+ }
+ DRW_gawain_render_context_enable(lbake->gwn_context);
+ }
+ else {
+ DRW_opengl_context_enable();
+ }
+}
+
+static void eevee_lightbake_context_disable(EEVEE_LightBake *lbake)
+{
+ if (lbake->gl_context) {
+ DRW_gawain_render_context_disable(lbake->gwn_context);
+ DRW_opengl_render_context_disable(lbake->gl_context);
+ }
+ else {
+ DRW_opengl_context_disable();
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Light Bake Job
+ * \{ */
+
+static void eevee_lightbake_count_probes(EEVEE_LightBake *lbake)
+{
+ Depsgraph *depsgraph = lbake->depsgraph;
+
+ /* At least one of each for the world */
+ lbake->grid_len = lbake->cube_len = lbake->total_irr_samples = 1;
+
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob)
+ {
+ if (!BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_FOR_RENDER)) {
+ continue;
+ }
+
+ if (ob->type == OB_LIGHTPROBE) {
+ LightProbe *prb = (LightProbe *)ob->data;
+
+ if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ lbake->total_irr_samples += prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
+ lbake->grid_len++;
+ }
+ else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
+ lbake->cube_len++;
+ }
+ }
+ }
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
+}
+
+static void eevee_lightbake_create_render_target(EEVEE_LightBake *lbake, int rt_res)
+{
+ lbake->rt_depth = DRW_texture_create_cube(rt_res, GPU_DEPTH_COMPONENT24, 0, NULL);
+ lbake->rt_color = DRW_texture_create_cube(rt_res, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+
+ for (int i = 0; i < 6; ++i) {
+ GPU_framebuffer_ensure_config(&lbake->rt_fb[i], {
+ GPU_ATTACHMENT_TEXTURE_CUBEFACE(lbake->rt_depth, i),
+ GPU_ATTACHMENT_TEXTURE_CUBEFACE(lbake->rt_color, i)
+ });
+ }
+
+ GPU_framebuffer_ensure_config(&lbake->store_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_NONE
+ });
+}
+
+static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake)
+{
+ Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph);
+ SceneEEVEE *eevee = &scene_eval->eevee;
+
+ lbake->bounce_len = eevee->gi_diffuse_bounces;
+ lbake->vis_res = eevee->gi_visibility_resolution;
+ lbake->rt_res = eevee->gi_cubemap_resolution;
+
+ irradiance_pool_size_get(lbake->vis_res, lbake->total_irr_samples, lbake->irr_size);
+
+ lbake->ref_cube_res = OCTAHEDRAL_SIZE_FROM_CUBESIZE(lbake->rt_res);
+
+ lbake->cube_prb = MEM_callocN(sizeof(LightProbe *) * lbake->cube_len, "EEVEE Cube visgroup ptr");
+ lbake->grid_prb = MEM_callocN(sizeof(LightProbe *) * lbake->grid_len, "EEVEE Grid visgroup ptr");
+
+ lbake->grid_prev = DRW_texture_create_2D_array(lbake->irr_size[0], lbake->irr_size[1], lbake->irr_size[2],
+ IRRADIANCE_FORMAT, DRW_TEX_FILTER, NULL);
+
+ /* Ensure Light Cache is ready to accept new data. If not recreate one.
+ * WARNING: All the following must be threadsafe. It's currently protected
+ * by the DRW mutex. */
+ lbake->lcache = eevee->light_cache;
+
+ /* TODO validate irradiance and reflection cache independantly... */
+ if (lbake->lcache != NULL &&
+ !EEVEE_lightcache_validate(lbake->lcache, lbake->cube_len, lbake->ref_cube_res, lbake->grid_len, lbake->irr_size))
+ {
+ eevee->light_cache = lbake->lcache = NULL;
+ }
+
+ if (lbake->lcache == NULL) {
+ lbake->lcache = EEVEE_lightcache_create(lbake->grid_len,
+ lbake->cube_len,
+ lbake->ref_cube_res,
+ lbake->vis_res,
+ lbake->irr_size);
+ lbake->lcache->flag = LIGHTCACHE_UPDATE_WORLD | LIGHTCACHE_UPDATE_CUBE | LIGHTCACHE_UPDATE_GRID;
+ lbake->lcache->vis_res = lbake->vis_res;
+ lbake->own_light_cache = true;
+
+ eevee->light_cache = lbake->lcache;
+ }
+
+ EEVEE_lightcache_load(eevee->light_cache);
+
+ lbake->lcache->flag |= LIGHTCACHE_BAKING;
+ lbake->lcache->cube_len = 1;
+}
+
+wmJob *EEVEE_lightbake_job_create(
+ struct wmWindowManager *wm, struct wmWindow *win, struct Main *bmain,
+ struct ViewLayer *view_layer, struct Scene *scene, int delay)
+{
+ EEVEE_LightBake *lbake = NULL;
+
+ /* only one render job at a time */
+ if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER))
+ return NULL;
+
+ wmJob *wm_job = WM_jobs_get(wm, win, scene, "Bake Lighting",
+ WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, WM_JOB_TYPE_LIGHT_BAKE);
+
+ /* If job exists do not recreate context and depsgraph. */
+ EEVEE_LightBake *old_lbake = (EEVEE_LightBake *)WM_jobs_customdata_get(wm_job);
+
+ if (old_lbake && (old_lbake->view_layer_input == view_layer) && (old_lbake->bmain == bmain)) {
+ lbake = MEM_callocN(sizeof(EEVEE_LightBake), "EEVEE_LightBake");
+ /* Cannot reuse depsgraph for now because we cannot get the update from the
+ * main database directly. TODO reuse depsgraph and only update positions. */
+ /* lbake->depsgraph = old_lbake->depsgraph; */
+ lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+
+ lbake->scene = scene;
+ lbake->bmain = bmain;
+ lbake->view_layer_input = view_layer;
+ lbake->gl_context = old_lbake->gl_context;
+ lbake->own_resources = true;
+ lbake->delay = delay;
+
+ old_lbake->own_resources = false;
+
+ if (old_lbake->stop != NULL) {
+ *old_lbake->stop = 1;
+ }
+ }
+ else {
+ lbake = EEVEE_lightbake_job_data_alloc(bmain, view_layer, scene, true);
+ lbake->delay = delay;
+ }
+
+ WM_jobs_customdata_set(wm_job, lbake, EEVEE_lightbake_job_data_free);
+ WM_jobs_timer(wm_job, 0.4, NC_SCENE | NA_EDITED, 0);
+ WM_jobs_callbacks(wm_job, EEVEE_lightbake_job, NULL, EEVEE_lightbake_update, EEVEE_lightbake_update);
+
+ G.is_break = false;
+
+ return wm_job;
+}
+
+/* MUST run on the main thread. */
+void *EEVEE_lightbake_job_data_alloc(
+ struct Main *bmain, struct ViewLayer *view_layer, struct Scene *scene, bool run_as_job)
+{
+ BLI_assert(BLI_thread_is_main());
+
+ EEVEE_LightBake *lbake = MEM_callocN(sizeof(EEVEE_LightBake), "EEVEE_LightBake");
+
+ lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ lbake->scene = scene;
+ lbake->bmain = bmain;
+ lbake->view_layer_input = view_layer;
+ lbake->own_resources = true;
+ lbake->own_light_cache = false;
+
+ if (run_as_job) {
+ lbake->gl_context = WM_opengl_context_create();
+ wm_window_reset_drawable();
+ }
+
+ return lbake;
+}
+
+void EEVEE_lightbake_job_data_free(void *custom_data)
+{
+ EEVEE_LightBake *lbake = (EEVEE_LightBake *)custom_data;
+
+ /* TODO reuse depsgraph. */
+ /* if (lbake->own_resources) { */
+ DEG_graph_free(lbake->depsgraph);
+ /* } */
+
+ MEM_SAFE_FREE(lbake->cube_prb);
+ MEM_SAFE_FREE(lbake->grid_prb);
+
+ MEM_freeN(lbake);
+}
+
+static void eevee_lightbake_delete_resources(EEVEE_LightBake *lbake)
+{
+ if (lbake->gl_context) {
+ DRW_opengl_render_context_enable(lbake->gl_context);
+ DRW_gawain_render_context_enable(lbake->gwn_context);
+ }
+ else if (!lbake->resource_only) {
+ DRW_opengl_context_enable();
+ }
+
+ if (lbake->own_light_cache) {
+ EEVEE_lightcache_free(lbake->lcache);
+ lbake->lcache = NULL;
+ }
+
+ DRW_TEXTURE_FREE_SAFE(lbake->rt_depth);
+ DRW_TEXTURE_FREE_SAFE(lbake->rt_color);
+ DRW_TEXTURE_FREE_SAFE(lbake->grid_prev);
+ GPU_FRAMEBUFFER_FREE_SAFE(lbake->store_fb);
+ for (int i = 0; i < 6; ++i) {
+ GPU_FRAMEBUFFER_FREE_SAFE(lbake->rt_fb[i]);
+ }
+
+ if (lbake->gwn_context) {
+ DRW_gawain_render_context_disable(lbake->gwn_context);
+ DRW_gawain_render_context_enable(lbake->gwn_context);
+ GWN_context_discard(lbake->gwn_context);
+ }
+
+ if (lbake->gl_context && lbake->own_resources) {
+ /* Delete the baking context. */
+ DRW_opengl_render_context_disable(lbake->gl_context);
+ WM_opengl_context_dispose(lbake->gl_context);
+ lbake->gwn_context = NULL;
+ lbake->gl_context = NULL;
+ }
+ else if (lbake->gl_context) {
+ DRW_opengl_render_context_disable(lbake->gl_context);
+ }
+ else if (!lbake->resource_only) {
+ DRW_opengl_context_disable();
+ }
+}
+
+/* Cache as in draw cache not light cache. */
+static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lbake)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph);
+ /* Disable all effects BUT high bitdepth shadows. */
+ scene_eval->eevee.flag &= SCE_EEVEE_SHADOW_HIGH_BITDEPTH;
+ scene_eval->eevee.taa_samples = 1;
+
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
+ stl->g_data->background_alpha = 1.0f;
+
+ /* XXX TODO remove this. This is in order to make the init functions work. */
+ DRWMatrixState dummy_mats = {{{{{0}}}}};
+ DRW_viewport_matrix_override_set_all(&dummy_mats);
+
+ if (sldata->common_ubo == NULL) {
+ sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data);
+ }
+ if (sldata->clip_ubo == NULL) {
+ sldata->clip_ubo = DRW_uniformbuffer_create(sizeof(sldata->clip_data), &sldata->clip_data);
+ }
+
+ EEVEE_effects_init(sldata, vedata, NULL);
+ EEVEE_materials_init(sldata, stl, fbl);
+ EEVEE_lights_init(sldata);
+ EEVEE_lightprobes_init(sldata, vedata);
+
+ EEVEE_effects_cache_init(sldata, vedata);
+ EEVEE_materials_cache_init(sldata, vedata);
+ EEVEE_lights_cache_init(sldata, vedata);
+ EEVEE_lightprobes_cache_init(sldata, vedata);
+
+ EEVEE_lightbake_cache_init(sldata, vedata, lbake->rt_color, lbake->rt_depth);
+
+ if (lbake->probe) {
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightProbe *prb = *lbake->probe;
+ pinfo->vis_data.collection = prb->visibility_grp;
+ pinfo->vis_data.invert = prb->flag & LIGHTPROBE_FLAG_INVERT_GROUP;
+ pinfo->vis_data.cached = false;
+ }
+ DRW_render_object_iter(vedata, NULL, lbake->depsgraph, EEVEE_render_cache);
+
+ EEVEE_materials_cache_finish(vedata);
+ EEVEE_lights_cache_finish(sldata);
+ EEVEE_lightprobes_cache_finish(sldata, vedata);
+
+ DRW_render_instance_buffer_finish();
+ DRW_hair_update();
+}
+
+static void eevee_lightbake_copy_irradiance(EEVEE_LightBake *lbake, LightCache *lcache)
+{
+ DRW_TEXTURE_FREE_SAFE(lbake->grid_prev);
+
+ /* Copy texture by reading back and reuploading it. */
+ float *tex = GPU_texture_read(lcache->grid_tx.tex, GPU_DATA_FLOAT, 0);
+ lbake->grid_prev = DRW_texture_create_2D_array(lbake->irr_size[0], lbake->irr_size[1], lbake->irr_size[2],
+ IRRADIANCE_FORMAT, DRW_TEX_FILTER, tex);
+
+ MEM_freeN(tex);
+}
+
+static void eevee_lightbake_render_world_sample(void *ved, void *user_data)
+{
+ EEVEE_Data *vedata = (EEVEE_Data *)ved;
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data;
+ Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph);
+ LightCache *lcache = scene_eval->eevee.light_cache;
+
+ /* TODO do this once for the whole bake when we have independant DRWManagers. */
+ eevee_lightbake_cache_create(vedata, lbake);
+
+ EEVEE_lightbake_render_world(sldata, vedata, lbake->rt_fb);
+ EEVEE_lightbake_filter_glossy(sldata, vedata, lbake->rt_color, lbake->store_fb, 0, 1.0f, lcache->mips_len);
+ EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake->rt_color, lbake->store_fb, 0, 1.0f);
+
+ /* Clear the cache to avoid white values in the grid. */
+ GPU_framebuffer_texture_attach(lbake->store_fb, lbake->grid_prev, 0, 0);
+ GPU_framebuffer_bind(lbake->store_fb);
+ /* Clear to 1.0f for visibility. */
+ GPU_framebuffer_clear_color(lbake->store_fb, ((float[4]){1.0f, 1.0f, 1.0f, 1.0f}));
+ DRW_draw_pass(vedata->psl->probe_grid_fill);
+
+ SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex);
+
+ /* Make a copy for later. */
+ eevee_lightbake_copy_irradiance(lbake, lcache);
+
+ lcache->cube_len = 1;
+ lcache->grid_len = lbake->grid_len;
+
+ lcache->flag |= LIGHTCACHE_CUBE_READY | LIGHTCACHE_GRID_READY;
+ lcache->flag &= ~LIGHTCACHE_UPDATE_WORLD;
+}
+
+static void cell_id_to_grid_loc(EEVEE_LightGrid *egrid, int cell_idx, int r_local_cell[3])
+{
+ /* Keep in sync with lightprobe_grid_display_vert */
+ r_local_cell[2] = cell_idx % egrid->resolution[2];
+ r_local_cell[1] = (cell_idx / egrid->resolution[2]) % egrid->resolution[1];
+ r_local_cell[0] = cell_idx / (egrid->resolution[2] * egrid->resolution[1]);
+}
+
+static void compute_cell_id(
+ EEVEE_LightGrid *egrid, LightProbe *probe,
+ int cell_idx, int *r_final_idx, int r_local_cell[3], int *r_stride)
+{
+ const int cell_count = probe->grid_resolution_x * probe->grid_resolution_y * probe->grid_resolution_z;
+
+ /* Add one for level 0 */
+ int max_lvl = (int)floorf(log2f((float)MAX3(probe->grid_resolution_x,
+ probe->grid_resolution_y,
+ probe->grid_resolution_z)));
+
+ int visited_cells = 0;
+ for (int lvl = max_lvl; lvl >= 0; --lvl) {
+ *r_stride = 1 << lvl;
+ int prev_stride = *r_stride << 1;
+ for (int i = 0; i < cell_count; ++i) {
+ *r_final_idx = i;
+ cell_id_to_grid_loc(egrid, *r_final_idx, r_local_cell);
+ if (((r_local_cell[0] % *r_stride) == 0) &&
+ ((r_local_cell[1] % *r_stride) == 0) &&
+ ((r_local_cell[2] % *r_stride) == 0))
+ {
+ if (!(((r_local_cell[0] % prev_stride) == 0) &&
+ ((r_local_cell[1] % prev_stride) == 0) &&
+ ((r_local_cell[2] % prev_stride) == 0)) ||
+ ((i == 0) && (lvl == max_lvl)))
+ {
+ if (visited_cells == cell_idx) {
+ return;
+ }
+ else {
+ visited_cells++;
+ }
+ }
+ }
+ }
+ }
+
+ BLI_assert(0);
+}
+
+static void grid_loc_to_world_loc(EEVEE_LightGrid *egrid, int local_cell[3], float r_pos[3])
+{
+ copy_v3_v3(r_pos, egrid->corner);
+ madd_v3_v3fl(r_pos, egrid->increment_x, local_cell[0]);
+ madd_v3_v3fl(r_pos, egrid->increment_y, local_cell[1]);
+ madd_v3_v3fl(r_pos, egrid->increment_z, local_cell[2]);
+}
+
+static void eevee_lightbake_render_grid_sample(void *ved, void *user_data)
+{
+ EEVEE_Data *vedata = (EEVEE_Data *)ved;
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data;
+ EEVEE_LightGrid *egrid = lbake->grid;
+ LightProbe *prb = *lbake->probe;
+ Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph);
+ LightCache *lcache = scene_eval->eevee.light_cache;
+ int grid_loc[3], sample_id, sample_offset, stride;
+ float pos[3];
+ const bool is_last_bounce_sample = ((egrid->offset + lbake->grid_sample) == (lbake->total_irr_samples - 1));
+
+ /* No bias for rendering the probe. */
+ egrid->level_bias = 1.0f;
+
+ /* Use the previous bounce for rendering this bounce. */
+ SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex);
+
+ /* TODO do this once for the whole bake when we have independant DRWManagers.
+ * Warning: Some of the things above require this. */
+ eevee_lightbake_cache_create(vedata, lbake);
+
+ /* Compute sample position */
+ compute_cell_id(egrid, prb, lbake->grid_sample, &sample_id, grid_loc, &stride);
+ sample_offset = egrid->offset + sample_id;
+
+ grid_loc_to_world_loc(egrid, grid_loc, pos);
+
+ /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */
+ common_data->spec_toggle = false;
+ common_data->prb_num_planar = 0;
+ common_data->prb_num_render_cube = 0;
+ if (lbake->bounce_curr == 0) {
+ common_data->prb_num_render_grid = 0;
+ }
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+
+ EEVEE_lightbake_render_scene(sldata, vedata, lbake->rt_fb, pos, prb->clipsta, prb->clipend);
+
+ /* Restore before filtering. */
+ SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex);
+
+ EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake->rt_color, lbake->store_fb, sample_offset, prb->intensity);
+
+ if (lbake->bounce_curr == 0) {
+ /* We only need to filter the visibility for the first bounce. */
+ EEVEE_lightbake_filter_visibility(sldata, vedata, lbake->rt_depth, lbake->store_fb, sample_offset,
+ prb->clipsta, prb->clipend, egrid->visibility_range,
+ prb->vis_blur, lbake->vis_res);
+ }
+
+ /* Update level for progressive update. */
+ if (is_last_bounce_sample) {
+ egrid->level_bias = 1.0f;
+ }
+ else if (lbake->bounce_curr == 0) {
+ egrid->level_bias = (float)(stride << 1);
+ }
+
+ /* Only run this for the last sample of a bounce. */
+ if (is_last_bounce_sample) {
+ eevee_lightbake_copy_irradiance(lbake, lcache);
+ }
+
+ /* If it is the last sample grid sample (and last bounce). */
+ if ((lbake->bounce_curr == lbake->bounce_len - 1) &&
+ (lbake->grid_curr == lbake->grid_len - 1) &&
+ (lbake->grid_sample == lbake->grid_sample_len - 1))
+ {
+ lcache->flag &= ~LIGHTCACHE_UPDATE_GRID;
+ }
+}
+
+static void eevee_lightbake_render_probe_sample(void *ved, void *user_data)
+{
+ EEVEE_Data *vedata = (EEVEE_Data *)ved;
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data;
+ Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph);
+ LightCache *lcache = scene_eval->eevee.light_cache;
+ EEVEE_LightProbe *eprobe = lbake->cube;
+ LightProbe *prb = *lbake->probe;
+
+ /* TODO do this once for the whole bake when we have independant DRWManagers. */
+ eevee_lightbake_cache_create(vedata, lbake);
+
+ /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */
+ common_data->spec_toggle = false;
+ common_data->prb_num_planar = 0;
+ common_data->prb_num_render_cube = 0;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+
+ EEVEE_lightbake_render_scene(sldata, vedata, lbake->rt_fb, eprobe->position, prb->clipsta, prb->clipend);
+ EEVEE_lightbake_filter_glossy(sldata, vedata, lbake->rt_color, lbake->store_fb, lbake->cube_offset, prb->intensity, lcache->mips_len);
+
+ lcache->cube_len += 1;
+
+ /* If it's the last probe. */
+ if (lbake->cube_offset == lbake->cube_len - 1) {
+ lcache->flag &= ~LIGHTCACHE_UPDATE_CUBE;
+ }
+}
+
+static float eevee_lightbake_grid_influence_volume(EEVEE_LightGrid *grid)
+{
+ return mat4_to_scale(grid->mat);
+}
+
+static float eevee_lightbake_cube_influence_volume(EEVEE_LightProbe *eprb)
+{
+ return mat4_to_scale(eprb->attenuationmat);
+}
+
+static bool eevee_lightbake_grid_comp(EEVEE_LightGrid *grid_a, EEVEE_LightGrid *grid_b)
+{
+ float vol_a = eevee_lightbake_grid_influence_volume(grid_a);
+ float vol_b = eevee_lightbake_grid_influence_volume(grid_b);
+ return (vol_a < vol_b);
+}
+
+static bool eevee_lightbake_cube_comp(EEVEE_LightProbe *prb_a, EEVEE_LightProbe *prb_b)
+{
+ float vol_a = eevee_lightbake_cube_influence_volume(prb_a);
+ float vol_b = eevee_lightbake_cube_influence_volume(prb_b);
+ return (vol_a < vol_b);
+}
+
+#define SORT_PROBE(elems_type, prbs, elems, elems_len, comp_fn) \
+{ \
+ bool sorted = false; \
+ while (!sorted) { \
+ sorted = true; \
+ for (int i = 0; i < (elems_len) - 1; ++i) { \
+ if ((comp_fn)((elems) + i, (elems) + i+1)) { \
+ SWAP(elems_type, (elems)[i], (elems)[i+1]); \
+ SWAP(LightProbe *, (prbs)[i], (prbs)[i+1]); \
+ sorted = false; \
+ } \
+ } \
+ } \
+}
+
+static void eevee_lightbake_gather_probes(EEVEE_LightBake *lbake)
+{
+ Depsgraph *depsgraph = lbake->depsgraph;
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ LightCache *lcache = scene_eval->eevee.light_cache;
+
+ /* At least one for the world */
+ int grid_len = 1;
+ int cube_len = 1;
+ int total_irr_samples = 1;
+
+ /* Convert all lightprobes to tight UBO data from all lightprobes in the scene.
+ * This allows a large number of probe to be precomputed (even dupli ones). */
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob)
+ {
+ if (!BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_FOR_RENDER)) {
+ continue;
+ }
+
+ if (ob->type == OB_LIGHTPROBE) {
+ LightProbe *prb = (LightProbe *)ob->data;
+
+ if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ lbake->grid_prb[grid_len] = prb;
+ EEVEE_LightGrid *egrid = &lcache->grid_data[grid_len++];
+ EEVEE_lightprobes_grid_data_from_object(ob, egrid, &total_irr_samples);
+ }
+ else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
+ lbake->cube_prb[cube_len] = prb;
+ EEVEE_LightProbe *eprobe = &lcache->cube_data[cube_len++];
+ EEVEE_lightprobes_cube_data_from_object(ob, eprobe);
+ }
+ }
+ }
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
+
+ SORT_PROBE(EEVEE_LightGrid, lbake->grid_prb + 1, lcache->grid_data + 1, lbake->grid_len - 1, eevee_lightbake_grid_comp);
+ SORT_PROBE(EEVEE_LightProbe, lbake->cube_prb + 1, lcache->cube_data + 1, lbake->cube_len - 1, eevee_lightbake_cube_comp);
+
+ lbake->total = lbake->total_irr_samples * lbake->bounce_len + lbake->cube_len;
+ lbake->done = 0;
+}
+
+void EEVEE_lightbake_update(void *custom_data)
+{
+ EEVEE_LightBake *lbake = (EEVEE_LightBake *)custom_data;
+ Scene *scene_orig = lbake->scene;
+
+ /* If a new lightcache was created, free the old one and reference the new. */
+ if (lbake->lcache && scene_orig->eevee.light_cache != lbake->lcache) {
+ if (scene_orig->eevee.light_cache != NULL) {
+ EEVEE_lightcache_free(scene_orig->eevee.light_cache);
+ }
+ scene_orig->eevee.light_cache = lbake->lcache;
+ lbake->own_light_cache = false;
+ }
+
+ EEVEE_lightcache_info_update(&lbake->scene->eevee);
+
+ DEG_id_tag_update(&scene_orig->id, DEG_TAG_COPY_ON_WRITE);
+}
+
+static bool lightbake_do_sample(EEVEE_LightBake *lbake, void (*render_callback)(void *ved, void *user_data))
+{
+ if (G.is_break == true || *lbake->stop) {
+ return false;
+ }
+
+ Depsgraph *depsgraph = lbake->depsgraph;
+
+ /* TODO: make DRW manager instanciable (and only lock on drawing) */
+ eevee_lightbake_context_enable(lbake);
+ DRW_custom_pipeline(&draw_engine_eevee_type, depsgraph, render_callback, lbake);
+ lbake->done += 1;
+ *lbake->progress = lbake->done / (float)lbake->total;
+ *lbake->do_update = 1;
+ eevee_lightbake_context_disable(lbake);
+
+ return true;
+}
+
+void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float *progress)
+{
+ EEVEE_LightBake *lbake = (EEVEE_LightBake *)custom_data;
+ Depsgraph *depsgraph = lbake->depsgraph;
+ int frame = 0; /* TODO make it user param. */
+
+ DEG_graph_relations_update(depsgraph, lbake->bmain, lbake->scene, lbake->view_layer_input);
+ DEG_evaluate_on_framechange(lbake->bmain, depsgraph, frame);
+
+ lbake->view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ lbake->stop = stop;
+ lbake->do_update = do_update;
+ lbake->progress = progress;
+
+ /* Count lightprobes */
+ eevee_lightbake_count_probes(lbake);
+
+ /* We need to create the FBOs in the right context.
+ * We cannot do it in the main thread. */
+ eevee_lightbake_context_enable(lbake);
+ eevee_lightbake_create_resources(lbake);
+ eevee_lightbake_create_render_target(lbake, lbake->rt_res);
+ eevee_lightbake_context_disable(lbake);
+
+ /* Gather all probes data */
+ eevee_lightbake_gather_probes(lbake);
+
+ LightCache *lcache = lbake->lcache;
+
+ /* HACK: Sleep to delay the first rendering operation
+ * that causes a small freeze (caused by VBO generation)
+ * because this step is locking at this moment. */
+ /* TODO remove this. */
+ if (lbake->delay) {
+ PIL_sleep_ms(lbake->delay);
+ }
+
+ /* Render world irradiance and reflection first */
+ if (lcache->flag & LIGHTCACHE_UPDATE_WORLD) {
+ lbake->probe = NULL;
+ lightbake_do_sample(lbake, eevee_lightbake_render_world_sample);
+ }
+
+ /* Render irradiance grids */
+ if (lcache->flag & LIGHTCACHE_UPDATE_GRID) {
+ for (lbake->bounce_curr = 0; lbake->bounce_curr < lbake->bounce_len; ++lbake->bounce_curr) {
+ /* Bypass world, start at 1. */
+ lbake->probe = lbake->grid_prb + 1;
+ lbake->grid = lcache->grid_data + 1;
+ for (lbake->grid_curr = 1;
+ lbake->grid_curr < lbake->grid_len;
+ ++lbake->grid_curr, ++lbake->probe, ++lbake->grid)
+ {
+ LightProbe *prb = *lbake->probe;
+ lbake->grid_sample_len = prb->grid_resolution_x *
+ prb->grid_resolution_y *
+ prb->grid_resolution_z;
+ for (lbake->grid_sample = 0;
+ lbake->grid_sample < lbake->grid_sample_len;
+ ++lbake->grid_sample)
+ {
+ lightbake_do_sample(lbake, eevee_lightbake_render_grid_sample);
+ }
+ }
+ }
+ }
+
+ /* Render reflections */
+ if (lcache->flag & LIGHTCACHE_UPDATE_CUBE) {
+ /* Bypass world, start at 1. */
+ lbake->probe = lbake->cube_prb + 1;
+ lbake->cube = lcache->cube_data + 1;
+ for (lbake->cube_offset = 1;
+ lbake->cube_offset < lbake->cube_len;
+ ++lbake->cube_offset, ++lbake->probe, ++lbake->cube)
+ {
+ lightbake_do_sample(lbake, eevee_lightbake_render_probe_sample);
+ }
+ }
+
+ /* Read the resulting lighting data to save it to file/disk. */
+ eevee_lightbake_context_enable(lbake);
+ eevee_lightbake_readback_irradiance(lcache);
+ eevee_lightbake_readback_reflections(lcache);
+ eevee_lightbake_context_disable(lbake);
+
+ lcache->flag |= LIGHTCACHE_BAKED;
+ lcache->flag &= ~LIGHTCACHE_BAKING;
+
+ eevee_lightbake_delete_resources(lbake);
+}
+
+/* This is to update the world irradiance and reflection contribution from
+ * within the viewport drawing (does not have the overhead of a full light cache rebuild.) */
+void EEVEE_lightbake_update_world_quick(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, const Scene *scene)
+{
+ LightCache *lcache = vedata->stl->g_data->light_cache;
+
+ EEVEE_LightBake lbake = {
+ .resource_only = true
+ };
+
+ /* Create resources. */
+ eevee_lightbake_create_render_target(&lbake, scene->eevee.gi_cubemap_resolution);
+
+ EEVEE_lightbake_cache_init(sldata, vedata, lbake.rt_color, lbake.rt_depth);
+
+ EEVEE_lightbake_render_world(sldata, vedata, lbake.rt_fb);
+ EEVEE_lightbake_filter_glossy(sldata, vedata, lbake.rt_color, lbake.store_fb, 0, 1.0f, lcache->mips_len);
+ EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake.rt_color, lbake.store_fb, 0, 1.0f);
+
+ /* Don't hide grids if they are already rendered. */
+ lcache->grid_len = max_ii(1, lcache->grid_len);
+ lcache->cube_len = 1;
+
+ lcache->flag |= LIGHTCACHE_CUBE_READY | LIGHTCACHE_GRID_READY;
+ lcache->flag &= ~LIGHTCACHE_UPDATE_WORLD;
+
+ eevee_lightbake_delete_resources(&lbake);
+}
+
+/** \} */
+
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h
new file mode 100644
index 00000000000..b58a0544c59
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2018, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_lightcache.h
+ * \ingroup eevee
+ */
+
+#ifndef __EEVEE_LIGHTCACHE_H__
+#define __EEVEE_LIGHTCACHE_H__
+
+#include "BLI_sys_types.h" /* for bool */
+
+struct ViewLayer;
+struct Scene;
+struct SceneEEVEE;
+struct LightCache;
+struct EEVEE_ViewLayerData;
+struct EEVEE_Data;
+struct EEVEE_LightBake;
+
+/* Light Bake */
+struct wmJob *EEVEE_lightbake_job_create(
+ struct wmWindowManager *wm, struct wmWindow *win, struct Main *bmain,
+ struct ViewLayer *view_layer, struct Scene *scene, int delay);
+void *EEVEE_lightbake_job_data_alloc(struct Main *bmain, struct ViewLayer *viewlayer, struct Scene *scene, bool run_as_job);
+void EEVEE_lightbake_job_data_free(void *custom_data);
+void EEVEE_lightbake_update(void *custom_data);
+void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float *progress);
+
+void EEVEE_lightbake_update_world_quick(struct EEVEE_ViewLayerData *sldata, struct EEVEE_Data *vedata, const Scene *scene);
+
+/* Light Cache */
+struct LightCache *EEVEE_lightcache_create(
+ const int grid_len, const int cube_len,
+ const int cube_size, const int vis_size,
+ const int irr_size[3]);
+void EEVEE_lightcache_free(struct LightCache *lcache);
+void EEVEE_lightcache_load(struct LightCache *lcache);
+void EEVEE_lightcache_info_update(struct SceneEEVEE *eevee);
+
+#endif /* __EEVEE_LIGHTCACHE_H__ */ \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index c4cf56483fa..1cb9a957211 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -20,7 +20,7 @@
*/
/** \file eevee_lightprobes.c
- * \ingroup DNA
+ * \ingroup draw_engine
*/
#include "DRW_render.h"
@@ -46,27 +46,14 @@
#include "DEG_depsgraph_query.h"
#include "eevee_engine.h"
+#include "eevee_lightcache.h"
#include "eevee_private.h"
#include "ED_screen.h"
-/* Rounded to nearest PowerOfTwo */
-#if defined(IRRADIANCE_SH_L2)
-#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */
-#define IRRADIANCE_SAMPLE_SIZE_Y 4 /* 3 in reality */
-#elif defined(IRRADIANCE_CUBEMAP)
-#define IRRADIANCE_SAMPLE_SIZE_X 8
-#define IRRADIANCE_SAMPLE_SIZE_Y 8
-#elif defined(IRRADIANCE_HL2)
-#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */
-#define IRRADIANCE_SAMPLE_SIZE_Y 2
-#endif
+#include "WM_api.h"
+#include "WM_types.h"
-#define IRRADIANCE_MAX_POOL_LAYER 256 /* OpenGL 3.3 core requirement, can be extended but it's already very big */
-#define IRRADIANCE_MAX_POOL_SIZE 1024
-#define MAX_IRRADIANCE_SAMPLES \
- (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_X) * \
- (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_Y)
#define HAMMERSLEY_SIZE 1024
static struct {
@@ -120,19 +107,30 @@ extern GlobalsUboStorage ts;
/* *********** FUNCTIONS *********** */
-static void irradiance_pool_size_get(int visibility_size, int total_samples, int r_size[3])
+/* TODO find a better way than this. This does not support dupli objects if
+ * the original object is hidden. */
+bool EEVEE_lightprobes_obj_visibility_cb(bool vis_in, void *user_data)
{
- /* Compute how many irradiance samples we can store per visibility sample. */
- int irr_per_vis = (visibility_size / IRRADIANCE_SAMPLE_SIZE_X) *
- (visibility_size / IRRADIANCE_SAMPLE_SIZE_Y);
+ EEVEE_ObjectEngineData *oed = (EEVEE_ObjectEngineData *)user_data;
+
+ /* test disabled if group is NULL */
+ if (oed->test_data->collection == NULL)
+ return vis_in;
+
+ if (oed->test_data->cached == false)
+ oed->ob_vis_dirty = true;
+
+ /* early out, don't need to compute ob_vis yet. */
+ if (vis_in == false)
+ return vis_in;
- /* The irradiance itself take one layer, hence the +1 */
- int layer_len = MIN2(irr_per_vis + 1, IRRADIANCE_MAX_POOL_LAYER);
+ if (oed->ob_vis_dirty) {
+ oed->ob_vis_dirty = false;
+ oed->ob_vis = BKE_collection_has_object_recursive(oed->test_data->collection, oed->ob);
+ oed->ob_vis = (oed->test_data->invert) ? !oed->ob_vis : oed->ob_vis;
+ }
- int texel_len = (int)ceilf((float)total_samples / (float)(layer_len - 1));
- r_size[0] = visibility_size * max_ii(1, min_ii(texel_len, (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
- r_size[1] = visibility_size * max_ii(1, (texel_len / (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
- r_size[2] = layer_len;
+ return vis_in && oed->ob_vis;
}
static struct GPUTexture *create_hammersley_sample_texture(int samples)
@@ -156,11 +154,11 @@ static struct GPUTexture *create_hammersley_sample_texture(int samples)
static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
{
+ EEVEE_TextureList *txl = vedata->txl;
+
/* XXX TODO OPTIMISATION : This is a complete waist of texture memory.
* Instead of allocating each planar probe for each viewport,
* only alloc them once using the biggest viewport resolution. */
- EEVEE_TextureList *txl = vedata->txl;
-
const float *viewport_size = DRW_viewport_size_get();
/* TODO get screen percentage from layer setting */
@@ -275,7 +273,7 @@ static void lightprobe_shaders_init(void)
datatoc_common_view_lib_glsl,
datatoc_lightprobe_cube_display_vert_glsl);
- e_data.probe_cube_display_sh = DRW_shader_create(vert_str, NULL, shader_str, NULL);
+ e_data.probe_cube_display_sh = DRW_shader_create(vert_str, NULL, shader_str, SHADER_DEFINES);
MEM_freeN(vert_str);
MEM_freeN(shader_str);
@@ -302,179 +300,65 @@ static void lightprobe_shaders_init(void)
e_data.hammersley = create_hammersley_sample_texture(HAMMERSLEY_SIZE);
}
-void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata))
+void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
- bool update_all = false;
+ EEVEE_StorageList *stl = vedata->stl;
+
const DRWContextState *draw_ctx = DRW_context_state_get();
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
- /* Shaders */
if (!e_data.probe_filter_glossy_sh) {
lightprobe_shaders_init();
}
+ if ((scene_eval->eevee.light_cache == NULL) &&
+ (sldata->fallback_lightcache == NULL)) {
+#if defined(IRRADIANCE_SH_L2)
+ int grid_res = 4;
+#elif defined(IRRADIANCE_CUBEMAP)
+ int grid_res = 8;
+#elif defined(IRRADIANCE_HL2)
+ int grid_res = 4;
+#endif
+ int cube_res = OCTAHEDRAL_SIZE_FROM_CUBESIZE(scene_eval->eevee.gi_cubemap_resolution);
+ int vis_res = scene_eval->eevee.gi_visibility_resolution;
+
+ sldata->fallback_lightcache = EEVEE_lightcache_create(1, 1, cube_res, vis_res, (int[3]){grid_res, grid_res, 1});
+ }
+
+ stl->g_data->light_cache = (scene_eval->eevee.light_cache) ? scene_eval->eevee.light_cache : sldata->fallback_lightcache;
+
+ EEVEE_lightcache_load(stl->g_data->light_cache);
+
if (!sldata->probes) {
sldata->probes = MEM_callocN(sizeof(EEVEE_LightProbesInfo), "EEVEE_LightProbesInfo");
- sldata->probes->grid_initialized = false;
sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL);
sldata->grid_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightGrid) * MAX_GRID, NULL);
sldata->planar_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_PlanarReflection) * MAX_PLANAR, NULL);
}
- /* Only start doing probes if all materials have finished compiling. */
- sldata->probes->all_materials_updated = true;
+ common_data->prb_num_planar = 0;
+ common_data->prb_num_render_cube = 1;
+ common_data->prb_num_render_grid = 1;
common_data->spec_toggle = true;
common_data->ssr_toggle = true;
common_data->sss_toggle = true;
- int prop_bounce_num = scene_eval->eevee.gi_diffuse_bounces;
- if (sldata->probes->num_bounce != prop_bounce_num) {
- sldata->probes->num_bounce = prop_bounce_num;
- update_all = true;
- }
-
- int prop_cubemap_res = scene_eval->eevee.gi_cubemap_resolution;
- if (sldata->probes->cubemap_res != prop_cubemap_res) {
- sldata->probes->cubemap_res = prop_cubemap_res;
- update_all = true;
-
- sldata->probes->target_size = prop_cubemap_res >> 1;
-
- DRW_TEXTURE_FREE_SAFE(sldata->probe_depth_rt);
- DRW_TEXTURE_FREE_SAFE(sldata->probe_rt);
- DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
- }
-
- const int visibility_res = scene_eval->eevee.gi_visibility_resolution;
- if (common_data->prb_irradiance_vis_size != visibility_res) {
- common_data->prb_irradiance_vis_size = visibility_res;
- update_all = true;
- }
-
- if (update_all) {
- sldata->probes->update_world |= PROBE_UPDATE_ALL;
- sldata->probes->updated_bounce = 0;
- sldata->probes->grid_initialized = false;
- }
-
- /* Setup Render Target Cubemap */
- if (!sldata->probe_rt) {
- sldata->probe_depth_rt = DRW_texture_create_cube(sldata->probes->target_size, GPU_DEPTH_COMPONENT24, 0, NULL);
- sldata->probe_rt = DRW_texture_create_cube(sldata->probes->target_size, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
- }
-
- for (int i = 0; i < 6; ++i) {
- GPU_framebuffer_ensure_config(&sldata->probe_face_fb[i], {
- GPU_ATTACHMENT_TEXTURE_CUBEFACE(sldata->probe_depth_rt, i),
- GPU_ATTACHMENT_TEXTURE_CUBEFACE(sldata->probe_rt, i)
- });
- }
-
/* Placeholder planar pool: used when rendering planar reflections (avoid dependency loop). */
if (!e_data.planar_pool_placeholder) {
e_data.planar_pool_placeholder = DRW_texture_create_2D_array(1, 1, 1, GPU_RGBA8, DRW_TEX_FILTER, NULL);
}
-
- if (!e_data.depth_placeholder) {
- e_data.depth_placeholder = DRW_texture_create_2D(1, 1, GPU_DEPTH_COMPONENT24, 0, NULL);
- }
- if (!e_data.depth_array_placeholder) {
- e_data.depth_array_placeholder = DRW_texture_create_2D_array(1, 1, 1, GPU_DEPTH_COMPONENT24, 0, NULL);
- }
}
-void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+/* Only init the passes usefull for rendering the light cache. */
+void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, GPUTexture *rt_color, GPUTexture *rt_depth)
{
- EEVEE_TextureList *txl = vedata->txl;
EEVEE_PassList *psl = vedata->psl;
- EEVEE_StorageList *stl = vedata->stl;
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
- /* Make sure no aditionnal visibility check runs by default. */
- pinfo->vis_data.collection = NULL;
-
- pinfo->do_cube_update = false;
- pinfo->num_cube = 1; /* at least one for the world */
- pinfo->num_grid = 1;
- pinfo->num_planar = 0;
- pinfo->total_irradiance_samples = 1;
- memset(pinfo->probes_cube_ref, 0, sizeof(pinfo->probes_cube_ref));
- memset(pinfo->probes_grid_ref, 0, sizeof(pinfo->probes_grid_ref));
- memset(pinfo->probes_planar_ref, 0, sizeof(pinfo->probes_planar_ref));
-
- {
- psl->probe_background = DRW_pass_create("World Probe Background Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
-
- struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
- DRWShadingGroup *grp = NULL;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- World *wo = scene->world;
-
- float *col = ts.colorBackground;
-
- /* LookDev */
- EEVEE_lookdev_cache_init(vedata, &grp, e_data.probe_default_studiolight_sh, psl->probe_background, wo, pinfo);
- /* END */
- if (!grp && wo) {
- col = &wo->horr;
- bool wo_sh_compiled = true;
-
- if (wo->use_nodes && wo->nodetree) {
- static float error_col[3] = {1.0f, 0.0f, 1.0f};
- static float compile_col[3] = {0.5f, 0.5f, 0.5f};
- struct GPUMaterial *gpumat = EEVEE_material_world_lightprobe_get(scene, wo);
-
- GPUMaterialStatus status = GPU_material_status(gpumat);
-
- switch (status) {
- case GPU_MAT_SUCCESS:
- grp = DRW_shgroup_material_create(gpumat, psl->probe_background);
- DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
- DRW_shgroup_call_add(grp, geom, NULL);
- wo_sh_compiled = true;
- break;
- case GPU_MAT_QUEUED:
- pinfo->all_materials_updated = false;
- wo_sh_compiled = false;
- /* TODO Bypass probe compilation. */
- col = compile_col;
- break;
- case GPU_MAT_FAILED:
- default:
- wo_sh_compiled = true;
- col = error_col;
- break;
- }
- }
-
- if (wo->update_flag != 0 || pinfo->prev_world != wo || pinfo->prev_wo_sh_compiled != wo_sh_compiled) {
- pinfo->update_world |= PROBE_UPDATE_ALL;
- pinfo->studiolight_index = 0;
- pinfo->prev_wo_sh_compiled = wo_sh_compiled;
- pinfo->prev_world = wo;
- }
- wo->update_flag = 0;
- }
- else if (pinfo->prev_world) {
- pinfo->update_world |= PROBE_UPDATE_ALL;
- pinfo->studiolight_index = 0;
- pinfo->prev_wo_sh_compiled = false;
- pinfo->prev_world = NULL;
- }
-
- /* Fallback if shader fails or if not using nodetree. */
- if (grp == NULL) {
- grp = DRW_shgroup_create(e_data.probe_default_sh, psl->probe_background);
- DRW_shgroup_uniform_vec3(grp, "color", col, 1);
- DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
- DRW_shgroup_call_add(grp, geom, NULL);
- }
- }
-
{
psl->probe_glossy_compute = DRW_pass_create("LightProbe Glossy Compute", DRW_STATE_WRITE_COLOR);
@@ -490,7 +374,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
DRW_shgroup_uniform_int(grp, "Layer", &pinfo->layer, 1);
DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
// DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter);
- DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt);
+ DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color);
DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
@@ -508,7 +392,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
#endif
DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1);
- DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt);
+ DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color);
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
DRW_shgroup_call_add(grp, geom, NULL);
@@ -527,7 +411,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
DRW_shgroup_uniform_float(grp, "nearClip", &pinfo->near_clip, 1);
DRW_shgroup_uniform_float(grp, "farClip", &pinfo->far_clip, 1);
DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
- DRW_shgroup_uniform_texture(grp, "probeDepth", sldata->probe_depth_rt);
+ DRW_shgroup_uniform_texture(grp, "probeDepth", rt_depth);
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
DRW_shgroup_call_add(grp, geom, NULL);
@@ -537,37 +421,115 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
psl->probe_grid_fill = DRW_pass_create("LightProbe Grid Floodfill", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_grid_fill_sh, psl->probe_grid_fill);
- DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &sldata->irradiance_pool);
+ DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &light_cache->grid_tx.tex);
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
DRW_shgroup_call_add(grp, geom, NULL);
}
+}
+
+void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightCache *lcache = stl->g_data->light_cache;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ pinfo->num_planar = 0;
+ pinfo->vis_data.collection = NULL;
+ pinfo->do_grid_update = false;
+ pinfo->do_cube_update = false;
{
+ psl->probe_background = DRW_pass_create("World Probe Background Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
+
+ struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
+ DRWShadingGroup *grp = NULL;
+
+ Scene *scene = draw_ctx->scene;
+ World *wo = scene->world;
+
+ float *col = ts.colorBackground;
+
+ /* LookDev */
+ EEVEE_lookdev_cache_init(vedata, &grp, e_data.probe_default_studiolight_sh, psl->probe_background, wo, pinfo);
+ /* END */
+ if (!grp && wo) {
+ col = &wo->horr;
+
+ if (wo->use_nodes && wo->nodetree) {
+ static float error_col[3] = {1.0f, 0.0f, 1.0f};
+ struct GPUMaterial *gpumat = EEVEE_material_world_lightprobe_get(scene, wo);
+
+ GPUMaterialStatus status = GPU_material_status(gpumat);
+
+ switch (status) {
+ case GPU_MAT_SUCCESS:
+ grp = DRW_shgroup_material_create(gpumat, psl->probe_background);
+ DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
+ DRW_shgroup_call_add(grp, geom, NULL);
+ break;
+ default:
+ col = error_col;
+ break;
+ }
+ }
+ }
+
+ /* Fallback if shader fails or if not using nodetree. */
+ if (grp == NULL) {
+ grp = DRW_shgroup_create(e_data.probe_default_sh, psl->probe_background);
+ DRW_shgroup_uniform_vec3(grp, "color", col, 1);
+ DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
+ DRW_shgroup_call_add(grp, geom, NULL);
+ }
+ }
+
+ if (DRW_state_draw_support()) {
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
psl->probe_display = DRW_pass_create("LightProbe Display", state);
- DRW_shgroup_instance_format(e_data.format_probe_display_cube, {
- {"probe_id", DRW_ATTRIB_INT, 1},
- {"probe_location", DRW_ATTRIB_FLOAT, 3},
- {"sphere_size", DRW_ATTRIB_FLOAT, 1},
- });
+ /* Cube Display */
+ if (scene_eval->eevee.flag & SCE_EEVEE_SHOW_CUBEMAPS && lcache->cube_len > 1) {
+ int cube_len = lcache->cube_len - 1; /* don't count the world. */
+ DRWShadingGroup *grp = DRW_shgroup_empty_tri_batch_create(e_data.probe_cube_display_sh,
+ psl->probe_display, cube_len * 2);
+ DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex);
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
+ DRW_shgroup_uniform_float_copy(grp, "sphere_size", scene_eval->eevee.gi_cubemap_draw_size * 0.5f);
+ }
- DRWShadingGroup *grp = DRW_shgroup_instance_create(
- e_data.probe_cube_display_sh,
- psl->probe_display,
- DRW_cache_sphere_get(),
- e_data.format_probe_display_cube);
- stl->g_data->cube_display_shgrp = grp;
- DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &sldata->probe_pool);
- DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ /* Grid Display */
+ if (scene_eval->eevee.flag & SCE_EEVEE_SHOW_IRRADIANCE) {
+ EEVEE_LightGrid *egrid = lcache->grid_data + 1;
+ for (int p = 1; p < lcache->grid_len; ++p, egrid++) {
+ DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.probe_grid_display_sh, psl->probe_display);
+ DRW_shgroup_uniform_int(shgrp, "offset", &egrid->offset, 1);
+ DRW_shgroup_uniform_ivec3(shgrp, "grid_resolution", egrid->resolution, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "corner", egrid->corner, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "increment_x", egrid->increment_x, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "increment_y", egrid->increment_y, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "increment_z", egrid->increment_z, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
+ DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &lcache->grid_tx.tex);
+ DRW_shgroup_uniform_float_copy(shgrp, "sphere_size", scene_eval->eevee.gi_irradiance_draw_size * 0.5f);
+ int tri_count = egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2] * 2;
+ DRW_shgroup_call_procedural_triangles_add(shgrp, tri_count, NULL);
+ }
+ }
+ /* Planar Display */
DRW_shgroup_instance_format(e_data.format_probe_display_planar, {
{"probe_id", DRW_ATTRIB_INT, 1},
{"probe_mat", DRW_ATTRIB_FLOAT, 16},
});
- grp = DRW_shgroup_instance_create(
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
e_data.probe_planar_display_sh,
psl->probe_display,
DRW_cache_quad_get(),
@@ -575,6 +537,9 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
stl->g_data->planar_display_shgrp = grp;
DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &txl->planar_pool);
}
+ else {
+ stl->g_data->planar_display_shgrp = NULL;
+ }
{
psl->probe_planar_downsample_ps = DRW_pass_create("LightProbe Planar Downsample", DRW_STATE_WRITE_COLOR);
@@ -586,514 +551,560 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
}
}
-bool EEVEE_lightprobes_obj_visibility_cb(bool vis_in, void *user_data)
+static bool eevee_lightprobes_culling_test(Object *ob)
{
- EEVEE_ObjectEngineData *oed = (EEVEE_ObjectEngineData *)user_data;
-
- /* test disabled if group is NULL */
- if (oed->test_data->collection == NULL)
- return vis_in;
-
- if (oed->test_data->cached == false)
- oed->ob_vis_dirty = true;
-
- /* early out, don't need to compute ob_vis yet. */
- if (vis_in == false)
- return vis_in;
+ LightProbe *probe = (LightProbe *)ob->data;
- if (oed->ob_vis_dirty) {
- oed->ob_vis_dirty = false;
- oed->ob_vis = BKE_collection_has_object_recursive(oed->test_data->collection, oed->ob);
- oed->ob_vis = (oed->test_data->invert) ? !oed->ob_vis : oed->ob_vis;
+ switch (probe->type) {
+ case LIGHTPROBE_TYPE_PLANAR:
+ {
+ /* See if this planar probe is inside the view frustum. If not, no need to update it. */
+ /* NOTE: this could be bypassed if we want feedback loop mirrors for rendering. */
+ BoundBox bbox; float tmp[4][4];
+ const float min[3] = {-1.0f, -1.0f, -1.0f};
+ const float max[3] = { 1.0f, 1.0f, 1.0f};
+ BKE_boundbox_init_from_minmax(&bbox, min, max);
+
+ copy_m4_m4(tmp, ob->obmat);
+ normalize_v3(tmp[2]);
+ mul_v3_fl(tmp[2], probe->distinf);
+
+ for (int v = 0; v < 8; ++v) {
+ mul_m4_v3(tmp, bbox.vec[v]);
+ }
+ return DRW_culling_box_test(&bbox);
+ }
+ case LIGHTPROBE_TYPE_CUBE:
+ return true; /* TODO */
+ case LIGHTPROBE_TYPE_GRID:
+ return true; /* TODO */
}
-
- return vis_in && oed->ob_vis;
+ BLI_assert(0);
+ return true;
}
-void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
+void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *ob)
{
EEVEE_LightProbesInfo *pinfo = sldata->probes;
LightProbe *probe = (LightProbe *)ob->data;
if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= MAX_PROBE) ||
(probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= MAX_PROBE) ||
- (probe->type == LIGHTPROBE_TYPE_PLANAR && pinfo->num_grid >= MAX_PLANAR))
+ (probe->type == LIGHTPROBE_TYPE_PLANAR && pinfo->num_planar >= MAX_PLANAR))
{
- printf("Too much probes in the scene !!!\n");
+ printf("Too many probes in the view !!!\n");
return;
}
if (probe->type == LIGHTPROBE_TYPE_PLANAR) {
- /* See if this planar probe is inside the view frustum. If not, no need to update it. */
- /* NOTE: this could be bypassed if we want feedback loop mirrors for rendering. */
- BoundBox bbox; float tmp[4][4];
- const float min[3] = {-1.0f, -1.0f, -1.0f};
- const float max[3] = { 1.0f, 1.0f, 1.0f};
- BKE_boundbox_init_from_minmax(&bbox, min, max);
-
- copy_m4_m4(tmp, ob->obmat);
- normalize_v3(tmp[2]);
- mul_v3_fl(tmp[2], probe->distinf);
-
- for (int v = 0; v < 8; ++v) {
- mul_m4_v3(tmp, bbox.vec[v]);
- }
- if (!DRW_culling_box_test(&bbox)) {
+ if (!eevee_lightprobes_culling_test(ob)) {
return; /* Culled */
}
+ EEVEE_lightprobes_planar_data_from_object(ob,
+ &pinfo->planar_data[pinfo->num_planar],
+ &pinfo->planar_vis_tests[pinfo->num_planar]);
+ /* Debug Display */
+ DRWShadingGroup *grp = vedata->stl->g_data->planar_display_shgrp;
+ if (grp && (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
+ DRW_shgroup_call_dynamic_add(grp, &pinfo->num_planar, ob->obmat);
+ }
+
+ pinfo->num_planar++;
}
+ else {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+ if (ped->need_update) {
+ if (probe->type == LIGHTPROBE_TYPE_GRID) {
+ pinfo->do_grid_update = true;
+ }
+ else {
+ pinfo->do_cube_update = true;
+ }
+ ped->need_update = false;
+ }
+ }
+}
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+void EEVEE_lightprobes_grid_data_from_object(Object *ob, EEVEE_LightGrid *egrid, int *offset)
+{
+ LightProbe *probe = (LightProbe *)ob->data;
- ped->num_cell = probe->grid_resolution_x * probe->grid_resolution_y * probe->grid_resolution_z;
+ copy_v3_v3_int(egrid->resolution, &probe->grid_resolution_x);
+
+ /* Save current offset and advance it for the next grid. */
+ egrid->offset = *offset;
+ *offset += egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2];
+
+ /* Add one for level 0 */
+ float fac = 1.0f / max_ff(1e-8f, probe->falloff);
+ egrid->attenuation_scale = fac / max_ff(1e-8f, probe->distinf);
+ egrid->attenuation_bias = fac;
+
+ /* Update transforms */
+ float cell_dim[3], half_cell_dim[3];
+ cell_dim[0] = 2.0f / egrid->resolution[0];
+ cell_dim[1] = 2.0f / egrid->resolution[1];
+ cell_dim[2] = 2.0f / egrid->resolution[2];
+
+ mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f);
+
+ /* Matrix converting world space to cell ranges. */
+ invert_m4_m4(egrid->mat, ob->obmat);
+
+ /* First cell. */
+ copy_v3_fl(egrid->corner, -1.0f);
+ add_v3_v3(egrid->corner, half_cell_dim);
+ mul_m4_v3(ob->obmat, egrid->corner);
+
+ /* Opposite neighbor cell. */
+ copy_v3_fl3(egrid->increment_x, cell_dim[0], 0.0f, 0.0f);
+ add_v3_v3(egrid->increment_x, half_cell_dim);
+ add_v3_fl(egrid->increment_x, -1.0f);
+ mul_m4_v3(ob->obmat, egrid->increment_x);
+ sub_v3_v3(egrid->increment_x, egrid->corner);
+
+ copy_v3_fl3(egrid->increment_y, 0.0f, cell_dim[1], 0.0f);
+ add_v3_v3(egrid->increment_y, half_cell_dim);
+ add_v3_fl(egrid->increment_y, -1.0f);
+ mul_m4_v3(ob->obmat, egrid->increment_y);
+ sub_v3_v3(egrid->increment_y, egrid->corner);
+
+ copy_v3_fl3(egrid->increment_z, 0.0f, 0.0f, cell_dim[2]);
+ add_v3_v3(egrid->increment_z, half_cell_dim);
+ add_v3_fl(egrid->increment_z, -1.0f);
+ mul_m4_v3(ob->obmat, egrid->increment_z);
+ sub_v3_v3(egrid->increment_z, egrid->corner);
+
+ /* Visibility bias */
+ egrid->visibility_bias = 0.05f * probe->vis_bias;
+ egrid->visibility_bleed = probe->vis_bleedbias;
+ egrid->visibility_range = 1.0f + sqrtf(max_fff(len_squared_v3(egrid->increment_x),
+ len_squared_v3(egrid->increment_y),
+ len_squared_v3(egrid->increment_z)));
+}
- if ((probe->type == LIGHTPROBE_TYPE_GRID) &&
- ((pinfo->total_irradiance_samples + ped->num_cell) >= MAX_IRRADIANCE_SAMPLES))
- {
- printf("Too much grid samples !!!\n");
- return;
- }
+void EEVEE_lightprobes_cube_data_from_object(Object *ob, EEVEE_LightProbe *eprobe)
+{
+ LightProbe *probe = (LightProbe *)ob->data;
- if (ped->need_full_update) {
- ped->need_full_update = false;
+ /* Update transforms */
+ copy_v3_v3(eprobe->position, ob->obmat[3]);
- ped->need_update = true;
- ped->probe_id = 0;
- if (probe->type == LIGHTPROBE_TYPE_GRID) {
- ped->updated_cells = 0;
- ped->updated_lvl = 0;
- pinfo->updated_bounce = 0;
- pinfo->grid_initialized = false;
- }
- }
+ /* Attenuation */
+ eprobe->attenuation_type = probe->attenuation_type;
+ eprobe->attenuation_fac = 1.0f / max_ff(1e-8f, probe->falloff);
- if (pinfo->update_world) {
- ped->need_update = true;
- ped->updated_cells = 0;
- ped->updated_lvl = 0;
- ped->probe_id = 0;
- }
+ unit_m4(eprobe->attenuationmat);
+ scale_m4_fl(eprobe->attenuationmat, probe->distinf);
+ mul_m4_m4m4(eprobe->attenuationmat, ob->obmat, eprobe->attenuationmat);
+ invert_m4(eprobe->attenuationmat);
- pinfo->do_cube_update |= ped->need_update;
+ /* Parallax */
+ unit_m4(eprobe->parallaxmat);
- switch (probe->type) {
- case LIGHTPROBE_TYPE_CUBE:
- pinfo->probes_cube_ref[pinfo->num_cube] = ob;
- pinfo->num_cube++;
- break;
- case LIGHTPROBE_TYPE_PLANAR:
- pinfo->probes_planar_ref[pinfo->num_planar] = ob;
- pinfo->num_planar++;
- break;
- case LIGHTPROBE_TYPE_GRID:
- pinfo->probes_grid_ref[pinfo->num_grid] = ob;
- pinfo->num_grid++;
- pinfo->total_irradiance_samples += ped->num_cell;
- break;
+ if ((probe->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) {
+ eprobe->parallax_type = probe->parallax_type;
+ scale_m4_fl(eprobe->parallaxmat, probe->distpar);
+ }
+ else {
+ eprobe->parallax_type = probe->attenuation_type;
+ scale_m4_fl(eprobe->parallaxmat, probe->distinf);
}
+
+ mul_m4_m4m4(eprobe->parallaxmat, ob->obmat, eprobe->parallaxmat);
+ invert_m4(eprobe->parallaxmat);
+}
+
+void EEVEE_lightprobes_planar_data_from_object(Object *ob, EEVEE_PlanarReflection *eplanar, EEVEE_LightProbeVisTest *vis_test)
+{
+ LightProbe *probe = (LightProbe *)ob->data;
+ float normat[4][4], imat[4][4];
+
+ vis_test->collection = probe->visibility_grp;
+ vis_test->invert = probe->flag & LIGHTPROBE_FLAG_INVERT_GROUP;
+ vis_test->cached = false;
+
+ /* Computing mtx : matrix that mirror position around object's XY plane. */
+ normalize_m4_m4(normat, ob->obmat); /* object > world */
+ invert_m4_m4(imat, normat); /* world > object */
+ /* XY reflection plane */
+ imat[0][2] = -imat[0][2];
+ imat[1][2] = -imat[1][2];
+ imat[2][2] = -imat[2][2];
+ imat[3][2] = -imat[3][2]; /* world > object > mirrored obj */
+ mul_m4_m4m4(eplanar->mtx, normat, imat); /* world > object > mirrored obj > world */
+
+ /* Compute clip plane equation / normal. */
+ copy_v3_v3(eplanar->plane_equation, ob->obmat[2]);
+ normalize_v3(eplanar->plane_equation); /* plane normal */
+ eplanar->plane_equation[3] = -dot_v3v3(eplanar->plane_equation, ob->obmat[3]);
+ eplanar->clipsta = probe->clipsta;
+
+ /* Compute XY clip planes. */
+ normalize_v3_v3(eplanar->clip_vec_x, ob->obmat[0]);
+ normalize_v3_v3(eplanar->clip_vec_y, ob->obmat[1]);
+
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+ vec[0] = 1.0f; vec[1] = 0.0f; vec[2] = 0.0f;
+ mul_m4_v3(ob->obmat, vec); /* Point on the edge */
+ eplanar->clip_edge_x_pos = dot_v3v3(eplanar->clip_vec_x, vec);
+
+ vec[0] = 0.0f; vec[1] = 1.0f; vec[2] = 0.0f;
+ mul_m4_v3(ob->obmat, vec); /* Point on the edge */
+ eplanar->clip_edge_y_pos = dot_v3v3(eplanar->clip_vec_y, vec);
+
+ vec[0] = -1.0f; vec[1] = 0.0f; vec[2] = 0.0f;
+ mul_m4_v3(ob->obmat, vec); /* Point on the edge */
+ eplanar->clip_edge_x_neg = dot_v3v3(eplanar->clip_vec_x, vec);
+
+ vec[0] = 0.0f; vec[1] = -1.0f; vec[2] = 0.0f;
+ mul_m4_v3(ob->obmat, vec); /* Point on the edge */
+ eplanar->clip_edge_y_neg = dot_v3v3(eplanar->clip_vec_y, vec);
+
+ /* Facing factors */
+ float max_angle = max_ff(1e-2f, probe->falloff) * M_PI * 0.5f;
+ float min_angle = 0.0f;
+ eplanar->facing_scale = 1.0f / max_ff(1e-8f, cosf(min_angle) - cosf(max_angle));
+ eplanar->facing_bias = -min_ff(1.0f - 1e-8f, cosf(max_angle)) * eplanar->facing_scale;
+
+ /* Distance factors */
+ float max_dist = probe->distinf;
+ float min_dist = min_ff(1.0f - 1e-8f, 1.0f - probe->falloff) * probe->distinf;
+ eplanar->attenuation_scale = -1.0f / max_ff(1e-8f, max_dist - min_dist);
+ eplanar->attenuation_bias = max_dist * -eplanar->attenuation_scale;
}
-/* TODO find a nice name to push it to math_matrix.c */
-static void scale_m4_v3(float R[4][4], float v[3])
+static void lightbake_planar_compute_render_matrices(
+ EEVEE_PlanarReflection *eplanar, DRWMatrixState *r_matstate, const float viewmat[4][4])
{
- for (int i = 0; i < 4; ++i)
- mul_v3_v3(R[i], v);
+ /* Reflect Camera Matrix. */
+ mul_m4_m4m4(r_matstate->viewmat, viewmat, eplanar->mtx);
+ /* TODO FOV margin */
+ /* Temporal sampling jitter should be already applied to the DRW_MAT_WIN. */
+ DRW_viewport_matrix_get(r_matstate->winmat, DRW_MAT_WIN);
+ /* Apply Projection Matrix. */
+ mul_m4_m4m4(r_matstate->persmat, r_matstate->winmat, r_matstate->viewmat);
+
+ /* This is the matrix used to reconstruct texture coordinates.
+ * We use the original view matrix because it does not create
+ * visual artifacts if receiver is not perfectly aligned with
+ * the planar reflection probe. */
+ mul_m4_m4m4(eplanar->reflectionmat, r_matstate->winmat, viewmat); /* TODO FOV margin */
+ /* Convert from [-1, 1] to [0, 1] (NDC to Texture coord). */
+ mul_m4_m4m4(eplanar->reflectionmat, texcomat, eplanar->reflectionmat);
}
-static void EEVEE_planar_reflections_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl)
+static void eevee_lightprobes_extract_from_cache(EEVEE_LightProbesInfo *pinfo, LightCache *lcache)
{
+ /* copy the entire cache for now (up to MAX_PROBE) */
+ /* TODO Frutum cull to only add visible probes. */
+ memcpy(pinfo->probe_data, lcache->cube_data, sizeof(EEVEE_LightProbe) * max_ii(1, min_ii(lcache->cube_len, MAX_PROBE)));
+ /* TODO compute the max number of grid based on sample count. */
+ memcpy(pinfo->grid_data, lcache->grid_data, sizeof(EEVEE_LightGrid) * max_ii(1, min_ii(lcache->grid_len, MAX_GRID)));
+}
+
+void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ LightCache *light_cache = stl->g_data->light_cache;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
- Object *ob;
- for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) {
- LightProbe *probe = (LightProbe *)ob->data;
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+ eevee_lightprobes_extract_from_cache(sldata->probes, light_cache);
- ped->probe_id = i;
+ DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data);
+ DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
- /* Debug Display */
- if (DRW_state_draw_support() &&
- (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA))
- {
- DRW_shgroup_call_dynamic_add(stl->g_data->planar_display_shgrp, &ped->probe_id, ob->obmat);
+ /* For shading, save max level of the octahedron map */
+ sldata->common_data.prb_lod_cube_max = (float)light_cache->mips_len - 1.0f;
+ sldata->common_data.prb_lod_planar_max = (float)MAX_PLANAR_LOD_LEVEL;
+ sldata->common_data.prb_irradiance_vis_size = light_cache->vis_res;
+ sldata->common_data.prb_num_render_cube = max_ii(1, light_cache->cube_len);
+ sldata->common_data.prb_num_render_grid = max_ii(1, light_cache->grid_len);
+ sldata->common_data.prb_num_planar = pinfo->num_planar;
+
+ if (pinfo->num_planar != pinfo->cache_num_planar) {
+ DRW_TEXTURE_FREE_SAFE(vedata->txl->planar_pool);
+ DRW_TEXTURE_FREE_SAFE(vedata->txl->planar_depth);
+ pinfo->cache_num_planar = pinfo->num_planar;
+ }
+ planar_pool_ensure_alloc(vedata, pinfo->num_planar);
+
+ /* If lightcache auto-update is enable we tag the relevant part
+ * of the cache to update and fire up a baking job. */
+ if (!DRW_state_is_image_render() && !DRW_state_is_opengl_render() &&
+ (pinfo->do_grid_update || pinfo->do_cube_update))
+ {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ BLI_assert(draw_ctx->evil_C);
+
+ if (draw_ctx->scene->eevee.flag & SCE_EEVEE_GI_AUTOBAKE) {
+ Scene *scene_orig = DEG_get_input_scene(draw_ctx->depsgraph);
+ if (scene_orig->eevee.light_cache != NULL) {
+ if (pinfo->do_grid_update) {
+ scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_GRID;
+ }
+ /* If we update grid we need to update the cubemaps too.
+ * So always refresh cubemaps. */
+ scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_CUBE;
+ }
+
+ /* Use a notifier to trigger the operator after drawing. */
+ WM_event_add_notifier(draw_ctx->evil_C, NC_LIGHTPROBE, scene_orig);
}
}
}
-static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata)
+/* -------------------------------------------------------------------- */
+
+/** \name Rendering
+ * \{ */
+
+typedef struct EEVEE_BakeRenderData{
+ EEVEE_Data *vedata;
+ EEVEE_ViewLayerData *sldata;
+ struct GPUFrameBuffer **face_fb; /* should contain 6 framebuffer */
+} EEVEE_BakeRenderData;
+
+static void render_cubemap(
+ void (*callback)(int face, EEVEE_BakeRenderData *user_data), EEVEE_BakeRenderData *user_data,
+ const float pos[3], float clipsta, float clipend)
{
- EEVEE_LightProbesInfo *pinfo = sldata->probes;
- Object *ob;
- float mtx[4][4], normat[4][4], imat[4][4], rangemat[4][4];
+ DRWMatrixState matstate;
- float viewmat[4][4];
- DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
+ /* Move to capture position */
+ float posmat[4][4];
+ unit_m4(posmat);
+ negate_v3_v3(posmat[3], pos);
- zero_m4(rangemat);
- rangemat[0][0] = rangemat[1][1] = rangemat[2][2] = 0.5f;
- rangemat[3][0] = rangemat[3][1] = rangemat[3][2] = 0.5f;
- rangemat[3][3] = 1.0f;
+ perspective_m4(matstate.winmat, -clipsta, clipsta, -clipsta, clipsta, clipsta, clipend);
+ invert_m4_m4(matstate.wininv, matstate.winmat);
- /* PLANAR REFLECTION */
- for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) {
- LightProbe *probe = (LightProbe *)ob->data;
- EEVEE_PlanarReflection *eplanar = &pinfo->planar_data[i];
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
- /* Computing mtx : matrix that mirror position around object's XY plane. */
- normalize_m4_m4(normat, ob->obmat); /* object > world */
- invert_m4_m4(imat, normat); /* world > object */
- float reflect[3] = {1.0f, 1.0f, -1.0f}; /* XY reflection plane */
- scale_m4_v3(imat, reflect); /* world > object > mirrored obj */
- mul_m4_m4m4(mtx, normat, imat); /* world > object > mirrored obj > world */
- /* Reflect Camera Matrix. */
- mul_m4_m4m4(ped->mats.mat[DRW_MAT_VIEW], viewmat, mtx);
- /* TODO FOV margin */
- /* Temporal sampling jitter should be already applied to the DRW_MAT_WIN. */
- DRW_viewport_matrix_get(ped->mats.mat[DRW_MAT_WIN], DRW_MAT_WIN);
- /* Apply Projection Matrix. */
- mul_m4_m4m4(ped->mats.mat[DRW_MAT_PERS], ped->mats.mat[DRW_MAT_WIN], ped->mats.mat[DRW_MAT_VIEW]);
- /* This is the matrix used to reconstruct texture coordinates.
- * We use the original view matrix because it does not create
- * visual artifacts if receiver is not perfectly aligned with
- * the planar reflection probe. */
- mul_m4_m4m4(eplanar->reflectionmat, ped->mats.mat[DRW_MAT_WIN], viewmat); /* TODO FOV margin */
- /* Convert from [-1, 1] to [0, 1] (NDC to Texture coord). */
- mul_m4_m4m4(eplanar->reflectionmat, rangemat, eplanar->reflectionmat);
-
- /* Compute clip plane equation / normal. */
- float refpoint[3];
- copy_v3_v3(eplanar->plane_equation, ob->obmat[2]);
- normalize_v3(eplanar->plane_equation); /* plane normal */
- eplanar->plane_equation[3] = -dot_v3v3(eplanar->plane_equation, ob->obmat[3]);
-
- /* Compute offset plane equation (fix missing texels near reflection plane). */
- copy_v3_v3(ped->planer_eq_offset, eplanar->plane_equation);
- mul_v3_v3fl(refpoint, eplanar->plane_equation, -probe->clipsta);
- add_v3_v3(refpoint, ob->obmat[3]);
- ped->planer_eq_offset[3] = -dot_v3v3(eplanar->plane_equation, refpoint);
-
- /* Compute XY clip planes. */
- normalize_v3_v3(eplanar->clip_vec_x, ob->obmat[0]);
- normalize_v3_v3(eplanar->clip_vec_y, ob->obmat[1]);
-
- float vec[3] = {0.0f, 0.0f, 0.0f};
- vec[0] = 1.0f; vec[1] = 0.0f; vec[2] = 0.0f;
- mul_m4_v3(ob->obmat, vec); /* Point on the edge */
- eplanar->clip_edge_x_pos = dot_v3v3(eplanar->clip_vec_x, vec);
-
- vec[0] = 0.0f; vec[1] = 1.0f; vec[2] = 0.0f;
- mul_m4_v3(ob->obmat, vec); /* Point on the edge */
- eplanar->clip_edge_y_pos = dot_v3v3(eplanar->clip_vec_y, vec);
-
- vec[0] = -1.0f; vec[1] = 0.0f; vec[2] = 0.0f;
- mul_m4_v3(ob->obmat, vec); /* Point on the edge */
- eplanar->clip_edge_x_neg = dot_v3v3(eplanar->clip_vec_x, vec);
-
- vec[0] = 0.0f; vec[1] = -1.0f; vec[2] = 0.0f;
- mul_m4_v3(ob->obmat, vec); /* Point on the edge */
- eplanar->clip_edge_y_neg = dot_v3v3(eplanar->clip_vec_y, vec);
-
- /* Facing factors */
- float max_angle = max_ff(1e-2f, probe->falloff) * M_PI * 0.5f;
- float min_angle = 0.0f;
- eplanar->facing_scale = 1.0f / max_ff(1e-8f, cosf(min_angle) - cosf(max_angle));
- eplanar->facing_bias = -min_ff(1.0f - 1e-8f, cosf(max_angle)) * eplanar->facing_scale;
-
- /* Distance factors */
- float max_dist = probe->distinf;
- float min_dist = min_ff(1.0f - 1e-8f, 1.0f - probe->falloff) * probe->distinf;
- eplanar->attenuation_scale = -1.0f / max_ff(1e-8f, max_dist - min_dist);
- eplanar->attenuation_bias = max_dist * -eplanar->attenuation_scale;
+ /* 1 - Render to each cubeface individually.
+ * We do this instead of using geometry shader because a) it's faster,
+ * b) it's easier than fixing the nodetree shaders (for view dependant effects). */
+ for (int i = 0; i < 6; ++i) {
+ /* Setup custom matrices */
+ mul_m4_m4m4(matstate.viewmat, cubefacemat[i], posmat);
+ mul_m4_m4m4(matstate.persmat, matstate.winmat, matstate.viewmat);
+ invert_m4_m4(matstate.persinv, matstate.persmat);
+ invert_m4_m4(matstate.viewinv, matstate.viewmat);
+ invert_m4_m4(matstate.wininv, matstate.winmat);
+
+ DRW_viewport_matrix_override_set_all(&matstate);
+
+ callback(i, user_data);
}
}
-static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl, EEVEE_StorageList *stl)
+static void render_reflections(
+ void (*callback)(int face, EEVEE_BakeRenderData *user_data), EEVEE_BakeRenderData *user_data,
+ EEVEE_PlanarReflection *planar_data, int ref_count)
{
- EEVEE_LightProbesInfo *pinfo = sldata->probes;
- Object *ob;
+ DRWMatrixState matstate;
- /* CUBE REFLECTION */
- for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
- LightProbe *probe = (LightProbe *)ob->data;
- EEVEE_LightProbe *eprobe = &pinfo->probe_data[i];
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+ float original_viewmat[4][4];
+ DRW_viewport_matrix_get(original_viewmat, DRW_MAT_VIEW);
- /* Update transforms */
- copy_v3_v3(eprobe->position, ob->obmat[3]);
+ for (int i = 0; i < ref_count; ++i) {
+ /* Setup custom matrices */
+ lightbake_planar_compute_render_matrices(planar_data + i, &matstate, original_viewmat);
+ invert_m4_m4(matstate.persinv, matstate.persmat);
+ invert_m4_m4(matstate.viewinv, matstate.viewmat);
+ invert_m4_m4(matstate.wininv, matstate.winmat);
+ DRW_viewport_matrix_override_set_all(&matstate);
- /* Attenuation */
- eprobe->attenuation_type = probe->attenuation_type;
- eprobe->attenuation_fac = 1.0f / max_ff(1e-8f, probe->falloff);
+ callback(i, user_data);
+ }
+}
- unit_m4(eprobe->attenuationmat);
- scale_m4_fl(eprobe->attenuationmat, probe->distinf);
- mul_m4_m4m4(eprobe->attenuationmat, ob->obmat, eprobe->attenuationmat);
- invert_m4(eprobe->attenuationmat);
+static void lightbake_render_world_face(int face, EEVEE_BakeRenderData *user_data)
+{
+ EEVEE_PassList *psl = user_data->vedata->psl;
+ struct GPUFrameBuffer **face_fb = user_data->face_fb;
- /* Parallax */
- float dist;
- if ((probe->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) {
- eprobe->parallax_type = probe->parallax_type;
- dist = probe->distpar;
- }
- else {
- eprobe->parallax_type = probe->attenuation_type;
- dist = probe->distinf;
- }
+ /* For world probe, we don't need to clear the color buffer
+ * since we render the background directly. */
+ GPU_framebuffer_bind(face_fb[face]);
+ GPU_framebuffer_clear_depth(face_fb[face], 1.0f);
+ DRW_draw_pass(psl->probe_background);
+}
- unit_m4(eprobe->parallaxmat);
- scale_m4_fl(eprobe->parallaxmat, dist);
- mul_m4_m4m4(eprobe->parallaxmat, ob->obmat, eprobe->parallaxmat);
- invert_m4(eprobe->parallaxmat);
+void EEVEE_lightbake_render_world(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, struct GPUFrameBuffer *face_fb[6])
+{
+ EEVEE_BakeRenderData brdata = {
+ .vedata = vedata,
+ .face_fb = face_fb
+ };
- /* Debug Display */
- if (DRW_state_draw_support() &&
- (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA))
- {
- ped->probe_size = probe->data_draw_size * 0.1f;
- DRW_shgroup_call_dynamic_add(
- stl->g_data->cube_display_shgrp, &ped->probe_id, ob->obmat[3], &ped->probe_size);
- }
- }
+ render_cubemap(lightbake_render_world_face, &brdata, (float[3]){0.0f}, 1.0f, 10.0f);
+}
- /* IRRADIANCE GRID */
- int offset = 1; /* to account for the world probe */
- for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
- LightProbe *probe = (LightProbe *)ob->data;
- EEVEE_LightGrid *egrid = &pinfo->grid_data[i];
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_data)
+{
+ EEVEE_ViewLayerData *sldata = user_data->sldata;
+ EEVEE_PassList *psl = user_data->vedata->psl;
+ struct GPUFrameBuffer **face_fb = user_data->face_fb;
- /* If one grid has move we need to recompute all the lighting. */
- if (!pinfo->grid_initialized) {
- ped->updated_cells = 0;
- ped->updated_lvl = 0;
- ped->need_update = true;
- }
+ /* Be sure that cascaded shadow maps are updated. */
+ EEVEE_draw_shadows(sldata, psl);
- /* Add one for level 0 */
- ped->max_lvl = 1.0f + floorf(log2f((float)MAX3(probe->grid_resolution_x,
- probe->grid_resolution_y,
- probe->grid_resolution_z)));
-
- egrid->offset = offset;
- float fac = 1.0f / max_ff(1e-8f, probe->falloff);
- egrid->attenuation_scale = fac / max_ff(1e-8f, probe->distinf);
- egrid->attenuation_bias = fac;
-
- /* Set offset for the next grid */
- offset += ped->num_cell;
-
- /* Update transforms */
- float cell_dim[3], half_cell_dim[3];
- cell_dim[0] = 2.0f / (float)(probe->grid_resolution_x);
- cell_dim[1] = 2.0f / (float)(probe->grid_resolution_y);
- cell_dim[2] = 2.0f / (float)(probe->grid_resolution_z);
-
- mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f);
-
- /* Matrix converting world space to cell ranges. */
- invert_m4_m4(egrid->mat, ob->obmat);
-
- /* First cell. */
- copy_v3_fl(egrid->corner, -1.0f);
- add_v3_v3(egrid->corner, half_cell_dim);
- mul_m4_v3(ob->obmat, egrid->corner);
-
- /* Opposite neighbor cell. */
- copy_v3_fl3(egrid->increment_x, cell_dim[0], 0.0f, 0.0f);
- add_v3_v3(egrid->increment_x, half_cell_dim);
- add_v3_fl(egrid->increment_x, -1.0f);
- mul_m4_v3(ob->obmat, egrid->increment_x);
- sub_v3_v3(egrid->increment_x, egrid->corner);
-
- copy_v3_fl3(egrid->increment_y, 0.0f, cell_dim[1], 0.0f);
- add_v3_v3(egrid->increment_y, half_cell_dim);
- add_v3_fl(egrid->increment_y, -1.0f);
- mul_m4_v3(ob->obmat, egrid->increment_y);
- sub_v3_v3(egrid->increment_y, egrid->corner);
-
- copy_v3_fl3(egrid->increment_z, 0.0f, 0.0f, cell_dim[2]);
- add_v3_v3(egrid->increment_z, half_cell_dim);
- add_v3_fl(egrid->increment_z, -1.0f);
- mul_m4_v3(ob->obmat, egrid->increment_z);
- sub_v3_v3(egrid->increment_z, egrid->corner);
-
- copy_v3_v3_int(egrid->resolution, &probe->grid_resolution_x);
-
- /* Visibility bias */
- egrid->visibility_bias = 0.05f * probe->vis_bias;
- egrid->visibility_bleed = probe->vis_bleedbias;
- egrid->visibility_range = (
- sqrtf(max_fff(len_squared_v3(egrid->increment_x),
- len_squared_v3(egrid->increment_y),
- len_squared_v3(egrid->increment_z))) + 1.0f);
+ GPU_framebuffer_bind(face_fb[face]);
+ GPU_framebuffer_clear_depth(face_fb[face], 1.0f);
- /* Debug Display */
- if (DRW_state_draw_support() &&
- (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA))
- {
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_grid_display_sh, psl->probe_display);
- DRW_shgroup_uniform_int(grp, "offset", &egrid->offset, 1);
- DRW_shgroup_uniform_ivec3(grp, "grid_resolution", egrid->resolution, 1);
- DRW_shgroup_uniform_vec3(grp, "corner", egrid->corner, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_x", egrid->increment_x, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_y", egrid->increment_y, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_z", egrid->increment_z, 1);
- DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &sldata->irradiance_pool);
- DRW_shgroup_uniform_float(grp, "sphere_size", &probe->data_draw_size, 1);
- DRW_shgroup_call_instances_add(grp, DRW_cache_sphere_get(), NULL, (uint *)&ped->num_cell);
- }
- }
+ DRW_draw_pass(psl->depth_pass);
+ DRW_draw_pass(psl->depth_pass_cull);
+ DRW_draw_pass(psl->probe_background);
+ DRW_draw_pass(psl->material_pass);
+ DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
+ EEVEE_draw_default_passes(psl);
}
-void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+/* Render the scene to the probe_rt texture. */
+void EEVEE_lightbake_render_scene(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUFrameBuffer *face_fb[6],
+ const float pos[3], float near_clip, float far_clip)
{
- EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_BakeRenderData brdata = {
+ .vedata = vedata,
+ .sldata = sldata,
+ .face_fb = face_fb
+ };
+
+ render_cubemap(lightbake_render_scene_face, &brdata, pos, near_clip, far_clip);
+}
+
+static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *user_data)
+{
+ EEVEE_Data *vedata = user_data->vedata;
+ EEVEE_ViewLayerData *sldata = user_data->sldata;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
- Object *ob;
+ EEVEE_PlanarReflection *eplanar = pinfo->planar_data + layer;
- /* Setup enough layers. */
- /* Free textures if number mismatch. */
- if (pinfo->num_cube != pinfo->cache_num_cube) {
- DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
- pinfo->cache_num_cube = pinfo->num_cube;
- }
+ GPU_framebuffer_ensure_config(&fbl->planarref_fb, {
+ GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_depth, layer),
+ GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_pool, layer)
+ });
- if (pinfo->num_planar != pinfo->cache_num_planar) {
- DRW_TEXTURE_FREE_SAFE(vedata->txl->planar_pool);
- DRW_TEXTURE_FREE_SAFE(vedata->txl->planar_depth);
- pinfo->cache_num_planar = pinfo->num_planar;
- }
+ /* Use visibility info for this planar reflection. */
+ pinfo->vis_data = pinfo->planar_vis_tests[layer];
- int irr_size[3];
- irradiance_pool_size_get(common_data->prb_irradiance_vis_size, pinfo->total_irradiance_samples, irr_size);
+ /* Avoid using the texture attached to framebuffer when rendering. */
+ /* XXX */
+ GPUTexture *tmp_planar_pool = txl->planar_pool;
+ GPUTexture *tmp_planar_depth = txl->planar_depth;
+ txl->planar_pool = e_data.planar_pool_placeholder;
+ txl->planar_depth = e_data.depth_array_placeholder;
- if ((irr_size[0] != pinfo->cache_irradiance_size[0]) ||
- (irr_size[1] != pinfo->cache_irradiance_size[1]) ||
- (irr_size[2] != pinfo->cache_irradiance_size[2]))
- {
- DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool);
- DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt);
- copy_v3_v3_int(pinfo->cache_irradiance_size, irr_size);
- }
+ /* Be sure that cascaded shadow maps are updated. */
+ DRW_stats_group_start("Planar Reflection");
- /* XXX this should be run each frame as it ensure planar_depth is set */
- planar_pool_ensure_alloc(vedata, pinfo->num_planar);
+ /* Be sure that cascaded shadow maps are updated. */
+ EEVEE_draw_shadows(sldata, psl);
+ /* Since we are rendering with an inverted view matrix, we need
+ * to invert the facing for backface culling to be the same. */
+ DRW_state_invert_facing();
+ /* Compute offset plane equation (fix missing texels near reflection plane). */
+ copy_v4_v4(sldata->clip_data.clip_planes[0], eplanar->plane_equation);
+ sldata->clip_data.clip_planes[0][3] += eplanar->clipsta;
+ /* Set clipping plane */
+ DRW_uniformbuffer_update(sldata->clip_ubo, &sldata->clip_data);
+ DRW_state_clip_planes_count_set(1);
- if (!sldata->probe_pool) {
- sldata->probe_pool = DRW_texture_create_2D_array(pinfo->cubemap_res, pinfo->cubemap_res, max_ff(1, pinfo->num_cube),
- GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
- if (sldata->probe_filter_fb) {
- GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
- }
- /* Tag probes to refresh */
- pinfo->update_world |= PROBE_UPDATE_CUBE;
- }
+ GPU_framebuffer_bind(fbl->planarref_fb);
+ GPU_framebuffer_clear_depth(fbl->planarref_fb, 1.0);
- if ((pinfo->update_world & PROBE_UPDATE_CUBE) != 0) {
- common_data->prb_num_render_cube = 0;
- for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
- ped->need_update = true;
- ped->ready_to_shade = false;
- ped->probe_id = 0;
- }
- }
+ /* Slight modification: we handle refraction as normal
+ * shading and don't do SSRefraction. */
-#ifdef IRRADIANCE_SH_L2
- /* we need a signed format for Spherical Harmonics */
- int irradiance_format = GPU_RGBA16F;
-#else
- int irradiance_format = GPU_RGBA8;
-#endif
+ DRW_draw_pass(psl->depth_pass_clip);
+ DRW_draw_pass(psl->depth_pass_clip_cull);
+ DRW_draw_pass(psl->refract_depth_pass);
+ DRW_draw_pass(psl->refract_depth_pass_cull);
- if (!sldata->irradiance_pool || !sldata->irradiance_rt) {
- if (!sldata->irradiance_pool) {
- sldata->irradiance_pool = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2],
- irradiance_format, DRW_TEX_FILTER, NULL);
- }
- if (!sldata->irradiance_rt) {
- sldata->irradiance_rt = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2],
- irradiance_format, DRW_TEX_FILTER, NULL);
- }
- /* Tag probes to refresh */
- pinfo->update_world |= PROBE_UPDATE_GRID;
- pinfo->grid_initialized = false;
- }
+ DRW_draw_pass(psl->probe_background);
+ EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer);
+ EEVEE_occlusion_compute(sldata, vedata, tmp_planar_depth, layer);
- if ((pinfo->update_world & PROBE_UPDATE_GRID) != 0) {
- common_data->prb_num_render_grid = 0;
- pinfo->updated_bounce = 0;
- for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_PROBE); i++) {
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
- ped->need_update = true;
- ped->updated_cells = 0;
- }
- }
+ GPU_framebuffer_bind(fbl->planarref_fb);
- if (common_data->prb_num_render_grid > pinfo->num_grid) {
- /* This can happen when deleting a probe. */
- common_data->prb_num_render_grid = pinfo->num_grid;
+ /* Shading pass */
+ EEVEE_draw_default_passes(psl);
+ DRW_draw_pass(psl->material_pass);
+ DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
+ DRW_draw_pass(psl->refract_pass);
+
+ /* Transparent */
+ if (DRW_state_is_image_render()) {
+ /* Do the reordering only for offline because it can be costly. */
+ DRW_pass_sort_shgroup_z(psl->transparent_pass);
}
+ DRW_draw_pass(psl->transparent_pass);
- EEVEE_planar_reflections_cache_finish(sldata, vedata->stl);
+ DRW_state_invert_facing();
+ DRW_state_clip_planes_reset();
- EEVEE_lightprobes_updates(sldata, vedata->psl, vedata->stl);
+ DRW_stats_group_end();
- DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data);
- DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
+ /* Restore */
+ txl->planar_pool = tmp_planar_pool;
+ txl->planar_depth = tmp_planar_depth;
}
-static void downsample_planar(void *vedata, int level)
+static void eevee_lightbake_render_scene_to_planars(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
- EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
- EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
-
- const float *size = DRW_viewport_size_get();
- copy_v2_v2(stl->g_data->planar_texel_size, size);
- for (int i = 0; i < level - 1; ++i) {
- stl->g_data->planar_texel_size[0] /= 2.0f;
- stl->g_data->planar_texel_size[1] /= 2.0f;
- min_ff(floorf(stl->g_data->planar_texel_size[0]), 1.0f);
- min_ff(floorf(stl->g_data->planar_texel_size[1]), 1.0f);
- }
- invert_v2(stl->g_data->planar_texel_size);
+ EEVEE_BakeRenderData brdata = {
+ .vedata = vedata,
+ .sldata = sldata,
+ };
- DRW_draw_pass(psl->probe_planar_downsample_ps);
+ render_reflections(lightbake_render_scene_reflected, &brdata, sldata->probes->planar_data, sldata->probes->num_planar);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
-/* Glossy filter probe_rt to probe_pool at index probe_idx */
-static void glossy_filter_probe(
- EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int probe_idx, float intensity)
+/** \name Filtering
+ * \{ */
+
+/* Glossy filter rt_color to light_cache->cube_tx.tex at index probe_idx */
+void EEVEE_lightbake_filter_glossy(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
+ struct GPUTexture *rt_color, struct GPUFrameBuffer *fb,
+ int probe_idx, float intensity, int maxlevel)
{
+ EEVEE_PassList *psl = vedata->psl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
- pinfo->intensity_fac = intensity;
+ float target_size = (float)GPU_texture_width(rt_color);
/* Max lod used from the render target probe */
- pinfo->lod_rt_max = floorf(log2f(pinfo->target_size)) - 2.0f;
+ pinfo->lod_rt_max = floorf(log2f(target_size)) - 2.0f;
+ pinfo->intensity_fac = intensity;
/* Start fresh */
- GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, {
+ GPU_framebuffer_ensure_config(&fb, {
GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_NONE
});
/* 2 - Let gpu create Mipmaps for Filtered Importance Sampling. */
/* Bind next framebuffer to be able to gen. mips for probe_rt. */
- EEVEE_downsample_cube_buffer(vedata, sldata->probe_rt, (int)(pinfo->lod_rt_max));
+ EEVEE_downsample_cube_buffer(vedata, rt_color, (int)(pinfo->lod_rt_max));
/* 3 - Render to probe array to the specified layer, do prefiltering. */
- float mipsize = pinfo->cubemap_res;
- const int maxlevel = (int)floorf(log2f(pinfo->cubemap_res));
- const int min_lod_level = 3;
- for (int i = 0; i < maxlevel - min_lod_level; i++) {
+ int mipsize = GPU_texture_width(light_cache->cube_tx.tex);
+ for (int i = 0; i < maxlevel + 1; i++) {
float bias = (i == 0) ? -1.0f : 1.0f;
- pinfo->texel_size = 1.0f / mipsize;
- pinfo->padding_size = powf(2.0f, (float)(maxlevel - min_lod_level - 1 - i));
+ pinfo->texel_size = 1.0f / (float)mipsize;
+ pinfo->padding_size = (float)(1 << (maxlevel - i - 1));
pinfo->padding_size *= pinfo->texel_size;
pinfo->layer = probe_idx;
- pinfo->roughness = (float)i / ((float)maxlevel - 4.0f);
+ pinfo->roughness = i / (float)maxlevel;
pinfo->roughness *= pinfo->roughness; /* Disney Roughness */
pinfo->roughness *= pinfo->roughness; /* Distribute Roughness accros lod more evenly */
CLAMP(pinfo->roughness, 1e-8f, 0.99999f); /* Avoid artifacts */
@@ -1111,35 +1122,34 @@ static void glossy_filter_probe(
#endif
pinfo->samples_len_inv = 1.0f / pinfo->samples_len;
- pinfo->lodfactor = bias + 0.5f * log((float)(pinfo->target_size * pinfo->target_size) * pinfo->samples_len_inv) / log(2);
+ pinfo->lodfactor = bias + 0.5f * log((float)(target_size * target_size) * pinfo->samples_len_inv) / log(2);
- GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, {
+ GPU_framebuffer_ensure_config(&fb, {
GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE_MIP(sldata->probe_pool, i)
+ GPU_ATTACHMENT_TEXTURE_MIP(light_cache->cube_tx.tex, i)
});
- GPU_framebuffer_bind(sldata->probe_filter_fb);
- GPU_framebuffer_viewport_set(sldata->probe_filter_fb, 0, 0, mipsize, mipsize);
+ GPU_framebuffer_bind(fb);
+ GPU_framebuffer_viewport_set(fb, 0, 0, mipsize, mipsize);
DRW_draw_pass(psl->probe_glossy_compute);
mipsize /= 2;
CLAMP_MIN(mipsize, 1);
}
- /* For shading, save max level of the octahedron map */
- sldata->common_data.prb_lod_cube_max = (float)(maxlevel - min_lod_level) - 1.0f;
}
-/* Diffuse filter probe_rt to irradiance_pool at index probe_idx */
-static void diffuse_filter_probe(
- EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int offset,
- float clipsta, float clipend, float vis_range, float vis_blur, float intensity)
+/* Diffuse filter rt_color to light_cache->grid_tx.tex at index grid_offset */
+void EEVEE_lightbake_filter_diffuse(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
+ struct GPUTexture *rt_color, struct GPUFrameBuffer *fb,
+ int grid_offset, float intensity)
{
- EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_PassList *psl = vedata->psl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
- pinfo->intensity_fac = intensity;
+ float target_size = (float)GPU_texture_width(rt_color);
- int pool_size[3];
- irradiance_pool_size_get(common_data->prb_irradiance_vis_size, pinfo->total_irradiance_samples, pool_size);
+ pinfo->intensity_fac = intensity;
/* find cell position on the virtual 3D texture */
/* NOTE : Keep in sync with load_irradiance_cell() */
@@ -1153,377 +1163,114 @@ static void diffuse_filter_probe(
pinfo->samples_len = 1024.0f;
#endif
- int cell_per_row = pool_size[0] / size[0];
- int x = size[0] * (offset % cell_per_row);
- int y = size[1] * (offset / cell_per_row);
+ int cell_per_row = GPU_texture_width(light_cache->grid_tx.tex) / size[0];
+ int x = size[0] * (grid_offset % cell_per_row);
+ int y = size[1] * (grid_offset / cell_per_row);
#ifndef IRRADIANCE_SH_L2
/* Tweaking parameters to balance perf. vs precision */
const float bias = 0.0f;
pinfo->samples_len_inv = 1.0f / pinfo->samples_len;
- pinfo->lodfactor = bias + 0.5f * log((float)(pinfo->target_size * pinfo->target_size) * pinfo->samples_len_inv) / log(2);
- pinfo->lod_rt_max = floorf(log2f(pinfo->target_size)) - 2.0f;
+ pinfo->lodfactor = bias + 0.5f * log((float)(target_size * target_size) * pinfo->samples_len_inv) / log(2);
+ pinfo->lod_rt_max = floorf(log2f(target_size)) - 2.0f;
#else
pinfo->shres = 32; /* Less texture fetches & reduce branches */
pinfo->lod_rt_max = 2.0f; /* Improve cache reuse */
#endif
/* Start fresh */
- GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, {
+ GPU_framebuffer_ensure_config(&fb, {
GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_NONE
});
- /* 4 - Compute spherical harmonics */
- EEVEE_downsample_cube_buffer(vedata, sldata->probe_rt, (int)(pinfo->lod_rt_max));
+ /* 4 - Compute diffuse irradiance */
+ EEVEE_downsample_cube_buffer(vedata, rt_color, (int)(pinfo->lod_rt_max));
- GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, {
+ GPU_framebuffer_ensure_config(&fb, {
GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE_LAYER(sldata->irradiance_rt, 0)
+ GPU_ATTACHMENT_TEXTURE_LAYER(light_cache->grid_tx.tex, 0)
});
- GPU_framebuffer_bind(sldata->probe_filter_fb);
- GPU_framebuffer_viewport_set(sldata->probe_filter_fb, x, y, size[0], size[1]);
+ GPU_framebuffer_bind(fb);
+ GPU_framebuffer_viewport_set(fb, x, y, size[0], size[1]);
DRW_draw_pass(psl->probe_diffuse_compute);
-
- /* World irradiance have no visibility */
- if (offset > 0) {
- /* Compute visibility */
- pinfo->samples_len = 512.0f; /* TODO refine */
- pinfo->samples_len_inv = 1.0f / pinfo->samples_len;
- pinfo->shres = common_data->prb_irradiance_vis_size;
- pinfo->visibility_range = vis_range;
- pinfo->visibility_blur = vis_blur;
- pinfo->near_clip = -clipsta;
- pinfo->far_clip = -clipend;
- pinfo->texel_size = 1.0f / (float)common_data->prb_irradiance_vis_size;
-
- int cell_per_col = pool_size[1] / common_data->prb_irradiance_vis_size;
- cell_per_row = pool_size[0] / common_data->prb_irradiance_vis_size;
- x = common_data->prb_irradiance_vis_size * (offset % cell_per_row);
- y = common_data->prb_irradiance_vis_size * ((offset / cell_per_row) % cell_per_col);
- int layer = 1 + ((offset / cell_per_row) / cell_per_col);
- const int vis_size = common_data->prb_irradiance_vis_size;
-
- GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE_LAYER(sldata->irradiance_rt, layer)
- });
- GPU_framebuffer_bind(sldata->probe_filter_fb);
- GPU_framebuffer_viewport_set(sldata->probe_filter_fb, x, y, vis_size, vis_size);
- DRW_draw_pass(psl->probe_visibility_compute);
- }
}
-/* Render the scene to the probe_rt texture. */
-static void render_scene_to_probe(
+/* Filter rt_depth to light_cache->grid_tx.tex at index grid_offset */
+void EEVEE_lightbake_filter_visibility(
EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
- const float pos[3], float clipsta, float clipend)
+ struct GPUTexture *UNUSED(rt_depth), struct GPUFrameBuffer *fb,
+ int grid_offset, float clipsta, float clipend,
+ float vis_range, float vis_blur, int vis_size)
{
- EEVEE_TextureList *txl = vedata->txl;
EEVEE_PassList *psl = vedata->psl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
- DRWMatrixState matstate;
- float (*viewmat)[4] = matstate.mat[DRW_MAT_VIEW];
- float (*viewinv)[4] = matstate.mat[DRW_MAT_VIEWINV];
- float (*persmat)[4] = matstate.mat[DRW_MAT_PERS];
- float (*persinv)[4] = matstate.mat[DRW_MAT_PERSINV];
- float (*winmat)[4] = matstate.mat[DRW_MAT_WIN];
- float (*wininv)[4] = matstate.mat[DRW_MAT_WININV];
-
- float posmat[4][4];
- unit_m4(posmat);
-
- /* Move to capture position */
- negate_v3_v3(posmat[3], pos);
-
- /* 1 - Render to each cube-face individually.
- * We do this instead of using geometry shader because a) it's faster,
- * b) it's easier than fixing the node-tree shaders (for view dependent effects). */
- pinfo->layer = 0;
- perspective_m4(winmat, -clipsta, clipsta, -clipsta, clipsta, clipsta, clipend);
-
- /* Avoid using the texture attached to framebuffer when rendering. */
- /* XXX */
- GPUTexture *tmp_planar_pool = txl->planar_pool;
- GPUTexture *tmp_maxz = txl->maxzbuffer;
- txl->planar_pool = e_data.planar_pool_placeholder;
- txl->maxzbuffer = e_data.depth_placeholder;
-
- DRW_stats_group_start("Cubemap Render");
-
- /* Update common uniforms */
- DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
-
- for (int i = 0; i < 6; ++i) {
- /* Recompute only on 1st drawloop. */
- pinfo->vis_data.cached = (i != 0);
-
- DRW_stats_group_start("Cubemap Face");
-
- /* Setup custom matrices */
- mul_m4_m4m4(viewmat, cubefacemat[i], posmat);
- mul_m4_m4m4(persmat, winmat, viewmat);
- invert_m4_m4(persinv, persmat);
- invert_m4_m4(viewinv, viewmat);
- invert_m4_m4(wininv, winmat);
-
- DRW_viewport_matrix_override_set_all(&matstate);
-
- /* Be sure that cascaded shadow maps are updated. */
- EEVEE_draw_shadows(sldata, psl);
-
- GPU_framebuffer_bind(sldata->probe_face_fb[i]);
- GPU_framebuffer_clear_depth(sldata->probe_face_fb[i], 1.0);
-
- /* Depth prepass */
- DRW_draw_pass(psl->depth_pass);
- DRW_draw_pass(psl->depth_pass_cull);
-
- DRW_draw_pass(psl->probe_background);
-
- // EEVEE_create_minmax_buffer(vedata, sldata->probe_depth_rt);
-
- /* Rebind Target FB */
- GPU_framebuffer_bind(sldata->probe_face_fb[i]);
-
- /* Shading pass */
- EEVEE_draw_default_passes(psl);
- DRW_draw_pass(psl->material_pass);
- DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
-
- DRW_stats_group_end();
- }
-
- DRW_stats_group_end();
-
- /* Make sure no aditionnal visibility check runs after this. */
- pinfo->vis_data.collection = NULL;
-
- /* Restore */
- txl->planar_pool = tmp_planar_pool;
- txl->maxzbuffer = tmp_maxz;
-}
-
-static void render_scene_to_planar(
- EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int layer,
- EEVEE_LightProbeEngineData *ped)
-{
- EEVEE_LightProbesInfo *pinfo = sldata->probes;
- EEVEE_FramebufferList *fbl = vedata->fbl;
- EEVEE_TextureList *txl = vedata->txl;
- EEVEE_PassList *psl = vedata->psl;
-
- float (*viewmat)[4] = ped->mats.mat[DRW_MAT_VIEW];
- float (*viewinv)[4] = ped->mats.mat[DRW_MAT_VIEWINV];
- float (*persmat)[4] = ped->mats.mat[DRW_MAT_PERS];
- float (*persinv)[4] = ped->mats.mat[DRW_MAT_PERSINV];
- float (*winmat)[4] = ped->mats.mat[DRW_MAT_WIN];
- float (*wininv)[4] = ped->mats.mat[DRW_MAT_WININV];
-
- invert_m4_m4(viewinv, viewmat);
- invert_m4_m4(persinv, persmat);
- invert_m4_m4(wininv, winmat);
-
- DRW_stats_group_start("Planar Reflection");
-
- DRW_viewport_matrix_override_set_all(&ped->mats);
-
- /* Don't reuse previous visibility. */
- pinfo->vis_data.cached = false;
-
- /* Be sure that cascaded shadow maps are updated. */
- EEVEE_draw_shadows(sldata, psl);
-
- /* Since we are rendering with an inverted view matrix, we need
- * to invert the facing for back-face culling to be the same. */
- DRW_state_invert_facing();
- /* Set clipping plan */
- copy_v4_v4(sldata->clip_data.clip_planes[0], ped->planer_eq_offset);
- DRW_uniformbuffer_update(sldata->clip_ubo, &sldata->clip_data);
- DRW_state_clip_planes_count_set(1);
-
- GPU_framebuffer_ensure_config(&fbl->planarref_fb, {
- GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_depth, layer),
- GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_pool, layer)
+ pinfo->samples_len = 512.0f; /* TODO refine */
+ pinfo->samples_len_inv = 1.0f / pinfo->samples_len;
+ pinfo->shres = vis_size;
+ pinfo->visibility_range = vis_range;
+ pinfo->visibility_blur = vis_blur;
+ pinfo->near_clip = -clipsta;
+ pinfo->far_clip = -clipend;
+ pinfo->texel_size = 1.0f / (float)vis_size;
+
+ int cell_per_col = GPU_texture_height(light_cache->grid_tx.tex) / vis_size;
+ int cell_per_row = GPU_texture_width(light_cache->grid_tx.tex) / vis_size;
+ int x = vis_size * (grid_offset % cell_per_row);
+ int y = vis_size * ((grid_offset / cell_per_row) % cell_per_col);
+ int layer = 1 + ((grid_offset / cell_per_row) / cell_per_col);
+
+ GPU_framebuffer_ensure_config(&fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE_LAYER(light_cache->grid_tx.tex, layer)
});
-
- GPU_framebuffer_bind(fbl->planarref_fb);
- GPU_framebuffer_clear_depth(fbl->planarref_fb, 1.0);
-
- /* Avoid using the texture attached to framebuffer when rendering. */
- /* XXX */
- GPUTexture *tmp_planar_pool = txl->planar_pool;
- GPUTexture *tmp_planar_depth = txl->planar_depth;
- txl->planar_pool = e_data.planar_pool_placeholder;
- txl->planar_depth = e_data.depth_array_placeholder;
-
- /* Slight modification: we handle refraction as normal
- * shading and don't do SSRefraction. */
-
- /* Depth prepass */
- DRW_draw_pass(psl->depth_pass_clip);
- DRW_draw_pass(psl->depth_pass_clip_cull);
- DRW_draw_pass(psl->refract_depth_pass);
- DRW_draw_pass(psl->refract_depth_pass_cull);
-
- /* Background */
- DRW_draw_pass(psl->probe_background);
-
- EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer);
-
- /* Compute GTAO Horizons */
- EEVEE_occlusion_compute(sldata, vedata, tmp_planar_depth, layer);
-
- /* Rebind Planar FB */
- GPU_framebuffer_bind(fbl->planarref_fb);
-
- /* Shading pass */
- EEVEE_draw_default_passes(psl);
- DRW_draw_pass(psl->material_pass);
- DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
- DRW_draw_pass(psl->refract_pass);
-
- /* Transparent */
- if (DRW_state_is_image_render()) {
- /* Do the reordering only for offline because it can be costly. */
- DRW_pass_sort_shgroup_z(psl->transparent_pass);
- }
- DRW_draw_pass(psl->transparent_pass);
-
- DRW_state_invert_facing();
- DRW_state_clip_planes_reset();
-
- DRW_stats_group_end();
-
- /* Make sure no aditionnal visibility check runs after this. */
- pinfo->vis_data.collection = NULL;
-
- /* Restore */
- txl->planar_pool = tmp_planar_pool;
- txl->planar_depth = tmp_planar_depth;
+ GPU_framebuffer_bind(fb);
+ GPU_framebuffer_viewport_set(fb, x, y, vis_size, vis_size);
+ DRW_draw_pass(psl->probe_visibility_compute);
}
-static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
+/* Actually a simple downsampling */
+static void downsample_planar(void *vedata, int level)
{
- EEVEE_LightProbesInfo *pinfo = sldata->probes;
- DRWMatrixState matstate;
- float (*viewmat)[4] = matstate.mat[DRW_MAT_VIEW];
- float (*viewinv)[4] = matstate.mat[DRW_MAT_VIEWINV];
- float (*persmat)[4] = matstate.mat[DRW_MAT_PERS];
- float (*persinv)[4] = matstate.mat[DRW_MAT_PERSINV];
- float (*winmat)[4] = matstate.mat[DRW_MAT_WIN];
- float (*wininv)[4] = matstate.mat[DRW_MAT_WININV];
-
- /* For world probe, we don't need to clear since we render the background directly. */
- pinfo->layer = 0;
-
- perspective_m4(winmat, -0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 1.0f);
- invert_m4_m4(wininv, winmat);
-
- for (int i = 0; i < 6; ++i) {
- /* Setup custom matrices */
- copy_m4_m4(viewmat, cubefacemat[i]);
- mul_m4_m4m4(persmat, winmat, viewmat);
- invert_m4_m4(persinv, persmat);
- invert_m4_m4(viewinv, viewmat);
- DRW_viewport_matrix_override_set_all(&matstate);
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
- GPU_framebuffer_bind(sldata->probe_face_fb[i]);
- GPU_framebuffer_clear_depth(sldata->probe_face_fb[i], 1.0f);
- DRW_draw_pass(psl->probe_background);
+ const float *size = DRW_viewport_size_get();
+ copy_v2_v2(stl->g_data->planar_texel_size, size);
+ for (int i = 0; i < level - 1; ++i) {
+ stl->g_data->planar_texel_size[0] /= 2.0f;
+ stl->g_data->planar_texel_size[1] /= 2.0f;
+ min_ff(floorf(stl->g_data->planar_texel_size[0]), 1.0f);
+ min_ff(floorf(stl->g_data->planar_texel_size[1]), 1.0f);
}
-}
-
-static void lightprobe_cell_grid_location_get(EEVEE_LightGrid *egrid, int cell_idx, float r_local_cell[3])
-{
- /* Keep in sync with lightprobe_grid_display_vert */
- r_local_cell[2] = (float)(cell_idx % egrid->resolution[2]);
- r_local_cell[1] = (float)((cell_idx / egrid->resolution[2]) % egrid->resolution[1]);
- r_local_cell[0] = (float)(cell_idx / (egrid->resolution[2] * egrid->resolution[1]));
-}
+ invert_v2(stl->g_data->planar_texel_size);
-static void lightprobe_cell_world_location_get(EEVEE_LightGrid *egrid, float local_cell[3], float r_pos[3])
-{
- float tmp[3];
-
- copy_v3_v3(r_pos, egrid->corner);
- mul_v3_v3fl(tmp, egrid->increment_x, local_cell[0]);
- add_v3_v3(r_pos, tmp);
- mul_v3_v3fl(tmp, egrid->increment_y, local_cell[1]);
- add_v3_v3(r_pos, tmp);
- mul_v3_v3fl(tmp, egrid->increment_z, local_cell[2]);
- add_v3_v3(r_pos, tmp);
+ DRW_draw_pass(psl->probe_planar_downsample_ps);
}
-static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+static void EEVEE_lightbake_filter_planar(EEVEE_Data *vedata)
{
- EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
- EEVEE_LightProbesInfo *pinfo = sldata->probes;
- EEVEE_PassList *psl = vedata->psl;
- EEVEE_StorageList *stl = vedata->stl;
- DRWMatrixState saved_mats;
-
- /* We need to save the Matrices before overidding them */
- DRW_viewport_matrix_get_all(&saved_mats);
-
- render_world_to_probe(sldata, psl);
- if (pinfo->update_world & PROBE_UPDATE_CUBE) {
- glossy_filter_probe(sldata, vedata, psl, 0, 1.0);
- common_data->prb_num_render_cube = 1;
- }
- if (pinfo->update_world & PROBE_UPDATE_GRID) {
- diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0, 1.0);
-
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
- GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
- GPU_framebuffer_bind(sldata->probe_filter_fb);
- DRW_draw_pass(psl->probe_grid_fill);
+ DRW_stats_group_start("Planar Probe Downsample");
- common_data->prb_num_render_grid = 1;
- /* Reset volume history. */
- stl->effects->volume_current_sample = -1;
- common_data->vol_history_alpha = 0.0f;
- }
- pinfo->update_world = 0;
- DRW_viewport_request_redraw();
- /* Do not let this frame accumulate. */
- stl->effects->taa_current_sample = 1;
+ GPU_framebuffer_ensure_config(&fbl->planar_downsample_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->planar_pool)
+ });
- DRW_viewport_matrix_override_set_all(&saved_mats);
+ GPU_framebuffer_recursive_downsample(fbl->planar_downsample_fb, MAX_PLANAR_LOD_LEVEL, &downsample_planar, vedata);
+ DRW_stats_group_end();
}
-static void lightprobes_refresh_initialize_grid(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
-{
- EEVEE_LightProbesInfo *pinfo = sldata->probes;
- EEVEE_PassList *psl = vedata->psl;
- if (pinfo->grid_initialized) {
- /* Grid is already initialized, nothing to do. */
- return;
- }
- /* Flood fill with world irradiance. */
- GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
- GPU_framebuffer_bind(sldata->probe_filter_fb);
- DRW_draw_pass(psl->probe_grid_fill);
-
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
-
- GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
- GPU_framebuffer_bind(sldata->probe_filter_fb);
- DRW_draw_pass(psl->probe_grid_fill);
-
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
-
- pinfo->grid_initialized = true;
-}
+/** \} */
void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
- EEVEE_FramebufferList *fbl = vedata->fbl;
- EEVEE_TextureList *txl = vedata->txl;
- Object *ob;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
DRWMatrixState saved_mats;
@@ -1534,9 +1281,6 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
return;
}
- EEVEE_planar_reflections_updates(sldata);
- DRW_uniformbuffer_update(sldata->planar_ubo, &sldata->probes->planar_data);
-
/* We need to save the Matrices before overidding them */
DRW_viewport_matrix_get_all(&saved_mats);
@@ -1548,13 +1292,13 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
- for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) {
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
- LightProbe *prb = (LightProbe *)ob->data;
- pinfo->vis_data.collection = prb->visibility_grp;
- pinfo->vis_data.invert = prb->flag & LIGHTPROBE_FLAG_INVERT_GROUP;
- render_scene_to_planar(sldata, vedata, i, ped);
- }
+ /* Rendering happens here! */
+ eevee_lightbake_render_scene_to_planars(sldata, vedata);
+
+ /* Make sure no aditionnal visibility check runs after this. */
+ pinfo->vis_data.collection = NULL;
+
+ DRW_uniformbuffer_update(sldata->planar_ubo, &sldata->probes->planar_data);
/* Restore */
common_data->prb_num_planar = pinfo->num_planar;
@@ -1563,17 +1307,7 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
/* Prefilter for SSR */
if ((vedata->stl->effects->enabled_effects & EFFECT_SSR) != 0) {
- const int max_lod = 9;
- DRW_stats_group_start("Planar Probe Downsample");
-
- GPU_framebuffer_ensure_config(&fbl->planar_downsample_fb, {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(txl->planar_pool)
- });
- GPU_framebuffer_recursive_downsample(fbl->planar_downsample_fb, max_lod, &downsample_planar, vedata);
- /* For shading, save max level of the planar map */
- common_data->prb_lod_planar_max = (float)(max_lod);
- DRW_stats_group_end();
+ EEVEE_lightbake_filter_planar(vedata);
}
DRW_viewport_matrix_override_set_all(&saved_mats);
@@ -1587,239 +1321,18 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
common_data->ssr_toggle = vedata->stl->g_data->valid_double_buffer;
}
-static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
-{
- EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
- EEVEE_PassList *psl = vedata->psl;
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_LightProbesInfo *pinfo = sldata->probes;
- Object *ob;
- for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
- if (!ped->need_update) {
- continue;
- }
- LightProbe *prb = (LightProbe *)ob->data;
- pinfo->vis_data.collection = prb->visibility_grp;
- pinfo->vis_data.invert = prb->flag & LIGHTPROBE_FLAG_INVERT_GROUP;
- render_scene_to_probe(sldata, vedata, ob->obmat[3], prb->clipsta, prb->clipend);
- glossy_filter_probe(sldata, vedata, psl, i, prb->intensity);
- ped->need_update = false;
- ped->probe_id = i;
- if (!ped->ready_to_shade) {
- common_data->prb_num_render_cube++;
- ped->ready_to_shade = true;
- }
-#if 0
- printf("Update Cubemap %d\n", i);
-#endif
- DRW_viewport_request_redraw();
- /* Do not let this frame accumulate. */
- stl->effects->taa_current_sample = 1;
- /* Only do one probe per frame */
- return;
- }
-
- pinfo->do_cube_update = false;
-}
-
-static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
-{
- EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
- EEVEE_PassList *psl = vedata->psl;
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_LightProbesInfo *pinfo = sldata->probes;
- Object *ob;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- RegionView3D *rv3d = draw_ctx->rv3d;
-
- if (draw_ctx->evil_C != NULL) {
- /* Only compute probes if not navigating or in playback */
- struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C);
- if (((rv3d->rflag & RV3D_NAVIGATING) != 0) || ED_screen_animation_no_scrub(wm) != NULL) {
- return;
- }
- }
- /* We need to save the Matrices before overidding them */
- DRWMatrixState saved_mats;
- DRW_viewport_matrix_get_all(&saved_mats);
- /* Make sure grid is initialized. */
- lightprobes_refresh_initialize_grid(sldata, vedata);
- /* Reflection probes depend on diffuse lighting thus on irradiance grid,
- * so update them first. */
- while (pinfo->updated_bounce < pinfo->num_bounce) {
- common_data->prb_num_render_grid = pinfo->num_grid;
- /* TODO(sergey): This logic can be split into smaller functions. */
- for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
- if (!ped->need_update) {
- continue;
- }
- EEVEE_LightGrid *egrid = &pinfo->grid_data[i];
- LightProbe *prb = (LightProbe *)ob->data;
- /* Find the next cell corresponding to the current level. */
- bool valid_cell = false;
- int cell_id = ped->updated_cells;
- float pos[3], grid_loc[3];
- /* Other levels */
- int current_stride = 1 << max_ii(0, ped->max_lvl - ped->updated_lvl);
- int prev_stride = current_stride << 1;
- bool do_rendering = true;
- while (!valid_cell) {
- cell_id = ped->updated_cells;
- lightprobe_cell_grid_location_get(egrid, cell_id, grid_loc);
- if (ped->updated_lvl == 0 && cell_id == 0) {
- valid_cell = true;
- ped->updated_cells = ped->num_cell;
- continue;
- }
- else if (((((int)grid_loc[0] % current_stride) == 0) &&
- (((int)grid_loc[1] % current_stride) == 0) &&
- (((int)grid_loc[2] % current_stride) == 0)) &&
- !((((int)grid_loc[0] % prev_stride) == 0) &&
- (((int)grid_loc[1] % prev_stride) == 0) &&
- (((int)grid_loc[2] % prev_stride) == 0)))
- {
- valid_cell = true;
- }
- ped->updated_cells++;
- if (ped->updated_cells > ped->num_cell) {
- do_rendering = false;
- break;
- }
- }
- if (do_rendering) {
- lightprobe_cell_world_location_get(egrid, grid_loc, pos);
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
- /* Temporary Remove all probes. */
- int tmp_num_render_grid = common_data->prb_num_render_grid;
- int tmp_num_render_cube = common_data->prb_num_render_cube;
- int tmp_num_planar = common_data->prb_num_planar;
- float tmp_level_bias = egrid->level_bias;
- common_data->prb_num_render_cube = 0;
- common_data->prb_num_planar = 0;
- /* Use light from previous bounce when capturing radiance. */
- if (pinfo->updated_bounce == 0) {
- /* But not on first bounce. */
- common_data->prb_num_render_grid = 0;
- }
- else {
- /* Remove bias */
- egrid->level_bias = (float)(1 << 0);
- DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
- }
- pinfo->vis_data.collection = prb->visibility_grp;
- pinfo->vis_data.invert = prb->flag & LIGHTPROBE_FLAG_INVERT_GROUP;
- render_scene_to_probe(sldata, vedata, pos, prb->clipsta, prb->clipend);
- diffuse_filter_probe(sldata, vedata, psl, egrid->offset + cell_id,
- prb->clipsta, prb->clipend, egrid->visibility_range, prb->vis_blur,
- prb->intensity);
- /* To see what is going on. */
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
- /* Restore */
- common_data->prb_num_render_cube = tmp_num_render_cube;
- pinfo->num_planar = tmp_num_planar;
- if (pinfo->updated_bounce == 0) {
- common_data->prb_num_render_grid = tmp_num_render_grid;
- }
- else {
- egrid->level_bias = tmp_level_bias;
- DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
- }
-#if 0
- printf("Updated Grid %d : cell %d / %d, bounce %d / %d\n",
- i, cell_id + 1, ped->num_cell, pinfo->updated_bounce + 1, pinfo->num_bounce);
-#endif
- }
- if (ped->updated_cells >= ped->num_cell) {
- ped->updated_lvl++;
- ped->updated_cells = 0;
- if (ped->updated_lvl > ped->max_lvl) {
- ped->need_update = false;
- }
- egrid->level_bias = (float)(1 << max_ii(0, ped->max_lvl - ped->updated_lvl + 1));
- DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
- }
- /* Only do one probe per frame */
- DRW_viewport_request_redraw();
- /* Do not let this frame accumulate. */
- stl->effects->taa_current_sample = 1;
- /* Reset volume history. */
- stl->effects->volume_current_sample = -1;
- common_data->vol_history_alpha = 0.0f;
- /* Restore matrices */
- DRW_viewport_matrix_override_set_all(&saved_mats);
- return;
- }
-
- pinfo->updated_bounce++;
- common_data->prb_num_render_grid = pinfo->num_grid;
-
- if (pinfo->updated_bounce < pinfo->num_bounce) {
- /* Retag all grids to update for next bounce */
- for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
- ped->need_update = true;
- ped->updated_cells = 0;
- ped->updated_lvl = 0;
- }
- /* Reset the next buffer so we can see the progress. */
- /* irradiance_rt is already the next rt because of the previous SWAP */
- GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
- GPU_framebuffer_bind(sldata->probe_filter_fb);
- DRW_draw_pass(psl->probe_grid_fill);
-
- GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
- /* Swap AFTER */
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
- }
- }
- /* Refresh cube probe when needed. */
- lightprobes_refresh_cube(sldata, vedata);
- /* Restore matrices */
- DRW_viewport_matrix_override_set_all(&saved_mats);
-}
-
-bool EEVEE_lightprobes_all_probes_ready(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata))
-{
- EEVEE_LightProbesInfo *pinfo = sldata->probes;
- EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
-
- return ((pinfo->do_cube_update == false) &&
- (pinfo->updated_bounce == pinfo->num_bounce) &&
- (common_data->prb_num_render_cube == pinfo->num_cube));
-}
-
void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
- EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
- EEVEE_LightProbesInfo *pinfo = sldata->probes;
-
- /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */
- common_data->spec_toggle = false;
- common_data->ssr_toggle = false;
- common_data->sss_toggle = false;
-
- /* Disable AO until we find a way to hide really bad discontinuities between cubefaces. */
- float tmp_ao_dist = common_data->ao_dist;
- float tmp_ao_settings = common_data->ao_settings;
- common_data->ao_settings = 0.0f;
- common_data->ao_dist = 0.0f;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
- /* Render world in priority */
- if (pinfo->update_world) {
- lightprobes_refresh_world(sldata, vedata);
- }
- else if (EEVEE_lightprobes_all_probes_ready(sldata, vedata) == false && pinfo->all_materials_updated) {
- lightprobes_refresh_all_no_world(sldata, vedata);
+ if (light_cache->flag & LIGHTCACHE_UPDATE_WORLD) {
+ DRWMatrixState saved_mats;
+ DRW_viewport_matrix_get_all(&saved_mats);
+ EEVEE_lightbake_update_world_quick(sldata, vedata, scene_eval);
+ DRW_viewport_matrix_override_set_all(&saved_mats);
}
-
- /* Restore */
- common_data->spec_toggle = true;
- common_data->ssr_toggle = true;
- common_data->sss_toggle = true;
- common_data->ao_dist = tmp_ao_dist;
- common_data->ao_settings = tmp_ao_settings;
}
void EEVEE_lightprobes_free(void)
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index 9214544fb17..0f0d9d281c9 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -148,7 +148,7 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_blur);
/* Compute adequate size for the octahedral map. */
- linfo->shadow_cube_store_size = (int)ceil(sqrt((sh_cube_size * sh_cube_size) * 6.0f));
+ linfo->shadow_cube_store_size = OCTAHEDRAL_SIZE_FROM_CUBESIZE(sh_cube_size);
CLAMP(linfo->shadow_cube_store_size, 1, 4096);
CLAMP(sh_cube_size, 1, 4096);
diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c
index 01599177fa4..2e568d97c07 100644
--- a/source/blender/draw/engines/eevee/eevee_lookdev.c
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -30,15 +30,31 @@
#include "DNA_screen_types.h"
#include "DNA_world_types.h"
+#include "DEG_depsgraph_query.h"
+
#include "ED_screen.h"
#include "eevee_private.h"
+#include "eevee_lightcache.h"
+
+static void eevee_lookdev_lightcache_delete(EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
+
+ MEM_SAFE_FREE(stl->lookdev_lightcache);
+ MEM_SAFE_FREE(stl->lookdev_grid_data);
+ MEM_SAFE_FREE(stl->lookdev_cube_data);
+ DRW_TEXTURE_FREE_SAFE(txl->lookdev_grid_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->lookdev_cube_tx);
+}
void EEVEE_lookdev_cache_init(
EEVEE_Data *vedata, DRWShadingGroup **grp, GPUShader *shader, DRWPass *pass,
World *world, EEVEE_LightProbesInfo *pinfo)
{
EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
const DRWContextState *draw_ctx = DRW_context_state_get();
View3D *v3d = draw_ctx->v3d;
if (LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d)) {
@@ -47,6 +63,43 @@ void EEVEE_lookdev_cache_init(
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
GPUTexture *tex = NULL;
+ /* If one of the component is missing we start from scratch. */
+ if ((stl->lookdev_grid_data == NULL) ||
+ (stl->lookdev_cube_data == NULL) ||
+ (txl->lookdev_grid_tx == NULL) ||
+ (txl->lookdev_cube_tx == NULL))
+ {
+ eevee_lookdev_lightcache_delete(vedata);
+ }
+
+ if (stl->lookdev_lightcache == NULL) {
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+#if defined(IRRADIANCE_SH_L2)
+ int grid_res = 4;
+#elif defined(IRRADIANCE_CUBEMAP)
+ int grid_res = 8;
+#elif defined(IRRADIANCE_HL2)
+ int grid_res = 4;
+#endif
+ int cube_res = OCTAHEDRAL_SIZE_FROM_CUBESIZE(scene_eval->eevee.gi_cubemap_resolution);
+ int vis_res = scene_eval->eevee.gi_visibility_resolution;
+
+ stl->lookdev_lightcache = EEVEE_lightcache_create(1, 1, cube_res, vis_res, (int[3]){grid_res, grid_res, 1});
+
+ /* We do this to use a special light cache for lookdev.
+ * This lightcache needs to be per viewport. But we need to
+ * have correct freeing when the viewport is closed. So we
+ * need to reference all textures to the txl and the memblocks
+ * to the stl. */
+ stl->lookdev_grid_data = stl->lookdev_lightcache->grid_data;
+ stl->lookdev_cube_data = stl->lookdev_lightcache->cube_data;
+ stl->lookdev_cube_mips = stl->lookdev_lightcache->cube_mips;
+ txl->lookdev_grid_tx = stl->lookdev_lightcache->grid_tx.tex;
+ txl->lookdev_cube_tx = stl->lookdev_lightcache->cube_tx.tex;
+ }
+
+ stl->g_data->light_cache = stl->lookdev_lightcache;
+
*grp = DRW_shgroup_create(shader, pass);
axis_angle_to_mat3_single(stl->g_data->studiolight_matrix, 'Z', v3d->shading.studiolight_rot_z);
DRW_shgroup_uniform_mat3(*grp, "StudioLightMatrix", stl->g_data->studiolight_matrix);
@@ -77,11 +130,9 @@ void EEVEE_lookdev_cache_init(
((pinfo->studiolight_index != sl->index) ||
(pinfo->studiolight_rot_z != v3d->shading.studiolight_rot_z)))
{
- pinfo->update_world |= PROBE_UPDATE_ALL;
+ stl->lookdev_lightcache->flag |= LIGHTCACHE_UPDATE_WORLD;
pinfo->studiolight_index = sl->index;
pinfo->studiolight_rot_z = v3d->shading.studiolight_rot_z;
- pinfo->prev_wo_sh_compiled = false;
- pinfo->prev_world = NULL;
}
}
}
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 4161d11e0c1..20d755d2245 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -362,6 +362,8 @@ static void add_standard_uniforms(
DRWShadingGroup *shgrp, EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
int *ssr_id, float *refract_depth, bool use_ssrefraction, bool use_alpha_blend)
{
+ LightCache *lcache = vedata->stl->g_data->light_cache;
+
if (ssr_id == NULL) {
static int no_ssr = -1.0f;
ssr_id = &no_ssr;
@@ -393,12 +395,12 @@ static void add_standard_uniforms(
/* TODO if diffuse bsdf */
if (true) {
- DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &sldata->irradiance_pool);
+ DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &lcache->grid_tx.tex);
}
/* TODO if glossy bsdf */
if (true) {
- DRW_shgroup_uniform_texture_ref(shgrp, "probeCubes", &sldata->probe_pool);
+ DRW_shgroup_uniform_texture_ref(shgrp, "probeCubes", &lcache->cube_tx.tex);
DRW_shgroup_uniform_texture_ref(shgrp, "probePlanars", &vedata->txl->planar_pool);
DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1);
}
@@ -654,14 +656,14 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, Wor
const void *engine = &DRW_engine_viewport_eevee_type;
const int options = VAR_WORLD_PROBE;
- GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, false);
if (mat != NULL) {
return mat;
}
return DRW_shader_create_from_world(
scene, wo, engine, options,
datatoc_background_vert_glsl, NULL, e_data.frag_shader_lib,
- SHADER_DEFINES "#define PROBE_CAPTURE\n");
+ SHADER_DEFINES "#define PROBE_CAPTURE\n", false);
}
struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, World *wo)
@@ -669,14 +671,14 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor
const void *engine = &DRW_engine_viewport_eevee_type;
int options = VAR_WORLD_BACKGROUND;
- GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, true);
if (mat != NULL) {
return mat;
}
return DRW_shader_create_from_world(
scene, wo, engine, options,
datatoc_background_vert_glsl, NULL, e_data.frag_shader_lib,
- SHADER_DEFINES "#define WORLD_BACKGROUND\n");
+ SHADER_DEFINES "#define WORLD_BACKGROUND\n", true);
}
struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *wo)
@@ -684,7 +686,7 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *
const void *engine = &DRW_engine_viewport_eevee_type;
int options = VAR_WORLD_VOLUME;
- GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, true);
if (mat != NULL) {
return mat;
}
@@ -694,7 +696,7 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *
mat = DRW_shader_create_from_world(
scene, wo, engine, options,
datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, e_data.volume_shader_lib,
- defines);
+ defines, true);
MEM_freeN(defines);
@@ -719,7 +721,7 @@ struct GPUMaterial *EEVEE_material_mesh_get(
options |= eevee_material_shadow_option(shadow_method);
- GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
if (mat) {
return mat;
}
@@ -729,7 +731,7 @@ struct GPUMaterial *EEVEE_material_mesh_get(
mat = DRW_shader_create_from_material(
scene, ma, engine, options,
e_data.vert_shader_str, NULL, e_data.frag_shader_lib,
- defines);
+ defines, true);
MEM_freeN(defines);
@@ -741,7 +743,7 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material
const void *engine = &DRW_engine_viewport_eevee_type;
int options = VAR_MAT_VOLUME;
- GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
if (mat != NULL) {
return mat;
}
@@ -751,7 +753,7 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material
mat = DRW_shader_create_from_material(
scene, ma, engine, options,
datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, e_data.volume_shader_lib,
- defines);
+ defines, true);
MEM_freeN(defines);
@@ -775,7 +777,7 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(
if (is_shadow)
options |= VAR_MAT_SHADOW;
- GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
if (mat) {
return mat;
}
@@ -791,7 +793,8 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(
(is_shadow) ? datatoc_shadow_vert_glsl : e_data.vert_shader_str,
NULL,
frag_str,
- defines);
+ defines,
+ true);
MEM_freeN(frag_str);
MEM_freeN(defines);
@@ -807,7 +810,7 @@ struct GPUMaterial *EEVEE_material_hair_get(
options |= eevee_material_shadow_option(shadow_method);
- GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
if (mat) {
return mat;
}
@@ -817,7 +820,7 @@ struct GPUMaterial *EEVEE_material_hair_get(
mat = DRW_shader_create_from_material(
scene, ma, engine, options,
e_data.vert_shader_str, NULL, e_data.frag_shader_lib,
- defines);
+ defines, true);
MEM_freeN(defines);
@@ -971,7 +974,6 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_call_add(grp, geom, NULL);
break;
case GPU_MAT_QUEUED:
- sldata->probes->all_materials_updated = false;
/* TODO Bypass probe compilation. */
col = compile_col;
break;
@@ -1228,7 +1230,6 @@ static void material_opaque(
}
case GPU_MAT_QUEUED:
{
- sldata->probes->all_materials_updated = false;
/* TODO Bypass probe compilation. */
color_p = compile_col;
metal_p = spec_p = rough_p = &half;
@@ -1315,7 +1316,6 @@ static void material_transparent(
}
case GPU_MAT_QUEUED:
{
- sldata->probes->all_materials_updated = false;
/* TODO Bypass probe compilation. */
color_p = compile_col;
metal_p = spec_p = rough_p = &half;
@@ -1645,7 +1645,6 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata,
}
case GPU_MAT_QUEUED:
{
- sldata->probes->all_materials_updated = false;
color_p = compile_col;
metal_p = spec_p = rough_p = &half;
break;
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index ef1d03c244e..e2a875dca1f 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -26,11 +26,14 @@
#ifndef __EEVEE_PRIVATE_H__
#define __EEVEE_PRIVATE_H__
+#include "DNA_lightprobe_types.h"
+
struct Object;
struct EEVEE_BoundSphere;
struct EEVEE_ShadowCasterBuffer;
struct RenderLayer;
struct RenderResult;
+struct GPUFrameBuffer;
extern struct DrawEngineType draw_engine_eevee_type;
@@ -98,6 +101,10 @@ extern struct DrawEngineType draw_engine_eevee_type;
#define USE_SCENE_LIGHT(v3d) ((!v3d) || (!LOOK_DEV_MODE_ENABLED(v3d)) || ((LOOK_DEV_MODE_ENABLED(v3d) && (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS))))
#define LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d) (LOOK_DEV_MODE_ENABLED(v3d) && !(v3d->shading.flag & V3D_SHADING_SCENE_WORLD))
+#define OCTAHEDRAL_SIZE_FROM_CUBESIZE(cube_size) ((int)ceilf(sqrtf((cube_size * cube_size) * 6.0f)))
+#define MIN_CUBE_LOD_LEVEL 3
+#define MAX_PLANAR_LOD_LEVEL 9
+
/* World shader variations */
enum {
VAR_WORLD_BACKGROUND = 0,
@@ -132,6 +139,27 @@ enum {
VAR_MAT_SSSALBED = (1 << 17),
};
+/* ************ PROBE UBO ************* */
+
+/* They are the same struct as their Cache siblings.
+ * typedef'ing just to keep the naming consistent with
+ * other eevee types. */
+typedef LightProbeCache EEVEE_LightProbe;
+typedef LightGridCache EEVEE_LightGrid;
+
+typedef struct EEVEE_PlanarReflection {
+ float plane_equation[4];
+ float clip_vec_x[3], attenuation_scale;
+ float clip_vec_y[3], attenuation_bias;
+ float clip_edge_x_pos, clip_edge_x_neg;
+ float clip_edge_y_pos, clip_edge_y_neg;
+ float facing_scale, facing_bias, clipsta, pad;
+ float reflectionmat[4][4]; /* Used for sampling the texture. */
+ float mtx[4][4]; /* Not used in shader. TODO move elsewhere. */
+} EEVEE_PlanarReflection;
+
+/* --------------------------------------- */
+
typedef struct EEVEE_BoundSphere {
float center[3], radius;
} EEVEE_BoundSphere;
@@ -272,6 +300,9 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *volume_scatter_history;
struct GPUTexture *volume_transmittance_history;
+ struct GPUTexture *lookdev_grid_tx;
+ struct GPUTexture *lookdev_cube_tx;
+
struct GPUTexture *planar_pool;
struct GPUTexture *planar_depth;
@@ -288,6 +319,10 @@ typedef struct EEVEE_StorageList {
struct EEVEE_PrivateData *g_data;
+ struct LightCache *lookdev_lightcache;
+ EEVEE_LightProbe *lookdev_cube_data;
+ EEVEE_LightGrid *lookdev_grid_data;
+ LightCacheTexture *lookdev_cube_mips;
} EEVEE_StorageList;
/* ************ LIGHT UBO ************* */
@@ -392,42 +427,11 @@ enum {
LIGHT_UPDATE_SHADOW_CUBE = (1 << 0),
};
-/* ************ PROBE UBO ************* */
-typedef struct EEVEE_LightProbe {
- float position[3], parallax_type;
- float attenuation_fac;
- float attenuation_type;
- float pad3[2];
- float attenuationmat[4][4];
- float parallaxmat[4][4];
-} EEVEE_LightProbe;
-
-typedef struct EEVEE_LightGrid {
- float mat[4][4];
- int resolution[3], offset;
- float corner[3], attenuation_scale;
- float increment_x[3], attenuation_bias; /* world space vector between 2 opposite cells */
- float increment_y[3], level_bias;
- float increment_z[3], pad4;
- float visibility_bias, visibility_bleed, visibility_range, pad5;
-} EEVEE_LightGrid;
-
-typedef struct EEVEE_PlanarReflection {
- float plane_equation[4];
- float clip_vec_x[3], attenuation_scale;
- float clip_vec_y[3], attenuation_bias;
- float clip_edge_x_pos, clip_edge_x_neg;
- float clip_edge_y_pos, clip_edge_y_neg;
- float facing_scale, facing_bias, pad[2];
- float reflectionmat[4][4];
-} EEVEE_PlanarReflection;
-
/* ************ PROBE DATA ************* */
-
typedef struct EEVEE_LightProbeVisTest {
+ struct Collection *collection; /* Skip test if NULL */
bool invert;
bool cached; /* Reuse last test results */
- struct Collection *collection; /* Skip test if NULL */
} EEVEE_LightProbeVisTest;
typedef struct EEVEE_LightProbesInfo {
@@ -440,13 +444,9 @@ typedef struct EEVEE_LightProbesInfo {
int updated_bounce;
int num_bounce;
int cubemap_res;
- int target_size;
- int grid_initialized;
- struct World *prev_world;
- int update_world;
- bool prev_wo_sh_compiled;
+ /* Update */
bool do_cube_update;
- bool all_materials_updated;
+ bool do_grid_update;
/* For rendering probes */
float probemat[6][4][4];
int layer;
@@ -465,15 +465,11 @@ typedef struct EEVEE_LightProbesInfo {
int shres;
int studiolight_index;
float studiolight_rot_z;
- /* List of probes in the scene. */
- /* XXX This is fragile, can get out of sync quickly. */
- struct Object *probes_cube_ref[MAX_PROBE];
- struct Object *probes_grid_ref[MAX_GRID];
- struct Object *probes_planar_ref[MAX_PLANAR];
+ EEVEE_LightProbeVisTest planar_vis_tests[MAX_PLANAR];
/* UBO Storage : data used by UBO */
- struct EEVEE_LightProbe probe_data[MAX_PROBE];
- struct EEVEE_LightGrid grid_data[MAX_GRID];
- struct EEVEE_PlanarReflection planar_data[MAX_PLANAR];
+ EEVEE_LightProbe probe_data[MAX_PROBE];
+ EEVEE_LightGrid grid_data[MAX_GRID];
+ EEVEE_PlanarReflection planar_data[MAX_PLANAR];
/* Probe Visibility Collection */
EEVEE_LightProbeVisTest vis_data;
} EEVEE_LightProbesInfo;
@@ -673,24 +669,18 @@ typedef struct EEVEE_ViewLayerData {
struct GPUUniformBuffer *grid_ubo;
struct GPUUniformBuffer *planar_ubo;
- struct GPUFrameBuffer *probe_filter_fb;
- struct GPUFrameBuffer *probe_face_fb[6];
-
- struct GPUTexture *probe_rt;
- struct GPUTexture *probe_depth_rt;
- struct GPUTexture *probe_pool;
- struct GPUTexture *irradiance_pool;
- struct GPUTexture *irradiance_rt;
-
/* Common Uniform Buffer */
struct EEVEE_CommonUniformBuffer common_data;
struct GPUUniformBuffer *common_ubo;
struct EEVEE_ClipPlanesUniformBuffer clip_data;
struct GPUUniformBuffer *clip_ubo;
+
+ struct LightCache *fallback_lightcache;
} EEVEE_ViewLayerData;
/* ************ OBJECT DATA ************ */
+
typedef struct EEVEE_LightData {
short light_id, shadow_id;
} EEVEE_LightData;
@@ -711,7 +701,7 @@ typedef struct EEVEE_ShadowCascadeData {
* It works with even if the object is in multiple layers
* because we don't get the same "Object *" for each layer. */
typedef struct EEVEE_LampEngineData {
- ObjectEngineData engine_data;
+ DrawData dd;
bool need_update;
/* This needs to be out of the union to avoid undefined behaviour. */
@@ -724,35 +714,13 @@ typedef struct EEVEE_LampEngineData {
} EEVEE_LampEngineData;
typedef struct EEVEE_LightProbeEngineData {
- ObjectEngineData engine_data;
-
- /* NOTE: need_full_update is set by dependency graph when the probe or it's
- * object is updated. This triggers full probe update, including it's
- * "progressive" GI refresh.
- *
- * need_update is always set to truth when need_full_update is tagged, but
- * might also be forced to be kept truth during GI refresh stages.
- *
- * TODO(sergey): Is there a way to avoid two flags here, or at least make
- * it more clear what's going on here?
- */
- bool need_full_update;
- bool need_update;
+ DrawData dd;
- bool ready_to_shade;
- int updated_cells;
- int updated_lvl;
- int num_cell;
- int max_lvl;
- int probe_id; /* Only used for display data */
- float probe_size; /* Only used for display data */
- DRWMatrixState mats; /* For planar probes */
- float planer_eq_offset[4];
- struct ListBase captured_object_list;
+ bool need_update;
} EEVEE_LightProbeEngineData;
typedef struct EEVEE_ObjectEngineData {
- ObjectEngineData engine_data;
+ DrawData dd;
Object *ob; /* self reference */
EEVEE_LightProbeVisTest *test_data;
@@ -762,6 +730,10 @@ typedef struct EEVEE_ObjectEngineData {
uint shadow_caster_id;
} EEVEE_ObjectEngineData;
+typedef struct EEVEE_WorldEngineData {
+ DrawData dd;
+} EEVEE_WorldEngineData;
+
/* *********************************** */
typedef struct EEVEE_Data {
@@ -786,6 +758,8 @@ typedef struct EEVEE_PrivateData {
struct DRWShadingGroup *planar_display_shgrp;
struct GHash *material_hash;
float background_alpha; /* TODO find a better place for this. */
+ /* Chosen lightcache: can come from Lookdev or the viewlayer. */
+ struct LightCache *light_cache;
/* For planar probes */
float planar_texel_size[2];
/* For double buffering */
@@ -803,6 +777,7 @@ typedef struct EEVEE_PrivateData {
/* eevee_data.c */
EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void);
+EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure_ex(struct ViewLayer *view_layer);
EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void);
EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob);
EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob);
@@ -810,6 +785,8 @@ EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob);
EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob);
EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob);
EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob);
+EEVEE_WorldEngineData *EEVEE_world_data_get(World *wo);
+EEVEE_WorldEngineData *EEVEE_world_data_ensure(World *wo);
/* eevee_materials.c */
struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */
@@ -849,17 +826,37 @@ void EEVEE_lights_update(EEVEE_ViewLayerData *sldata);
void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl);
void EEVEE_lights_free(void);
+
/* eevee_lightprobes.c */
bool EEVEE_lightprobes_obj_visibility_cb(bool vis_in, void *user_data);
-bool EEVEE_lightprobes_all_probes_ready(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob);
+void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *ob);
void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lightprobes_free(void);
+void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, GPUTexture *rt_color, GPUTexture *rt_depth);
+void EEVEE_lightbake_render_world(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUFrameBuffer *face_fb[6]);
+void EEVEE_lightbake_render_scene(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUFrameBuffer *face_fb[6],
+ const float pos[3], float near_clip, float far_clip);
+void EEVEE_lightbake_filter_glossy(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUTexture *rt_color, struct GPUFrameBuffer *fb,
+ int probe_idx, float intensity, int maxlevel);
+void EEVEE_lightbake_filter_diffuse(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUTexture *rt_color, struct GPUFrameBuffer *fb,
+ int grid_offset, float intensity);
+void EEVEE_lightbake_filter_visibility(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUTexture *rt_depth, struct GPUFrameBuffer *fb,
+ int grid_offset, float clipsta, float clipend, float vis_range, float vis_blur, int vis_size);
+
+void EEVEE_lightprobes_grid_data_from_object(Object *ob, EEVEE_LightGrid *prb_data, int *offset);
+void EEVEE_lightprobes_cube_data_from_object(Object *ob, EEVEE_LightProbe *prb_data);
+void EEVEE_lightprobes_planar_data_from_object(Object *ob, EEVEE_PlanarReflection *eplanar, EEVEE_LightProbeVisTest *vis_test);
+
/* eevee_depth_of_field.c */
int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera);
void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
@@ -948,6 +945,9 @@ void EEVEE_render_update_passes(struct RenderEngine *engine, struct Scene *scene
void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, DRWShadingGroup **grp, GPUShader *shader, DRWPass *pass, struct World *world, EEVEE_LightProbesInfo *pinfo);
void EEVEE_lookdev_draw_background(EEVEE_Data *vedata);
+/** eevee_engine.c */
+void EEVEE_cache_populate(void *vedata, Object *ob);
+
/* Shadow Matrix */
static const float texcomat[4][4] = { /* From NDC to TexCo */
{0.5f, 0.0f, 0.0f, 0.0f},
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index c650a6945ac..bc1bd97bdde 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -134,17 +134,31 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
EEVEE_volumes_cache_init(sldata, vedata);
}
+/* Used by light cache. in this case engine is NULL. */
void EEVEE_render_cache(
void *vedata, struct Object *ob,
struct RenderEngine *engine, struct Depsgraph *UNUSED(depsgraph))
{
EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
-
- char info[42];
- BLI_snprintf(info, sizeof(info), "Syncing %s", ob->id.name + 2);
- RE_engine_update_stats(engine, NULL, info);
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
bool cast_shadow = false;
+ if (pinfo->vis_data.collection) {
+ /* Used for rendering probe with visibility groups. */
+ bool ob_vis = BKE_collection_has_object_recursive(pinfo->vis_data.collection, ob);
+ ob_vis = (pinfo->vis_data.invert) ? !ob_vis : ob_vis;
+
+ if (!ob_vis) {
+ return;
+ }
+ }
+
+ if (engine) {
+ char info[42];
+ BLI_snprintf(info, sizeof(info), "Syncing %s", ob->id.name + 2);
+ RE_engine_update_stats(engine, NULL, info);
+ }
+
if (ob->base_flag & BASE_VISIBLE) {
EEVEE_hair_cache_populate(vedata, sldata, ob, &cast_shadow);
}
@@ -154,7 +168,7 @@ void EEVEE_render_cache(
EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow);
}
else if (ob->type == OB_LIGHTPROBE) {
- EEVEE_lightprobes_cache_add(sldata, ob);
+ EEVEE_lightprobes_cache_add(sldata, vedata, ob);
}
else if (ob->type == OB_LAMP) {
EEVEE_lights_cache_add(sldata, ob);
@@ -477,14 +491,8 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
DRW_viewport_matrix_override_set(g_data->viewinv, DRW_MAT_VIEWINV);
/* Refresh Probes */
- while (EEVEE_lightprobes_all_probes_ready(sldata, vedata) == false) {
- RE_engine_update_stats(engine, NULL, "Updating Probes");
- EEVEE_lightprobes_refresh(sldata, vedata);
- /* Refreshing probes can take some times, allow exit. */
- if (RE_engine_test_break(engine)) {
- return;
- }
- }
+ RE_engine_update_stats(engine, NULL, "Updating Probes");
+ EEVEE_lightprobes_refresh(sldata, vedata);
EEVEE_lightprobes_refresh_planar(sldata, vedata);
DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index 74760b9c828..ef949c32eed 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -187,6 +187,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
EEVEE_StorageList *stl = vedata->stl;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_EffectsInfo *effects = stl->effects;
+ LightCache *lcache = stl->g_data->light_cache;
struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
@@ -230,7 +231,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input);
DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input);
- DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &sldata->probe_pool);
+ DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex);
DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &vedata->txl->planar_pool);
DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &vedata->txl->planar_depth);
DRW_shgroup_uniform_texture_ref(grp, "hitBuffer", &effects->ssr_hit_output);
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index 560f898b275..d0cea65d05e 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -349,6 +349,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_StorageList *stl = vedata->stl;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_EffectsInfo *effects = stl->effects;
+ LightCache *lcache = stl->g_data->light_cache;
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
@@ -417,7 +418,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
psl->volumetric_scatter_ps = DRW_pass_create("Volumetric Scattering", DRW_STATE_WRITE_COLOR);
grp = DRW_shgroup_empty_tri_batch_create(scatter_sh, psl->volumetric_scatter_ps,
common_data->vol_tex_size[2]);
- DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &sldata->irradiance_pool);
+ DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &lcache->grid_tx.tex);
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_prop_scattering);
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl
index d10f4bc0d42..5a72244cfbe 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl
@@ -1,15 +1,18 @@
flat in int pid;
-in vec3 worldNormal;
-in vec3 worldPosition;
+in vec2 quadCoord;
out vec4 FragColor;
void main()
{
- vec3 V = (ProjectionMatrix[3][3] == 0.0) /* if perspective */
- ? normalize(cameraPos - worldPosition)
- : cameraForward;
- vec3 N = normalize(worldNormal);
- FragColor = vec4(textureLod_octahedron(probeCubes, vec4(reflect(-V, N), pid), 0.0, prbLodCubeMax).rgb, 1.0);
+ float dist_sqr = dot(quadCoord, quadCoord);
+
+ /* Discard outside the circle. */
+ if (dist_sqr > 1.0)
+ discard;
+
+ vec3 view_nor = vec3(quadCoord, sqrt(max(0.0, 1.0 - dist_sqr)));
+ vec3 world_ref = mat3(ViewMatrixInverse) * reflect(vec3(0.0, 0.0, -1.0), view_nor);
+ FragColor = vec4(textureLod_octahedron(probeCubes, vec4(world_ref, pid), 0.0, prbLodCubeMax).rgb, 1.0);
}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl
index b0a6cbe1707..b327878b63d 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl
@@ -1,26 +1,43 @@
-in vec3 pos;
+/* XXX TODO fix code duplication */
+struct CubeData {
+ vec4 position_type;
+ vec4 attenuation_fac_type;
+ mat4 influencemat;
+ mat4 parallaxmat;
+};
-/* Instance attrib */
-in int probe_id;
-in vec3 probe_location;
-in float sphere_size;
+layout(std140) uniform probe_block {
+ CubeData probes_data[MAX_PROBE];
+};
+
+uniform float sphere_size;
+uniform vec3 screen_vecs[2];
flat out int pid;
-out vec3 worldNormal;
-out vec3 worldPosition;
+out vec2 quadCoord;
+
+const vec2 pos[6] = vec2[6](
+ vec2(-1.0, -1.0),
+ vec2( 1.0, -1.0),
+ vec2(-1.0, 1.0),
+
+ vec2( 1.0, -1.0),
+ vec2( 1.0, 1.0),
+ vec2(-1.0, 1.0)
+);
void main()
{
- pid = probe_id;
+ pid = 1 + (gl_VertexID / 6); /* +1 for the world */
+ int vert_id = gl_VertexID % 6;
+
+ quadCoord = pos[vert_id];
- /* While this is not performant, we do this to
- * match the object mode engine instancing shader. */
- mat4 offsetmat = mat4(1.0); /* Identity */
- offsetmat[3].xyz = probe_location;
+ vec3 ws_location = probes_data[pid].position_type.xyz;
+ vec3 screen_pos = screen_vecs[0] * quadCoord.x + screen_vecs[1] * quadCoord.y;
+ ws_location += screen_pos * sphere_size;
- vec4 wpos = offsetmat * vec4(pos * sphere_size, 1.0);
- worldPosition = wpos.xyz;
- gl_Position = ViewProjectionMatrix * wpos;
- worldNormal = normalize(pos);
+ gl_Position = ViewProjectionMatrix * vec4(ws_location, 1.0);
+ gl_Position.z += 0.0001; /* Small bias to let the icon draw without zfighting */
}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_frag.glsl
index d333ad34bb0..fd8eb157aa5 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_frag.glsl
@@ -1,11 +1,19 @@
flat in int cellOffset;
-in vec3 worldNormal;
+in vec2 quadCoord;
out vec4 FragColor;
void main()
{
- IrradianceData ir_data = load_irradiance_cell(cellOffset, worldNormal);
- FragColor = vec4(compute_irradiance(worldNormal, ir_data), 1.0);
+ float dist_sqr = dot(quadCoord, quadCoord);
+
+ /* Discard outside the circle. */
+ if (dist_sqr > 1.0)
+ discard;
+
+ vec3 view_nor = vec3(quadCoord, sqrt(max(0.0, 1.0 - dist_sqr)));
+ vec3 world_nor = mat3(ViewMatrixInverse) * view_nor;
+ IrradianceData ir_data = load_irradiance_cell(cellOffset, world_nor);
+ FragColor = vec4(compute_irradiance(world_nor, ir_data), 1.0);
}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl
index a017a791e41..7a92b55e530 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl
@@ -1,6 +1,4 @@
-in vec3 pos;
-
uniform float sphere_size;
uniform int offset;
uniform ivec3 grid_resolution;
@@ -8,25 +6,44 @@ uniform vec3 corner;
uniform vec3 increment_x;
uniform vec3 increment_y;
uniform vec3 increment_z;
+uniform vec3 screen_vecs[2];
flat out int cellOffset;
-out vec3 worldNormal;
+out vec2 quadCoord;
+
+const vec2 pos[6] = vec2[6](
+ vec2(-1.0, -1.0),
+ vec2( 1.0, -1.0),
+ vec2(-1.0, 1.0),
+
+ vec2( 1.0, -1.0),
+ vec2( 1.0, 1.0),
+ vec2(-1.0, 1.0)
+);
void main()
{
+ int cell_id = gl_VertexID / 6;
+ int vert_id = gl_VertexID % 6;
+
vec3 ls_cell_location;
/* Keep in sync with update_irradiance_probe */
- ls_cell_location.z = float(gl_InstanceID % grid_resolution.z);
- ls_cell_location.y = float((gl_InstanceID / grid_resolution.z) % grid_resolution.y);
- ls_cell_location.x = float(gl_InstanceID / (grid_resolution.z * grid_resolution.y));
+ ls_cell_location.z = float(cell_id % grid_resolution.z);
+ ls_cell_location.y = float((cell_id / grid_resolution.z) % grid_resolution.y);
+ ls_cell_location.x = float(cell_id / (grid_resolution.z * grid_resolution.y));
- cellOffset = offset + gl_InstanceID;
+ cellOffset = offset + cell_id;
vec3 ws_cell_location = corner +
(increment_x * ls_cell_location.x +
increment_y * ls_cell_location.y +
increment_z * ls_cell_location.z);
- gl_Position = ViewProjectionMatrix * vec4(pos * 0.02 * sphere_size + ws_cell_location, 1.0);
- worldNormal = normalize(pos);
+
+ quadCoord = pos[vert_id];
+ vec3 screen_pos = screen_vecs[0] * quadCoord.x + screen_vecs[1] * quadCoord.y;
+ ws_cell_location += screen_pos * sphere_size;
+
+ gl_Position = ViewProjectionMatrix * vec4(ws_cell_location , 1.0);
+ gl_Position.z += 0.0001; /* Small bias to let the icon draw without zfighting */
}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
index 0ffc0cc4b49..6ae13e0102d 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
@@ -27,6 +27,7 @@ struct PlanarData {
vec4 clip_edges;
vec4 facing_scale_bias;
mat4 reflectionmat; /* transform world space into reflection texture space */
+ mat4 unused;
};
#define pl_plane_eq plane_equation
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
index 644b449c03e..22194c22f39 100644
--- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
@@ -256,7 +256,7 @@ void CLOSURE_NAME(
PlanarData pd = planars_data[i];
/* Fade on geometric normal. */
- float fade = probe_attenuation_planar(pd, worldPosition, worldNormal, roughness);
+ float fade = probe_attenuation_planar(pd, worldPosition, (gl_FrontFacing) ? worldNormal : -worldNormal, roughness);
if (fade > 0.0) {
if (!(ssrToggle && ssr_id == outputSsrId)) {
@@ -404,7 +404,7 @@ void CLOSURE_NAME(
spec_occlu = 1.0;
}
- out_spec += spec_accum.rgb * ssr_spec * spec_occlu * float(specToggle);
+ out_spec += spec_accum.rgb * ssr_spec * spec_occlu;
#endif
#ifdef CLOSURE_REFRACTION
@@ -419,7 +419,12 @@ void CLOSURE_NAME(
vec2 C_brdf_lut = texture(utilTex, vec3(C_uv, 1.0)).rg;
vec3 C_fresnel = F_ibl(vec3(0.04), brdf_lut) * specular_occlusion(NV, final_ao, C_roughness);
- out_spec += C_spec_accum.rgb * C_fresnel * float(specToggle) * C_intensity;
+ out_spec += C_spec_accum.rgb * C_fresnel * C_intensity;
+#endif
+
+#ifdef CLOSURE_GLOSSY
+ /* Global toggle for lightprobe baking. */
+ out_spec *= float(specToggle);
#endif
/* ---------------------------------------------------------------- */
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index d153728a000..784ed861014 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -258,9 +258,9 @@ static struct GPUTexture *create_jitter_texture(int num_samples)
/* Functions */
-static void workbench_init_object_data(ObjectEngineData *engine_data)
+static void workbench_init_object_data(DrawData *dd)
{
- WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)engine_data;
+ WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
data->shadow_bbox_dirty = true;
}
@@ -561,8 +561,8 @@ static WORKBENCH_MaterialData *get_or_create_material_data(
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_PrivateData *wpd = stl->g_data;
WORKBENCH_MaterialData *material;
- WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_object_engine_data_ensure(
- ob, &draw_engine_workbench_solid, sizeof(WORKBENCH_ObjectData), &workbench_init_object_data, NULL);
+ WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
+ &ob->id, &draw_engine_workbench_solid, sizeof(WORKBENCH_ObjectData), &workbench_init_object_data, NULL);
WORKBENCH_MaterialData material_template;
/* Solid */
@@ -731,8 +731,8 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
// DRW_shgroup_call_sculpt_add(wpd->shadow_shgrp, ob, ob->obmat);
}
else {
- WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_object_engine_data_ensure(
- ob, &draw_engine_workbench_solid, sizeof(WORKBENCH_ObjectData), &workbench_init_object_data, NULL);
+ WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
+ &ob->id, &draw_engine_workbench_solid, sizeof(WORKBENCH_ObjectData), &workbench_init_object_data, NULL);
if (studiolight_object_cast_visible_shadow(wpd, ob, engine_object_data)) {
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
index 76172443c2d..b03a0d67a22 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -126,9 +126,9 @@ static char *workbench_build_forward_composite_frag(void)
return str;
}
-static void workbench_init_object_data(ObjectEngineData *engine_data)
+static void workbench_init_object_data(DrawData *dd)
{
- WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)engine_data;
+ WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
}
@@ -139,8 +139,8 @@ static WORKBENCH_MaterialData *get_or_create_material_data(
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_PrivateData *wpd = stl->g_data;
WORKBENCH_MaterialData *material;
- WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_object_engine_data_ensure(
- ob, &draw_engine_workbench_solid, sizeof(WORKBENCH_ObjectData), &workbench_init_object_data, NULL);
+ WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
+ &ob->id, &draw_engine_workbench_solid, sizeof(WORKBENCH_ObjectData), &workbench_init_object_data, NULL);
WORKBENCH_MaterialData material_template;
DRWShadingGroup *grp;
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index a8fa1beb3b7..4210e03f470 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -201,12 +201,8 @@ typedef struct WORKBENCH_MaterialData {
} WORKBENCH_MaterialData;
typedef struct WORKBENCH_ObjectData {
- struct ObjectEngineData *next, *prev;
- struct DrawEngineType *engine_type;
- /* Only nested data, NOT the engine data itself. */
- ObjectEngineDataFreeCb free;
- /* Accumulated recalc flags, which corresponds to ID->recalc flags. */
- int recalc;
+ DrawData dd;
+
/* Shadow direction in local object space. */
float shadow_dir[3], shadow_depth;
float shadow_min[3], shadow_max[3]; /* Min, max in shadow space */
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index f732082018d..4d1b8269494 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -44,6 +44,7 @@
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_scene_types.h"
+#include "DNA_world_types.h"
#include "GPU_framebuffer.h"
#include "GPU_texture.h"
@@ -239,14 +240,14 @@ struct GPUShader *DRW_shader_create_2D(const char *frag, const char *defines);
struct GPUShader *DRW_shader_create_3D(const char *frag, const char *defines);
struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines);
struct GPUShader *DRW_shader_create_3D_depth_only(void);
-struct GPUMaterial *DRW_shader_find_from_world(struct World *wo, const void *engine_type, int options);
-struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma, const void *engine_type, int options);
+struct GPUMaterial *DRW_shader_find_from_world(struct World *wo, const void *engine_type, int options, bool no_deferred);
+struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma, const void *engine_type, int options, bool no_deferred);
struct GPUMaterial *DRW_shader_create_from_world(
struct Scene *scene, struct World *wo, const void *engine_type, int options,
- const char *vert, const char *geom, const char *frag_lib, const char *defines);
+ const char *vert, const char *geom, const char *frag_lib, const char *defines, bool no_deferred);
struct GPUMaterial *DRW_shader_create_from_material(
struct Scene *scene, struct Material *ma, const void *engine_type, int options,
- const char *vert, const char *geom, const char *frag_lib, const char *defines);
+ const char *vert, const char *geom, const char *frag_lib, const char *defines, bool no_deferred);
void DRW_shader_free(struct GPUShader *shader);
#define DRW_SHADER_FREE_SAFE(shader) do { \
if (shader != NULL) { \
@@ -409,6 +410,7 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass);
/* Viewport */
typedef enum {
+ /* keep in sync with the union struct DRWMatrixState. */
DRW_MAT_PERS = 0,
DRW_MAT_PERSINV,
DRW_MAT_VIEW,
@@ -420,7 +422,18 @@ typedef enum {
} DRWViewportMatrixType;
typedef struct DRWMatrixState {
- float mat[DRW_MAT_COUNT][4][4];
+ union {
+ float mat[DRW_MAT_COUNT][4][4];
+ struct {
+ /* keep in sync with the enum DRWViewportMatrixType. */
+ float persmat[4][4];
+ float persinv[4][4];
+ float viewmat[4][4];
+ float viewinv[4][4];
+ float winmat[4][4];
+ float wininv[4][4];
+ };
+ };
} DRWMatrixState;
void DRW_viewport_init(const bContext *C);
@@ -453,6 +466,12 @@ void DRW_render_object_iter(
void (*callback)(void *vedata, struct Object *ob, struct RenderEngine *engine, struct Depsgraph *depsgraph));
void DRW_render_instance_buffer_finish(void);
+void DRW_custom_pipeline(
+ DrawEngineType *draw_engine_type,
+ struct Depsgraph *depsgraph,
+ void (*callback)(void *vedata, void *user_data),
+ void *user_data);
+
/* ViewLayers */
void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type);
void **DRW_view_layer_engine_data_ensure_ex(
@@ -460,16 +479,14 @@ void **DRW_view_layer_engine_data_ensure_ex(
void **DRW_view_layer_engine_data_ensure(
DrawEngineType *engine_type, void (*callback)(void *storage));
-/* Objects */
-ObjectEngineData *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type);
-ObjectEngineData *DRW_object_engine_data_ensure(
- Object *ob,
+/* DrawData */
+DrawData *DRW_drawdata_get(ID *ib, DrawEngineType *engine_type);
+DrawData *DRW_drawdata_ensure(
+ ID *id,
DrawEngineType *engine_type,
size_t size,
- ObjectEngineDataInitCb init_cb,
- ObjectEngineDataFreeCb free_cb);
-struct LampEngineData *DRW_lamp_engine_data_ensure(Object *ob, struct RenderEngineType *engine_type);
-void DRW_lamp_engine_data_free(struct LampEngineData *led);
+ DrawDataInitCb init_cb,
+ DrawDataFreeCb free_cb);
/* Settings */
bool DRW_object_is_renderable(struct Object *ob);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index a1e44e479d4..30f7742fd35 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -44,6 +44,7 @@
#include "DNA_camera_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_world_types.h"
#include "ED_space_api.h"
#include "ED_screen.h"
@@ -696,34 +697,96 @@ void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*cal
/* -------------------------------------------------------------------- */
-/** \name Objects (DRW_object)
+/** \name Draw Data (DRW_drawdata)
* \{ */
-ObjectEngineData *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type)
+/* Used for DRW_drawdata_from_id()
+ * All ID-datablocks which have their own 'local' DrawData
+ * should have the same arrangement in their structs.
+ */
+typedef struct IdDdtTemplate {
+ ID id;
+ struct AnimData *adt;
+ DrawDataList drawdata;
+} IdDdtTemplate;
+
+/* Check if ID can have AnimData */
+static bool id_type_can_have_drawdata(const short id_type)
+{
+ /* Only some ID-blocks have this info for now */
+ /* TODO: finish adding this for the other blocktypes */
+ switch (id_type) {
+ /* has DrawData */
+ case ID_OB:
+ case ID_WO:
+ return true;
+
+ /* no DrawData */
+ default:
+ return false;
+ }
+}
+
+static bool id_can_have_drawdata(const ID *id)
+{
+ /* sanity check */
+ if (id == NULL)
+ return false;
+
+ return id_type_can_have_drawdata(GS(id->name));
+}
+
+/* Get DrawData from the given ID-block. In order for this to work, we assume that
+ * the DrawData pointer is stored in the struct in the same fashion as in IdDdtTemplate.
+ */
+DrawDataList *DRW_drawdatalist_from_id(ID *id)
{
- for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) {
- if (oed->engine_type == engine_type) {
- return oed;
+ /* only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdDdtTemplate, and extract the
+ * DrawData that way
+ */
+ if (id_can_have_drawdata(id)) {
+ IdDdtTemplate *idt = (IdDdtTemplate *)id;
+ return &idt->drawdata;
+ }
+ else
+ return NULL;
+}
+
+DrawData *DRW_drawdata_get(ID *id, DrawEngineType *engine_type)
+{
+ DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
+
+ if (drawdata == NULL)
+ return NULL;
+
+ LISTBASE_FOREACH(DrawData *, dd, drawdata) {
+ if (dd->engine_type == engine_type) {
+ return dd;
}
}
return NULL;
}
-ObjectEngineData *DRW_object_engine_data_ensure(
- Object *ob,
+DrawData *DRW_drawdata_ensure(
+ ID *id,
DrawEngineType *engine_type,
size_t size,
- ObjectEngineDataInitCb init_cb,
- ObjectEngineDataFreeCb free_cb)
+ DrawDataInitCb init_cb,
+ DrawDataFreeCb free_cb)
{
- BLI_assert(size >= sizeof(ObjectEngineData));
+ BLI_assert(size >= sizeof(DrawData));
+ BLI_assert(id_can_have_drawdata(id));
/* Try to re-use existing data. */
- ObjectEngineData *oed = DRW_object_engine_data_get(ob, engine_type);
- if (oed != NULL) {
- return oed;
+ DrawData *dd = DRW_drawdata_get(id, engine_type);
+ if (dd != NULL) {
+ return dd;
}
+
+ DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
+
/* Allocate new data. */
- if ((ob->base_flag & BASE_FROMDUPLI) != 0) {
+ if ((GS(id->name) == ID_OB) && (((Object *)id)->base_flag & BASE_FROMDUPLI) != 0) {
/* NOTE: data is not persistent in this case. It is reset each redraw. */
BLI_assert(free_cb == NULL); /* No callback allowed. */
/* Round to sizeof(float) for DRW_instance_data_request(). */
@@ -734,21 +797,37 @@ ObjectEngineData *DRW_object_engine_data_ensure(
if (DST.object_instance_data[fsize] == NULL) {
DST.object_instance_data[fsize] = DRW_instance_data_request(DST.idatalist, fsize);
}
- oed = (ObjectEngineData *)DRW_instance_data_next(DST.object_instance_data[fsize]);
- memset(oed, 0, size);
+ dd = (DrawData *)DRW_instance_data_next(DST.object_instance_data[fsize]);
+ memset(dd, 0, size);
}
else {
- oed = MEM_callocN(size, "ObjectEngineData");
+ dd = MEM_callocN(size, "DrawData");
}
- oed->engine_type = engine_type;
- oed->free = free_cb;
+ dd->engine_type = engine_type;
+ dd->free = free_cb;
/* Perform user-side initialization, if needed. */
if (init_cb != NULL) {
- init_cb(oed);
+ init_cb(dd);
}
/* Register in the list. */
- BLI_addtail(&ob->drawdata, oed);
- return oed;
+ BLI_addtail((ListBase *)drawdata, dd);
+ return dd;
+}
+
+void DRW_drawdata_free(ID *id)
+{
+ DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
+
+ if (drawdata == NULL)
+ return;
+
+ LISTBASE_FOREACH(DrawData *, dd, drawdata) {
+ if (dd->free != NULL) {
+ dd->free(dd);
+ }
+ }
+
+ BLI_freelistN((ListBase *)drawdata);
}
/** \} */
@@ -794,6 +873,22 @@ static void drw_engines_cache_init(void)
}
}
+static void drw_engines_world_update(Scene *scene)
+{
+ if (scene->world == NULL) {
+ return;
+ }
+
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
+
+ if (engine->id_update) {
+ engine->id_update(data, &scene->world->id);
+ }
+ }
+}
+
static void drw_engines_cache_populate(Object *ob)
{
DST.ob_state = NULL;
@@ -1161,7 +1256,7 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
/* XXX Really nasty locking. But else this could
* be executed by the material previews thread
* while rendering a viewport. */
- BLI_mutex_lock(&DST.gl_context_mutex);
+ BLI_ticket_mutex_lock(DST.gl_context_mutex);
/* Reset before using it. */
drw_state_prepare_clean_for_draw(&DST);
@@ -1189,7 +1284,7 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
drw_engines_disable();
- BLI_mutex_unlock(&DST.gl_context_mutex);
+ BLI_ticket_mutex_unlock(DST.gl_context_mutex);
}
}
@@ -1273,6 +1368,7 @@ void DRW_draw_render_loop_ex(
{
PROFILE_START(stime);
drw_engines_cache_init();
+ drw_engines_world_update(scene);
const int object_type_exclude_viewport = v3d->object_type_exclude_viewport;
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob)
@@ -1458,14 +1554,10 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
/* Changing Context */
if (re_gl_context != NULL) {
- /* TODO get rid of the blocking. Only here because of the static global DST. */
- BLI_mutex_lock(&DST.gl_context_mutex);
- WM_opengl_context_activate(re_gl_context);
+ DRW_opengl_render_context_enable(re_gl_context);
+ /* We need to query gwn context after a gl context has been bound. */
re_gwn_context = RE_gwn_context_get(render);
- if (GWN_context_active_get() == NULL) {
- GWN_context_active_set(re_gwn_context);
- }
- DRW_shape_cache_reset(); /* XXX fix that too. */
+ DRW_gawain_render_context_enable(re_gwn_context);
}
else {
DRW_opengl_context_enable();
@@ -1544,12 +1636,8 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
/* Changing Context */
if (re_gl_context != NULL) {
- DRW_shape_cache_reset(); /* XXX fix that too. */
- glFlush();
- GWN_context_active_set(NULL);
- WM_opengl_context_release(re_gl_context);
- /* TODO get rid of the blocking. */
- BLI_mutex_unlock(&DST.gl_context_mutex);
+ DRW_gawain_render_context_disable(re_gwn_context);
+ DRW_opengl_render_context_disable(re_gl_context);
}
else {
DRW_opengl_context_disable();
@@ -1575,6 +1663,56 @@ void DRW_render_object_iter(
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END
}
+/* Assume a valid gl context is bound (and that the gl_context_mutex has been aquired).
+ * This function only setup DST and execute the given function.
+ * Warning: similar to DRW_render_to_image you cannot use default lists (dfbl & dtxl). */
+void DRW_custom_pipeline(
+ DrawEngineType *draw_engine_type,
+ struct Depsgraph *depsgraph,
+ void (*callback)(void *vedata, void *user_data),
+ void *user_data)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+ DST.options.is_image_render = true;
+ DST.options.is_scene_render = true;
+ DST.options.draw_background = false;
+
+ DST.draw_ctx = (DRWContextState){
+ .scene = scene,
+ .view_layer = view_layer,
+ .engine_type = NULL,
+ .depsgraph = depsgraph,
+ .object_mode = OB_MODE_OBJECT,
+ };
+ drw_context_state_init();
+
+ DST.viewport = GPU_viewport_create();
+ const int size[2] = {1, 1};
+ GPU_viewport_size_set(DST.viewport, size);
+
+ drw_viewport_var_init();
+
+ DRW_hair_init();
+
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine_type);
+
+ /* Execute the callback */
+ callback(data, user_data);
+ DST.buffer_finish_called = false;
+
+ GPU_viewport_free(DST.viewport);
+ GPU_framebuffer_restore();
+
+#ifdef DEBUG
+ /* Avoid accidental reuse. */
+ drw_state_ensure_not_reused(&DST);
+#endif
+}
+
static struct DRWSelectBuffer {
struct GPUFrameBuffer *framebuffer;
struct GPUTexture *texture_depth;
@@ -1697,6 +1835,7 @@ void DRW_draw_select_loop(
{
drw_engines_cache_init();
+ drw_engines_world_update(scene);
if (use_obedit) {
#if 0
@@ -1891,6 +2030,7 @@ void DRW_draw_depth_loop(
{
drw_engines_cache_init();
+ drw_engines_world_update(scene);
const int object_type_exclude_viewport = v3d->object_type_exclude_viewport;
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob)
@@ -2182,7 +2322,7 @@ void DRW_opengl_context_create(void)
{
BLI_assert(DST.gl_context == NULL); /* Ensure it's called once */
- BLI_mutex_init(&DST.gl_context_mutex);
+ DST.gl_context_mutex = BLI_ticket_mutex_alloc();
if (!G.background) {
immDeactivate();
}
@@ -2207,7 +2347,7 @@ void DRW_opengl_context_destroy(void)
GWN_context_active_set(DST.gwn_context);
GWN_context_discard(DST.gwn_context);
WM_opengl_context_dispose(DST.gl_context);
- BLI_mutex_end(&DST.gl_context_mutex);
+ BLI_ticket_mutex_free(DST.gl_context_mutex);
}
}
@@ -2217,7 +2357,7 @@ void DRW_opengl_context_enable(void)
/* IMPORTANT: We dont support immediate mode in render mode!
* This shall remain in effect until immediate mode supports
* multiple threads. */
- BLI_mutex_lock(&DST.gl_context_mutex);
+ BLI_ticket_mutex_lock(DST.gl_context_mutex);
if (BLI_thread_is_main()) {
if (!G.background) {
immDeactivate();
@@ -2251,8 +2391,43 @@ void DRW_opengl_context_disable(void)
GWN_context_active_set(NULL);
}
- BLI_mutex_unlock(&DST.gl_context_mutex);
+ BLI_ticket_mutex_unlock(DST.gl_context_mutex);
}
}
+void DRW_opengl_render_context_enable(void *re_gl_context)
+{
+ /* If thread is main you should use DRW_opengl_context_enable(). */
+ BLI_assert(!BLI_thread_is_main());
+
+ /* TODO get rid of the blocking. Only here because of the static global DST. */
+ BLI_ticket_mutex_lock(DST.gl_context_mutex);
+ WM_opengl_context_activate(re_gl_context);
+}
+
+void DRW_opengl_render_context_disable(void *re_gl_context)
+{
+ glFlush();
+ WM_opengl_context_release(re_gl_context);
+ /* TODO get rid of the blocking. */
+ BLI_ticket_mutex_unlock(DST.gl_context_mutex);
+}
+
+/* Needs to be called AFTER DRW_opengl_render_context_enable() */
+void DRW_gawain_render_context_enable(void *re_gwn_context)
+{
+ /* If thread is main you should use DRW_opengl_context_enable(). */
+ BLI_assert(!BLI_thread_is_main());
+
+ GWN_context_active_set(re_gwn_context);
+ DRW_shape_cache_reset(); /* XXX fix that too. */
+}
+
+/* Needs to be called BEFORE DRW_opengl_render_context_disable() */
+void DRW_gawain_render_context_disable(void *UNUSED(re_gwn_context))
+{
+ DRW_shape_cache_reset(); /* XXX fix that too. */
+ GWN_context_active_set(NULL);
+}
+
/** \} */
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 91a30fa45ae..6eae3459c2b 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -373,7 +373,7 @@ typedef struct DRWManager {
* the top portion of the struct so DO NOT MOVE IT! */
void *gl_context; /* Unique ghost context used by the draw manager. */
Gwn_Context *gwn_context;
- ThreadMutex gl_context_mutex; /* Mutex to lock the drw manager and avoid concurent context usage. */
+ TicketMutex *gl_context_mutex; /* Mutex to lock the drw manager and avoid concurent context usage. */
/** GPU Resource State: Memory storage between drawing. */
struct {
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index 435c6c77e59..b0aec4a7600 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -154,10 +154,10 @@ static void drw_deferred_shader_compilation_free(void *custom_data)
MEM_freeN(comp);
}
-static void drw_deferred_shader_add(GPUMaterial *mat)
+static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred)
{
/* Do not deferre the compilation if we are rendering for image. */
- if (DRW_state_is_image_render() || !USE_DEFERRED_COMPILATION) {
+ if (DRW_state_is_image_render() || !USE_DEFERRED_COMPILATION || !deferred) {
/* Double checking that this GPUMaterial is not going to be
* compiled by another thread. */
DRW_deferred_shader_remove(mat);
@@ -308,10 +308,10 @@ GPUShader *DRW_shader_create_3D_depth_only(void)
return GPU_shader_get_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY);
}
-GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, int options)
+GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, int options, bool deferred)
{
GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options);
- if (DRW_state_is_image_render()) {
+ if (DRW_state_is_image_render() || !deferred) {
if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) {
/* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX
* with the shader code and we will resume the compilation from there. */
@@ -321,10 +321,10 @@ GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, int
return mat;
}
-GPUMaterial *DRW_shader_find_from_material(Material *ma, const void *engine_type, int options)
+GPUMaterial *DRW_shader_find_from_material(Material *ma, const void *engine_type, int options, bool deferred)
{
GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options);
- if (DRW_state_is_image_render()) {
+ if (DRW_state_is_image_render() || !deferred) {
if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) {
/* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX
* with the shader code and we will resume the compilation from there. */
@@ -336,7 +336,7 @@ GPUMaterial *DRW_shader_find_from_material(Material *ma, const void *engine_type
GPUMaterial *DRW_shader_create_from_world(
struct Scene *scene, World *wo, const void *engine_type, int options,
- const char *vert, const char *geom, const char *frag_lib, const char *defines)
+ const char *vert, const char *geom, const char *frag_lib, const char *defines, bool deferred)
{
GPUMaterial *mat = NULL;
if (DRW_state_is_image_render()) {
@@ -350,7 +350,7 @@ GPUMaterial *DRW_shader_create_from_world(
}
if (GPU_material_status(mat) == GPU_MAT_QUEUED) {
- drw_deferred_shader_add(mat);
+ drw_deferred_shader_add(mat, deferred);
}
return mat;
@@ -358,7 +358,7 @@ GPUMaterial *DRW_shader_create_from_world(
GPUMaterial *DRW_shader_create_from_material(
struct Scene *scene, Material *ma, const void *engine_type, int options,
- const char *vert, const char *geom, const char *frag_lib, const char *defines)
+ const char *vert, const char *geom, const char *frag_lib, const char *defines, bool deferred)
{
GPUMaterial *mat = NULL;
if (DRW_state_is_image_render()) {
@@ -372,7 +372,7 @@ GPUMaterial *DRW_shader_create_from_material(
}
if (GPU_material_status(mat) == GPU_MAT_QUEUED) {
- drw_deferred_shader_add(mat);
+ drw_deferred_shader_add(mat, deferred);
}
return mat;
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index da44d9d8c0b..2ac16906102 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -908,7 +908,7 @@ static void OBJECT_cache_init(void *vedata)
}
{
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_POINT;
DRWPass *pass = psl->lightprobes = DRW_pass_create("Object Probe Pass", state);
struct Gwn_Batch *sphere = DRW_cache_sphere_get();
struct Gwn_Batch *quad = DRW_cache_quad_get();
@@ -1355,14 +1355,14 @@ static void DRW_shgroup_lamp(OBJECT_StorageList *stl, Object *ob, ViewLayer *vie
static float zero = 0.0f;
typedef struct LampEngineData {
- ObjectEngineData engine_data;
+ DrawData dd;
float shape_mat[4][4];
float spot_blend_mat[4][4];
} LampEngineData;
LampEngineData *lamp_engine_data =
- (LampEngineData *)DRW_object_engine_data_ensure(
- ob,
+ (LampEngineData *)DRW_drawdata_ensure(
+ &ob->id,
&draw_engine_object_type,
sizeof(LampEngineData),
NULL,
@@ -1712,7 +1712,7 @@ static void DRW_shgroup_speaker(OBJECT_StorageList *stl, Object *ob, ViewLayer *
}
typedef struct OBJECT_LightProbeEngineData {
- ObjectEngineData engine_data;
+ DrawData dd;
float prb_mats[6][4][4];
float probe_cube_mat[4][4];
@@ -1733,8 +1733,8 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl
int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color);
OBJECT_LightProbeEngineData *prb_data =
- (OBJECT_LightProbeEngineData *)DRW_object_engine_data_ensure(
- ob,
+ (OBJECT_LightProbeEngineData *)DRW_drawdata_ensure(
+ &ob->id,
&draw_engine_object_type,
sizeof(OBJECT_LightProbeEngineData),
NULL,
@@ -1785,8 +1785,7 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl
DRW_shgroup_uniform_vec3(grp, "increment_y", prb_data->increment_y, 1);
DRW_shgroup_uniform_vec3(grp, "increment_z", prb_data->increment_z, 1);
DRW_shgroup_uniform_ivec3(grp, "grid_resolution", &prb->grid_resolution_x, 1);
- DRW_shgroup_uniform_float(grp, "sphere_size", &prb->data_draw_size, 1);
- DRW_shgroup_call_instances_add(grp, DRW_cache_sphere_get(), NULL, &prb_data->cell_count);
+ DRW_shgroup_call_procedural_points_add(grp, prb_data->cell_count, NULL);
}
else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
prb_data->draw_size = prb->data_draw_size * 0.1f;
@@ -1794,6 +1793,9 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl
copy_v3_v3(prb_data->probe_cube_mat[3], ob->obmat[3]);
DRWShadingGroup *grp = shgroup_theme_id_to_probe_cube_outline_shgrp(stl, theme_id);
+ /* TODO remove or change the drawing of the cube probes. Theses line draws nothing on purpose
+ * to keep the call ids correct. */
+ zero_m4(prb_data->probe_cube_mat);
DRW_shgroup_call_dynamic_add(grp, call_id, &prb_data->draw_size, prb_data->probe_cube_mat);
}
else {
diff --git a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
index d9616076dbf..bcdf5adca55 100644
--- a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
+++ b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
@@ -1,7 +1,4 @@
-in vec3 pos;
-in vec3 nor;
-
uniform mat4 ViewProjectionMatrix;
uniform float sphere_size;
@@ -10,6 +7,7 @@ uniform vec3 corner;
uniform vec3 increment_x;
uniform vec3 increment_y;
uniform vec3 increment_z;
+uniform vec3 screen_vecs[2];
uniform int call_id; /* we don't want the builtin callId which would be 0. */
uniform int baseId;
@@ -20,16 +18,17 @@ void main()
{
vec3 ls_cell_location;
/* Keep in sync with update_irradiance_probe */
- ls_cell_location.z = float(gl_InstanceID % grid_resolution.z);
- ls_cell_location.y = float((gl_InstanceID / grid_resolution.z) % grid_resolution.y);
- ls_cell_location.x = float(gl_InstanceID / (grid_resolution.z * grid_resolution.y));
+ ls_cell_location.z = float(gl_VertexID % grid_resolution.z);
+ ls_cell_location.y = float((gl_VertexID / grid_resolution.z) % grid_resolution.y);
+ ls_cell_location.x = float(gl_VertexID / (grid_resolution.z * grid_resolution.y));
vec3 ws_cell_location = corner +
(increment_x * ls_cell_location.x +
increment_y * ls_cell_location.y +
increment_z * ls_cell_location.z);
- gl_Position = ViewProjectionMatrix * vec4(pos * 0.02 * sphere_size + ws_cell_location, 1.0);
+ gl_Position = ViewProjectionMatrix * vec4(ws_cell_location, 1.0);
+ gl_PointSize = 2.0f;
finalId = uint(baseId + call_id);
}
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h
index 77bf16f5e22..585a7999290 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.h
@@ -56,6 +56,9 @@ void MATERIAL_OT_paste(struct wmOperatorType *ot);
void SCENE_OT_view_layer_add(struct wmOperatorType *ot);
void SCENE_OT_view_layer_remove(struct wmOperatorType *ot);
+void SCENE_OT_light_cache_bake(struct wmOperatorType *ot);
+void SCENE_OT_light_cache_free(struct wmOperatorType *ot);
+
void SCENE_OT_render_view_add(struct wmOperatorType *ot);
void SCENE_OT_render_view_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c
index fd534dd9129..7961ea27fdc 100644
--- a/source/blender/editors/render/render_ops.c
+++ b/source/blender/editors/render/render_ops.c
@@ -62,6 +62,9 @@ void ED_operatortypes_render(void)
WM_operatortype_append(SCENE_OT_render_view_add);
WM_operatortype_append(SCENE_OT_render_view_remove);
+ WM_operatortype_append(SCENE_OT_light_cache_bake);
+ WM_operatortype_append(SCENE_OT_light_cache_free);
+
#ifdef WITH_FREESTYLE
WM_operatortype_append(SCENE_OT_freestyle_module_add);
WM_operatortype_append(SCENE_OT_freestyle_module_remove);
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 1673e0d7ca0..886b3112aad 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -33,6 +33,7 @@
#include "DNA_curve_types.h"
#include "DNA_lamp_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -94,6 +95,8 @@
#include "RE_pipeline.h"
+#include "engines/eevee/eevee_lightcache.h"
+
#include "render_intern.h" // own include
/********************** material slot operators *********************/
@@ -673,6 +676,185 @@ void SCENE_OT_view_layer_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
}
+/********************** light cache operators *********************/
+enum {
+ LIGHTCACHE_SUBSET_ALL = 0,
+ LIGHTCACHE_SUBSET_DIRTY,
+ LIGHTCACHE_SUBSET_CUBE,
+};
+
+static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op)
+{
+ if (scene->eevee.light_cache != NULL) {
+ int subset = RNA_enum_get(op->ptr, "subset");
+ switch (subset) {
+ case LIGHTCACHE_SUBSET_ALL:
+ scene->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_GRID | LIGHTCACHE_UPDATE_CUBE;
+ break;
+ case LIGHTCACHE_SUBSET_CUBE:
+ scene->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_CUBE;
+ break;
+ case LIGHTCACHE_SUBSET_DIRTY:
+ /* Leave tag untouched. */
+ break;
+ }
+ }
+}
+
+/* catch esc */
+static int light_cache_bake_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Scene *scene = (Scene *) op->customdata;
+
+ /* no running blender, remove handler and pass through */
+ if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER)) {
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ }
+
+ /* running render */
+ switch (event->type) {
+ case ESCKEY:
+ return OPERATOR_RUNNING_MODAL;
+ }
+ return OPERATOR_PASS_THROUGH;
+}
+
+static void light_cache_bake_cancel(bContext *C, wmOperator *op)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ Scene *scene = (Scene *) op->customdata;
+
+ /* kill on cancel, because job is using op->reports */
+ WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_RENDER);
+}
+
+/* executes blocking render */
+static int light_cache_bake_exec(bContext *C, wmOperator *op)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ G.is_break = false;
+
+ /* TODO abort if selected engine is not eevee. */
+ void *rj = EEVEE_lightbake_job_data_alloc(bmain, view_layer, scene, false);
+
+ light_cache_bake_tag_cache(scene, op);
+
+ short stop = 0, do_update; float progress; /* Not actually used. */
+ EEVEE_lightbake_job(rj, &stop, &do_update, &progress);
+ EEVEE_lightbake_update(rj);
+ EEVEE_lightbake_job_data_free(rj);
+
+ // no redraw needed, we leave state as we entered it
+ ED_update_for_newframe(bmain, CTX_data_depsgraph(C));
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+static int light_cache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ int delay = RNA_int_get(op->ptr, "delay");
+
+ wmJob *wm_job = EEVEE_lightbake_job_create(wm, win, bmain, view_layer, scene, delay);
+
+ if (!wm_job) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* add modal handler for ESC */
+ WM_event_add_modal_handler(C, op);
+
+ light_cache_bake_tag_cache(scene, op);
+
+ /* store actual owner of job, so modal operator could check for it,
+ * the reason of this is that active scene could change when rendering
+ * several layers from compositor [#31800]
+ */
+ op->customdata = scene;
+
+ WM_jobs_start(wm, wm_job);
+
+ WM_cursor_wait(0);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SCENE_OT_light_cache_bake(wmOperatorType *ot)
+{
+ static const EnumPropertyItem light_cache_subset_items[] = {
+ {LIGHTCACHE_SUBSET_ALL, "ALL", 0, "All LightProbes", "Bake both irradiance grids and reflection cubemaps"},
+ {LIGHTCACHE_SUBSET_DIRTY, "DIRTY", 0, "Dirty Only", "Only bake lightprobes that are marked as dirty"},
+ {LIGHTCACHE_SUBSET_CUBE, "CUBEMAPS", 0, "Cubemaps Only", "Try to only bake reflection cubemaps if irradiance "
+ "grids are up to date"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Bake Light Cache";
+ ot->idname = "SCENE_OT_light_cache_bake";
+ ot->description = "Bake the active view layer lighting";
+
+ /* api callbacks */
+ ot->invoke = light_cache_bake_invoke;
+ ot->modal = light_cache_bake_modal;
+ ot->cancel = light_cache_bake_cancel;
+ ot->exec = light_cache_bake_exec;
+
+ ot->prop = RNA_def_int(ot->srna, "delay", 0, 0, 2000, "Delay", "Delay in millisecond before baking starts", 0, 2000);
+ RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
+
+ ot->prop = RNA_def_enum(ot->srna, "subset", light_cache_subset_items, 0, "Subset", "Subset of probes to update");
+ RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
+}
+
+static bool light_cache_free_poll(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ return scene->eevee.light_cache;
+}
+
+static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+
+ if (!scene->eevee.light_cache) {
+ return OPERATOR_CANCELLED;
+ }
+
+ EEVEE_lightcache_free(scene->eevee.light_cache);
+ scene->eevee.light_cache = NULL;
+
+ EEVEE_lightcache_info_update(&scene->eevee);
+
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_light_cache_free(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Free Light Cache";
+ ot->idname = "SCENE_OT_light_cache_free";
+ ot->description = "Free cached indirect lighting";
+
+ /* api callbacks */
+ ot->exec = light_cache_free_exec;
+ ot->poll = light_cache_free_poll;
+}
+
/********************** render view operators *********************/
static bool render_view_remove_poll(bContext *C)
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index 97fd7295a7b..e473b98b4a1 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -294,9 +294,6 @@ static void world_changed(Main *UNUSED(bmain), World *wo)
/* icons */
BKE_icon_changed(BKE_icon_id_ensure(&wo->id));
- /* XXX temporary flag waiting for depsgraph proper tagging */
- wo->update_flag = 1;
-
/* glsl */
if (wo->id.recalc & ID_RECALC) {
if (!BLI_listbase_is_empty(&defmaterial.gpumaterial)) {
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 83189159086..9aaced3e583 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -683,6 +683,18 @@ static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
}
}
+static void view3d_lightcache_update(bContext *C)
+{
+ PointerRNA op_ptr;
+
+ WM_operator_properties_create(&op_ptr, "SCENE_OT_light_cache_bake");
+ RNA_int_set(&op_ptr, "delay", 200);
+ RNA_enum_set_identifier(C, &op_ptr, "subset", "DIRTY");
+
+ WM_operator_name_call(C, "SCENE_OT_light_cache_bake", WM_OP_INVOKE_DEFAULT, &op_ptr);
+
+ WM_operator_properties_free(&op_ptr);
+}
/* region dropbox definition */
static void view3d_dropboxes(void)
@@ -980,6 +992,9 @@ static void view3d_main_region_listener(
break;
}
break;
+ case NC_LIGHTPROBE:
+ ED_area_tag_refresh(sa);
+ break;
case NC_IMAGE:
/* this could be more fine grained checks if we had
* more context than just the region */
@@ -1409,6 +1424,13 @@ static void space_view3d_listener(
}
}
+static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(sa))
+{
+ /* This is only used by the auto lightprobe refresh for the moment.
+ * So we don't need to check anything to know what to do. */
+ view3d_lightcache_update((bContext *)C);
+}
+
const char *view3d_context_dir[] = {
"active_base", "active_object", NULL
};
@@ -1509,6 +1531,7 @@ void ED_spacetype_view3d(void)
st->free = view3d_free;
st->init = view3d_init;
st->listener = space_view3d_listener;
+ st->refresh = space_view3d_refresh;
st->duplicate = view3d_duplicate;
st->operatortypes = view3d_operatortypes;
st->keymap = view3d_keymap;
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 341abeba72f..3ed9014d431 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -144,8 +144,23 @@ typedef enum GPUTextureFormat {
GPU_DEPTH_COMPONENT16,
} GPUTextureFormat;
+typedef enum GPUDataFormat {
+ GPU_DATA_FLOAT,
+ GPU_DATA_INT,
+ GPU_DATA_UNSIGNED_INT,
+ GPU_DATA_UNSIGNED_BYTE,
+ GPU_DATA_UNSIGNED_INT_24_8,
+ GPU_DATA_10_11_11_REV,
+} GPUDataFormat;
+
unsigned int GPU_texture_memory_usage_get(void);
+/* TODO make it static function again. (create function with GPUDataFormat exposed) */
+GPUTexture *GPU_texture_create_nD(
+ int w, int h, int d, int n, const void *pixels,
+ GPUTextureFormat tex_format, GPUDataFormat gpu_data_format, int samples,
+ const bool can_rescale, char err_out[256]);
+
GPUTexture *GPU_texture_create_1D(
int w, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
GPUTexture *GPU_texture_create_2D(
@@ -168,11 +183,15 @@ GPUTexture *GPU_texture_from_blender(
struct Image *ima, struct ImageUser *iuser, int textarget, bool is_data, double time);
GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
-void GPU_texture_update(GPUTexture *tex, const void *pixels);
+void GPU_texture_add_mipmap(GPUTexture *tex, GPUDataFormat gpu_data_format, int miplvl, const void *pixels);
+
+void GPU_texture_update(GPUTexture *tex, GPUDataFormat data_format, const void *pixels);
void GPU_texture_update_sub(
- GPUTexture *tex, const void *pixels,
+ GPUTexture *tex, GPUDataFormat gpu_data_format, const void *pixels,
int offset_x, int offset_y, int offset_z, int width, int height, int depth);
+void *GPU_texture_read(GPUTexture *tex, GPUDataFormat gpu_data_format, int miplvl);
+
void GPU_invalid_tex_init(void);
void GPU_invalid_tex_bind(int mode);
void GPU_invalid_tex_free(void);
@@ -202,6 +221,7 @@ int GPU_texture_detach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb);
int GPU_texture_target(const GPUTexture *tex);
int GPU_texture_width(const GPUTexture *tex);
int GPU_texture_height(const GPUTexture *tex);
+int GPU_texture_layers(const GPUTexture *tex);
GPUTextureFormat GPU_texture_format(const GPUTexture *tex);
int GPU_texture_samples(const GPUTexture *tex);
bool GPU_texture_cube(const GPUTexture *tex);
@@ -210,6 +230,8 @@ bool GPU_texture_stencil(const GPUTexture *tex);
bool GPU_texture_integer(const GPUTexture *tex);
int GPU_texture_opengl_bindcode(const GPUTexture *tex);
+void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index b7385bdf07c..d9248e06dfb 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -134,73 +134,159 @@ unsigned int GPU_texture_memory_usage_get(void)
/* -------------------------------- */
-static GLenum gpu_texture_get_format(
- int components, GPUTextureFormat data_type,
- GLenum *format, GLenum *data_format, GPUTextureFormatFlag *format_flag, unsigned int *bytesize)
+static int gpu_get_component_count(GPUTextureFormat format)
+{
+ switch (format) {
+ case GPU_RGBA8:
+ case GPU_RGBA16F:
+ case GPU_RGBA16:
+ case GPU_RGBA32F:
+ return 4;
+ case GPU_RGB16F:
+ case GPU_R11F_G11F_B10F:
+ return 3;
+ case GPU_RG8:
+ case GPU_RG16:
+ case GPU_RG16F:
+ case GPU_RG16I:
+ case GPU_RG16UI:
+ case GPU_RG32F:
+ return 2;
+ default:
+ return 1;
+ }
+}
+
+/* Definitely not complete, edit according to the gl specification. */
+static void gpu_validate_data_format(GPUTextureFormat tex_format, GPUDataFormat data_format)
+{
+ if (ELEM(tex_format, GPU_DEPTH_COMPONENT24,
+ GPU_DEPTH_COMPONENT16,
+ GPU_DEPTH_COMPONENT32F))
+ {
+ BLI_assert(data_format == GPU_DATA_FLOAT);
+ }
+ else if (tex_format == GPU_DEPTH24_STENCIL8) {
+ BLI_assert(data_format == GPU_DATA_UNSIGNED_INT_24_8);
+ }
+ else {
+ /* Integer formats */
+ if (ELEM(tex_format, GPU_RG16I, GPU_R16I, GPU_RG16UI, GPU_R16UI, GPU_R32UI)) {
+ if (ELEM(tex_format, GPU_R16UI, GPU_RG16UI, GPU_R32UI)) {
+ BLI_assert(data_format == GPU_DATA_UNSIGNED_INT);
+ }
+ else {
+ BLI_assert(data_format == GPU_DATA_INT);
+ }
+ }
+ /* Byte formats */
+ else if (ELEM(tex_format, GPU_R8, GPU_RG8, GPU_RGBA8)) {
+ BLI_assert(ELEM(data_format, GPU_DATA_UNSIGNED_BYTE, GPU_DATA_FLOAT));
+ }
+ /* Special case */
+ else if (ELEM(tex_format, GPU_R11F_G11F_B10F)) {
+ BLI_assert(ELEM(data_format, GPU_DATA_10_11_11_REV, GPU_DATA_FLOAT));
+ }
+ /* Float formats */
+ else {
+ BLI_assert(ELEM(data_format, GPU_DATA_FLOAT));
+ }
+ }
+}
+
+static GPUDataFormat gpu_get_data_format_from_tex_format(GPUTextureFormat tex_format)
+{
+ if (ELEM(tex_format, GPU_DEPTH_COMPONENT24,
+ GPU_DEPTH_COMPONENT16,
+ GPU_DEPTH_COMPONENT32F))
+ {
+ return GPU_DATA_FLOAT;
+ }
+ else if (tex_format == GPU_DEPTH24_STENCIL8) {
+ return GPU_DATA_UNSIGNED_INT_24_8;
+ }
+ else {
+ /* Integer formats */
+ if (ELEM(tex_format, GPU_RG16I, GPU_R16I, GPU_RG16UI, GPU_R16UI, GPU_R32UI)) {
+ if (ELEM(tex_format, GPU_R16UI, GPU_RG16UI, GPU_R32UI)) {
+ return GPU_DATA_UNSIGNED_INT;
+ }
+ else {
+ return GPU_DATA_INT;
+ }
+ }
+ /* Byte formats */
+ else if (ELEM(tex_format, GPU_R8)) {
+ return GPU_DATA_UNSIGNED_BYTE;
+ }
+ /* Special case */
+ else if (ELEM(tex_format, GPU_R11F_G11F_B10F)) {
+ return GPU_DATA_10_11_11_REV;
+ }
+ else {
+ return GPU_DATA_FLOAT;
+ }
+ }
+}
+
+/* Definitely not complete, edit according to the gl specification. */
+static GLenum gpu_get_gl_dataformat(GPUTextureFormat data_type, GPUTextureFormatFlag *format_flag)
{
if (ELEM(data_type, GPU_DEPTH_COMPONENT24,
GPU_DEPTH_COMPONENT16,
GPU_DEPTH_COMPONENT32F))
{
*format_flag |= GPU_FORMAT_DEPTH;
- *data_format = GL_FLOAT;
- *format = GL_DEPTH_COMPONENT;
+ return GL_DEPTH_COMPONENT;
}
else if (data_type == GPU_DEPTH24_STENCIL8) {
*format_flag |= GPU_FORMAT_DEPTH | GPU_FORMAT_STENCIL;
- *data_format = GL_UNSIGNED_INT_24_8;
- *format = GL_DEPTH_STENCIL;
+ return GL_DEPTH_STENCIL;
}
else {
/* Integer formats */
if (ELEM(data_type, GPU_RG16I, GPU_R16I, GPU_RG16UI, GPU_R16UI, GPU_R32UI)) {
- if (ELEM(data_type, GPU_R16UI, GPU_RG16UI, GPU_R32UI)) {
- *data_format = GL_UNSIGNED_INT;
- }
- else {
- *data_format = GL_INT;
- }
-
*format_flag |= GPU_FORMAT_INTEGER;
- switch (components) {
- case 1: *format = GL_RED_INTEGER; break;
- case 2: *format = GL_RG_INTEGER; break;
- case 3: *format = GL_RGB_INTEGER; break;
- case 4: *format = GL_RGBA_INTEGER; break;
- default: break;
+ switch (gpu_get_component_count(data_type)) {
+ case 1: return GL_RED_INTEGER; break;
+ case 2: return GL_RG_INTEGER; break;
+ case 3: return GL_RGB_INTEGER; break;
+ case 4: return GL_RGBA_INTEGER; break;
}
}
else if (ELEM(data_type, GPU_R8)) {
- *data_format = GL_UNSIGNED_BYTE;
- *format = GL_RED;
+ *format_flag |= GPU_FORMAT_FLOAT;
+ return GL_RED;
}
else {
- *data_format = GL_FLOAT;
*format_flag |= GPU_FORMAT_FLOAT;
- switch (components) {
- case 1: *format = GL_RED; break;
- case 2: *format = GL_RG; break;
- case 3: *format = GL_RGB; break;
- case 4: *format = GL_RGBA; break;
- default: break;
+ switch (gpu_get_component_count(data_type)) {
+ case 1: return GL_RED; break;
+ case 2: return GL_RG; break;
+ case 3: return GL_RGB; break;
+ case 4: return GL_RGBA; break;
}
}
}
+ BLI_assert(0);
+ *format_flag |= GPU_FORMAT_FLOAT;
+ return GL_RGBA;
+}
+
+static unsigned int gpu_get_bytesize(GPUTextureFormat data_type)
+{
switch (data_type) {
case GPU_RGBA32F:
- *bytesize = 32;
- break;
+ return 32;
case GPU_RG32F:
case GPU_RGBA16F:
case GPU_RGBA16:
- *bytesize = 16;
- break;
+ return 16;
case GPU_RGB16F:
- *bytesize = 12;
- break;
+ return 12;
case GPU_RG16F:
case GPU_RG16I:
case GPU_RG16UI:
@@ -212,28 +298,28 @@ static GLenum gpu_texture_get_format(
case GPU_R32F:
case GPU_R32UI:
case GPU_R32I:
- *bytesize = 4;
- break;
+ return 4;
case GPU_DEPTH_COMPONENT24:
- *bytesize = 3;
- break;
+ return 3;
case GPU_DEPTH_COMPONENT16:
case GPU_R16F:
+ case GPU_R16UI:
case GPU_R16I:
case GPU_RG8:
- *bytesize = 2;
- break;
+ return 2;
case GPU_R8:
- *bytesize = 1;
- break;
+ return 1;
default:
- *bytesize = 0;
- break;
+ BLI_assert(!"Texture format incorrect or unsupported\n");
+ return 0;
}
+}
+static GLenum gpu_get_gl_internalformat(GPUTextureFormat format)
+{
/* You can add any of the available type to this list
* For available types see GPU_texture.h */
- switch (data_type) {
+ switch (format) {
/* Formats texture & renderbuffer */
case GPU_RGBA32F: return GL_RGBA32F;
case GPU_RGBA16F: return GL_RGBA16F;
@@ -265,31 +351,29 @@ static GLenum gpu_texture_get_format(
case GPU_DEPTH_COMPONENT24: return GL_DEPTH_COMPONENT24;
case GPU_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT16;
default:
- fprintf(stderr, "Texture format incorrect or unsupported\n");
+ BLI_assert(!"Texture format incorrect or unsupported\n");
return 0;
}
}
-static int gpu_texture_get_component_count(GPUTextureFormat format)
+static GLenum gpu_get_gl_datatype(GPUDataFormat format)
{
switch (format) {
- case GPU_RGBA8:
- case GPU_RGBA16F:
- case GPU_RGBA16:
- case GPU_RGBA32F:
- return 4;
- case GPU_RGB16F:
- case GPU_R11F_G11F_B10F:
- return 3;
- case GPU_RG8:
- case GPU_RG16:
- case GPU_RG16F:
- case GPU_RG16I:
- case GPU_RG16UI:
- case GPU_RG32F:
- return 2;
+ case GPU_DATA_FLOAT:
+ return GL_FLOAT;
+ case GPU_DATA_INT:
+ return GL_INT;
+ case GPU_DATA_UNSIGNED_INT:
+ return GL_UNSIGNED_INT;
+ case GPU_DATA_UNSIGNED_BYTE:
+ return GL_UNSIGNED_BYTE;
+ case GPU_DATA_UNSIGNED_INT_24_8:
+ return GL_UNSIGNED_INT_24_8;
+ case GPU_DATA_10_11_11_REV:
+ return GL_UNSIGNED_INT_10F_11F_11F_REV;
default:
- return 1;
+ BLI_assert(!"Unhandled data format");
+ return GL_FLOAT;
}
}
@@ -331,22 +415,22 @@ static float *GPU_texture_3D_rescale(GPUTexture *tex, int w, int h, int d, int c
/* This tries to allocate video memory for a given texture
* If alloc fails, lower the resolution until it fits. */
static bool gpu_texture_try_alloc(
- GPUTexture *tex, GLenum proxy, GLenum internalformat, GLenum format, GLenum data_format,
+ GPUTexture *tex, GLenum proxy, GLenum internalformat, GLenum data_format, GLenum data_type,
int channels, bool try_rescale, const float *fpixels, float **rescaled_fpixels)
{
int r_width;
switch (proxy) {
case GL_PROXY_TEXTURE_1D:
- glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, data_format, NULL);
+ glTexImage1D(proxy, 0, internalformat, tex->w, 0, data_format, data_type, NULL);
break;
case GL_PROXY_TEXTURE_1D_ARRAY:
case GL_PROXY_TEXTURE_2D:
- glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, data_format, NULL);
+ glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, NULL);
break;
case GL_PROXY_TEXTURE_2D_ARRAY:
case GL_PROXY_TEXTURE_3D:
- glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, NULL);
+ glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, data_format, data_type, NULL);
break;
}
@@ -367,11 +451,11 @@ static bool gpu_texture_try_alloc(
if (tex->d == 0 && proxy == GL_PROXY_TEXTURE_3D) break;
if (proxy == GL_PROXY_TEXTURE_1D)
- glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, data_format, NULL);
+ glTexImage1D(proxy, 0, internalformat, tex->w, 0, data_format, data_type, NULL);
else if (proxy == GL_PROXY_TEXTURE_2D)
- glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, data_format, NULL);
+ glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, NULL);
else if (proxy == GL_PROXY_TEXTURE_3D)
- glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, NULL);
+ glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, data_format, data_type, NULL);
glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
}
@@ -384,6 +468,7 @@ static bool gpu_texture_try_alloc(
/* Do nothing for now */
return false;
case GL_PROXY_TEXTURE_3D:
+ BLI_assert(data_type == GL_FLOAT);
*rescaled_fpixels = GPU_texture_3D_rescale(tex, w, h, d, channels, fpixels);
return (bool)*rescaled_fpixels;
}
@@ -393,9 +478,9 @@ static bool gpu_texture_try_alloc(
return (r_width > 0);
}
-static GPUTexture *GPU_texture_create_nD(
- int w, int h, int d, int n, const float *fpixels,
- GPUTextureFormat data_type, int samples,
+GPUTexture *GPU_texture_create_nD(
+ int w, int h, int d, int n, const void *pixels,
+ GPUTextureFormat tex_format, GPUDataFormat gpu_data_format, int samples,
const bool can_rescale, char err_out[256])
{
if (samples) {
@@ -409,8 +494,9 @@ static GPUTexture *GPU_texture_create_nD(
tex->samples = samples;
tex->number = -1;
tex->refcount = 1;
- tex->format = data_type;
- tex->components = gpu_texture_get_component_count(data_type);
+ tex->format = tex_format;
+ tex->components = gpu_get_component_count(tex_format);
+ tex->bytesize = gpu_get_bytesize(tex_format);
tex->format_flag = 0;
if (n == 2) {
@@ -434,12 +520,14 @@ static GPUTexture *GPU_texture_create_nD(
return NULL;
}
+ gpu_validate_data_format(tex_format, gpu_data_format);
+
if (samples && n == 2 && d == 0)
tex->target = GL_TEXTURE_2D_MULTISAMPLE;
- GLenum format, internalformat, data_format;
- internalformat = gpu_texture_get_format(tex->components, data_type, &format, &data_format,
- &tex->format_flag, &tex->bytesize);
+ GLenum internalformat = gpu_get_gl_internalformat(tex_format);
+ GLenum data_format = gpu_get_gl_dataformat(tex_format, &tex->format_flag);
+ GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
gpu_texture_memory_footprint_add(tex);
@@ -448,9 +536,9 @@ static GPUTexture *GPU_texture_create_nD(
if (!tex->bindcode) {
if (err_out)
- BLI_snprintf(err_out, 256, "GPUTexture: texture create failed");
+ BLI_snprintf(err_out, 256, "GPUTexture: texture create failed\n");
else
- fprintf(stderr, "GPUTexture: texture create failed");
+ fprintf(stderr, "GPUTexture: texture create failed\n");
GPU_texture_free(tex);
return NULL;
}
@@ -474,9 +562,9 @@ static GPUTexture *GPU_texture_create_nD(
proxy = GL_PROXY_TEXTURE_3D;
}
- float *rescaled_fpixels = NULL;
- bool valid = gpu_texture_try_alloc(tex, proxy, internalformat, format, data_format, tex->components, can_rescale,
- fpixels, &rescaled_fpixels);
+ float *rescaled_pixels = NULL;
+ bool valid = gpu_texture_try_alloc(tex, proxy, internalformat, data_format, data_type, tex->components, can_rescale,
+ pixels, &rescaled_pixels);
if (!valid) {
if (err_out)
BLI_snprintf(err_out, 256, "GPUTexture: texture alloc failed");
@@ -487,7 +575,7 @@ static GPUTexture *GPU_texture_create_nD(
}
/* Upload Texture */
- const float *pix = (rescaled_fpixels) ? rescaled_fpixels : fpixels;
+ const float *pix = (rescaled_pixels) ? rescaled_pixels : pixels;
if (tex->target == GL_TEXTURE_2D ||
tex->target == GL_TEXTURE_2D_MULTISAMPLE ||
@@ -496,21 +584,21 @@ static GPUTexture *GPU_texture_create_nD(
if (samples) {
glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true);
if (pix)
- glTexSubImage2D(tex->target, 0, 0, 0, tex->w, tex->h, format, data_format, pix);
+ glTexSubImage2D(tex->target, 0, 0, 0, tex->w, tex->h, data_format, data_type, pix);
}
else {
- glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, format, data_format, pix);
+ glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pix);
}
}
else if (tex->target == GL_TEXTURE_1D) {
- glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, data_format, pix);
+ glTexImage1D(tex->target, 0, internalformat, tex->w, 0, data_format, data_type, pix);
}
else {
- glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, pix);
+ glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->d, 0, data_format, data_type, pix);
}
- if (rescaled_fpixels)
- MEM_freeN(rescaled_fpixels);
+ if (rescaled_pixels)
+ MEM_freeN(rescaled_pixels);
/* Texture Parameters */
if (GPU_texture_stencil(tex) || /* Does not support filtering */
@@ -547,11 +635,9 @@ static GPUTexture *GPU_texture_cube_create(
int w, int d,
const float *fpixels_px, const float *fpixels_py, const float *fpixels_pz,
const float *fpixels_nx, const float *fpixels_ny, const float *fpixels_nz,
- GPUTextureFormat data_type,
+ GPUTextureFormat tex_format, GPUDataFormat gpu_data_format,
char err_out[256])
{
- GLenum format, internalformat, data_format;
-
GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
tex->w = w;
tex->h = w;
@@ -559,8 +645,9 @@ static GPUTexture *GPU_texture_cube_create(
tex->samples = 0;
tex->number = -1;
tex->refcount = 1;
- tex->format = data_type;
- tex->components = gpu_texture_get_component_count(data_type);
+ tex->format = tex_format;
+ tex->components = gpu_get_component_count(tex_format);
+ tex->bytesize = gpu_get_bytesize(tex_format);
tex->format_flag = GPU_FORMAT_CUBE;
if (d == 0) {
@@ -571,8 +658,9 @@ static GPUTexture *GPU_texture_cube_create(
// tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY;
}
- internalformat = gpu_texture_get_format(tex->components, data_type, &format, &data_format,
- &tex->format_flag, &tex->bytesize);
+ GLenum internalformat = gpu_get_gl_internalformat(tex_format);
+ GLenum data_format = gpu_get_gl_dataformat(tex_format, &tex->format_flag);
+ GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
gpu_texture_memory_footprint_add(tex);
@@ -581,9 +669,9 @@ static GPUTexture *GPU_texture_cube_create(
if (!tex->bindcode) {
if (err_out)
- BLI_snprintf(err_out, 256, "GPUTexture: texture create failed");
+ BLI_snprintf(err_out, 256, "GPUTexture: texture create failed\n");
else
- fprintf(stderr, "GPUTexture: texture create failed");
+ fprintf(stderr, "GPUTexture: texture create failed\n");
GPU_texture_free(tex);
return NULL;
}
@@ -591,12 +679,12 @@ static GPUTexture *GPU_texture_cube_create(
glBindTexture(tex->target, tex->bindcode);
/* Upload Texture */
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_px);
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_py);
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_pz);
- glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_nx);
- glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_ny);
- glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_nz);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, fpixels_px);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, fpixels_py);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, fpixels_pz);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, fpixels_nx);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, fpixels_ny);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, fpixels_nz);
/* Texture Parameters */
if (GPU_texture_stencil(tex) || /* Does not support filtering */
@@ -625,36 +713,37 @@ static GPUTexture *GPU_texture_cube_create(
return tex;
}
-/* Special buffer textures. data_type must be compatible with the buffer content. */
-GPUTexture *GPU_texture_create_buffer(GPUTextureFormat data_type, const GLuint buffer)
+/* Special buffer textures. tex_format must be compatible with the buffer content. */
+GPUTexture *GPU_texture_create_buffer(GPUTextureFormat tex_format, const GLuint buffer)
{
GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
tex->number = -1;
tex->refcount = 1;
- tex->format = data_type;
- tex->components = gpu_texture_get_component_count(data_type);
+ tex->format = tex_format;
+ tex->components = gpu_get_component_count(tex_format);
tex->format_flag = 0;
tex->target_base = tex->target = GL_TEXTURE_BUFFER;
-
- GLenum format, internalformat, data_format;
- internalformat = gpu_texture_get_format(tex->components, data_type, &format, &data_format,
- &tex->format_flag, &tex->bytesize);
-
- if (!(ELEM(data_type, GPU_R8, GPU_R16) ||
- ELEM(data_type, GPU_R16F, GPU_R32F) ||
- ELEM(data_type, GPU_R8I, GPU_R16I, GPU_R32I) ||
- ELEM(data_type, GPU_R8UI, GPU_R16UI, GPU_R32UI) ||
- ELEM(data_type, GPU_RG8, GPU_RG16) ||
- ELEM(data_type, GPU_RG16F, GPU_RG32F) ||
- ELEM(data_type, GPU_RG8I, GPU_RG16I, GPU_RG32I) ||
- ELEM(data_type, GPU_RG8UI, GPU_RG16UI, GPU_RG32UI) ||
- //ELEM(data_type, GPU_RGB32F, GPU_RGB32I, GPU_RGB32UI) || /* Not available until gl 4.0 */
- ELEM(data_type, GPU_RGBA8, GPU_RGBA16) ||
- ELEM(data_type, GPU_RGBA16F, GPU_RGBA32F) ||
- ELEM(data_type, GPU_RGBA8I, GPU_RGBA16I, GPU_RGBA32I) ||
- ELEM(data_type, GPU_RGBA8UI, GPU_RGBA16UI, GPU_RGBA32UI)))
+ tex->bytesize = gpu_get_bytesize(tex_format);
+
+ GLenum internalformat = gpu_get_gl_internalformat(tex_format);
+
+ gpu_get_gl_dataformat(tex_format, &tex->format_flag);
+
+ if (!(ELEM(tex_format, GPU_R8, GPU_R16) ||
+ ELEM(tex_format, GPU_R16F, GPU_R32F) ||
+ ELEM(tex_format, GPU_R8I, GPU_R16I, GPU_R32I) ||
+ ELEM(tex_format, GPU_R8UI, GPU_R16UI, GPU_R32UI) ||
+ ELEM(tex_format, GPU_RG8, GPU_RG16) ||
+ ELEM(tex_format, GPU_RG16F, GPU_RG32F) ||
+ ELEM(tex_format, GPU_RG8I, GPU_RG16I, GPU_RG32I) ||
+ ELEM(tex_format, GPU_RG8UI, GPU_RG16UI, GPU_RG32UI) ||
+ //ELEM(tex_format, GPU_RGB32F, GPU_RGB32I, GPU_RGB32UI) || /* Not available until gl 4.0 */
+ ELEM(tex_format, GPU_RGBA8, GPU_RGBA16) ||
+ ELEM(tex_format, GPU_RGBA16F, GPU_RGBA32F) ||
+ ELEM(tex_format, GPU_RGBA8I, GPU_RGBA16I, GPU_RGBA32I) ||
+ ELEM(tex_format, GPU_RGBA8UI, GPU_RGBA16UI, GPU_RGBA32UI)))
{
- fprintf(stderr, "GPUTexture: invalid format for texture buffer");
+ fprintf(stderr, "GPUTexture: invalid format for texture buffer\n");
GPU_texture_free(tex);
return NULL;
}
@@ -663,9 +752,9 @@ GPUTexture *GPU_texture_create_buffer(GPUTextureFormat data_type, const GLuint b
glGenTextures(1, &tex->bindcode);
if (!tex->bindcode) {
- fprintf(stderr, "GPUTexture: texture create failed");
+ fprintf(stderr, "GPUTexture: texture create failed\n");
GPU_texture_free(tex);
- BLI_assert(0 && "glGenTextures failled: Are you sure a valid OGL context is active on this thread?");
+ BLI_assert(0 && "glGenTextures failled: Are you sure a valid OGL context is active on this thread?\n");
return NULL;
}
@@ -766,40 +855,45 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
}
GPUTexture *GPU_texture_create_1D(
- int w, GPUTextureFormat data_type, const float *pixels, char err_out[256])
+ int w, GPUTextureFormat tex_format, const float *pixels, char err_out[256])
{
- return GPU_texture_create_nD(w, 0, 0, 1, pixels, data_type, 0, false, err_out);
+ GPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
+ return GPU_texture_create_nD(w, 0, 0, 1, pixels, tex_format, data_format, 0, false, err_out);
}
GPUTexture *GPU_texture_create_2D(
- int w, int h, GPUTextureFormat data_type, const float *pixels, char err_out[256])
+ int w, int h, GPUTextureFormat tex_format, const float *pixels, char err_out[256])
{
- return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, 0, false, err_out);
+ GPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
+ return GPU_texture_create_nD(w, h, 0, 2, pixels, tex_format, data_format, 0, false, err_out);
}
GPUTexture *GPU_texture_create_2D_multisample(
- int w, int h, GPUTextureFormat data_type, const float *pixels, int samples, char err_out[256])
+ int w, int h, GPUTextureFormat tex_format, const float *pixels, int samples, char err_out[256])
{
- return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, samples, false, err_out);
+ GPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
+ return GPU_texture_create_nD(w, h, 0, 2, pixels, tex_format, data_format, samples, false, err_out);
}
GPUTexture *GPU_texture_create_2D_array(
- int w, int h, int d, GPUTextureFormat data_type, const float *pixels, char err_out[256])
+ int w, int h, int d, GPUTextureFormat tex_format, const float *pixels, char err_out[256])
{
- return GPU_texture_create_nD(w, h, d, 2, pixels, data_type, 0, false, err_out);
+ GPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
+ return GPU_texture_create_nD(w, h, d, 2, pixels, tex_format, data_format, 0, false, err_out);
}
GPUTexture *GPU_texture_create_3D(
- int w, int h, int d, GPUTextureFormat data_type, const float *pixels, char err_out[256])
+ int w, int h, int d, GPUTextureFormat tex_format, const float *pixels, char err_out[256])
{
- return GPU_texture_create_nD(w, h, d, 3, pixels, data_type, 0, true, err_out);
+ GPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
+ return GPU_texture_create_nD(w, h, d, 3, pixels, tex_format, data_format, 0, true, err_out);
}
GPUTexture *GPU_texture_create_cube(
- int w, GPUTextureFormat data_type, const float *fpixels, char err_out[256])
+ int w, GPUTextureFormat tex_format, const float *fpixels, char err_out[256])
{
const float *fpixels_px, *fpixels_py, *fpixels_pz, *fpixels_nx, *fpixels_ny, *fpixels_nz;
- const int channels = gpu_texture_get_component_count(data_type);
+ const int channels = gpu_get_component_count(tex_format);
if (fpixels) {
fpixels_px = fpixels + 0 * w * w * channels;
@@ -814,7 +908,7 @@ GPUTexture *GPU_texture_create_cube(
}
return GPU_texture_cube_create(w, 0, fpixels_px, fpixels_py, fpixels_pz, fpixels_nx, fpixels_ny, fpixels_nz,
- data_type, err_out);
+ tex_format, GPU_DATA_FLOAT, err_out);
}
GPUTexture *GPU_texture_create_from_vertbuf(Gwn_VertBuf *vert)
@@ -886,17 +980,56 @@ GPUTexture *GPU_texture_create_from_vertbuf(Gwn_VertBuf *vert)
return GPU_texture_create_buffer(data_type, vert->vbo_id);
}
+void GPU_texture_add_mipmap(
+ GPUTexture *tex, GPUDataFormat gpu_data_format, int miplvl, const void *pixels)
+{
+ BLI_assert((int)tex->format > -1);
+ BLI_assert(tex->components > -1);
+
+ gpu_validate_data_format(tex->format, gpu_data_format);
+
+ GLenum internalformat = gpu_get_gl_internalformat(tex->format);
+ GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag);
+ GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
+
+ glBindTexture(tex->target, tex->bindcode);
+
+ int size[3];
+ GPU_texture_get_mipmap_size(tex, miplvl, size);
+
+ switch (tex->target) {
+ case GL_TEXTURE_1D:
+ glTexImage1D(tex->target, miplvl, internalformat, size[0], 0, data_format, data_type, pixels);
+ break;
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_1D_ARRAY:
+ glTexImage2D(tex->target, miplvl, internalformat, size[0], size[1], 0, data_format, data_type, pixels);
+ break;
+ case GL_TEXTURE_3D:
+ case GL_TEXTURE_2D_ARRAY:
+ glTexImage3D(tex->target, miplvl, internalformat, size[0], size[1], size[2], 0, data_format, data_type, pixels);
+ break;
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ /* Multisample textures cannot have mipmaps. */
+ default:
+ BLI_assert(!"tex->target mode not supported");
+ }
+
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, miplvl);
+
+ glBindTexture(tex->target, 0);
+}
+
void GPU_texture_update_sub(
- GPUTexture *tex, const void *pixels,
+ GPUTexture *tex, GPUDataFormat gpu_data_format, const void *pixels,
int offset_x, int offset_y, int offset_z, int width, int height, int depth)
{
BLI_assert((int)tex->format > -1);
BLI_assert(tex->components > -1);
- GLenum format, data_format;
+ GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag);
+ GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
GLint alignment;
- gpu_texture_get_format(tex->components, tex->format, &format, &data_format,
- &tex->format_flag, &tex->bytesize);
/* The default pack size for textures is 4, which won't work for byte based textures */
if (tex->bytesize == 1) {
@@ -906,21 +1039,21 @@ void GPU_texture_update_sub(
glBindTexture(tex->target, tex->bindcode);
switch (tex->target) {
+ case GL_TEXTURE_1D:
+ glTexSubImage1D(tex->target, 0, offset_x, width, data_format, data_type, pixels);
+ break;
case GL_TEXTURE_2D:
case GL_TEXTURE_2D_MULTISAMPLE:
case GL_TEXTURE_1D_ARRAY:
glTexSubImage2D(
tex->target, 0, offset_x, offset_y,
- width, height, format, data_format, pixels);
- break;
- case GL_TEXTURE_1D:
- glTexSubImage1D(tex->target, 0, offset_x, width, format, data_format, pixels);
+ width, height, data_format, data_type, pixels);
break;
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
glTexSubImage3D(
tex->target, 0, offset_x, offset_y, offset_z,
- width, height, depth, format, data_format, pixels);
+ width, height, depth, data_format, data_type, pixels);
break;
default:
BLI_assert(!"tex->target mode not supported");
@@ -933,9 +1066,53 @@ void GPU_texture_update_sub(
glBindTexture(tex->target, 0);
}
-void GPU_texture_update(GPUTexture *tex, const void *pixels)
+void *GPU_texture_read(GPUTexture *tex, GPUDataFormat gpu_data_format, int miplvl)
{
- GPU_texture_update_sub(tex, pixels, 0, 0, 0, tex->w, tex->h, tex->d);
+ int size[3] = {0, 0, 0};
+ GPU_texture_get_mipmap_size(tex, miplvl, size);
+
+ gpu_validate_data_format(tex->format, gpu_data_format);
+
+ size_t buf_size = gpu_texture_memory_footprint_compute(tex);
+ size_t samples_count = max_ii(1, tex->samples);
+
+ samples_count *= size[0];
+ samples_count *= max_ii(1, size[1]);
+ samples_count *= max_ii(1, size[2]);
+
+ switch (gpu_data_format) {
+ case GPU_DATA_FLOAT:
+ buf_size = sizeof(float) * samples_count * tex->components;
+ break;
+ case GPU_DATA_INT:
+ case GPU_DATA_UNSIGNED_INT:
+ buf_size = sizeof(int) * samples_count * tex->components;
+ break;
+ case GPU_DATA_UNSIGNED_INT_24_8:
+ case GPU_DATA_10_11_11_REV:
+ buf_size = sizeof(int) * samples_count;
+ break;
+ case GPU_DATA_UNSIGNED_BYTE:
+ break;
+ }
+
+ void *buf = MEM_mallocN(buf_size, "GPU_texture_read");
+
+ GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag);
+ GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
+
+ glBindTexture(tex->target, tex->bindcode);
+
+ glGetTexImage(tex->target, miplvl, data_format, data_type, buf);
+
+ glBindTexture(tex->target, 0);
+
+ return buf;
+}
+
+void GPU_texture_update(GPUTexture *tex, GPUDataFormat data_format, const void *pixels)
+{
+ GPU_texture_update_sub(tex, data_format, pixels, 0, 0, 0, tex->w, tex->h, tex->d);
}
void GPU_invalid_tex_init(void)
@@ -1199,6 +1376,11 @@ int GPU_texture_height(const GPUTexture *tex)
return tex->h;
}
+int GPU_texture_layers(const GPUTexture *tex)
+{
+ return tex->d;
+}
+
GPUTextureFormat GPU_texture_format(const GPUTexture *tex)
{
return tex->format;
@@ -1260,3 +1442,24 @@ int GPU_texture_detach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb)
BLI_assert(!"Error: Texture: Framebuffer is not attached");
return 0;
}
+
+void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size)
+{
+ /* TODO assert if lvl is bellow the limit of 1px in each dimension. */
+ int div = 1 << lvl;
+ size[0] = max_ii(1, tex->w / div);
+
+ if (tex->target == GL_TEXTURE_1D_ARRAY) {
+ size[1] = tex->h;
+ }
+ else if (tex->h > 0) {
+ size[1] = max_ii(1, tex->h / div);
+ }
+
+ if (tex->target == GL_TEXTURE_2D_ARRAY) {
+ size[2] = tex->d;
+ }
+ else if (tex->d > 0) {
+ size[2] = max_ii(1, tex->d / div);
+ }
+}
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index fa97fd53f32..ec71f28cb23 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -45,6 +45,27 @@ struct ID;
struct PackedFile;
struct GPUTexture;
+/* Runtime display data */
+struct DrawData;
+typedef void (*DrawDataInitCb)(struct DrawData *engine_data);
+typedef void (*DrawDataFreeCb)(struct DrawData *engine_data);
+
+#
+#
+typedef struct DrawData {
+ struct DrawData *next, *prev;
+ struct DrawEngineType *engine_type;
+ /* Only nested data, NOT the engine data itself. */
+ DrawDataFreeCb free;
+ /* Accumulated recalc flags, which corresponds to ID->recalc flags. */
+ int recalc;
+} DrawData;
+
+typedef struct DrawDataList {
+ struct DrawData *first, *last;
+} DrawDataList;
+
+
typedef struct IDPropertyData {
void *pointer;
ListBase group;
diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h
index 86d4645ecf5..c06d75a4021 100644
--- a/source/blender/makesdna/DNA_lightprobe_types.h
+++ b/source/blender/makesdna/DNA_lightprobe_types.h
@@ -106,6 +106,78 @@ enum {
LIGHTPROBE_SHAPE_BOX = 1,
};
+/* ------- Eevee LightProbes ------- */
+/* Needs to be there because written to file
+ * with the lightcache. */
+
+typedef struct LightProbeCache {
+ float position[3], parallax_type;
+ float attenuation_fac;
+ float attenuation_type;
+ float pad3[2];
+ float attenuationmat[4][4];
+ float parallaxmat[4][4];
+} LightProbeCache;
+
+typedef struct LightGridCache {
+ float mat[4][4];
+ int resolution[3], offset; /* offset to the first irradiance sample in the pool. */
+ float corner[3], attenuation_scale;
+ float increment_x[3], attenuation_bias; /* world space vector between 2 opposite cells */
+ float increment_y[3], level_bias;
+ float increment_z[3], pad4;
+ float visibility_bias, visibility_bleed, visibility_range, pad5;
+} LightGridCache;
+
+/* ------ Eevee Lightcache ------- */
+
+typedef struct LightCacheTexture {
+ struct GPUTexture *tex;
+ /* Copy of GPU datas to create GPUTextures on file read. */
+ char *data;
+ int tex_size[3];
+ char data_type;
+ char components;
+ char pad[2];
+} LightCacheTexture;
+
+typedef struct LightCache {
+ int flag;
+ /* only a single cache for now */
+ int cube_len, grid_len; /* Number of probes to use for rendering. */
+ int mips_len; /* Number of mipmap level to use. */
+ int vis_res, ref_res; /* Size of a visibility/reflection sample. */
+ int pad[2];
+ /* In the future, we could create a bigger texture containing
+ * multiple caches (for animation) and interpolate between the
+ * caches overtime to another texture. */
+ LightCacheTexture grid_tx;
+ LightCacheTexture cube_tx; /* Contains data for mipmap level 0. */
+ LightCacheTexture *cube_mips; /* Does not contains valid GPUTexture, only data. */
+ /* All lightprobes data contained in the cache. */
+ LightProbeCache *cube_data;
+ LightGridCache *grid_data;
+} LightCache;
+
+/* LightCache->flag */
+enum {
+ LIGHTCACHE_BAKED = (1 << 0),
+ LIGHTCACHE_BAKING = (1 << 1),
+ LIGHTCACHE_CUBE_READY = (1 << 2),
+ LIGHTCACHE_GRID_READY = (1 << 3),
+ /* Update tagging */
+ LIGHTCACHE_UPDATE_CUBE = (1 << 4),
+ LIGHTCACHE_UPDATE_GRID = (1 << 5),
+ LIGHTCACHE_UPDATE_WORLD = (1 << 6),
+};
+
+/* EEVEE_LightCacheTexture->data_type */
+enum {
+ LIGHTCACHETEX_BYTE = (1 << 0),
+ LIGHTCACHETEX_FLOAT = (1 << 1),
+ LIGHTCACHETEX_UINT = (1 << 2),
+};
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 3bcc0fb6dcc..999ebe0ccc3 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -76,22 +76,6 @@ typedef struct bFaceMap {
char pad[7];
} bFaceMap;
-/* Object Runtime display data */
-struct ObjectEngineData;
-typedef void (*ObjectEngineDataInitCb)(struct ObjectEngineData *engine_data);
-typedef void (*ObjectEngineDataFreeCb)(struct ObjectEngineData *engine_data);
-
-#
-#
-typedef struct ObjectEngineData {
- struct ObjectEngineData *next, *prev;
- struct DrawEngineType *engine_type;
- /* Only nested data, NOT the engine data itself. */
- ObjectEngineDataFreeCb free;
- /* Accumulated recalc flags, which corresponds to ID->recalc flags. */
- int recalc;
-} ObjectEngineData;
-
#define MAX_VGROUP_NAME 64
/* bDeformGroup->flag */
@@ -163,6 +147,7 @@ typedef struct Object_Runtime {
typedef struct Object {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
+ struct DrawDataList drawdata; /* runtime (must be immediately after id for utilities to use it). */
struct SculptSession *sculpt;
@@ -312,7 +297,6 @@ typedef struct Object {
struct PreviewImage *preview;
- ListBase drawdata; /* runtime, ObjectEngineData */
int pad6;
int select_color;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index f8d7e657b76..e6ad7835b24 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1389,6 +1389,9 @@ typedef struct SceneEEVEE {
int gi_cubemap_resolution;
int gi_visibility_resolution;
+ float gi_cubemap_draw_size;
+ float gi_irradiance_draw_size;
+
int taa_samples;
int taa_render_samples;
int sss_samples;
@@ -1428,6 +1431,9 @@ typedef struct SceneEEVEE {
int shadow_method;
int shadow_cube_size;
int shadow_cascade_size;
+
+ struct LightCache *light_cache;
+ char light_cache_info[64];
} SceneEEVEE;
/* *************************************************************** */
@@ -2101,6 +2107,9 @@ enum {
SCE_EEVEE_SSR_ENABLED = (1 << 14),
SCE_EEVEE_SSR_REFRACTION = (1 << 15),
SCE_EEVEE_SSR_HALF_RESOLUTION = (1 << 16),
+ SCE_EEVEE_SHOW_IRRADIANCE = (1 << 17),
+ SCE_EEVEE_SHOW_CUBEMAPS = (1 << 18),
+ SCE_EEVEE_GI_AUTOBAKE = (1 << 19),
};
/* SceneEEVEE->shadow_method */
diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h
index 2e38a402abb..7769833a835 100644
--- a/source/blender/makesdna/DNA_world_types.h
+++ b/source/blender/makesdna/DNA_world_types.h
@@ -51,6 +51,7 @@ struct MTex;
typedef struct World {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
+ DrawDataList drawdata; /* runtime (must be immediately after id for utilities to use it). */
char _pad0[4];
short texact, mistype;
@@ -81,8 +82,7 @@ typedef struct World {
short flag, pad3[3];
struct Ipo *ipo DNA_DEPRECATED; /* old animation system, deprecated for 2.5 */
- short pr_texture, use_nodes, pad;
- short update_flag; /* XXX temporary flag waiting for depsgraph proper tagging */
+ short pr_texture, use_nodes, pad[2];
/* previews */
struct PreviewImage *preview;
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 5b7377eed17..20203492990 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -5814,6 +5814,38 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
"Size of the shadow map applied to each irradiance sample");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ prop = RNA_def_property(srna, "gi_show_irradiance", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHOW_IRRADIANCE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Show Irradiance Cache", "Display irradiance samples in the viewport");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "gi_show_cubemaps", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHOW_CUBEMAPS);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Show Cubemap Cache", "Display captured cubemaps in the viewport");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "gi_irradiance_draw_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.05f, 10.0f);
+ RNA_def_property_float_default(prop, 0.2f);
+ RNA_def_property_ui_text(prop, "Irradiance Draw Size", "Size of the irradiance sample spheres to debug captured light");
+
+ prop = RNA_def_property(srna, "gi_cubemap_draw_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.05f, 10.0f);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Cubemap Draw Size", "Size of the cubemap spheres to debug captured light");
+
+ prop = RNA_def_property(srna, "gi_auto_bake", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GI_AUTOBAKE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Auto Bake", "Auto bake indirect lighting when editing probes");
+
+ prop = RNA_def_property(srna, "gi_cache_info", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "light_cache_info");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Light Cache Info", "Info on current cache status");
+
/* Temporal Anti-Aliasing (super sampling) */
prop = RNA_def_property(srna, "taa_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_default(prop, 16);
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 6d577afdbf9..ccbed11e6e8 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -524,6 +524,7 @@ enum {
WM_JOB_TYPE_ALEMBIC,
WM_JOB_TYPE_SHADER_COMPILATION,
WM_JOB_TYPE_STUDIOLIGHT,
+ WM_JOB_TYPE_LIGHT_BAKE,
/* add as needed, screencast, seq proxy build
* if having hard coded values is a problem */
};
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 8e05822dd55..8b7633b635b 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -257,6 +257,7 @@ typedef struct wmNotifier {
#define NC_GPENCIL (22<<24)
#define NC_LINESTYLE (23<<24)
#define NC_CAMERA (24<<24)
+#define NC_LIGHTPROBE (25<<24)
/* data type, 256 entries is enough, it can overlap */
#define NOTE_DATA 0x00FF0000