diff options
author | Julian Eisel <julian@blender.org> | 2020-03-12 17:58:03 +0300 |
---|---|---|
committer | Julian Eisel <julian@blender.org> | 2020-03-12 17:58:03 +0300 |
commit | b86be9b2145458037fd0b17433b7af0efa7b6472 (patch) | |
tree | f333625555402992ebb35d258f93eda1130389e6 | |
parent | 00f83ec125207e90bf180b3eb7752d8cb6482a86 (diff) | |
parent | cb6cec904fa14ce0ab10a2a53af5c936d56376cf (diff) |
Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside
277 files changed, 8505 insertions, 8220 deletions
diff --git a/extern/bullet2/CMakeLists.txt b/extern/bullet2/CMakeLists.txt index f1bb6a37cbf..b386aa4035b 100644 --- a/extern/bullet2/CMakeLists.txt +++ b/extern/bullet2/CMakeLists.txt @@ -415,4 +415,11 @@ if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") endif() +if(MSVC) + # bullet is responsible for quite a few silly warnings + # suppress all of them. Not great, but they really needed + # to sort that out themselves. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W0") +endif() + blender_add_lib(extern_bullet "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/extern/glog/CMakeLists.txt b/extern/glog/CMakeLists.txt index c60e30d0b48..bfe715d3463 100644 --- a/extern/glog/CMakeLists.txt +++ b/extern/glog/CMakeLists.txt @@ -77,6 +77,11 @@ if(WIN32) list(APPEND INC src/windows ) + if(MSVC) + # Suppress warning about google::LogMessageFatal::~LogMessageFatal + # not returning. + add_definitions("/wd4722") + endif() else() list(APPEND INC include diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index 1014831c403..6d4d2e38e82 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -177,14 +177,11 @@ if(CXX_HAS_AVX2) add_definitions(-DWITH_KERNEL_AVX2) endif() -if(WITH_CYCLES_OSL) - # LLVM and OSL need to build without RTTI - if(WIN32 AND MSVC) - set(RTTI_DISABLE_FLAGS "/GR- -DBOOST_NO_RTTI -DBOOST_NO_TYPEID") - elseif(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang")) - set(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID") - endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RTTI_DISABLE_FLAGS}") +# LLVM and OSL need to build without RTTI +if(WIN32 AND MSVC) + set(RTTI_DISABLE_FLAGS "/GR- -DBOOST_NO_RTTI -DBOOST_NO_TYPEID") +elseif(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang")) + set(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID") endif() # Definitions and Includes diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index 2540786a014..11db5b1a07d 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -292,7 +292,7 @@ static void xml_read_shader_graph(XMLReadState &state, Shader *shader, xml_node filepath = path_join(state.base, filepath); } - snode = ((OSLShaderManager *)manager)->osl_node(filepath); + snode = OSLShaderManager::osl_node(manager, filepath); if (!snode) { fprintf(stderr, "Failed to create OSL node from \"%s\".\n", filepath.c_str()); diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index d9a2ebf8571..ae191b6c0f7 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -38,6 +38,7 @@ set(SRC CCL_api.h blender_device.h blender_id_map.h + blender_image.h blender_object_cull.h blender_sync.h blender_session.h diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 1a93a603e23..cd72da128aa 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -361,6 +361,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Noise level step to stop sampling at, lower values reduce noise the cost of render time. Zero for automatic setting based on number of AA samples", min=0.0, max=1.0, default=0.0, + precision=4, ) adaptive_min_samples: IntProperty( name="Adaptive Min Samples", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index d24d965bb06..3e0d40bc5fd 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -770,6 +770,8 @@ class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel): col.prop(view_layer, "use_solid", text="Surfaces") col = flow.column() col.prop(view_layer, "use_strand", text="Hair") + col = flow.column() + col.prop(view_layer, "use_volumes", text="Volumes") if with_freestyle: col = flow.column() col.prop(view_layer, "use_freestyle", text="Freestyle") diff --git a/intern/cycles/blender/blender_device.cpp b/intern/cycles/blender/blender_device.cpp index d0f8465a98f..5140f190f36 100644 --- a/intern/cycles/blender/blender_device.cpp +++ b/intern/cycles/blender/blender_device.cpp @@ -17,6 +17,8 @@ #include "blender/blender_device.h" #include "blender/blender_util.h" +#include "util/util_foreach.h" + CCL_NAMESPACE_BEGIN enum DenoiserType { diff --git a/intern/cycles/blender/blender_geometry.cpp b/intern/cycles/blender/blender_geometry.cpp index 304b3d18e27..e2a4a125ca1 100644 --- a/intern/cycles/blender/blender_geometry.cpp +++ b/intern/cycles/blender/blender_geometry.cpp @@ -23,6 +23,8 @@ #include "blender/blender_sync.h" #include "blender/blender_util.h" +#include "util/util_foreach.h" + CCL_NAMESPACE_BEGIN Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, diff --git a/intern/cycles/blender/blender_image.cpp b/intern/cycles/blender/blender_image.cpp index 55ce6a295d1..459dc1779fb 100644 --- a/intern/cycles/blender/blender_image.cpp +++ b/intern/cycles/blender/blender_image.cpp @@ -14,206 +14,71 @@ * limitations under the License. */ -#include "render/image.h" +#include "MEM_guardedalloc.h" -#include "blender/blender_sync.h" +#include "blender/blender_image.h" #include "blender/blender_session.h" #include "blender/blender_util.h" CCL_NAMESPACE_BEGIN -/* builtin image file name is actually an image datablock name with - * absolute sequence frame number concatenated via '@' character - * - * this function splits frame from builtin name - */ -int BlenderSession::builtin_image_frame(const string &builtin_name) +/* Packed Images */ + +BlenderImageLoader::BlenderImageLoader(BL::Image b_image, int frame) + : b_image(b_image), frame(frame), free_cache(!b_image.has_data()) { - int last = builtin_name.find_last_of('@'); - return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str()); } -void BlenderSession::builtin_image_info(const string &builtin_name, - void *builtin_data, - ImageMetaData &metadata) +bool BlenderImageLoader::load_metadata(ImageMetaData &metadata) { - /* empty image */ - metadata.width = 1; - metadata.height = 1; - - if (!builtin_data) - return; - - /* recover ID pointer */ - PointerRNA ptr; - RNA_id_pointer_create((ID *)builtin_data, &ptr); - BL::ID b_id(ptr); - - if (b_id.is_a(&RNA_Image)) { - /* image data */ - BL::Image b_image(b_id); + metadata.width = b_image.size()[0]; + metadata.height = b_image.size()[1]; + metadata.depth = 1; + metadata.channels = b_image.channels(); - metadata.builtin_free_cache = !b_image.has_data(); - metadata.is_float = b_image.is_float(); - metadata.width = b_image.size()[0]; - metadata.height = b_image.size()[1]; - metadata.depth = 1; - metadata.channels = b_image.channels(); - - if (metadata.is_float) { - /* Float images are already converted on the Blender side, - * no need to do anything in Cycles. */ - metadata.colorspace = u_colorspace_raw; + if (b_image.is_float()) { + if (metadata.channels == 1) { + metadata.type = IMAGE_DATA_TYPE_FLOAT; } - } - else if (b_id.is_a(&RNA_Object)) { - /* smoke volume data */ - BL::Object b_ob(b_id); - BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob); - - metadata.is_float = true; - metadata.depth = 1; - metadata.channels = 1; - - if (!b_domain) - return; - - if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) - metadata.channels = 1; - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) - metadata.channels = 4; - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) - metadata.channels = 3; - else - return; - - int3 resolution = get_int3(b_domain.domain_resolution()); - int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1; - - /* Velocity and heat data is always low-resolution. */ - if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) { - amplify = 1; + else if (metadata.channels == 4) { + metadata.type = IMAGE_DATA_TYPE_FLOAT4; } - - metadata.width = resolution.x * amplify; - metadata.height = resolution.y * amplify; - metadata.depth = resolution.z * amplify; - } - else { - /* TODO(sergey): Check we're indeed in shader node tree. */ - PointerRNA ptr; - RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr); - BL::Node b_node(ptr); - if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) { - BL::ShaderNodeTexPointDensity b_point_density_node(b_node); - metadata.channels = 4; - metadata.width = b_point_density_node.resolution(); - metadata.height = metadata.width; - metadata.depth = metadata.width; - metadata.is_float = true; + else { + return false; } - } -} -bool BlenderSession::builtin_image_pixels(const string &builtin_name, - void *builtin_data, - int tile, - unsigned char *pixels, - const size_t pixels_size, - const bool associate_alpha, - const bool free_cache) -{ - if (!builtin_data) { - return false; - } - - const int frame = builtin_image_frame(builtin_name); - - PointerRNA ptr; - RNA_id_pointer_create((ID *)builtin_data, &ptr); - BL::Image b_image(ptr); - - const int width = b_image.size()[0]; - const int height = b_image.size()[1]; - const int channels = b_image.channels(); - - unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile); - const size_t num_pixels = ((size_t)width) * height; - - if (image_pixels && num_pixels * channels == pixels_size) { - memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char)); + /* Float images are already converted on the Blender side, + * no need to do anything in Cycles. */ + metadata.colorspace = u_colorspace_raw; } else { - if (channels == 1) { - memset(pixels, 0, pixels_size * sizeof(unsigned char)); + if (metadata.channels == 1) { + metadata.type = IMAGE_DATA_TYPE_BYTE; + } + else if (metadata.channels == 4) { + metadata.type = IMAGE_DATA_TYPE_BYTE4; } else { - const size_t num_pixels_safe = pixels_size / channels; - unsigned char *cp = pixels; - for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) { - cp[0] = 255; - cp[1] = 0; - cp[2] = 255; - if (channels == 4) { - cp[3] = 255; - } - } + return false; } } - if (image_pixels) { - MEM_freeN(image_pixels); - } - - /* Free image buffers to save memory during render. */ - if (free_cache) { - b_image.buffers_free(); - } - - if (associate_alpha) { - /* Premultiply, byte images are always straight for Blender. */ - unsigned char *cp = pixels; - for (size_t i = 0; i < num_pixels; i++, cp += channels) { - cp[0] = (cp[0] * cp[3]) >> 8; - cp[1] = (cp[1] * cp[3]) >> 8; - cp[2] = (cp[2] * cp[3]) >> 8; - } - } return true; } -bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, - void *builtin_data, - int tile, - float *pixels, - const size_t pixels_size, - const bool, - const bool free_cache) +bool BlenderImageLoader::load_pixels(const ImageMetaData &metadata, + void *pixels, + const size_t pixels_size, + const bool associate_alpha) { - if (!builtin_data) { - return false; - } + const size_t num_pixels = ((size_t)metadata.width) * metadata.height; + const int channels = metadata.channels; + const int tile = 0; /* TODO(lukas): Support tiles here? */ - PointerRNA ptr; - RNA_id_pointer_create((ID *)builtin_data, &ptr); - BL::ID b_id(ptr); - - if (b_id.is_a(&RNA_Image)) { + if (b_image.is_float()) { /* image data */ - BL::Image b_image(b_id); - int frame = builtin_image_frame(builtin_name); - - const int width = b_image.size()[0]; - const int height = b_image.size()[1]; - const int channels = b_image.channels(); - float *image_pixels; image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile); - const size_t num_pixels = ((size_t)width) * height; if (image_pixels && num_pixels * channels == pixels_size) { memcpy(pixels, image_pixels, pixels_size * sizeof(float)); @@ -224,7 +89,7 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, } else { const size_t num_pixels_safe = pixels_size / channels; - float *fp = pixels; + float *fp = (float *)pixels; for (int i = 0; i < num_pixels_safe; i++, fp += channels) { fp[0] = 1.0f; fp[1] = 0.0f; @@ -239,107 +104,91 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, if (image_pixels) { MEM_freeN(image_pixels); } - - /* Free image buffers to save memory during render. */ - if (free_cache) { - b_image.buffers_free(); - } - - return true; } - else if (b_id.is_a(&RNA_Object)) { - /* smoke volume data */ - BL::Object b_ob(b_id); - BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob); - - if (!b_domain) { - return false; - } -#ifdef WITH_FLUID - int3 resolution = get_int3(b_domain.domain_resolution()); - int length, amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1; - - /* Velocity and heat data is always low-resolution. */ - if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) { - amplify = 1; - } - - const int width = resolution.x * amplify; - const int height = resolution.y * amplify; - const int depth = resolution.z * amplify; - const size_t num_pixels = ((size_t)width) * height * depth; + else { + unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile); - if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) { - FluidDomainSettings_density_grid_get_length(&b_domain.ptr, &length); - if (length == num_pixels) { - FluidDomainSettings_density_grid_get(&b_domain.ptr, pixels); - return true; - } - } - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) { - /* this is in range 0..1, and interpreted by the OpenGL smoke viewer - * as 1500..3000 K with the first part faded to zero density */ - FluidDomainSettings_flame_grid_get_length(&b_domain.ptr, &length); - if (length == num_pixels) { - FluidDomainSettings_flame_grid_get(&b_domain.ptr, pixels); - return true; - } + if (image_pixels && num_pixels * channels == pixels_size) { + memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char)); } - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) { - /* the RGB is "premultiplied" by density for better interpolation results */ - FluidDomainSettings_color_grid_get_length(&b_domain.ptr, &length); - if (length == num_pixels * 4) { - FluidDomainSettings_color_grid_get(&b_domain.ptr, pixels); - return true; + else { + if (channels == 1) { + memset(pixels, 0, pixels_size * sizeof(unsigned char)); } - } - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) { - FluidDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length); - if (length == num_pixels * 3) { - FluidDomainSettings_velocity_grid_get(&b_domain.ptr, pixels); - return true; + else { + const size_t num_pixels_safe = pixels_size / channels; + unsigned char *cp = (unsigned char *)pixels; + for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) { + cp[0] = 255; + cp[1] = 0; + cp[2] = 255; + if (channels == 4) { + cp[3] = 255; + } + } } } - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) { - FluidDomainSettings_heat_grid_get_length(&b_domain.ptr, &length); - if (length == num_pixels) { - FluidDomainSettings_heat_grid_get(&b_domain.ptr, pixels); - return true; - } + + if (image_pixels) { + MEM_freeN(image_pixels); } - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) { - FluidDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length); - if (length == num_pixels) { - FluidDomainSettings_temperature_grid_get(&b_domain.ptr, pixels); - return true; + + if (associate_alpha) { + /* Premultiply, byte images are always straight for Blender. */ + unsigned char *cp = (unsigned char *)pixels; + for (size_t i = 0; i < num_pixels; i++, cp += channels) { + cp[0] = (cp[0] * cp[3]) >> 8; + cp[1] = (cp[1] * cp[3]) >> 8; + cp[2] = (cp[2] * cp[3]) >> 8; } } - else { - fprintf( - stderr, "Cycles error: unknown volume attribute %s, skipping\n", builtin_name.c_str()); - pixels[0] = 0.0f; - return false; - } -#endif - fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n"); } - else { - /* We originally were passing view_layer here but in reality we need a - * a depsgraph to pass to the RE_point_density_minmax() function. - */ - /* TODO(sergey): Check we're indeed in shader node tree. */ - PointerRNA ptr; - RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr); - BL::Node b_node(ptr); - if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) { - BL::ShaderNodeTexPointDensity b_point_density_node(b_node); - int length; - b_point_density_node.calc_point_density(b_depsgraph, &length, &pixels); - } + + /* Free image buffers to save memory during render. */ + if (free_cache) { + b_image.buffers_free(); } - return false; + return true; +} + +string BlenderImageLoader::name() const +{ + return BL::Image(b_image).name(); +} + +bool BlenderImageLoader::equals(const ImageLoader &other) const +{ + const BlenderImageLoader &other_loader = (const BlenderImageLoader &)other; + return b_image == other_loader.b_image && frame == other_loader.frame; +} + +/* Point Density */ + +BlenderPointDensityLoader::BlenderPointDensityLoader(BL::Depsgraph b_depsgraph, + BL::ShaderNodeTexPointDensity b_node) + : b_depsgraph(b_depsgraph), b_node(b_node) +{ +} + +bool BlenderPointDensityLoader::load_metadata(ImageMetaData &metadata) +{ + metadata.channels = 4; + metadata.width = b_node.resolution(); + metadata.height = metadata.width; + metadata.depth = metadata.width; + metadata.type = IMAGE_DATA_TYPE_FLOAT4; + return true; +} + +bool BlenderPointDensityLoader::load_pixels(const ImageMetaData &, + void *pixels, + const size_t, + const bool) +{ + int length; + b_node.calc_point_density(b_depsgraph, &length, (float **)&pixels); + return true; } void BlenderSession::builtin_images_load() @@ -357,4 +206,15 @@ void BlenderSession::builtin_images_load() manager->device_load_builtin(device, session->scene, session->progress); } +string BlenderPointDensityLoader::name() const +{ + return BL::ShaderNodeTexPointDensity(b_node).name(); +} + +bool BlenderPointDensityLoader::equals(const ImageLoader &other) const +{ + const BlenderPointDensityLoader &other_loader = (const BlenderPointDensityLoader &)other; + return b_node == other_loader.b_node && b_depsgraph == other_loader.b_depsgraph; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_image.h b/intern/cycles/blender/blender_image.h new file mode 100644 index 00000000000..b58a159a6ba --- /dev/null +++ b/intern/cycles/blender/blender_image.h @@ -0,0 +1,61 @@ +/* + * Copyright 2011-2020 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __BLENDER_IMAGE_H__ +#define __BLENDER_IMAGE_H__ + +#include "RNA_blender_cpp.h" + +#include "render/image.h" + +CCL_NAMESPACE_BEGIN + +class BlenderImageLoader : public ImageLoader { + public: + BlenderImageLoader(BL::Image b_image, int frame); + + bool load_metadata(ImageMetaData &metadata) override; + bool load_pixels(const ImageMetaData &metadata, + void *pixels, + const size_t pixels_size, + const bool associate_alpha) override; + string name() const override; + bool equals(const ImageLoader &other) const override; + + BL::Image b_image; + int frame; + bool free_cache; +}; + +class BlenderPointDensityLoader : public ImageLoader { + public: + BlenderPointDensityLoader(BL::Depsgraph depsgraph, BL::ShaderNodeTexPointDensity b_node); + + bool load_metadata(ImageMetaData &metadata) override; + bool load_pixels(const ImageMetaData &metadata, + void *pixels, + const size_t pixels_size, + const bool associate_alpha) override; + string name() const override; + bool equals(const ImageLoader &other) const override; + + BL::Depsgraph b_depsgraph; + BL::ShaderNodeTexPointDensity b_node; +}; + +CCL_NAMESPACE_END + +#endif /* __BLENDER_IMAGE_H__ */ diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index ac307743e48..8e01ad9a96d 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -138,14 +138,6 @@ void BlenderSession::create_session() scene = new Scene(scene_params, session->device); scene->name = b_scene.name(); - /* setup callbacks for builtin image support */ - scene->image_manager->builtin_image_info_cb = function_bind( - &BlenderSession::builtin_image_info, this, _1, _2, _3); - scene->image_manager->builtin_image_pixels_cb = function_bind( - &BlenderSession::builtin_image_pixels, this, _1, _2, _3, _4, _5, _6, _7); - scene->image_manager->builtin_image_float_pixels_cb = function_bind( - &BlenderSession::builtin_image_float_pixels, this, _1, _2, _3, _4, _5, _6, _7); - session->scene = scene; /* There is no single depsgraph to use for the entire render. diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index a107d526dd6..3e6498bb655 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -157,22 +157,6 @@ class BlenderSession { bool do_update_only); void do_write_update_render_tile(RenderTile &rtile, bool do_update_only, bool highlight); - int builtin_image_frame(const string &builtin_name); - void builtin_image_info(const string &builtin_name, void *builtin_data, ImageMetaData &metadata); - bool builtin_image_pixels(const string &builtin_name, - void *builtin_data, - int tile, - unsigned char *pixels, - const size_t pixels_size, - const bool associate_alpha, - const bool free_cache); - bool builtin_image_float_pixels(const string &builtin_name, - void *builtin_data, - int tile, - float *pixels, - const size_t pixels_size, - const bool associate_alpha, - const bool free_cache); void builtin_images_load(); /* Update tile manager to reflect resumable render settings. */ diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 732c4b0da96..dc226805664 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -23,6 +23,7 @@ #include "render/scene.h" #include "render/shader.h" +#include "blender/blender_image.h" #include "blender/blender_texture.h" #include "blender/blender_sync.h" #include "blender/blender_util.h" @@ -619,16 +620,16 @@ static ShaderNode *add_node(Scene *scene, /* create script node */ BL::ShaderNodeScript b_script_node(b_node); - OSLShaderManager *manager = (OSLShaderManager *)scene->shader_manager; + ShaderManager *manager = scene->shader_manager; string bytecode_hash = b_script_node.bytecode_hash(); if (!bytecode_hash.empty()) { - node = manager->osl_node("", bytecode_hash, b_script_node.bytecode()); + node = OSLShaderManager::osl_node(manager, "", bytecode_hash, b_script_node.bytecode()); } else { string absolute_filepath = blender_absolute_path( b_data, b_ntree, b_script_node.filepath()); - node = manager->osl_node(absolute_filepath, ""); + node = OSLShaderManager::osl_node(manager, absolute_filepath, ""); } } #else @@ -650,6 +651,18 @@ static ShaderNode *add_node(Scene *scene, get_tex_mapping(&image->tex_mapping, b_texture_mapping); if (b_image) { + PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr; + image->colorspace = get_enum_identifier(colorspace_ptr, "name"); + + image->animated = b_image_node.image_user().use_auto_refresh(); + image->alpha_type = get_image_alpha_type(b_image); + + image->tiles.clear(); + BL::Image::tiles_iterator b_iter; + for (b_image.tiles.begin(b_iter); b_iter != b_image.tiles.end(); ++b_iter) { + image->tiles.push_back(b_iter->number()); + } + /* builtin images will use callback-based reading because * they could only be loaded correct from blender side */ @@ -666,34 +679,13 @@ static ShaderNode *add_node(Scene *scene, */ int scene_frame = b_scene.frame_current(); int image_frame = image_user_frame_number(b_image_user, scene_frame); - image->filename = b_image.name() + "@" + string_printf("%d", image_frame); - image->builtin_data = b_image.ptr.data; + image->handle = scene->image_manager->add_image( + new BlenderImageLoader(b_image, image_frame), image->image_params()); } else { image->filename = image_user_file_path( b_image_user, b_image, b_scene.frame_current(), true); - image->builtin_data = NULL; - } - - PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr; - image->colorspace = get_enum_identifier(colorspace_ptr, "name"); - - image->animated = b_image_node.image_user().use_auto_refresh(); - image->alpha_type = get_image_alpha_type(b_image); - - image->tiles.clear(); - BL::Image::tiles_iterator b_iter; - for (b_image.tiles.begin(b_iter); b_iter != b_image.tiles.end(); ++b_iter) { - image->tiles.push_back(b_iter->number()); - } - - /* TODO: restore */ - /* TODO(sergey): Does not work properly when we change builtin type. */ -#if 0 - if (b_image.is_updated()) { - scene->image_manager->tag_reload_image(image->image_key()); } -#endif } node = image; } @@ -709,6 +701,12 @@ static ShaderNode *add_node(Scene *scene, get_tex_mapping(&env->tex_mapping, b_texture_mapping); if (b_image) { + PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr; + env->colorspace = get_enum_identifier(colorspace_ptr, "name"); + + env->animated = b_env_node.image_user().use_auto_refresh(); + env->alpha_type = get_image_alpha_type(b_image); + bool is_builtin = b_image.packed_file() || b_image.source() == BL::Image::source_GENERATED || b_image.source() == BL::Image::source_MOVIE || (b_engine.is_preview() && b_image.source() != BL::Image::source_SEQUENCE); @@ -716,28 +714,13 @@ static ShaderNode *add_node(Scene *scene, if (is_builtin) { int scene_frame = b_scene.frame_current(); int image_frame = image_user_frame_number(b_image_user, scene_frame); - env->filename = b_image.name() + "@" + string_printf("%d", image_frame); - env->builtin_data = b_image.ptr.data; + env->handle = scene->image_manager->add_image(new BlenderImageLoader(b_image, image_frame), + env->image_params()); } else { env->filename = image_user_file_path( b_image_user, b_image, b_scene.frame_current(), false); - env->builtin_data = NULL; } - - PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr; - env->colorspace = get_enum_identifier(colorspace_ptr, "name"); - - env->animated = b_env_node.image_user().use_auto_refresh(); - env->alpha_type = get_image_alpha_type(b_image); - - /* TODO: restore */ - /* TODO(sergey): Does not work properly when we change builtin type. */ -#if 0 - if (b_image.is_updated()) { - scene->image_manager->tag_reload_image(env->image_key()); - } -#endif } node = env; } @@ -881,18 +864,13 @@ static ShaderNode *add_node(Scene *scene, else if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) { BL::ShaderNodeTexPointDensity b_point_density_node(b_node); PointDensityTextureNode *point_density = new PointDensityTextureNode(); - point_density->filename = b_point_density_node.name(); point_density->space = (NodeTexVoxelSpace)b_point_density_node.space(); point_density->interpolation = get_image_interpolation(b_point_density_node); - point_density->builtin_data = b_point_density_node.ptr.data; - point_density->image_manager = scene->image_manager; - - /* TODO(sergey): Use more proper update flag. */ - if (true) { - point_density->add_image(); - b_point_density_node.cache_point_density(b_depsgraph); - scene->image_manager->tag_reload_image(point_density->image_key()); - } + point_density->handle = scene->image_manager->add_image( + new BlenderPointDensityLoader(b_depsgraph, b_point_density_node), + point_density->image_params()); + + b_point_density_node.cache_point_density(b_depsgraph); node = point_density; /* Transformation form world space to texture space. diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 8f00f9ccda0..4529c6a2798 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -405,6 +405,7 @@ void BlenderSync::sync_view_layer(BL::SpaceView3D & /*b_v3d*/, BL::ViewLayer &b_ view_layer.use_background_ao = b_view_layer.use_ao(); view_layer.use_surfaces = b_view_layer.use_solid(); view_layer.use_hair = b_view_layer.use_strand(); + view_layer.use_volumes = b_view_layer.use_volumes(); /* Material override. */ view_layer.material_override = b_view_layer.material_override(); diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 0a7174e407b..d212caa69f7 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -236,6 +236,7 @@ class BlenderSync { use_background_ao(true), use_surfaces(true), use_hair(true), + use_volumes(true), samples(0), bound_samples(false) { @@ -247,6 +248,7 @@ class BlenderSync { bool use_background_ao; bool use_surfaces; bool use_hair; + bool use_volumes; int samples; bool bound_samples; } view_layer; diff --git a/intern/cycles/blender/blender_volume.cpp b/intern/cycles/blender/blender_volume.cpp index 47259d4945c..237c5d061e8 100644 --- a/intern/cycles/blender/blender_volume.cpp +++ b/intern/cycles/blender/blender_volume.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2011-2013 Blender Foundation * @@ -24,6 +23,152 @@ CCL_NAMESPACE_BEGIN +/* TODO: verify this is not loading unnecessary attributes. */ +class BlenderSmokeLoader : public ImageLoader { + public: + BlenderSmokeLoader(const BL::Object &b_ob, AttributeStandard attribute) + : b_ob(b_ob), attribute(attribute) + { + } + + bool load_metadata(ImageMetaData &metadata) override + { + BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob); + + if (!b_domain) { + return false; + } + + if (attribute == ATTR_STD_VOLUME_DENSITY || attribute == ATTR_STD_VOLUME_FLAME || + attribute == ATTR_STD_VOLUME_HEAT || attribute == ATTR_STD_VOLUME_TEMPERATURE) { + metadata.type = IMAGE_DATA_TYPE_FLOAT; + metadata.channels = 1; + } + else if (attribute == ATTR_STD_VOLUME_COLOR) { + metadata.type = IMAGE_DATA_TYPE_FLOAT4; + metadata.channels = 4; + } + else if (attribute == ATTR_STD_VOLUME_VELOCITY) { + metadata.type = IMAGE_DATA_TYPE_FLOAT4; + metadata.channels = 3; + } + else { + return false; + } + + int3 resolution = get_int3(b_domain.domain_resolution()); + int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1; + + /* Velocity and heat data is always low-resolution. */ + if (attribute == ATTR_STD_VOLUME_VELOCITY || attribute == ATTR_STD_VOLUME_HEAT) { + amplify = 1; + } + + metadata.width = resolution.x * amplify; + metadata.height = resolution.y * amplify; + metadata.depth = resolution.z * amplify; + + return true; + } + + bool load_pixels(const ImageMetaData &, void *pixels, const size_t, const bool) override + { + /* smoke volume data */ + BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob); + + if (!b_domain) { + return false; + } +#ifdef WITH_FLUID + int3 resolution = get_int3(b_domain.domain_resolution()); + int length, amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1; + + /* Velocity and heat data is always low-resolution. */ + if (attribute == ATTR_STD_VOLUME_VELOCITY || attribute == ATTR_STD_VOLUME_HEAT) { + amplify = 1; + } + + const int width = resolution.x * amplify; + const int height = resolution.y * amplify; + const int depth = resolution.z * amplify; + const size_t num_pixels = ((size_t)width) * height * depth; + + float *fpixels = (float *)pixels; + + if (attribute == ATTR_STD_VOLUME_DENSITY) { + FluidDomainSettings_density_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels) { + FluidDomainSettings_density_grid_get(&b_domain.ptr, fpixels); + return true; + } + } + else if (attribute == ATTR_STD_VOLUME_FLAME) { + /* this is in range 0..1, and interpreted by the OpenGL smoke viewer + * as 1500..3000 K with the first part faded to zero density */ + FluidDomainSettings_flame_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels) { + FluidDomainSettings_flame_grid_get(&b_domain.ptr, fpixels); + return true; + } + } + else if (attribute == ATTR_STD_VOLUME_COLOR) { + /* the RGB is "premultiplied" by density for better interpolation results */ + FluidDomainSettings_color_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels * 4) { + FluidDomainSettings_color_grid_get(&b_domain.ptr, fpixels); + return true; + } + } + else if (attribute == ATTR_STD_VOLUME_VELOCITY) { + FluidDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels * 3) { + FluidDomainSettings_velocity_grid_get(&b_domain.ptr, fpixels); + return true; + } + } + else if (attribute == ATTR_STD_VOLUME_HEAT) { + FluidDomainSettings_heat_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels) { + FluidDomainSettings_heat_grid_get(&b_domain.ptr, fpixels); + return true; + } + } + else if (attribute == ATTR_STD_VOLUME_TEMPERATURE) { + FluidDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels) { + FluidDomainSettings_temperature_grid_get(&b_domain.ptr, fpixels); + return true; + } + } + else { + fprintf(stderr, + "Cycles error: unknown volume attribute %s, skipping\n", + Attribute::standard_name(attribute)); + fpixels[0] = 0.0f; + return false; + } +#else + (void)pixels; +#endif + fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n"); + return false; + } + + string name() const override + { + return Attribute::standard_name(attribute); + } + + bool equals(const ImageLoader &other) const override + { + const BlenderSmokeLoader &other_loader = (const BlenderSmokeLoader &)other; + return b_ob == other_loader.b_ob && attribute == other_loader.attribute; + } + + BL::Object b_ob; + AttributeStandard attribute; +}; + static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Mesh *mesh, float frame) { BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob); @@ -31,7 +176,6 @@ static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Mesh *mesh, float return; } - ImageManager *image_manager = scene->image_manager; AttributeStandard attributes[] = {ATTR_STD_VOLUME_DENSITY, ATTR_STD_VOLUME_COLOR, ATTR_STD_VOLUME_FLAME, @@ -49,15 +193,12 @@ static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Mesh *mesh, float mesh->volume_isovalue = b_domain.clipping(); Attribute *attr = mesh->attributes.add(std); - VoxelAttribute *volume_data = attr->data_voxel(); - ImageMetaData metadata; - ImageKey key; - key.filename = Attribute::standard_name(std); - key.builtin_data = b_ob.ptr.data; + ImageLoader *loader = new BlenderSmokeLoader(b_ob, std); + ImageParams params; + params.frame = frame; - volume_data->manager = image_manager; - volume_data->slot = image_manager->add_image(key, frame, metadata); + attr->data_voxel() = scene->image_manager->add_image(loader, params); } /* Create a matrix to transform from object space to mesh texture space. @@ -75,18 +216,33 @@ static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Mesh *mesh, float } } +/* If the voxel attributes change, we need to rebuild the bounding mesh. */ +static vector<int> get_voxel_image_slots(Mesh *mesh) +{ + vector<int> slots; + for (const Attribute &attr : mesh->attributes.attributes) { + if (attr.element == ATTR_ELEMENT_VOXEL) { + slots.push_back(attr.data_voxel().svm_slot()); + } + } + + return slots; +} + void BlenderSync::sync_volume(BL::Object &b_ob, Mesh *mesh, const vector<Shader *> &used_shaders) { - bool old_has_voxel_attributes = mesh->has_voxel_attributes(); + vector<int> old_voxel_slots = get_voxel_image_slots(mesh); mesh->clear(); mesh->used_shaders = used_shaders; /* Smoke domain. */ - sync_smoke_volume(scene, b_ob, mesh, b_scene.frame_current()); + if (view_layer.use_volumes) { + sync_smoke_volume(scene, b_ob, mesh, b_scene.frame_current()); + } /* Tag update. */ - bool rebuild = (old_has_voxel_attributes != mesh->has_voxel_attributes()); + bool rebuild = (old_voxel_slots != get_voxel_image_slots(mesh)); mesh->tag_update(scene, rebuild); } diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index 3a8b0fe7fa2..e6502a40313 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -535,8 +535,9 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) /* Modify offsets into arrays */ int4 data = bvh_nodes[i + nsize_bbox]; - int4 data1 = bvh_nodes[i + nsize_bbox - 1]; + if (use_obvh) { + int4 data1 = bvh_nodes[i + nsize_bbox - 1]; data.z += (data.z < 0) ? -noffset_leaf : noffset; data.w += (data.w < 0) ? -noffset_leaf : noffset; data.x += (data.x < 0) ? -noffset_leaf : noffset; @@ -545,6 +546,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) data1.w += (data1.w < 0) ? -noffset_leaf : noffset; data1.x += (data1.x < 0) ? -noffset_leaf : noffset; data1.y += (data1.y < 0) ? -noffset_leaf : noffset; + pack_nodes[pack_nodes_offset + nsize_bbox] = data; + pack_nodes[pack_nodes_offset + nsize_bbox - 1] = data1; } else { data.z += (data.z < 0) ? -noffset_leaf : noffset; @@ -553,10 +556,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) data.x += (data.x < 0) ? -noffset_leaf : noffset; data.y += (data.y < 0) ? -noffset_leaf : noffset; } - } - pack_nodes[pack_nodes_offset + nsize_bbox] = data; - if (use_obvh) { - pack_nodes[pack_nodes_offset + nsize_bbox - 1] = data1; + pack_nodes[pack_nodes_offset + nsize_bbox] = data; } /* Usually this copies nothing, but we better diff --git a/intern/cycles/bvh/bvh_optix.cpp b/intern/cycles/bvh/bvh_optix.cpp index a3b6261dcad..da548e9c0db 100644 --- a/intern/cycles/bvh/bvh_optix.cpp +++ b/intern/cycles/bvh/bvh_optix.cpp @@ -22,6 +22,7 @@ # include "render/geometry.h" # include "render/mesh.h" # include "render/object.h" +# include "util/util_foreach.h" # include "util/util_logging.h" # include "util/util_progress.h" diff --git a/intern/cycles/device/cuda/device_cuda_impl.cpp b/intern/cycles/device/cuda/device_cuda_impl.cpp index 4e8d8b7ca7c..4df1ca2097a 100644 --- a/intern/cycles/device/cuda/device_cuda_impl.cpp +++ b/intern/cycles/device/cuda/device_cuda_impl.cpp @@ -1169,10 +1169,10 @@ void CUDADevice::tex_alloc(device_memory &mem) } /* Kepler+, bindless textures. */ - int flat_slot = 0; + int slot = 0; if (string_startswith(mem.name, "__tex_image")) { int pos = string(mem.name).rfind("_"); - flat_slot = atoi(mem.name + pos + 1); + slot = atoi(mem.name + pos + 1); } else { assert(0); @@ -1214,15 +1214,16 @@ void CUDADevice::tex_alloc(device_memory &mem) cuda_assert(cuTexObjectCreate(&cmem->texobject, &resDesc, &texDesc, NULL)); /* Resize once */ - if (flat_slot >= texture_info.size()) { + if (slot >= texture_info.size()) { /* Allocate some slots in advance, to reduce amount * of re-allocations. */ - texture_info.resize(flat_slot + 128); + texture_info.resize(slot + 128); } /* Set Mapping and tag that we need to (re-)upload to device */ - TextureInfo &info = texture_info[flat_slot]; + TextureInfo &info = texture_info[slot]; info.data = (uint64_t)cmem->texobject; + info.data_type = mem.image_data_type; info.cl_buffer = 0; info.interpolation = mem.interpolation; info.extension = mem.extension; diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index d11918ccbbf..56569a5ee3d 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -465,23 +465,24 @@ class CPUDevice : public Device { } else { /* Image Texture. */ - int flat_slot = 0; + int slot = 0; if (string_startswith(mem.name, "__tex_image")) { int pos = string(mem.name).rfind("_"); - flat_slot = atoi(mem.name + pos + 1); + slot = atoi(mem.name + pos + 1); } else { assert(0); } - if (flat_slot >= texture_info.size()) { + if (slot >= texture_info.size()) { /* Allocate some slots in advance, to reduce amount * of re-allocations. */ - texture_info.resize(flat_slot + 128); + texture_info.resize(slot + 128); } - TextureInfo &info = texture_info[flat_slot]; + TextureInfo &info = texture_info[slot]; info.data = (uint64_t)mem.host_pointer; + info.data_type = mem.image_data_type; info.cl_buffer = 0; info.interpolation = mem.interpolation; info.extension = mem.extension; diff --git a/intern/cycles/device/device_memory.cpp b/intern/cycles/device/device_memory.cpp index 3a99a49dffc..f22b91f3fa1 100644 --- a/intern/cycles/device/device_memory.cpp +++ b/intern/cycles/device/device_memory.cpp @@ -31,6 +31,7 @@ device_memory::device_memory(Device *device, const char *name, MemoryType type) data_depth(0), type(type), name(name), + image_data_type(IMAGE_DATA_NUM_TYPES), interpolation(INTERPOLATION_NONE), extension(EXTENSION_REPEAT), device(device), diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h index 2949773ef0c..617cc0c4342 100644 --- a/intern/cycles/device/device_memory.h +++ b/intern/cycles/device/device_memory.h @@ -208,6 +208,7 @@ class device_memory { size_t data_depth; MemoryType type; const char *name; + ImageDataType image_data_type; InterpolationType interpolation; ExtensionType extension; diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp index 30d624fdf7c..329876ce6f6 100644 --- a/intern/cycles/device/device_optix.cpp +++ b/intern/cycles/device/device_optix.cpp @@ -477,9 +477,9 @@ class OptiXDevice : public CUDADevice { // Calculate maximum trace continuation stack size unsigned int trace_css = stack_size[PG_HITD].cssCH; // This is based on the maximum of closest-hit and any-hit/intersection programs - trace_css = max(trace_css, stack_size[PG_HITD].cssIS + stack_size[PG_HITD].cssAH); - trace_css = max(trace_css, stack_size[PG_HITL].cssIS + stack_size[PG_HITL].cssAH); - trace_css = max(trace_css, stack_size[PG_HITS].cssIS + stack_size[PG_HITS].cssAH); + trace_css = std::max(trace_css, stack_size[PG_HITD].cssIS + stack_size[PG_HITD].cssAH); + trace_css = std::max(trace_css, stack_size[PG_HITL].cssIS + stack_size[PG_HITL].cssAH); + trace_css = std::max(trace_css, stack_size[PG_HITS].cssIS + stack_size[PG_HITS].cssAH); OptixPipelineLinkOptions link_options; link_options.maxTraceDepth = 1; @@ -548,8 +548,9 @@ class OptiXDevice : public CUDADevice { &pipelines[PIP_SHADER_EVAL])); // Calculate continuation stack size based on the maximum of all ray generation stack sizes - const unsigned int css = max(stack_size[PG_BAKE].cssRG, - max(stack_size[PG_DISP].cssRG, stack_size[PG_BACK].cssRG)) + + const unsigned int css = std::max(stack_size[PG_BAKE].cssRG, + std::max(stack_size[PG_DISP].cssRG, + stack_size[PG_BACK].cssRG)) + link_options.maxTraceDepth * trace_css; check_result_optix_ret(optixPipelineSetStackSize( diff --git a/intern/cycles/device/opencl/device_opencl_impl.cpp b/intern/cycles/device/opencl/device_opencl_impl.cpp index 3dbe54b38aa..09d3b78dd28 100644 --- a/intern/cycles/device/opencl/device_opencl_impl.cpp +++ b/intern/cycles/device/opencl/device_opencl_impl.cpp @@ -1298,6 +1298,8 @@ void OpenCLDevice::flush_texture_buffers() if (string_startswith(slot.name, "__tex_image")) { device_memory *mem = textures[slot.name]; + info.data_type = mem->image_data_type; + info.width = mem->data_width; info.height = mem->data_height; info.depth = mem->data_depth; diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h index ec41ef2f0e9..f4c3b36e778 100644 --- a/intern/cycles/kernel/kernel_random.h +++ b/intern/cycles/kernel/kernel_random.h @@ -302,7 +302,7 @@ ccl_device_inline bool sample_is_even(int pattern, int sample) #elif defined(__KERNEL_OPENCL__) return popcount(sample & 0xaaaaaaaa) & 1; #else -/* TODO(Stefan): popcnt intrinsic for Windows with fallback for older CPUs. */ + /* TODO(Stefan): popcnt intrinsic for Windows with fallback for older CPUs. */ int i = sample & 0xaaaaaaaa; i = i - ((i >> 1) & 0x55555555); i = (i & 0x33333333) + ((i >> 2) & 0x33333333); diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h index 8f311baf010..7eb66b0b4ca 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h +++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h @@ -474,7 +474,7 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, fl { const TextureInfo &info = kernel_tex_fetch(__texture_info, id); - switch (kernel_tex_type(id)) { + switch (info.data_type) { case IMAGE_DATA_TYPE_HALF: return TextureInterpolator<half>::interp(info, x, y); case IMAGE_DATA_TYPE_BYTE: @@ -503,7 +503,7 @@ ccl_device float4 kernel_tex_image_interp_3d( { const TextureInfo &info = kernel_tex_fetch(__texture_info, id); - switch (kernel_tex_type(id)) { + switch (info.data_type) { case IMAGE_DATA_TYPE_HALF: return TextureInterpolator<half>::interp_3d(info, x, y, z, interp); case IMAGE_DATA_TYPE_BYTE: diff --git a/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h b/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h index 7c68f08ea10..24bc3c7b59e 100644 --- a/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h +++ b/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h @@ -124,7 +124,7 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, fl CUtexObject tex = (CUtexObject)info.data; /* float4, byte4, ushort4 and half4 */ - const int texture_type = kernel_tex_type(id); + const int texture_type = info.data_type; if (texture_type == IMAGE_DATA_TYPE_FLOAT4 || texture_type == IMAGE_DATA_TYPE_BYTE4 || texture_type == IMAGE_DATA_TYPE_HALF4 || texture_type == IMAGE_DATA_TYPE_USHORT4) { if (info.interpolation == INTERPOLATION_CUBIC) { @@ -156,7 +156,7 @@ ccl_device float4 kernel_tex_image_interp_3d( CUtexObject tex = (CUtexObject)info.data; uint interpolation = (interp == INTERPOLATION_NONE) ? info.interpolation : interp; - const int texture_type = kernel_tex_type(id); + const int texture_type = info.data_type; if (texture_type == IMAGE_DATA_TYPE_FLOAT4 || texture_type == IMAGE_DATA_TYPE_BYTE4 || texture_type == IMAGE_DATA_TYPE_HALF4 || texture_type == IMAGE_DATA_TYPE_USHORT4) { if (interpolation == INTERPOLATION_CUBIC) { diff --git a/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h b/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h index b6390679331..f7dea383b82 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h +++ b/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h @@ -47,7 +47,7 @@ ccl_device_inline float4 svm_image_texture_read(KernelGlobals *kg, int id, int offset) { - const int texture_type = kernel_tex_type(id); + const int texture_type = info->data_type; /* Float4 */ if (texture_type == IMAGE_DATA_TYPE_FLOAT4) { diff --git a/intern/cycles/kernel/osl/CMakeLists.txt b/intern/cycles/kernel/osl/CMakeLists.txt index 5be5bd181ec..fc0c845fd4f 100644 --- a/intern/cycles/kernel/osl/CMakeLists.txt +++ b/intern/cycles/kernel/osl/CMakeLists.txt @@ -33,6 +33,9 @@ set(LIB ${LLVM_LIBRARY} ) +# OSL and LLVM are built without RTTI +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RTTI_DISABLE_FLAGS}") + include_directories(${INC}) include_directories(SYSTEM ${INC_SYS}) diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index 90f1a7845c7..63939a049a5 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -30,10 +30,6 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, if ((flags & NODE_IMAGE_ALPHA_UNASSOCIATE) && alpha != 1.0f && alpha != 0.0f) { r /= alpha; - const int texture_type = kernel_tex_type(id); - if (texture_type == IMAGE_DATA_TYPE_BYTE4 || texture_type == IMAGE_DATA_TYPE_BYTE) { - r = min(r, make_float4(1.0f, 1.0f, 1.0f, 1.0f)); - } r.w = alpha; } diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index 2a077f486fa..9922547a8d2 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -23,6 +23,7 @@ set(SRC graph.cpp hair.cpp image.cpp + image_oiio.cpp integrator.cpp jitter.cpp light.cpp @@ -61,6 +62,7 @@ set(SRC_HEADERS graph.h hair.h image.h + image_oiio.h integrator.h light.h jitter.h @@ -92,6 +94,8 @@ if(WITH_CYCLES_OSL) list(APPEND LIB cycles_kernel_osl ) + + SET_PROPERTY(SOURCE osl.cpp PROPERTY COMPILE_FLAGS ${RTTI_DISABLE_FLAGS}) endif() include_directories(${INC}) diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index 1e293f1aa16..d0d9888ac88 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -26,46 +26,51 @@ CCL_NAMESPACE_BEGIN /* Attribute */ -Attribute::~Attribute() -{ - /* for voxel data, we need to remove the image from the image manager */ - if (element == ATTR_ELEMENT_VOXEL) { - VoxelAttribute *voxel_data = data_voxel(); - - if (voxel_data && voxel_data->slot != -1) { - voxel_data->manager->remove_image(voxel_data->slot); - } - } -} - -void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_) +Attribute::Attribute( + ustring name, TypeDesc type, AttributeElement element, Geometry *geom, AttributePrimitive prim) + : name(name), std(ATTR_STD_NONE), type(type), element(element), flags(0) { - name = name_; - type = type_; - element = element_; - std = ATTR_STD_NONE; - flags = 0; - /* string and matrix not supported! */ assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor || type == TypeDesc::TypePoint || type == TypeDesc::TypeVector || type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix || type == TypeFloat2 || type == TypeRGBA); + + if (element == ATTR_ELEMENT_VOXEL) { + buffer.resize(sizeof(ImageHandle)); + new (buffer.data()) ImageHandle(); + } + else { + resize(geom, prim, false); + } } -void Attribute::resize(Geometry *geom, AttributePrimitive prim, bool reserve_only) +Attribute::~Attribute() { - if (reserve_only) { - buffer.reserve(buffer_size(geom, prim)); + /* For voxel data, we need to free the image handle. */ + if (element == ATTR_ELEMENT_VOXEL) { + ImageHandle &handle = data_voxel(); + handle.~ImageHandle(); } - else { - buffer.resize(buffer_size(geom, prim), 0); +} + +void Attribute::resize(Geometry *geom, AttributePrimitive prim, bool reserve_only) +{ + if (element != ATTR_ELEMENT_VOXEL) { + if (reserve_only) { + buffer.reserve(buffer_size(geom, prim)); + } + else { + buffer.resize(buffer_size(geom, prim), 0); + } } } void Attribute::resize(size_t num_elements) { - buffer.resize(num_elements * data_sizeof(), 0); + if (element != ATTR_ELEMENT_VOXEL) { + buffer.resize(num_elements * data_sizeof(), 0); + } } void Attribute::add(const float &f) @@ -123,17 +128,6 @@ void Attribute::add(const Transform &f) buffer.push_back(data[i]); } -void Attribute::add(const VoxelAttribute &f) -{ - assert(data_sizeof() == sizeof(VoxelAttribute)); - - char *data = (char *)&f; - size_t size = sizeof(f); - - for (size_t i = 0; i < size; i++) - buffer.push_back(data[i]); -} - void Attribute::add(const char *data) { size_t size = data_sizeof(); @@ -145,7 +139,7 @@ void Attribute::add(const char *data) size_t Attribute::data_sizeof() const { if (element == ATTR_ELEMENT_VOXEL) - return sizeof(VoxelAttribute); + return sizeof(ImageHandle); else if (element == ATTR_ELEMENT_CORNER_BYTE) return sizeof(uchar4); else if (type == TypeDesc::TypeFloat) @@ -414,23 +408,9 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement eleme remove(name); } -#if __cplusplus >= 201103L - attributes.emplace_back(); - attr = &attributes.back(); - attr->set(name, type, element); -#else - { - Attribute attr_temp; - attr_temp.set(name, type, element); - attributes.push_back(attr_temp); - attr = &attributes.back(); - } -#endif - - /* this is weak .. */ - attr->resize(geometry, prim, false); - - return attr; + Attribute new_attr(name, type, element, geometry, prim); + attributes.emplace_back(std::move(new_attr)); + return &attributes.back(); } Attribute *AttributeSet::find(ustring name) const diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h index f1fd30fd85a..351357a7f7a 100644 --- a/intern/cycles/render/attribute.h +++ b/intern/cycles/render/attribute.h @@ -17,6 +17,8 @@ #ifndef __ATTRIBUTE_H__ #define __ATTRIBUTE_H__ +#include "render/image.h" + #include "kernel/kernel_types.h" #include "util/util_list.h" @@ -31,19 +33,12 @@ class Attribute; class AttributeRequest; class AttributeRequestSet; class AttributeSet; -class ImageManager; +class ImageHandle; class Geometry; class Hair; class Mesh; struct Transform; -/* Attributes for voxels are images */ - -struct VoxelAttribute { - ImageManager *manager; - int slot; -}; - /* Attribute * * Arbitrary data layers on meshes. @@ -59,9 +54,11 @@ class Attribute { AttributeElement element; uint flags; /* enum AttributeFlag */ - Attribute() - { - } + Attribute(ustring name, + TypeDesc type, + AttributeElement element, + Geometry *geom, + AttributePrimitive prim); ~Attribute(); void set(ustring name, TypeDesc type, AttributeElement element); void resize(Geometry *geom, AttributePrimitive prim, bool reserve_only); @@ -105,10 +102,12 @@ class Attribute { assert(data_sizeof() == sizeof(Transform)); return (Transform *)data(); } - VoxelAttribute *data_voxel() + + /* Attributes for voxels are images */ + ImageHandle &data_voxel() { - assert(data_sizeof() == sizeof(VoxelAttribute)); - return (VoxelAttribute *)data(); + assert(data_sizeof() == sizeof(ImageHandle)); + return *(ImageHandle *)data(); } const char *data() const @@ -140,10 +139,10 @@ class Attribute { assert(data_sizeof() == sizeof(Transform)); return (const Transform *)data(); } - const VoxelAttribute *data_voxel() const + const ImageHandle &data_voxel() const { - assert(data_sizeof() == sizeof(VoxelAttribute)); - return (const VoxelAttribute *)data(); + assert(data_sizeof() == sizeof(ImageHandle)); + return *(const ImageHandle *)data(); } void zero_data(void *dst); @@ -153,8 +152,7 @@ class Attribute { void add(const float2 &f); void add(const float3 &f); void add(const uchar4 &f); - void add(const Transform &f); - void add(const VoxelAttribute &f); + void add(const Transform &tfm); void add(const char *data); static bool same_storage(TypeDesc a, TypeDesc b); diff --git a/intern/cycles/render/colorspace.cpp b/intern/cycles/render/colorspace.cpp index 2e5b53057c0..97a9ba3f012 100644 --- a/intern/cycles/render/colorspace.cpp +++ b/intern/cycles/render/colorspace.cpp @@ -283,7 +283,7 @@ inline void processor_apply_pixels(const OCIO::Processor *processor, for (size_t x = 0; x < width; x++, i++) { float4 value = cast_to_float4(pixels + 4 * (y * width + x)); - if (!(value.w == 0.0f || value.w == 1.0f)) { + if (!(value.w <= 0.0f || value.w == 1.0f)) { float inv_alpha = 1.0f / value.w; value.x *= inv_alpha; value.y *= inv_alpha; @@ -302,14 +302,16 @@ inline void processor_apply_pixels(const OCIO::Processor *processor, for (size_t x = 0; x < width; x++, i++) { float4 value = float_pixels[i]; - value.x *= value.w; - value.y *= value.w; - value.z *= value.w; - if (compress_as_srgb) { value = color_linear_to_srgb_v4(value); } + if (!(value.w <= 0.0f || value.w == 1.0f)) { + value.x *= value.w; + value.y *= value.w; + value.z *= value.w; + } + cast_from_float4(pixels + 4 * (y * width + x), value); } } diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp index 880fb7b4c7d..748a8f7cf67 100644 --- a/intern/cycles/render/geometry.cpp +++ b/intern/cycles/render/geometry.cpp @@ -534,8 +534,8 @@ static void update_attribute_element_offset(Geometry *geom, if (mattr->element == ATTR_ELEMENT_VOXEL) { /* store slot in offset value */ - VoxelAttribute *voxel_data = mattr->data_voxel(); - offset = voxel_data->slot; + ImageHandle &handle = mattr->data_voxel(); + offset = handle.svm_slot(); } else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { uchar4 *data = mattr->data_uchar4(); @@ -1143,7 +1143,7 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro } Mesh *mesh = static_cast<Mesh *>(geom); - create_volume_mesh(scene, mesh, progress); + create_volume_mesh(mesh, progress); } } } @@ -1171,7 +1171,8 @@ void GeometryManager::device_update_displacement_images(Device *device, } ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode *>(node); - foreach (int slot, image_node->slots) { + for (int i = 0; i < image_node->handle.num_tiles(); i++) { + const int slot = image_node->handle.svm_slot(i); if (slot != -1) { bump_images.insert(slot); } @@ -1204,10 +1205,10 @@ void GeometryManager::device_update_volume_images(Device *device, Scene *scene, continue; } - VoxelAttribute *voxel = attr.data_voxel(); - - if (voxel->slot != -1) { - volume_images.insert(voxel->slot); + ImageHandle &handle = attr.data_voxel(); + const int slot = handle.svm_slot(); + if (slot != -1) { + volume_images.insert(slot); } } } diff --git a/intern/cycles/render/geometry.h b/intern/cycles/render/geometry.h index 66ae8472102..82f539d391d 100644 --- a/intern/cycles/render/geometry.h +++ b/intern/cycles/render/geometry.h @@ -166,7 +166,7 @@ class GeometryManager { protected: bool displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress &progress); - void create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress); + void create_volume_mesh(Mesh *mesh, Progress &progress); /* Attributes */ void update_osl_attributes(Device *device, diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index e5fb2fcaf3d..b4539b5ce3c 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -15,12 +15,14 @@ */ #include "render/image.h" +#include "render/image_oiio.h" #include "device/device.h" #include "render/colorspace.h" #include "render/scene.h" #include "render/stats.h" #include "util/util_foreach.h" +#include "util/util_image.h" #include "util/util_image_impl.h" #include "util/util_logging.h" #include "util/util_path.h" @@ -50,21 +52,6 @@ bool isfinite(uint16_t /*value*/) return true; } -/* The lower three bits of a device texture slot number indicate its type. - * These functions convert the slot ids from ImageManager "images" ones - * to device ones and vice verse. - */ -int type_index_to_flattened_slot(int slot, ImageDataType type) -{ - return (slot << IMAGE_DATA_TYPE_SHIFT) | (type); -} - -int flattened_slot_to_type_index(int flat_slot, ImageDataType *type) -{ - *type = (ImageDataType)(flat_slot & IMAGE_DATA_TYPE_MASK); - return flat_slot >> IMAGE_DATA_TYPE_SHIFT; -} - const char *name_from_type(ImageDataType type) { switch (type) { @@ -94,302 +81,342 @@ const char *name_from_type(ImageDataType type) } // namespace -ImageManager::ImageManager(const DeviceInfo &info) +/* Image Handle */ + +ImageHandle::ImageHandle() : manager(NULL) { - need_update = true; - osl_texture_system = NULL; - animation_frame = 0; +} - /* Set image limits */ - max_num_images = TEX_NUM_MAX; - has_half_images = info.has_half_images; +ImageHandle::ImageHandle(const ImageHandle &other) + : tile_slots(other.tile_slots), manager(other.manager) +{ + /* Increase image user count. */ + foreach (const int slot, tile_slots) { + manager->add_image_user(slot); + } +} - for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - tex_num_images[type] = 0; +ImageHandle &ImageHandle::operator=(const ImageHandle &other) +{ + clear(); + manager = other.manager; + tile_slots = other.tile_slots; + + foreach (const int slot, tile_slots) { + manager->add_image_user(slot); } + + return *this; } -ImageManager::~ImageManager() +ImageHandle::~ImageHandle() { - for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) - assert(!images[type][slot]); + clear(); +} + +void ImageHandle::clear() +{ + foreach (const int slot, tile_slots) { + manager->remove_image_user(slot); } } -void ImageManager::set_osl_texture_system(void *texture_system) +bool ImageHandle::empty() { - osl_texture_system = texture_system; + return tile_slots.empty(); } -bool ImageManager::set_animation_frame_update(int frame) +int ImageHandle::num_tiles() { - if (frame != animation_frame) { - animation_frame = frame; + return tile_slots.size(); +} - for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) { - if (images[type][slot] && images[type][slot]->key.animated) - return true; - } - } +ImageMetaData ImageHandle::metadata() +{ + if (tile_slots.empty()) { + return ImageMetaData(); } - return false; + ImageManager::Image *img = manager->images[tile_slots.front()]; + manager->load_image_metadata(img); + return img->metadata; } -device_memory *ImageManager::image_memory(int flat_slot) +int ImageHandle::svm_slot(const int tile_index) const { - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); + if (tile_index >= tile_slots.size()) { + return -1; + } - Image *img = images[type][slot]; + if (manager->osl_texture_system) { + ImageManager::Image *img = manager->images[tile_slots[tile_index]]; + if (img->loader->osl_filepath()) { + return -1; + } + } - return img->mem; + return tile_slots[tile_index]; } -bool ImageManager::get_image_metadata(int flat_slot, ImageMetaData &metadata) +device_memory *ImageHandle::image_memory(const int tile_index) const { - if (flat_slot == -1) { - return false; + if (tile_index >= tile_slots.size()) { + return NULL; } - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); + ImageManager::Image *img = manager->images[tile_slots[tile_index]]; + return img ? img->mem : NULL; +} - Image *img = images[type][slot]; - if (img) { - metadata = img->metadata; - return true; - } +bool ImageHandle::operator==(const ImageHandle &other) const +{ + return manager == other.manager && tile_slots == other.tile_slots; +} - return false; +/* Image MetaData */ + +ImageMetaData::ImageMetaData() + : channels(0), + width(0), + height(0), + depth(0), + type(IMAGE_DATA_NUM_TYPES), + colorspace(u_colorspace_raw), + colorspace_file_format(""), + compress_as_srgb(false) +{ +} + +bool ImageMetaData::operator==(const ImageMetaData &other) const +{ + return channels == other.channels && width == other.width && height == other.height && + depth == other.depth && type == other.type && colorspace == other.colorspace && + compress_as_srgb == other.compress_as_srgb; +} + +bool ImageMetaData::is_float() const +{ + return (type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4 || + type == IMAGE_DATA_TYPE_HALF || type == IMAGE_DATA_TYPE_HALF4); } -void ImageManager::metadata_detect_colorspace(ImageMetaData &metadata, const char *file_format) +void ImageMetaData::detect_colorspace() { /* Convert used specified color spaces to one we know how to handle. */ - metadata.colorspace = ColorSpaceManager::detect_known_colorspace( - metadata.colorspace, file_format, metadata.is_float || metadata.is_half); + colorspace = ColorSpaceManager::detect_known_colorspace( + colorspace, colorspace_file_format, is_float()); - if (metadata.colorspace == u_colorspace_raw) { + if (colorspace == u_colorspace_raw) { /* Nothing to do. */ } - else if (metadata.colorspace == u_colorspace_srgb) { + else if (colorspace == u_colorspace_srgb) { /* Keep sRGB colorspace stored as sRGB, to save memory and/or loading time * for the common case of 8bit sRGB images like PNG. */ - metadata.compress_as_srgb = true; + compress_as_srgb = true; } else { /* Always compress non-raw 8bit images as scene linear + sRGB, as a * heuristic to keep memory usage the same without too much data loss * due to quantization in common cases. */ - metadata.compress_as_srgb = (metadata.type == IMAGE_DATA_TYPE_BYTE || - metadata.type == IMAGE_DATA_TYPE_BYTE4); + compress_as_srgb = (type == IMAGE_DATA_TYPE_BYTE || type == IMAGE_DATA_TYPE_BYTE4); /* If colorspace conversion needed, use half instead of short so we can * represent HDR values that might result from conversion. */ - if (metadata.type == IMAGE_DATA_TYPE_USHORT) { - metadata.type = IMAGE_DATA_TYPE_HALF; + if (type == IMAGE_DATA_TYPE_USHORT) { + type = IMAGE_DATA_TYPE_HALF; } - else if (metadata.type == IMAGE_DATA_TYPE_USHORT4) { - metadata.type = IMAGE_DATA_TYPE_HALF4; + else if (type == IMAGE_DATA_TYPE_USHORT4) { + type = IMAGE_DATA_TYPE_HALF4; } } } -bool ImageManager::get_image_metadata(const ImageKey &key, ImageMetaData &metadata) -{ - metadata = ImageMetaData(); - metadata.colorspace = key.colorspace; +/* Image Loader */ - if (key.builtin_data) { - if (builtin_image_info_cb) { - builtin_image_info_cb(key.filename, key.builtin_data, metadata); - } - else { - return false; - } - - if (metadata.is_float) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT; - } - else { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE; - } +ImageLoader::ImageLoader() +{ +} - metadata_detect_colorspace(metadata, ""); +ustring ImageLoader::osl_filepath() const +{ + return ustring(); +} +bool ImageLoader::equals(const ImageLoader *a, const ImageLoader *b) +{ + if (a == NULL && b == NULL) { return true; } - - /* Perform preliminary checks, with meaningful logging. */ - if (!path_exists(key.filename)) { - VLOG(1) << "File '" << key.filename << "' does not exist."; - return false; + else { + return (a && b && typeid(*a) == typeid(*b) && a->equals(*b)); } - if (path_is_directory(key.filename)) { - VLOG(1) << "File '" << key.filename << "' is a directory, can't use as image."; - return false; +} + +/* Image Manager */ + +ImageManager::ImageManager(const DeviceInfo &info) +{ + need_update = true; + osl_texture_system = NULL; + animation_frame = 0; + + /* Set image limits */ + has_half_images = info.has_half_images; +} + +ImageManager::~ImageManager() +{ + for (size_t slot = 0; slot < images.size(); slot++) + assert(!images[slot]); +} + +void ImageManager::set_osl_texture_system(void *texture_system) +{ + osl_texture_system = texture_system; +} + +bool ImageManager::set_animation_frame_update(int frame) +{ + if (frame != animation_frame) { + animation_frame = frame; + + for (size_t slot = 0; slot < images.size(); slot++) { + if (images[slot] && images[slot]->params.animated) + return true; + } } - unique_ptr<ImageInput> in(ImageInput::create(key.filename)); + return false; +} - if (!in) { - return false; +void ImageManager::load_image_metadata(Image *img) +{ + if (!img->need_metadata) { + return; } - ImageSpec spec; - if (!in->open(key.filename, spec)) { - return false; + thread_scoped_lock image_lock(img->mutex); + if (!img->need_metadata) { + return; } - metadata.width = spec.width; - metadata.height = spec.height; - metadata.depth = spec.depth; - metadata.compress_as_srgb = false; + ImageMetaData &metadata = img->metadata; + metadata = ImageMetaData(); + metadata.colorspace = img->params.colorspace; - /* Check the main format, and channel formats. */ - size_t channel_size = spec.format.basesize(); + img->loader->load_metadata(metadata); - if (spec.format.is_floating_point()) { - metadata.is_float = true; - } + metadata.detect_colorspace(); - for (size_t channel = 0; channel < spec.channelformats.size(); channel++) { - channel_size = max(channel_size, spec.channelformats[channel].basesize()); - if (spec.channelformats[channel].is_floating_point()) { - metadata.is_float = true; + /* No half textures on OpenCL, use full float instead. */ + if (!has_half_images) { + if (metadata.type == IMAGE_DATA_TYPE_HALF4) { + metadata.type = IMAGE_DATA_TYPE_FLOAT4; + } + else if (metadata.type == IMAGE_DATA_TYPE_HALF) { + metadata.type = IMAGE_DATA_TYPE_FLOAT; } } - /* check if it's half float */ - if (spec.format == TypeDesc::HALF) { - metadata.is_half = true; - } + img->need_metadata = false; +} - /* set type and channels */ - metadata.channels = spec.nchannels; +ImageHandle ImageManager::add_image(const string &filename, const ImageParams ¶ms) +{ + const int slot = add_image_slot(new OIIOImageLoader(filename), params, false); - if (metadata.is_half) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF; - } - else if (metadata.is_float) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT; - } - else if (spec.format == TypeDesc::USHORT) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4 : IMAGE_DATA_TYPE_USHORT; - } - else { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE; + ImageHandle handle; + handle.tile_slots.push_back(slot); + handle.manager = this; + return handle; +} + +ImageHandle ImageManager::add_image(const string &filename, + const ImageParams ¶ms, + const vector<int> &tiles) +{ + ImageHandle handle; + handle.manager = this; + + foreach (int tile, tiles) { + string tile_filename = filename; + if (tile != 0) { + string_replace(tile_filename, "<UDIM>", string_printf("%04d", tile)); + } + const int slot = add_image_slot(new OIIOImageLoader(tile_filename), params, false); + handle.tile_slots.push_back(slot); } - metadata_detect_colorspace(metadata, in->format_name()); + return handle; +} - in->close(); +ImageHandle ImageManager::add_image(ImageLoader *loader, const ImageParams ¶ms) +{ + const int slot = add_image_slot(loader, params, true); - return true; + ImageHandle handle; + handle.tile_slots.push_back(slot); + handle.manager = this; + return handle; } -int ImageManager::add_image(const ImageKey &key, float frame, ImageMetaData &metadata) +int ImageManager::add_image_slot(ImageLoader *loader, + const ImageParams ¶ms, + const bool builtin) { Image *img; size_t slot; - get_image_metadata(key, metadata); - ImageDataType type = metadata.type; - thread_scoped_lock device_lock(device_mutex); - /* No half textures on OpenCL, use full float instead. */ - if (!has_half_images) { - if (type == IMAGE_DATA_TYPE_HALF4) { - type = IMAGE_DATA_TYPE_FLOAT4; - } - else if (type == IMAGE_DATA_TYPE_HALF) { - type = IMAGE_DATA_TYPE_FLOAT; - } - } - /* Fnd existing image. */ - for (slot = 0; slot < images[type].size(); slot++) { - img = images[type][slot]; - if (img && img->key == key) { - if (img->frame != frame) { - img->frame = frame; - img->need_load = true; - } - if (!(img->metadata == metadata)) { - img->metadata = metadata; - img->need_load = true; - } + for (slot = 0; slot < images.size(); slot++) { + img = images[slot]; + if (img && ImageLoader::equals(img->loader, loader) && img->params == params) { img->users++; - return type_index_to_flattened_slot(slot, type); + delete loader; + return slot; } } /* Find free slot. */ - for (slot = 0; slot < images[type].size(); slot++) { - if (!images[type][slot]) + for (slot = 0; slot < images.size(); slot++) { + if (!images[slot]) break; } - /* Count if we're over the limit. - * Very unlikely, since max_num_images is insanely big. But better safe - * than sorry. - */ - int tex_count = 0; - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - tex_count += tex_num_images[type]; - } - if (tex_count > max_num_images) { - printf( - "ImageManager::add_image: Reached image limit (%d), " - "skipping '%s'\n", - max_num_images, - key.filename.c_str()); - return -1; - } - - if (slot == images[type].size()) { - images[type].resize(images[type].size() + 1); + if (slot == images.size()) { + images.resize(images.size() + 1); } /* Add new image. */ img = new Image(); - img->key = key; - img->frame = frame; - img->metadata = metadata; - img->need_load = true; + img->params = params; + img->loader = loader; + img->need_metadata = true; + img->need_load = !(osl_texture_system && img->loader->osl_filepath()); + img->builtin = builtin; img->users = 1; img->mem = NULL; - images[type][slot] = img; - - ++tex_num_images[type]; + images[slot] = img; need_update = true; - return type_index_to_flattened_slot(slot, type); + return slot; } -void ImageManager::add_image_user(int flat_slot) +void ImageManager::add_image_user(int slot) { - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); - - Image *image = images[type][slot]; + Image *image = images[slot]; assert(image && image->users >= 1); image->users++; } -void ImageManager::remove_image(int flat_slot) +void ImageManager::remove_image_user(int slot) { - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); - - Image *image = images[type][slot]; + Image *image = images[slot]; assert(image && image->users >= 1); /* decrement user count */ @@ -402,98 +429,22 @@ void ImageManager::remove_image(int flat_slot) need_update = true; } -void ImageManager::remove_image(const ImageKey &key) -{ - size_t slot; - - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (slot = 0; slot < images[type].size(); slot++) { - if (images[type][slot] && images[type][slot]->key == key) { - remove_image(type_index_to_flattened_slot(slot, (ImageDataType)type)); - return; - } - } - } -} - -/* TODO(sergey): Deduplicate with the iteration above, but make it pretty, - * without bunch of arguments passing around making code readability even - * more cluttered. - */ -void ImageManager::tag_reload_image(const ImageKey &key) -{ - for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) { - if (images[type][slot] && images[type][slot]->key == key) { - images[type][slot]->need_load = true; - break; - } - } - } -} - static bool image_associate_alpha(ImageManager::Image *img) { /* For typical RGBA images we let OIIO convert to associated alpha, * but some types we want to leave the RGB channels untouched. */ - return !(ColorSpaceManager::colorspace_is_data(img->key.colorspace) || - img->key.alpha_type == IMAGE_ALPHA_IGNORE || - img->key.alpha_type == IMAGE_ALPHA_CHANNEL_PACKED); -} - -bool ImageManager::file_load_image_generic(Image *img, unique_ptr<ImageInput> *in) -{ - if (img->key.filename == "") - return false; - - if (!img->key.builtin_data) { - /* NOTE: Error logging is done in meta data acquisition. */ - if (!path_exists(img->key.filename) || path_is_directory(img->key.filename)) { - return false; - } - - /* load image from file through OIIO */ - *in = unique_ptr<ImageInput>(ImageInput::create(img->key.filename)); - - if (!*in) - return false; - - ImageSpec spec = ImageSpec(); - ImageSpec config = ImageSpec(); - - if (!image_associate_alpha(img)) { - config.attribute("oiio:UnassociatedAlpha", 1); - } - - if (!(*in)->open(img->key.filename, spec, config)) { - return false; - } - } - else { - /* load image using builtin images callbacks */ - if (!builtin_image_info_cb || !builtin_image_pixels_cb) - return false; - } - - /* we only handle certain number of components */ - if (!(img->metadata.channels >= 1 && img->metadata.channels <= 4)) { - if (*in) { - (*in)->close(); - } - return false; - } - - return true; + return !(ColorSpaceManager::colorspace_is_data(img->params.colorspace) || + img->params.alpha_type == IMAGE_ALPHA_IGNORE || + img->params.alpha_type == IMAGE_ALPHA_CHANNEL_PACKED); } template<TypeDesc::BASETYPE FileFormat, typename StorageType, typename DeviceType> bool ImageManager::file_load_image(Image *img, - ImageDataType type, int texture_limit, device_vector<DeviceType> &tex_img) { - unique_ptr<ImageInput> in = NULL; - if (!file_load_image_generic(img, &in)) { + /* we only handle certain number of components */ + if (!(img->metadata.channels >= 1 && img->metadata.channels <= 4)) { return false; } @@ -527,90 +478,21 @@ bool ImageManager::file_load_image(Image *img, return false; } - bool cmyk = false; const size_t num_pixels = ((size_t)width) * height * depth; - if (in) { - /* Read pixels through OpenImageIO. */ - StorageType *readpixels = pixels; - vector<StorageType> tmppixels; - if (components > 4) { - tmppixels.resize(((size_t)width) * height * components); - readpixels = &tmppixels[0]; - } - - if (depth <= 1) { - size_t scanlinesize = ((size_t)width) * components * sizeof(StorageType); - in->read_image(FileFormat, - (uchar *)readpixels + (height - 1) * scanlinesize, - AutoStride, - -scanlinesize, - AutoStride); - } - else { - in->read_image(FileFormat, (uchar *)readpixels); - } - - if (components > 4) { - size_t dimensions = ((size_t)width) * height; - for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) { - pixels[i * 4 + 3] = tmppixels[i * components + 3]; - pixels[i * 4 + 2] = tmppixels[i * components + 2]; - pixels[i * 4 + 1] = tmppixels[i * components + 1]; - pixels[i * 4 + 0] = tmppixels[i * components + 0]; - } - tmppixels.clear(); - } - - cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4; - in->close(); - } - else { - /* Read pixels through callback. */ - if (FileFormat == TypeDesc::FLOAT) { - builtin_image_float_pixels_cb(img->key.filename, - img->key.builtin_data, - 0, /* TODO(lukas): Support tiles here? */ - (float *)&pixels[0], - num_pixels * components, - image_associate_alpha(img), - img->metadata.builtin_free_cache); - } - else if (FileFormat == TypeDesc::UINT8) { - builtin_image_pixels_cb(img->key.filename, - img->key.builtin_data, - 0, /* TODO(lukas): Support tiles here? */ - (uchar *)&pixels[0], - num_pixels * components, - image_associate_alpha(img), - img->metadata.builtin_free_cache); - } - else { - /* TODO(dingto): Support half for ImBuf. */ - } - } + img->loader->load_pixels( + img->metadata, pixels, num_pixels * components, image_associate_alpha(img)); /* The kernel can handle 1 and 4 channel images. Anything that is not a single * channel image is converted to RGBA format. */ - bool is_rgba = (type == IMAGE_DATA_TYPE_FLOAT4 || type == IMAGE_DATA_TYPE_HALF4 || - type == IMAGE_DATA_TYPE_BYTE4 || type == IMAGE_DATA_TYPE_USHORT4); + bool is_rgba = (img->metadata.type == IMAGE_DATA_TYPE_FLOAT4 || + img->metadata.type == IMAGE_DATA_TYPE_HALF4 || + img->metadata.type == IMAGE_DATA_TYPE_BYTE4 || + img->metadata.type == IMAGE_DATA_TYPE_USHORT4); if (is_rgba) { const StorageType one = util_image_cast_from_float<StorageType>(1.0f); - if (cmyk) { - /* CMYK to RGBA. */ - for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) { - float c = util_image_cast_to_float(pixels[i * 4 + 0]); - float m = util_image_cast_to_float(pixels[i * 4 + 1]); - float y = util_image_cast_to_float(pixels[i * 4 + 2]); - float k = util_image_cast_to_float(pixels[i * 4 + 3]); - pixels[i * 4 + 0] = util_image_cast_from_float<StorageType>((1.0f - c) * (1.0f - k)); - pixels[i * 4 + 1] = util_image_cast_from_float<StorageType>((1.0f - m) * (1.0f - k)); - pixels[i * 4 + 2] = util_image_cast_from_float<StorageType>((1.0f - y) * (1.0f - k)); - pixels[i * 4 + 3] = one; - } - } - else if (components == 2) { + if (components == 2) { /* Grayscale + alpha to RGBA. */ for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i * 4 + 3] = pixels[i * 2 + 1]; @@ -639,7 +521,7 @@ bool ImageManager::file_load_image(Image *img, } /* Disable alpha if requested by the user. */ - if (img->key.alpha_type == IMAGE_ALPHA_IGNORE) { + if (img->params.alpha_type == IMAGE_ALPHA_IGNORE) { for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i * 4 + 3] = one; } @@ -686,7 +568,8 @@ bool ImageManager::file_load_image(Image *img, while (max_size * scale_factor > texture_limit) { scale_factor *= 0.5f; } - VLOG(1) << "Scaling image " << img->key.filename << " by a factor of " << scale_factor << "."; + VLOG(1) << "Scaling image " << img->loader->name() << " by a factor of " << scale_factor + << "."; vector<StorageType> scaled_pixels; size_t scaled_width, scaled_height, scaled_depth; util_image_resize_pixels(pixels_storage, @@ -716,29 +599,28 @@ bool ImageManager::file_load_image(Image *img, static void image_set_device_memory(ImageManager::Image *img, device_memory *mem) { img->mem = mem; - mem->interpolation = img->key.interpolation; - mem->extension = img->key.extension; + mem->image_data_type = img->metadata.type; + mem->interpolation = img->params.interpolation; + mem->extension = img->params.extension; } -void ImageManager::device_load_image( - Device *device, Scene *scene, ImageDataType type, int slot, Progress *progress) +void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Progress *progress) { - if (progress->get_cancel()) + if (progress->get_cancel()) { return; + } - Image *img = images[type][slot]; + Image *img = images[slot]; - if (osl_texture_system && !img->key.builtin_data) - return; - - string filename = path_filename(images[type][slot]->key.filename); - progress->set_status("Updating Images", "Loading " + filename); + progress->set_status("Updating Images", "Loading " + img->loader->name()); const int texture_limit = scene->params.texture_limit; + load_image_metadata(img); + ImageDataType type = img->metadata.type; + /* Slot assignment */ - int flat_slot = type_index_to_flattened_slot(slot, type); - img->mem_name = string_printf("__tex_image_%s_%03d", name_from_type(type), flat_slot); + img->mem_name = string_printf("__tex_image_%s_%03d", name_from_type(type), slot); /* Free previous texture in slot. */ if (img->mem) { @@ -752,7 +634,7 @@ void ImageManager::device_load_image( device_vector<float4> *tex_img = new device_vector<float4>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::FLOAT, float>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); float *pixels = (float *)tex_img->alloc(1, 1); @@ -772,7 +654,7 @@ void ImageManager::device_load_image( device_vector<float> *tex_img = new device_vector<float>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::FLOAT, float>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); float *pixels = (float *)tex_img->alloc(1, 1); @@ -789,7 +671,7 @@ void ImageManager::device_load_image( device_vector<uchar4> *tex_img = new device_vector<uchar4>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::UINT8, uchar>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); uchar *pixels = (uchar *)tex_img->alloc(1, 1); @@ -809,7 +691,7 @@ void ImageManager::device_load_image( device_vector<uchar> *tex_img = new device_vector<uchar>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::UINT8, uchar>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); uchar *pixels = (uchar *)tex_img->alloc(1, 1); @@ -826,7 +708,7 @@ void ImageManager::device_load_image( device_vector<half4> *tex_img = new device_vector<half4>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::HALF, half>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); half *pixels = (half *)tex_img->alloc(1, 1); @@ -846,7 +728,7 @@ void ImageManager::device_load_image( device_vector<uint16_t> *tex_img = new device_vector<uint16_t>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); uint16_t *pixels = (uint16_t *)tex_img->alloc(1, 1); @@ -863,7 +745,7 @@ void ImageManager::device_load_image( device_vector<ushort4> *tex_img = new device_vector<ushort4>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); uint16_t *pixels = (uint16_t *)tex_img->alloc(1, 1); @@ -883,7 +765,7 @@ void ImageManager::device_load_image( device_vector<half> *tex_img = new device_vector<half>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::HALF, half>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); half *pixels = (half *)tex_img->alloc(1, 1); @@ -896,30 +778,36 @@ void ImageManager::device_load_image( thread_scoped_lock device_lock(device_mutex); tex_img->copy_to_device(); } + + /* Cleanup memory in image loader. */ + img->loader->cleanup(); img->need_load = false; } -void ImageManager::device_free_image(Device *, ImageDataType type, int slot) +void ImageManager::device_free_image(Device *, int slot) { - Image *img = images[type][slot]; + Image *img = images[slot]; + if (img == NULL) { + return; + } - if (img) { - if (osl_texture_system && !img->key.builtin_data) { + if (osl_texture_system) { #ifdef WITH_OSL - ustring filename(images[type][slot]->key.filename); - ((OSL::TextureSystem *)osl_texture_system)->invalidate(filename); -#endif - } - - if (img->mem) { - thread_scoped_lock device_lock(device_mutex); - delete img->mem; + ustring filepath = img->loader->osl_filepath(); + if (filepath) { + ((OSL::TextureSystem *)osl_texture_system)->invalidate(filepath); } +#endif + } - delete img; - images[type][slot] = NULL; - --tex_num_images[type]; + if (img->mem) { + thread_scoped_lock device_lock(device_mutex); + delete img->mem; } + + delete img->loader; + delete img; + images[slot] = NULL; } void ImageManager::device_update(Device *device, Scene *scene, Progress &progress) @@ -929,24 +817,14 @@ void ImageManager::device_update(Device *device, Scene *scene, Progress &progres } TaskPool pool; - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) { - if (!images[type][slot]) - continue; - - if (images[type][slot]->users == 0) { - device_free_image(device, (ImageDataType)type, slot); - } - else if (images[type][slot]->need_load) { - if (!osl_texture_system || images[type][slot]->key.builtin_data) - pool.push(function_bind(&ImageManager::device_load_image, - this, - device, - scene, - (ImageDataType)type, - slot, - &progress)); - } + for (size_t slot = 0; slot < images.size(); slot++) { + Image *img = images[slot]; + if (img && img->users == 0) { + device_free_image(device, slot); + } + else if (img && img->need_load) { + pool.push( + function_bind(&ImageManager::device_load_image, this, device, scene, slot, &progress)); } } @@ -955,23 +833,16 @@ void ImageManager::device_update(Device *device, Scene *scene, Progress &progres need_update = false; } -void ImageManager::device_update_slot(Device *device, - Scene *scene, - int flat_slot, - Progress *progress) +void ImageManager::device_update_slot(Device *device, Scene *scene, int slot, Progress *progress) { - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); + Image *img = images[slot]; + assert(img != NULL); - Image *image = images[type][slot]; - assert(image != NULL); - - if (image->users == 0) { - device_free_image(device, type, slot); + if (img->users == 0) { + device_free_image(device, slot); } - else if (image->need_load) { - if (!osl_texture_system || image->key.builtin_data) - device_load_image(device, scene, type, slot, progress); + else if (img->need_load) { + device_load_image(device, scene, slot, progress); } } @@ -984,22 +855,11 @@ void ImageManager::device_load_builtin(Device *device, Scene *scene, Progress &p } TaskPool pool; - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) { - if (!images[type][slot]) - continue; - - if (images[type][slot]->need_load) { - if (images[type][slot]->key.builtin_data) { - pool.push(function_bind(&ImageManager::device_load_image, - this, - device, - scene, - (ImageDataType)type, - slot, - &progress)); - } - } + for (size_t slot = 0; slot < images.size(); slot++) { + Image *img = images[slot]; + if (img && img->need_load && img->builtin) { + pool.push( + function_bind(&ImageManager::device_load_image, this, device, scene, slot, &progress)); } } @@ -1008,31 +868,27 @@ void ImageManager::device_load_builtin(Device *device, Scene *scene, Progress &p void ImageManager::device_free_builtin(Device *device) { - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) { - if (images[type][slot] && images[type][slot]->key.builtin_data) - device_free_image(device, (ImageDataType)type, slot); + for (size_t slot = 0; slot < images.size(); slot++) { + Image *img = images[slot]; + if (img && img->builtin) { + device_free_image(device, slot); } } } void ImageManager::device_free(Device *device) { - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) { - device_free_image(device, (ImageDataType)type, slot); - } - images[type].clear(); + for (size_t slot = 0; slot < images.size(); slot++) { + device_free_image(device, slot); } + images.clear(); } void ImageManager::collect_statistics(RenderStats *stats) { - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - foreach (const Image *image, images[type]) { - stats->image.textures.add_entry( - NamedSizeEntry(path_filename(image->key.filename), image->mem->memory_size())); - } + foreach (const Image *image, images) { + stats->image.textures.add_entry( + NamedSizeEntry(image->loader->name(), image->mem->memory_size())); } } diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index ee60390d628..82f3e2759c6 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -22,7 +22,6 @@ #include "render/colorspace.h" -#include "util/util_image.h" #include "util/util_string.h" #include "util/util_thread.h" #include "util/util_unique_ptr.h" @@ -31,91 +30,144 @@ CCL_NAMESPACE_BEGIN class Device; +class ImageHandle; +class ImageKey; +class ImageMetaData; +class ImageManager; class Progress; class RenderStats; class Scene; class ColorSpaceProcessor; -class ImageMetaData { +/* Image Parameters */ +class ImageParams { public: - /* Must be set by image file or builtin callback. */ - bool is_float, is_half; - int channels; - size_t width, height, depth; - bool builtin_free_cache; - - /* Automatically set. */ - ImageDataType type; - ustring colorspace; - bool compress_as_srgb; - - ImageMetaData() - : is_float(false), - is_half(false), - channels(0), - width(0), - height(0), - depth(0), - builtin_free_cache(false), - type((ImageDataType)0), - colorspace(u_colorspace_raw), - compress_as_srgb(false) - { - } - - bool operator==(const ImageMetaData &other) const - { - return is_float == other.is_float && is_half == other.is_half && channels == other.channels && - width == other.width && height == other.height && depth == other.depth && - type == other.type && colorspace == other.colorspace && - compress_as_srgb == other.compress_as_srgb; - } -}; - -class ImageKey { - public: - string filename; - void *builtin_data; bool animated; InterpolationType interpolation; ExtensionType extension; ImageAlphaType alpha_type; ustring colorspace; + float frame; - ImageKey() - : builtin_data(NULL), - animated(false), + ImageParams() + : animated(false), interpolation(INTERPOLATION_LINEAR), extension(EXTENSION_CLIP), alpha_type(IMAGE_ALPHA_AUTO), - colorspace(u_colorspace_raw) + colorspace(u_colorspace_raw), + frame(0.0f) { } - bool operator==(const ImageKey &other) const + bool operator==(const ImageParams &other) const { - return (filename == other.filename && builtin_data == other.builtin_data && - animated == other.animated && interpolation == other.interpolation && + return (animated == other.animated && interpolation == other.interpolation && extension == other.extension && alpha_type == other.alpha_type && - colorspace == other.colorspace); + colorspace == other.colorspace && frame == other.frame); } }; +/* Image MetaData + * + * Information about the image that is available before the image pixels are loaded. */ +class ImageMetaData { + public: + /* Set by ImageLoader.load_metadata(). */ + int channels; + size_t width, height, depth; + ImageDataType type; + + /* Optional color space, defaults to raw. */ + ustring colorspace; + const char *colorspace_file_format; + + /* Automatically set. */ + bool compress_as_srgb; + + ImageMetaData(); + bool operator==(const ImageMetaData &other) const; + bool is_float() const; + void detect_colorspace(); +}; + +/* Image loader base class, that can be subclassed to load image data + * from custom sources (file, memory, procedurally generated, etc). */ +class ImageLoader { + public: + ImageLoader(); + virtual ~ImageLoader(){}; + + /* Load metadata without actual image yet, should be fast. */ + virtual bool load_metadata(ImageMetaData &metadata) = 0; + + /* Load actual image contents. */ + virtual bool load_pixels(const ImageMetaData &metadata, + void *pixels, + const size_t pixels_size, + const bool associate_alpha) = 0; + + /* Name for logs and stats. */ + virtual string name() const = 0; + + /* Optional for OSL texture cache. */ + virtual ustring osl_filepath() const; + + /* Free any memory used for loading metadata and pixels. */ + virtual void cleanup(){}; + + /* Compare avoid loading the same image multiple times. */ + virtual bool equals(const ImageLoader &other) const = 0; + static bool equals(const ImageLoader *a, const ImageLoader *b); + + /* Work around for no RTTI. */ +}; + +/* Image Handle + * + * Access handle for image in the image manager. Multiple shader nodes may + * share the same image, and this class handles reference counting for that. */ +class ImageHandle { + public: + ImageHandle(); + ImageHandle(const ImageHandle &other); + ImageHandle &operator=(const ImageHandle &other); + ~ImageHandle(); + + bool operator==(const ImageHandle &other) const; + + void clear(); + + bool empty(); + int num_tiles(); + + ImageMetaData metadata(); + int svm_slot(const int tile_index = 0) const; + device_memory *image_memory(const int tile_index = 0) const; + + protected: + vector<int> tile_slots; + ImageManager *manager; + + friend class ImageManager; +}; + +/* Image Manager + * + * Handles loading and storage of all images in the scene. This includes 2D + * texture images and 3D volume images. */ class ImageManager { public: explicit ImageManager(const DeviceInfo &info); ~ImageManager(); - int add_image(const ImageKey &key, float frame, ImageMetaData &metadata); - void add_image_user(int flat_slot); - void remove_image(int flat_slot); - void remove_image(const ImageKey &key); - void tag_reload_image(const ImageKey &key); - bool get_image_metadata(const ImageKey &key, ImageMetaData &metadata); - bool get_image_metadata(int flat_slot, ImageMetaData &metadata); + ImageHandle add_image(const string &filename, const ImageParams ¶ms); + ImageHandle add_image(const string &filename, + const ImageParams ¶ms, + const vector<int> &tiles); + ImageHandle add_image(ImageLoader *loader, const ImageParams ¶ms); void device_update(Device *device, Scene *scene, Progress &progress); - void device_update_slot(Device *device, Scene *scene, int flat_slot, Progress *progress); + void device_update_slot(Device *device, Scene *scene, int slot, Progress *progress); void device_free(Device *device); void device_load_builtin(Device *device, Scene *scene, Progress &progress); @@ -124,72 +176,49 @@ class ImageManager { void set_osl_texture_system(void *texture_system); bool set_animation_frame_update(int frame); - device_memory *image_memory(int flat_slot); - void collect_statistics(RenderStats *stats); bool need_update; - /* NOTE: Here pixels_size is a size of storage, which equals to - * width * height * depth. - * Use this to avoid some nasty memory corruptions. - */ - function<void(const string &filename, void *data, ImageMetaData &metadata)> - builtin_image_info_cb; - function<bool(const string &filename, - void *data, - int tile, - unsigned char *pixels, - const size_t pixels_size, - const bool associate_alpha, - const bool free_cache)> - builtin_image_pixels_cb; - function<bool(const string &filename, - void *data, - int tile, - float *pixels, - const size_t pixels_size, - const bool associate_alpha, - const bool free_cache)> - builtin_image_float_pixels_cb; - struct Image { - ImageKey key; + ImageParams params; ImageMetaData metadata; + ImageLoader *loader; float frame; + bool need_metadata; bool need_load; + bool builtin; string mem_name; device_memory *mem; int users; + thread_mutex mutex; }; private: - int tex_num_images[IMAGE_DATA_NUM_TYPES]; - int max_num_images; bool has_half_images; thread_mutex device_mutex; int animation_frame; - vector<Image *> images[IMAGE_DATA_NUM_TYPES]; + vector<Image *> images; void *osl_texture_system; - bool file_load_image_generic(Image *img, unique_ptr<ImageInput> *in); + int add_image_slot(ImageLoader *loader, const ImageParams ¶ms, const bool builtin); + void add_image_user(int slot); + void remove_image_user(int slot); + + void load_image_metadata(Image *img); template<TypeDesc::BASETYPE FileFormat, typename StorageType, typename DeviceType> - bool file_load_image(Image *img, - ImageDataType type, - int texture_limit, - device_vector<DeviceType> &tex_img); + bool file_load_image(Image *img, int texture_limit, device_vector<DeviceType> &tex_img); - void metadata_detect_colorspace(ImageMetaData &metadata, const char *file_format); + void device_load_image(Device *device, Scene *scene, int slot, Progress *progress); + void device_free_image(Device *device, int slot); - void device_load_image( - Device *device, Scene *scene, ImageDataType type, int slot, Progress *progress); - void device_free_image(Device *device, ImageDataType type, int slot); + friend class ImageHandle; }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/image_oiio.cpp b/intern/cycles/render/image_oiio.cpp new file mode 100644 index 00000000000..c4f95c6b4bc --- /dev/null +++ b/intern/cycles/render/image_oiio.cpp @@ -0,0 +1,236 @@ +/* + * Copyright 2011-2020 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "render/image_oiio.h" + +#include "util/util_image.h" +#include "util/util_logging.h" +#include "util/util_path.h" + +CCL_NAMESPACE_BEGIN + +OIIOImageLoader::OIIOImageLoader(const string &filepath) : filepath(filepath) +{ +} + +OIIOImageLoader::~OIIOImageLoader() +{ +} + +bool OIIOImageLoader::load_metadata(ImageMetaData &metadata) +{ + /* Perform preliminary checks, with meaningful logging. */ + if (!path_exists(filepath.string())) { + VLOG(1) << "File '" << filepath.string() << "' does not exist."; + return false; + } + if (path_is_directory(filepath.string())) { + VLOG(1) << "File '" << filepath.string() << "' is a directory, can't use as image."; + return false; + } + + unique_ptr<ImageInput> in(ImageInput::create(filepath.string())); + + if (!in) { + return false; + } + + ImageSpec spec; + if (!in->open(filepath.string(), spec)) { + return false; + } + + metadata.width = spec.width; + metadata.height = spec.height; + metadata.depth = spec.depth; + metadata.compress_as_srgb = false; + + /* Check the main format, and channel formats. */ + size_t channel_size = spec.format.basesize(); + + bool is_float = false; + bool is_half = false; + + if (spec.format.is_floating_point()) { + is_float = true; + } + + for (size_t channel = 0; channel < spec.channelformats.size(); channel++) { + channel_size = max(channel_size, spec.channelformats[channel].basesize()); + if (spec.channelformats[channel].is_floating_point()) { + is_float = true; + } + } + + /* check if it's half float */ + if (spec.format == TypeDesc::HALF) { + is_half = true; + } + + /* set type and channels */ + metadata.channels = spec.nchannels; + + if (is_half) { + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF; + } + else if (is_float) { + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT; + } + else if (spec.format == TypeDesc::USHORT) { + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4 : IMAGE_DATA_TYPE_USHORT; + } + else { + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE; + } + + metadata.colorspace_file_format = in->format_name(); + + in->close(); + + return true; +} + +template<TypeDesc::BASETYPE FileFormat, typename StorageType> +static void oiio_load_pixels(const ImageMetaData &metadata, + const unique_ptr<ImageInput> &in, + StorageType *pixels) +{ + const int width = metadata.width; + const int height = metadata.height; + const int depth = metadata.depth; + const int components = metadata.channels; + + /* Read pixels through OpenImageIO. */ + StorageType *readpixels = pixels; + vector<StorageType> tmppixels; + if (components > 4) { + tmppixels.resize(((size_t)width) * height * components); + readpixels = &tmppixels[0]; + } + + if (depth <= 1) { + size_t scanlinesize = ((size_t)width) * components * sizeof(StorageType); + in->read_image(FileFormat, + (uchar *)readpixels + (height - 1) * scanlinesize, + AutoStride, + -scanlinesize, + AutoStride); + } + else { + in->read_image(FileFormat, (uchar *)readpixels); + } + + if (components > 4) { + size_t dimensions = ((size_t)width) * height; + for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) { + pixels[i * 4 + 3] = tmppixels[i * components + 3]; + pixels[i * 4 + 2] = tmppixels[i * components + 2]; + pixels[i * 4 + 1] = tmppixels[i * components + 1]; + pixels[i * 4 + 0] = tmppixels[i * components + 0]; + } + tmppixels.clear(); + } + + /* CMYK to RGBA. */ + const bool cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4; + if (cmyk) { + const StorageType one = util_image_cast_from_float<StorageType>(1.0f); + + const size_t num_pixels = ((size_t)width) * height * depth; + for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) { + float c = util_image_cast_to_float(pixels[i * 4 + 0]); + float m = util_image_cast_to_float(pixels[i * 4 + 1]); + float y = util_image_cast_to_float(pixels[i * 4 + 2]); + float k = util_image_cast_to_float(pixels[i * 4 + 3]); + pixels[i * 4 + 0] = util_image_cast_from_float<StorageType>((1.0f - c) * (1.0f - k)); + pixels[i * 4 + 1] = util_image_cast_from_float<StorageType>((1.0f - m) * (1.0f - k)); + pixels[i * 4 + 2] = util_image_cast_from_float<StorageType>((1.0f - y) * (1.0f - k)); + pixels[i * 4 + 3] = one; + } + } +} + +bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata, + void *pixels, + const size_t, + const bool associate_alpha) +{ + unique_ptr<ImageInput> in = NULL; + + /* NOTE: Error logging is done in meta data acquisition. */ + if (!path_exists(filepath.string()) || path_is_directory(filepath.string())) { + return false; + } + + /* load image from file through OIIO */ + in = unique_ptr<ImageInput>(ImageInput::create(filepath.string())); + if (!in) { + return false; + } + + ImageSpec spec = ImageSpec(); + ImageSpec config = ImageSpec(); + + if (!associate_alpha) { + config.attribute("oiio:UnassociatedAlpha", 1); + } + + if (!in->open(filepath.string(), spec, config)) { + return false; + } + + switch (metadata.type) { + case IMAGE_DATA_TYPE_BYTE: + case IMAGE_DATA_TYPE_BYTE4: + oiio_load_pixels<TypeDesc::UINT8, uchar>(metadata, in, (uchar *)pixels); + break; + case IMAGE_DATA_TYPE_USHORT: + case IMAGE_DATA_TYPE_USHORT4: + oiio_load_pixels<TypeDesc::USHORT, uint16_t>(metadata, in, (uint16_t *)pixels); + break; + case IMAGE_DATA_TYPE_HALF: + case IMAGE_DATA_TYPE_HALF4: + oiio_load_pixels<TypeDesc::HALF, half>(metadata, in, (half *)pixels); + break; + case IMAGE_DATA_TYPE_FLOAT: + case IMAGE_DATA_TYPE_FLOAT4: + oiio_load_pixels<TypeDesc::FLOAT, float>(metadata, in, (float *)pixels); + break; + case IMAGE_DATA_NUM_TYPES: + break; + } + + in->close(); + return true; +} + +string OIIOImageLoader::name() const +{ + return path_filename(filepath.string()); +} + +ustring OIIOImageLoader::osl_filepath() const +{ + return filepath; +} + +bool OIIOImageLoader::equals(const ImageLoader &other) const +{ + const OIIOImageLoader &other_loader = (const OIIOImageLoader &)other; + return filepath == other_loader.filepath; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/render/image_oiio.h b/intern/cycles/render/image_oiio.h new file mode 100644 index 00000000000..a234b968557 --- /dev/null +++ b/intern/cycles/render/image_oiio.h @@ -0,0 +1,48 @@ +/* + * Copyright 2011-2020 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __IMAGE_OIIO__ +#define __IMAGE_OIIO__ + +#include "render/image.h" + +CCL_NAMESPACE_BEGIN + +class OIIOImageLoader : public ImageLoader { + public: + OIIOImageLoader(const string &filepath); + ~OIIOImageLoader(); + + bool load_metadata(ImageMetaData &metadata) override; + + bool load_pixels(const ImageMetaData &metadata, + void *pixels, + const size_t pixels_size, + const bool associate_alpha) override; + + string name() const override; + + ustring osl_filepath() const override; + + bool equals(const ImageLoader &other) const override; + + protected: + ustring filepath; +}; + +CCL_NAMESPACE_END + +#endif /* __IMAGE_OIIO__ */ diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 509637aedd9..8263f68fa9c 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -577,8 +577,8 @@ void LightManager::device_update_background(Device *device, if (node->type == EnvironmentTextureNode::node_type) { EnvironmentTextureNode *env = (EnvironmentTextureNode *)node; ImageMetaData metadata; - if (env->image_manager && !env->slots.empty() && - env->image_manager->get_image_metadata(env->slots[0], metadata)) { + if (!env->handle.empty()) { + ImageMetaData metadata = env->handle.metadata(); res.x = max(res.x, metadata.width); res.y = max(res.y, metadata.height); } diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp index 74c6a7759a6..3c91aba511d 100644 --- a/intern/cycles/render/mesh_volume.cpp +++ b/intern/cycles/render/mesh_volume.cpp @@ -362,7 +362,7 @@ struct VoxelAttributeGrid { int channels; }; -void GeometryManager::create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress) +void GeometryManager::create_volume_mesh(Mesh *mesh, Progress &progress) { string msg = string_printf("Computing Volume Mesh %s", mesh->name.c_str()); progress.set_status("Updating Mesh", msg); @@ -378,8 +378,8 @@ void GeometryManager::create_volume_mesh(Scene *scene, Mesh *mesh, Progress &pro continue; } - VoxelAttribute *voxel = attr.data_voxel(); - device_memory *image_memory = scene->image_manager->image_memory(voxel->slot); + ImageHandle &handle = attr.data_voxel(); + device_memory *image_memory = handle.image_memory(); int3 resolution = make_int3( image_memory->data_width, image_memory->data_height, image_memory->data_depth); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 3967b4ef00e..26b816b65e9 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -206,27 +206,6 @@ void TextureMapping::compile(OSLCompiler &compiler) /* Image Texture */ -ImageSlotTextureNode::~ImageSlotTextureNode() -{ - if (image_manager) { - foreach (int slot, slots) { - if (slot != -1) { - image_manager->remove_image(slot); - } - } - } -} - -void ImageSlotTextureNode::add_image_user() const -{ - /* Increase image user count for new node. */ - foreach (int slot, slots) { - if (slot != -1) { - image_manager->add_image_user(slot); - } - } -} - NODE_DEFINE(ImageTextureNode) { NodeType *type = NodeType::add("image_texture", create, NodeType::SHADER); @@ -276,34 +255,27 @@ NODE_DEFINE(ImageTextureNode) ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode(node_type) { - is_float = false; - compress_as_srgb = false; colorspace = u_colorspace_raw; - builtin_data = NULL; animated = false; tiles.push_back(1001); } ShaderNode *ImageTextureNode::clone() const { - add_image_user(); - return new ImageTextureNode(*this); + ImageTextureNode *node = new ImageTextureNode(*this); + node->handle = handle; + return node; } -ImageKey ImageTextureNode::image_key(const int tile) const +ImageParams ImageTextureNode::image_params() const { - ImageKey key; - key.filename = filename.string(); - if (tile != 0) { - string_replace(key.filename, "<UDIM>", string_printf("%04d", tile)); - } - key.builtin_data = builtin_data; - key.animated = animated; - key.interpolation = interpolation; - key.extension = extension; - key.alpha_type = alpha_type; - key.colorspace = colorspace; - return key; + ImageParams params; + params.animated = animated; + params.interpolation = interpolation; + params.extension = extension; + params.alpha_type = alpha_type; + params.colorspace = colorspace; + return params; } void ImageTextureNode::cull_tiles(Scene *scene, ShaderGraph *graph) @@ -388,113 +360,80 @@ void ImageTextureNode::compile(SVMCompiler &compiler) ShaderOutput *color_out = output("Color"); ShaderOutput *alpha_out = output("Alpha"); - image_manager = compiler.scene->image_manager; - if (slots.empty()) { + if (handle.empty()) { cull_tiles(compiler.scene, compiler.current_graph); - slots.reserve(tiles.size()); - - bool have_metadata = false; - foreach (int tile, tiles) { - ImageKey key = image_key(tile); - ImageMetaData metadata; - int slot = image_manager->add_image(key, 0, metadata); - slots.push_back(slot); - - /* We assume that all tiles have the same metadata. */ - if (!have_metadata) { - is_float = metadata.is_float; - compress_as_srgb = metadata.compress_as_srgb; - known_colorspace = metadata.colorspace; - have_metadata = true; - } - } + ImageManager *image_manager = compiler.scene->image_manager; + handle = image_manager->add_image(filename.string(), image_params(), tiles); } - bool has_image = false; - foreach (int slot, slots) { - if (slot != -1) { - has_image = true; - break; - } - } + /* All tiles have the same metadata. */ + const ImageMetaData metadata = handle.metadata(); + const bool compress_as_srgb = metadata.compress_as_srgb; + const ustring known_colorspace = metadata.colorspace; + + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + uint flags = 0; - if (has_image) { - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - uint flags = 0; + if (compress_as_srgb) { + flags |= NODE_IMAGE_COMPRESS_AS_SRGB; + } + if (!alpha_out->links.empty()) { + const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) || + alpha_type == IMAGE_ALPHA_CHANNEL_PACKED || + alpha_type == IMAGE_ALPHA_IGNORE); - if (compress_as_srgb) { - flags |= NODE_IMAGE_COMPRESS_AS_SRGB; + if (unassociate_alpha) { + flags |= NODE_IMAGE_ALPHA_UNASSOCIATE; } - if (!alpha_out->links.empty()) { - const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) || - alpha_type == IMAGE_ALPHA_CHANNEL_PACKED || - alpha_type == IMAGE_ALPHA_IGNORE); + } - if (unassociate_alpha) { - flags |= NODE_IMAGE_ALPHA_UNASSOCIATE; - } + if (projection != NODE_IMAGE_PROJ_BOX) { + /* If there only is one image (a very common case), we encode it as a negative value. */ + int num_nodes; + if (handle.num_tiles() == 1) { + num_nodes = -handle.svm_slot(); + } + else { + num_nodes = divide_up(handle.num_tiles(), 2); } - if (projection != NODE_IMAGE_PROJ_BOX) { - /* If there only is one image (a very common case), we encode it as a negative value. */ - int num_nodes; - if (slots.size() == 1) { - num_nodes = -slots[0]; - } - else { - num_nodes = divide_up(slots.size(), 2); - } + compiler.add_node(NODE_TEX_IMAGE, + num_nodes, + compiler.encode_uchar4(vector_offset, + compiler.stack_assign_if_linked(color_out), + compiler.stack_assign_if_linked(alpha_out), + flags), + projection); - compiler.add_node(NODE_TEX_IMAGE, - num_nodes, - compiler.encode_uchar4(vector_offset, - compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(alpha_out), - flags), - projection); - - if (num_nodes > 0) { - for (int i = 0; i < num_nodes; i++) { - int4 node; - node.x = tiles[2 * i]; - node.y = slots[2 * i]; - if (2 * i + 1 < slots.size()) { - node.z = tiles[2 * i + 1]; - node.w = slots[2 * i + 1]; - } - else { - node.z = -1; - node.w = -1; - } - compiler.add_node(node.x, node.y, node.z, node.w); + if (num_nodes > 0) { + for (int i = 0; i < num_nodes; i++) { + int4 node; + node.x = tiles[2 * i]; + node.y = handle.svm_slot(2 * i); + if (2 * i + 1 < tiles.size()) { + node.z = tiles[2 * i + 1]; + node.w = handle.svm_slot(2 * i + 1); } + else { + node.z = -1; + node.w = -1; + } + compiler.add_node(node.x, node.y, node.z, node.w); } } - else { - assert(slots.size() == 1); - compiler.add_node(NODE_TEX_IMAGE_BOX, - slots[0], - compiler.encode_uchar4(vector_offset, - compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(alpha_out), - flags), - __float_as_int(projection_blend)); - } - - tex_mapping.compile_end(compiler, vector_in, vector_offset); } else { - /* image not found */ - if (!color_out->links.empty()) { - compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out)); - compiler.add_node( - NODE_VALUE_V, - make_float3(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B)); - } - if (!alpha_out->links.empty()) - compiler.add_node( - NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), compiler.stack_assign(alpha_out)); + assert(handle.num_tiles() == 1); + compiler.add_node(NODE_TEX_IMAGE_BOX, + handle.svm_slot(), + compiler.encode_uchar4(vector_offset, + compiler.stack_assign_if_linked(color_out), + compiler.stack_assign_if_linked(alpha_out), + flags), + __float_as_int(projection_blend)); } + + tex_mapping.compile_end(compiler, vector_in, vector_offset); } void ImageTextureNode::compile(OSLCompiler &compiler) @@ -503,29 +442,22 @@ void ImageTextureNode::compile(OSLCompiler &compiler) tex_mapping.compile(compiler); - image_manager = compiler.scene->image_manager; - if (slots.size() == 0) { - ImageMetaData metadata; - if (builtin_data == NULL) { - ImageKey key = image_key(1001); - image_manager->get_image_metadata(key, metadata); - slots.push_back(-1); - } - else { - int slot = image_manager->add_image(image_key(), 0, metadata); - slots.push_back(slot); - } - is_float = metadata.is_float; - compress_as_srgb = metadata.compress_as_srgb; - known_colorspace = metadata.colorspace; + if (handle.empty()) { + ImageManager *image_manager = compiler.scene->image_manager; + handle = image_manager->add_image(filename.string(), image_params()); } - if (slots[0] == -1) { + const ImageMetaData metadata = handle.metadata(); + const bool is_float = metadata.is_float(); + const bool compress_as_srgb = metadata.compress_as_srgb; + const ustring known_colorspace = metadata.colorspace; + + if (handle.svm_slot() == -1) { compiler.parameter_texture( "filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace); } else { - compiler.parameter_texture("filename", slots[0]); + compiler.parameter_texture("filename", handle.svm_slot()); } const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) || @@ -587,30 +519,26 @@ NODE_DEFINE(EnvironmentTextureNode) EnvironmentTextureNode::EnvironmentTextureNode() : ImageSlotTextureNode(node_type) { - is_float = false; - compress_as_srgb = false; colorspace = u_colorspace_raw; - builtin_data = NULL; animated = false; } ShaderNode *EnvironmentTextureNode::clone() const { - add_image_user(); - return new EnvironmentTextureNode(*this); + EnvironmentTextureNode *node = new EnvironmentTextureNode(*this); + node->handle = handle; + return node; } -ImageKey EnvironmentTextureNode::image_key() const +ImageParams EnvironmentTextureNode::image_params() const { - ImageKey key; - key.filename = filename.string(); - key.builtin_data = builtin_data; - key.animated = animated; - key.interpolation = interpolation; - key.extension = EXTENSION_REPEAT; - key.alpha_type = alpha_type; - key.colorspace = colorspace; - return key; + ImageParams params; + params.animated = animated; + params.interpolation = interpolation; + params.extension = EXTENSION_REPEAT; + params.alpha_type = alpha_type; + params.colorspace = colorspace; + return params; } void EnvironmentTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -632,77 +560,53 @@ void EnvironmentTextureNode::compile(SVMCompiler &compiler) ShaderOutput *color_out = output("Color"); ShaderOutput *alpha_out = output("Alpha"); - image_manager = compiler.scene->image_manager; - if (slots.empty()) { - ImageMetaData metadata; - int slot = image_manager->add_image(image_key(), 0, metadata); - slots.push_back(slot); - is_float = metadata.is_float; - compress_as_srgb = metadata.compress_as_srgb; - known_colorspace = metadata.colorspace; + if (handle.empty()) { + ImageManager *image_manager = compiler.scene->image_manager; + handle = image_manager->add_image(filename.string(), image_params()); } - if (slots[0] != -1) { - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - uint flags = 0; + const ImageMetaData metadata = handle.metadata(); + const bool compress_as_srgb = metadata.compress_as_srgb; + const ustring known_colorspace = metadata.colorspace; - if (compress_as_srgb) { - flags |= NODE_IMAGE_COMPRESS_AS_SRGB; - } - - compiler.add_node(NODE_TEX_ENVIRONMENT, - slots[0], - compiler.encode_uchar4(vector_offset, - compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(alpha_out), - flags), - projection); + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + uint flags = 0; - tex_mapping.compile_end(compiler, vector_in, vector_offset); - } - else { - /* image not found */ - if (!color_out->links.empty()) { - compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out)); - compiler.add_node( - NODE_VALUE_V, - make_float3(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B)); - } - if (!alpha_out->links.empty()) - compiler.add_node( - NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), compiler.stack_assign(alpha_out)); + if (compress_as_srgb) { + flags |= NODE_IMAGE_COMPRESS_AS_SRGB; } + + compiler.add_node(NODE_TEX_ENVIRONMENT, + handle.svm_slot(), + compiler.encode_uchar4(vector_offset, + compiler.stack_assign_if_linked(color_out), + compiler.stack_assign_if_linked(alpha_out), + flags), + projection); + + tex_mapping.compile_end(compiler, vector_in, vector_offset); } void EnvironmentTextureNode::compile(OSLCompiler &compiler) { + if (handle.empty()) { + ImageManager *image_manager = compiler.scene->image_manager; + handle = image_manager->add_image(filename.string(), image_params()); + } + tex_mapping.compile(compiler); - /* See comments in ImageTextureNode::compile about support - * of builtin images. - */ - image_manager = compiler.scene->image_manager; - if (slots.empty()) { - ImageMetaData metadata; - if (builtin_data == NULL) { - image_manager->get_image_metadata(image_key(), metadata); - slots.push_back(-1); - } - else { - int slot = image_manager->add_image(image_key(), 0, metadata); - slots.push_back(slot); - } - is_float = metadata.is_float; - compress_as_srgb = metadata.compress_as_srgb; - known_colorspace = metadata.colorspace; - } + const ImageMetaData metadata = handle.metadata(); + const bool is_float = metadata.is_float(); + const bool compress_as_srgb = metadata.compress_as_srgb; + const ustring known_colorspace = metadata.colorspace; - if (slots[0] == -1) { + if (handle.svm_slot() == -1) { compiler.parameter_texture( "filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace); } else { - compiler.parameter_texture("filename", slots[0]); + compiler.parameter_texture("filename", handle.svm_slot()); } compiler.parameter(this, "projection"); @@ -1741,16 +1645,10 @@ NODE_DEFINE(PointDensityTextureNode) PointDensityTextureNode::PointDensityTextureNode() : ShaderNode(node_type) { - image_manager = NULL; - slot = -1; - builtin_data = NULL; } PointDensityTextureNode::~PointDensityTextureNode() { - if (image_manager) { - image_manager->remove_image(image_key()); - } } ShaderNode *PointDensityTextureNode::clone() const @@ -1758,10 +1656,9 @@ ShaderNode *PointDensityTextureNode::clone() const /* Increase image user count for new node. We need to ensure to not call * add_image again, to work around access of freed data on the Blender * side. A better solution should be found to avoid this. */ - if (slot != -1) { - image_manager->add_image_user(slot); - } - return new PointDensityTextureNode(*this); + PointDensityTextureNode *node = new PointDensityTextureNode(*this); + node->handle = handle; /* TODO: not needed? */ + return node; } void PointDensityTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -1772,21 +1669,11 @@ void PointDensityTextureNode::attributes(Shader *shader, AttributeRequestSet *at ShaderNode::attributes(shader, attributes); } -void PointDensityTextureNode::add_image() -{ - if (slot == -1) { - ImageMetaData metadata; - slot = image_manager->add_image(image_key(), 0, metadata); - } -} - -ImageKey PointDensityTextureNode::image_key() const +ImageParams PointDensityTextureNode::image_params() const { - ImageKey key; - key.filename = filename.string(); - key.builtin_data = builtin_data; - key.interpolation = interpolation; - return key; + ImageParams params; + params.interpolation = interpolation; + return params; } void PointDensityTextureNode::compile(SVMCompiler &compiler) @@ -1798,11 +1685,13 @@ void PointDensityTextureNode::compile(SVMCompiler &compiler) const bool use_density = !density_out->links.empty(); const bool use_color = !color_out->links.empty(); - image_manager = compiler.scene->image_manager; - if (use_density || use_color) { - add_image(); + if (handle.empty()) { + ImageManager *image_manager = compiler.scene->image_manager; + handle = image_manager->add_image(filename.string(), image_params()); + } + const int slot = handle.svm_slot(); if (slot != -1) { compiler.stack_assign(vector_in); compiler.add_node(NODE_TEX_VOXEL, @@ -1839,12 +1728,13 @@ void PointDensityTextureNode::compile(OSLCompiler &compiler) const bool use_density = !density_out->links.empty(); const bool use_color = !color_out->links.empty(); - image_manager = compiler.scene->image_manager; - if (use_density || use_color) { - add_image(); + if (handle.empty()) { + ImageManager *image_manager = compiler.scene->image_manager; + handle = image_manager->add_image(filename.string(), image_params()); + } - compiler.parameter_texture("filename", slot); + compiler.parameter_texture("filename", handle.svm_slot()); if (space == NODE_TEX_VOXEL_SPACE_WORLD) { compiler.parameter("mapping", tfm); compiler.parameter("use_mapping", 1); @@ -3358,7 +3248,7 @@ NODE_DEFINE(PrincipledVolumeNode) SOCKET_IN_COLOR(emission_color, "Emission Color", make_float3(1.0f, 1.0f, 1.0f)); SOCKET_IN_FLOAT(blackbody_intensity, "Blackbody Intensity", 0.0f); SOCKET_IN_COLOR(blackbody_tint, "Blackbody Tint", make_float3(1.0f, 1.0f, 1.0f)); - SOCKET_IN_FLOAT(temperature, "Temperature", 1500.0f); + SOCKET_IN_FLOAT(temperature, "Temperature", 1000.0f); SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); SOCKET_OUT_CLOSURE(volume, "Volume"); @@ -3369,6 +3259,8 @@ NODE_DEFINE(PrincipledVolumeNode) PrincipledVolumeNode::PrincipledVolumeNode() : VolumeNode(node_type) { closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; + density_attribute = ustring("density"); + temperature_attribute = ustring("temperature"); } void PrincipledVolumeNode::attributes(Shader *shader, AttributeRequestSet *attributes) diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 1d76cb5e828..1f52a2a49ab 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -78,12 +78,15 @@ class ImageSlotTextureNode : public TextureNode { explicit ImageSlotTextureNode(const NodeType *node_type) : TextureNode(node_type) { special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT; - image_manager = NULL; } - ~ImageSlotTextureNode(); - void add_image_user() const; - ImageManager *image_manager; - vector<int> slots; + + virtual bool equals(const ShaderNode &other) + { + const ImageSlotTextureNode &other_node = (const ImageSlotTextureNode &)other; + return TextureNode::equals(other) && handle == other_node.handle; + } + + ImageHandle handle; }; class ImageTextureNode : public ImageSlotTextureNode { @@ -98,16 +101,14 @@ class ImageTextureNode : public ImageSlotTextureNode { virtual bool equals(const ShaderNode &other) { - const ImageTextureNode &image_node = (const ImageTextureNode &)other; - return ImageSlotTextureNode::equals(other) && builtin_data == image_node.builtin_data && - animated == image_node.animated; + const ImageTextureNode &other_node = (const ImageTextureNode &)other; + return ImageSlotTextureNode::equals(other) && animated == other_node.animated; } - ImageKey image_key(const int tile = 0) const; + ImageParams image_params() const; /* Parameters. */ ustring filename; - void *builtin_data; ustring colorspace; ImageAlphaType alpha_type; NodeImageProjection projection; @@ -118,11 +119,6 @@ class ImageTextureNode : public ImageSlotTextureNode { float3 vector; ccl::vector<int> tiles; - /* Runtime. */ - bool is_float; - bool compress_as_srgb; - ustring known_colorspace; - protected: void cull_tiles(Scene *scene, ShaderGraph *graph); }; @@ -143,27 +139,20 @@ class EnvironmentTextureNode : public ImageSlotTextureNode { virtual bool equals(const ShaderNode &other) { - const EnvironmentTextureNode &env_node = (const EnvironmentTextureNode &)other; - return ImageSlotTextureNode::equals(other) && builtin_data == env_node.builtin_data && - animated == env_node.animated; + const EnvironmentTextureNode &other_node = (const EnvironmentTextureNode &)other; + return ImageSlotTextureNode::equals(other) && animated == other_node.animated; } - ImageKey image_key() const; + ImageParams image_params() const; /* Parameters. */ ustring filename; - void *builtin_data; ustring colorspace; ImageAlphaType alpha_type; NodeEnvironmentProjection projection; InterpolationType interpolation; bool animated; float3 vector; - - /* Runtime. */ - bool is_float; - bool compress_as_srgb; - ustring known_colorspace; }; class SkyTextureNode : public TextureNode { @@ -370,26 +359,22 @@ class PointDensityTextureNode : public ShaderNode { return true; } - void add_image(); - - ImageKey image_key() const; - /* Parameters. */ ustring filename; NodeTexVoxelSpace space; InterpolationType interpolation; Transform tfm; float3 vector; - void *builtin_data; /* Runtime. */ - ImageManager *image_manager; - int slot; + ImageHandle handle; + + ImageParams image_params() const; virtual bool equals(const ShaderNode &other) { - const PointDensityTextureNode &point_dendity_node = (const PointDensityTextureNode &)other; - return ShaderNode::equals(other) && builtin_data == point_dendity_node.builtin_data; + const PointDensityTextureNode &other_node = (const PointDensityTextureNode &)other; + return ShaderNode::equals(other) && handle == other_node.handle; } }; diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index b3916a67f0c..d17d7270cd5 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -102,8 +102,8 @@ void OSLShaderManager::device_update(Device *device, device_free(device, dscene, scene); - /* determine which shaders are in use */ - device_update_shaders_used(scene); + /* set texture system */ + scene->image_manager->set_osl_texture_system((void *)ts); /* create shaders */ OSLGlobals *og = (OSLGlobals *)device->osl_memory(); @@ -142,9 +142,6 @@ void OSLShaderManager::device_update(Device *device, need_update = false; - /* set texture system */ - scene->image_manager->set_osl_texture_system((void *)ts); - /* add special builtin texture types */ services->textures.insert(ustring("@ao"), new OSLTextureHandle(OSLTextureHandle::AO)); services->textures.insert(ustring("@bevel"), new OSLTextureHandle(OSLTextureHandle::BEVEL)); @@ -440,27 +437,35 @@ const char *OSLShaderManager::shader_load_bytecode(const string &hash, const str return loaded_shaders.find(hash)->first.c_str(); } -OSLNode *OSLShaderManager::osl_node(const std::string &filepath, +/* This is a static function to avoid RTTI link errors with only this + * file being compiled without RTTI to match OSL and LLVM libraries. */ +OSLNode *OSLShaderManager::osl_node(ShaderManager *manager, + const std::string &filepath, const std::string &bytecode_hash, const std::string &bytecode) { + if (!manager->use_osl()) { + return NULL; + } + /* create query */ + OSLShaderManager *osl_manager = static_cast<OSLShaderManager *>(manager); const char *hash; if (!filepath.empty()) { - hash = shader_load_filepath(filepath); + hash = osl_manager->shader_load_filepath(filepath); } else { - hash = shader_test_loaded(bytecode_hash); + hash = osl_manager->shader_test_loaded(bytecode_hash); if (!hash) - hash = shader_load_bytecode(bytecode_hash, bytecode); + hash = osl_manager->shader_load_bytecode(bytecode_hash, bytecode); } if (!hash) { return NULL; } - OSLShaderInfo *info = shader_loaded_info(hash); + OSLShaderInfo *info = osl_manager->shader_loaded_info(hash); /* count number of inputs */ size_t num_inputs = 0; diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h index 62cbfebf7eb..4dd9f6630f2 100644 --- a/intern/cycles/render/osl.h +++ b/intern/cycles/render/osl.h @@ -93,9 +93,10 @@ class OSLShaderManager : public ShaderManager { OSLShaderInfo *shader_loaded_info(const string &hash); /* create OSL node using OSLQuery */ - OSLNode *osl_node(const std::string &filepath, - const std::string &bytecode_hash = "", - const std::string &bytecode = ""); + static OSLNode *osl_node(ShaderManager *manager, + const std::string &filepath, + const std::string &bytecode_hash = "", + const std::string &bytecode = ""); protected: void texture_system_init(); diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 7fab2fdedeb..1e20513e88a 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -104,9 +104,11 @@ Scene::Scene(const SceneParams ¶ms_, Device *device) /* OSL only works on the CPU */ if (device->info.has_osl) - shader_manager = ShaderManager::create(this, params.shadingsystem); + shader_manager = ShaderManager::create(params.shadingsystem); else - shader_manager = ShaderManager::create(this, SHADINGSYSTEM_SVM); + shader_manager = ShaderManager::create(SHADINGSYSTEM_SVM); + + shader_manager->add_default(this); } Scene::~Scene() diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 1dceb93aef7..d2570138b53 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -230,6 +230,7 @@ class Scene { /* default shaders */ Shader *default_surface; + Shader *default_volume; Shader *default_light; Shader *default_background; Shader *default_empty; diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 6bf2160f9fa..b5d434a604c 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -987,7 +987,8 @@ bool Session::update_scene() /* update scene */ if (scene->need_update()) { - bool new_kernels_needed = load_kernels(false); + /* Updated used shader tag so we know which features are need for the kernel. */ + scene->shader_manager->update_shaders_used(scene); /* Update max_closures. */ KernelIntegrator *kintegrator = &scene->dscene.data.integrator; @@ -999,6 +1000,9 @@ bool Session::update_scene() kintegrator->max_closures = MAX_CLOSURE; } + /* Load render kernels, before device update where we upload data to the GPU. */ + bool new_kernels_needed = load_kernels(false); + progress.set_status("Updating Scene"); MEM_GUARDED_CALL(&progress, scene->device_update, device, progress); @@ -1271,8 +1275,11 @@ int Session::get_max_closure_count() int max_closures = 0; for (int i = 0; i < scene->shaders.size(); i++) { - int num_closures = scene->shaders[i]->graph->get_num_closures(); - max_closures = max(max_closures, num_closures); + Shader *shader = scene->shaders[i]; + if (shader->used) { + int num_closures = shader->graph->get_num_closures(); + max_closures = max(max_closures, num_closures); + } } max_closure_global = max(max_closure_global, max_closures); diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index 60f38aa14da..cc6eb2e5e7f 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -168,7 +168,7 @@ NODE_DEFINE(Shader) SOCKET_ENUM(volume_sampling_method, "Volume Sampling Method", volume_sampling_method_enum, - VOLUME_SAMPLING_DISTANCE); + VOLUME_SAMPLING_MULTIPLE_IMPORTANCE); static NodeEnum volume_interpolation_method_enum; volume_interpolation_method_enum.insert("linear", VOLUME_INTERPOLATION_LINEAR); @@ -415,7 +415,7 @@ ShaderManager::~ShaderManager() { } -ShaderManager *ShaderManager::create(Scene *scene, int shadingsystem) +ShaderManager *ShaderManager::create(int shadingsystem) { ShaderManager *manager; @@ -431,8 +431,6 @@ ShaderManager *ShaderManager::create(Scene *scene, int shadingsystem) manager = new SVMShaderManager(); } - add_default(scene); - return manager; } @@ -471,8 +469,12 @@ int ShaderManager::get_shader_id(Shader *shader, bool smooth) return id; } -void ShaderManager::device_update_shaders_used(Scene *scene) +void ShaderManager::update_shaders_used(Scene *scene) { + if (!need_update) { + return; + } + /* figure out which shaders are in use, so SVM/OSL can skip compiling them * for speed and avoid loading image textures into memory */ uint id = 0; @@ -623,9 +625,27 @@ void ShaderManager::add_default(Scene *scene) Shader *shader = new Shader(); shader->name = "default_surface"; - shader->graph = graph; + shader->set_graph(graph); scene->shaders.push_back(shader); scene->default_surface = shader; + shader->tag_update(scene); + } + + /* default volume */ + { + ShaderGraph *graph = new ShaderGraph(); + + PrincipledVolumeNode *principled = new PrincipledVolumeNode(); + graph->add(principled); + + graph->connect(principled->output("Volume"), graph->output()->input("Volume")); + + Shader *shader = new Shader(); + shader->name = "default_volume"; + shader->set_graph(graph); + scene->shaders.push_back(shader); + scene->default_volume = shader; + shader->tag_update(scene); } /* default light */ @@ -641,9 +661,10 @@ void ShaderManager::add_default(Scene *scene) Shader *shader = new Shader(); shader->name = "default_light"; - shader->graph = graph; + shader->set_graph(graph); scene->shaders.push_back(shader); scene->default_light = shader; + shader->tag_update(scene); } /* default background */ @@ -652,9 +673,10 @@ void ShaderManager::add_default(Scene *scene) Shader *shader = new Shader(); shader->name = "default_background"; - shader->graph = graph; + shader->set_graph(graph); scene->shaders.push_back(shader); scene->default_background = shader; + shader->tag_update(scene); } /* default empty */ @@ -663,9 +685,10 @@ void ShaderManager::add_default(Scene *scene) Shader *shader = new Shader(); shader->name = "default_empty"; - shader->graph = graph; + shader->set_graph(graph); scene->shaders.push_back(shader); scene->default_empty = shader; + shader->tag_update(scene); } } @@ -704,6 +727,10 @@ void ShaderManager::get_requested_features(Scene *scene, requested_features->nodes_features = 0; for (int i = 0; i < scene->shaders.size(); i++) { Shader *shader = scene->shaders[i]; + if (!shader->used) { + continue; + } + /* Gather requested features from all the nodes from the graph nodes. */ get_requested_graph_features(shader->graph, requested_features); ShaderNode *output_node = shader->graph->output(); diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h index c6f40bb7833..5a5b42de994 100644 --- a/intern/cycles/render/shader.h +++ b/intern/cycles/render/shader.h @@ -163,7 +163,7 @@ class ShaderManager { public: bool need_update; - static ShaderManager *create(Scene *scene, int shadingsystem); + static ShaderManager *create(int shadingsystem); virtual ~ShaderManager(); virtual void reset(Scene *scene) = 0; @@ -180,7 +180,6 @@ class ShaderManager { Progress &progress) = 0; virtual void device_free(Device *device, DeviceScene *dscene, Scene *scene) = 0; - void device_update_shaders_used(Scene *scene); void device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); void device_free_common(Device *device, DeviceScene *dscene, Scene *scene); @@ -196,6 +195,7 @@ class ShaderManager { static void add_default(Scene *scene); /* Selective nodes compilation. */ + void update_shaders_used(Scene *scene); void get_requested_features(Scene *scene, DeviceRequestedFeatures *requested_features); static void free_memory(); diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 7c33f6c04ae..2946614a3b7 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -85,9 +85,6 @@ void SVMShaderManager::device_update(Device *device, /* test if we need to update */ device_free(device, dscene, scene); - /* determine which shaders are in use */ - device_update_shaders_used(scene); - /* Build all shaders. */ TaskPool task_pool; vector<array<int4>> shader_svm_nodes(num_shaders); diff --git a/intern/cycles/util/util_profiling.cpp b/intern/cycles/util/util_profiling.cpp index bbefbadd0fe..dc5bc35c48d 100644 --- a/intern/cycles/util/util_profiling.cpp +++ b/intern/cycles/util/util_profiling.cpp @@ -15,6 +15,7 @@ */ #include "util/util_algorithm.h" +#include "util/util_foreach.h" #include "util/util_profiling.h" #include "util/util_set.h" diff --git a/intern/cycles/util/util_profiling.h b/intern/cycles/util/util_profiling.h index f5f500239f2..ceec08ed894 100644 --- a/intern/cycles/util/util_profiling.h +++ b/intern/cycles/util/util_profiling.h @@ -19,7 +19,6 @@ #include <atomic> -#include "util/util_foreach.h" #include "util/util_map.h" #include "util/util_thread.h" #include "util/util_vector.h" diff --git a/intern/cycles/util/util_texture.h b/intern/cycles/util/util_texture.h index d43852480d1..d0672886cba 100644 --- a/intern/cycles/util/util_texture.h +++ b/intern/cycles/util/util_texture.h @@ -91,12 +91,15 @@ typedef enum ExtensionType { typedef struct TextureInfo { /* Pointer, offset or texture depending on device. */ uint64_t data; + /* Data Type */ + uint data_type; /* Buffer number for OpenCL. */ uint cl_buffer; /* Interpolation and extension type. */ uint interpolation, extension; /* Dimensions. */ uint width, height, depth; + uint pad[3]; } TextureInfo; CCL_NAMESPACE_END diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 5bf40ba33d0..d03b9343eab 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -1052,7 +1052,7 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA /* Unlike on Linux, not all keys can send repeat events. E.g. modifier keys don't. */ if (keyDown) { if (system->m_keycode_last_repeat_key == vk) { - is_repeat = true; + is_repeat = true; } system->m_keycode_last_repeat_key = vk; } diff --git a/intern/ghost/test/CMakeLists.txt b/intern/ghost/test/CMakeLists.txt index f97397715bf..2d97489f657 100644 --- a/intern/ghost/test/CMakeLists.txt +++ b/intern/ghost/test/CMakeLists.txt @@ -1,16 +1,36 @@ +# see "cmake --help-policy CMP0003" +# So library linking is more sane cmake_policy(SET CMP0003 NEW) + +# So BUILDINFO and BLENDERPATH strings are automatically quoted cmake_policy(SET CMP0005 NEW) -cmake_minimum_required(VERSION 2.8) +# So syntax problems are errors +cmake_policy(SET CMP0010 NEW) + +# Input directories must have CMakeLists.txt +cmake_policy(SET CMP0014 NEW) + +cmake_minimum_required(VERSION 3.5) + +project(GhostMultiTest) list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../../..//build_files/cmake/Modules") set(WITH_GUARDEDALLOC ON) +add_executable(datatoc + "${CMAKE_SOURCE_DIR}/../../../source/blender/datatoc/datatoc.c") + +# Fake the current source dir for includes. +set(_CMAKE_CURRENT_SOURCE_DIR_INIT "${CMAKE_CURRENT_SOURCE_DIR}") + # ----------------------------------------------------------------------------- # Macros +# For data_to_c macro. +# include(../../../build_files/cmake/macros.cmake) # stub macro, does nothing macro(blender_add_lib @@ -18,6 +38,7 @@ macro(blender_add_lib sources includes includes_sys + library_deps # ignored. ) endmacro() @@ -28,10 +49,15 @@ macro(suffix_relpaths set(${new_files}) foreach(_file ${files}) - if(IS_ABSOLUTE _file) + if(IS_ABSOLUTE "${_file}") list(APPEND ${new_files} ${_file}) else() - list(APPEND ${new_files} "${prefix}${_file}") + set(_file_to "${prefix}${_file}") + list(APPEND ${new_files} ${_file_to}) + get_source_file_property(_is_generated ${_file} GENERATED) + set_source_files_properties(${_file_to} PROPERTIES GENERATED ${_is_generated}) + unset(_file_to) + unset(_is_generated) endif() endforeach() unset(_file) @@ -48,11 +74,39 @@ macro(data_to_c add_custom_command( OUTPUT ${file_to} COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path} - COMMAND ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/datatoc ${file_from} ${file_to} + COMMAND "$<TARGET_FILE:datatoc>" ${file_from} ${file_to} DEPENDS ${file_from} datatoc) unset(_file_to_path) endmacro() +# same as above but generates the var name and output automatic. +function(data_to_c_simple + file_from + list_to_add + ) + + # remove ../'s + get_filename_component(_file_from ${CMAKE_CURRENT_SOURCE_DIR}/${file_from} REALPATH) + get_filename_component(_file_to ${CMAKE_CURRENT_BINARY_DIR}/${file_from}.c REALPATH) + + + list(APPEND ${list_to_add} ${_file_to}) + source_group(Generated FILES ${_file_to}) + list(APPEND ${list_to_add} ${file_from}) + set(${list_to_add} ${${list_to_add}} PARENT_SCOPE) + + get_filename_component(_file_to_path ${_file_to} PATH) + + message(OUTPUT " ${_file_to}") + add_custom_command( + OUTPUT ${_file_to} + COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path} + COMMAND "$<TARGET_FILE:datatoc>" ${_file_from} ${_file_to} + DEPENDS ${_file_from} datatoc) + + set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE) +endfunction() + # ----------------------------------------------------------------------------- # Defines @@ -96,6 +150,13 @@ suffix_relpaths(SRC_NEW "${SRC}" "../../string/") include_directories(${INC_NEW}) add_library(string_lib ${SRC_NEW}) +# numaapi (for 'bli_lib') +include(${CMAKE_SOURCE_DIR}/../../numaapi/CMakeLists.txt) +suffix_relpaths(INC_NEW "${INC}" "../../numaapi/") +suffix_relpaths(SRC_NEW "${SRC}" "../../numaapi/") +include_directories(${INC_NEW}) +add_library(numaapi_lib ${SRC_NEW}) + # guardedalloc include(${CMAKE_SOURCE_DIR}/../../guardedalloc/CMakeLists.txt) suffix_relpaths(INC_NEW "${INC}" "../../guardedalloc/") @@ -103,6 +164,25 @@ suffix_relpaths(SRC_NEW "${SRC}" "../../guardedalloc/") include_directories(${INC_NEW}) add_library(guardedalloc_lib ${SRC_NEW}) +# gpu (used by blenfont) +add_definitions(-DGPU_STANDALONE) +set(CMAKE_CURRENT_SOURCE_DIR "${CMAKE_SOURCE_DIR}/../../../source/blender/gpu") +include(${CMAKE_SOURCE_DIR}/../../../source/blender/gpu/CMakeLists.txt) +suffix_relpaths(INC_NEW "${INC}" "../../../source/blender/gpu/") +suffix_relpaths(SRC_NEW "${SRC}" "../../../source/blender/gpu/") +include_directories(${INC_NEW}) +add_library(gpu_lib ${SRC_NEW}) +set(CMAKE_CURRENT_SOURCE_DIR "${_CMAKE_CURRENT_SOURCE_DIR_INIT}") + +# imbuf (used by ) +# set(CMAKE_CURRENT_SOURCE_DIR "${CMAKE_SOURCE_DIR}/../../../source/blender/imbuf") +# include(${CMAKE_SOURCE_DIR}/../../../source/blender/imbuf/CMakeLists.txt) +# suffix_relpaths(INC_NEW "${INC}" "../../../source/blender/imbuf/") +# suffix_relpaths(SRC_NEW "${SRC}" "../../../source/blender/imbuf/") +# include_directories(${INC_NEW}) +# add_library(imbuf_lib ${SRC_NEW}) +# set(CMAKE_CURRENT_SOURCE_DIR "${_CMAKE_CURRENT_SOURCE_DIR_INIT}") + # blenfont include(${CMAKE_SOURCE_DIR}/../../../source/blender/blenfont/CMakeLists.txt) suffix_relpaths(INC_NEW "${INC}" "../../../source/blender/blenfont/") @@ -128,6 +208,10 @@ add_library(glewmx_lib ${SRC_NEW}) include_directories( "../../../source/blender/blenlib" ) + +# Needed for math_matrix.c to avoid eigen_capi.h dep. +add_definitions(-DMATH_STANDALONE) + add_library(bli_lib "../../../source/blender/blenlib/intern/fileops.c" "../../../source/blender/blenlib/intern/gsqueue.c" @@ -136,15 +220,23 @@ add_library(bli_lib "../../../source/blender/blenlib/intern/string_utf8.c" "../../../source/blender/blenlib/intern/listbase.c" "../../../source/blender/blenlib/intern/math_color.c" + "../../../source/blender/blenlib/intern/math_geom.c" + "../../../source/blender/blenlib/intern/math_matrix.c" + "../../../source/blender/blenlib/intern/math_rotation.c" + "../../../source/blender/blenlib/intern/math_vector.c" "../../../source/blender/blenlib/intern/storage.c" "../../../source/blender/blenlib/intern/task.c" "../../../source/blender/blenlib/intern/threads.c" "../../../source/blender/blenlib/intern/time.c" "../../../source/blender/blenlib/intern/path_util.c" "../../../source/blender/blenlib/intern/BLI_dynstr.c" + "../../../source/blender/blenlib/intern/BLI_ghash.c" + "../../../source/blender/blenlib/intern/BLI_ghash_utils.c" "../../../source/blender/blenlib/intern/BLI_linklist.c" "../../../source/blender/blenlib/intern/BLI_memarena.c" "../../../source/blender/blenlib/intern/BLI_mempool.c" + "../../../source/blender/blenlib/intern/hash_mm2a.c" + "../../../source/blender/blenlib/intern/string_utils.c" "../../../source/blender/blenlib/intern/system.c" ) @@ -190,10 +282,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PLATFORM_CFLAGS}") # ----------------------------------------------------------------------------- # Executables -# DataToC -add_executable(datatoc - ${CMAKE_SOURCE_DIR}/../../../source/blender/datatoc/datatoc.c) - # Gears (C) add_executable(gears_c ${CMAKE_SOURCE_DIR}/gears/GHOST_C-Test.c) @@ -224,8 +312,11 @@ target_link_libraries(gears_cpp # MultiTest (C) set(data_to_c_files) -data_to_c(${CMAKE_SOURCE_DIR}/../../../release/datafiles/bfont.ttf - ${CMAKE_CURRENT_BINARY_DIR}/bfont.ttf.c data_to_c_files) +data_to_c( + ${CMAKE_SOURCE_DIR}/../../../release/datafiles/bfont.ttf + ${CMAKE_CURRENT_BINARY_DIR}/bfont.ttf.c + data_to_c_files +) add_executable(multitest_c ${CMAKE_SOURCE_DIR}/multitest/Basic.c @@ -240,16 +331,20 @@ add_executable(multitest_c target_link_libraries(multitest_c - blenfont_lib - bli_lib - ghost_lib - glewmx_lib - string_lib - guardedalloc_lib - wcwidth_lib - ${OPENGL_gl_LIBRARY} - ${FREETYPE_LIBRARY} - ${ZLIB_LIBRARIES} - ${CMAKE_DL_LIBS} - ${PLATFORM_LINKLIBS} - ) + blenfont_lib + bli_lib + gpu_lib + # imbuf_lib + ghost_lib + bli_lib # again... + glewmx_lib + string_lib + numaapi_lib + guardedalloc_lib + wcwidth_lib + ${OPENGL_gl_LIBRARY} + ${FREETYPE_LIBRARY} + ${ZLIB_LIBRARIES} + ${CMAKE_DL_LIBS} + ${PLATFORM_LINKLIBS} +) diff --git a/intern/ghost/test/multitest/MultiTest.c b/intern/ghost/test/multitest/MultiTest.c index 21d706966c1..374c7170dc6 100644 --- a/intern/ghost/test/multitest/MultiTest.c +++ b/intern/ghost/test/multitest/MultiTest.c @@ -16,7 +16,18 @@ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. */ -#define FALSE 0 + +/* Developers Note: + * + * This test currently only creates windows and draws a 'dot' under the cursor on LMB, + * quits when Q is pressed. + * + * More work is needed for logging drawing to work properly. + * + * - Use GPU_matrix API. + * - Replace old OpenGL calls to glColor, etc with 'imm' API. + * - Investigate BLF font flushing (UI_widgetbase_draw_cache_flush) which is currently disabled. + */ #ifdef _MSC_VER # pragma warning(disable : 4244 4305) @@ -27,22 +38,14 @@ #include <stdio.h> #include <math.h> +#include <GL/glew.h> #include "GL.h" #include "MEM_guardedalloc.h" #include "GHOST_C-api.h" -#ifdef USE_BMF -# include "BMF_Api.h" -#else -# include "BLF_api.h" -extern int datatoc_bfont_ttf_size; -extern char datatoc_bfont_ttf[]; - -/* cheat */ -char U[1024] = {0}; -#endif +#include "BLF_api.h" #include "Util.h" #include "Basic.h" @@ -51,7 +54,13 @@ char U[1024] = {0}; #include "WindowData.h" -/***/ +/* GPU API. */ +#include "GPU_immediate.h" +#include "GPU_context.h" +#include "GPU_init_exit.h" + +extern int datatoc_bfont_ttf_size; +extern char datatoc_bfont_ttf[]; typedef struct _LoggerWindow LoggerWindow; typedef struct _MultiTestApp MultiTestApp; @@ -128,6 +137,7 @@ typedef struct { MultiTestApp *app; GHOST_WindowHandle win; + GPUContext *gpu_context; int size[2]; @@ -144,6 +154,7 @@ static void mainwindow_log(MainWindow *mw, char *str) static void mainwindow_do_draw(MainWindow *mw) { GHOST_ActivateWindowDrawingContext(mw->win); + GPU_context_active_set(mw->gpu_context); if (mw->lmbut[0]) { glClearColor(0.5, 0.5, 0.5, 1); @@ -164,6 +175,7 @@ static void mainwindow_do_reshape(MainWindow *mw) GHOST_RectangleHandle bounds = GHOST_GetClientBounds(mw->win); GHOST_ActivateWindowDrawingContext(mw->win); + GPU_context_active_set(mw->gpu_context); mw->size[0] = GHOST_GetWidthRectangle(bounds); mw->size[1] = GHOST_GetHeightRectangle(bounds); @@ -317,6 +329,11 @@ MainWindow *mainwindow_new(MultiTestApp *app) if (win) { MainWindow *mw = MEM_callocN(sizeof(*mw), "mainwindow_new"); + + GLuint default_fb = GHOST_GetDefaultOpenGLFramebuffer(win); + mw->gpu_context = GPU_context_create(default_fb); + GPU_init(); + mw->app = app; mw->win = win; @@ -348,13 +365,9 @@ struct _LoggerWindow { MultiTestApp *app; GHOST_WindowHandle win; + GPUContext *gpu_context; -#ifdef USE_BMF - BMF_Font *font; -#else int font; -#endif - int fonttexid; int fontheight; int size[2]; @@ -411,6 +424,7 @@ static void loggerwindow_do_reshape(LoggerWindow *lw) GHOST_RectangleHandle bounds = GHOST_GetClientBounds(lw->win); GHOST_ActivateWindowDrawingContext(lw->win); + GPU_context_active_set(lw->gpu_context); lw->size[0] = GHOST_GetWidthRectangle(bounds); lw->size[1] = GHOST_GetHeightRectangle(bounds); @@ -425,6 +439,8 @@ static void loggerwindow_do_draw(LoggerWindow *lw) int sb_rect[2][2], sb_thumb[2][2]; GHOST_ActivateWindowDrawingContext(lw->win); + GPU_context_active_set(lw->gpu_context); + immActivate(); glClearColor(1, 1, 1, 1); glClear(GL_COLOR_BUFFER_BIT); @@ -449,13 +465,6 @@ static void loggerwindow_do_draw(LoggerWindow *lw) startline = scrollbar_get_thumbpos(lw->scroll) * (lw->nloglines - 1); ndisplines = min_i(lw->ndisplines, lw->nloglines - startline); - if (lw->fonttexid != -1) { - glBindTexture(GL_TEXTURE_2D, lw->fonttexid); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - glEnable(GL_TEXTURE_2D); - } glColor3f(0, 0, 0); for (i = 0; i < ndisplines; i++) { /* stored in reverse order */ @@ -463,28 +472,13 @@ static void loggerwindow_do_draw(LoggerWindow *lw) int x_pos = lw->textarea[0][0] + 4; int y_pos = lw->textarea[0][1] + 4 + i * lw->fontheight; -#ifdef USE_BMF - if (lw->fonttexid == -1) { - glRasterPos2i(x_pos, y_pos); - BMF_DrawString(lw->font, line); - } - else { - BMF_DrawStringTexture(lw->font, line, x_pos, y_pos, 0.0); - } -#else BLF_position(lw->font, x_pos, y_pos, 0.0); BLF_draw(lw->font, line, 256); // XXX -#endif } -#ifdef USE_BMF - if (lw->fonttexid != -1) { - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - } -#endif - GHOST_SwapWindowBuffers(lw->win); + + immDeactivate(); } static void loggerwindow_do_move(LoggerWindow *lw, int x, int y) @@ -592,21 +586,18 @@ LoggerWindow *loggerwindow_new(MultiTestApp *app) if (win) { LoggerWindow *lw = MEM_callocN(sizeof(*lw), "loggerwindow_new"); + + GLuint default_fb = GHOST_GetDefaultOpenGLFramebuffer(win); + lw->gpu_context = GPU_context_create(default_fb); + GPU_init(); + int bbox[2][2]; lw->app = app; lw->win = win; -#ifdef USE_BMF - lw->font = BMF_GetFont(BMF_kScreen12); - lw->fonttexid = BMF_GetFontTexture(lw->font); - - BMF_GetBoundingBox(lw->font, &bbox[0][0], &bbox[0][1], &bbox[1][0], &bbox[1][1]); - lw->fontheight = rect_height(bbox); -#else lw->font = BLF_load_mem("default", (unsigned char *)datatoc_bfont_ttf, datatoc_bfont_ttf_size); BLF_size(lw->font, 11, 72); lw->fontheight = BLF_height(lw->font, "A_", 2); -#endif lw->nloglines = lw->logsize = 0; lw->loglines = MEM_mallocN(sizeof(*lw->loglines) * lw->nloglines, "loglines"); @@ -659,6 +650,7 @@ typedef struct { MultiTestApp *app; GHOST_WindowHandle win; + GPUContext *gpu_context; int size[2]; } ExtraWindow; @@ -666,6 +658,7 @@ typedef struct { static void extrawindow_do_draw(ExtraWindow *ew) { GHOST_ActivateWindowDrawingContext(ew->win); + GPU_context_active_set(ew->gpu_context); glClearColor(1, 1, 1, 1); glClear(GL_COLOR_BUFFER_BIT); @@ -681,6 +674,7 @@ static void extrawindow_do_reshape(ExtraWindow *ew) GHOST_RectangleHandle bounds = GHOST_GetClientBounds(ew->win); GHOST_ActivateWindowDrawingContext(ew->win); + GPU_context_active_set(ew->gpu_context); ew->size[0] = GHOST_GetWidthRectangle(bounds); ew->size[1] = GHOST_GetHeightRectangle(bounds); @@ -793,6 +787,11 @@ ExtraWindow *extrawindow_new(MultiTestApp *app) if (win) { ExtraWindow *ew = MEM_callocN(sizeof(*ew), "mainwindow_new"); + + GLuint default_fb = GHOST_GetDefaultOpenGLFramebuffer(win); + ew->gpu_context = GPU_context_create(default_fb); + GPU_init(); + ew->app = app; ew->win = win; @@ -932,6 +931,9 @@ void multitestapp_run(MultiTestApp *app) void multitestapp_free(MultiTestApp *app) { + BLF_exit(); + GPU_exit(); + mainwindow_free(app->main); loggerwindow_free(app->logger); GHOST_DisposeSystem(app->sys); @@ -944,9 +946,7 @@ int main(int argc, char **argv) { MultiTestApp *app; -#ifndef USE_BMF BLF_init(); -#endif app = multitestapp_new(); diff --git a/intern/ghost/test/multitest/stubs.c b/intern/ghost/test/multitest/stubs.c index f0b076eeba0..151cdc71777 100644 --- a/intern/ghost/test/multitest/stubs.c +++ b/intern/ghost/test/multitest/stubs.c @@ -23,6 +23,7 @@ #include "IMB_imbuf.h" struct ImBuf; +struct ColorSpace; void IMB_freeImBuf(struct ImBuf *UNUSED(ibuf)) { @@ -31,3 +32,31 @@ void IMB_colormanagement_display_to_scene_linear_v3(float UNUSED(pixel[3]), struct ColorManagedDisplay *UNUSED(display)) { } + +bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace) +{ + return false; +} + +bool IMB_colormanagement_space_is_data(struct ColorSpace *colorspace) +{ + return false; +} + +void BKE_material_defaults_free_gpu(void) +{ +} + +/* Variables. */ +int G; + +/* Functions which aren't called. */ +void *BKE_image_free_buffers = NULL; +void *BKE_image_get_tile = NULL; +void *BKE_image_get_tile_from_iuser = NULL; +void *BKE_tempdir_session = NULL; +void *DRW_deferred_shader_remove = NULL; +void *datatoc_common_view_lib_glsl = NULL; +void *ntreeFreeLocalTree = NULL; +void *ntreeGPUMaterialNodes = NULL; +void *ntreeLocalize = NULL; diff --git a/intern/mantaflow/extern/manta_fluid_API.h b/intern/mantaflow/extern/manta_fluid_API.h index 5ed94d99edd..48d42504994 100644 --- a/intern/mantaflow/extern/manta_fluid_API.h +++ b/intern/mantaflow/extern/manta_fluid_API.h @@ -132,14 +132,14 @@ void manta_smoke_turbulence_export(struct MANTA *smoke, float **tcw2); void manta_smoke_get_rgba(struct MANTA *smoke, float *data, int sequential); void manta_smoke_turbulence_get_rgba(struct MANTA *smoke, float *data, int sequential); -void manta_smoke_get_rgba_from_density(struct MANTA *smoke, - float color[3], - float *data, - int sequential); -void manta_smoke_turbulence_get_rgba_from_density(struct MANTA *smoke, - float color[3], - float *data, - int sequential); +void manta_smoke_get_rgba_fixed_color(struct MANTA *smoke, + float color[3], + float *data, + int sequential); +void manta_smoke_turbulence_get_rgba_fixed_color(struct MANTA *smoke, + float color[3], + float *data, + int sequential); void manta_smoke_ensure_heat(struct MANTA *smoke, struct FluidModifierData *mmd); void manta_smoke_ensure_fire(struct MANTA *smoke, struct FluidModifierData *mmd); void manta_smoke_ensure_colors(struct MANTA *smoke, struct FluidModifierData *mmd); diff --git a/intern/mantaflow/intern/manta_fluid_API.cpp b/intern/mantaflow/intern/manta_fluid_API.cpp index 7e3e4520485..89c69bebc51 100644 --- a/intern/mantaflow/intern/manta_fluid_API.cpp +++ b/intern/mantaflow/intern/manta_fluid_API.cpp @@ -455,14 +455,9 @@ static void get_rgba( for (i = 0; i < total_cells; i++) { float alpha = a[i]; - if (alpha) { - data[i * m] = r[i]; - data[i * m + i_g] = g[i]; - data[i * m + i_b] = b[i]; - } - else { - data[i * m] = data[i * m + i_g] = data[i * m + i_b] = 0.0f; - } + data[i * m] = r[i] * alpha; + data[i * m + i_g] = g[i] * alpha; + data[i * m + i_b] = b[i] * alpha; data[i * m + i_a] = alpha; } } @@ -489,8 +484,7 @@ void manta_smoke_turbulence_get_rgba(MANTA *smoke, float *data, int sequential) sequential); } -static void get_rgba_from_density( - float color[3], float *a, int total_cells, float *data, int sequential) +static void get_rgba_fixed_color(float color[3], int total_cells, float *data, int sequential) { int i; int m = 4, i_g = 1, i_b = 2, i_a = 3; @@ -502,31 +496,24 @@ static void get_rgba_from_density( } for (i = 0; i < total_cells; i++) { - float alpha = a[i]; - if (alpha) { - data[i * m] = color[0] * alpha; - data[i * m + i_g] = color[1] * alpha; - data[i * m + i_b] = color[2] * alpha; - } - else { - data[i * m] = data[i * m + i_g] = data[i * m + i_b] = 0.0f; - } - data[i * m + i_a] = alpha; + data[i * m] = color[0]; + data[i * m + i_g] = color[1]; + data[i * m + i_b] = color[2]; + data[i * m + i_a] = 1.0f; } } -void manta_smoke_get_rgba_from_density(MANTA *smoke, float color[3], float *data, int sequential) +void manta_smoke_get_rgba_fixed_color(MANTA *smoke, float color[3], float *data, int sequential) { - get_rgba_from_density(color, smoke->getDensity(), smoke->getTotalCells(), data, sequential); + get_rgba_fixed_color(color, smoke->getTotalCells(), data, sequential); } -void manta_smoke_turbulence_get_rgba_from_density(MANTA *smoke, - float color[3], - float *data, - int sequential) +void manta_smoke_turbulence_get_rgba_fixed_color(MANTA *smoke, + float color[3], + float *data, + int sequential) { - get_rgba_from_density( - color, smoke->getDensityHigh(), smoke->getTotalCellsHigh(), data, sequential); + get_rgba_fixed_color(color, smoke->getTotalCellsHigh(), data, sequential); } void manta_smoke_ensure_heat(MANTA *smoke, struct FluidModifierData *mmd) diff --git a/release/scripts/modules/bl_ui_utils/bug_report_url.py b/release/scripts/modules/bl_ui_utils/bug_report_url.py index 008eafc2c46..2adee70bc86 100644 --- a/release/scripts/modules/bl_ui_utils/bug_report_url.py +++ b/release/scripts/modules/bl_ui_utils/bug_report_url.py @@ -57,7 +57,7 @@ def url_prefill_from_blender(addon_info=None): ) ) fh.write( - "Worked: (optional)\n" + "Worked: (newest version of Blender that worked as expected)\n" ) if addon_info: fh.write( diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 3cefbee8c17..99508bf8fab 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -725,6 +725,19 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "size") col.prop(md, "spatial_size") + layout.separator() + + layout.prop(md, "spectrum") + + if md.spectrum in {'TEXEL_MARSEN_ARSLOE', 'JONSWAP'}: + split = layout.split() + + col = split.column() + col.prop(md, "sharpen_peak_jonswap") + + col = split.column() + col.prop(md, "fetch_jonswap") + layout.label(text="Waves:") split = layout.split() @@ -2028,13 +2041,22 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel): sub.prop(md, "frame_start", text="Start") sub.prop(md, "frame_end", text="End") - col = layout.column() - col.separator() - col.label(text="Layer:") - row = col.row(align=True) + layout.label(text="Influence Filters:") + + split = layout.split(factor=0.25) + + col1 = split.column() + + col1.label(text="Layer:") + + col2 = split.column() + + split = col2.split(factor=0.6) + row = split.row(align=True) row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT') - row = layout.row(align=True) + + row = split.row(align=True) row.prop(md, "layer_pass", text="Pass") row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT') diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 8117445e4af..76ba4dfb78e 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -252,15 +252,25 @@ class DOPESHEET_HT_editor_buttons(Header): # Layer management if st.mode == 'GPENCIL': - row = layout.row(align=True) - row.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP' - row.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN' + ob = context.active_object + selected = st.dopesheet.show_only_selected + enable_but = selected and ob is not None and ob.type == 'GPENCIL' row = layout.row(align=True) + row.enabled = enable_but row.operator("gpencil.layer_add", icon='ADD', text="") row.operator("gpencil.layer_remove", icon='REMOVE', text="") + row.menu("GPENCIL_MT_layer_context_menu", icon='DOWNARROW_HLT', text="") - layout.separator_spacer() + row = layout.row(align=True) + row.enabled = enable_but + row.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP' + row.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN' + + row = layout.row(align=True) + row.enabled = enable_but + row.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_ON', text="").affect_visibility = True + row.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False layout.separator_spacer() @@ -270,15 +280,8 @@ class DOPESHEET_HT_editor_buttons(Header): dopesheet_filter(layout, context) elif st.mode == 'GPENCIL': row = layout.row(align=True) - row.prop(st.dopesheet, "show_gpencil_3d_only", text="Active Only") - - if st.dopesheet.show_gpencil_3d_only: - row = layout.row(align=True) - row.prop(st.dopesheet, "show_only_selected", text="") - row.prop(st.dopesheet, "show_hidden", text="") - - row = layout.row(align=True) - row.prop(st.dopesheet, "filter_text", text="") + row.prop(st.dopesheet, "show_only_selected", text="") + row.prop(st.dopesheet, "show_hidden", text="") layout.popover( panel="DOPESHEET_PT_filters", diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 447386b8f9d..969f9b4bd1a 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -5888,7 +5888,9 @@ class VIEW3D_PT_overlay_guides(Panel): sub.prop(overlay, "show_cursor", text="3D Cursor") if shading.type == 'MATERIAL': - col.prop(overlay, "show_look_dev") + row = col.row() + row.active = shading.render_pass == 'COMBINED' + row.prop(overlay, "show_look_dev") col.prop(overlay, "show_annotation", text="Annotations") @@ -6900,7 +6902,7 @@ class VIEW3D_PT_gpencil_sculpt_context_menu(Panel): def draw(self, context): ts = context.tool_settings - settings = ts.gpencil_paint + settings = ts.gpencil_sculpt_paint brush = settings.brush layout = self.layout @@ -6920,7 +6922,7 @@ class VIEW3D_PT_gpencil_weight_context_menu(Panel): def draw(self, context): ts = context.tool_settings - settings = ts.gpencil_paint + settings = ts.gpencil_weight_paint brush = settings.brush layout = self.layout diff --git a/source/blender/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt index 6c786dfcc7a..0b1ce5149da 100644 --- a/source/blender/blendthumb/CMakeLists.txt +++ b/source/blender/blendthumb/CMakeLists.txt @@ -28,6 +28,8 @@ set(SRC src/Dll.cpp ) +set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /nodefaultlib:MSVCRT.lib") + add_library(BlendThumb SHARED ${SRC}) target_link_libraries(BlendThumb ${ZLIB_LIBRARIES}) diff --git a/source/blender/blendthumb/src/Dll.cpp b/source/blender/blendthumb/src/Dll.cpp index 08b3d253be8..fec792ebfeb 100644 --- a/source/blender/blendthumb/src/Dll.cpp +++ b/source/blender/blendthumb/src/Dll.cpp @@ -159,7 +159,8 @@ struct REGISTRY_ENTRY { PCWSTR pszKeyName; PCWSTR pszValueName; DWORD dwValueType; - PCWSTR pszData; + PCWSTR pszData; // These two fields could/should have been a union, but C++ + DWORD dwData; // only lets you initalize the first field in a union. }; // Creates a registry key (if needed) and sets the default value of the key @@ -187,7 +188,7 @@ HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry) break; case REG_DWORD: size = sizeof(DWORD); - data = (DWORD)pRegistryEntry->pszData; + data = pRegistryEntry->dwData; lpData = (BYTE *)&data; break; default: @@ -235,6 +236,7 @@ STDAPI DllRegisterServer() L"Software\\Classes\\.blend\\", L"Treatment", REG_DWORD, + 0, 0}, // doesn't appear to do anything... {HKEY_CURRENT_USER, L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 725c4c0712d..5664b9ae0a0 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -47,11 +47,9 @@ #include "IMB_colormanagement.h" -#ifndef BLF_STANDALONE -# include "GPU_shader.h" -# include "GPU_matrix.h" -# include "GPU_immediate.h" -#endif +#include "GPU_shader.h" +#include "GPU_matrix.h" +#include "GPU_immediate.h" #include "blf_internal_types.h" #include "blf_internal.h" diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index f0afe184233..0f75d9b5ab0 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -230,8 +230,10 @@ void blf_batch_draw(void) GPU_blend_set_func_separate( GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); +#ifndef BLF_STANDALONE /* We need to flush widget base first to ensure correct ordering. */ UI_widgetbase_draw_cache_flush(); +#endif GPUTexture *texture = blf_batch_cache_texture_load(); GPU_texture_bind(texture, 0); diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 3ab6814c531..3270eec58f9 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -46,10 +46,8 @@ #include "BLF_api.h" -#ifndef BLF_STANDALONE -# include "GPU_immediate.h" -# include "GPU_extensions.h" -#endif +#include "GPU_immediate.h" +#include "GPU_extensions.h" #include "blf_internal_types.h" #include "blf_internal.h" diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h index b12803b1603..f3e15529f77 100644 --- a/source/blender/blenkernel/BKE_lib_query.h +++ b/source/blender/blenkernel/BKE_lib_query.h @@ -55,14 +55,14 @@ enum { IDWALK_CB_INDIRECT_USAGE = (1 << 2), /** - * That ID is used as mere sub-data by its owner - * (only case currently: those f***ing nodetrees in materials etc.). - * This means callback shall not *do* anything, - * only use this as informative data if it needs it. + * That ID is used as mere sub-data by its owner (only case currently: those root nodetrees in + * materials etc., and the Scene's master collections). + * This means callback shall not *do* anything, only use this as informative data if it needs it. */ - IDWALK_CB_PRIVATE = (1 << 3), + IDWALK_CB_EMBEDDED = (1 << 3), - /** That ID is not really used by its owner, it's just an internal hint/helper. + /** + * That ID is not really used by its owner, it's just an internal hint/helper. * This addresses Their Highest Ugliness the 'from' pointers: Object->from_proxy and Key->from. * How to handle that kind of cases totally depends on what caller code is doing... */ IDWALK_CB_LOOPBACK = (1 << 4), @@ -89,11 +89,15 @@ enum { typedef struct LibraryIDLinkCallbackData { void *user_data; - /* 'Real' ID, the one that might be in bmain, only differs from self_id when the later is a - * private one. */ + /** + * 'Real' ID, the one that might be in bmain, only differs from self_id when the later is an + * embedded one. + */ struct ID *id_owner; - /* ID from which the current ID pointer is being processed. It may be a 'private' ID like master - * collection or root node tree. */ + /** + * ID from which the current ID pointer is being processed. It may be an embedded ID like master + * collection or root node tree. + */ struct ID *id_self; struct ID **id_pointer; int cb_flag; @@ -112,6 +116,8 @@ enum { IDWALK_READONLY = (1 << 0), IDWALK_RECURSE = (1 << 1), /* Also implies IDWALK_READONLY. */ IDWALK_INCLUDE_UI = (1 << 2), /* Include UI pointers (from WM and screens editors). */ + /** Do not process ID pointers inside embedded IDs. Needed by depsgraph processing e.g. */ + IDWALK_IGNORE_EMBEDDED_ID = (1 << 3), IDWALK_NO_INDIRECT_PROXY_DATA_USAGE = (1 << 8), /* Ugly special case :(((( */ }; diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 6f1f68e1ef2..ed36d3892ac 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -391,9 +391,6 @@ struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user); struct bNodeTree *ntreeCopyTree(struct Main *bmain, const struct bNodeTree *ntree); -/* node->id user count */ -void ntreeUserIncrefID(struct bNodeTree *ntree); -void ntreeUserDecrefID(struct bNodeTree *ntree); struct bNodeTree **BKE_ntree_ptr_from_id(struct ID *id); struct bNodeTree *ntreeFromID(struct ID *id); diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h index 3ba6486e6c5..d3ac825039d 100644 --- a/source/blender/blenkernel/BKE_ocean.h +++ b/source/blender/blenkernel/BKE_ocean.h @@ -84,6 +84,9 @@ void BKE_ocean_init(struct Ocean *o, float alignment, float depth, float time, + int spectrum, + float fetch_jonswap, + float sharpen_peak_jonswap, short do_height_field, short do_chop, short do_normals, @@ -122,6 +125,11 @@ void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, in void BKE_ocean_free_cache(struct OceanCache *och); void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd); +/* ocean_spectrum.c */ +float BLI_ocean_spectrum_piersonmoskowitz(const struct Ocean *oc, const float kx, const float kz); +float BLI_ocean_spectrum_texelmarsenarsloe(const struct Ocean *oc, const float kx, const float kz); +float BLI_ocean_spectrum_jonswap(const struct Ocean *oc, const float kx, const float kz); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 90e5459b599..8018178fcee 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -215,6 +215,7 @@ int BKE_scene_multiview_num_videos_get(const struct RenderData *rd); void BKE_scene_allocate_depsgraph_hash(struct Scene *scene); void BKE_scene_ensure_depsgraph_hash(struct Scene *scene); void BKE_scene_free_depsgraph_hash(struct Scene *scene); +void BKE_scene_free_view_layer_depsgraph(struct Scene *scene, struct ViewLayer *view_layer); struct Depsgraph *BKE_scene_get_depsgraph(struct Main *bmain, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index a6ed1274f19..2231cc36861 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -190,6 +190,8 @@ typedef struct ARegionType { /* return without drawing. * lock is set by region definition, and copied to do_lock by render. can become flag. */ short do_lock, lock; + /** Don't handle gizmos events behind #uiBlock's with #UI_BLOCK_CLIP_EVENTS flag set. */ + bool clip_gizmo_events_by_ui; /* call cursor function on each move event */ short event_cursor; } ARegionType; diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index 5edde7441de..83129bed5f7 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -170,7 +170,7 @@ void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree, float r_point_co[3]); /* - * NULL initializers to local data + * NULL initializes to local data */ #define NULL_ShrinkwrapCalcData \ { \ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 22123f05cab..135168a6de4 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -178,6 +178,7 @@ set(SRC intern/object_facemap.c intern/object_update.c intern/ocean.c + intern/ocean_spectrum.c intern/outliner_treehash.c intern/packedFile.c intern/paint.c diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 0580ad55e43..c23cb9231d7 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1008,12 +1008,12 @@ void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param, * - These properties allow users to hand-animate the * bone curve/shape, without having to resort to using * extra bones - * - The "bone" level offsets are for defining the restpose + * - The "bone" level offsets are for defining the rest-pose * shape of the bone (e.g. for curved eyebrows for example). * -> In the viewport, it's needed to define what the rest pose * looks like * -> For "rest == 0", we also still need to have it present - * so that we can "cancel out" this restpose when it comes + * so that we can "cancel out" this rest-pose when it comes * time to deform some geometry, it won't cause double transforms. * - The "pchan" level offsets are the ones that animators actually * end up animating diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 74c492573b1..67e9feac0cf 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -443,7 +443,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; brush->gpencil_settings->draw_angle = 0.0f; brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->hardeness = 0.211f; + brush->gpencil_settings->hardeness = 0.9f; copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); brush->gpencil_tool = GPAINT_TOOL_DRAW; diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 5c4636db728..d9954323594 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -89,7 +89,7 @@ static void collection_copy_data(Main *bmain, ID *id_dst, const ID *id_src, cons const Collection *collection_src = (const Collection *)id_src; BLI_assert(((collection_src->flag & COLLECTION_IS_MASTER) != 0) == - ((collection_src->id.flag & LIB_PRIVATE_DATA) != 0)); + ((collection_src->id.flag & LIB_EMBEDDED_DATA) != 0)); /* Do not copy collection's preview (same behavior as for objects). */ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ @@ -366,7 +366,7 @@ Collection *BKE_collection_duplicate(Main *bmain, const bool do_obdata) { /* It's not allowed to copy the master collection. */ - BLI_assert((collection->id.flag & LIB_PRIVATE_DATA) == 0); + BLI_assert((collection->id.flag & LIB_EMBEDDED_DATA) == 0); BLI_assert((collection->flag & COLLECTION_IS_MASTER) == 0); if (collection->flag & COLLECTION_IS_MASTER) { return NULL; @@ -514,7 +514,7 @@ Collection *BKE_collection_master_add() /* Not an actual datablock, but owned by scene. */ Collection *master_collection = MEM_callocN(sizeof(Collection), "Master Collection"); STRNCPY(master_collection->id.name, "GRMaster Collection"); - master_collection->id.flag |= LIB_PRIVATE_DATA; + master_collection->id.flag |= LIB_EMBEDDED_DATA; master_collection->flag |= COLLECTION_IS_MASTER; return master_collection; } diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 03c9cc7d151..9919a0d7385 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -2741,7 +2741,7 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, } /* Optimization: Static liquid flow objects don't need emission computation after first * frame. - * TODO (sebbas): Also do not use static mode if inital velocities are enabled. */ + * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */ if (mfs->type == FLUID_FLOW_TYPE_LIQUID && is_static && !is_first_frame && !use_velocity) { continue; } @@ -2961,7 +2961,7 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, if (is_liquid && !is_first_frame) { /* Skip static liquid objects that are not on the first frame. - * TODO (sebbas): Also do not use static mode if inital velocities are enabled. */ + * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */ if (is_static && !use_velocity) { continue; } @@ -3222,7 +3222,7 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj float cell_size_scaled[3]; /* Assign material + flags to new mesh. - * If there are no faces in original mesj, keep materials and flags unchanged. */ + * If there are no faces in original mesh, keep materials and flags unchanged. */ MPoly *mpoly; MPoly mp_example = {0}; mpoly = orgmesh->mpoly; diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 7a697f19b8b..4220408749a 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -3023,7 +3023,7 @@ Image *BKE_image_ensure_viewer(Main *bmain, int type, const char *name) /* happens on reload, imagewindow cannot be image user when hidden*/ if (ima->id.us == 0) { - id_us_plus(&ima->id); + id_us_ensure_real(&ima->id); } return ima; diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 919f249eea6..c342185d0b8 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -340,7 +340,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data) ID *id_self = cb_data->id_self; ID **id_pointer = cb_data->id_pointer; int const cb_flag = cb_data->cb_flag; - if (cb_flag & IDWALK_CB_PRIVATE) { + if (cb_flag & IDWALK_CB_EMBEDDED) { return IDWALK_RET_NOP; } @@ -1148,7 +1148,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori ID *new_id = *r_newid; int flag = orig_flag; - const bool is_private_id_data = (id->flag & LIB_PRIVATE_DATA) != 0; + const bool is_private_id_data = (id->flag & LIB_EMBEDDED_DATA) != 0; BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL); BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0); @@ -1167,7 +1167,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori } /* The id->flag bits to copy over. */ - const int copy_idflag_mask = LIB_PRIVATE_DATA; + const int copy_idflag_mask = LIB_EMBEDDED_DATA; if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) { /* r_newid already contains pointer to allocated memory. */ @@ -1744,7 +1744,7 @@ static void library_make_local_copying_check(ID *id, } /* Shapekeys are considered 'private' to their owner ID here, and never tagged - * (since they cannot be linked), * so we have to switch effective parent to their owner. + * (since they cannot be linked), so we have to switch effective parent to their owner. */ if (GS(par_id->name) == ID_KE) { par_id = ((Key *)par_id)->from; diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index ee27d0e546d..41d938e897d 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -137,11 +137,15 @@ enum { typedef struct LibraryForeachIDData { Main *bmain; - /* 'Real' ID, the one that might be in bmain, only differs from self_id when the later is a - * private one. */ + /** + * 'Real' ID, the one that might be in bmain, only differs from self_id when the later is a + * private one. + */ ID *owner_id; - /* ID from which the current ID pointer is being processed. It may be a 'private' ID like master - * collection or root node tree. */ + /** + * ID from which the current ID pointer is being processed. It may be an embedded ID like master + * collection or root node tree. + */ ID *self_id; int flag; @@ -343,8 +347,8 @@ static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBas /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad * anyway... */ const int cb_flag = (lc->collection != NULL && - (lc->collection->id.flag & LIB_PRIVATE_DATA) != 0) ? - IDWALK_CB_PRIVATE : + (lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? + IDWALK_CB_EMBEDDED : IDWALK_CB_NOP; FOREACH_CALLBACK_INVOKE(data, lc->collection, cb_flag); library_foreach_layer_collection(data, &lc->layer_collections); @@ -367,8 +371,8 @@ static void library_foreach_collection(LibraryForeachIDData *data, Collection *c /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad * anyway... */ const int cb_flag = ((parent->collection != NULL && - (parent->collection->id.flag & LIB_PRIVATE_DATA) != 0) ? - IDWALK_CB_PRIVATE : + (parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? + IDWALK_CB_EMBEDDED : IDWALK_CB_NOP); FOREACH_CALLBACK_INVOKE( data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag); @@ -484,13 +488,13 @@ static void library_foreach_screen_area(LibraryForeachIDData *data, ScrArea *are FOREACH_CALLBACK_INVOKE_ID(data, snode->from, IDWALK_CB_NOP); FOREACH_CALLBACK_INVOKE( - data, snode->nodetree, is_private_nodetree ? IDWALK_CB_PRIVATE : IDWALK_CB_USER); + data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER); for (path = snode->treepath.first; path; path = path->next) { if (path == snode->treepath.first) { /* first nodetree in path is same as snode->nodetree */ FOREACH_CALLBACK_INVOKE( - data, path->nodetree, is_private_nodetree ? IDWALK_CB_PRIVATE : IDWALK_CB_NOP); + data, path->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_NOP); } else { FOREACH_CALLBACK_INVOKE(data, path->nodetree, IDWALK_CB_USER); @@ -527,10 +531,13 @@ static void library_foreach_ID_as_subdata_link(ID **id_pp, { /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */ ID *id = *id_pp; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_PRIVATE); + FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_EMBEDDED); BLI_assert(id == *id_pp); - if (flag & IDWALK_RECURSE) { + if (flag & IDWALK_IGNORE_EMBEDDED_ID) { + /* Do Nothing. */ + } + else if (flag & IDWALK_RECURSE) { /* Defer handling into main loop, recursively calling BKE_library_foreach_ID_link in * IDWALK_RECURSE case is troublesome, see T49553. */ /* XXX note that this breaks the 'owner id' thing now, we likely want to handle that @@ -583,7 +590,12 @@ static void library_foreach_ID_link(Main *bmain, for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) { data.self_id = id; - data.owner_id = (id->flag & LIB_PRIVATE_DATA) ? id_owner : data.self_id; + /* Note that we may call this functions sometime directly on an embedded ID, without any + * knowledge of the owner ID then. + * While not great, and that should be probably sanitized at some point, we cal live with it + * for now. */ + data.owner_id = ((id->flag & LIB_EMBEDDED_DATA) != 0 && id_owner != NULL) ? id_owner : + data.self_id; /* inherit_data is non-NULL when this function is called for some sub-data ID * (like root nodetree of a material). diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index d4b7696074a..1a22a6e6f79 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -68,7 +68,7 @@ typedef struct IDRemap { ID *old_id; ID *new_id; /** The ID in which we are replacing old_id by new_id usages. */ - ID *id; + ID *id_owner; short flag; /* 'Output' data. */ @@ -94,16 +94,21 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) { const int cb_flag = cb_data->cb_flag; - if (cb_flag & IDWALK_CB_PRIVATE) { + if (cb_flag & IDWALK_CB_EMBEDDED) { return IDWALK_RET_NOP; } + ID *id_owner = cb_data->id_owner; ID *id_self = cb_data->id_self; ID **id_p = cb_data->id_pointer; IDRemap *id_remap_data = cb_data->user_data; ID *old_id = id_remap_data->old_id; ID *new_id = id_remap_data->new_id; - ID *id = id_remap_data->id; + + /* Those asserts ensure the general sanity of ID tags regarding 'embedded' ID data (root + * nodetrees and co). */ + BLI_assert(id_owner == id_remap_data->id_owner); + BLI_assert(id_self == id_owner || (id_self->flag & LIB_EMBEDDED_DATA) != 0); if (!old_id) { /* Used to cleanup all IDs used by a specific one. */ BLI_assert(!new_id); @@ -123,9 +128,10 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct, * on the other hand since they get reset to lib data on file open/reload it is indirect too. * Edit Mode is also a 'skip direct' case. */ - const bool is_obj = (GS(id->name) == ID_OB); - const bool is_obj_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group)); - const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id)); + const bool is_obj = (GS(id_owner->name) == ID_OB); + const bool is_obj_proxy = (is_obj && + (((Object *)id_owner)->proxy || ((Object *)id_owner)->proxy_group)); + const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner)); const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) && (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_OVERRIDE_LIBRARY) != 0; @@ -149,19 +155,19 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) { - id->tag |= LIB_TAG_DOIT; + id_owner->tag |= LIB_TAG_DOIT; } /* Special hack in case it's Object->data and we are in edit mode, and new_id is not NULL * (otherwise, we follow common NEVER_NULL flags). * (skipped_indirect too). */ if ((is_never_null && skip_never_null) || - (is_obj_editmode && (((Object *)id)->data == *id_p) && new_id != NULL) || + (is_obj_editmode && (((Object *)id_owner)->data == *id_p) && new_id != NULL) || (skip_indirect && is_indirect) || (is_reference && skip_reference)) { if (is_indirect) { id_remap_data->skipped_indirect++; if (is_obj) { - Object *ob = (Object *)id; + Object *ob = (Object *)id_owner; if (ob->data == *id_p && ob->proxy != NULL) { /* And another 'Proudly brought to you by Proxy Hell' hack! * This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */ @@ -189,6 +195,11 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) DEG_id_tag_update_ex(id_remap_data->bmain, id_self, ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + if (id_self != id_owner) { + DEG_id_tag_update_ex(id_remap_data->bmain, + id_owner, + ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + } } if (cb_flag & IDWALK_CB_USER) { /* NOTE: We don't user-count IDs which are not in the main database. @@ -215,7 +226,7 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) } /* We need to remap proxy_from pointer of remapped proxy... sigh. */ if (is_obj_proxy && new_id != NULL) { - Object *ob = (Object *)id; + Object *ob = (Object *)id_owner; if (ob->proxy == (Object *)new_id) { ob->proxy->proxy_from = ob; } @@ -228,11 +239,11 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) { - switch (GS(r_id_remap_data->id->name)) { + switch (GS(r_id_remap_data->id_owner->name)) { case ID_OB: { ID *old_id = r_id_remap_data->old_id; if (!old_id || GS(old_id->name) == ID_AR) { - Object *ob = (Object *)r_id_remap_data->id; + Object *ob = (Object *)r_id_remap_data->id_owner; /* Object's pose holds reference to armature bones... sic */ /* Note that in theory, we should have to bother about * linked/non-linked/never-null/etc. flags/states. @@ -371,7 +382,7 @@ static void libblock_remap_data( r_id_remap_data->bmain = bmain; r_id_remap_data->old_id = old_id; r_id_remap_data->new_id = new_id; - r_id_remap_data->id = NULL; + r_id_remap_data->id_owner = NULL; r_id_remap_data->flag = remap_flags; r_id_remap_data->status = 0; r_id_remap_data->skipped_direct = 0; @@ -382,7 +393,7 @@ static void libblock_remap_data( #ifdef DEBUG_PRINT printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib); #endif - r_id_remap_data->id = id; + r_id_remap_data->id_owner = id; libblock_remap_data_preprocess(r_id_remap_data); BKE_library_foreach_ID_link( NULL, id, foreach_libblock_remap_callback, (void *)r_id_remap_data, foreach_id_flags); @@ -398,7 +409,7 @@ static void libblock_remap_data( /* Note that we cannot skip indirect usages of old_id here (if requested), * we still need to check it for the user count handling... * XXX No more true (except for debug usage of those skipping counters). */ - r_id_remap_data->id = id_curr; + r_id_remap_data->id_owner = id_curr; libblock_remap_data_preprocess(r_id_remap_data); BKE_library_foreach_ID_link(NULL, id_curr, @@ -642,7 +653,7 @@ void BKE_libblock_relink_ex( static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data) { const int cb_flag = cb_data->cb_flag; - if (cb_flag & IDWALK_CB_PRIVATE) { + if (cb_flag & IDWALK_CB_EMBEDDED) { return IDWALK_RET_NOP; } diff --git a/source/blender/blenkernel/intern/main_idmap.c b/source/blender/blenkernel/intern/main_idmap.c index 26eb0b681a1..8b83482d685 100644 --- a/source/blender/blenkernel/intern/main_idmap.c +++ b/source/blender/blenkernel/intern/main_idmap.c @@ -124,6 +124,8 @@ struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain, const bool existing_key = BLI_ghash_ensure_p( id_map->uuid_map, POINTER_FROM_UINT(id->session_uuid), &id_ptr_v); BLI_assert(existing_key == false); + UNUSED_VARS_NDEBUG(existing_key); + *id_ptr_v = id; } FOREACH_MAIN_ID_END; diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 1feb20ec272..8ddb78bcc17 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1654,7 +1654,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) } else { ntree = MEM_callocN(sizeof(bNodeTree), "new node tree"); - ntree->id.flag |= LIB_PRIVATE_DATA; + ntree->id.flag |= LIB_EMBEDDED_DATA; *((short *)ntree->id.name) = ID_NT; BLI_strncpy(ntree->id.name + 2, name, sizeof(ntree->id.name)); } @@ -1682,21 +1682,6 @@ bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree) return ntreeCopyTree_ex(ntree, bmain, true); } -void ntreeUserIncrefID(bNodeTree *ntree) -{ - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - id_us_plus(node->id); - } -} -void ntreeUserDecrefID(bNodeTree *ntree) -{ - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - id_us_min(node->id); - } -} - /* *************** Node Preview *********** */ /* XXX this should be removed eventually ... diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index c27fb59835f..26485d10fbd 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -38,11 +38,11 @@ #include "BLI_path_util.h" #include "BLI_rand.h" #include "BLI_task.h" -#include "BLI_threads.h" #include "BLI_utildefines.h" #include "BKE_image.h" #include "BKE_ocean.h" +#include "ocean_intern.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -54,95 +54,6 @@ #ifdef WITH_OCEANSIM /* Ocean code */ -# include "fftw3.h" - -# define GRAVITY 9.81f - -typedef struct Ocean { - /* ********* input parameters to the sim ********* */ - float _V; - float _l; - float _w; - float _A; - float _damp_reflections; - float _wind_alignment; - float _depth; - - float _wx; - float _wz; - - float _L; - - /* dimensions of computational grid */ - int _M; - int _N; - - /* spatial size of computational grid */ - float _Lx; - float _Lz; - - float normalize_factor; /* init w */ - float time; - - short _do_disp_y; - short _do_normals; - short _do_chop; - short _do_jacobian; - - /* mutex for threaded texture access */ - ThreadRWMutex oceanmutex; - - /* ********* sim data arrays ********* */ - - /* two dimensional arrays of complex */ - fftw_complex *_fft_in; /* init w sim w */ - fftw_complex *_fft_in_x; /* init w sim w */ - fftw_complex *_fft_in_z; /* init w sim w */ - fftw_complex *_fft_in_jxx; /* init w sim w */ - fftw_complex *_fft_in_jzz; /* init w sim w */ - fftw_complex *_fft_in_jxz; /* init w sim w */ - fftw_complex *_fft_in_nx; /* init w sim w */ - fftw_complex *_fft_in_nz; /* init w sim w */ - fftw_complex *_htilda; /* init w sim w (only once) */ - - /* fftw "plans" */ - fftw_plan _disp_y_plan; /* init w sim r */ - fftw_plan _disp_x_plan; /* init w sim r */ - fftw_plan _disp_z_plan; /* init w sim r */ - fftw_plan _N_x_plan; /* init w sim r */ - fftw_plan _N_z_plan; /* init w sim r */ - fftw_plan _Jxx_plan; /* init w sim r */ - fftw_plan _Jxz_plan; /* init w sim r */ - fftw_plan _Jzz_plan; /* init w sim r */ - - /* two dimensional arrays of float */ - double *_disp_y; /* init w sim w via plan? */ - double *_N_x; /* init w sim w via plan? */ - /* all member of this array has same values, - * so convert this array to a float to reduce memory usage (MEM01). */ - /*float * _N_y; */ - double _N_y; /* sim w ********* can be rearranged? */ - double *_N_z; /* init w sim w via plan? */ - double *_disp_x; /* init w sim w via plan? */ - double *_disp_z; /* init w sim w via plan? */ - - /* two dimensional arrays of float */ - /* Jacobian and minimum eigenvalue */ - double *_Jxx; /* init w sim w */ - double *_Jzz; /* init w sim w */ - double *_Jxz; /* init w sim w */ - - /* one dimensional float array */ - float *_kx; /* init w sim r */ - float *_kz; /* init w sim r */ - - /* two dimensional complex array */ - fftw_complex *_h0; /* init w sim r */ - fftw_complex *_h0_minus; /* init w sim r */ - - /* two dimensional float array */ - float *_k; /* init w sim r */ -} Ocean; static float nextfr(RNG *rng, float min, float max) { @@ -285,7 +196,7 @@ float BKE_ocean_jminus_to_foam(float jminus, float coverage) { float foam = jminus * -0.005f + coverage; CLAMP(foam, 0.0f, 1.0f); - return foam * foam; + return foam; } void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float v) @@ -893,6 +804,9 @@ void BKE_ocean_init_from_modifier(struct Ocean *ocean, struct OceanModifierData omd->wave_alignment, omd->depth, omd->time, + omd->spectrum, + omd->fetch_jonswap, + omd->sharpen_peak_jonswap, do_heightfield, do_chop, do_normals, @@ -913,6 +827,9 @@ void BKE_ocean_init(struct Ocean *o, float alignment, float depth, float time, + int spectrum, + float fetch_jonswap, + float sharpen_peak_jonswap, short do_height_field, short do_chop, short do_normals, @@ -940,6 +857,13 @@ void BKE_ocean_init(struct Ocean *o, o->_L = V * V / GRAVITY; /* largest wave for a given velocity V */ o->time = time; + /* Spectrum to use. */ + o->_spectrum = spectrum; + + /* Common JONSWAP parameters. */ + o->_fetch_jonswap = fetch_jonswap; + o->_sharpen_peak_jonswap = sharpen_peak_jonswap; + o->_do_disp_y = do_height_field; o->_do_normals = do_normals; o->_do_chop = do_chop; @@ -1001,10 +925,46 @@ void BKE_ocean_init(struct Ocean *o, fftw_complex r1r2; init_complex(r1r2, r1, r2); - mul_complex_f( - o->_h0[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, o->_kx[i], o->_kz[j]) / 2.0f))); - mul_complex_f( - o->_h0_minus[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, -o->_kx[i], -o->_kz[j]) / 2.0f))); + switch (o->_spectrum) { + case MOD_OCEAN_SPECTRUM_JONSWAP: + mul_complex_f(o->_h0[i * o->_N + j], + r1r2, + (float)(sqrt(BLI_ocean_spectrum_jonswap(o, o->_kx[i], o->_kz[j]) / 2.0f))); + mul_complex_f( + o->_h0_minus[i * o->_N + j], + r1r2, + (float)(sqrt(BLI_ocean_spectrum_jonswap(o, -o->_kx[i], -o->_kz[j]) / 2.0f))); + break; + case MOD_OCEAN_SPECTRUM_TEXEL_MARSEN_ARSLOE: + mul_complex_f( + o->_h0[i * o->_N + j], + r1r2, + (float)(sqrt(BLI_ocean_spectrum_texelmarsenarsloe(o, o->_kx[i], o->_kz[j]) / 2.0f))); + mul_complex_f( + o->_h0_minus[i * o->_N + j], + r1r2, + (float)(sqrt(BLI_ocean_spectrum_texelmarsenarsloe(o, -o->_kx[i], -o->_kz[j]) / + 2.0f))); + break; + case MOD_OCEAN_SPECTRUM_PIERSON_MOSKOWITZ: + mul_complex_f( + o->_h0[i * o->_N + j], + r1r2, + (float)(sqrt(BLI_ocean_spectrum_piersonmoskowitz(o, o->_kx[i], o->_kz[j]) / 2.0f))); + mul_complex_f( + o->_h0_minus[i * o->_N + j], + r1r2, + (float)(sqrt(BLI_ocean_spectrum_piersonmoskowitz(o, -o->_kx[i], -o->_kz[j]) / + 2.0f))); + break; + default: + mul_complex_f( + o->_h0[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, o->_kx[i], o->_kz[j]) / 2.0f))); + mul_complex_f(o->_h0_minus[i * o->_N + j], + r1r2, + (float)(sqrt(Ph(o, -o->_kx[i], -o->_kz[j]) / 2.0f))); + break; + } } } @@ -1517,12 +1477,6 @@ void BKE_ocean_bake(struct Ocean *o, #else /* WITH_OCEANSIM */ -/* stub */ -typedef struct Ocean { - /* need some data here, C does not allow empty struct */ - int stub; -} Ocean; - float BKE_ocean_jminus_to_foam(float UNUSED(jminus), float UNUSED(coverage)) { return 0.0f; @@ -1591,6 +1545,9 @@ void BKE_ocean_init(struct Ocean *UNUSED(o), float UNUSED(alignment), float UNUSED(depth), float UNUSED(time), + int UNUSED(spectrum), + float UNUSED(fetch_jonswap), + float UNUSED(sharpen_peak_jonswap), short UNUSED(do_height_field), short UNUSED(do_chop), short UNUSED(do_normals), diff --git a/source/blender/blenkernel/intern/ocean_intern.h b/source/blender/blenkernel/intern/ocean_intern.h new file mode 100644 index 00000000000..7da88419219 --- /dev/null +++ b/source/blender/blenkernel/intern/ocean_intern.h @@ -0,0 +1,137 @@ +/* + * 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. + */ + +#ifndef __BKE_OCEAN_INTERN_H__ +#define __BKE_OCEAN_INTERN_H__ + +/** \file + * \ingroup bli + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WITH_OCEANSIM +# include "BLI_threads.h" +# include "fftw3.h" +# define GRAVITY 9.81f + +typedef struct Ocean { + /* ********* input parameters to the sim ********* */ + float _V; + float _l; + float _w; + float _A; + float _damp_reflections; + float _wind_alignment; + float _depth; + + float _wx; + float _wz; + + float _L; + + /* dimensions of computational grid */ + int _M; + int _N; + + /* spatial size of computational grid */ + float _Lx; + float _Lz; + + float normalize_factor; /* init w */ + float time; + + short _do_disp_y; + short _do_normals; + short _do_chop; + short _do_jacobian; + + /* Which spectral model we are using. */ + int _spectrum; + + /* JONSWAP common parameters. */ + float _fetch_jonswap; + float _sharpen_peak_jonswap; + + /* mutex for threaded texture access */ + ThreadRWMutex oceanmutex; + + /* ********* sim data arrays ********* */ + + /* two dimensional arrays of complex */ + fftw_complex *_fft_in; /* init w sim w */ + fftw_complex *_fft_in_x; /* init w sim w */ + fftw_complex *_fft_in_z; /* init w sim w */ + fftw_complex *_fft_in_jxx; /* init w sim w */ + fftw_complex *_fft_in_jzz; /* init w sim w */ + fftw_complex *_fft_in_jxz; /* init w sim w */ + fftw_complex *_fft_in_nx; /* init w sim w */ + fftw_complex *_fft_in_nz; /* init w sim w */ + fftw_complex *_htilda; /* init w sim w (only once) */ + + /* fftw "plans" */ + fftw_plan _disp_y_plan; /* init w sim r */ + fftw_plan _disp_x_plan; /* init w sim r */ + fftw_plan _disp_z_plan; /* init w sim r */ + fftw_plan _N_x_plan; /* init w sim r */ + fftw_plan _N_z_plan; /* init w sim r */ + fftw_plan _Jxx_plan; /* init w sim r */ + fftw_plan _Jxz_plan; /* init w sim r */ + fftw_plan _Jzz_plan; /* init w sim r */ + + /* two dimensional arrays of float */ + double *_disp_y; /* init w sim w via plan? */ + double *_N_x; /* init w sim w via plan? */ + /* all member of this array has same values, + * so convert this array to a float to reduce memory usage (MEM01). */ + /*float * _N_y; */ + double _N_y; /* sim w ********* can be rearranged? */ + double *_N_z; /* init w sim w via plan? */ + double *_disp_x; /* init w sim w via plan? */ + double *_disp_z; /* init w sim w via plan? */ + + /* two dimensional arrays of float */ + /* Jacobian and minimum eigenvalue */ + double *_Jxx; /* init w sim w */ + double *_Jzz; /* init w sim w */ + double *_Jxz; /* init w sim w */ + + /* one dimensional float array */ + float *_kx; /* init w sim r */ + float *_kz; /* init w sim r */ + + /* two dimensional complex array */ + fftw_complex *_h0; /* init w sim r */ + fftw_complex *_h0_minus; /* init w sim r */ + + /* two dimensional float array */ + float *_k; /* init w sim r */ +} Ocean; +#else +/* stub */ +typedef struct Ocean { + /* need some data here, C does not allow empty struct */ + int stub; +} Ocean; +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/blender/blenkernel/intern/ocean_spectrum.c b/source/blender/blenkernel/intern/ocean_spectrum.c new file mode 100644 index 00000000000..93018f4a5b0 --- /dev/null +++ b/source/blender/blenkernel/intern/ocean_spectrum.c @@ -0,0 +1,224 @@ +/* + * 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. + */ + +/** \file + * \ingroup bke + */ + +#include "BLI_math.h" +#include "BKE_ocean.h" +#include "ocean_intern.h" + +#ifdef WITH_OCEANSIM + +/* -------------------------------------------------------------------- */ +/** \name Ocean Spectrum from EncinoWaves + * \{ */ + +/* + * Original code from EncinoWaves project Copyright (c) 2015 Christopher Jon Horvath + * Modifications made to work within blender. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +/** + * alpha_beta_spectrum is a common algorithm for the Pierson-Moskowitz, JONSWAP and TMA models. + * This is a modified implementation from the EncinoWaves project. + */ +static float alpha_beta_spectrum(const float alpha, + const float beta, + const float gamma, + const float omega, + const float peakomega) +{ + return (alpha * sqrt(gamma) / pow(omega, 5.0)) * exp(-beta * pow(peakomega / omega, 4.0)); +} + +static float peak_sharpen(const float omega, const float m_peakomega, const float m_gamma) +{ + const float peak_sharpening_sigma = (omega < m_peakomega) ? 0.07 : 0.09; + const float peak_sharpening = pow( + m_gamma, exp(-sqrt((omega - m_peakomega) / (peak_sharpening_sigma * m_peakomega)) / 2.0)); + + return peak_sharpening; +} + +/** + * Spectrum-type independent modifications. + */ +static float ocean_spectrum_wind_and_damp(const Ocean *oc, + const float kx, + const float kz, + const float val) +{ + const float k2 = kx * kx + kz * kz; + const float k_mag_inv = 1.0f / k2; + const float k_dot_w = (kx * k_mag_inv * oc->_wx) + (kz * k_mag_inv * oc->_wz); + + /* Bias towards wind dir. */ + float newval = val * pow(fabs(k_dot_w), oc->_wind_alignment); + + /* Eliminate wavelengths smaller than cutoff. */ + /* val *= exp(-k2 * m_cutoff); */ + + /* Reduce reflected waves. */ + if (k_dot_w < 0.0f) { + if (oc->_wind_alignment > 0.0) { + newval *= oc->_damp_reflections; + } + } + + return newval; +} + +static float jonswap(const Ocean *oc, const float k2) +{ + /* Get our basic JONSWAP value from #alpha_beta_spectrum. */ + const float k_mag = sqrt(k2); + + const float m_omega = GRAVITY * k_mag * tanh(k_mag * oc->_depth); + const float omega = sqrt(m_omega); + + const float m_fetch = oc->_fetch_jonswap; + + /* Strictly, this should be a random value from a Gaussian (mean 3.3, variance 0.67), + * clamped 1.0 to 6.0. */ + float m_gamma = oc->_sharpen_peak_jonswap; + if (m_gamma < 1.0) { + m_gamma = 1.00; + } + if (m_gamma > 6.0) { + m_gamma = 6.0; + } + + const float m_windspeed = oc->_V; + + const float m_dimensionlessFetch = fabs(GRAVITY * m_fetch / sqrt(m_windspeed)); + const float m_alpha = 0.076 * pow(m_dimensionlessFetch, -0.22); + + const float m_tau = M_PI * 2; + const float m_peakomega = m_tau * 3.5 * fabs(GRAVITY / oc->_V) * + pow(m_dimensionlessFetch, -0.33); + + const float beta = 1.25f; + + float val = alpha_beta_spectrum(m_alpha, beta, GRAVITY, omega, m_peakomega); + + /* Peak sharpening */ + val *= peak_sharpen(m_omega, m_peakomega, m_gamma); + + return val; +} + +/** + * Pierson-Moskowitz model, 1964, assumes waves reach equilibrium with wind. + * Model is intended for large area 'fully developed' sea, where winds have been steadily blowing + * for days over an area that includes hundreds of wavelengths on a side. + */ +float BLI_ocean_spectrum_piersonmoskowitz(const Ocean *oc, const float kx, const float kz) +{ + const float k2 = kx * kx + kz * kz; + + if (k2 == 0.0f) { + /* No DC component. */ + return 0.0f; + } + + /* Get Pierson-Moskowitz value from #alpha_beta_spectrum. */ + const float peak_omega_PM = 0.87f * GRAVITY / oc->_V; + + const float k_mag = sqrt(k2); + const float m_omega = GRAVITY * k_mag * tanh(k_mag * oc->_depth); + + const float omega = sqrt(m_omega); + const float alpha = 0.0081f; + const float beta = 1.291f; + + float val = alpha_beta_spectrum(alpha, beta, GRAVITY, omega, peak_omega_PM); + + val = ocean_spectrum_wind_and_damp(oc, kx, kz, val); + + return val; +} + +/** + * TMA extends the JONSWAP spectrum. + * This spectral model is best suited to shallow water. + */ +float BLI_ocean_spectrum_texelmarsenarsloe(const Ocean *oc, const float kx, const float kz) +{ + const float k2 = kx * kx + kz * kz; + + if (k2 == 0.0f) { + /* No DC component. */ + return 0.0f; + } + + float val = jonswap(oc, k2); + + val = ocean_spectrum_wind_and_damp(oc, kx, kz, val); + + /* TMA modifications to JONSWAP. */ + const float m_depth = oc->_depth; + const float gain = sqrt(m_depth / GRAVITY); + + const float k_mag = sqrt(k2); + + const float m_omega = GRAVITY * k_mag * tanh(k_mag * oc->_depth); + const float omega = sqrt(m_omega); + + const float kitaigorodskiiDepth_wh = omega * gain; + const float kitaigorodskiiDepth = 0.5 + (0.5 * tanh(1.8 * (kitaigorodskiiDepth_wh - 1.125))); + + val *= kitaigorodskiiDepth; + + val = ocean_spectrum_wind_and_damp(oc, kx, kz, val); + + return val; +} + +/** + * Hasselmann et al, 1973. This model extends the Pierson-Moskowitz model with a peak sharpening + * function This enhancement is an artificial construct to address the problem that the wave + * spectrum is never fully developed. + * + * The fetch parameter represents the distance from a lee shore, + * called the fetch, or the distance over which the wind blows with constant velocity. + */ +float BLI_ocean_spectrum_jonswap(const Ocean *oc, const float kx, const float kz) +{ + const float k2 = kx * kx + kz * kz; + + if (k2 == 0.0f) { + /* No DC component. */ + return 0.0f; + } + + float val = jonswap(oc, k2); + + val = ocean_spectrum_wind_and_damp(oc, kx, kz, val); + + return val; +} + +/** \} */ + +#endif /* WITH_OCEANSIM */ diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 90a4a2dee23..b0163436cc4 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1953,8 +1953,8 @@ static bool foreach_object_ptcache( if (!foreach_object_modifier_ptcache(object, callback, callback_user_data)) { return false; } - /* Consider all object in dupli groups to be part of the same object, - * for baking with linking dupligroups. Once we have better overrides + /* Consider all object in dupli-groups to be part of the same object, + * for baking with linking dupli-groups. Once we have better overrides * this can be revisited so users select the local objects directly. */ if (scene != NULL && (duplis-- > 0) && (object->instance_collection != NULL)) { FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (object->instance_collection, current_object) { diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 37049014ef7..6ca14ec9197 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -395,9 +395,9 @@ static void scene_free_data(ID *id) scene->master_collection = NULL; } - if (scene->eevee.light_cache) { - EEVEE_lightcache_free(scene->eevee.light_cache); - scene->eevee.light_cache = NULL; + if (scene->eevee.light_cache_data) { + EEVEE_lightcache_free(scene->eevee.light_cache_data); + scene->eevee.light_cache_data = NULL; } if (scene->display.shading.prop) { @@ -583,7 +583,7 @@ void BKE_scene_copy_data_eevee(Scene *sce_dst, const Scene *sce_src) { /* Copy eevee data between scenes. */ sce_dst->eevee = sce_src->eevee; - sce_dst->eevee.light_cache = NULL; + sce_dst->eevee.light_cache_data = NULL; sce_dst->eevee.light_cache_info[0] = '\0'; /* TODO Copy the cache. */ } @@ -2057,6 +2057,14 @@ void BKE_scene_free_depsgraph_hash(Scene *scene) scene->depsgraph_hash = NULL; } +void BKE_scene_free_view_layer_depsgraph(Scene *scene, ViewLayer *view_layer) +{ + if (scene->depsgraph_hash != NULL) { + DepsgraphKey key = {view_layer}; + BLI_ghash_remove(scene->depsgraph_hash, &key, depsgraph_key_free, depsgraph_key_value_free); + } +} + /* Query depsgraph for a specific contexts. */ Depsgraph *BKE_scene_get_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, bool allocate) diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index f1243330567..a9bd1d17567 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -621,7 +621,7 @@ MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track) new_track->markers = MEM_dupallocN(new_track->markers); - /* Orevent duplicate from being used for 2D stabilization. + /* Prevent duplicate from being used for 2D stabilization. * If necessary, it shall be added explicitly. */ new_track->flag &= ~TRACK_USE_2D_STAB; diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c index ee9ea15835b..b532202ebaa 100644 --- a/source/blender/blenlib/intern/BLI_memblock.c +++ b/source/blender/blenlib/intern/BLI_memblock.c @@ -191,10 +191,14 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter) return ptr; } -/* Direct access. elem is element index inside the chosen chunk. */ +/* Direct access. elem is element index inside the chosen chunk. + * Double usage: You can set chunk to 0 and set the absolute elem index. + * The correct chunk will be retrieve. */ void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) { BLI_assert(chunk < mblk->chunk_len); - BLI_assert(elem < (mblk->chunk_size / mblk->elem_size)); + int elem_per_chunk = mblk->chunk_size / mblk->elem_size; + chunk += elem / elem_per_chunk; + elem = elem % elem_per_chunk; return (char *)(mblk->chunk_list[chunk]) + mblk->elem_size * elem; } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 7e17d1235fe..3059caf83f1 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -157,6 +157,8 @@ #include "RE_engine.h" +#include "engines/eevee/eevee_lightcache.h" + #include "readfile.h" #include <errno.h> @@ -1852,8 +1854,8 @@ void blo_make_scene_pointer_map(FileData *fd, Main *oldmain) fd->scenemap = oldnewmap_new(); for (; sce; sce = sce->id.next) { - if (sce->eevee.light_cache) { - struct LightCache *light_cache = sce->eevee.light_cache; + if (sce->eevee.light_cache_data) { + struct LightCache *light_cache = sce->eevee.light_cache_data; oldnewmap_insert(fd->scenemap, light_cache, light_cache, 0); } } @@ -1873,7 +1875,7 @@ void blo_end_scene_pointer_map(FileData *fd, Main *oldmain) } for (; sce; sce = sce->id.next) { - sce->eevee.light_cache = newsceadr(fd, sce->eevee.light_cache); + sce->eevee.light_cache_data = newsceadr(fd, sce->eevee.light_cache_data); } } @@ -5439,7 +5441,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb, Object *ob) mmd->domain->fluid = NULL; mmd->domain->fluid_mutex = BLI_rw_mutex_alloc(); - mmd->domain->tex = NULL; + mmd->domain->tex_density = NULL; + mmd->domain->tex_color = NULL; mmd->domain->tex_shadow = NULL; mmd->domain->tex_flame = NULL; mmd->domain->tex_flame_coba = NULL; @@ -6926,19 +6929,20 @@ static void direct_link_scene(FileData *fd, Scene *sce) 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); + sce->eevee.light_cache_data = newsceadr(fd, sce->eevee.light_cache_data); } else { - sce->eevee.light_cache = NULL; + sce->eevee.light_cache_data = NULL; } } else { /* else try to read the cache from file. */ - sce->eevee.light_cache = newdataadr(fd, sce->eevee.light_cache); - if (sce->eevee.light_cache) { - direct_link_lightcache(fd, sce->eevee.light_cache); + sce->eevee.light_cache_data = newdataadr(fd, sce->eevee.light_cache_data); + if (sce->eevee.light_cache_data) { + direct_link_lightcache(fd, sce->eevee.light_cache_data); } } + EEVEE_lightcache_info_update(&sce->eevee); direct_link_view3dshading(fd, &sce->display.shading); @@ -7791,7 +7795,7 @@ static int lib_link_main_data_restore_cb(LibraryIDLinkCallbackData *cb_data) { const int cb_flag = cb_data->cb_flag; ID **id_pointer = cb_data->id_pointer; - if (cb_flag & IDWALK_CB_PRIVATE || *id_pointer == NULL) { + if (cb_flag & IDWALK_CB_EMBEDDED || *id_pointer == NULL) { return IDWALK_RET_NOP; } @@ -7802,7 +7806,7 @@ static int lib_link_main_data_restore_cb(LibraryIDLinkCallbackData *cb_data) Collection *collection = (Collection *)*id_pointer; if (collection->flag & COLLECTION_IS_MASTER) { /* We should never reach that point anymore, since master collection private ID should be - * properly tagged with IDWALK_CB_PRIVATE. */ + * properly tagged with IDWALK_CB_EMBEDDED. */ BLI_assert(0); return IDWALK_RET_NOP; } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 34041b0ca22..0ce32d234a8 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -4091,7 +4091,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) FOREACH_MAIN_ID_BEGIN (bmain, id) { bNodeTree *ntree = ntreeFromID(id); if (ntree) { - ntree->id.flag |= LIB_PRIVATE_DATA; + ntree->id.flag |= LIB_EMBEDDED_DATA; } } FOREACH_MAIN_ID_END; @@ -4108,7 +4108,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) /* Older files do not have a master collection, which is then added through * `BKE_collection_master_add()`, so everything is fine. */ if (scene->master_collection != NULL) { - scene->master_collection->id.flag |= LIB_PRIVATE_DATA; + scene->master_collection->id.flag |= LIB_EMBEDDED_DATA; } } } @@ -4851,6 +4851,18 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) */ { /* Keep this block, even when empty. */ + + if (!DNA_struct_elem_find(fd->filesdna, "OceanModifierData", "float", "fetch_jonswap")) { + for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) { + for (ModifierData *md = object->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Ocean) { + OceanModifierData *omd = (OceanModifierData *)md; + omd->fetch_jonswap = 120.0f; + } + } + } + } + if (!DNA_struct_find(fd->filesdna, "XrSessionSettings")) { for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) { const View3D *v3d_default = DNA_struct_default_get(View3D); diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 81df00ebdef..a9c5008062b 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2767,9 +2767,9 @@ static void write_scene(WriteData *wd, Scene *sce) } /* 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); + if (sce->eevee.light_cache_data && !wd->use_memfile) { + writestruct(wd, DATA, LightCache, 1, sce->eevee.light_cache_data); + write_lightcache(wd, sce->eevee.light_cache_data); } write_view3dshading(wd, &sce->display.shading); diff --git a/source/blender/blentranslation/msgfmt/CMakeLists.txt b/source/blender/blentranslation/msgfmt/CMakeLists.txt index 147c375aa6e..350473fa195 100644 --- a/source/blender/blentranslation/msgfmt/CMakeLists.txt +++ b/source/blender/blentranslation/msgfmt/CMakeLists.txt @@ -37,6 +37,10 @@ if(APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}") endif() +if(WIN32) + set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /nodefaultlib:MSVCRT.lib") +endif() + add_executable(msgfmt ${SRC}) target_link_libraries(msgfmt bf_blenlib) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 01d84f6b5d8..c512300200e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -319,6 +319,18 @@ void DepsgraphNodeBuilder::begin_build() * them for new ID nodes. */ id_info_hash_ = BLI_ghash_ptr_new("Depsgraph id hash"); for (IDNode *id_node : graph_->id_nodes) { + /* It is possible that the ID does not need to have CoW version in which case id_cow is the + * same as id_orig. Additionally, such ID might have been removed, which makes the check + * for whether id_cow is expanded to access freed memory. In orderr to deal with this we + * check whether CoW is needed based on a scalar value which does not lead to access of + * possibly deleted memory. + * Additionally, this saves some space in the map by skipping mapping for datablocks which + * do not need CoW, */ + if (!deg_copy_on_write_is_needed(id_node->id_type)) { + id_node->id_cow = nullptr; + continue; + } + IDInfo *id_info = (IDInfo *)MEM_mallocN(sizeof(IDInfo), "depsgraph id info"); if (deg_copy_on_write_is_expanded(id_node->id_cow) && id_node->id_orig != id_node->id_cow) { id_info->id_cow = id_node->id_cow; diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index df61a1416bd..1296c87bbb0 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -37,6 +37,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_node_types.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -343,11 +344,13 @@ void depsgraph_ensure_view_layer(Depsgraph *graph) * - It was tagged for update of CoW component. * This allows us to have proper view layer pointer. */ Scene *scene_cow = graph->scene_cow; - if (!deg_copy_on_write_is_expanded(&scene_cow->id) || - scene_cow->id.recalc & ID_RECALC_COPY_ON_WRITE) { - const IDNode *id_node = graph->find_id_node(&graph->scene->id); - deg_update_copy_on_write_datablock(graph, id_node); + if (deg_copy_on_write_is_expanded(&scene_cow->id) && + (scene_cow->id.recalc & ID_RECALC_COPY_ON_WRITE) == 0) { + return; } + + const IDNode *scene_id_node = graph->find_id_node(&graph->scene->id); + deg_update_copy_on_write_datablock(graph, scene_id_node); } } // namespace 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 1841f5f024f..d8ce590c611 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 @@ -804,7 +804,7 @@ void update_id_after_copy(const Depsgraph *depsgraph, Scene *scene_cow = (Scene *)id_cow; const Scene *scene_orig = (const Scene *)id_orig; scene_cow->toolsettings = scene_orig->toolsettings; - scene_cow->eevee.light_cache = scene_orig->eevee.light_cache; + scene_cow->eevee.light_cache_data = scene_orig->eevee.light_cache_data; scene_setup_view_layers_after_remap(depsgraph, id_node, reinterpret_cast<Scene *>(id_cow)); update_scene_orig_pointers(scene_orig, scene_cow); break; @@ -914,8 +914,11 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, user_data.depsgraph = depsgraph; user_data.node_builder = node_builder; user_data.create_placeholders = create_placeholders; - BKE_library_foreach_ID_link( - nullptr, id_cow, foreach_libblock_remap_callback, (void *)&user_data, IDWALK_NOP); + BKE_library_foreach_ID_link(nullptr, + id_cow, + foreach_libblock_remap_callback, + (void *)&user_data, + IDWALK_IGNORE_EMBEDDED_ID); /* Correct or tweak some pointers which are not taken care by foreach * from above. */ update_id_after_copy(depsgraph, id_node, id_orig, id_cow); @@ -1000,7 +1003,7 @@ void discard_scene_pointers(ID *id_cow) { Scene *scene_cow = (Scene *)id_cow; scene_cow->toolsettings = nullptr; - scene_cow->eevee.light_cache = nullptr; + scene_cow->eevee.light_cache_data = nullptr; } /* nullptr-ify all edit mode pointers which points to data from @@ -1113,6 +1116,11 @@ bool deg_copy_on_write_is_expanded(const ID *id_cow) bool deg_copy_on_write_is_needed(const ID *id_orig) { const ID_Type id_type = GS(id_orig->name); + return deg_copy_on_write_is_needed(id_type); +} + +bool deg_copy_on_write_is_needed(const ID_Type id_type) +{ return ID_TYPE_IS_COW(id_type); } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h index 1992c80e036..05464d11f13 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h @@ -25,6 +25,8 @@ #include <stddef.h> +#include "DNA_ID.h" + struct ID; /* Uncomment this to have verbose log about original and CoW pointers @@ -94,5 +96,6 @@ bool deg_copy_on_write_is_expanded(const struct ID *id_cow); * This includes images. */ bool deg_copy_on_write_is_needed(const ID *id_orig); +bool deg_copy_on_write_is_needed(const ID_Type id_type); } // namespace DEG diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc index 0fbf658ceb3..cd25cc14069 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.cc +++ b/source/blender/depsgraph/intern/node/deg_node_id.cc @@ -103,6 +103,7 @@ void IDNode::init(const ID *id, const char *UNUSED(subdata)) { BLI_assert(id != nullptr); /* Store ID-pointer. */ + id_type = GS(id->name); id_orig = (ID *)id; eval_flags = 0; previous_eval_flags = 0; diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h index 886c25b5a4e..6eea31ebff9 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.h +++ b/source/blender/depsgraph/intern/node/deg_node_id.h @@ -25,6 +25,7 @@ #include "intern/node/deg_node.h" #include "BLI_sys_types.h" +#include "DNA_ID.h" struct GHash; @@ -73,6 +74,10 @@ struct IDNode : public Node { IDComponentsMask get_visible_components_mask() const; /* ID Block referenced. */ + /* Type of the ID stored separately, so it's possible to perform check whether CoW is needed + * without de-referencing the id_cow (which is not safe when ID is NOT covered by CoW and has + * been deleted from the main database.) */ + ID_Type id_type; ID *id_orig; ID *id_cow; diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 1f04739644e..a1213be4be0 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -97,19 +97,18 @@ set(SRC engines/eevee/eevee_subsurface.c engines/eevee/eevee_temporal_sampling.c engines/eevee/eevee_volumes.c - engines/workbench/solid_mode.c - engines/workbench/transparent_mode.c engines/workbench/workbench_data.c - engines/workbench/workbench_deferred.c - engines/workbench/workbench_effect_aa.c + engines/workbench/workbench_effect_antialiasing.c + engines/workbench/workbench_effect_cavity.c engines/workbench/workbench_effect_dof.c - engines/workbench/workbench_effect_fxaa.c - engines/workbench/workbench_effect_taa.c + engines/workbench/workbench_effect_outline.c engines/workbench/workbench_engine.c - engines/workbench/workbench_forward.c engines/workbench/workbench_materials.c + engines/workbench/workbench_opaque.c engines/workbench/workbench_render.c - engines/workbench/workbench_studiolight.c + engines/workbench/workbench_shader.c + engines/workbench/workbench_shadow.c + engines/workbench/workbench_transparent.c engines/workbench/workbench_volume.c engines/external/external_engine.c engines/gpencil/gpencil_antialiasing.c @@ -231,6 +230,7 @@ data_to_c_simple(engines/eevee/shaders/btdf_lut_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/bsdf_common_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/irradiance_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/octahedron_lib.glsl SRC) +data_to_c_simple(engines/eevee/shaders/cubemap_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_frag.glsl SRC) @@ -247,28 +247,32 @@ data_to_c_simple(engines/eevee/shaders/volumetric_scatter_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/volumetric_integration_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_cavity_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_cavity_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_composite_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_deferred_composite_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_deferred_background_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_effect_cavity_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_effect_dof_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_effect_fxaa_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_effect_outline_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_vert.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_forward_composite_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_forward_depth_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_ghost_resolve_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_object_outline_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_image_lib.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_matcap_lib.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_material_lib.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_merge_infront_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_prepass_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_prepass_hair_vert.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_shader_interface_lib.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_shadow_caps_geom.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_shadow_debug_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_transparent_accum_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_transparent_resolve_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC) data_to_c_simple(intern/shaders/common_colormanagement_lib.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 2b11a608bd0..35a45cc97f4 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -42,6 +42,7 @@ #include "eevee_private.h" #include "GPU_context.h" +#include "GPU_extensions.h" #include "WM_api.h" #include "WM_types.h" @@ -195,6 +196,16 @@ static uint eevee_lightcache_memsize_get(LightCache *lcache) return size; } +static bool eevee_lightcache_version_check(LightCache *lcache) +{ + switch (lcache->type) { + case LIGHTCACHE_TYPE_STATIC: + return lcache->version == LIGHTCACHE_STATIC_VERSION; + default: + return false; + } +} + static int eevee_lightcache_irradiance_sample_count(LightCache *lcache) { int total_irr_samples = 0; @@ -208,9 +219,23 @@ static int eevee_lightcache_irradiance_sample_count(LightCache *lcache) void EEVEE_lightcache_info_update(SceneEEVEE *eevee) { - LightCache *lcache = eevee->light_cache; + LightCache *lcache = eevee->light_cache_data; if (lcache != NULL) { + if (!eevee_lightcache_version_check(lcache)) { + BLI_strncpy(eevee->light_cache_info, + TIP_("Incompatible Light cache version, please bake again"), + sizeof(eevee->light_cache_info)); + return; + } + + if (lcache->cube_tx.tex_size[2] > GPU_max_texture_layers()) { + BLI_strncpy(eevee->light_cache_info, + TIP_("Error: Light cache is too big for your GPU to be loaded"), + sizeof(eevee->light_cache_info)); + return; + } + if (lcache->flag & LIGHTCACHE_BAKING) { BLI_strncpy( eevee->light_cache_info, TIP_("Baking light cache"), sizeof(eevee->light_cache_info)); @@ -266,8 +291,8 @@ static bool EEVEE_lightcache_validate(const LightCache *light_cache, (irr_size[2] == light_cache->grid_tx.tex_size[2]) && (grid_len == light_cache->grid_len)) { int mip_len = log2_floor_u(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]) && (cube_len == light_cache->cube_len) && - (mip_len == light_cache->mips_len)) { + (cube_len == light_cache->cube_tx.tex_size[2] / 6) && + (cube_len == light_cache->cube_len) && (mip_len == light_cache->mips_len)) { return true; } } @@ -283,6 +308,9 @@ LightCache *EEVEE_lightcache_create(const int grid_len, { LightCache *light_cache = MEM_callocN(sizeof(LightCache), "LightCache"); + light_cache->version = LIGHTCACHE_STATIC_VERSION; + light_cache->type = LIGHTCACHE_TYPE_STATIC; + 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"); @@ -292,13 +320,26 @@ LightCache *EEVEE_lightcache_create(const int grid_len, 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); + int mips_len = log2_floor_u(cube_size) - MIN_CUBE_LOD_LEVEL; + + if (GPU_arb_texture_cube_map_array_is_supported()) { + light_cache->cube_tx.tex = DRW_texture_create_cube_array( + cube_size, cube_len, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); + } + else { + light_cache->cube_tx.tex = DRW_texture_create_2d_array(cube_size, + cube_size, + cube_len * 6, + 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->cube_tx.tex_size[2] = cube_len * 6; - light_cache->mips_len = log2_floor_u(cube_size) - MIN_CUBE_LOD_LEVEL; + light_cache->mips_len = mips_len; light_cache->vis_res = vis_size; light_cache->ref_res = cube_size; @@ -315,9 +356,19 @@ LightCache *EEVEE_lightcache_create(const int grid_len, return light_cache; } -void EEVEE_lightcache_load(LightCache *lcache) +static bool eevee_lightcache_static_load(LightCache *lcache) { - if (lcache->grid_tx.tex == NULL && lcache->grid_tx.data) { + /* We use fallback if a texture is not setup and there is no data to restore it. */ + if ((!lcache->grid_tx.tex && !lcache->grid_tx.data) || + (!lcache->cube_tx.tex && !lcache->cube_tx.data)) { + return false; + } + /* If cache is too big for this GPU. */ + if (lcache->cube_tx.tex_size[2] > GPU_max_texture_layers()) { + return false; + } + + if (lcache->grid_tx.tex == NULL) { 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], @@ -333,17 +384,28 @@ void EEVEE_lightcache_load(LightCache *lcache) 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); + if (lcache->cube_tx.tex == NULL) { + if (GPU_arb_texture_cube_map_array_is_supported()) { + lcache->cube_tx.tex = GPU_texture_cube_create(lcache->cube_tx.tex_size[0], + lcache->cube_tx.tex_size[2] / 6, + lcache->cube_tx.data, + GPU_R11F_G11F_B10F, + GPU_DATA_10_11_11_REV, + NULL); + } + else { + 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++) { @@ -352,6 +414,25 @@ void EEVEE_lightcache_load(LightCache *lcache) } GPU_texture_unbind(lcache->cube_tx.tex); } + return true; +} + +bool EEVEE_lightcache_load(LightCache *lcache) +{ + if (lcache == NULL) { + return false; + } + + if (!eevee_lightcache_version_check(lcache)) { + return false; + } + + switch (lcache->type) { + case LIGHTCACHE_TYPE_STATIC: + return eevee_lightcache_static_load(lcache); + default: + return false; + } } static void eevee_lightbake_readback_irradiance(LightCache *lcache) @@ -457,7 +538,7 @@ static void eevee_lightbake_count_probes(EEVEE_LightBake *lbake) prb->grid_resolution_z; lbake->grid_len++; } - else if (prb->type == LIGHTPROBE_TYPE_CUBE) { + else if (prb->type == LIGHTPROBE_TYPE_CUBE && lbake->cube_len < EEVEE_PROBE_MAX) { lbake->cube_len++; } } @@ -491,8 +572,7 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake) 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->ref_cube_res = 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"); @@ -506,12 +586,12 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake) /* 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; + lbake->lcache = eevee->light_cache_data; /* TODO validate irradiance and reflection cache independently... */ if (!EEVEE_lightcache_validate( lbake->lcache, lbake->cube_len, lbake->ref_cube_res, lbake->grid_len, lbake->irr_size)) { - eevee->light_cache = lbake->lcache = NULL; + eevee->light_cache_data = lbake->lcache = NULL; } if (lbake->lcache == NULL) { @@ -522,10 +602,10 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake) lbake->lcache->vis_res = lbake->vis_res; lbake->own_light_cache = true; - eevee->light_cache = lbake->lcache; + eevee->light_cache_data = lbake->lcache; } - EEVEE_lightcache_load(eevee->light_cache); + EEVEE_lightcache_load(eevee->light_cache_data); lbake->lcache->flag |= LIGHTCACHE_BAKING; lbake->lcache->cube_len = 1; @@ -804,7 +884,7 @@ static void eevee_lightbake_render_world_sample(void *ved, void *user_data) 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; + LightCache *lcache = scene_eval->eevee.light_cache_data; float clamp = scene_eval->eevee.gi_glossy_clamp; float filter_quality = scene_eval->eevee.gi_filter_quality; @@ -920,7 +1000,7 @@ static void eevee_lightbake_render_grid_sample(void *ved, void *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; + LightCache *lcache = scene_eval->eevee.light_cache_data; int grid_loc[3], sample_id, sample_offset, stride; float pos[3]; const bool is_last_bounce_sample = ((egrid->offset + lbake->grid_sample) == @@ -1002,7 +1082,7 @@ static void eevee_lightbake_render_probe_sample(void *ved, void *user_data) 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; + LightCache *lcache = scene_eval->eevee.light_cache_data; EEVEE_LightProbe *eprobe = lbake->cube; LightProbe *prb = *lbake->probe; float clamp = scene_eval->eevee.gi_glossy_clamp; @@ -1083,7 +1163,7 @@ 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; + LightCache *lcache = scene_eval->eevee.light_cache_data; /* At least one for the world */ int grid_len = 1; @@ -1106,7 +1186,7 @@ static void eevee_lightbake_gather_probes(EEVEE_LightBake *lbake) 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) { + else if (prb->type == LIGHTPROBE_TYPE_CUBE && cube_len < EEVEE_PROBE_MAX) { lbake->cube_prb[cube_len] = prb; EEVEE_LightProbe *eprobe = &lcache->cube_data[cube_len++]; EEVEE_lightprobes_cube_data_from_object(ob, eprobe); @@ -1136,11 +1216,11 @@ void EEVEE_lightbake_update(void *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); + if (lbake->lcache && scene_orig->eevee.light_cache_data != lbake->lcache) { + if (scene_orig->eevee.light_cache_data != NULL) { + EEVEE_lightcache_free(scene_orig->eevee.light_cache_data); } - scene_orig->eevee.light_cache = lbake->lcache; + scene_orig->eevee.light_cache_data = lbake->lcache; lbake->own_light_cache = false; } @@ -1182,6 +1262,12 @@ void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float lbake->do_update = do_update; lbake->progress = progress; + if (G.background) { + /* Make sure to init GL capabilities before counting probes. */ + eevee_lightbake_context_enable(lbake); + eevee_lightbake_context_disable(lbake); + } + /* Count lightprobes */ eevee_lightbake_count_probes(lbake); diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h index ede2de13dce..0db36ce0c2e 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.h +++ b/source/blender/draw/engines/eevee/eevee_lightcache.h @@ -60,7 +60,7 @@ struct LightCache *EEVEE_lightcache_create(const int grid_len, const int vis_size, const int irr_size[3]); void EEVEE_lightcache_free(struct LightCache *lcache); -void EEVEE_lightcache_load(struct LightCache *lcache); +bool EEVEE_lightcache_load(struct LightCache *lcache); void EEVEE_lightcache_info_update(struct SceneEEVEE *eevee); #endif /* __EEVEE_LIGHTCACHE_H__ */ diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 4fbecfe3120..61ca2317572 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -37,6 +37,7 @@ #include "GPU_material.h" #include "GPU_texture.h" +#include "GPU_extensions.h" #include "DEG_depsgraph_query.h" @@ -171,32 +172,28 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) memset(stl->g_data->world_views, 0, sizeof(stl->g_data->world_views)); memset(stl->g_data->planar_views, 0, sizeof(stl->g_data->planar_views)); - /* Use fallback if we don't have gpu texture allocated an we cannot restore them. */ - bool use_fallback_lightcache = (scene_eval->eevee.light_cache == NULL) || - ((scene_eval->eevee.light_cache->grid_tx.tex == NULL) && - (scene_eval->eevee.light_cache->grid_tx.data == NULL)) || - ((scene_eval->eevee.light_cache->cube_tx.tex == NULL) && - (scene_eval->eevee.light_cache->cube_tx.data == NULL)); - - if (use_fallback_lightcache && (sldata->fallback_lightcache == NULL)) { + if (EEVEE_lightcache_load(scene_eval->eevee.light_cache_data)) { + stl->g_data->light_cache = scene_eval->eevee.light_cache_data; + } + else { + if (!sldata->fallback_lightcache) { #if defined(IRRADIANCE_SH_L2) - int grid_res = 4; + int grid_res = 4; #elif defined(IRRADIANCE_CUBEMAP) - int grid_res = 8; + int grid_res = 8; #elif defined(IRRADIANCE_HL2) - int grid_res = 4; + 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}); + sldata->fallback_lightcache = EEVEE_lightcache_create( + 1, + 1, + scene_eval->eevee.gi_cubemap_resolution, + scene_eval->eevee.gi_visibility_resolution, + (int[3]){grid_res, grid_res, 1}); + } + stl->g_data->light_cache = sldata->fallback_lightcache; } - stl->g_data->light_cache = (use_fallback_lightcache) ? sldata->fallback_lightcache : - scene_eval->eevee.light_cache; - - EEVEE_lightcache_load(stl->g_data->light_cache); - if (!sldata->probes) { sldata->probes = MEM_callocN(sizeof(EEVEE_LightProbesInfo), "EEVEE_LightProbesInfo"); sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL); @@ -255,7 +252,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call(grp, geom, NULL); + DRW_shgroup_call_instances(grp, NULL, geom, 6); } { @@ -508,8 +505,8 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata 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) || + if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= EEVEE_PROBE_MAX) || + (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= EEVEE_PROBE_MAX) || (probe->type == LIGHTPROBE_TYPE_PLANAR && pinfo->num_planar >= MAX_PLANAR)) { printf("Too many probes in the view !!!\n"); return; @@ -762,7 +759,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); /* 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_cube_max = (float)light_cache->mips_len; 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_irradiance_smooth = square_f(scene_eval->eevee.gi_irradiance_smoothing); @@ -785,15 +782,15 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved 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 (scene_orig->eevee.light_cache_data != NULL) { if (pinfo->do_grid_update) { - scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_GRID; + scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_GRID; } - /* If we update grid we need to update the cube-maps too. - * So always refresh cube-maps. */ - scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_CUBE; - /* Tag the light-cache to auto update. */ - scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_AUTO; + /* If we update grid we need to update the cubemaps too. + * So always refresh cubemaps. */ + scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_CUBE; + /* Tag the lightcache to auto update. */ + scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_AUTO; /* Use a notifier to trigger the operator after drawing. */ WM_event_add_notifier(draw_ctx->evil_C, NC_LIGHTPROBE, scene_orig); } @@ -1077,7 +1074,7 @@ void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata, pinfo->texel_size = 1.0f / (float)mipsize; pinfo->padding_size = (i == maxlevel) ? 0 : (float)(1 << (maxlevel - i - 1)); pinfo->padding_size *= pinfo->texel_size; - pinfo->layer = probe_idx; + pinfo->layer = probe_idx * 6; pinfo->roughness = i / (float)maxlevel; pinfo->roughness *= pinfo->roughness; /* Disney Roughness */ pinfo->roughness *= pinfo->roughness; /* Distribute Roughness accros lod more evenly */ diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c index 7be6fc2d030..a725a3583f3 100644 --- a/source/blender/draw/engines/eevee/eevee_lookdev.c +++ b/source/blender/draw/engines/eevee/eevee_lookdev.c @@ -76,7 +76,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, effects->lookdev_view = NULL; - if (LOOK_DEV_OVERLAY_ENABLED(v3d)) { + if (eevee_hdri_preview_overlay_enabled(v3d)) { /* Viewport / Spheres size. */ const rcti *rect; rcti fallback_rect; @@ -116,7 +116,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, EEVEE_shaders_background_studiolight_sh_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - int cube_res = octahedral_size_from_cubesize(scene_eval->eevee.gi_cubemap_resolution); + int cube_res = scene_eval->eevee.gi_cubemap_resolution; /* If one of the component is missing we start from scratch. */ if ((stl->lookdev_grid_data == NULL) || (stl->lookdev_cube_data == NULL) || @@ -228,7 +228,7 @@ void EEVEE_lookdev_draw(EEVEE_Data *vedata) const DRWContextState *draw_ctx = DRW_context_state_get(); - if (psl->lookdev_diffuse_pass && LOOK_DEV_OVERLAY_ENABLED(draw_ctx->v3d)) { + if (psl->lookdev_diffuse_pass && eevee_hdri_preview_overlay_enabled(draw_ctx->v3d)) { /* Config renderer. */ EEVEE_CommonUniformBuffer *common = &sldata->common_data; common->la_num_light = 0; diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index a37c063adf6..230a0725493 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -89,6 +89,7 @@ extern char datatoc_common_hair_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_lit_surface_frag_glsl[]; extern char datatoc_lit_surface_vert_glsl[]; extern char datatoc_raytrace_lib_glsl[]; @@ -618,6 +619,7 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, datatoc_raytrace_lib_glsl, datatoc_ssr_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_ltc_lib_glsl, @@ -641,6 +643,7 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, datatoc_bsdf_common_lib_glsl, datatoc_ambient_occlusion_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_ltc_lib_glsl, @@ -776,6 +779,7 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, Wor wo, engine, options, + false, e_data.vert_background_shader_str, NULL, e_data.frag_shader_lib, @@ -796,6 +800,7 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor wo, engine, options, + false, e_data.vert_background_shader_str, NULL, e_data.frag_shader_lib, @@ -819,6 +824,7 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World * wo, engine, options, + true, e_data.vert_volume_shader_str, e_data.geom_volume_shader_str, e_data.volume_shader_lib, @@ -853,6 +859,7 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, ma, engine, options, + false, e_data.vert_shader_str, NULL, e_data.frag_shader_lib, @@ -880,6 +887,7 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material ma, engine, options, + true, e_data.vert_volume_shader_str, e_data.geom_volume_shader_str, e_data.volume_shader_lib, @@ -916,6 +924,7 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, ma, engine, options, + false, (is_shadow) ? e_data.vert_shadow_shader_str : e_data.vert_shader_str, NULL, @@ -945,6 +954,7 @@ struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma) ma, engine, options, + false, e_data.vert_shader_str, NULL, e_data.frag_shader_lib, @@ -1256,7 +1266,7 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } - if (LOOK_DEV_OVERLAY_ENABLED(draw_ctx->v3d)) { + if (eevee_hdri_preview_overlay_enabled(draw_ctx->v3d)) { DRWShadingGroup *shgrp; struct GPUBatch *sphere = DRW_cache_sphere_get(); @@ -1919,7 +1929,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, * to know if the material has a "volume nodetree". */ bool use_volume_material = (gpumat_array[0] && - GPU_material_use_domain_volume(gpumat_array[0])); + GPU_material_has_volume_output(gpumat_array[0])); if ((ob->dt >= OB_SOLID) || DRW_state_is_image_render()) { /* Get per-material split surface */ @@ -1968,7 +1978,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, /* Do not render surface if we are rendering a volume object * and do not have a surface closure. */ if (use_volume_material && - (gpumat_array[i] && !GPU_material_use_domain_surface(gpumat_array[i]))) { + (gpumat_array[i] && !GPU_material_has_surface_output(gpumat_array[i]))) { continue; } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 5ffea393e1f..0f084ba306b 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -78,6 +78,8 @@ extern struct DrawEngineType draw_engine_eevee_type; SHADER_IRRADIANCE /* clang-format on */ +#define EEVEE_PROBE_MAX min_ii(MAX_PROBE, GPU_max_texture_layers() / 6) + #define SWAP_DOUBLE_BUFFERS() \ { \ if (effects->swap_double_buffer) { \ @@ -123,9 +125,21 @@ extern struct DrawEngineType draw_engine_eevee_type; } \ ((void)0) -#define LOOK_DEV_OVERLAY_ENABLED(v3d) \ - ((v3d) && (v3d->shading.type == OB_MATERIAL) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && \ - (v3d->overlay.flag & V3D_OVERLAY_LOOK_DEV)) +BLI_INLINE bool eevee_hdri_preview_overlay_enabled(View3D *v3d) +{ + /* Only show the HDRI Preview in Shading Preview in the Viewport. */ + if (v3d == NULL || v3d->shading.type != OB_MATERIAL) { + return false; + } + + /* Only show the HDRI Preview when viewing the Combined render pass */ + if (v3d->shading.render_pass != SCE_PASS_COMBINED) { + return false; + } + + return ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->overlay.flag & V3D_OVERLAY_LOOK_DEV); +} + #define USE_SCENE_LIGHT(v3d) \ ((!v3d) || \ ((v3d->shading.type == OB_MATERIAL) && (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS)) || \ @@ -137,19 +151,6 @@ extern struct DrawEngineType draw_engine_eevee_type; ((v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER) == 0)))) #define MIN_CUBE_LOD_LEVEL 3 - -BLI_INLINE int octahedral_size_from_cubesize(int cube_size) -{ - int cube_pixel_count = square_i(cube_size) * 6; - int octa_size = (int)ceilf(sqrtf(cube_pixel_count)); - int lod_count = log2_floor_u(octa_size) - MIN_CUBE_LOD_LEVEL; - /* Find lowest lod size and grow back to avoid having non matching mipsizes that would - * break trilinear interpolation. */ - octa_size /= 1 << lod_count; - octa_size *= 1 << lod_count; - return octa_size; -} - #define MAX_PLANAR_LOD_LEVEL 9 /* All the renderpasses that use the GPUMaterial for accumulation */ diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index d231edf1383..e875187bdbf 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -54,6 +54,7 @@ extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_effect_ssr_frag_glsl[]; extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_raytrace_lib_glsl[]; @@ -67,6 +68,7 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options) datatoc_bsdf_sampling_lib_glsl, datatoc_ambient_occlusion_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_raytrace_lib_glsl, datatoc_effect_ssr_frag_glsl); diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index 2d91e4bb4bd..50b7c5c5f97 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -88,6 +88,7 @@ extern char datatoc_lightprobe_planar_downsample_vert_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; /* Velocity Resolve */ extern char datatoc_effect_velocity_resolve_frag_glsl[]; @@ -196,6 +197,7 @@ GPUShader *EEVEE_shaders_background_studiolight_sh_get(void) { if (e_data.probe_background_studiolight_sh == NULL) { char *frag_str = BLI_string_joinN(datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_lightprobe_lib_glsl, @@ -217,6 +219,7 @@ GPUShader *EEVEE_shaders_probe_cube_display_sh_get(void) { if (e_data.probe_cube_display_sh == NULL) { char *shader_str = BLI_string_joinN(datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, @@ -238,6 +241,7 @@ GPUShader *EEVEE_shaders_probe_grid_display_sh_get(void) { if (e_data.probe_grid_display_sh == NULL) { char *shader_str = BLI_string_joinN(datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 98e799acb5e..bab89a8a87b 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -41,6 +41,7 @@ extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_lights_lib_glsl[]; extern char datatoc_raytrace_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_effect_subsurface_frag_glsl[]; @@ -59,6 +60,7 @@ static void eevee_create_shader_subsurface(void) datatoc_bsdf_sampling_lib_glsl, datatoc_raytrace_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_lights_lib_glsl, datatoc_effect_translucency_frag_glsl); diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index d11e93bbc3f..8c1c72a3c20 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -72,6 +72,7 @@ extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lights_lib_glsl[]; extern char datatoc_volumetric_accum_frag_glsl[]; @@ -99,6 +100,7 @@ static void eevee_create_shader_volumes(void) datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lights_lib_glsl, datatoc_volumetric_lib_glsl); @@ -141,10 +143,10 @@ static void eevee_create_shader_volumes(void) e_data.volumetric_accum_sh = DRW_shader_create_fullscreen(datatoc_volumetric_accum_frag_glsl, NULL); - float color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - e_data.dummy_density = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, color); + const float density[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + e_data.dummy_density = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, density); - float flame = 0.0f; + const float flame = 0.0f; e_data.dummy_flame = DRW_texture_create_3d(1, 1, 1, GPU_R8, DRW_TEX_WRAP, &flame); } @@ -351,7 +353,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) !LOOK_DEV_STUDIO_LIGHT_ENABLED(draw_ctx->v3d)) { struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo); - if (GPU_material_use_domain_volume(mat)) { + if (GPU_material_has_volume_output(mat)) { grp = DRW_shgroup_material_create(mat, psl->volumetric_world_ps); } @@ -367,9 +369,11 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); /* Fix principle volumetric not working with world materials. */ - DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density); - DRW_shgroup_uniform_texture(grp, "sampflame", e_data.dummy_flame); - DRW_shgroup_uniform_vec2_copy(grp, "unftemperature", (float[2]){0.0f, 1.0f}); + ListBase gpu_grids = GPU_material_volume_grids(mat); + for (GPUMaterialVolumeGrid *gpu_grid = gpu_grids.first; gpu_grid; + gpu_grid = gpu_grid->next) { + DRW_shgroup_uniform_texture(grp, gpu_grid->sampler_name, e_data.dummy_density); + } DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]); @@ -445,6 +449,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1); DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1); + ListBase gpu_grids = GPU_material_volume_grids(mat); /* Smoke Simulation */ if (((ob->base_flag & BASE_FROM_DUPLI) == 0) && (md = modifiers_findByType(ob, eModifierType_Fluid)) && @@ -476,10 +481,25 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(mmd)); } - DRW_shgroup_uniform_texture_ref( - grp, "sampdensity", mds->tex ? &mds->tex : &e_data.dummy_density); - DRW_shgroup_uniform_texture_ref( - grp, "sampflame", mds->tex_flame ? &mds->tex_flame : &e_data.dummy_flame); + for (GPUMaterialVolumeGrid *gpu_grid = gpu_grids.first; gpu_grid; gpu_grid = gpu_grid->next) { + if (STREQ(gpu_grid->name, "density")) { + DRW_shgroup_uniform_texture_ref(grp, + gpu_grid->sampler_name, + mds->tex_density ? &mds->tex_density : + &e_data.dummy_density); + } + else if (STREQ(gpu_grid->name, "color")) { + DRW_shgroup_uniform_texture_ref( + grp, gpu_grid->sampler_name, mds->tex_color ? &mds->tex_color : &e_data.dummy_density); + } + else if (STREQ(gpu_grid->name, "flame") || STREQ(gpu_grid->name, "temperature")) { + DRW_shgroup_uniform_texture_ref( + grp, gpu_grid->sampler_name, mds->tex_flame ? &mds->tex_flame : &e_data.dummy_flame); + } + else { + DRW_shgroup_uniform_texture_ref(grp, gpu_grid->sampler_name, &e_data.dummy_density); + } + } /* Constant Volume color. */ bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 && @@ -489,13 +509,13 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, grp, "volumeColor", (use_constant_color) ? mds->active_color : white, 1); /* Output is such that 0..1 maps to 0..1000K */ - DRW_shgroup_uniform_vec2(grp, "unftemperature", &mds->flame_ignition, 1); + DRW_shgroup_uniform_vec2(grp, "volumeTemperature", &mds->flame_ignition, 1); } else { - DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density); - DRW_shgroup_uniform_texture(grp, "sampflame", e_data.dummy_flame); + for (GPUMaterialVolumeGrid *gpu_grid = gpu_grids.first; gpu_grid; gpu_grid = gpu_grid->next) { + DRW_shgroup_uniform_texture(grp, gpu_grid->sampler_name, e_data.dummy_density); + } DRW_shgroup_uniform_vec3(grp, "volumeColor", white, 1); - DRW_shgroup_uniform_vec2(grp, "unftemperature", (float[2]){0.0f, 1.0f}, 1); } /* TODO Reduce to number of slices intersecting. */ diff --git a/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl new file mode 100644 index 00000000000..90272400915 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl @@ -0,0 +1,130 @@ + +#ifdef GPU_ARB_texture_cube_map_array + +# define textureLod_cubemapArray(tex, co, lod) textureLod(tex, co, lod) + +#else + +/* Fallback implementation for hardware not supporting cubemap arrays. */ +# define samplerCubeArray sampler2DArray + +float cubemap_face_index(vec3 P) +{ + vec3 aP = abs(P); + if (all(greaterThan(aP.xx, aP.yz))) { + return (P.x > 0.0) ? 0.0 : 1.0; + } + else if (all(greaterThan(aP.yy, aP.xz))) { + return (P.y > 0.0) ? 2.0 : 3.0; + } + else { + return (P.z > 0.0) ? 4.0 : 5.0; + } +} + +vec2 cubemap_face_coord(vec3 P, float face) +{ + if (face < 2.0) { + return (P.zy / P.x) * vec2(-0.5, -sign(P.x) * 0.5) + 0.5; + } + else if (face < 4.0) { + return (P.xz / P.y) * vec2(sign(P.y) * 0.5, 0.5) + 0.5; + } + else { + return (P.xy / P.z) * vec2(0.5, -sign(P.z) * 0.5) + 0.5; + } +} + +vec3 cubemap_adj_x(float face) +{ + bool y_axis = (face == 2.0 || face == 3.0); + return y_axis ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); +} + +vec3 cubemap_adj_y(float face) +{ + bool x_axis = (face < 2.0); + return x_axis ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); +} + +vec3 cubemap_adj_xy(float face) +{ + if (face < 2.0) { + return vec3(0.0, 1.0, 1.0); + } + else if (face < 4.0) { + return vec3(1.0, 0.0, 1.0); + } + else { + return vec3(1.0, 1.0, 0.0); + } +} + +vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod) +{ + /* Manual Cube map Layer indexing. */ + float face = cubemap_face_index(cubevec.xyz); + vec2 uv = cubemap_face_coord(cubevec.xyz, face); + vec3 coord = vec3(uv, cubevec.w * 6.0 + face); + + vec4 col = textureLod(tex, coord, lod); + + float cube_size = float(textureSize(tex, int(lod)).x); + + vec2 uv_border = (abs(uv - 0.5) + (0.5 / cube_size - 0.5)) * 2.0 * cube_size; + bvec2 border = greaterThan(uv_border, vec2(0.0)); + if (all(border)) { + /* Corners case. */ + vec3 cubevec_adj; + float face_adj; + /* Get the other face coords. */ + cubevec_adj = cubevec.xyz * cubemap_adj_x(face); + face_adj = cubemap_face_index(cubevec_adj); + /* Still use the original cubevec to get the outer texels or the face. */ + uv = cubemap_face_coord(cubevec.xyz, face_adj); + coord = vec3(uv, cubevec.w * 6.0 + face_adj); + vec4 col1 = textureLod(tex, coord, lod); + + /* Get the 3rd face coords. */ + cubevec_adj = cubevec.xyz * cubemap_adj_y(face); + face_adj = cubemap_face_index(cubevec_adj); + /* Still use the original cubevec to get the outer texels or the face. */ + uv = cubemap_face_coord(cubevec.xyz, face_adj); + coord = vec3(uv, cubevec.w * 6.0 + face_adj); + vec4 col2 = textureLod(tex, coord, lod); + + /* Mix all colors to get the corner color. */ + vec4 col3 = (col + col1 + col2) / 3.0; + + vec2 mix_fac = uv_border * 0.5; + return mix(mix(col, col2, mix_fac.x), mix(col1, col3, mix_fac.x), mix_fac.y); + } + else if (any(border)) { + /* Edges case. */ + /* Get the other face coords. */ + vec3 cubevec_adj = cubevec.xyz * cubemap_adj_xy(face); + face = cubemap_face_index(cubevec_adj); + /* Still use the original cubevec to get the outer texels or the face. */ + uv = cubemap_face_coord(cubevec.xyz, face); + coord = vec3(uv, cubevec.w * 6.0 + face); + + float mix_fac = max(uv_border.x, uv_border.y) * 0.5; + return mix(col, textureLod(tex, coord, lod), mix_fac); + } + else { + return col; + } +} + +vec4 textureLod_cubemapArray(sampler2DArray tex, vec4 cubevec, float lod) +{ + float lod1 = floor(lod); + float lod2 = ceil(lod); + + vec4 col_lod1 = cubemap_seamless(tex, cubevec, lod1); + vec4 col_lod2 = cubemap_seamless(tex, cubevec, lod2); + + return mix(col_lod1, col_lod2, lod - lod1); +} + +#endif 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 a852dd47872..96fe94fc41e 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 @@ -15,6 +15,5 @@ void main() 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); + FragColor = vec4(textureLod_cubemapArray(probeCubes, vec4(world_ref, pid), 0.0).rgb, 1.0); } diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl index 06c31272ecd..00eb3c7e200 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl @@ -33,29 +33,9 @@ vec3 octahedral_to_cubemap_proj(vec2 co) void main() { - vec2 uvs = gl_FragCoord.xy * texelSize; - - /* Add a N pixel border to ensure filtering is correct - * for N mipmap levels. */ - uvs = (uvs - paddingSize) / (1.0 - 2.0 * paddingSize); - - /* edge mirroring : only mirror if directly adjacent - * (not diagonally adjacent) */ - vec2 m = abs(uvs - 0.5) + 0.5; - vec2 f = floor(m); - if (f.x - f.y != 0.0) { - uvs = 1.0 - uvs; - } - - /* clamp to [0-1] */ - uvs = fract(uvs); - - /* get cubemap vector */ - vec3 cubevec = octahedral_to_cubemap_proj(uvs); - vec3 N, T, B, V; - vec3 R = normalize(cubevec); + vec3 R = normalize(worldPosition); /* Isotropic assumption */ N = V = R; diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl index ab205b78274..6c6db88139b 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl @@ -1,7 +1,7 @@ /* ----------- Uniforms --------- */ uniform sampler2DArray probePlanars; -uniform sampler2DArray probeCubes; +uniform samplerCubeArray probeCubes; /* ----------- Structures --------- */ @@ -172,15 +172,12 @@ vec3 probe_evaluate_cube(int pd_id, vec3 W, vec3 R, float roughness) float fac = saturate(original_roughness * 2.0 - 1.0); R = mix(intersection, R, fac * fac); - return textureLod_octahedron( - probeCubes, vec4(R, float(pd_id)), roughness * prbLodCubeMax, prbLodCubeMax) - .rgb; + return textureLod_cubemapArray(probeCubes, vec4(R, float(pd_id)), roughness * prbLodCubeMax).rgb; } vec3 probe_evaluate_world_spec(vec3 R, float roughness) { - return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax, prbLodCubeMax) - .rgb; + return textureLod_cubemapArray(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax).rgb; } vec3 probe_evaluate_planar( diff --git a/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl b/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl index bfb6bc890ec..e05cc2719fa 100644 --- a/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl @@ -18,21 +18,3 @@ vec2 mapping_octahedron(vec3 cubevec, vec2 texel_size) return uvs; } - -vec4 textureLod_octahedron(sampler2DArray tex, vec4 cubevec, float lod, float lod_max) -{ - vec2 texelSize = 1.0 / vec2(textureSize(tex, int(lod_max))); - - vec2 uvs = mapping_octahedron(cubevec.xyz, texelSize); - - return textureLod(tex, vec3(uvs, cubevec.w), lod); -} - -vec4 texture_octahedron(sampler2DArray tex, vec4 cubevec) -{ - vec2 texelSize = 1.0 / vec2(textureSize(tex, 0)); - - vec2 uvs = mapping_octahedron(cubevec.xyz, texelSize); - - return texture(tex, vec3(uvs, cubevec.w)); -} diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index 743171b09fb..3459685f504 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -61,7 +61,7 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) /* TODO: This does not work quite well if you use * strokes not aligned with the object axes. Maybe we could try to * compute the minimum axis of all strokes. But this would be more - * computationaly heavy and should go into the GPData evaluation. */ + * computationally heavy and should go into the GPData evaluation. */ BoundBox *bbox = BKE_object_boundbox_get(ob); /* Convert bbox to matrix */ float mat[4][4], size[3], center[3]; diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c index 77baadfc83a..625af8cec6f 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c @@ -108,7 +108,7 @@ static void gpencil_object_random_color_get(const Object *ob, float r_color[3]) static void gpencil_shade_color(float color[3]) { - /* This is scene refered color, not gamma corrected and not per perceptual. + /* This is scene refereed color, not gamma corrected and not per perceptual. * So we lower the threshold a bit. (1.0 / 3.0) */ if (color[0] + color[1] + color[2] > 1.1) { add_v3_fl(color, -0.25f); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index d47d6f8a836..37aef5a633a 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -710,7 +710,7 @@ void GPENCIL_cache_finish(void *ved) if (pd->use_mask_fb) { /* We need an extra depth to not disturb the normal drawing. - * The color_tx is needed for framebuffer cmpleteness. */ + * The color_tx is needed for frame-buffer completeness. */ GPUTexture *color_tx, *depth_tx; depth_tx = DRW_texture_pool_query_2d( size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type); diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index cfa0fa9eb1a..740ca42800e 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -382,9 +382,6 @@ static void OVERLAY_cache_finish(void *vedata) DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0); GPU_framebuffer_ensure_config( - &dfbl->default_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); - GPU_framebuffer_ensure_config( &dfbl->in_front_fb, {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); } diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c index e77a0a143a9..0395f6890bd 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.c +++ b/source/blender/draw/engines/overlay/overlay_outline.c @@ -33,7 +33,7 @@ #include "overlay_private.h" -/* Returns the normal plane in ndc space. */ +/* Returns the normal plane in NDC space. */ static void gpencil_depth_plane(Object *ob, float r_plane[4]) { /* TODO put that into private data. */ @@ -42,11 +42,11 @@ static void gpencil_depth_plane(Object *ob, float r_plane[4]) float *camera_z_axis = viewinv[2]; float *camera_pos = viewinv[3]; - /* Find the normal most likely to represent the gpObject. */ + /* Find the normal most likely to represent the grease pencil object. */ /* TODO: This does not work quite well if you use * strokes not aligned with the object axes. Maybe we could try to * compute the minimum axis of all strokes. But this would be more - * computationaly heavy and should go into the GPData evaluation. */ + * computationally heavy and should go into the GPData evaluation. */ BoundBox *bbox = BKE_object_boundbox_get(ob); /* Convert bbox to matrix */ float mat[4][4], size[3], center[3]; diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c index 722055c36f0..6b0e5e0b72e 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.c +++ b/source/blender/draw/engines/overlay/overlay_wireframe.c @@ -68,22 +68,17 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) OVERLAY_shader_wireframe(); for (int xray = 0; xray < (is_material_shmode ? 1 : 2); xray++) { - /* Only do stencil test if stencil buffer is written by the render engine. */ - DRWState stencil_state = is_material_shmode ? 0 : DRW_STATE_STENCIL_EQUAL; DRWState state = DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; DRWPass *pass; - uint stencil_mask; if (xray == 0) { - DRW_PASS_CREATE(psl->wireframe_ps, state | stencil_state | pd->clipping_state); + DRW_PASS_CREATE(psl->wireframe_ps, state | pd->clipping_state); pass = psl->wireframe_ps; - stencil_mask = 0xFF; } else { DRW_PASS_CREATE(psl->wireframe_xray_ps, state | pd->clipping_state); pass = psl->wireframe_xray_ps; - stencil_mask = 0x00; } for (int use_coloring = 0; use_coloring < 2; use_coloring++) { @@ -94,17 +89,14 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); DRW_shgroup_uniform_bool_copy(grp, "isObjectColor", is_object_color); DRW_shgroup_uniform_bool_copy(grp, "isRandomColor", is_random_color); - DRW_shgroup_stencil_mask(grp, stencil_mask); pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass); DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 1.0f); - DRW_shgroup_stencil_mask(grp, stencil_mask); } pd->wires_sculpt_grp[xray] = grp = DRW_shgroup_create(wires_sh, pass); DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f); DRW_shgroup_uniform_bool_copy(grp, "useColoring", false); - DRW_shgroup_stencil_mask(grp, stencil_mask); } if (is_material_shmode) { diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl deleted file mode 100644 index a0e04f252e2..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl +++ /dev/null @@ -1,81 +0,0 @@ -out vec4 fragColor; - -uniform sampler2D depthBuffer; -uniform sampler2D colorBuffer; -uniform sampler2D normalBuffer; -uniform usampler2D objectId; - -uniform vec2 invertedViewportSize; -uniform mat4 WinMatrix; /* inverse WinMatrix */ - -uniform vec4 viewvecs[3]; -uniform vec4 ssao_params; -uniform vec4 ssao_settings; -uniform vec2 curvature_settings; -uniform sampler2D ssao_jitter; - -layout(std140) uniform samples_block -{ - vec4 ssao_samples[500]; -}; - -#define ssao_samples_num ssao_params.x -#define jitter_tilling ssao_params.yz -#define ssao_iteration ssao_params.w - -#define ssao_distance ssao_settings.x -#define ssao_factor_cavity ssao_settings.y -#define ssao_factor_edge ssao_settings.z -#define ssao_attenuation ssao_settings.w - -vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth) -{ - if (WinMatrix[3][3] == 0.0) { - /* Perspective */ - float d = 2.0 * depth - 1.0; - - float zview = -WinMatrix[3][2] / (d + WinMatrix[2][2]); - - return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz); - } - else { - /* Orthographic */ - vec3 offset = vec3(uvcoords, depth); - - return viewvecs[0].xyz + offset * viewvecs[1].xyz; - } -} - -/* forward declaration */ -void ssao_factors(in float depth, - in vec3 normal, - in vec3 position, - in vec2 screenco, - out float cavities, - out float edges); - -void main() -{ - vec2 screenco = vec2(gl_FragCoord.xy) * invertedViewportSize; - ivec2 texel = ivec2(gl_FragCoord.xy); - - float cavity = 0.0, edges = 0.0, curvature = 0.0; - -#ifdef USE_CAVITY - float depth = texelFetch(depthBuffer, texel, 0).x; - vec3 position = get_view_space_from_depth(screenco, depth); - vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg); - - ssao_factors(depth, normal_viewport, position, screenco, cavity, edges); -#endif - -#ifdef USE_CURVATURE - curvature = calculate_curvature( - objectId, normalBuffer, texel, curvature_settings.x, curvature_settings.y); -#endif - - float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0); - - /* Using UNORM render target so compress the range. */ - fragColor = vec4(final_cavity_factor / CAVITY_BUFFER_RANGE); -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl index 376b19cdd1b..87d04144cde 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl @@ -1,77 +1,87 @@ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) -/* from The Alchemy screen-space ambient obscurance algorithm +layout(std140) uniform samples_block +{ + vec4 samples_coords[512]; +}; + +uniform sampler2D cavityJitter; + +/* From The Alchemy screen-space ambient obscurance algorithm * http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */ -void ssao_factors(in float depth, - in vec3 normal, - in vec3 position, - in vec2 screenco, - out float cavities, - out float edges) +void cavity_compute(vec2 screenco, + sampler2D depthBuffer, + sampler2D normalBuffer, + out float cavities, + out float edges) { cavities = edges = 0.0; - /* early out if there is no need for SSAO */ - if (ssao_factor_cavity == 0.0 && ssao_factor_edge == 0.0) { + + float depth = texture(depthBuffer, screenco).x; + + /* Early out if background and infront. */ + if (depth == 1.0 || depth == 0.0) { return; } - /* take the normalized ray direction here */ - vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb; + vec3 position = view_position_from_depth(screenco, depth, world_data.viewvecs, ProjectionMatrix); + vec3 normal = workbench_normal_decode(texture(normalBuffer, screenco)); + + vec2 jitter_co = (screenco * world_data.viewport_size.xy) * world_data.cavity_jitter_scale; + vec3 noise = texture(cavityJitter, jitter_co).rgb; /* find the offset in screen space by multiplying a point * in camera space at the depth of the point by the projection matrix. */ vec2 offset; - float homcoord = WinMatrix[2][3] * position.z + WinMatrix[3][3]; - offset.x = WinMatrix[0][0] * ssao_distance / homcoord; - offset.y = WinMatrix[1][1] * ssao_distance / homcoord; + float homcoord = ProjectionMatrix[2][3] * position.z + ProjectionMatrix[3][3]; + offset.x = ProjectionMatrix[0][0] * world_data.cavity_distance / homcoord; + offset.y = ProjectionMatrix[1][1] * world_data.cavity_distance / homcoord; /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */ offset *= 0.5; - int num_samples = int(ssao_samples_num); - /* Note. Putting noise usage here to put some ALU after texture fetch. */ vec2 rotX = noise.rg; vec2 rotY = vec2(-rotX.y, rotX.x); - for (int x = 0; x < num_samples; x++) { - int sample_index = x + (int(ssao_iteration) * num_samples); - if (sample_index > 500) { - continue; - } - /* ssao_samples[x].xy is sample direction (normalized). - * ssao_samples[x].z is sample distance from disk center. */ - + int sample_start = world_data.cavity_sample_start; + int sample_end = world_data.cavity_sample_end; + for (int i = sample_start; i < sample_end && i < 512; i++) { + /* sample_coord.xy is sample direction (normalized). + * sample_coord.z is sample distance from disk center. */ + vec3 sample_coord = samples_coords[i].xyz; /* Rotate with random direction to get jittered result. */ - vec2 dir_jittered = vec2(dot(ssao_samples[sample_index].xy, rotX), - dot(ssao_samples[sample_index].xy, rotY)); - dir_jittered.xy *= ssao_samples[sample_index].z + noise.b; + vec2 dir_jittered = vec2(dot(sample_coord.xy, rotX), dot(sample_coord.xy, rotY)); + dir_jittered.xy *= sample_coord.z + noise.b; - vec2 uvcoords = screenco.xy + dir_jittered * offset; - - if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0) { + vec2 uvcoords = screenco + dir_jittered * offset; + /* Out of screen case. */ + if (any(greaterThan(abs(uvcoords - 0.5), vec2(0.5)))) { continue; } - - float depth_new = texture(depthBuffer, uvcoords).r; - + /* Sample depth. */ + float s_depth = texture(depthBuffer, uvcoords).r; /* Handle Background case */ - bool is_background = (depth_new == 1.0); - + bool is_background = (s_depth == 1.0); /* This trick provide good edge effect even if no neighbor is found. */ - vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new); + s_depth = (is_background) ? depth : s_depth; + vec3 s_pos = view_position_from_depth( + uvcoords, s_depth, world_data.viewvecs, ProjectionMatrix); if (is_background) { - pos_new.z -= ssao_distance; + s_pos.z -= world_data.cavity_distance; } - vec3 dir = pos_new - position; + vec3 dir = s_pos - position; float len = length(dir); float f_cavities = dot(dir, normal); float f_edge = -f_cavities; float f_bias = 0.05 * len + 0.0001; - float attenuation = 1.0 / (len * (1.0 + len * len * ssao_attenuation)); + float attenuation = 1.0 / (len * (1.0 + len * len * world_data.cavity_attenuation)); /* use minor bias here to avoid self shadowing */ if (f_cavities > -f_bias) { @@ -82,11 +92,10 @@ void ssao_factors(in float depth, edges += f_edge * attenuation; } } - - cavities /= ssao_samples_num; - edges /= ssao_samples_num; + cavities *= world_data.cavity_sample_count_inv; + edges *= world_data.cavity_sample_count_inv; /* don't let cavity wash out the surface appearance */ - cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0); - edges = edges * ssao_factor_edge; + cavities = clamp(cavities * world_data.cavity_valley_factor, 0.0, 1.0); + edges = edges * world_data.cavity_ridge_factor; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl index c0d7719180b..25eaf003e07 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl @@ -1,30 +1,16 @@ -#define NO_OBJECT_ID uint(0) + #define EPSILON 0.00001 #define M_PI 3.14159265358979323846 #define CAVITY_BUFFER_RANGE 4.0 -/* 4x4 bayer matrix prepared for 8bit UNORM precision error. */ -#define P(x) (((x + 0.5) * (1.0 / 16.0) - 0.5) * (1.0 / 255.0)) -const vec4 dither_mat4x4[4] = vec4[4](vec4(P(0.0), P(8.0), P(2.0), P(10.0)), - vec4(P(12.0), P(4.0), P(14.0), P(6.0)), - vec4(P(3.0), P(11.0), P(1.0), P(9.0)), - vec4(P(15.0), P(7.0), P(13.0), P(5.0))); - -float bayer_dither_noise() -{ - ivec2 tx1 = ivec2(gl_FragCoord.xy) % 4; - ivec2 tx2 = ivec2(gl_FragCoord.xy) % 2; - return dither_mat4x4[tx1.x][tx1.y]; -} - #ifdef WORKBENCH_ENCODE_NORMALS # define WB_Normal vec2 /* From http://aras-p.info/texts/CompactNormalStorage.html * Using Method #4: Spheremap Transform */ -vec3 workbench_normal_decode(WB_Normal enc) +vec3 workbench_normal_decode(vec4 enc) { vec2 fenc = enc.xy * 4.0 - 2.0; float f = dot(fenc, fenc); @@ -37,8 +23,9 @@ vec3 workbench_normal_decode(WB_Normal enc) /* From http://aras-p.info/texts/CompactNormalStorage.html * Using Method #4: Spheremap Transform */ -WB_Normal workbench_normal_encode(vec3 n) +WB_Normal workbench_normal_encode(bool front_face, vec3 n) { + n = normalize(front_face ? n : -n); float p = sqrt(n.z * 8.0 + 8.0); n.xy = clamp(n.xy / p + 0.5, 0.0, 1.0); return n.xy; @@ -47,161 +34,64 @@ WB_Normal workbench_normal_encode(vec3 n) #else # define WB_Normal vec3 /* Well just do nothing... */ -# define workbench_normal_encode(a) (a) -# define workbench_normal_decode(a) (a) +# define workbench_normal_encode(f, a) (a) +# define workbench_normal_decode(a) (a.xyz) #endif /* WORKBENCH_ENCODE_NORMALS */ -/* Encoding into the alpha of a RGBA8 UNORM texture. */ +/* Encoding into the alpha of a RGBA16F texture. (10bit mantissa) */ #define TARGET_BITCOUNT 8u #define METALLIC_BITS 3u /* Metallic channel is less important. */ #define ROUGHNESS_BITS (TARGET_BITCOUNT - METALLIC_BITS) -#define TOTAL_BITS (METALLIC_BITS + ROUGHNESS_BITS) /* Encode 2 float into 1 with the desired precision. */ float workbench_float_pair_encode(float v1, float v2) { - // const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS); // const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS); // const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS); /* Same as above because some compiler are dumb af. and think we use mediump int. */ - const int total_mask = 0xFF; const int v1_mask = 0x1F; const int v2_mask = 0x7; int iv1 = int(v1 * float(v1_mask)); int iv2 = int(v2 * float(v2_mask)) << int(ROUGHNESS_BITS); - return float(iv1 | iv2) * (1.0 / float(total_mask)); + return float(iv1 | iv2); } void workbench_float_pair_decode(float data, out float v1, out float v2) { - // const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS); // const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS); // const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS); /* Same as above because some compiler are dumb af. and think we use mediump int. */ - const int total_mask = 0xFF; const int v1_mask = 0x1F; const int v2_mask = 0x7; - int idata = int(data * float(total_mask)); + int idata = int(data); v1 = float(idata & v1_mask) * (1.0 / float(v1_mask)); v2 = float(idata >> int(ROUGHNESS_BITS)) * (1.0 / float(v2_mask)); } -float calculate_transparent_weight(float z, float alpha) -{ -#if 0 - /* Eq 10 : Good for surfaces with varying opacity (like particles) */ - float a = min(1.0, alpha * 10.0) + 0.01; - float b = -gl_FragCoord.z * 0.95 + 1.0; - float w = a * a * a * 3e2 * b * b * b; -#else - /* Eq 7 put more emphasis on surfaces closer to the view. */ - // float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */ - // float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */ - // float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */ - /* Same as eq 7, but optimized. */ - float a = abs(z) / 5.0; - float b = abs(z) / 200.0; - b *= b; - float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */ -#endif - return alpha * clamp(w, 1e-2, 3e2); -} - -/* Special function only to be used with calculate_transparent_weight(). */ -float linear_zdepth(float depth, vec4 viewvecs[3], mat4 proj_mat) +vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[3], mat4 proj_mat) { if (proj_mat[3][3] == 0.0) { - float d = 2.0 * depth - 1.0; - return -proj_mat[3][2] / (d + proj_mat[2][2]); + return normalize(viewvecs[0].xyz + vec3(uv, 0.0) * viewvecs[1].xyz); } else { - /* Return depth from near plane. */ - return depth * viewvecs[1].z; - } -} - -vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[3], mat4 proj_mat) -{ - return (proj_mat[3][3] == 0.0) ? normalize(viewvecs[0].xyz + vec3(uv, 0.0) * viewvecs[1].xyz) : - vec3(0.0, 0.0, 1.0); -} - -vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped) -{ - /* Quick creation of an orthonormal basis */ - float a = 1.0 / (1.0 + I.z); - float b = -I.x * I.y * a; - vec3 b1 = vec3(1.0 - I.x * I.x * a, b, -I.x); - vec3 b2 = vec3(b, 1.0 - I.y * I.y * a, -I.y); - vec2 matcap_uv = vec2(dot(b1, N), dot(b2, N)); - if (flipped) { - matcap_uv.x = -matcap_uv.x; + return vec3(0.0, 0.0, 1.0); } - return matcap_uv * 0.496 + 0.5; } -bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map) +vec3 view_position_from_depth(vec2 uvcoords, float depth, vec4 viewvecs[3], mat4 proj_mat) { - vec2 tile_pos = floor(co.xy); - - if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10) - return false; - - float tile = 10.0 * tile_pos.y + tile_pos.x; - if (tile >= textureSize(map, 0).x) - return false; - - /* Fetch tile information. */ - float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x; - if (tile_layer < 0.0) - return false; - - vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0); - - co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer); - return true; -} + if (proj_mat[3][3] == 0.0) { + /* Perspective */ + float d = 2.0 * depth - 1.0; -vec4 workbench_sample_texture(sampler2D image, - vec2 coord, - bool nearest_sampling, - bool premultiplied) -{ - vec2 tex_size = vec2(textureSize(image, 0).xy); - /* TODO(fclem) We could do the same with sampler objects. - * But this is a quick workaround instead of messing with the GPUTexture itself. */ - vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord; - vec4 color = texture(image, uv); + float zview = -proj_mat[3][2] / (d + proj_mat[2][2]); - /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */ - if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) { - color.rgb = color.rgb / color.a; + return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz); } + else { + /* Orthographic */ + vec3 offset = vec3(uvcoords, depth); - return color; -} - -vec4 workbench_sample_texture_array(sampler2DArray tile_array, - sampler1DArray tile_data, - vec2 coord, - bool nearest_sampling, - bool premultiplied) -{ - vec2 tex_size = vec2(textureSize(tile_array, 0).xy); - - vec3 uv = vec3(coord, 0); - if (!node_tex_tile_lookup(uv, tile_array, tile_data)) - return vec4(1.0, 0.0, 1.0, 1.0); - - /* TODO(fclem) We could do the same with sampler objects. - * But this is a quick workaround instead of messing with the GPUTexture itself. */ - uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy; - vec4 color = texture(tile_array, uv); - - /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */ - if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) { - color.rgb = color.rgb / color.a; + return viewvecs[0].xyz + offset * viewvecs[1].xyz; } - - return color; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl new file mode 100644 index 00000000000..cdb9823096c --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl @@ -0,0 +1,44 @@ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl) + +uniform sampler2D materialBuffer; +uniform sampler2D normalBuffer; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +void main() +{ + /* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */ + vec3 I = view_vector_from_screen_uv(uvcoordsvar.st, world_data.viewvecs, ProjectionMatrix); + vec3 N = workbench_normal_decode(texture(normalBuffer, uvcoordsvar.st)); + vec4 mat_data = texture(materialBuffer, uvcoordsvar.st); + + vec3 base_color = mat_data.rgb; + + float roughness, metallic; + workbench_float_pair_decode(mat_data.a, roughness, metallic); + +#ifdef V3D_LIGHTING_MATCAP + /* When using matcaps, mat_data.a is the backface sign. */ + N = (mat_data.a > 0.0) ? N : -N; + + fragColor.rgb = get_matcap_lighting(base_color, N, I); +#endif + +#ifdef V3D_LIGHTING_STUDIO + fragColor.rgb = get_world_lighting(base_color, roughness, metallic, N, I); +#endif + +#ifdef V3D_LIGHTING_FLAT + fragColor.rgb = base_color; +#endif + + fragColor.rgb *= get_shadow(N); + + fragColor.a = 1.0; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl index 22dc906be83..e6bc4c7bbc6 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl @@ -1,6 +1,5 @@ -#ifndef CURVATURE_OFFSET -# define CURVATURE_OFFSET 1 -#endif + +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) float curvature_soft_clamp(float curvature, float control) { @@ -10,33 +9,35 @@ float curvature_soft_clamp(float curvature, float control) return 0.25 / control; } -float calculate_curvature( - usampler2D objectId, sampler2D normalBuffer, ivec2 texel, float ridge, float valley) +void curvature_compute(vec2 uv, + usampler2D objectIdBuffer, + sampler2D normalBuffer, + out float curvature) { - uint object_up = texelFetchOffset(objectId, texel, 0, ivec2(0, CURVATURE_OFFSET)).r; - uint object_down = texelFetchOffset(objectId, texel, 0, ivec2(0, -CURVATURE_OFFSET)).r; - uint object_left = texelFetchOffset(objectId, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).r; - uint object_right = texelFetchOffset(objectId, texel, 0, ivec2(CURVATURE_OFFSET, 0)).r; + curvature = 0.0; + + vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale; + uint object_up = texture(objectIdBuffer, uv + offset.zy).r; + uint object_down = texture(objectIdBuffer, uv - offset.zy).r; + uint object_right = texture(objectIdBuffer, uv + offset.xz).r; + uint object_left = texture(objectIdBuffer, uv - offset.xz).r; + /* Remove object outlines. */ if ((object_up != object_down) || (object_right != object_left)) { - return 0.0; + return; } - vec2 normal_up = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, CURVATURE_OFFSET)).rg; - vec2 normal_down = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, -CURVATURE_OFFSET)).rg; - vec2 normal_left = texelFetchOffset(normalBuffer, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).rg; - vec2 normal_right = texelFetchOffset(normalBuffer, texel, 0, ivec2(CURVATURE_OFFSET, 0)).rg; - - normal_up = workbench_normal_decode(normal_up).rg; - normal_down = workbench_normal_decode(normal_down).rg; - normal_left = workbench_normal_decode(normal_left).rg; - normal_right = workbench_normal_decode(normal_right).rg; + float normal_up = workbench_normal_decode(texture(normalBuffer, uv + offset.zy)).g; + float normal_down = workbench_normal_decode(texture(normalBuffer, uv - offset.zy)).g; + float normal_right = workbench_normal_decode(texture(normalBuffer, uv + offset.xz)).r; + float normal_left = workbench_normal_decode(texture(normalBuffer, uv - offset.xz)).r; - float normal_diff = ((normal_up.g - normal_down.g) + (normal_right.r - normal_left.r)); + float normal_diff = (normal_up - normal_down) + (normal_right - normal_left); if (normal_diff < 0) { - return -2.0 * curvature_soft_clamp(-normal_diff, valley); + curvature = -2.0 * curvature_soft_clamp(-normal_diff, world_data.curvature_valley); + } + else { + curvature = 2.0 * curvature_soft_clamp(normal_diff, world_data.curvature_ridge); } - - return 2.0 * curvature_soft_clamp(normal_diff, ridge); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl index 0c984b094d3..5f3283e1643 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl @@ -5,12 +5,42 @@ struct LightData { }; struct WorldData { + vec4 viewvecs[3]; + vec4 viewport_size; vec4 object_outline_color; vec4 shadow_direction_vs; + float shadow_focus; + float shadow_shift; + float shadow_mul; + float shadow_add; + /* - 16 bytes alignment- */ LightData lights[4]; vec4 ambient_color; - int num_lights; - int matcap_orientation; + + int cavity_sample_start; + int cavity_sample_end; + float cavity_sample_count_inv; + float cavity_jitter_scale; + + float cavity_valley_factor; + float cavity_ridge_factor; + float cavity_attenuation; + float cavity_distance; + float curvature_ridge; float curvature_valley; + float ui_scale; + float _pad0; + + int matcap_orientation; + bool use_specular; + int _pad1; + int _pad2; +}; + +#define viewport_size_inv viewport_size.zw + +layout(std140) uniform world_block +{ + WorldData world_data; }; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl deleted file mode 100644 index 22fa2babbbf..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl +++ /dev/null @@ -1,30 +0,0 @@ - -uniform usampler2D objectId; - -uniform vec2 invertedViewportSize; - -out vec4 fragColor; - -layout(std140) uniform world_block -{ - WorldData world_data; -}; - -void main() -{ - vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - -#ifndef V3D_SHADING_OBJECT_OUTLINE - - fragColor = vec4(0.0); - -#else /* !V3D_SHADING_OBJECT_OUTLINE */ - - ivec2 texel = ivec2(gl_FragCoord.xy); - uint object_id = texelFetch(objectId, texel, 0).r; - float object_outline = calculate_object_outline(objectId, texel, object_id); - - fragColor = vec4(world_data.object_outline_color.rgb, 1.0) * (1.0 - object_outline); - -#endif /* !V3D_SHADING_OBJECT_OUTLINE */ -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl deleted file mode 100644 index fd4cea4279a..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl +++ /dev/null @@ -1,103 +0,0 @@ -out vec4 fragColor; - -uniform usampler2D objectId; -uniform sampler2D materialBuffer; -uniform sampler2D normalBuffer; -/* normalBuffer contains viewport normals */ -uniform sampler2D cavityBuffer; -uniform sampler2D matcapDiffuseImage; -uniform sampler2D matcapSpecularImage; - -uniform vec2 invertedViewportSize; -uniform vec4 viewvecs[3]; -uniform float shadowMultiplier; -uniform float lightMultiplier; -uniform float shadowShift = 0.1; -uniform float shadowFocus = 1.0; - -uniform vec3 materialSingleColor; - -layout(std140) uniform world_block -{ - WorldData world_data; -}; - -void main() -{ - ivec2 texel = ivec2(gl_FragCoord.xy); - vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - - float roughness, metallic; - vec3 base_color; - -#ifndef MATDATA_PASS_ENABLED - base_color = materialSingleColor; - metallic = 0.0; - roughness = 0.5; -#else - vec4 material_data = texelFetch(materialBuffer, texel, 0); - base_color = material_data.rgb; - workbench_float_pair_decode(material_data.a, roughness, metallic); -#endif - -/* Do we need normals */ -#ifdef NORMAL_VIEWPORT_PASS_ENABLED - vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg); -#endif - - vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix); - - /* -------- SHADING --------- */ -#ifdef V3D_LIGHTING_FLAT - vec3 shaded_color = base_color; - -#elif defined(V3D_LIGHTING_MATCAP) - /* When using matcaps, the metallic is the backface sign. */ - normal_viewport = (metallic > 0.0) ? normal_viewport : -normal_viewport; - bool flipped = world_data.matcap_orientation != 0; - vec2 matcap_uv = matcap_uv_compute(I_vs, normal_viewport, flipped); - vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb; - -# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb; -# else - vec3 matcap_specular = vec3(0.0); -# endif - - vec3 shaded_color = matcap_diffuse * base_color + matcap_specular; - -#elif defined(V3D_LIGHTING_STUDIO) - -# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - vec3 specular_color = mix(vec3(0.05), base_color, metallic); - vec3 diffuse_color = mix(base_color, vec3(0.0), metallic); -# else - roughness = 0.0; - vec3 specular_color = vec3(0.0); - vec3 diffuse_color = base_color; -# endif - - vec3 shaded_color = get_world_lighting( - world_data, diffuse_color, specular_color, roughness, normal_viewport, I_vs); -#endif - - /* -------- POST EFFECTS --------- */ -#ifdef WB_CAVITY - /* Using UNORM texture so decompress the range */ - shaded_color *= texelFetch(cavityBuffer, texel, 0).r * CAVITY_BUFFER_RANGE; -#endif - -#ifdef V3D_SHADING_SHADOW - float light_factor = -dot(normal_viewport, world_data.shadow_direction_vs.xyz); - float shadow_mix = smoothstep(shadowFocus, shadowShift, light_factor); - shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix); -#endif - -#ifdef V3D_SHADING_OBJECT_OUTLINE - uint object_id = texelFetch(objectId, texel, 0).r; - float object_outline = calculate_object_outline(objectId, texel, object_id); - shaded_color = mix(world_data.object_outline_color.rgb, shaded_color, object_outline); -#endif - - fragColor = vec4(shaded_color, 1.0); -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl new file mode 100644 index 00000000000..328d50e69e0 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl @@ -0,0 +1,31 @@ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_cavity_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_curvature_lib.glsl) + +uniform sampler2D depthBuffer; +uniform sampler2D normalBuffer; +uniform usampler2D objectIdBuffer; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +void main() +{ + float cavity = 0.0, edges = 0.0, curvature = 0.0; + +#ifdef USE_CAVITY + cavity_compute(uvcoordsvar.st, depthBuffer, normalBuffer, cavity, edges); +#endif + +#ifdef USE_CURVATURE + curvature_compute(uvcoordsvar.st, objectIdBuffer, normalBuffer, curvature); +#endif + + float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0); + + fragColor.rgb = vec3(final_cavity_factor); + fragColor.a = 1.0; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl deleted file mode 100644 index 95ca2c0c297..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl +++ /dev/null @@ -1,14 +0,0 @@ - -in vec4 uvcoordsvar; - -out vec4 FragColor; - -uniform sampler2D colorBuffer; -uniform vec2 invertedViewportSize; - -void main() -{ - ivec2 texel = ivec2(gl_FragCoord.xy); - FragColor = FxaaPixelShader( - uvcoordsvar.st, colorBuffer, invertedViewportSize, 1.0, 0.166, 0.0833); -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl new file mode 100644 index 00000000000..fb6fdb93462 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl @@ -0,0 +1,24 @@ + +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) + +uniform usampler2D objectIdBuffer; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +void main() +{ + vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale; + vec2 uv = uvcoordsvar.st; + + uint center_id = texture(objectIdBuffer, uv).r; + uvec4 adjacent_ids = uvec4(texture(objectIdBuffer, uv + offset.zy).r, + texture(objectIdBuffer, uv - offset.zy).r, + texture(objectIdBuffer, uv + offset.xz).r, + texture(objectIdBuffer, uv - offset.xz).r); + + float outline_opacity = 1.0 - dot(vec4(equal(uvec4(center_id), adjacent_ids)), vec4(0.25)); + + fragColor = world_data.object_outline_color * outline_opacity; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl new file mode 100644 index 00000000000..2dea2fc4883 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl @@ -0,0 +1,44 @@ + +uniform sampler2D edgesTex; +uniform sampler2D areaTex; +uniform sampler2D searchTex; +uniform sampler2D blendTex; +uniform sampler2D colorTex; +uniform float mixFactor; +uniform float taaSampleCountInv; + +in vec2 uvs; +in vec2 pixcoord; +in vec4 offset[3]; + +#if SMAA_STAGE == 0 +out vec2 fragColor; +#else +out vec4 fragColor; +#endif + +void main() +{ +#if SMAA_STAGE == 0 + /* Detect edges in color and revealage buffer. */ + fragColor = SMAALumaEdgeDetectionPS(uvs, offset, colorTex); + /* Discard if there is no edge. */ + if (dot(fragColor, float2(1.0, 1.0)) == 0.0) { + discard; + } + +#elif SMAA_STAGE == 1 + fragColor = SMAABlendingWeightCalculationPS( + uvs, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0)); + +#elif SMAA_STAGE == 2 + fragColor = vec4(0.0); + if (mixFactor > 0.0) { + fragColor += SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex) * mixFactor; + } + if (mixFactor < 1.0) { + fragColor += texture(colorTex, uvs) * (1.0 - mixFactor); + } + fragColor *= taaSampleCountInv; +#endif +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl new file mode 100644 index 00000000000..07734d19972 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl @@ -0,0 +1,21 @@ + +out vec2 uvs; +out vec2 pixcoord; +out vec4 offset[3]; + +void main() +{ + int v = gl_VertexID % 3; + float x = -1.0 + float((v & 1) << 2); + float y = -1.0 + float((v & 2) << 1); + gl_Position = vec4(x, y, 1.0, 1.0); + uvs = (gl_Position.xy + 1.0) * 0.5; + +#if SMAA_STAGE == 0 + SMAAEdgeDetectionVS(uvs, offset); +#elif SMAA_STAGE == 1 + SMAABlendingWeightCalculationVS(uvs, pixcoord, offset); +#elif SMAA_STAGE == 2 + SMAANeighborhoodBlendingVS(uvs, offset[0]); +#endif +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl index 5795268f794..b877c2c3f76 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl @@ -1,14 +1,11 @@ -uniform sampler2D historyBuffer; + uniform sampler2D colorBuffer; -out vec4 colorOutput; +in vec4 uvcoordsvar; -uniform float mixFactor; +out vec4 fragColor; void main() { - ivec2 texel = ivec2(gl_FragCoord.xy); - vec4 color_buffer = texelFetch(colorBuffer, texel, 0); - vec4 history_buffer = texelFetch(historyBuffer, texel, 0); - colorOutput = mix(history_buffer, color_buffer, mixFactor); + fragColor = texture(colorBuffer, uvcoordsvar.st); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl deleted file mode 100644 index 0a4d64b37ad..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl +++ /dev/null @@ -1,36 +0,0 @@ -out vec4 fragColor; - -uniform usampler2D objectId; -uniform sampler2D transparentAccum; -uniform sampler2D transparentRevealage; -uniform vec2 invertedViewportSize; - -#ifndef ALPHA_COMPOSITE -layout(std140) uniform world_block -{ - WorldData world_data; -}; -#endif - -/* TODO: Bypass the whole shader if there is no xray pass and no outline pass. */ -void main() -{ - ivec2 texel = ivec2(gl_FragCoord.xy); - vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - - /* Listing 4 */ - vec4 trans_accum = texelFetch(transparentAccum, texel, 0); - float trans_revealage = trans_accum.a; - trans_accum.a = texelFetch(transparentRevealage, texel, 0).r; - - vec3 trans_color = trans_accum.rgb / clamp(trans_accum.a, 1e-4, 5e4); - - fragColor.a = 1.0 - trans_revealage; - fragColor.rgb = trans_color * fragColor.a; - -#ifdef V3D_SHADING_OBJECT_OUTLINE - uint object_id = texelFetch(objectId, texel, 0).r; - float outline = calculate_object_outline(objectId, texel, object_id); - fragColor = mix(vec4(world_data.object_outline_color.rgb, 1.0), fragColor, outline); -#endif -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl deleted file mode 100644 index abd8c1f6579..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl +++ /dev/null @@ -1,20 +0,0 @@ - -layout(location = 0) out uint objectId; - -uniform float ImageTransparencyCutoff = 0.1; -#ifdef V3D_SHADING_TEXTURE_COLOR -uniform sampler2D image; - -in vec2 uv_interp; -#endif - -void main() -{ -#ifdef V3D_SHADING_TEXTURE_COLOR - if (texture(image, uv_interp).a < ImageTransparencyCutoff) { - discard; - } -#endif - - objectId = uint(resource_id + 1) & 0xFFu; -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl deleted file mode 100644 index 559dc07c107..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl +++ /dev/null @@ -1,118 +0,0 @@ - -uniform float ImageTransparencyCutoff = 0.1; -#ifdef TEXTURE_IMAGE_ARRAY -uniform sampler2DArray image_tile_array; -uniform sampler1DArray image_tile_data; -#else -uniform sampler2D image; -#endif -uniform bool imageNearest; -uniform bool imagePremultiplied; - -uniform float alpha = 0.5; -uniform vec2 invertedViewportSize; -uniform vec4 viewvecs[3]; - -uniform vec4 materialColorAndMetal; -uniform float materialRoughness; - -uniform float shadowMultiplier = 0.5; -uniform float lightMultiplier = 1.0; -uniform float shadowShift = 0.1; -uniform float shadowFocus = 1.0; - -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -in vec3 normal_viewport; -#endif /* NORMAL_VIEWPORT_PASS_ENABLED */ -#ifdef V3D_SHADING_TEXTURE_COLOR -in vec2 uv_interp; -#endif -#ifdef V3D_SHADING_VERTEX_COLOR -in vec3 vertexColor; -#endif -#ifdef V3D_LIGHTING_MATCAP -uniform sampler2D matcapDiffuseImage; -uniform sampler2D matcapSpecularImage; -#endif - -layout(std140) uniform world_block -{ - WorldData world_data; -}; - -layout(location = 0) out vec4 transparentAccum; -layout(location = 1) out - float revealageAccum; /* revealage actually stored in transparentAccum.a */ - -void main() -{ - vec4 base_color; - -#if defined(V3D_SHADING_TEXTURE_COLOR) -# ifdef TEXTURE_IMAGE_ARRAY - base_color = workbench_sample_texture_array( - image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied); -# else - base_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied); -# endif - if (base_color.a < ImageTransparencyCutoff) { - discard; - } -#elif defined(V3D_SHADING_VERTEX_COLOR) - base_color.rgb = vertexColor; -#else - base_color.rgb = materialColorAndMetal.rgb; -#endif /* V3D_SHADING_TEXTURE_COLOR */ - - vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix); - -#ifdef NORMAL_VIEWPORT_PASS_ENABLED - vec3 nor = normalize(normal_viewport); -#endif - - /* -------- SHADING --------- */ -#ifdef V3D_LIGHTING_FLAT - vec3 shaded_color = base_color.rgb; - -#elif defined(V3D_LIGHTING_MATCAP) - bool flipped = world_data.matcap_orientation != 0; - vec2 matcap_uv = matcap_uv_compute(I_vs, nor, flipped); - vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb; -# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb; -# else - vec3 matcap_specular = vec3(0.0); -# endif - vec3 shaded_color = matcap_diffuse * base_color.rgb + matcap_specular; - -#elif defined(V3D_LIGHTING_STUDIO) -# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - float metallic = materialColorAndMetal.a; - vec3 specular_color = mix(vec3(0.05), base_color.rgb, metallic); - vec3 diffuse_color = mix(base_color.rgb, vec3(0.0), metallic); -# else - vec3 specular_color = vec3(0.0); - vec3 diffuse_color = base_color.rgb; -# endif - - vec3 shaded_color = get_world_lighting( - world_data, diffuse_color, specular_color, materialRoughness, nor, I_vs); -#endif - -#ifdef V3D_SHADING_SHADOW - float light_factor = -dot(nor, world_data.shadow_direction_vs.xyz); - float shadow_mix = smoothstep(shadowFocus, shadowShift, light_factor); - shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix); -#endif - - /* Based on : - * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of - * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013 - */ - /* Listing 4 */ - float z = linear_zdepth(gl_FragCoord.z, viewvecs, ProjectionMatrix); - float weight = calculate_transparent_weight(z, alpha); - transparentAccum = vec4(shaded_color * weight, alpha); - revealageAccum = weight; -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl deleted file mode 100644 index d223a7650c5..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl +++ /dev/null @@ -1,13 +0,0 @@ -uniform sampler2D depthBuffer; - -void main(void) -{ - float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r; - - /* background, discard */ - if (depth >= 1.0) { - discard; - } - - gl_FragDepth = depth; -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl new file mode 100644 index 00000000000..6f99739f259 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl @@ -0,0 +1,83 @@ + +/* TODO(fclem) deduplicate code. */ +bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map) +{ + vec2 tile_pos = floor(co.xy); + + if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10) + return false; + + float tile = 10.0 * tile_pos.y + tile_pos.x; + if (tile >= textureSize(map, 0).x) + return false; + + /* Fetch tile information. */ + float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x; + if (tile_layer < 0.0) + return false; + + vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0); + + co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer); + return true; +} + +vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling) +{ + vec2 tex_size = vec2(textureSize(image, 0).xy); + /* TODO(fclem) We could do the same with sampler objects. + * But this is a quick workaround instead of messing with the GPUTexture itself. */ + vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord; + return texture(image, uv); +} + +vec4 workbench_sample_texture_array(sampler2DArray tile_array, + sampler1DArray tile_data, + vec2 coord, + bool nearest_sampling) +{ + vec2 tex_size = vec2(textureSize(tile_array, 0).xy); + + vec3 uv = vec3(coord, 0); + if (!node_tex_tile_lookup(uv, tile_array, tile_data)) + return vec4(1.0, 0.0, 1.0, 1.0); + + /* TODO(fclem) We could do the same with sampler objects. + * But this is a quick workaround instead of messing with the GPUTexture itself. */ + uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy; + return texture(tile_array, uv); +} + +uniform sampler2DArray imageTileArray; +uniform sampler1DArray imageTileData; +uniform sampler2D imageTexture; + +uniform float imageTransparencyCutoff = 0.1; +uniform bool imageNearest; +uniform bool imagePremult; + +vec3 workbench_image_color(vec2 uvs) +{ +#ifdef V3D_SHADING_TEXTURE_COLOR +# ifdef TEXTURE_IMAGE_ARRAY + vec4 color = workbench_sample_texture_array(imageTileArray, imageTileData, uvs, imageNearest); +# else + vec4 color = workbench_sample_texture(imageTexture, uvs, imageNearest); +# endif + + /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */ + if (imagePremult && !(color.a == 0.0 || color.a == 1.0)) { + color.rgb /= color.a; + } + +# ifdef GPU_FRAGMENT_SHADER + if (color.a < imageTransparencyCutoff) { + discard; + } +# endif + + return color.rgb; +#else + return vec3(1.0); +#endif +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl new file mode 100644 index 00000000000..2d18cc1b014 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl @@ -0,0 +1,30 @@ + +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) + +vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped) +{ + /* Quick creation of an orthonormal basis */ + float a = 1.0 / (1.0 + I.z); + float b = -I.x * I.y * a; + vec3 b1 = vec3(1.0 - I.x * I.x * a, b, -I.x); + vec3 b2 = vec3(b, 1.0 - I.y * I.y * a, -I.y); + vec2 matcap_uv = vec2(dot(b1, N), dot(b2, N)); + if (flipped) { + matcap_uv.x = -matcap_uv.x; + } + return matcap_uv * 0.496 + 0.5; +} + +uniform sampler2D matcapDiffuseImage; +uniform sampler2D matcapSpecularImage; + +vec3 get_matcap_lighting(vec3 base_color, vec3 N, vec3 I) +{ + bool flipped = world_data.matcap_orientation != 0; + vec2 uv = matcap_uv_compute(I, N, flipped); + + vec3 diffuse = textureLod(matcapDiffuseImage, uv, 0.0).rgb; + vec3 specular = textureLod(matcapSpecularImage, uv, 0.0).rgb; + + return diffuse * base_color + specular * float(world_data.use_specular); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl new file mode 100644 index 00000000000..1d8950e34b3 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl @@ -0,0 +1,21 @@ + +layout(std140) uniform material_block +{ + vec4 mat_data[4096]; +}; + +/* If set to -1, the resource handle is used instead. */ +uniform int materialIndex; + +void workbench_material_data_get( + int handle, out vec3 color, out float alpha, out float roughness, out float metallic) +{ + handle = (materialIndex != -1) ? materialIndex : handle; + vec4 data = mat_data[uint(handle) & 0xFFFu]; + color = data.rgb; + + uint encoded_data = floatBitsToUint(data.w); + alpha = float((encoded_data >> 16u) & 0xFFu) * (1.0 / 255.0); + roughness = float((encoded_data >> 8u) & 0xFFu) * (1.0 / 255.0); + metallic = float(encoded_data & 0xFFu) * (1.0 / 255.0); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl new file mode 100644 index 00000000000..58becb03290 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl @@ -0,0 +1,18 @@ + +uniform sampler2D depthBuffer; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +void main() +{ + float depth = texture(depthBuffer, uvcoordsvar.st).r; + /* Discard background pixels. */ + if (depth == 1.0) { + discard; + } + /* Make this fragment occlude any fragment that will try to + * render over it in the normal passes. */ + gl_FragDepth = 0.0; +}
\ No newline at end of file diff --git a/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl deleted file mode 100644 index a4a5d9c31a3..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl +++ /dev/null @@ -1,12 +0,0 @@ -#define OBJECT_OUTLINE_OFFSET 1 - -float calculate_object_outline(usampler2D objectId, ivec2 texel, uint object_id) -{ - uvec4 oid_offset = uvec4( - texelFetchOffset(objectId, texel, 0, ivec2(0, OBJECT_OUTLINE_OFFSET)).r, - texelFetchOffset(objectId, texel, 0, ivec2(0, -OBJECT_OUTLINE_OFFSET)).r, - texelFetchOffset(objectId, texel, 0, ivec2(-OBJECT_OUTLINE_OFFSET, 0)).r, - texelFetchOffset(objectId, texel, 0, ivec2(OBJECT_OUTLINE_OFFSET, 0)).r); - - return dot(vec4(equal(uvec4(object_id), oid_offset)), vec4(0.25)); -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl index 94e41b4bcd4..6d24b001d4d 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl @@ -1,92 +1,29 @@ -uniform vec4 materialColorAndMetal; -uniform float materialRoughness; +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_image_lib.glsl) -#ifdef TEXTURE_IMAGE_ARRAY -uniform sampler2DArray image_tile_array; -uniform sampler1DArray image_tile_data; -#else -uniform sampler2D image; -#endif -uniform float ImageTransparencyCutoff = 0.1; -uniform bool imageNearest; -uniform bool imagePremultiplied; - -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -in vec3 normal_viewport; -#endif - -#ifdef V3D_SHADING_TEXTURE_COLOR -in vec2 uv_interp; -#endif -#ifdef V3D_SHADING_VERTEX_COLOR -in vec3 vertexColor; -#endif - -#ifdef HAIR_SHADER -flat in float hair_rand; -#endif - -#ifdef MATDATA_PASS_ENABLED layout(location = 0) out vec4 materialData; -#endif -#ifdef OBJECT_ID_PASS_ENABLED -layout(location = 1) out uint objectId; -#endif -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -layout(location = 2) out WB_Normal normalViewport; -#endif +layout(location = 1) out WB_Normal normalData; +layout(location = 2) out uint objectId; + +uniform bool useMatcap = false; void main() { -#ifdef MATDATA_PASS_ENABLED - float metallic, roughness; - vec4 color; - -# if defined(V3D_SHADING_TEXTURE_COLOR) -# ifdef TEXTURE_IMAGE_ARRAY - color = workbench_sample_texture_array( - image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied); -# else - color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied); -# endif - if (color.a < ImageTransparencyCutoff) { - discard; - } -# elif defined(V3D_SHADING_VERTEX_COLOR) - color.rgb = vertexColor; -# else - color.rgb = materialColorAndMetal.rgb; -# endif - -# ifdef V3D_LIGHTING_MATCAP - /* Encode front facing in metallic channel. */ - metallic = float(gl_FrontFacing); - roughness = 0.0; -# else - metallic = materialColorAndMetal.a; - roughness = materialRoughness; -# endif + normalData = workbench_normal_encode(gl_FrontFacing, normal_interp); -# ifdef HAIR_SHADER - /* Add some variation to the hairs to avoid uniform look. */ - float hair_variation = hair_rand * 0.1; - color = clamp(color - hair_variation, 0.0, 1.0); - metallic = clamp(materialColorAndMetal.a - hair_variation, 0.0, 1.0); - roughness = clamp(materialRoughness - hair_variation, 0.0, 1.0); -# endif + materialData = vec4(color_interp, packed_rough_metal); - materialData.rgb = color.rgb; - materialData.a = workbench_float_pair_encode(roughness, metallic); -#endif /* MATDATA_PASS_ENABLED */ + objectId = uint(object_id); -#ifdef OBJECT_ID_PASS_ENABLED - objectId = uint(resource_id + 1) & 0xFFu; -#endif + if (useMatcap) { + /* For matcaps, save front facing in alpha channel. */ + materialData.a = float(gl_FrontFacing); + } -#ifdef NORMAL_VIEWPORT_PASS_ENABLED - vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport; - n = normalize(n); - normalViewport = workbench_normal_encode(n); +#ifdef V3D_SHADING_TEXTURE_COLOR + materialData.rgb = workbench_image_color(uv_interp); #endif } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl new file mode 100644 index 00000000000..6a7bc185fe9 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl @@ -0,0 +1,94 @@ +#pragma BLENDER_REQUIRE(common_hair_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_material_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_image_lib.glsl) + +uniform samplerBuffer ac; /* active color layer */ +uniform samplerBuffer au; /* active texture layer */ + +/* From http://libnoise.sourceforge.net/noisegen/index.html */ +float integer_noise(int n) +{ + n = (n >> 13) ^ n; + int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; + return (float(nn) / 1073741824.0); +} + +vec3 workbench_hair_random_normal(vec3 tan, vec3 binor, float rand) +{ + /* To "simulate" anisotropic shading, randomize hair normal per strand. */ + vec3 nor = cross(tan, binor); + nor = normalize(mix(nor, -tan, rand * 0.1)); + float cos_theta = (rand * 2.0 - 1.0) * 0.2; + float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta)); + nor = nor * sin_theta + binor * cos_theta; + return nor; +} + +void workbench_hair_random_material(float rand, + inout vec3 color, + inout float roughness, + inout float metallic) +{ + /* Center noise around 0. */ + rand -= 0.5; + rand *= 0.1; + /* Add some variation to the hairs to avoid uniform look. */ + metallic = clamp(metallic + rand, 0.0, 1.0); + roughness = clamp(roughness + rand, 0.0, 1.0); + /* Modulate by color intensity to reduce very high contrast when color is dark. */ + color = clamp(color + rand * (color + 0.05), 0.0, 1.0); +} + +void main() +{ + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + float time, thick_time, thickness; + vec3 world_pos, tan, binor; + hair_get_pos_tan_binor_time(is_persp, + ModelMatrixInverse, + ViewMatrixInverse[3].xyz, + ViewMatrixInverse[2].xyz, + world_pos, + tan, + binor, + time, + thickness, + thick_time); + + gl_Position = point_world_to_ndc(world_pos); + + float hair_rand = integer_noise(hair_get_strand_id()); + vec3 nor = workbench_hair_random_normal(tan, binor, hair_rand); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif + + uv_interp = hair_get_customdata_vec2(au); + + normal_interp = normalize(normal_world_to_view(nor)); + +#ifdef OPAQUE_MATERIAL + float metallic, roughness; +#endif + workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic); + + if (materialIndex == 0) { + color_interp = hair_get_customdata_vec3(ac); + } + + /* Hairs have lots of layer and can rapidly become the most prominent surface. + * So we lower their alpha artificially. */ + alpha_interp *= 0.3; + + workbench_hair_random_material(hair_rand, color_interp, roughness, metallic); + +#ifdef OPAQUE_MATERIAL + packed_rough_metal = workbench_float_pair_encode(roughness, metallic); +#endif + + object_id = int((uint(resource_id) + 1u) & 0xFFu); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl index 0a3252f0b9b..31e298d1540 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -1,110 +1,40 @@ -#ifndef HAIR_SHADER +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_material_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_image_lib.glsl) + in vec3 pos; in vec3 nor; -in vec2 au; /* active texture layer */ -# ifdef V3D_SHADING_VERTEX_COLOR in vec4 ac; /* active color */ -# endif -# define uv au -#else /* HAIR_SHADER */ - -# ifdef V3D_SHADING_TEXTURE_COLOR -uniform samplerBuffer au; /* active texture layer */ -# endif -# ifdef V3D_SHADING_VERTEX_COLOR -uniform samplerBuffer ac; /* active color layer */ -# endif - -flat out float hair_rand; -#endif /* HAIR_SHADER */ - -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -out vec3 normal_viewport; -#endif - -#ifdef V3D_SHADING_TEXTURE_COLOR -out vec2 uv_interp; -#endif -#ifdef V3D_SHADING_VERTEX_COLOR -out vec3 vertexColor; -#endif - -#ifdef OBJECT_ID_PASS_ENABLED -RESOURCE_ID_VARYING -#endif - -/* From http://libnoise.sourceforge.net/noisegen/index.html */ -float integer_noise(int n) -{ - n = (n >> 13) ^ n; - int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; - return (float(nn) / 1073741824.0); -} - -vec3 workbench_hair_hair_normal(vec3 tan, vec3 binor, float rand) -{ - /* To "simulate" anisotropic shading, randomize hair normal per strand. */ - vec3 nor = cross(tan, binor); - nor = normalize(mix(nor, -tan, rand * 0.1)); - float cos_theta = (rand * 2.0 - 1.0) * 0.2; - float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta)); - nor = nor * sin_theta + binor * cos_theta; - return nor; -} +in vec2 au; /* active texture layer */ void main() { -#ifdef HAIR_SHADER -# ifdef V3D_SHADING_TEXTURE_COLOR - vec2 uv = hair_get_customdata_vec2(au); -# endif - float time, thick_time, thickness; - vec3 world_pos, tan, binor; - hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0), - ModelMatrixInverse, - ViewMatrixInverse[3].xyz, - ViewMatrixInverse[2].xyz, - world_pos, - tan, - binor, - time, - thickness, - thick_time); - - hair_rand = integer_noise(hair_get_strand_id()); - vec3 nor = workbench_hair_hair_normal(tan, binor, hair_rand); -#else vec3 world_pos = point_object_to_world(pos); -#endif gl_Position = point_world_to_ndc(world_pos); -#ifdef V3D_SHADING_TEXTURE_COLOR - uv_interp = uv; +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); #endif -#ifdef V3D_SHADING_VERTEX_COLOR -# ifndef HAIR_SHADER - vertexColor = ac.rgb; -# else - vertexColor = hair_get_customdata_vec4(ac).rgb; -# endif -#endif + uv_interp = au; -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -# ifndef HAIR_SHADER - normal_viewport = normal_object_to_view(nor); - normal_viewport = normalize(normal_viewport); -# else - normal_viewport = normal_world_to_view(nor); -# endif -#endif + normal_interp = normalize(normal_object_to_view(nor)); -#ifdef OBJECT_ID_PASS_ENABLED - PASS_RESOURCE_ID +#ifdef OPAQUE_MATERIAL + float metallic, roughness; #endif + workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic); -#ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance(world_pos); + if (materialIndex == 0) { + color_interp = ac.rgb; + } + +#ifdef OPAQUE_MATERIAL + packed_rough_metal = workbench_float_pair_encode(roughness, metallic); #endif + + object_id = int((uint(resource_id) + 1u) & 0xFFu); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl new file mode 100644 index 00000000000..8e2f7ba4735 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl @@ -0,0 +1,21 @@ + +#ifdef GPU_VERTEX_SHADER +# define IN_OUT out +#else +# define IN_OUT in +#endif + +IN_OUT ShaderStageInterface +{ + vec3 normal_interp; + vec3 color_interp; + float alpha_interp; + vec2 uv_interp; +#ifdef TRANSPARENT_MATERIAL + flat float roughness; + flat float metallic; +#else + flat float packed_rough_metal; +#endif + flat int object_id; +}; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl index 6b0741b6d1b..6fa76510e6e 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl @@ -1,15 +1,19 @@ out vec4 fragColor; +layout(location = 0) out vec4 materialData; +layout(location = 1) out vec4 normalData; +layout(location = 2) out uint objectId; + void main() { - const float intensity = 0.25; + const float a = 0.25; #ifdef SHADOW_PASS - fragColor = vec4( - (gl_FrontFacing) ? vec3(intensity, -intensity, 0.0) : vec3(-intensity, intensity, 0.0), 1.0); + materialData.rgb = gl_FrontFacing ? vec3(a, -a, 0.0) : vec3(-a, a, 0.0); #else - fragColor = vec4((gl_FrontFacing) ? vec3(intensity, intensity, -intensity) : - vec3(-intensity, -intensity, intensity), - 1.0); + materialData.rgb = gl_FrontFacing ? vec3(a, a, -a) : vec3(-a, -a, a); #endif + materialData.a = 0.0; + normalData = vec4(0.0); + objectId = 0u; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl new file mode 100644 index 00000000000..3c2d1a9c0c7 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl @@ -0,0 +1,89 @@ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_image_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl) + +/* Revealage is actually stored in transparentAccum alpha channel. + * This is a workaround to older hardware not having separate blend equation per render target. */ +layout(location = 0) out vec4 transparentAccum; +layout(location = 1) out vec4 revealageAccum; + +/* Note: Blending will be skipped on objectId because output is a non-normalized integer buffer. */ +layout(location = 2) out uint objectId; + +/* Special function only to be used with calculate_transparent_weight(). */ +float linear_zdepth(float depth, vec4 viewvecs[3], mat4 proj_mat) +{ + if (proj_mat[3][3] == 0.0) { + float d = 2.0 * depth - 1.0; + return -proj_mat[3][2] / (d + proj_mat[2][2]); + } + else { + /* Return depth from near plane. */ + return depth * viewvecs[1].z; + } +} + +/* Based on : + * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of + * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013 + */ +float calculate_transparent_weight(void) +{ + float z = linear_zdepth(gl_FragCoord.z, world_data.viewvecs, ProjectionMatrix); +#if 0 + /* Eq 10 : Good for surfaces with varying opacity (like particles) */ + float a = min(1.0, alpha * 10.0) + 0.01; + float b = -gl_FragCoord.z * 0.95 + 1.0; + float w = a * a * a * 3e2 * b * b * b; +#else + /* Eq 7 put more emphasis on surfaces closer to the view. */ + // float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */ + // float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */ + // float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */ + /* Same as eq 7, but optimized. */ + float a = abs(z) / 5.0; + float b = abs(z) / 200.0; + b *= b; + float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */ +#endif + return clamp(w, 1e-2, 3e2); +} + +void main() +{ + /* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */ + vec2 uv_viewport = gl_FragCoord.xy * world_data.viewport_size_inv; + vec3 I = view_vector_from_screen_uv(uv_viewport, world_data.viewvecs, ProjectionMatrix); + vec3 N = normalize(normal_interp); + + vec3 color = color_interp; + +#ifdef V3D_SHADING_TEXTURE_COLOR + color = workbench_image_color(uv_interp); +#endif + +#ifdef V3D_LIGHTING_MATCAP + vec3 shaded_color = get_matcap_lighting(color, N, I); +#endif + +#ifdef V3D_LIGHTING_STUDIO + vec3 shaded_color = get_world_lighting(color, roughness, metallic, N, I); +#endif + +#ifdef V3D_LIGHTING_FLAT + vec3 shaded_color = color; +#endif + + shaded_color *= get_shadow(N); + + /* Listing 4 */ + float weight = calculate_transparent_weight() * alpha_interp; + transparentAccum = vec4(shaded_color * weight, alpha_interp); + revealageAccum = vec4(weight); + + objectId = uint(object_id); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl new file mode 100644 index 00000000000..d985737a35b --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl @@ -0,0 +1,26 @@ + +uniform sampler2D transparentAccum; +uniform sampler2D transparentRevealage; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +/* Based on : + * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of + * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013 + */ + +void main() +{ + /* Revealage is actually stored in transparentAccum alpha channel. + * This is a workaround to older hardware not having separate blend equation per render target. + */ + vec4 trans_accum = texture(transparentAccum, uvcoordsvar.st); + float trans_weight = texture(transparentRevealage, uvcoordsvar.st).r; + float trans_reveal = trans_accum.a; + + /* Listing 4 */ + fragColor.rgb = trans_accum.rgb / clamp(trans_weight, 1e-4, 5e4); + fragColor.a = 1.0 - trans_reveal; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl index c38d8fe06bc..e957f8bbe9c 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -1,4 +1,9 @@ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) + uniform sampler2D depthBuffer; uniform sampler3D densityTexture; @@ -8,10 +13,9 @@ uniform sampler1D flameColorTexture; uniform sampler1D transferTexture; uniform int samplesLen = 256; -uniform float noiseOfs = 0.0f; +uniform float noiseOfs = 0.0; uniform float stepLength; /* Step length in local space. */ uniform float densityScale; /* Simple Opacity multiplicator. */ -uniform vec4 viewvecs[3]; uniform vec3 activeColor; uniform float slicePosition; @@ -23,34 +27,11 @@ in vec3 localPos; out vec4 fragColor; -#define M_PI 3.1415926535897932 /* pi */ - float phase_function_isotropic() { return 1.0 / (4.0 * M_PI); } -float get_view_z_from_depth(float depth) -{ - if (ProjectionMatrix[3][3] == 0.0) { - float d = 2.0 * depth - 1.0; - return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]); - } - else { - return viewvecs[0].z + depth * viewvecs[1].z; - } -} - -vec3 get_view_space_from_depth(vec2 uvcoords, float depth) -{ - if (ProjectionMatrix[3][3] == 0.0) { - return vec3(viewvecs[0].xy + uvcoords * viewvecs[1].xy, 1.0) * get_view_z_from_depth(depth); - } - else { - return viewvecs[0].xyz + vec3(uvcoords, depth) * viewvecs[1].xyz; - } -} - float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); @@ -134,8 +115,9 @@ void volume_properties(vec3 ls_pos, out vec3 scattering, out float extinction) float shadows = sample_volume_texture(shadowTexture, co).r; vec4 density = sample_volume_texture(densityTexture, co); /* rgb: color, a: density */ - scattering = density.rgb * (density.a * densityScale) * activeColor; + scattering = density.rgb * densityScale; extinction = max(1e-4, dot(scattering, vec3(0.33333))); + scattering *= activeColor; /* Scale shadows in log space and clamp them to avoid completely black shadows. */ scattering *= exp(clamp(log(shadows) * densityScale * 0.1, -2.5, 0.0)) * M_PI; @@ -208,8 +190,10 @@ void main() float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r; float depth_end = min(depth, gl_FragCoord.z); - vec3 vs_ray_end = get_view_space_from_depth(screen_uv, depth_end); - vec3 vs_ray_ori = get_view_space_from_depth(screen_uv, 0.0); + vec3 vs_ray_end = view_position_from_depth( + screen_uv, depth_end, world_data.viewvecs, ProjectionMatrix); + vec3 vs_ray_ori = view_position_from_depth( + screen_uv, 0.0, world_data.viewvecs, ProjectionMatrix); vec3 vs_ray_dir = (is_persp) ? (vs_ray_end - vs_ray_ori) : vec3(0.0, 0.0, -1.0); vs_ray_dir /= abs(vs_ray_dir.z); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl index 3542a1a91fc..1a32a202290 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl @@ -1,4 +1,7 @@ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl) + uniform float slicePosition; uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl index 690ce5d527f..81f6e651be0 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl @@ -1,4 +1,6 @@ +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) + /* [Drobot2014a] Low Level Optimizations for GCN */ vec4 fast_rcp(vec4 v) { @@ -41,9 +43,19 @@ vec4 wrapped_lighting(vec4 NL, vec4 w) return clamp((NL + w) * denom, 0.0, 1.0); } -vec3 get_world_lighting( - WorldData world_data, vec3 diffuse_color, vec3 specular_color, float roughness, vec3 N, vec3 I) +vec3 get_world_lighting(vec3 base_color, float roughness, float metallic, vec3 N, vec3 I) { + vec3 specular_color, diffuse_color; + + if (world_data.use_specular) { + diffuse_color = mix(base_color, vec3(0.0), metallic); + specular_color = mix(vec3(0.05), base_color, metallic); + } + else { + diffuse_color = base_color; + specular_color = vec3(0.0); + } + vec3 specular_light = world_data.ambient_color.rgb; vec3 diffuse_light = world_data.ambient_color.rgb; vec4 wrap = vec4(world_data.lights[0].diffuse_color_wrap.a, @@ -51,37 +63,37 @@ vec3 get_world_lighting( world_data.lights[2].diffuse_color_wrap.a, world_data.lights[3].diffuse_color_wrap.a); -#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - /* Prepare Specular computation. Eval 4 lights at once. */ - vec3 R = -reflect(I, N); - vec4 spec_angle, spec_NL, wrap_NL; - prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x); - prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y); - prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z); - prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w); - - vec4 gloss = vec4(1.0 - roughness); - /* Reduce gloss for smooth light. (simulate bigger light) */ - gloss *= 1.0 - wrap; - vec4 shininess = exp2(10.0 * gloss + 1.0); - - vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL); - - /* Simulate Env. light. */ - vec4 w = mix(wrap, vec4(1.0), roughness); - vec4 spec_env = wrapped_lighting(wrap_NL, w); - - spec_light = mix(spec_light, spec_env, wrap * wrap); - - /* Multiply result by lights specular colors. */ - specular_light += spec_light.x * world_data.lights[0].specular_color.rgb; - specular_light += spec_light.y * world_data.lights[1].specular_color.rgb; - specular_light += spec_light.z * world_data.lights[2].specular_color.rgb; - specular_light += spec_light.w * world_data.lights[3].specular_color.rgb; - - float NV = clamp(dot(N, I), 0.0, 1.0); - specular_color = brdf_approx(specular_color, roughness, NV); -#endif + if (world_data.use_specular) { + /* Prepare Specular computation. Eval 4 lights at once. */ + vec3 R = -reflect(I, N); + vec4 spec_angle, spec_NL, wrap_NL; + prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x); + prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y); + prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z); + prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w); + + vec4 gloss = vec4(1.0 - roughness); + /* Reduce gloss for smooth light. (simulate bigger light) */ + gloss *= 1.0 - wrap; + vec4 shininess = exp2(10.0 * gloss + 1.0); + + vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL); + + /* Simulate Env. light. */ + vec4 w = mix(wrap, vec4(1.0), roughness); + vec4 spec_env = wrapped_lighting(wrap_NL, w); + + spec_light = mix(spec_light, spec_env, wrap * wrap); + + /* Multiply result by lights specular colors. */ + specular_light += spec_light.x * world_data.lights[0].specular_color.rgb; + specular_light += spec_light.y * world_data.lights[1].specular_color.rgb; + specular_light += spec_light.z * world_data.lights[2].specular_color.rgb; + specular_light += spec_light.w * world_data.lights[3].specular_color.rgb; + + float NV = clamp(dot(N, I), 0.0, 1.0); + specular_color = brdf_approx(specular_color, roughness, NV); + } specular_light *= specular_color; /* Prepare diffuse computation. Eval 4 lights at once. */ @@ -107,3 +119,13 @@ vec3 get_world_lighting( return diffuse_light + specular_light; } + +uniform bool forceShadowing = false; + +float get_shadow(vec3 N) +{ + float light_factor = -dot(N, world_data.shadow_direction_vs.xyz); + float shadow_mix = smoothstep(world_data.shadow_shift, world_data.shadow_focus, light_factor); + shadow_mix *= forceShadowing ? 0.0 : world_data.shadow_mul; + return shadow_mix + world_data.shadow_add; +}
\ No newline at end of file diff --git a/source/blender/draw/engines/workbench/solid_mode.c b/source/blender/draw/engines/workbench/solid_mode.c deleted file mode 100644 index fed7e230a86..00000000000 --- a/source/blender/draw/engines/workbench/solid_mode.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - * - * Simple engine for drawing color and/or depth. - * When we only need simple studio shaders. - */ - -#include "DRW_render.h" - -#include "GPU_shader.h" - -#include "RE_pipeline.h" - -#include "workbench_private.h" - -/* Functions */ - -static void workbench_solid_engine_init(void *vedata) -{ - WORKBENCH_Data *data = vedata; - workbench_deferred_engine_init(data); -} - -static void workbench_solid_cache_init(void *vedata) -{ - - WORKBENCH_Data *data = vedata; - workbench_deferred_cache_init(data); -} - -static void workbench_solid_cache_populate(void *vedata, Object *ob) -{ - WORKBENCH_Data *data = vedata; - workbench_deferred_solid_cache_populate(data, ob); -} - -static void workbench_solid_cache_finish(void *vedata) -{ - WORKBENCH_Data *data = vedata; - workbench_deferred_cache_finish(data); -} - -static void workbench_solid_draw_scene(void *vedata) -{ - WORKBENCH_Data *data = vedata; - const int num_samples = workbench_num_viewport_rendering_iterations(data); - - for (int sample = 0; sample < num_samples; sample++) { - workbench_deferred_draw_scene(data); - } - workbench_deferred_draw_finish(data); -} - -static void workbench_solid_engine_free(void) -{ - workbench_deferred_engine_free(); -} - -static void workbench_solid_view_update(void *vedata) -{ - WORKBENCH_Data *data = vedata; - workbench_taa_view_updated(data); -} - -static void workbench_solid_id_update(void *UNUSED(vedata), struct ID *id) -{ - if (GS(id->name) == ID_OB) { - WORKBENCH_ObjectData *oed = (WORKBENCH_ObjectData *)DRW_drawdata_get( - id, &draw_engine_workbench_solid); - if (oed != NULL && oed->dd.recalc != 0) { - oed->shadow_bbox_dirty = (oed->dd.recalc & ID_RECALC_ALL) != 0; - oed->dd.recalc = 0; - } - } -} - -static void workbench_render_to_image(void *vedata, - RenderEngine *engine, - RenderLayer *render_layer, - const rcti *rect) -{ - workbench_render(vedata, engine, render_layer, rect); -} - -static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data); - -DrawEngineType draw_engine_workbench_solid = { - NULL, - NULL, - N_("Workbench"), - &workbench_data_size, - &workbench_solid_engine_init, - &workbench_solid_engine_free, - &workbench_solid_cache_init, - &workbench_solid_cache_populate, - &workbench_solid_cache_finish, - &workbench_solid_draw_scene, - &workbench_solid_view_update, - &workbench_solid_id_update, - &workbench_render_to_image, -}; diff --git a/source/blender/draw/engines/workbench/transparent_mode.c b/source/blender/draw/engines/workbench/transparent_mode.c deleted file mode 100644 index fef1ffded8d..00000000000 --- a/source/blender/draw/engines/workbench/transparent_mode.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - * - * Simple engine for drawing color and/or depth. - * When we only need simple studio shaders. - */ - -#include "DRW_render.h" - -#include "GPU_shader.h" - -#include "workbench_private.h" - -/* Functions */ - -static void workbench_transparent_engine_init(void *vedata) -{ - WORKBENCH_Data *data = vedata; - workbench_forward_engine_init(data); -} - -static void workbench_transparent_cache_init(void *vedata) -{ - - WORKBENCH_Data *data = vedata; - workbench_forward_cache_init(data); -} - -static void workbench_transparent_cache_populate(void *vedata, Object *ob) -{ - WORKBENCH_Data *data = vedata; - workbench_forward_cache_populate(data, ob); -} - -static void workbench_transparent_cache_finish(void *vedata) -{ - WORKBENCH_Data *data = vedata; - workbench_forward_cache_finish(data); -} - -static void workbench_transparent_draw_scene(void *vedata) -{ - WORKBENCH_Data *data = vedata; - const int num_samples = workbench_num_viewport_rendering_iterations(data); - - for (int sample = 0; sample < num_samples; sample++) { - workbench_forward_draw_scene(data); - } - workbench_forward_draw_finish(data); -} - -static void workbench_transparent_engine_free(void) -{ - workbench_forward_engine_free(); -} - -static void workbench_transparent_view_update(void *vedata) -{ - WORKBENCH_Data *data = vedata; - workbench_taa_view_updated(data); -} - -static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data); - -DrawEngineType draw_engine_workbench_transparent = { - NULL, - NULL, - N_("Workbench"), - &workbench_data_size, - &workbench_transparent_engine_init, - &workbench_transparent_engine_free, - &workbench_transparent_cache_init, - &workbench_transparent_cache_populate, - &workbench_transparent_cache_finish, - &workbench_transparent_draw_scene, - &workbench_transparent_view_update, - NULL, - NULL, -}; diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 623a3c0cb15..0ab67d620ee 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -22,133 +22,231 @@ #include "workbench_private.h" +#include "BLI_memblock.h" + #include "DNA_userdef_types.h" #include "ED_view3d.h" +#include "ED_screen.h" #include "UI_resources.h" -#include "GPU_batch.h" +#include "GPU_uniformbuffer.h" /* -------------------------------------------------------------------- */ /** \name World Data * \{ */ -static void workbench_world_data_free(DrawData *dd) +GPUUniformBuffer *workbench_material_ubo_alloc(WORKBENCH_PrivateData *wpd) { - WORKBENCH_WorldData *data = (WORKBENCH_WorldData *)dd; - DRW_UBO_FREE_SAFE(data->world_ubo); + struct GPUUniformBuffer **ubo = BLI_memblock_alloc(wpd->material_ubo); + if (*ubo == NULL) { + *ubo = GPU_uniformbuffer_create(sizeof(WORKBENCH_UBO_Material) * MAX_MATERIAL, NULL, NULL); + } + return *ubo; } -/* Ensure the availability of the world_ubo in the given WORKBENCH_PrivateData - * - * See T70167: Some platforms create threads to upload ubo's. - * - * Reuses the last previous created `world_ubo`. Due to limitations of - * DrawData it will only be reused when there is a world attached to the Scene. - * Future development: The best location would be to store it in the View3D. - * - * We don't cache the data itself as there was no indication that that lead to - * an improvement. - * - * This functions also sets the `WORKBENCH_PrivateData.is_world_ubo_owner` that must - * be respected. - */ -static void workbench_world_data_ubo_ensure(const Scene *scene, WORKBENCH_PrivateData *wpd) +static void workbench_ubo_free(void *elem) { - World *world = scene->world; - if (world) { - WORKBENCH_WorldData *engine_world_data = (WORKBENCH_WorldData *)DRW_drawdata_ensure( - &world->id, - &draw_engine_workbench_solid, - sizeof(WORKBENCH_WorldData), - NULL, - &workbench_world_data_free); - - if (engine_world_data->world_ubo == NULL) { - engine_world_data->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), - &wpd->world_data); - } - else { - DRW_uniformbuffer_update(engine_world_data->world_ubo, &wpd->world_data); - } - - /* Borrow world data ubo */ - wpd->is_world_ubo_owner = false; - wpd->world_ubo = engine_world_data->world_ubo; - } - else { - /* there is no world so we cannot cache the UBO. */ - BLI_assert(!wpd->world_ubo || wpd->is_world_ubo_owner); - if (!wpd->world_ubo) { - wpd->is_world_ubo_owner = true; - wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), &wpd->world_data); - } - } + GPUUniformBuffer **ubo = elem; + DRW_UBO_FREE_SAFE(*ubo); } -static void workbench_world_data_update_shadow_direction_vs(WORKBENCH_PrivateData *wpd) +static void workbench_view_layer_data_free(void *storage) { - WORKBENCH_UBO_World *wd = &wpd->world_data; - float light_direction[3]; - float view_matrix[4][4]; - DRW_view_viewmat_get(NULL, view_matrix, false); + WORKBENCH_ViewLayerData *vldata = (WORKBENCH_ViewLayerData *)storage; + + DRW_UBO_FREE_SAFE(vldata->dof_sample_ubo); + DRW_UBO_FREE_SAFE(vldata->world_ubo); + DRW_UBO_FREE_SAFE(vldata->cavity_sample_ubo); + DRW_TEXTURE_FREE_SAFE(vldata->cavity_jitter_tx); + + BLI_memblock_destroy(vldata->material_ubo_data, NULL); + BLI_memblock_destroy(vldata->material_ubo, workbench_ubo_free); +} - workbench_private_data_get_light_direction(light_direction); +static WORKBENCH_ViewLayerData *workbench_view_layer_data_ensure_ex(struct ViewLayer *view_layer) +{ + WORKBENCH_ViewLayerData **vldata = (WORKBENCH_ViewLayerData **) + DRW_view_layer_engine_data_ensure_ex(view_layer, + (DrawEngineType *)&workbench_view_layer_data_ensure_ex, + &workbench_view_layer_data_free); + + if (*vldata == NULL) { + *vldata = MEM_callocN(sizeof(**vldata), "WORKBENCH_ViewLayerData"); + size_t matbuf_size = sizeof(WORKBENCH_UBO_Material) * MAX_MATERIAL; + (*vldata)->material_ubo_data = BLI_memblock_create_ex(matbuf_size, matbuf_size * 2); + (*vldata)->material_ubo = BLI_memblock_create_ex(sizeof(void *), sizeof(void *) * 8); + (*vldata)->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), NULL); + } - /* Shadow direction. */ - mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, light_direction); + return *vldata; } /* \} */ -void workbench_clear_color_get(float color[4]) +static void workbench_viewvecs_update(float r_viewvecs[3][4]) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene = draw_ctx->scene; + float invproj[4][4]; + const bool is_persp = DRW_view_is_persp_get(NULL); + DRW_view_winmat_get(NULL, invproj, true); + + /* view vectors for the corners of the view frustum. + * Can be used to recreate the world space position easily */ + copy_v4_fl4(r_viewvecs[0], -1.0f, -1.0f, -1.0f, 1.0f); + copy_v4_fl4(r_viewvecs[1], 1.0f, -1.0f, -1.0f, 1.0f); + copy_v4_fl4(r_viewvecs[2], -1.0f, 1.0f, -1.0f, 1.0f); + + /* convert the view vectors to view space */ + for (int i = 0; i < 3; i++) { + mul_m4_v4(invproj, r_viewvecs[i]); + /* normalized trick see: + * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ + mul_v3_fl(r_viewvecs[i], 1.0f / r_viewvecs[i][3]); + if (is_persp) { + mul_v3_fl(r_viewvecs[i], 1.0f / r_viewvecs[i][2]); + } + r_viewvecs[i][3] = 1.0; + } + + /* we need to store the differences */ + r_viewvecs[1][0] -= r_viewvecs[0][0]; + r_viewvecs[1][1] = r_viewvecs[2][1] - r_viewvecs[0][1]; - if (!DRW_state_is_scene_render() || !DRW_state_draw_background()) { - zero_v4(color); + /* calculate a depth offset as well */ + if (!is_persp) { + float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f}; + mul_m4_v4(invproj, vec_far); + mul_v3_fl(vec_far, 1.0f / vec_far[3]); + r_viewvecs[1][2] = vec_far[2] - r_viewvecs[0][2]; } - else if (scene->world) { - copy_v3_v3(color, &scene->world->horr); - color[3] = 1.0f; +} + +static void workbench_studiolight_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd) +{ + StudioLight *studiolight = wpd->studio_light; + float view_matrix[4][4], rot_matrix[4][4]; + DRW_view_viewmat_get(NULL, view_matrix, false); + + if (USE_WORLD_ORIENTATION(wpd)) { + axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z); + mul_m4_m4m4(rot_matrix, view_matrix, rot_matrix); + swap_v3_v3(rot_matrix[2], rot_matrix[1]); + negate_v3(rot_matrix[2]); } else { - zero_v3(color); - color[3] = 1.0f; + unit_m4(rot_matrix); } -} -void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info) -{ - effect_info->jitter_index = 0; - effect_info->view_updated = true; + if (U.edit_studio_light) { + studiolight = BKE_studiolight_studio_edit_get(); + } + + /* Studio Lights. */ + for (int i = 0; i < 4; i++) { + WORKBENCH_UBO_Light *light = &wd->lights[i]; + + SolidLight *sl = (studiolight) ? &studiolight->light[i] : NULL; + if (sl && sl->flag) { + copy_v3_v3(light->light_direction, sl->vec); + mul_mat3_m4_v3(rot_matrix, light->light_direction); + /* We should predivide the power by PI but that makes the lights really dim. */ + copy_v3_v3(light->specular_color, sl->spec); + copy_v3_v3(light->diffuse_color, sl->col); + light->wrapped = sl->smooth; + } + else { + copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f); + copy_v3_fl(light->specular_color, 0.0f); + copy_v3_fl(light->diffuse_color, 0.0f); + } + } + + if (studiolight) { + copy_v3_v3(wd->ambient_color, studiolight->light_ambient); + } + else { + copy_v3_fl(wd->ambient_color, 1.0f); + } + + wd->use_specular = workbench_is_specular_highlight_enabled(wpd); } void workbench_private_data_init(WORKBENCH_PrivateData *wpd) { const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene = draw_ctx->scene; - wpd->material_hash = BLI_ghash_ptr_new(__func__); - wpd->material_transp_hash = BLI_ghash_ptr_new(__func__); + RegionView3D *rv3d = draw_ctx->rv3d; + View3D *v3d = draw_ctx->v3d; + Scene *scene = draw_ctx->scene; + WORKBENCH_ViewLayerData *vldata = workbench_view_layer_data_ensure_ex(draw_ctx->view_layer); + + wpd->is_playback = DRW_state_is_playback(); + wpd->is_navigating = rv3d && (rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)); + + wpd->ctx_mode = CTX_data_mode_enum_ex( + draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode); + wpd->preferences = &U; + wpd->scene = scene; + wpd->sh_cfg = draw_ctx->sh_cfg; + wpd->clip_state = RV3D_CLIPPING_ENABLED(v3d, rv3d) ? DRW_STATE_CLIP_PLANES : 0; + wpd->cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0; + wpd->vldata = vldata; + wpd->world_ubo = vldata->world_ubo; - View3D *v3d = draw_ctx->v3d; - RegionView3D *rv3d = draw_ctx->rv3d; + wpd->taa_sample_len = workbench_antialiasing_sample_count_get(wpd); + + wpd->volumes_do = false; + BLI_listbase_clear(&wpd->smoke_domains); if (!v3d || (v3d->shading.type == OB_RENDER && BKE_scene_uses_blender_workbench(scene))) { + /* FIXME: This reproduce old behavior when workbench was separated in 2 engines. + * But this is a workaround for a missing update tagging from operators. */ + if (scene->display.shading.type != wpd->shading.type || + XRAY_ENABLED(v3d) != XRAY_ENABLED((&scene->display))) { + wpd->view_updated = true; + } + wpd->shading = scene->display.shading; - wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display)); - wpd->use_color_render_settings = true; + if (XRAY_FLAG_ENABLED((&scene->display))) { + wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display)); + } + else { + wpd->shading.xray_alpha = 1.0f; + } + + if (scene->r.alphamode == R_ALPHAPREMUL) { + copy_v4_fl(wpd->background_color, 0.0f); + } + else if (scene->world) { + World *wo = scene->world; + copy_v4_fl4(wpd->background_color, wo->horr, wo->horg, wo->horb, 1.0f); + } + else { + copy_v4_fl4(wpd->background_color, 0.0f, 0.0f, 0.0f, 1.0f); + } } else { + /* FIXME: This reproduce old behavior when workbench was separated in 2 engines. + * But this is a workaround for a missing update tagging from operators. */ + if (v3d->shading.type != wpd->shading.type || XRAY_ENABLED(v3d) != XRAY_ENABLED(wpd)) { + wpd->view_updated = true; + } + wpd->shading = v3d->shading; - wpd->shading.xray_alpha = XRAY_ALPHA(v3d); - wpd->use_color_render_settings = false; - } + if (wpd->shading.type < OB_SOLID) { + wpd->shading.xray_alpha = 0.0f; + } + else if (XRAY_ENABLED(v3d)) { + wpd->shading.xray_alpha = XRAY_ALPHA(v3d); + } + else { + wpd->shading.xray_alpha = 1.0f; + } - wpd->use_color_management = BKE_scene_check_color_management_enabled(scene); + /* No background. The overlays will draw the correct one. */ + copy_v4_fl(wpd->background_color, 0.0f); + } if (wpd->shading.light == V3D_LIGHTING_MATCAP) { wpd->studio_light = BKE_studiolight_find(wpd->shading.matcap, STUDIOLIGHT_TYPE_MATCAP); @@ -162,119 +260,56 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wpd->studio_light = BKE_studiolight_find(wpd->shading.studio_light, STUDIOLIGHT_TYPE_STUDIO); } - float shadow_focus = scene->display.shadow_focus; - /* Clamp to avoid overshadowing and shading errors. */ - CLAMP(shadow_focus, 0.0001f, 0.99999f); - wpd->shadow_shift = scene->display.shadow_shift; - wpd->shadow_focus = 1.0f - shadow_focus * (1.0f - wpd->shadow_shift); - wpd->shadow_multiplier = 1.0 - wpd->shading.shadow_intensity; - - WORKBENCH_UBO_World *wd = &wpd->world_data; - wd->matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) != 0; - - studiolight_update_world(wpd, wpd->studio_light, wd); - - copy_v3_v3(wd->object_outline_color, wpd->shading.object_outline_color); - wd->object_outline_color[3] = 1.0f; - - wd->curvature_ridge = 0.5f / max_ff(square_f(wpd->shading.curvature_ridge_factor), 1e-4f); - wd->curvature_valley = 0.7f / max_ff(square_f(wpd->shading.curvature_valley_factor), 1e-4f); - - /* Will be NULL when rendering. */ - if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { - wpd->world_clip_planes = rv3d->clip; - } - else { - wpd->world_clip_planes = NULL; - } - - workbench_world_data_update_shadow_direction_vs(wpd); - workbench_world_data_ubo_ensure(scene, wpd); - - /* Cavity settings */ { - const int ssao_samples = scene->display.matcap_ssao_samples; - - float invproj[4][4]; - const bool is_persp = DRW_view_is_persp_get(NULL); - /* view vectors for the corners of the view frustum. - * Can be used to recreate the world space position easily */ - float viewvecs[3][4] = { - {-1.0f, -1.0f, -1.0f, 1.0f}, - {1.0f, -1.0f, -1.0f, 1.0f}, - {-1.0f, 1.0f, -1.0f, 1.0f}, - }; - int i; - const float *size = DRW_viewport_size_get(); - - wpd->ssao_params[0] = ssao_samples; - wpd->ssao_params[1] = size[0] / 64.0; - wpd->ssao_params[2] = size[1] / 64.0; - wpd->ssao_params[3] = 0; - - /* distance, factor, factor, attenuation */ - copy_v4_fl4(wpd->ssao_settings, - scene->display.matcap_ssao_distance, - wpd->shading.cavity_valley_factor, - wpd->shading.cavity_ridge_factor, - scene->display.matcap_ssao_attenuation); - - DRW_view_winmat_get(NULL, wpd->winmat, false); - DRW_view_winmat_get(NULL, invproj, true); - - /* convert the view vectors to view space */ - for (i = 0; i < 3; i++) { - mul_m4_v4(invproj, viewvecs[i]); - /* normalized trick see: - * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ - mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]); - if (is_persp) { - mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); - } - viewvecs[i][3] = 1.0; - - copy_v4_v4(wpd->viewvecs[i], viewvecs[i]); - } - - /* we need to store the differences */ - wpd->viewvecs[1][0] -= wpd->viewvecs[0][0]; - wpd->viewvecs[1][1] = wpd->viewvecs[2][1] - wpd->viewvecs[0][1]; - - /* calculate a depth offset as well */ - if (!is_persp) { - float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f}; - mul_m4_v4(invproj, vec_far); - mul_v3_fl(vec_far, 1.0f / vec_far[3]); - wpd->viewvecs[1][2] = vec_far[2] - wpd->viewvecs[0][2]; - } + /* Material UBOs. */ + wpd->material_ubo_data = vldata->material_ubo_data; + wpd->material_ubo = vldata->material_ubo; + wpd->material_chunk_count = 1; + wpd->material_chunk_curr = 0; + wpd->material_index = 1; + /* Create default material ubo. */ + wpd->material_ubo_data_curr = BLI_memblock_alloc(wpd->material_ubo_data); + wpd->material_ubo_curr = workbench_material_ubo_alloc(wpd); + /* Init default material used by vertex color & texture. */ + workbench_material_ubo_data( + wpd, NULL, NULL, &wpd->material_ubo_data_curr[0], V3D_SHADING_MATERIAL_COLOR); } - - wpd->volumes_do = false; - BLI_listbase_clear(&wpd->smoke_domains); } -void workbench_private_data_get_light_direction(float r_light_direction[3]) +void workbench_update_world_ubo(WORKBENCH_PrivateData *wpd) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; + WORKBENCH_UBO_World wd; - copy_v3_v3(r_light_direction, scene->display.light_direction); - SWAP(float, r_light_direction[2], r_light_direction[1]); - r_light_direction[2] = -r_light_direction[2]; - r_light_direction[0] = -r_light_direction[0]; + copy_v2_v2(wd.viewport_size, DRW_viewport_size_get()); + copy_v2_v2(wd.viewport_size_inv, DRW_viewport_invert_size_get()); + copy_v3_v3(wd.object_outline_color, wpd->shading.object_outline_color); + wd.object_outline_color[3] = 1.0f; + wd.ui_scale = G_draw.block.sizePixel; + wd.matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) != 0; + + workbench_studiolight_data_update(wpd, &wd); + workbench_shadow_data_update(wpd, &wd); + workbench_cavity_data_update(wpd, &wd); + workbench_viewvecs_update(wd.viewvecs); + + DRW_uniformbuffer_update(wpd->world_ubo, &wd); } -void workbench_private_data_free(WORKBENCH_PrivateData *wpd) +void workbench_update_material_ubos(WORKBENCH_PrivateData *UNUSED(wpd)) { - BLI_ghash_free(wpd->material_hash, NULL, MEM_freeN); - BLI_ghash_free(wpd->material_transp_hash, NULL, MEM_freeN); - - if (wpd->is_world_ubo_owner) { - DRW_UBO_FREE_SAFE(wpd->world_ubo); - } - else { - wpd->world_ubo = NULL; + const DRWContextState *draw_ctx = DRW_context_state_get(); + WORKBENCH_ViewLayerData *vldata = workbench_view_layer_data_ensure_ex(draw_ctx->view_layer); + + BLI_memblock_iter iter, iter_data; + BLI_memblock_iternew(vldata->material_ubo, &iter); + BLI_memblock_iternew(vldata->material_ubo_data, &iter_data); + WORKBENCH_UBO_Material *matchunk; + while ((matchunk = BLI_memblock_iterstep(&iter_data))) { + GPUUniformBuffer **ubo = BLI_memblock_iterstep(&iter); + BLI_assert(*ubo != NULL); + GPU_uniformbuffer_update(*ubo, matchunk); } - DRW_UBO_FREE_SAFE(wpd->dof_ubo); + BLI_memblock_clear(vldata->material_ubo, workbench_ubo_free); + BLI_memblock_clear(vldata->material_ubo_data, NULL); } diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c deleted file mode 100644 index df9a597faf9..00000000000 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ /dev/null @@ -1,1415 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - */ - -#include "workbench_private.h" - -#include "BLI_alloca.h" -#include "BLI_dynstr.h" -#include "BLI_utildefines.h" -#include "BLI_rand.h" -#include "BLI_string_utils.h" - -#include "BKE_modifier.h" -#include "BKE_object.h" -#include "BKE_paint.h" -#include "BKE_particle.h" - -#include "DNA_image_types.h" -#include "DNA_fluid_types.h" -#include "DNA_mesh_types.h" -#include "DNA_modifier_types.h" -#include "DNA_node_types.h" - -#include "GPU_shader.h" -#include "GPU_texture.h" -#include "GPU_extensions.h" - -#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */ - -/* *********** STATIC *********** */ - -/* #define DEBUG_SHADOW_VOLUME */ - -#ifdef DEBUG_SHADOW_VOLUME -# include "draw_debug.h" -#endif - -typedef struct WORKBENCH_DEFERRED_Shaders { - struct GPUShader *prepass_sh_cache[MAX_PREPASS_SHADERS]; -} WORKBENCH_DEFERRED_Shaders; - -static struct { - WORKBENCH_DEFERRED_Shaders sh_data[GPU_SHADER_CFG_LEN]; - - struct GPUShader *composite_sh_cache[MAX_COMPOSITE_SHADERS]; - struct GPUShader *cavity_sh[MAX_CAVITY_SHADERS]; - struct GPUShader *background_sh[2]; - struct GPUShader *ghost_resolve_sh; - struct GPUShader *shadow_fail_sh; - struct GPUShader *shadow_fail_manifold_sh; - struct GPUShader *shadow_pass_sh; - struct GPUShader *shadow_pass_manifold_sh; - struct GPUShader *shadow_caps_sh; - struct GPUShader *shadow_caps_manifold_sh; - struct GPUShader *oit_resolve_sh; - - /* TODO(fclem) move everything below to wpd and custom viewlayer data. */ - struct GPUTexture *oit_accum_tx; /* ref only, not alloced */ - struct GPUTexture *oit_revealage_tx; /* ref only, not alloced */ - struct GPUTexture *object_id_tx; /* ref only, not alloced */ - struct GPUTexture *color_buffer_tx; /* ref only, not alloced */ - struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */ - struct GPUTexture *normal_buffer_tx; /* ref only, not alloced */ - struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */ - - SceneDisplay display; /* world light direction for shadows */ - - struct GPUUniformBuffer *sampling_ubo; - struct GPUTexture *jitter_tx; - int cached_sample_num; -} e_data = {{{{NULL}}}}; - -/* Shaders */ -extern char datatoc_common_hair_lib_glsl[]; -extern char datatoc_common_view_lib_glsl[]; - -extern char datatoc_workbench_prepass_vert_glsl[]; -extern char datatoc_workbench_prepass_frag_glsl[]; -extern char datatoc_workbench_cavity_frag_glsl[]; -extern char datatoc_workbench_forward_composite_frag_glsl[]; -extern char datatoc_workbench_deferred_composite_frag_glsl[]; -extern char datatoc_workbench_deferred_background_frag_glsl[]; -extern char datatoc_workbench_ghost_resolve_frag_glsl[]; - -extern char datatoc_workbench_shadow_vert_glsl[]; -extern char datatoc_workbench_shadow_geom_glsl[]; -extern char datatoc_workbench_shadow_caps_geom_glsl[]; -extern char datatoc_workbench_shadow_debug_frag_glsl[]; - -extern char datatoc_workbench_cavity_lib_glsl[]; -extern char datatoc_workbench_common_lib_glsl[]; -extern char datatoc_workbench_data_lib_glsl[]; -extern char datatoc_workbench_object_outline_lib_glsl[]; -extern char datatoc_workbench_curvature_lib_glsl[]; -extern char datatoc_workbench_world_light_lib_glsl[]; - -extern char datatoc_gpu_shader_depth_only_frag_glsl[]; - -static char *workbench_build_composite_frag(WORKBENCH_PrivateData *wpd) -{ - DynStr *ds = BLI_dynstr_new(); - - BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); - - if (!FLAT_ENABLED(wpd)) { - BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl); - } - if (OBJECT_OUTLINE_ENABLED(wpd)) { - BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl); - } - if (CURVATURE_ENABLED(wpd)) { - BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl); - } - - BLI_dynstr_append(ds, datatoc_workbench_deferred_composite_frag_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static char *workbench_build_prepass_frag(void) -{ - DynStr *ds = BLI_dynstr_new(); - - BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_prepass_frag_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static char *workbench_build_prepass_vert(bool is_hair) -{ - DynStr *ds = BLI_dynstr_new(); - if (is_hair) { - BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl); - } - BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl); - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static char *workbench_build_cavity_frag(bool cavity, bool curvature, bool high_dpi) -{ - DynStr *ds = BLI_dynstr_new(); - - if (cavity) { - BLI_dynstr_append(ds, "#define USE_CAVITY\n"); - } - if (curvature) { - BLI_dynstr_append(ds, "#define USE_CURVATURE\n"); - } - if (high_dpi) { - BLI_dynstr_append(ds, "#define CURVATURE_OFFSET 2\n"); - } - if (NORMAL_ENCODING_ENABLED()) { - BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n"); - } - BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_cavity_frag_glsl); - BLI_dynstr_append(ds, datatoc_workbench_cavity_lib_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static GPUShader *workbench_cavity_shader_get(bool cavity, bool curvature) -{ - const bool high_dpi = (U.pixelsize > 1.5f); - int index = 0; - SET_FLAG_FROM_TEST(index, cavity, 1 << 0); - SET_FLAG_FROM_TEST(index, curvature, 1 << 1); - SET_FLAG_FROM_TEST(index, high_dpi, 1 << 2); - - GPUShader **sh = &e_data.cavity_sh[index]; - if (*sh == NULL) { - char *cavity_frag = workbench_build_cavity_frag(cavity, curvature, high_dpi); - *sh = DRW_shader_create_fullscreen(cavity_frag, NULL); - MEM_freeN(cavity_frag); - } - return *sh; -} - -static GPUShader *ensure_deferred_prepass_shader(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override, - eGPUShaderConfig sh_cfg) -{ - WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - int index = workbench_material_get_prepass_shader_index( - wpd, is_uniform_color, is_hair, is_tiled, color_override); - if (sh_data->prepass_sh_cache[index] == NULL) { - const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; - char *defines = workbench_material_build_defines( - wpd, is_uniform_color, is_hair, is_tiled, color_override); - char *prepass_vert = workbench_build_prepass_vert(is_hair); - char *prepass_frag = workbench_build_prepass_frag(); - sh_data->prepass_sh_cache[index] = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, prepass_vert, NULL}, - .frag = (const char *[]){prepass_frag, NULL}, - .defs = (const char *[]){sh_cfg_data->def, defines, NULL}, - }); - MEM_freeN(prepass_vert); - MEM_freeN(prepass_frag); - MEM_freeN(defines); - } - return sh_data->prepass_sh_cache[index]; -} - -static GPUShader *ensure_deferred_composite_shader(WORKBENCH_PrivateData *wpd) -{ - int index = workbench_material_get_composite_shader_index(wpd); - if (e_data.composite_sh_cache[index] == NULL) { - char *defines = workbench_material_build_defines( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF); - char *composite_frag = workbench_build_composite_frag(wpd); - e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); - MEM_freeN(composite_frag); - MEM_freeN(defines); - } - return e_data.composite_sh_cache[index]; -} - -static GPUShader *ensure_background_shader(WORKBENCH_PrivateData *wpd) -{ - const int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0; - if (e_data.background_sh[index] == NULL) { - const char *defines = (index) ? "#define V3D_SHADING_OBJECT_OUTLINE\n" : NULL; - char *frag = BLI_string_joinN(datatoc_workbench_data_lib_glsl, - datatoc_workbench_common_lib_glsl, - datatoc_workbench_object_outline_lib_glsl, - datatoc_workbench_deferred_background_frag_glsl); - e_data.background_sh[index] = DRW_shader_create_fullscreen(frag, defines); - MEM_freeN(frag); - } - return e_data.background_sh[index]; -} - -static void select_deferred_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg) -{ - wpd->prepass_sh = ensure_deferred_prepass_shader( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->prepass_hair_sh = ensure_deferred_prepass_shader( - wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->prepass_uniform_sh = ensure_deferred_prepass_shader( - wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->prepass_uniform_hair_sh = ensure_deferred_prepass_shader( - wpd, true, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->prepass_textured_sh = ensure_deferred_prepass_shader( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg); - wpd->prepass_textured_array_sh = ensure_deferred_prepass_shader( - wpd, false, false, true, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg); - wpd->prepass_vertex_sh = ensure_deferred_prepass_shader( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg); - wpd->composite_sh = ensure_deferred_composite_shader(wpd); - wpd->background_sh = ensure_background_shader(wpd); -} - -/* Using Hammersley distribution */ -static float *create_disk_samples(int num_samples, int num_iterations) -{ - /* vec4 to ensure memory alignment. */ - const int total_samples = num_samples * num_iterations; - float(*texels)[4] = MEM_mallocN(sizeof(float[4]) * total_samples, __func__); - const float num_samples_inv = 1.0f / num_samples; - - for (int i = 0; i < total_samples; i++) { - float it_add = (i / num_samples) * 0.499f; - float r = fmodf((i + 0.5f + it_add) * num_samples_inv, 1.0f); - double dphi; - BLI_hammersley_1d(i, &dphi); - - float phi = (float)dphi * 2.0f * M_PI + it_add; - texels[i][0] = cosf(phi); - texels[i][1] = sinf(phi); - /* This deliberately distribute more samples - * at the center of the disk (and thus the shadow). */ - texels[i][2] = r; - } - - return (float *)texels; -} - -static struct GPUTexture *create_jitter_texture(int num_samples) -{ - float jitter[64 * 64][4]; - const float num_samples_inv = 1.0f / num_samples; - - for (int i = 0; i < 64 * 64; i++) { - float phi = blue_noise[i][0] * 2.0f * M_PI; - /* This rotate the sample per pixels */ - jitter[i][0] = cosf(phi); - jitter[i][1] = sinf(phi); - /* This offset the sample along it's direction axis (reduce banding) */ - float bn = blue_noise[i][1] - 0.5f; - CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */ - jitter[i][2] = bn * num_samples_inv; - jitter[i][3] = blue_noise[i][1]; - } - - UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral); - - return DRW_texture_create_2d(64, 64, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]); -} -/* Functions */ - -static void workbench_init_object_data(DrawData *dd) -{ - WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd; - data->shadow_bbox_dirty = true; -} - -static void workbench_init_oit_framebuffer(WORKBENCH_FramebufferList *fbl, - DefaultTextureList *dtxl) -{ - const float *size = DRW_viewport_size_get(); - e_data.oit_accum_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid); - e_data.oit_revealage_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_R16F, &draw_engine_workbench_solid); - - GPU_framebuffer_ensure_config(&fbl->transparent_accum_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(e_data.oit_accum_tx), - GPU_ATTACHMENT_TEXTURE(e_data.oit_revealage_tx), - }); -} - -void workbench_deferred_engine_init(WORKBENCH_Data *vedata) -{ - WORKBENCH_FramebufferList *fbl = vedata->fbl; - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - const DRWContextState *draw_ctx = DRW_context_state_get(); - RegionView3D *rv3d = draw_ctx->rv3d; - View3D *v3d = draw_ctx->v3d; - Scene *scene = draw_ctx->scene; - Object *camera; - - if (v3d && rv3d) { - camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL; - } - else { - camera = scene->camera; - } - - if (!stl->g_data) { - /* Alloc transient pointers */ - stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); - } - if (!stl->effects) { - stl->effects = MEM_callocN(sizeof(*stl->effects), __func__); - workbench_effect_info_init(stl->effects); - } - - if (!e_data.shadow_pass_sh) { - WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - memset(sh_data->prepass_sh_cache, 0, sizeof(sh_data->prepass_sh_cache)); - memset(e_data.composite_sh_cache, 0, sizeof(e_data.composite_sh_cache)); -#ifdef DEBUG_SHADOW_VOLUME - const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl; -#else - const char *shadow_frag = datatoc_gpu_shader_depth_only_frag_glsl; -#endif - /* TODO only compile on demand */ - e_data.shadow_pass_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_workbench_shadow_vert_glsl, - NULL}, - .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL}, - .frag = (const char *[]){shadow_frag, NULL}, - .defs = (const char *[]){"#define SHADOW_PASS\n" - "#define DOUBLE_MANIFOLD\n", - NULL}, - }); - e_data.shadow_pass_manifold_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_workbench_shadow_vert_glsl, - NULL}, - .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL}, - .frag = (const char *[]){shadow_frag, NULL}, - .defs = (const char *[]){"#define SHADOW_PASS\n", NULL}, - }); - e_data.shadow_fail_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_workbench_shadow_vert_glsl, - NULL}, - .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL}, - .frag = (const char *[]){shadow_frag, NULL}, - .defs = (const char *[]){"#define SHADOW_FAIL\n" - "#define DOUBLE_MANIFOLD\n", - NULL}, - }); - e_data.shadow_fail_manifold_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_workbench_shadow_vert_glsl, - NULL}, - .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL}, - .frag = (const char *[]){shadow_frag, NULL}, - .defs = (const char *[]){"#define SHADOW_FAIL\n", NULL}, - }); - e_data.shadow_caps_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_workbench_shadow_vert_glsl, - NULL}, - .geom = (const char *[]){datatoc_workbench_shadow_caps_geom_glsl, NULL}, - .frag = (const char *[]){shadow_frag, NULL}, - .defs = (const char *[]){"#define SHADOW_FAIL\n" - "#define DOUBLE_MANIFOLD\n", - NULL}, - }); - e_data.shadow_caps_manifold_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_workbench_shadow_vert_glsl, - NULL}, - .geom = (const char *[]){datatoc_workbench_shadow_caps_geom_glsl, NULL}, - .frag = (const char *[]){shadow_frag, NULL}, - .defs = (const char *[]){"#define SHADOW_FAIL\n", NULL}, - }); - - e_data.ghost_resolve_sh = DRW_shader_create_fullscreen( - datatoc_workbench_ghost_resolve_frag_glsl, NULL); - } - workbench_volume_engine_init(); - workbench_fxaa_engine_init(); - workbench_taa_engine_init(vedata); - - WORKBENCH_PrivateData *wpd = stl->g_data; - workbench_private_data_init(wpd); - - wpd->shading.xray_alpha = 1.0f; - - workbench_dof_engine_init(vedata, camera); - - if (OIT_ENABLED(wpd)) { - if (e_data.oit_resolve_sh == NULL) { - e_data.oit_resolve_sh = DRW_shader_create_fullscreen( - datatoc_workbench_forward_composite_frag_glsl, "#define ALPHA_COMPOSITE\n"); - } - - workbench_forward_choose_shaders(wpd, draw_ctx->sh_cfg); - workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg); - } - - { - const float *viewport_size = DRW_viewport_size_get(); - const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; - const eGPUTextureFormat nor_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16 : GPU_RGBA32F; - const eGPUTextureFormat comp_tex_format = GPU_RGBA16F; - const eGPUTextureFormat col_tex_format = workbench_color_texture_format(wpd); - const eGPUTextureFormat id_tex_format = OBJECT_ID_PASS_ENABLED(wpd) ? GPU_R32UI : GPU_R8; - - e_data.object_id_tx = NULL; - e_data.color_buffer_tx = NULL; - e_data.composite_buffer_tx = NULL; - e_data.normal_buffer_tx = NULL; - e_data.cavity_buffer_tx = NULL; - - e_data.composite_buffer_tx = DRW_texture_pool_query_2d( - size[0], size[1], comp_tex_format, &draw_engine_workbench_solid); - - if (workbench_is_matdata_pass_enabled(wpd) || GPU_unused_fb_slot_workaround()) { - e_data.color_buffer_tx = DRW_texture_pool_query_2d( - size[0], size[1], col_tex_format, &draw_engine_workbench_solid); - } - if (OBJECT_ID_PASS_ENABLED(wpd) || GPU_unused_fb_slot_workaround()) { - e_data.object_id_tx = DRW_texture_pool_query_2d( - size[0], size[1], id_tex_format, &draw_engine_workbench_solid); - } - if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) { - e_data.normal_buffer_tx = DRW_texture_pool_query_2d( - size[0], size[1], nor_tex_format, &draw_engine_workbench_solid); - } - if (CAVITY_ENABLED(wpd)) { - e_data.cavity_buffer_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_R16, &draw_engine_workbench_solid); - } - - GPU_framebuffer_ensure_config(&fbl->prepass_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx), - GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), - GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx), - }); - GPU_framebuffer_ensure_config(&fbl->cavity_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.cavity_buffer_tx), - }); - GPU_framebuffer_ensure_config(&fbl->composite_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx), - }); - GPU_framebuffer_ensure_config(&fbl->color_only_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx), - }); - - if (!workbench_is_matdata_pass_enabled(wpd) && !GPU_unused_fb_slot_workaround()) { - e_data.color_buffer_tx = DRW_texture_pool_query_2d( - size[0], size[1], col_tex_format, &draw_engine_workbench_solid); - } - - GPU_framebuffer_ensure_config(&fbl->effect_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx), - }); - - if (OBJECT_ID_PASS_ENABLED(wpd)) { - GPU_framebuffer_ensure_config(&fbl->id_clear_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), - }); - } - } - - { - /* AO Samples Tex */ - int num_iterations = workbench_taa_calculate_num_iterations(vedata); - - const int ssao_samples_single_iteration = scene->display.matcap_ssao_samples; - const int ssao_samples = MIN2(num_iterations * ssao_samples_single_iteration, 500); - - if (e_data.sampling_ubo && (e_data.cached_sample_num != ssao_samples)) { - DRW_UBO_FREE_SAFE(e_data.sampling_ubo); - DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx); - } - - if (e_data.sampling_ubo == NULL) { - float *samples = create_disk_samples(ssao_samples_single_iteration, num_iterations); - e_data.jitter_tx = create_jitter_texture(ssao_samples); - e_data.sampling_ubo = DRW_uniformbuffer_create(sizeof(float[4]) * ssao_samples, samples); - e_data.cached_sample_num = ssao_samples; - MEM_freeN(samples); - } - } - - /* Prepass */ - { - DRWShadingGroup *grp; - DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0; - DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0; - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - - psl->prepass_pass = DRW_pass_create("Prepass", state | cull_state | clip_state); - psl->prepass_hair_pass = DRW_pass_create("Prepass", state | clip_state); - - psl->ghost_prepass_pass = DRW_pass_create("Prepass Ghost", state | cull_state | clip_state); - psl->ghost_prepass_hair_pass = DRW_pass_create("Prepass Ghost", state | clip_state); - - psl->ghost_resolve_pass = DRW_pass_create("Resolve Ghost Depth", - DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); - grp = DRW_shgroup_create(e_data.ghost_resolve_sh, psl->ghost_resolve_pass); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth_in_front); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - - { - workbench_aa_create_pass(vedata, &e_data.color_buffer_tx); - } - - { - workbench_dof_create_pass(vedata, &e_data.composite_buffer_tx, e_data.jitter_tx); - } - - if (CAVITY_ENABLED(wpd)) { - int state = DRW_STATE_WRITE_COLOR; - GPUShader *shader = workbench_cavity_shader_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd)); - psl->cavity_pass = DRW_pass_create("Cavity", state); - DRWShadingGroup *grp = DRW_shgroup_create(shader, psl->cavity_pass); - DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx); - DRW_shgroup_uniform_block(grp, "samples_block", e_data.sampling_ubo); - - if (SSAO_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); - DRW_shgroup_uniform_vec4(grp, "ssao_params", wpd->ssao_params, 1); - DRW_shgroup_uniform_vec4(grp, "ssao_settings", wpd->ssao_settings, 1); - DRW_shgroup_uniform_mat4(grp, "WinMatrix", wpd->winmat); - DRW_shgroup_uniform_texture(grp, "ssao_jitter", e_data.jitter_tx); - } - - if (CURVATURE_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); - DRW_shgroup_uniform_vec2(grp, "curvature_settings", &wpd->world_data.curvature_ridge, 1); - } - - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } -} - -void workbench_deferred_engine_free(void) -{ - for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) { - WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[sh_data_index]; - for (int index = 0; index < MAX_PREPASS_SHADERS; index++) { - DRW_SHADER_FREE_SAFE(sh_data->prepass_sh_cache[index]); - } - } - for (int index = 0; index < MAX_COMPOSITE_SHADERS; index++) { - DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]); - } - for (int index = 0; index < MAX_CAVITY_SHADERS; index++) { - DRW_SHADER_FREE_SAFE(e_data.cavity_sh[index]); - } - DRW_SHADER_FREE_SAFE(e_data.ghost_resolve_sh); - DRW_UBO_FREE_SAFE(e_data.sampling_ubo); - DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx); - DRW_SHADER_FREE_SAFE(e_data.background_sh[0]); - DRW_SHADER_FREE_SAFE(e_data.background_sh[1]); - - DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh); - - DRW_SHADER_FREE_SAFE(e_data.shadow_pass_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_pass_manifold_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_fail_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_fail_manifold_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_caps_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_caps_manifold_sh); - - workbench_volume_engine_free(); - workbench_fxaa_engine_free(); - workbench_taa_engine_free(); - workbench_dof_engine_free(); -} - -static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp) -{ - DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - if (workbench_is_matdata_pass_enabled(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "materialBuffer", &e_data.color_buffer_tx); - } - else { - DRW_shgroup_uniform_vec3(grp, "materialSingleColor", wpd->shading.single_color, 1); - } - if (OBJECT_OUTLINE_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); - } - if (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx); - } - if (CAVITY_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "cavityBuffer", &e_data.cavity_buffer_tx); - } - if (workbench_is_specular_highlight_enabled(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); - } - if (workbench_is_specular_highlight_enabled(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - } - if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { - BKE_studiolight_ensure_flag(wpd->studio_light, - STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE | - STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE); - DRW_shgroup_uniform_texture( - grp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture); - if (workbench_is_specular_highlight_enabled(wpd)) { - DRW_shgroup_uniform_texture( - grp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture); - } - } -} - -void workbench_deferred_cache_init(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; - DRWShadingGroup *grp; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - Scene *scene = draw_ctx->scene; - - workbench_volume_cache_init(vedata); - select_deferred_shaders(wpd, draw_ctx->sh_cfg); - - /* Background Pass */ - { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL; - if (DRW_state_is_scene_render()) { - /* Composite the scene over cleared background. */ - state |= DRW_STATE_BLEND_ALPHA_PREMUL; - } - psl->background_pass = DRW_pass_create("Background", state); - grp = DRW_shgroup_create(wpd->background_sh, psl->background_pass); - DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - if (OBJECT_OUTLINE_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); - } - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - - /* Deferred Mix Pass */ - { - workbench_private_data_get_light_direction(e_data.display.light_direction); - studiolight_update_light(wpd, e_data.display.light_direction); - - if (SHADOW_ENABLED(wpd)) { - psl->composite_pass = DRW_pass_create( - "Composite", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL | DRW_STATE_DEPTH_GREATER); - grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); - workbench_composite_uniforms(wpd, grp); - DRW_shgroup_stencil_mask(grp, 0x00); - DRW_shgroup_uniform_float_copy(grp, "lightMultiplier", 1.0f); - DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1); - DRW_shgroup_uniform_float_copy(grp, "shadowShift", scene->display.shadow_shift); - DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - - /* Stencil Shadow passes. */ -#ifdef DEBUG_SHADOW_VOLUME - DRWState depth_pass_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_COLOR | - DRW_STATE_BLEND_ADD; - DRWState depth_fail_state = DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_WRITE_COLOR | - DRW_STATE_BLEND_ADD; -#else - DRWState depth_pass_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_PASS | - DRW_STATE_STENCIL_ALWAYS; - DRWState depth_fail_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_FAIL | - DRW_STATE_STENCIL_ALWAYS; -#endif - psl->shadow_depth_pass_pass = DRW_pass_create("Shadow Pass", depth_pass_state); - psl->shadow_depth_pass_mani_pass = DRW_pass_create("Shadow Pass Mani", depth_pass_state); - psl->shadow_depth_fail_pass = DRW_pass_create("Shadow Fail", depth_fail_state); - psl->shadow_depth_fail_mani_pass = DRW_pass_create("Shadow Fail Mani", depth_fail_state); - psl->shadow_depth_fail_caps_pass = DRW_pass_create("Shadow Fail Caps", depth_fail_state); - psl->shadow_depth_fail_caps_mani_pass = DRW_pass_create("Shadow Fail Caps Mani", - depth_fail_state); - -#ifndef DEBUG_SHADOW_VOLUME - grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - grp = DRW_shgroup_create(e_data.shadow_pass_manifold_sh, psl->shadow_depth_pass_mani_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - grp = DRW_shgroup_create(e_data.shadow_fail_manifold_sh, psl->shadow_depth_fail_mani_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - grp = DRW_shgroup_create(e_data.shadow_caps_sh, psl->shadow_depth_fail_caps_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - grp = DRW_shgroup_create(e_data.shadow_caps_manifold_sh, - psl->shadow_depth_fail_caps_mani_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - - psl->composite_shadow_pass = DRW_pass_create( - "Composite Shadow", - DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL | DRW_STATE_DEPTH_GREATER); - grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_shadow_pass); - DRW_shgroup_stencil_mask(grp, 0x00); - workbench_composite_uniforms(wpd, grp); - DRW_shgroup_uniform_float(grp, "lightMultiplier", &wpd->shadow_multiplier, 1); - DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1); - DRW_shgroup_uniform_float_copy(grp, "shadowShift", scene->display.shadow_shift); - DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); -#endif - } - else { - psl->composite_pass = DRW_pass_create("Composite", - DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER); - grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); - workbench_composite_uniforms(wpd, grp); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - } - - /** - * Order Independent Transparency. - * Similar to workbench forward. Duplicated code to avoid - * spaghetti with workbench forward. It would be great if we unify - * this in a clean way. - */ - if (OIT_ENABLED(wpd)) { - DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0; - DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0; - /* Transparency Accum */ - { - /* Same as forward but here we use depth test to - * not bleed through other solid objects. */ - int state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND_OIT | cull_state | - clip_state; - psl->transparent_accum_pass = DRW_pass_create("Transparent Accum", state); - } - /* Depth */ - { - int state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state | clip_state; - psl->object_outline_pass = DRW_pass_create("Transparent Depth", state); - } - /* OIT Composite */ - { - int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL; - psl->oit_composite_pass = DRW_pass_create("OIT Composite", state); - - grp = DRW_shgroup_create(e_data.oit_resolve_sh, psl->oit_composite_pass); - DRW_shgroup_uniform_texture_ref(grp, "transparentAccum", &e_data.oit_accum_tx); - DRW_shgroup_uniform_texture_ref(grp, "transparentRevealage", &e_data.oit_revealage_tx); - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - } -} - -static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedata, - Object *ob, - Material *mat, - Image *ima, - ImageUser *iuser, - eV3DShadingColorType color_type, - int interp) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; - WORKBENCH_MaterialData *material; - WORKBENCH_MaterialData material_template; - const bool is_ghost = (ob->dtx & OB_DRAWXRAY); - - /* Solid */ - workbench_material_update_data(wpd, ob, mat, &material_template, color_type); - material_template.color_type = color_type; - material_template.ima = ima; - material_template.iuser = iuser; - material_template.interp = interp; - uint hash = workbench_material_get_hash(&material_template, is_ghost); - - material = BLI_ghash_lookup(wpd->material_hash, POINTER_FROM_UINT(hash)); - if (material == NULL) { - material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__); - /* select the correct prepass shader */ - GPUShader *shader = (wpd->shading.color_type == color_type) ? wpd->prepass_sh : - wpd->prepass_uniform_sh; - const bool is_tiled = (ima && ima->source == IMA_SRC_TILED); - if (color_type == V3D_SHADING_TEXTURE_COLOR) { - shader = is_tiled ? wpd->prepass_textured_array_sh : wpd->prepass_textured_sh; - } - if (color_type == V3D_SHADING_VERTEX_COLOR) { - shader = wpd->prepass_vertex_sh; - } - material->shgrp = DRW_shgroup_create( - shader, (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass); - workbench_material_copy(material, &material_template); - DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF); - workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, is_tiled, interp); - BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material); - } - return material; -} - -static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; - - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type != eModifierType_ParticleSystem) { - continue; - } - ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; - if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) { - continue; - } - ParticleSettings *part = psys->part; - const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - - if (draw_as == PART_DRAW_PATH) { - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, part->omat, &image, &iuser, &interp, &mat); - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, false); - WORKBENCH_MaterialData *material = get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp); - - struct GPUShader *shader = (wpd->shading.color_type == color_type) ? - wpd->prepass_hair_sh : - wpd->prepass_uniform_hair_sh; - DRWShadingGroup *shgrp = DRW_shgroup_hair_create( - ob, - psys, - md, - (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_hair_pass : psl->prepass_hair_pass, - shader); - DRW_shgroup_stencil_mask(shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF); - workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, false, interp); - } - } -} - -static void workbench_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - Scene *scene = draw_ctx->scene; - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - WORKBENCH_MaterialData *material; - - /* Force workbench to render active object textured when in texture paint mode */ - const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - - /* Single Image mode */ - if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) { - Image *image = imapaint->canvas; - int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : - SHD_INTERP_CLOSEST; - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, use_sculpt_pbvh); - struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); - material = get_or_create_material_data(vedata, ob, NULL, image, NULL, color_type, interp); - - DRW_shgroup_call(material->shgrp, geom, ob); - } - else { - /* IMAGEPAINT_MODE_MATERIAL */ - const int materials_len = DRW_cache_object_material_count_get(ob); - struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); - for (int i = 0; i < materials_len; i++) { - if (geom_array != NULL && geom_array[i] != NULL) { - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, use_sculpt_pbvh); - material = get_or_create_material_data(vedata, ob, mat, image, iuser, color_type, interp); - DRW_shgroup_call(material->shgrp, geom_array[i], ob); - } - } - } -} - -static void workbench_cache_populate_vertex_paint_mode(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - WORKBENCH_MaterialData *material; - - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, NULL, ob, use_sculpt_pbvh); - struct GPUBatch *geom = DRW_cache_mesh_surface_vertpaint_get(ob); - material = get_or_create_material_data(vedata, ob, NULL, NULL, NULL, color_type, false); - DRW_shgroup_call(material->shgrp, geom, ob); -} - -void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - - if (!DRW_object_is_renderable(ob)) { - return; - } - - if (ob->type == OB_MESH) { - workbench_cache_populate_particles(vedata, ob); - } - - ModifierData *md; - if (((ob->base_flag & BASE_FROM_DUPLI) == 0) && - (md = modifiers_findByType(ob, eModifierType_Fluid)) && - (modifier_isEnabled(scene, md, eModifierMode_Realtime)) && - (((FluidModifierData *)md)->domain != NULL) && - (((FluidModifierData *)md)->domain->type == FLUID_DOMAIN_TYPE_GAS)) { - workbench_volume_cache_populate(vedata, scene, ob, md); - return; /* Do not draw solid in this case. */ - } - - if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { - return; - } - if ((ob->dt < OB_SOLID) && !DRW_state_is_scene_render()) { - return; - } - - WORKBENCH_MaterialData *material; - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { - const bool is_active = (ob == draw_ctx->obact); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - const bool use_hide = is_active && DRW_object_use_hide_faces(ob); - const int materials_len = DRW_cache_object_material_count_get(ob); - const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; - bool has_transp_mat = false; - const WORKBENCH_ColorOverride color_override = workbench_object_color_override_get(ob); - const bool use_texture_paint_drawing = !(DRW_state_is_image_render() && - draw_ctx->v3d == NULL) && - (color_override == WORKBENCH_COLOR_OVERRIDE_TEXTURE) && - me && me->mloopuv; - const bool use_vertex_paint_drawing = !(DRW_state_is_image_render() && - draw_ctx->v3d == NULL) && - (color_override == WORKBENCH_COLOR_OVERRIDE_VERTEX) && - me && me->mloopcol; - - if (use_texture_paint_drawing) { - workbench_cache_populate_texture_paint_mode(vedata, ob); - } - else if (use_vertex_paint_drawing) { - workbench_cache_populate_vertex_paint_mode(vedata, ob); - } - else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { - /* Draw textured */ - struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); - for (int i = 0; i < materials_len; i++) { - if (geom_array != NULL && geom_array[i] != NULL) { - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, use_sculpt_pbvh); - if (color_type == V3D_SHADING_MATERIAL_COLOR && mat && mat->a < 1.0) { - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, 0); - has_transp_mat = true; - } - else { - material = get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp); - } - DRW_shgroup_call(material->shgrp, geom_array[i], ob); - } - } - } - else if (ELEM(wpd->shading.color_type, - V3D_SHADING_SINGLE_COLOR, - V3D_SHADING_OBJECT_COLOR, - V3D_SHADING_RANDOM_COLOR, - V3D_SHADING_VERTEX_COLOR)) { - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, NULL, ob, use_sculpt_pbvh); - - if ((ob->color[3] < 1.0f) && (color_type == V3D_SHADING_OBJECT_COLOR)) { - material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, 0); - has_transp_mat = true; - } - else { - /* Draw solid color */ - material = get_or_create_material_data(vedata, ob, NULL, NULL, NULL, color_type, 0); - } - - if (use_sculpt_pbvh) { - bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR); - DRW_shgroup_call_sculpt(material->shgrp, ob, false, false, use_vcol); - } - else { - struct GPUBatch *geom; - if (color_type == V3D_SHADING_VERTEX_COLOR) { - geom = DRW_cache_mesh_surface_vertpaint_get(ob); - } - else { - geom = DRW_cache_object_surface_get(ob); - } - - if (geom) { - DRW_shgroup_call(material->shgrp, geom, ob); - } - } - } - else { - /* Draw material color */ - if (use_sculpt_pbvh) { - struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len); - - for (int i = 0; i < materials_len; i++) { - struct Material *mat = BKE_object_material_get(ob, i + 1); - if (mat != NULL && mat->a < 1.0f) { - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - has_transp_mat = true; - } - else { - material = get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - } - shgrps[i] = material->shgrp; - } - DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false); - } - else { - struct GPUBatch **geoms; - struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); - memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len); - - geoms = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len); - for (int i = 0; i < materials_len; i++) { - if (geoms != NULL && geoms[i] != NULL) { - Material *mat = BKE_object_material_get(ob, i + 1); - if (mat != NULL && mat->a < 1.0f) { - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - has_transp_mat = true; - } - else { - material = get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - } - DRW_shgroup_call(material->shgrp, geoms[i], ob); - } - } - } - } - - if (SHADOW_ENABLED(wpd) && !(ob->dtx & OB_DRAW_NO_SHADOW_CAST)) { - bool is_manifold; - struct GPUBatch *geom_shadow = DRW_cache_object_edge_detection_get(ob, &is_manifold); - if (geom_shadow) { - if (use_sculpt_pbvh || use_hide) { - /* Currently unsupported in sculpt mode. We could revert to the slow - * method in this case but I'm not sure if it's a good idea given that - * sculpted meshes are heavy to begin with. */ - // DRW_shgroup_call_sculpt(wpd->shadow_shgrp, ob, ob->obmat); - } - else { - 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)) { - - mul_v3_mat3_m4v3( - engine_object_data->shadow_dir, ob->imat, e_data.display.light_direction); - - DRWShadingGroup *grp; - bool use_shadow_pass_technique = !studiolight_camera_in_object_shadow( - wpd, ob, engine_object_data); - - if (use_shadow_pass_technique && !has_transp_mat) { - if (is_manifold) { - grp = DRW_shgroup_create(e_data.shadow_pass_manifold_sh, - psl->shadow_depth_pass_mani_pass); - } - else { - grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass); - } - DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); - DRW_shgroup_uniform_float_copy(grp, "lightDistance", 1e5f); - DRW_shgroup_call_no_cull(grp, geom_shadow, ob); -#ifdef DEBUG_SHADOW_VOLUME - DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){1.0f, 0.0f, 0.0f, 1.0f}); -#endif - } - else { - float extrude_distance = studiolight_object_shadow_distance( - wpd, ob, engine_object_data); - - /* TODO(fclem): only use caps if they are in the view frustum. */ - const bool need_caps = true; - if (need_caps) { - if (is_manifold) { - grp = DRW_shgroup_create(e_data.shadow_caps_manifold_sh, - psl->shadow_depth_fail_caps_mani_pass); - } - else { - grp = DRW_shgroup_create(e_data.shadow_caps_sh, - psl->shadow_depth_fail_caps_pass); - } - DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); - DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance); - DRW_shgroup_call_no_cull(grp, DRW_cache_object_surface_get(ob), ob); - } - - if (is_manifold) { - grp = DRW_shgroup_create(e_data.shadow_fail_manifold_sh, - psl->shadow_depth_fail_mani_pass); - } - else { - grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass); - } - DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); - DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance); - DRW_shgroup_call_no_cull(grp, geom_shadow, ob); -#ifdef DEBUG_SHADOW_VOLUME - DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){0.0f, 1.0f, 0.0f, 1.0f}); -#endif - } - } - } - } - } - } -} - -void workbench_deferred_cache_finish(WORKBENCH_Data *vedata) -{ - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_FramebufferList *fbl = vedata->fbl; - - if (GHOST_ENABLED(psl)) { - /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */ - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - - DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0); - - GPU_framebuffer_ensure_config( - &dfbl->default_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); - GPU_framebuffer_ensure_config( - &dfbl->in_front_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); - - GPU_framebuffer_ensure_config(&fbl->ghost_prepass_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), - GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx), - GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), - GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx), - }); - } -} - -void workbench_deferred_draw_scene(WORKBENCH_Data *vedata) -{ - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_FramebufferList *fbl = vedata->fbl; - WORKBENCH_PrivateData *wpd = stl->g_data; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - - if (workbench_is_taa_enabled(wpd)) { - workbench_taa_draw_scene_start(vedata); - } - - const float clear_depth = 1.0f; - const float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - uint clear_stencil = 0x00; - int clear_bits = GPU_DEPTH_BIT; - SET_FLAG_FROM_TEST(clear_bits, SHADOW_ENABLED(wpd), GPU_STENCIL_BIT); - - if (OBJECT_ID_PASS_ENABLED(wpd)) { - /* From all the color buffers, only object id needs to be cleared. */ - GPU_framebuffer_bind(fbl->id_clear_fb); - GPU_framebuffer_clear_color(fbl->id_clear_fb, clear_col); - } - - GPU_framebuffer_bind(fbl->prepass_fb); - GPU_framebuffer_clear(fbl->prepass_fb, clear_bits, clear_col, clear_depth, clear_stencil); - - DRW_draw_pass(psl->prepass_pass); - DRW_draw_pass(psl->prepass_hair_pass); - - if (fbl->ghost_prepass_fb) { - GPU_framebuffer_bind(fbl->ghost_prepass_fb); - GPU_framebuffer_clear_depth(fbl->ghost_prepass_fb, 1.0f); - } - else if (dtxl->depth_in_front) { - /* TODO(fclem) This clear should be done in a global place. */ - GPU_framebuffer_bind(dfbl->in_front_fb); - GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f); - } - - if (GHOST_ENABLED(psl)) { - DRW_draw_pass(psl->ghost_prepass_pass); - DRW_draw_pass(psl->ghost_prepass_hair_pass); - - GPU_framebuffer_bind(dfbl->depth_only_fb); - DRW_draw_pass(psl->ghost_resolve_pass); - } - - if (CAVITY_ENABLED(wpd)) { - GPU_framebuffer_bind(fbl->cavity_fb); - DRW_draw_pass(psl->cavity_pass); - } - - if (DRW_state_is_scene_render()) { - float clear_color[4]; - workbench_clear_color_get(clear_color); - GPU_framebuffer_bind(fbl->composite_fb); - GPU_framebuffer_clear_color(fbl->composite_fb, clear_color); - } - - if (SHADOW_ENABLED(wpd)) { -#ifdef DEBUG_SHADOW_VOLUME - GPU_framebuffer_bind(fbl->composite_fb); - DRW_draw_pass(psl->composite_pass); -#else - GPU_framebuffer_bind(dfbl->depth_only_fb); -#endif - DRW_draw_pass(psl->shadow_depth_pass_pass); - DRW_draw_pass(psl->shadow_depth_pass_mani_pass); - DRW_draw_pass(psl->shadow_depth_fail_pass); - DRW_draw_pass(psl->shadow_depth_fail_mani_pass); - DRW_draw_pass(psl->shadow_depth_fail_caps_pass); - DRW_draw_pass(psl->shadow_depth_fail_caps_mani_pass); - - if (GHOST_ENABLED(psl)) { - /* We need to set the stencil buffer to 0 where Ghost objects are - * else they will get shadow and even badly shadowed. */ - DRWState state = DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; - DRW_pass_state_set(psl->ghost_prepass_pass, state); - DRW_pass_state_set(psl->ghost_prepass_hair_pass, state); - - DRW_draw_pass(psl->ghost_prepass_pass); - DRW_draw_pass(psl->ghost_prepass_hair_pass); - } -#ifndef DEBUG_SHADOW_VOLUME - GPU_framebuffer_bind(fbl->composite_fb); - DRW_draw_pass(psl->composite_pass); - DRW_draw_pass(psl->composite_shadow_pass); -#endif - } - else { - GPU_framebuffer_bind(fbl->composite_fb); - DRW_draw_pass(psl->composite_pass); - } - - /* In order to not draw on top of ghost objects, we clear the stencil - * to 0xFF and the ghost object to 0x00 and only draw overlays on top if - * stencil is not 0. */ - /* TODO(fclem) Remove this hack. */ - GPU_framebuffer_bind(dfbl->depth_only_fb); - GPU_framebuffer_clear_stencil(dfbl->depth_only_fb, 0xFF); - - /* TODO(fclem): only enable when needed (when there is overlays). */ - if (GHOST_ENABLED(psl)) { - DRWState state = DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; - DRW_pass_state_set(psl->ghost_prepass_pass, state); - DRW_pass_state_set(psl->ghost_prepass_hair_pass, state); - - DRW_draw_pass(psl->ghost_prepass_pass); - DRW_draw_pass(psl->ghost_prepass_hair_pass); - } - - GPU_framebuffer_bind(fbl->composite_fb); - DRW_draw_pass(psl->background_pass); - - if (OIT_ENABLED(wpd) && !DRW_pass_is_empty(psl->transparent_accum_pass)) { - /* meh, late init to not request buffers we won't use. */ - workbench_init_oit_framebuffer(fbl, dtxl); - - const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - GPU_framebuffer_bind(fbl->transparent_accum_fb); - GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color); - DRW_draw_pass(psl->transparent_accum_pass); - - GPU_framebuffer_bind(fbl->composite_fb); - DRW_draw_pass(psl->oit_composite_pass); - } - - if (wpd->volumes_do) { - GPU_framebuffer_bind(fbl->color_only_fb); - DRW_draw_pass(psl->volume_pass); - } - - workbench_dof_draw_pass(vedata); - workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx); -} - -void workbench_deferred_draw_finish(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - - /* XXX TODO(fclem) do not discard UBOS after drawing! Store them per viewport. */ - workbench_private_data_free(wpd); - workbench_volume_smoke_textures_free(wpd); -} diff --git a/source/blender/draw/engines/workbench/workbench_effect_aa.c b/source/blender/draw/engines/workbench/workbench_effect_aa.c deleted file mode 100644 index c03fe5cd5c8..00000000000 --- a/source/blender/draw/engines/workbench/workbench_effect_aa.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - */ - -#include "ED_screen.h" - -#include "draw_color_management.h" - -#include "workbench_private.h" - -void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_EffectInfo *effect_info = stl->effects; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - if (draw_ctx->evil_C != NULL) { - struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); - wpd->is_playback = ED_screen_animation_playing(wm) != NULL; - } - else { - wpd->is_playback = false; - } - - if (workbench_is_taa_enabled(wpd)) { - psl->effect_aa_pass = workbench_taa_create_pass(vedata, tx); - } - else if (workbench_is_fxaa_enabled(wpd)) { - psl->effect_aa_pass = workbench_fxaa_create_pass(tx); - effect_info->jitter_index = 0; - } - else { - psl->effect_aa_pass = NULL; - effect_info->jitter_index = 0; - } -} - -static void workspace_aa_draw_transform(GPUTexture *tx, WORKBENCH_PrivateData *UNUSED(wpd)) -{ - DRW_transform_none(tx); -} - -void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - WORKBENCH_FramebufferList *fbl = vedata->fbl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_EffectInfo *effect_info = stl->effects; - - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - if (workbench_is_fxaa_enabled(wpd)) { - GPU_framebuffer_bind(fbl->effect_fb); - workspace_aa_draw_transform(tx, wpd); - GPU_framebuffer_bind(dfbl->color_only_fb); - DRW_draw_pass(psl->effect_aa_pass); - } - else if (workbench_is_taa_enabled(wpd)) { - /* - * when drawing the first TAA frame, we transform directly to the - * color_only_fb as the TAA shader is just performing a direct copy. - * the workbench_taa_draw_screen_end will fill the history buffer - * for the other iterations. - */ - if (effect_info->jitter_index == 1) { - GPU_framebuffer_bind(dfbl->color_only_fb); - workspace_aa_draw_transform(tx, wpd); - } - else { - GPU_framebuffer_bind(fbl->effect_fb); - workspace_aa_draw_transform(tx, wpd); - GPU_framebuffer_bind(dfbl->color_only_fb); - DRW_draw_pass(psl->effect_aa_pass); - } - workbench_taa_draw_scene_end(vedata); - } - else { - GPU_framebuffer_bind(dfbl->color_only_fb); - workspace_aa_draw_transform(tx, wpd); - } -} diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c new file mode 100644 index 00000000000..3cd21dfeace --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c @@ -0,0 +1,421 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Anti-aliasing: + * + * We use SMAA (Smart Morphological Anti-Aliasing) as a fast antialiasing solution. + * + * If the viewport stays static, the engine ask for multiple redraw and will progressively + * converge to a much more accurate image without aliasing. + * We call this one TAA (Temporal Anti-Aliasing). + * + * This is done using an accumulation buffer and a final pass that will output the final color + * to the scene buffer. We softly blend between SMAA and TAA to avoid really harsh transitions. + */ + +#include "ED_screen.h" + +#include "BLI_jitter_2d.h" + +#include "smaa_textures.h" + +#include "workbench_private.h" + +static struct { + bool init; + float jitter_5[5][2]; + float jitter_8[8][2]; + float jitter_11[11][2]; + float jitter_16[16][2]; + float jitter_32[32][2]; +} e_data = {false}; + +static void workbench_taa_jitter_init_order(float (*table)[2], int num) +{ + BLI_jitter_init(table, num); + + /* find closest element to center */ + int closest_index = 0; + float closest_squared_distance = 1.0f; + + for (int index = 0; index < num; index++) { + const float squared_dist = square_f(table[index][0]) + square_f(table[index][1]); + if (squared_dist < closest_squared_distance) { + closest_squared_distance = squared_dist; + closest_index = index; + } + } + + /* move jitter table so that closest sample is in center */ + for (int index = 0; index < num; index++) { + sub_v2_v2(table[index], table[closest_index]); + mul_v2_fl(table[index], 2.0f); + } + + /* swap center sample to the start of the table */ + if (closest_index != 0) { + swap_v2_v2(table[0], table[closest_index]); + } + + /* sort list based on furtest distance with previous */ + for (int i = 0; i < num - 2; i++) { + float f_squared_dist = 0.0; + int f_index = i; + for (int j = i + 1; j < num; j++) { + const float squared_dist = square_f(table[i][0] - table[j][0]) + + square_f(table[i][1] - table[j][1]); + if (squared_dist > f_squared_dist) { + f_squared_dist = squared_dist; + f_index = j; + } + } + swap_v2_v2(table[i + 1], table[f_index]); + } +} + +static void workbench_taa_jitter_init(void) +{ + if (e_data.init == false) { + e_data.init = true; + workbench_taa_jitter_init_order(e_data.jitter_5, 5); + workbench_taa_jitter_init_order(e_data.jitter_8, 8); + workbench_taa_jitter_init_order(e_data.jitter_11, 11); + workbench_taa_jitter_init_order(e_data.jitter_16, 16); + workbench_taa_jitter_init_order(e_data.jitter_32, 32); + } +} + +int workbench_antialiasing_sample_count_get(WORKBENCH_PrivateData *wpd) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + + if (wpd->is_navigating || wpd->is_playback) { + /* Only draw using SMAA or no AA when navigating. */ + return min_ii(wpd->preferences->viewport_aa, 1); + } + else if (DRW_state_is_image_render()) { + if (draw_ctx->v3d) { + return scene->display.viewport_aa; + } + else { + return scene->display.render_aa; + } + } + else { + return wpd->preferences->viewport_aa; + } +} + +void workbench_antialiasing_view_updated(WORKBENCH_Data *vedata) +{ + WORKBENCH_StorageList *stl = vedata->stl; + if (stl && stl->wpd) { + stl->wpd->view_updated = true; + } +} + +void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata) +{ + WORKBENCH_FramebufferList *fbl = vedata->fbl; + WORKBENCH_TextureList *txl = vedata->txl; + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + DrawEngineType *owner = (DrawEngineType *)&workbench_antialiasing_engine_init; + + wpd->view = NULL; + + /* reset complete drawing when navigating. */ + if (wpd->taa_sample != 0) { + if (wpd->is_navigating) { + wpd->taa_sample = 0; + } + } + + if (wpd->view_updated) { + wpd->taa_sample = 0; + wpd->view_updated = false; + } + + { + float persmat[4][4]; + DRW_view_persmat_get(NULL, persmat, false); + if (!equals_m4m4(persmat, wpd->last_mat)) { + copy_m4_m4(wpd->last_mat, persmat); + wpd->taa_sample = 0; + } + } + + if (wpd->taa_sample_len > 0) { + workbench_taa_jitter_init(); + + DRW_texture_ensure_fullscreen_2d(&txl->history_buffer_tx, GPU_RGBA16F, DRW_TEX_FILTER); + DRW_texture_ensure_fullscreen_2d(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0); + + wpd->smaa_edge_tx = DRW_texture_pool_query_fullscreen(GPU_RG8, owner); + wpd->smaa_weight_tx = DRW_texture_pool_query_fullscreen(GPU_RGBA8, owner); + + GPU_framebuffer_ensure_config(&fbl->antialiasing_fb, + { + GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx), + GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx), + }); + + GPU_framebuffer_ensure_config(&fbl->smaa_edge_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(wpd->smaa_edge_tx), + }); + + GPU_framebuffer_ensure_config(&fbl->smaa_weight_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(wpd->smaa_weight_tx), + }); + + /* TODO could be shared for all viewports. */ + if (txl->smaa_search_tx == NULL) { + txl->smaa_search_tx = GPU_texture_create_nD(SEARCHTEX_WIDTH, + SEARCHTEX_HEIGHT, + 0, + 2, + searchTexBytes, + GPU_R8, + GPU_DATA_UNSIGNED_BYTE, + 0, + false, + NULL); + + txl->smaa_area_tx = GPU_texture_create_nD(AREATEX_WIDTH, + AREATEX_HEIGHT, + 0, + 2, + areaTexBytes, + GPU_RG8, + GPU_DATA_UNSIGNED_BYTE, + 0, + false, + NULL); + + GPU_texture_bind(txl->smaa_search_tx, 0); + GPU_texture_filter_mode(txl->smaa_search_tx, true); + GPU_texture_unbind(txl->smaa_search_tx); + + GPU_texture_bind(txl->smaa_area_tx, 0); + GPU_texture_filter_mode(txl->smaa_area_tx, true); + GPU_texture_unbind(txl->smaa_area_tx); + } + } + else { + /* Cleanup */ + DRW_TEXTURE_FREE_SAFE(txl->history_buffer_tx); + DRW_TEXTURE_FREE_SAFE(txl->depth_buffer_tx); + DRW_TEXTURE_FREE_SAFE(txl->smaa_search_tx); + DRW_TEXTURE_FREE_SAFE(txl->smaa_area_tx); + } +} + +void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata) +{ + WORKBENCH_TextureList *txl = vedata->txl; + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + WORKBENCH_PassList *psl = vedata->psl; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DRWShadingGroup *grp = NULL; + + if (wpd->taa_sample_len == 0) { + return; + } + + { + DRW_PASS_CREATE(psl->aa_accum_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL); + + GPUShader *shader = workbench_shader_antialiasing_accumulation_get(); + grp = DRW_shgroup_create(shader, psl->aa_accum_ps); + DRW_shgroup_uniform_texture(grp, "colorBuffer", dtxl->color); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + + const float *size = DRW_viewport_size_get(); + const float *sizeinv = DRW_viewport_invert_size_get(); + float metrics[4] = {sizeinv[0], sizeinv[1], size[0], size[1]}; + + { + /* Stage 1: Edge detection. */ + DRW_PASS_CREATE(psl->aa_edge_ps, DRW_STATE_WRITE_COLOR); + + GPUShader *sh = workbench_shader_antialiasing_get(0); + grp = DRW_shgroup_create(sh, psl->aa_edge_ps); + DRW_shgroup_uniform_texture(grp, "colorTex", txl->history_buffer_tx); + DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); + + DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + { + /* Stage 2: Blend Weight/Coord. */ + DRW_PASS_CREATE(psl->aa_weight_ps, DRW_STATE_WRITE_COLOR); + + GPUShader *sh = workbench_shader_antialiasing_get(1); + grp = DRW_shgroup_create(sh, psl->aa_weight_ps); + DRW_shgroup_uniform_texture(grp, "edgesTex", wpd->smaa_edge_tx); + DRW_shgroup_uniform_texture(grp, "areaTex", txl->smaa_area_tx); + DRW_shgroup_uniform_texture(grp, "searchTex", txl->smaa_search_tx); + DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); + + DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + { + /* Stage 3: Resolve. */ + DRW_PASS_CREATE(psl->aa_resolve_ps, DRW_STATE_WRITE_COLOR); + + GPUShader *sh = workbench_shader_antialiasing_get(2); + grp = DRW_shgroup_create(sh, psl->aa_resolve_ps); + DRW_shgroup_uniform_texture(grp, "blendTex", wpd->smaa_weight_tx); + DRW_shgroup_uniform_texture(grp, "colorTex", txl->history_buffer_tx); + DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); + DRW_shgroup_uniform_float(grp, "mixFactor", &wpd->smaa_mix_factor, 1); + DRW_shgroup_uniform_float(grp, "taaSampleCountInv", &wpd->taa_sample_inv, 1); + + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } +} + +/* Return true if render is not cached. */ +bool workbench_antialiasing_setup(WORKBENCH_Data *vedata) +{ + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + + if (wpd->taa_sample_len == 0) { + /* AA disabled. */ + return true; + } + + if (wpd->taa_sample >= wpd->taa_sample_len) { + /* TAA accumulation has finish. Just copy the result back */ + return false; + } + else { + const float *viewport_size = DRW_viewport_size_get(); + const DRWView *default_view = DRW_view_default_get(); + float *transform_offset; + + switch (wpd->taa_sample_len) { + default: + case 5: + transform_offset = e_data.jitter_5[min_ii(wpd->taa_sample, 5)]; + break; + case 8: + transform_offset = e_data.jitter_8[min_ii(wpd->taa_sample, 8)]; + break; + case 11: + transform_offset = e_data.jitter_11[min_ii(wpd->taa_sample, 11)]; + break; + case 16: + transform_offset = e_data.jitter_16[min_ii(wpd->taa_sample, 16)]; + break; + case 32: + transform_offset = e_data.jitter_32[min_ii(wpd->taa_sample, 32)]; + break; + } + + /* construct new matrices from transform delta */ + float winmat[4][4], viewmat[4][4], persmat[4][4]; + DRW_view_winmat_get(default_view, winmat, false); + DRW_view_viewmat_get(default_view, viewmat, false); + DRW_view_persmat_get(default_view, persmat, false); + + window_translate_m4(winmat, + persmat, + transform_offset[0] / viewport_size[0], + transform_offset[1] / viewport_size[1]); + + if (wpd->view) { + /* When rendering just update the view. This avoids recomputing the culling. */ + DRW_view_update_sub(wpd->view, viewmat, winmat); + } + else { + /* TAA is not making a big change to the matrices. + * Reuse the main view culling by creating a sub-view. */ + wpd->view = DRW_view_create_sub(default_view, viewmat, winmat); + } + DRW_view_set_active(wpd->view); + return true; + } +} + +void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata) +{ + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + WORKBENCH_FramebufferList *fbl = vedata->fbl; + WORKBENCH_PassList *psl = vedata->psl; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + + if (wpd->taa_sample_len == 0) { + /* AA disabled. */ + /* Just set sample to 1 to avoid rendering indefinitely. */ + wpd->taa_sample = 1; + return; + } + + /** + * We always do SMAA on top of TAA accumulation, unless the number of samples of TAA is already + * high. This ensure a smoother transition. + * If TAA accumulation is finished, we only blit the result. + */ + + if (wpd->taa_sample == 0) { + /* In playback mode, we are sure the next redraw will not use the same viewmatrix. + * In this case no need to save the depth buffer. */ + eGPUFrameBufferBits bits = GPU_COLOR_BIT | (!wpd->is_playback ? GPU_DEPTH_BIT : 0); + GPU_framebuffer_blit(dfbl->default_fb, 0, fbl->antialiasing_fb, 0, bits); + } + else { + /* Accumulate result to the TAA buffer. */ + GPU_framebuffer_bind(fbl->antialiasing_fb); + DRW_draw_pass(psl->aa_accum_ps); + /* Copy back the saved depth buffer for correct overlays. */ + GPU_framebuffer_blit(fbl->antialiasing_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT); + } + + if (!DRW_state_is_image_render() || wpd->taa_sample + 1 == wpd->taa_sample_len) { + /* After a certain point SMAA is no longer necessary. */ + wpd->smaa_mix_factor = 1.0f - clamp_f(wpd->taa_sample / 4.0f, 0.0f, 1.0f); + wpd->taa_sample_inv = 1.0f / (wpd->taa_sample + 1); + + if (wpd->smaa_mix_factor > 0.0f) { + GPU_framebuffer_bind(fbl->smaa_edge_fb); + DRW_draw_pass(psl->aa_edge_ps); + + GPU_framebuffer_bind(fbl->smaa_weight_fb); + DRW_draw_pass(psl->aa_weight_ps); + } + + GPU_framebuffer_bind(dfbl->default_fb); + DRW_draw_pass(psl->aa_resolve_ps); + } + + wpd->taa_sample++; + + if (!DRW_state_is_image_render() && wpd->taa_sample < wpd->taa_sample_len) { + DRW_viewport_request_redraw(); + } +} diff --git a/source/blender/draw/engines/workbench/workbench_effect_cavity.c b/source/blender/draw/engines/workbench/workbench_effect_cavity.c new file mode 100644 index 00000000000..cdf8a93fc57 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_effect_cavity.c @@ -0,0 +1,182 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Cavity Effect: + * + * We use Screen Space Ambient Occlusion (SSAO) to enhance geometric details of the surfaces. + * We also use a Curvature effect computed only using the surface normals. + * + * This is done after the opaque pass. It only affects the opaque surfaces. + */ + +#include "DRW_render.h" + +#include "BLI_rand.h" + +#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */ + +#include "workbench_engine.h" +#include "workbench_private.h" + +#define JITTER_TEX_SIZE 64 +#define CAVITY_MAX_SAMPLES 512 + +/* Using Hammersley distribution */ +static float *create_disk_samples(int num_samples, int num_iterations) +{ + const int total_samples = num_samples * num_iterations; + const float num_samples_inv = 1.0f / num_samples; + /* vec4 to ensure memory alignment. */ + float(*texels)[4] = MEM_callocN(sizeof(float[4]) * CAVITY_MAX_SAMPLES, __func__); + + for (int i = 0; i < total_samples; i++) { + float it_add = (i / num_samples) * 0.499f; + float r = fmodf((i + 0.5f + it_add) * num_samples_inv, 1.0f); + double dphi; + BLI_hammersley_1d(i, &dphi); + + float phi = (float)dphi * 2.0f * M_PI + it_add; + texels[i][0] = cosf(phi); + texels[i][1] = sinf(phi); + /* This deliberately distribute more samples + * at the center of the disk (and thus the shadow). */ + texels[i][2] = r; + } + + return (float *)texels; +} + +static struct GPUTexture *create_jitter_texture(int num_samples) +{ + float jitter[64 * 64][4]; + const float num_samples_inv = 1.0f / num_samples; + + for (int i = 0; i < 64 * 64; i++) { + float phi = blue_noise[i][0] * 2.0f * M_PI; + /* This rotate the sample per pixels */ + jitter[i][0] = cosf(phi); + jitter[i][1] = sinf(phi); + /* This offset the sample along it's direction axis (reduce banding) */ + float bn = blue_noise[i][1] - 0.5f; + CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */ + jitter[i][2] = bn * num_samples_inv; + jitter[i][3] = blue_noise[i][1]; + } + + UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral); + + return DRW_texture_create_2d(64, 64, GPU_RGBA16F, DRW_TEX_WRAP, &jitter[0][0]); +} + +BLI_INLINE int workbench_cavity_total_sample_count(const WORKBENCH_PrivateData *wpd, + const Scene *scene) +{ + return min_ii(max_ii(1, wpd->taa_sample_len) * scene->display.matcap_ssao_samples, + CAVITY_MAX_SAMPLES); +} + +void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd) +{ + View3DShading *shading = &wpd->shading; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + + if (CAVITY_ENABLED(wpd)) { + int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples; + int cavity_sample_count_total = workbench_cavity_total_sample_count(wpd, scene); + int max_iter_count = cavity_sample_count_total / cavity_sample_count_single_iteration; + + int sample = wpd->taa_sample % max_iter_count; + wd->cavity_sample_start = cavity_sample_count_single_iteration * sample; + wd->cavity_sample_end = cavity_sample_count_single_iteration * (sample + 1); + + wd->cavity_sample_count_inv = 1.0f / (wd->cavity_sample_end - wd->cavity_sample_start); + wd->cavity_jitter_scale = 1.0f / 64.0f; + + wd->cavity_valley_factor = shading->cavity_valley_factor; + wd->cavity_ridge_factor = shading->cavity_ridge_factor; + wd->cavity_attenuation = scene->display.matcap_ssao_attenuation; + wd->cavity_distance = scene->display.matcap_ssao_distance; + + wd->curvature_ridge = 0.5f / max_ff(square_f(shading->curvature_ridge_factor), 1e-4f); + wd->curvature_valley = 0.7f / max_ff(square_f(shading->curvature_valley_factor), 1e-4f); + } +} + +void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + + int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples; + int cavity_sample_count = workbench_cavity_total_sample_count(wpd, scene); + + if (wpd->vldata->cavity_sample_count != cavity_sample_count) { + DRW_UBO_FREE_SAFE(wpd->vldata->cavity_sample_ubo); + DRW_TEXTURE_FREE_SAFE(wpd->vldata->cavity_jitter_tx); + } + + if (wpd->vldata->cavity_sample_ubo == NULL) { + float *samples = create_disk_samples(cavity_sample_count_single_iteration, + max_ii(1, wpd->taa_sample_len)); + wpd->vldata->cavity_jitter_tx = create_jitter_texture(cavity_sample_count); + /* NOTE: Uniform buffer needs to always be filled to be valid. */ + wpd->vldata->cavity_sample_ubo = DRW_uniformbuffer_create( + sizeof(float[4]) * CAVITY_MAX_SAMPLES, samples); + wpd->vldata->cavity_sample_count = cavity_sample_count; + MEM_freeN(samples); + } +} + +void workbench_cavity_cache_init(WORKBENCH_Data *data) +{ + WORKBENCH_PassList *psl = data->psl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + struct GPUShader *sh; + DRWShadingGroup *grp; + + if (CAVITY_ENABLED(wpd)) { + workbench_cavity_samples_ubo_ensure(wpd); + + int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL; + DRW_PASS_CREATE(psl->cavity_ps, state); + + sh = workbench_shader_cavity_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd)); + + grp = DRW_shgroup_create(sh, psl->cavity_ps); + DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx); + DRW_shgroup_uniform_block(grp, "samples_block", wpd->vldata->cavity_sample_ubo); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); + + if (SSAO_ENABLED(wpd)) { + DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth); + DRW_shgroup_uniform_texture(grp, "cavityJitter", wpd->vldata->cavity_jitter_tx); + } + if (CURVATURE_ENABLED(wpd)) { + DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx); + } + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + else { + psl->cavity_ps = NULL; + } +} diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c index ae3e2218463..9716ccd4b44 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_dof.c +++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c @@ -18,6 +18,17 @@ /** \file * \ingroup draw_engine + * + * Depth of Field Effect: + * + * We use a gather approach by sampling a lowres version of the color buffer. + * The process can be summarized like this: + * - down-sample the color buffer using a COC (Circle of Confusion) aware down-sample algorithm. + * - do a gather pass using the COC computed in the previous pass. + * - do a median filter to reduce noise amount. + * - composite on top of main color buffer. + * + * This is done after all passes and affects every surfaces. */ #include "workbench_private.h" @@ -27,24 +38,6 @@ #include "DNA_camera_types.h" -/* *********** STATIC *********** */ -static struct { - struct GPUShader *effect_dof_prepare_sh; - struct GPUShader *effect_dof_downsample_sh; - struct GPUShader *effect_dof_flatten_v_sh; - struct GPUShader *effect_dof_flatten_h_sh; - struct GPUShader *effect_dof_dilate_v_sh; - struct GPUShader *effect_dof_dilate_h_sh; - struct GPUShader *effect_dof_blur1_sh; - struct GPUShader *effect_dof_blur2_sh; - struct GPUShader *effect_dof_resolve_sh; -} e_data = {NULL}; - -/* Shaders */ -extern char datatoc_workbench_effect_dof_frag_glsl[]; - -/* *********** Functions *********** */ - /** * Transform [-1..1] square to unit circle. */ @@ -130,52 +123,40 @@ static void workbench_dof_setup_samples(struct GPUUniformBuffer **ubo, DRW_uniformbuffer_update(*ubo, *data); } -void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) +void workbench_dof_engine_init(WORKBENCH_Data *vedata) { WORKBENCH_TextureList *txl = vedata->txl; WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; + WORKBENCH_PrivateData *wpd = stl->wpd; WORKBENCH_FramebufferList *fbl = vedata->fbl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + RegionView3D *rv3d = draw_ctx->rv3d; + View3D *v3d = draw_ctx->v3d; + Scene *scene = draw_ctx->scene; + Object *camera; + + if (v3d && rv3d) { + camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL; + } + else { + camera = scene->camera; + } + Camera *cam = camera != NULL ? camera->data : NULL; if ((wpd->shading.flag & V3D_SHADING_DEPTH_OF_FIELD) == 0 || (cam == NULL) || ((cam->dof.flag & CAM_DOF_ENABLED) == 0)) { wpd->dof_enabled = false; - return; - } - - if (e_data.effect_dof_prepare_sh == NULL) { - e_data.effect_dof_prepare_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define PREPARE\n"); - - e_data.effect_dof_downsample_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define DOWNSAMPLE\n"); - - e_data.effect_dof_flatten_v_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define FLATTEN_VERTICAL\n"); - - e_data.effect_dof_flatten_h_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define FLATTEN_HORIZONTAL\n"); - - e_data.effect_dof_dilate_v_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define DILATE_VERTICAL\n"); - - e_data.effect_dof_dilate_h_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define DILATE_HORIZONTAL\n"); - e_data.effect_dof_blur1_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define BLUR1\n"); - - e_data.effect_dof_blur2_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define BLUR2\n"); - - e_data.effect_dof_resolve_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define RESOLVE\n"); + /* Cleanup. */ + DRW_TEXTURE_FREE_SAFE(txl->dof_source_tx); + DRW_TEXTURE_FREE_SAFE(txl->coc_halfres_tx); + return; } const float *full_size = DRW_viewport_size_get(); int size[2] = {max_ii(1, (int)full_size[0] / 2), max_ii(1, (int)full_size[1] / 2)}; -#if 0 +#if 0 /* TODO(fclem) finish COC min_max optimisation */ /* NOTE: We Ceil here in order to not miss any edge texel if using a NPO2 texture. */ int shrink_h_size[2] = {ceilf(size[0] / 8.0f), size[1]}; int shrink_w_size[2] = {shrink_h_size[0], ceilf(size[1] / 8.0f)}; @@ -186,14 +167,14 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) DRW_texture_ensure_2d( &txl->coc_halfres_tx, size[0], size[1], GPU_RG8, DRW_TEX_FILTER | DRW_TEX_MIPMAP); wpd->dof_blur_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid); -#if 0 + size[0], size[1], GPU_RGBA16F, &draw_engine_workbench); +#if 0 /* TODO(fclem) finish COC min_max optimisation */ wpd->coc_temp_tx = DRW_texture_pool_query_2d( - shrink_h_size[0], shrink_h_size[1], GPU_RG8, &draw_engine_workbench_solid); + shrink_h_size[0], shrink_h_size[1], GPU_RG8, &draw_engine_workbench); wpd->coc_tiles_tx[0] = DRW_texture_pool_query_2d( - shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid); + shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench); wpd->coc_tiles_tx[1] = DRW_texture_pool_query_2d( - shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid); + shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench); #endif GPU_framebuffer_ensure_config(&fbl->dof_downsample_fb, @@ -202,7 +183,7 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) GPU_ATTACHMENT_TEXTURE(txl->dof_source_tx), GPU_ATTACHMENT_TEXTURE(txl->coc_halfres_tx), }); -#if 0 +#if 0 /* TODO(fclem) finish COC min_max optimisation */ GPU_framebuffer_ensure_config(&fbl->dof_coc_tile_h_fb, { GPU_ATTACHMENT_NONE, @@ -231,11 +212,7 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) }); { - const DRWContextState *draw_ctx = DRW_context_state_get(); - RegionView3D *rv3d = draw_ctx->rv3d; - /* Parameters */ - /* TODO UI Options */ float fstop = cam->dof.aperture_fstop; float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y); float focus_dist = BKE_camera_object_dof_distance(camera); @@ -263,128 +240,125 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) float rotation = cam->dof.aperture_rotation; float ratio = 1.0f / cam->dof.aperture_ratio; - if (wpd->dof_ubo == NULL || blades != wpd->dof_blades || rotation != wpd->dof_rotation || - ratio != wpd->dof_ratio) { + if (wpd->vldata->dof_sample_ubo == NULL || blades != wpd->dof_blades || + rotation != wpd->dof_rotation || ratio != wpd->dof_ratio) { wpd->dof_blades = blades; wpd->dof_rotation = rotation; wpd->dof_ratio = ratio; - workbench_dof_setup_samples(&wpd->dof_ubo, &stl->dof_ubo_data, blades, rotation, ratio); + workbench_dof_setup_samples( + &wpd->vldata->dof_sample_ubo, &stl->dof_ubo_data, blades, rotation, ratio); } } wpd->dof_enabled = true; } -void workbench_dof_create_pass(WORKBENCH_Data *vedata, - GPUTexture **dof_input, - GPUTexture *noise_tex) +void workbench_dof_cache_init(WORKBENCH_Data *vedata) { WORKBENCH_PassList *psl = vedata->psl; WORKBENCH_TextureList *txl = vedata->txl; WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); + WORKBENCH_PrivateData *wpd = stl->wpd; if (!wpd->dof_enabled) { return; } - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + GPUShader *prepare_sh, *downsample_sh, *blur1_sh, *blur2_sh, *resolve_sh; + workbench_shader_depth_of_field_get( + &prepare_sh, &downsample_sh, &blur1_sh, &blur2_sh, &resolve_sh); - psl->dof_down_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR); - psl->dof_down2_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR); - psl->dof_flatten_h_ps = DRW_pass_create("DoF Flatten Coc H", DRW_STATE_WRITE_COLOR); - psl->dof_flatten_v_ps = DRW_pass_create("DoF Flatten Coc V", DRW_STATE_WRITE_COLOR); - psl->dof_dilate_h_ps = DRW_pass_create("DoF Dilate Coc H", DRW_STATE_WRITE_COLOR); - psl->dof_dilate_v_ps = DRW_pass_create("DoF Dilate Coc V", DRW_STATE_WRITE_COLOR); - psl->dof_blur1_ps = DRW_pass_create("DoF Blur 1", DRW_STATE_WRITE_COLOR); - psl->dof_blur2_ps = DRW_pass_create("DoF Blur 2", DRW_STATE_WRITE_COLOR); - psl->dof_resolve_ps = DRW_pass_create("DoF Resolve", - DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_prepare_sh, psl->dof_down_ps); - DRW_shgroup_uniform_texture_ref(grp, "sceneColorTex", dof_input); + psl->dof_down_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(prepare_sh, psl->dof_down_ps); + DRW_shgroup_uniform_texture(grp, "sceneColorTex", dtxl->color); DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1); DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_downsample_sh, psl->dof_down2_ps); + psl->dof_down2_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(downsample_sh, psl->dof_down2_ps); DRW_shgroup_uniform_texture(grp, "sceneColorTex", txl->dof_source_tx); DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } -#if 0 +#if 0 /* TODO(fclem) finish COC min_max optimization */ { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_h_sh, - psl->dof_flatten_h_ps); + psl->dof_flatten_h_ps = DRW_pass_create("DoF Flatten Coc H", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(flatten_h_sh, psl->dof_flatten_h_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_v_sh, - psl->dof_flatten_v_ps); + psl->dof_flatten_v_ps = DRW_pass_create("DoF Flatten Coc V", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(flatten_v_sh, psl->dof_flatten_v_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_temp_tx); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_v_sh, psl->dof_dilate_v_ps); + psl->dof_dilate_h_ps = DRW_pass_create("DoF Dilate Coc H", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(dilate_v_sh, psl->dof_dilate_v_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[0]); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_h_sh, psl->dof_dilate_h_ps); + psl->dof_dilate_v_ps = DRW_pass_create("DoF Dilate Coc V", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(dilate_h_sh, psl->dof_dilate_h_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[1]); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } #endif { - float offset = stl->effects->jitter_index / - (float)workbench_taa_calculate_num_iterations(vedata); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur1_sh, psl->dof_blur1_ps); - DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->dof_ubo); - DRW_shgroup_uniform_texture(grp, "noiseTex", noise_tex); + psl->dof_blur1_ps = DRW_pass_create("DoF Blur 1", DRW_STATE_WRITE_COLOR); + + /* We reuse the same noise texture. Ensure it is up to date. */ + workbench_cavity_samples_ubo_ensure(wpd); + + float offset = wpd->taa_sample / wpd->taa_sample_len; + DRWShadingGroup *grp = DRW_shgroup_create(blur1_sh, psl->dof_blur1_ps); + DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->vldata->dof_sample_ubo); + DRW_shgroup_uniform_texture(grp, "noiseTex", wpd->vldata->cavity_jitter_tx); DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx); DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); DRW_shgroup_uniform_float_copy(grp, "noiseOffset", offset); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur2_sh, psl->dof_blur2_ps); + psl->dof_blur2_ps = DRW_pass_create("DoF Blur 2", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(blur2_sh, psl->dof_blur2_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx); DRW_shgroup_uniform_texture(grp, "blurTex", wpd->dof_blur_tx); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_resolve_sh, psl->dof_resolve_ps); + psl->dof_resolve_ps = DRW_pass_create("DoF Resolve", + DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM); + + DRWShadingGroup *grp = DRW_shgroup_create(resolve_sh, psl->dof_resolve_ps); DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx); DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1); DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } } -void workbench_dof_engine_free(void) -{ - DRW_SHADER_FREE_SAFE(e_data.effect_dof_prepare_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_downsample_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_v_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_h_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_v_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_h_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur1_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur2_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_resolve_sh); -} - static void workbench_dof_downsample_level(void *userData, int UNUSED(level)) { WORKBENCH_PassList *psl = (WORKBENCH_PassList *)userData; @@ -396,7 +370,8 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata) WORKBENCH_FramebufferList *fbl = vedata->fbl; WORKBENCH_StorageList *stl = vedata->stl; WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; + WORKBENCH_PrivateData *wpd = stl->wpd; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); if (!wpd->dof_enabled) { return; @@ -410,7 +385,7 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata) GPU_framebuffer_recursive_downsample( fbl->dof_downsample_fb, 2, workbench_dof_downsample_level, psl); -#if 0 +#if 0 /* TODO(fclem) finish COC min_max optimization */ GPU_framebuffer_bind(fbl->dof_coc_tile_h_fb); DRW_draw_pass(psl->dof_flatten_h_ps); @@ -430,7 +405,7 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata) GPU_framebuffer_bind(fbl->dof_blur2_fb); DRW_draw_pass(psl->dof_blur2_ps); - GPU_framebuffer_bind(fbl->color_only_fb); + GPU_framebuffer_bind(dfbl->color_only_fb); DRW_draw_pass(psl->dof_resolve_ps); DRW_stats_group_end(); diff --git a/source/blender/draw/engines/workbench/workbench_effect_fxaa.c b/source/blender/draw/engines/workbench/workbench_effect_fxaa.c deleted file mode 100644 index 6e3bf1658ab..00000000000 --- a/source/blender/draw/engines/workbench/workbench_effect_fxaa.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - */ -#include "workbench_private.h" - -/* *********** STATIC *********** */ -static struct { - struct GPUShader *effect_fxaa_sh; -} e_data = {NULL}; - -/* Shaders */ -extern char datatoc_common_fxaa_lib_glsl[]; -extern char datatoc_common_fullscreen_vert_glsl[]; -extern char datatoc_workbench_effect_fxaa_frag_glsl[]; - -/* *********** Functions *********** */ -void workbench_fxaa_engine_init(void) -{ - if (e_data.effect_fxaa_sh == NULL) { - e_data.effect_fxaa_sh = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl, - NULL, - datatoc_workbench_effect_fxaa_frag_glsl, - datatoc_common_fxaa_lib_glsl, - NULL); - } -} - -DRWPass *workbench_fxaa_create_pass(GPUTexture **color_buffer_tx) -{ - DRWPass *pass = DRW_pass_create("Effect FXAA", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_fxaa_sh, pass); - DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx); - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - return pass; -} - -void workbench_fxaa_engine_free(void) -{ - DRW_SHADER_FREE_SAFE(e_data.effect_fxaa_sh); -} diff --git a/source/blender/draw/engines/workbench/workbench_effect_outline.c b/source/blender/draw/engines/workbench/workbench_effect_outline.c new file mode 100644 index 00000000000..d1bc6b6c435 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_effect_outline.c @@ -0,0 +1,55 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Outline Effect: + * + * Simple effect that just samples an object id buffer to detect objects outlines. + */ + +#include "DRW_render.h" + +#include "workbench_engine.h" +#include "workbench_private.h" + +void workbench_outline_cache_init(WORKBENCH_Data *data) +{ + WORKBENCH_PassList *psl = data->psl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + struct GPUShader *sh; + DRWShadingGroup *grp; + + if (OBJECT_OUTLINE_ENABLED(wpd)) { + int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL; + DRW_PASS_CREATE(psl->outline_ps, state); + + sh = workbench_shader_outline_get(); + + grp = DRW_shgroup_create(sh, psl->outline_ps); + DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx); + DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + else { + psl->outline_ps = NULL; + } +} diff --git a/source/blender/draw/engines/workbench/workbench_effect_taa.c b/source/blender/draw/engines/workbench/workbench_effect_taa.c deleted file mode 100644 index e2864f8c832..00000000000 --- a/source/blender/draw/engines/workbench/workbench_effect_taa.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - */ - -#include "workbench_private.h" -#include "BLI_jitter_2d.h" - -static struct { - struct GPUShader *effect_taa_sh; - float jitter_5[5][2]; - float jitter_8[8][2]; - float jitter_11[11][2]; - float jitter_16[16][2]; - float jitter_32[32][2]; -} e_data = {NULL}; - -extern char datatoc_workbench_effect_taa_frag_glsl[]; - -static void workbench_taa_jitter_init_order(float (*table)[2], int num) -{ - BLI_jitter_init(table, num); - - /* find closest element to center */ - int closest_index = 0; - float closest_squared_distance = 1.0f; - - for (int index = 0; index < num; index++) { - const float squared_dist = square_f(table[index][0]) + square_f(table[index][1]); - if (squared_dist < closest_squared_distance) { - closest_squared_distance = squared_dist; - closest_index = index; - } - } - - /* move jitter table so that closest sample is in center */ - for (int index = 0; index < num; index++) { - sub_v2_v2(table[index], table[closest_index]); - mul_v2_fl(table[index], 2.0f); - } - - /* swap center sample to the start of the table */ - if (closest_index != 0) { - swap_v2_v2(table[0], table[closest_index]); - } - - /* sort list based on furtest distance with previous */ - for (int i = 0; i < num - 2; i++) { - float f_squared_dist = 0.0; - int f_index = i; - for (int j = i + 1; j < num; j++) { - const float squared_dist = square_f(table[i][0] - table[j][0]) + - square_f(table[i][1] - table[j][1]); - if (squared_dist > f_squared_dist) { - f_squared_dist = squared_dist; - f_index = j; - } - } - swap_v2_v2(table[i + 1], table[f_index]); - } -} - -static void workbench_taa_jitter_init(void) -{ - workbench_taa_jitter_init_order(e_data.jitter_5, 5); - workbench_taa_jitter_init_order(e_data.jitter_8, 8); - workbench_taa_jitter_init_order(e_data.jitter_11, 11); - workbench_taa_jitter_init_order(e_data.jitter_16, 16); - workbench_taa_jitter_init_order(e_data.jitter_32, 32); -} - -int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const Scene *scene = DRW_context_state_get()->scene; - int result; - if (workbench_is_taa_enabled(wpd)) { - if (DRW_state_is_image_render()) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - if (draw_ctx->v3d) { - result = scene->display.viewport_aa; - } - else { - result = scene->display.render_aa; - } - } - else { - result = wpd->preferences->viewport_aa; - } - } - else { - /* when no TAA is disabled return 1 to render a single sample - * see `workbench_render.c` */ - result = 1; - } - return result; -} - -int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *UNUSED(vedata)) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene = draw_ctx->scene; - int result = DRW_state_is_image_render() ? scene->display.viewport_aa : 1; - result = MAX2(result, 1); - return result; -} - -void workbench_taa_engine_init(WORKBENCH_Data *vedata) -{ - WORKBENCH_EffectInfo *effect_info = vedata->stl->effects; - const DRWContextState *draw_ctx = DRW_context_state_get(); - RegionView3D *rv3d = draw_ctx->rv3d; - - if (e_data.effect_taa_sh == NULL) { - e_data.effect_taa_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_taa_frag_glsl, - NULL); - workbench_taa_jitter_init(); - } - - effect_info->view = NULL; - - /* reset complete drawing when navigating. */ - if (effect_info->jitter_index != 0) { - if (rv3d && rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)) { - effect_info->jitter_index = 0; - } - } - - if (effect_info->view_updated) { - effect_info->jitter_index = 0; - effect_info->view_updated = false; - } - - { - float persmat[4][4]; - DRW_view_persmat_get(NULL, persmat, false); - if (!equals_m4m4(persmat, effect_info->last_mat)) { - copy_m4_m4(effect_info->last_mat, persmat); - effect_info->jitter_index = 0; - } - } -} - -void workbench_taa_engine_free(void) -{ - DRW_SHADER_FREE_SAFE(e_data.effect_taa_sh); -} - -DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_buffer_tx) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_TextureList *txl = vedata->txl; - WORKBENCH_EffectInfo *effect_info = stl->effects; - WORKBENCH_FramebufferList *fbl = vedata->fbl; - const WORKBENCH_PrivateData *wpd = stl->g_data; - - { - const eGPUTextureFormat hist_buffer_format = workbench_color_texture_format(wpd); - DRW_texture_ensure_fullscreen_2d(&txl->history_buffer_tx, hist_buffer_format, 0); - DRW_texture_ensure_fullscreen_2d(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0); - } - - { - GPU_framebuffer_ensure_config(&fbl->effect_taa_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx), - }); - GPU_framebuffer_ensure_config(&fbl->depth_buffer_fb, - { - GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx), - }); - } - - DRWPass *pass = DRW_pass_create("Effect TAA", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_taa_sh, pass); - DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx); - DRW_shgroup_uniform_texture_ref(grp, "historyBuffer", &txl->history_buffer_tx); - DRW_shgroup_uniform_float(grp, "mixFactor", &effect_info->taa_mix_factor, 1); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - - return pass; -} - -void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_EffectInfo *effect_info = stl->effects; - WORKBENCH_PrivateData *wpd = stl->g_data; - - const float *viewport_size = DRW_viewport_size_get(); - const DRWView *default_view = DRW_view_default_get(); - int num_samples = 8; - float(*samples)[2]; - - num_samples = workbench_taa_calculate_num_iterations(vedata); - switch (num_samples) { - default: - case 5: - samples = e_data.jitter_5; - break; - case 8: - samples = e_data.jitter_8; - break; - case 11: - samples = e_data.jitter_11; - break; - case 16: - samples = e_data.jitter_16; - break; - case 32: - samples = e_data.jitter_32; - break; - } - - const int jitter_index = effect_info->jitter_index; - const float *transform_offset = samples[jitter_index]; - effect_info->taa_mix_factor = 1.0f / (jitter_index + 1); - effect_info->jitter_index = (jitter_index + 1) % num_samples; - /* Copy jitter index to Cavity iteration */ - wpd->ssao_params[3] = effect_info->jitter_index; - - /* construct new matrices from transform delta */ - float winmat[4][4], viewmat[4][4], persmat[4][4]; - DRW_view_winmat_get(default_view, winmat, false); - DRW_view_viewmat_get(default_view, viewmat, false); - DRW_view_persmat_get(default_view, persmat, false); - - window_translate_m4(winmat, - persmat, - transform_offset[0] / viewport_size[0], - transform_offset[1] / viewport_size[1]); - - if (effect_info->view) { - /* When rendering just update the view. This avoids recomputing the culling. */ - DRW_view_update_sub(effect_info->view, viewmat, winmat); - } - else { - /* TAA is not making a big change to the matrices. - * Reuse the main view culling by creating a subview. */ - effect_info->view = DRW_view_create_sub(default_view, viewmat, winmat); - } - DRW_view_set_active(effect_info->view); -} - -void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata) -{ - /* - * If first frame then the offset is 0.0 and its depth is the depth buffer to use - * for the rest of the draw engines. We store it in a persistent buffer. - * - * If it is not the first frame we copy the persistent buffer back to the - * default depth buffer - */ - const WORKBENCH_StorageList *stl = vedata->stl; - const WORKBENCH_FramebufferList *fbl = vedata->fbl; - const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - WORKBENCH_EffectInfo *effect_info = stl->effects; - - if (effect_info->jitter_index == 1) { - GPU_framebuffer_blit(dfbl->depth_only_fb, 0, fbl->depth_buffer_fb, 0, GPU_DEPTH_BIT); - } - else { - GPU_framebuffer_blit(fbl->depth_buffer_fb, 0, dfbl->depth_only_fb, 0, GPU_DEPTH_BIT); - } - - GPU_framebuffer_blit(dfbl->color_only_fb, 0, fbl->effect_taa_fb, 0, GPU_COLOR_BIT); - - if (!DRW_state_is_image_render()) { - DRW_view_set_active(NULL); - } - - if (effect_info->jitter_index != 0 && !DRW_state_is_image_render()) { - DRW_viewport_request_redraw(); - } -} - -void workbench_taa_view_updated(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - if (stl) { - WORKBENCH_EffectInfo *effect_info = stl->effects; - if (effect_info) { - effect_info->view_updated = true; - } - } -} diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 62a192bbb25..b91ca7cf070 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -19,18 +19,557 @@ /** \file * \ingroup draw_engine * - * Simple engine for drawing color and/or depth. - * When we only need simple flat shaders. + * Workbench Engine: + * + * Optimized engine to draw the working viewport with solid and transparent geometry. */ #include "DRW_render.h" +#include "BLI_alloca.h" + +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_particle.h" + +#include "DNA_image_types.h" +#include "DNA_fluid_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_node_types.h" + #include "workbench_engine.h" #include "workbench_private.h" #define WORKBENCH_ENGINE "BLENDER_WORKBENCH" -/* Note: currently unused, we may want to register so we can see this when debugging the view. */ +void workbench_engine_init(void *ved) +{ + WORKBENCH_Data *vedata = ved; + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_TextureList *txl = vedata->txl; + + workbench_shader_library_ensure(); + + if (!stl->wpd) { + stl->wpd = MEM_callocN(sizeof(*stl->wpd), __func__); + stl->wpd->view_updated = true; + } + + WORKBENCH_PrivateData *wpd = stl->wpd; + workbench_private_data_init(wpd); + workbench_update_world_ubo(wpd); + + if (txl->dummy_image_tx == NULL) { + float fpixel[4] = {1.0f, 0.0f, 1.0f, 1.0f}; + txl->dummy_image_tx = DRW_texture_create_2d(1, 1, GPU_RGBA8, 0, fpixel); + } + wpd->dummy_image_tx = txl->dummy_image_tx; + + if (OBJECT_ID_PASS_ENABLED(wpd)) { + wpd->object_id_tx = DRW_texture_pool_query_fullscreen(GPU_R16UI, &draw_engine_workbench); + } + else { + /* Dont free because it's a pool texture. */ + wpd->object_id_tx = NULL; + } + + workbench_opaque_engine_init(vedata); + workbench_transparent_engine_init(vedata); + workbench_dof_engine_init(vedata); + workbench_antialiasing_engine_init(vedata); + workbench_volume_engine_init(vedata); +} + +void workbench_cache_init(void *ved) +{ + WORKBENCH_Data *vedata = ved; + + workbench_opaque_cache_init(vedata); + workbench_transparent_cache_init(vedata); + workbench_shadow_cache_init(vedata); + workbench_cavity_cache_init(vedata); + workbench_outline_cache_init(vedata); + workbench_dof_cache_init(vedata); + workbench_antialiasing_cache_init(vedata); + workbench_volume_cache_init(vedata); +} + +/* TODO(fclem) DRW_cache_object_surface_material_get needs a refactor to allow passing NULL + * instead of gpumat_array. Avoiding all this boilerplate code. */ +static struct GPUBatch **workbench_object_surface_material_get(Object *ob) +{ + const int materials_len = DRW_cache_object_material_count_get(ob); + struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); + memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len); + + return DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len); +} + +static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd, + Object *ob, + eV3DShadingColorType color_type) +{ + const bool use_vcol = ELEM(color_type, V3D_SHADING_VERTEX_COLOR); + const bool use_single_drawcall = !ELEM(color_type, V3D_SHADING_MATERIAL_COLOR); + BLI_assert(wpd->shading.color_type != V3D_SHADING_TEXTURE_COLOR); + + if (use_single_drawcall) { + DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, NULL); + DRW_shgroup_call_sculpt(grp, ob, false, false, use_vcol); + } + else { + const int materials_len = DRW_cache_object_material_count_get(ob); + struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len); + for (int i = 0; i < materials_len; i++) { + shgrps[i] = workbench_material_setup(wpd, ob, i + 1, color_type, NULL); + } + DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false); + } +} + +static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; + const bool use_single_drawcall = imapaint->mode == IMAGEPAINT_MODE_IMAGE; + + if (use_single_drawcall) { + struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); + if (geom) { + Image *ima = imapaint->canvas; + int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : + SHD_INTERP_CLOSEST; + + DRWShadingGroup *grp = workbench_image_setup(wpd, ob, 0, ima, NULL, interp); + DRW_shgroup_call(grp, geom, ob); + } + } + else { + struct GPUBatch **geoms = DRW_cache_mesh_surface_texpaint_get(ob); + if (geoms) { + const int materials_len = DRW_cache_object_material_count_get(ob); + for (int i = 0; i < materials_len; i++) { + DRWShadingGroup *grp = workbench_image_setup(wpd, ob, i + 1, NULL, NULL, 0); + DRW_shgroup_call(grp, geoms[i], ob); + } + } + } +} + +static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd, + Object *ob, + eV3DShadingColorType color_type, + bool *r_transp) +{ + const bool use_tex = ELEM(color_type, V3D_SHADING_TEXTURE_COLOR); + const bool use_vcol = ELEM(color_type, V3D_SHADING_VERTEX_COLOR); + const bool use_single_drawcall = !ELEM( + color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR); + + if (use_single_drawcall) { + struct GPUBatch *geom = (use_vcol) ? DRW_cache_mesh_surface_vertpaint_get(ob) : + DRW_cache_object_surface_get(ob); + if (geom) { + DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, r_transp); + DRW_shgroup_call(grp, geom, ob); + } + } + else { + struct GPUBatch **geoms = (use_tex) ? DRW_cache_mesh_surface_texpaint_get(ob) : + workbench_object_surface_material_get(ob); + if (geoms) { + const int materials_len = DRW_cache_object_material_count_get(ob); + for (int i = 0; i < materials_len; i++) { + DRWShadingGroup *grp = workbench_material_setup(wpd, ob, i + 1, color_type, r_transp); + DRW_shgroup_call(grp, geoms[i], ob); + } + } + } +} + +static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd, + Object *ob, + ModifierData *md, + eV3DShadingColorType color_type, + bool use_texpaint_mode) +{ + ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; + ParticleSettings *part = psys->part; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + + const ImagePaintSettings *imapaint = use_texpaint_mode ? &scene->toolsettings->imapaint : NULL; + Image *ima = (imapaint && imapaint->mode == IMAGEPAINT_MODE_IMAGE) ? imapaint->canvas : NULL; + int interp = (imapaint && imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : + SHD_INTERP_CLOSEST; + DRWShadingGroup *grp = (use_texpaint_mode) ? + workbench_image_hair_setup(wpd, ob, part->omat, ima, NULL, interp) : + workbench_material_hair_setup(wpd, ob, part->omat, color_type); + + DRW_shgroup_hair_create_sub(ob, psys, md, grp); +} + +/* Decide what colortype to draw the object with. + * In some cases it can be overwritten by workbench_material_setup(). */ +static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd, + Object *ob, + bool *r_sculpt_pbvh, + bool *r_texpaint_mode, + bool *r_draw_shadow) +{ + eV3DShadingColorType color_type = wpd->shading.color_type; + const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + const bool is_active = (ob == draw_ctx->obact); + const bool is_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + !DRW_state_is_image_render(); + const bool is_render = DRW_state_is_image_render() && (draw_ctx->v3d == NULL); + const bool is_texpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_TEXTURE); + const bool is_vertpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_VERTEX); + + if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (ob->dt < OB_TEXTURE)) { + color_type = V3D_SHADING_MATERIAL_COLOR; + } + /* Disable color mode if data layer is unavailable. */ + if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (me == NULL || me->mloopuv == NULL)) { + color_type = V3D_SHADING_MATERIAL_COLOR; + } + if ((color_type == V3D_SHADING_VERTEX_COLOR) && (me == NULL || me->mloopcol == NULL)) { + color_type = V3D_SHADING_OBJECT_COLOR; + } + + *r_sculpt_pbvh = is_sculpt_pbvh; + *r_texpaint_mode = false; + + if (!is_sculpt_pbvh && !is_render) { + /* Force texture or vertex mode if object is in paint mode. */ + if (is_texpaint_mode && me && me->mloopuv) { + color_type = V3D_SHADING_TEXTURE_COLOR; + *r_texpaint_mode = true; + } + else if (is_vertpaint_mode && me && me->mloopcol) { + color_type = V3D_SHADING_VERTEX_COLOR; + } + } + + if (r_draw_shadow) { + *r_draw_shadow = (ob->dtx & OB_DRAW_NO_SHADOW_CAST) == 0 && SHADOW_ENABLED(wpd); + /* Currently unsupported in sculpt mode. We could revert to the slow + * method in this case but I'm not sure if it's a good idea given that + * sculpted meshes are heavy to begin with. */ + if (is_sculpt_pbvh) { + *r_draw_shadow = false; + } + + if (is_active && DRW_object_use_hide_faces(ob)) { + *r_draw_shadow = false; + } + } + + return color_type; +} + +void workbench_cache_populate(void *ved, Object *ob) +{ + WORKBENCH_Data *vedata = ved; + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_PrivateData *wpd = stl->wpd; + + if (!DRW_object_is_renderable(ob)) { + return; + } + + if (ob->type == OB_MESH && ob->modifiers.first != NULL) { + bool use_sculpt_pbvh, use_texpaint_mode; + int color_type = workbench_color_type_get(wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, NULL); + + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type != eModifierType_ParticleSystem) { + continue; + } + ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; + if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) { + continue; + } + ParticleSettings *part = psys->part; + const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; + + if (draw_as == PART_DRAW_PATH) { + workbench_cache_hair_populate(wpd, ob, md, color_type, use_texpaint_mode); + } + } + } + + if (!(ob->base_flag & BASE_FROM_DUPLI)) { + ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid); + if (md && modifier_isEnabled(wpd->scene, md, eModifierMode_Realtime)) { + FluidModifierData *fmd = (FluidModifierData *)md; + if (fmd->domain && fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) { + workbench_volume_cache_populate(vedata, wpd->scene, ob, md); + return; /* Do not draw solid in this case. */ + } + } + } + + if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { + return; + } + + if ((ob->dt < OB_SOLID) && !DRW_state_is_scene_render()) { + return; + } + + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { + bool use_sculpt_pbvh, use_texpaint_mode, draw_shadow, has_transp_mat = false; + eV3DShadingColorType color_type = workbench_color_type_get( + wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, &draw_shadow); + + if (use_sculpt_pbvh) { + workbench_cache_sculpt_populate(wpd, ob, color_type); + } + else if (use_texpaint_mode) { + workbench_cache_texpaint_populate(wpd, ob); + } + else { + workbench_cache_common_populate(wpd, ob, color_type, &has_transp_mat); + } + + if (draw_shadow) { + workbench_shadow_cache_populate(vedata, ob, has_transp_mat); + } + } +} + +void workbench_cache_finish(void *ved) +{ + WORKBENCH_Data *vedata = ved; + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_FramebufferList *fbl = vedata->fbl; + WORKBENCH_PrivateData *wpd = stl->wpd; + + /* TODO(fclem) Only do this when really needed. */ + { + /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */ + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0); + + GPU_framebuffer_ensure_config(&dfbl->in_front_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), + GPU_ATTACHMENT_TEXTURE(dtxl->color), + }); + + GPU_framebuffer_ensure_config(&fbl->opaque_infront_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), + GPU_ATTACHMENT_TEXTURE(wpd->material_buffer_tx), + GPU_ATTACHMENT_TEXTURE(wpd->normal_buffer_tx), + GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx), + }); + + GPU_framebuffer_ensure_config(&fbl->transp_accum_infront_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), + GPU_ATTACHMENT_TEXTURE(wpd->accum_buffer_tx), + GPU_ATTACHMENT_TEXTURE(wpd->reveal_buffer_tx), + }); + } + + if (wpd->object_id_tx) { + GPU_framebuffer_ensure_config(&fbl->id_clear_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx), + }); + } + else { + GPU_FRAMEBUFFER_FREE_SAFE(fbl->id_clear_fb); + } + + workbench_update_material_ubos(wpd); + + /* TODO don't free reuse next redraw. */ + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { + if (wpd->prepass[i][j][k].material_hash) { + BLI_ghash_free(wpd->prepass[i][j][k].material_hash, NULL, NULL); + wpd->prepass[i][j][k].material_hash = NULL; + } + } + } + } +} + +/* Used by viewport rendering & final rendering. + * Do one render loop iteration (i.e: One TAA sample). */ +void workbench_draw_sample(void *ved) +{ + WORKBENCH_Data *vedata = ved; + WORKBENCH_FramebufferList *fbl = vedata->fbl; + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + WORKBENCH_PassList *psl = vedata->psl; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float clear_col_with_alpha[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + + const bool do_render = workbench_antialiasing_setup(vedata); + const bool xray_is_visible = wpd->shading.xray_alpha > 0.0f; + const bool do_transparent_infront_pass = !DRW_pass_is_empty(psl->transp_accum_infront_ps); + const bool do_transparent_pass = !DRW_pass_is_empty(psl->transp_accum_ps); + const bool do_opaque_infront_pass = !DRW_pass_is_empty(psl->opaque_infront_ps); + const bool do_opaque_pass = !DRW_pass_is_empty(psl->opaque_ps) || do_opaque_infront_pass; + + if (dfbl->in_front_fb) { + GPU_framebuffer_bind(dfbl->in_front_fb); + GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f); + } + + if (do_render) { + GPU_framebuffer_bind(dfbl->default_fb); + GPU_framebuffer_clear_color_depth_stencil(dfbl->default_fb, wpd->background_color, 1.0f, 0x00); + + if (fbl->id_clear_fb) { + GPU_framebuffer_bind(fbl->id_clear_fb); + GPU_framebuffer_clear_color(fbl->id_clear_fb, clear_col); + } + + if (do_opaque_pass) { + GPU_framebuffer_bind(fbl->opaque_fb); + DRW_draw_pass(psl->opaque_ps); + + if (psl->shadow_ps[0]) { + DRW_draw_pass(psl->shadow_ps[0]); + DRW_draw_pass(psl->shadow_ps[1]); + } + + if (do_opaque_infront_pass) { + GPU_framebuffer_bind(fbl->opaque_infront_fb); + DRW_draw_pass(psl->opaque_infront_ps); + + GPU_framebuffer_bind(fbl->opaque_fb); + DRW_draw_pass(psl->merge_infront_ps); + } + + GPU_framebuffer_bind(dfbl->default_fb); + DRW_draw_pass(psl->composite_ps); + + if (psl->cavity_ps) { + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->cavity_ps); + } + } + + workbench_volume_draw_pass(vedata); + + if (xray_is_visible) { + if (do_transparent_pass) { + GPU_framebuffer_bind(fbl->transp_accum_fb); + GPU_framebuffer_clear_color(fbl->transp_accum_fb, clear_col_with_alpha); + + DRW_draw_pass(psl->transp_accum_ps); + + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->transp_resolve_ps); + } + + if (do_transparent_infront_pass) { + GPU_framebuffer_bind(fbl->transp_accum_infront_fb); + GPU_framebuffer_clear_color(fbl->transp_accum_infront_fb, clear_col_with_alpha); + + DRW_draw_pass(psl->transp_accum_infront_ps); + + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->transp_resolve_ps); + } + } + + workbench_transparent_draw_depth_pass(vedata); + + if (psl->outline_ps) { + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->outline_ps); + } + + workbench_dof_draw_pass(vedata); + } + + workbench_antialiasing_draw_pass(vedata); +} + +/* Viewport rendering. */ +static void workbench_draw_scene(void *ved) +{ + WORKBENCH_Data *vedata = ved; + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + + if (DRW_state_is_opengl_render()) { + while (wpd->taa_sample < max_ii(1, wpd->taa_sample_len)) { + workbench_update_world_ubo(wpd); + + workbench_draw_sample(vedata); + } + } + else { + workbench_draw_sample(vedata); + } + + workbench_draw_finish(vedata); +} + +void workbench_draw_finish(void *ved) +{ + WORKBENCH_Data *vedata = ved; + workbench_volume_draw_finish(vedata); +} + +static void workbench_engine_free(void) +{ + workbench_shader_free(); +} + +static void workbench_view_update(void *vedata) +{ + WORKBENCH_Data *data = vedata; + workbench_antialiasing_view_updated(data); +} + +static void workbench_id_update(void *UNUSED(vedata), struct ID *id) +{ + if (GS(id->name) == ID_OB) { + WORKBENCH_ObjectData *oed = (WORKBENCH_ObjectData *)DRW_drawdata_get(id, + &draw_engine_workbench); + if (oed != NULL && oed->dd.recalc != 0) { + oed->shadow_bbox_dirty = (oed->dd.recalc & ID_RECALC_ALL) != 0; + oed->dd.recalc = 0; + } + } +} + +static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data); + +DrawEngineType draw_engine_workbench = { + NULL, + NULL, + N_("Workbench"), + &workbench_data_size, + &workbench_engine_init, + &workbench_engine_free, + &workbench_cache_init, + &workbench_cache_populate, + &workbench_cache_finish, + &workbench_draw_scene, + &workbench_view_update, + &workbench_id_update, + &workbench_render, +}; + RenderEngineType DRW_engine_viewport_workbench_type = { NULL, NULL, @@ -44,7 +583,7 @@ RenderEngineType DRW_engine_viewport_workbench_type = { NULL, NULL, &workbench_render_update_passes, - &draw_engine_workbench_solid, + &draw_engine_workbench, {NULL, NULL, NULL}, }; diff --git a/source/blender/draw/engines/workbench/workbench_engine.h b/source/blender/draw/engines/workbench/workbench_engine.h index 78f70abdaab..eee53fcde07 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.h +++ b/source/blender/draw/engines/workbench/workbench_engine.h @@ -23,8 +23,6 @@ #ifndef __WORKBENCH_ENGINE_H__ #define __WORKBENCH_ENGINE_H__ -extern DrawEngineType draw_engine_workbench_solid; -extern DrawEngineType draw_engine_workbench_transparent; extern RenderEngineType DRW_engine_viewport_workbench_type; #endif /* __WORKBENCH_ENGINE_H__ */ diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c deleted file mode 100644 index 7e09016cf61..00000000000 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ /dev/null @@ -1,817 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - */ - -#include "workbench_private.h" - -#include "BLI_alloca.h" -#include "BLI_dynstr.h" -#include "BLI_string_utils.h" -#include "BLI_utildefines.h" - -#include "BKE_modifier.h" -#include "BKE_object.h" -#include "BKE_paint.h" -#include "BKE_particle.h" - -#include "DNA_image_types.h" -#include "DNA_fluid_types.h" -#include "DNA_mesh_types.h" -#include "DNA_modifier_types.h" -#include "DNA_node_types.h" - -#include "ED_view3d.h" - -#include "GPU_shader.h" -#include "GPU_texture.h" - -/* *********** STATIC *********** */ - -typedef struct WORKBENCH_FORWARD_Shaders { - struct GPUShader *transparent_accum_sh_cache[MAX_ACCUM_SHADERS]; - struct GPUShader *object_outline_sh; - struct GPUShader *object_outline_texture_sh; - struct GPUShader *object_outline_hair_sh; -} WORKBENCH_FORWARD_Shaders; - -static struct { - WORKBENCH_FORWARD_Shaders sh_data[GPU_SHADER_CFG_LEN]; - - struct GPUShader *composite_sh_cache[2]; - - struct GPUTexture *object_id_tx; /* ref only, not alloced */ - struct GPUTexture *transparent_accum_tx; /* ref only, not alloced */ - struct GPUTexture *transparent_revealage_tx; /* ref only, not alloced */ - struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */ -} e_data = {{{{NULL}}}}; - -/* Shaders */ -extern char datatoc_common_hair_lib_glsl[]; -extern char datatoc_common_view_lib_glsl[]; - -extern char datatoc_workbench_forward_composite_frag_glsl[]; -extern char datatoc_workbench_forward_depth_frag_glsl[]; -extern char datatoc_workbench_forward_transparent_accum_frag_glsl[]; -extern char datatoc_workbench_data_lib_glsl[]; -extern char datatoc_workbench_object_outline_lib_glsl[]; -extern char datatoc_workbench_curvature_lib_glsl[]; -extern char datatoc_workbench_prepass_vert_glsl[]; -extern char datatoc_workbench_common_lib_glsl[]; -extern char datatoc_workbench_world_light_lib_glsl[]; - -/* static functions */ -static char *workbench_build_forward_vert(bool is_hair) -{ - DynStr *ds = BLI_dynstr_new(); - if (is_hair) { - BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl); - } - BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static char *workbench_build_forward_outline_frag(void) -{ - DynStr *ds = BLI_dynstr_new(); - - BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_forward_depth_frag_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static char *workbench_build_forward_transparent_accum_frag(void) -{ - DynStr *ds = BLI_dynstr_new(); - - BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_forward_transparent_accum_frag_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static char *workbench_build_forward_composite_frag(void) -{ - DynStr *ds = BLI_dynstr_new(); - - BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_forward_composite_frag_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data( - WORKBENCH_Data *vedata, - Object *ob, - Material *mat, - Image *ima, - ImageUser *iuser, - eV3DShadingColorType color_type, - int interp) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; - WORKBENCH_MaterialData *material; - WORKBENCH_MaterialData material_template; - DRWShadingGroup *grp; - - /* Solid */ - workbench_material_update_data(wpd, ob, mat, &material_template, color_type); - material_template.color_type = color_type; - material_template.ima = ima; - material_template.iuser = iuser; - material_template.interp = interp; - uint hash = workbench_material_get_hash(&material_template, false); - - material = BLI_ghash_lookup(wpd->material_transp_hash, POINTER_FROM_UINT(hash)); - if (material == NULL) { - material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__); - - /* transparent accum */ - /* select the correct transparent accum shader */ - GPUShader *shader = (wpd->shading.color_type == color_type) ? - wpd->transparent_accum_sh : - wpd->transparent_accum_uniform_sh; - const bool is_tiled = (ima && ima->source == IMA_SRC_TILED); - if (color_type == V3D_SHADING_TEXTURE_COLOR) { - shader = is_tiled ? wpd->transparent_accum_textured_array_sh : - wpd->transparent_accum_textured_sh; - } - - grp = DRW_shgroup_create(shader, psl->transparent_accum_pass); - DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", material_template.alpha); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); - workbench_material_copy(material, &material_template); - if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { - BKE_studiolight_ensure_flag(wpd->studio_light, - STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE | - STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE); - DRW_shgroup_uniform_texture( - grp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture); - if (workbench_is_specular_highlight_enabled(wpd)) { - DRW_shgroup_uniform_texture( - grp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture); - } - } - if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) { - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - } - if (SHADOW_ENABLED(wpd)) { - DRW_shgroup_uniform_float_copy(grp, "shadowMultiplier", wpd->shadow_multiplier); - DRW_shgroup_uniform_float_copy(grp, "shadowShift", wpd->shadow_shift); - DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus); - } - - workbench_material_shgroup_uniform(wpd, grp, material, ob, false, is_tiled, interp); - material->shgrp = grp; - - /* Depth */ - if (color_type == V3D_SHADING_TEXTURE_COLOR) { - material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_texture_sh, - psl->object_outline_pass); - GPUTexture *tex = GPU_texture_from_blender( - material->ima, material->iuser, NULL, GL_TEXTURE_2D); - DRW_shgroup_uniform_texture(material->shgrp_object_outline, "image", tex); - } - else { - material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_sh, - psl->object_outline_pass); - } - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_shgroup_state_enable(material->shgrp_object_outline, DRW_STATE_CLIP_PLANES); - } - BLI_ghash_insert(wpd->material_transp_hash, POINTER_FROM_UINT(hash), material); - } - return material; -} - -static GPUShader *ensure_forward_accum_shaders(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override, - eGPUShaderConfig sh_cfg) -{ - WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - int index = workbench_material_get_accum_shader_index( - wpd, is_uniform_color, is_hair, is_tiled, color_override); - if (sh_data->transparent_accum_sh_cache[index] == NULL) { - const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; - char *defines = workbench_material_build_defines( - wpd, is_uniform_color, is_hair, is_tiled, color_override); - char *transparent_accum_vert = workbench_build_forward_vert(is_hair); - char *transparent_accum_frag = workbench_build_forward_transparent_accum_frag(); - sh_data->transparent_accum_sh_cache[index] = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, transparent_accum_vert, NULL}, - .frag = (const char *[]){transparent_accum_frag, NULL}, - .defs = (const char *[]){sh_cfg_data->def, defines, NULL}, - }); - MEM_freeN(transparent_accum_vert); - MEM_freeN(transparent_accum_frag); - MEM_freeN(defines); - } - return sh_data->transparent_accum_sh_cache[index]; -} - -static GPUShader *ensure_forward_composite_shaders(WORKBENCH_PrivateData *wpd) -{ - int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0; - if (e_data.composite_sh_cache[index] == NULL) { - char *defines = workbench_material_build_defines( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF); - char *composite_frag = workbench_build_forward_composite_frag(); - e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); - MEM_freeN(composite_frag); - MEM_freeN(defines); - } - return e_data.composite_sh_cache[index]; -} - -void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg) -{ - wpd->composite_sh = ensure_forward_composite_shaders(wpd); - wpd->transparent_accum_sh = ensure_forward_accum_shaders( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->transparent_accum_hair_sh = ensure_forward_accum_shaders( - wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->transparent_accum_uniform_sh = ensure_forward_accum_shaders( - wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->transparent_accum_uniform_hair_sh = ensure_forward_accum_shaders( - wpd, true, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->transparent_accum_textured_sh = ensure_forward_accum_shaders( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg); - wpd->transparent_accum_textured_array_sh = ensure_forward_accum_shaders( - wpd, false, false, true, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg); - wpd->transparent_accum_vertex_sh = ensure_forward_accum_shaders( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg); -} - -void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg) -{ - WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - - if (sh_data->object_outline_sh == NULL) { - const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; - char *defines = workbench_material_build_defines( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF); - char *defines_texture = workbench_material_build_defines( - wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF); - char *defines_hair = workbench_material_build_defines( - wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF); - char *forward_vert = workbench_build_forward_vert(false); - char *forward_frag = workbench_build_forward_outline_frag(); - char *forward_hair_vert = workbench_build_forward_vert(true); - - const char *define_id_pass = "#define OBJECT_ID_PASS_ENABLED\n"; - - sh_data->object_outline_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL}, - .frag = (const char *[]){forward_frag, NULL}, - .defs = (const char *[]){sh_cfg_data->def, defines, define_id_pass, NULL}, - }); - sh_data->object_outline_texture_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL}, - .frag = (const char *[]){forward_frag, NULL}, - .defs = (const char *[]){sh_cfg_data->def, defines_texture, define_id_pass, NULL}, - }); - sh_data->object_outline_hair_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, forward_hair_vert, NULL}, - .frag = (const char *[]){forward_frag, NULL}, - .defs = (const char *[]){sh_cfg_data->def, defines_hair, define_id_pass, NULL}, - }); - - MEM_freeN(forward_hair_vert); - MEM_freeN(forward_vert); - MEM_freeN(forward_frag); - MEM_freeN(defines); - MEM_freeN(defines_texture); - MEM_freeN(defines_hair); - } -} - -/* public functions */ -void workbench_forward_engine_init(WORKBENCH_Data *vedata) -{ - WORKBENCH_FramebufferList *fbl = vedata->fbl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_StorageList *stl = vedata->stl; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - const DRWContextState *draw_ctx = DRW_context_state_get(); - DRWShadingGroup *grp; - - if (!stl->g_data) { - /* Alloc transient pointers */ - stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); - } - if (!stl->effects) { - stl->effects = MEM_callocN(sizeof(*stl->effects), __func__); - workbench_effect_info_init(stl->effects); - } - WORKBENCH_PrivateData *wpd = stl->g_data; - workbench_private_data_init(wpd); - - workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg); - - workbench_volume_engine_init(); - workbench_fxaa_engine_init(); - workbench_taa_engine_init(vedata); - - workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg); - workbench_forward_choose_shaders(wpd, draw_ctx->sh_cfg); - - const float *viewport_size = DRW_viewport_size_get(); - const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; - const eGPUTextureFormat comp_tex_format = GPU_RGBA16F; - - e_data.object_id_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_R32UI, &draw_engine_workbench_transparent); - e_data.transparent_accum_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_transparent); - e_data.transparent_revealage_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_R16F, &draw_engine_workbench_transparent); - e_data.composite_buffer_tx = DRW_texture_pool_query_2d( - size[0], size[1], comp_tex_format, &draw_engine_workbench_transparent); - - GPU_framebuffer_ensure_config(&fbl->object_outline_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), - }); - GPU_framebuffer_ensure_config(&fbl->transparent_accum_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.transparent_accum_tx), - GPU_ATTACHMENT_TEXTURE(e_data.transparent_revealage_tx), - }); - GPU_framebuffer_ensure_config(&fbl->composite_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx), - }); - GPU_framebuffer_ensure_config(&fbl->effect_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.transparent_accum_tx), - }); - - workbench_volume_cache_init(vedata); - - DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0; - DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0; - - /* Transparency Accum */ - { - int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_OIT | cull_state | clip_state; - psl->transparent_accum_pass = DRW_pass_create("Transparent Accum", state); - } - /* Depth */ - { - int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state | - clip_state; - psl->object_outline_pass = DRW_pass_create("Object Outline Pass", state); - } - /* Composite */ - { - int state = DRW_STATE_WRITE_COLOR; - if (DRW_state_is_scene_render()) { - /* Composite the scene over cleared background. */ - state |= DRW_STATE_BLEND_ALPHA_PREMUL; - } - psl->composite_pass = DRW_pass_create("Composite", state); - - grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); - if (OBJECT_ID_PASS_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); - } - DRW_shgroup_uniform_texture_ref(grp, "transparentAccum", &e_data.transparent_accum_tx); - DRW_shgroup_uniform_texture_ref(grp, "transparentRevealage", &e_data.transparent_revealage_tx); - DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - - { - workbench_aa_create_pass(vedata, &e_data.transparent_accum_tx); - } - - if (wpd->shading.type == OB_WIRE) { - wpd->shading.xray_alpha = 0.0f; - wpd->shading.xray_alpha_wire = 0.0f; - } -} - -void workbench_forward_engine_free() -{ - for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) { - WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_data_index]; - for (int index = 0; index < MAX_ACCUM_SHADERS; index++) { - DRW_SHADER_FREE_SAFE(sh_data->transparent_accum_sh_cache[index]); - } - DRW_SHADER_FREE_SAFE(sh_data->object_outline_sh); - DRW_SHADER_FREE_SAFE(sh_data->object_outline_texture_sh); - DRW_SHADER_FREE_SAFE(sh_data->object_outline_hair_sh); - } - - for (int index = 0; index < 2; index++) { - DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]); - } - - workbench_volume_engine_free(); - workbench_fxaa_engine_free(); - workbench_taa_engine_free(); - workbench_dof_engine_free(); -} - -void workbench_forward_cache_init(WORKBENCH_Data *UNUSED(vedata)) -{ -} - -static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; - - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type != eModifierType_ParticleSystem) { - continue; - } - ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; - if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) { - continue; - } - ParticleSettings *part = psys->part; - const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - - if (draw_as == PART_DRAW_PATH) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, part->omat, &image, &iuser, &interp, &mat); - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, false); - WORKBENCH_MaterialData *material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp); - - struct GPUShader *shader = (wpd->shading.color_type == color_type) ? - wpd->transparent_accum_hair_sh : - wpd->transparent_accum_uniform_hair_sh; - DRWShadingGroup *shgrp = DRW_shgroup_hair_create( - ob, psys, md, psl->transparent_accum_pass, shader); - DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo); - workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false, interp); - DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3); - /* Hairs have lots of layer and can rapidly become the most prominent surface. - * So lower their alpha artificially. */ - float hair_alpha = XRAY_ALPHA(wpd) * 0.33f; - DRW_shgroup_uniform_float_copy(shgrp, "alpha", hair_alpha); - if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { - BKE_studiolight_ensure_flag(wpd->studio_light, - STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE | - STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE); - DRW_shgroup_uniform_texture( - shgrp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture); - if (workbench_is_specular_highlight_enabled(wpd)) { - DRW_shgroup_uniform_texture( - shgrp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture); - } - } - if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) { - DRW_shgroup_uniform_vec2(shgrp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - } - - WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - shgrp = DRW_shgroup_hair_create( - ob, psys, md, vedata->psl->object_outline_pass, sh_data->object_outline_hair_sh); - } - } -} -static void workbench_forward_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - Scene *scene = draw_ctx->scene; - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - WORKBENCH_MaterialData *material; - - /* Force workbench to render active object textured when in texture paint mode */ - const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - - /* Single Image mode */ - if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) { - Image *image = imapaint->canvas; - int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : - SHD_INTERP_CLOSEST; - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, use_sculpt_pbvh); - struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); - material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, image, NULL, color_type, interp); - - DRW_shgroup_call(material->shgrp, geom, ob); - DRW_shgroup_call(material->shgrp_object_outline, geom, ob); - } - else { - /* IMAGEPAINT_MODE_MATERIAL */ - const int materials_len = DRW_cache_object_material_count_get(ob); - struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); - for (int i = 0; i < materials_len; i++) { - if (geom_array != NULL && geom_array[i] != NULL) { - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, use_sculpt_pbvh); - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp); - - DRW_shgroup_call(material->shgrp, geom_array[i], ob); - DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob); - } - } - } -} -static void workbench_forward_cache_populate_vertex_paint_mode(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - WORKBENCH_MaterialData *material; - - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, NULL, ob, use_sculpt_pbvh); - struct GPUBatch *geom = DRW_cache_mesh_surface_vertpaint_get(ob); - material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, false); - DRW_shgroup_call(material->shgrp, geom, ob); - DRW_shgroup_call(material->shgrp_object_outline, geom, ob); -} - -void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - const bool is_wire = (ob->dt == OB_WIRE); - - if (!DRW_object_is_renderable(ob)) { - return; - } - - if (ob->type == OB_MESH) { - workbench_forward_cache_populate_particles(vedata, ob); - } - - ModifierData *md; - if (((ob->base_flag & BASE_FROM_DUPLI) == 0) && - (md = modifiers_findByType(ob, eModifierType_Fluid)) && - (modifier_isEnabled(scene, md, eModifierMode_Realtime)) && - (((FluidModifierData *)md)->domain != NULL) && - (((FluidModifierData *)md)->domain->type == FLUID_DOMAIN_TYPE_GAS)) { - workbench_volume_cache_populate(vedata, scene, ob, md); - return; /* Do not draw solid in this case. */ - } - - if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { - return; - } - if (ob->dt < OB_WIRE) { - return; - } - - WORKBENCH_MaterialData *material = NULL; - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - const int materials_len = DRW_cache_object_material_count_get(ob); - const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; - const WORKBENCH_ColorOverride color_override = workbench_object_color_override_get(ob); - const bool use_texture_paint_drawing = !(DRW_state_is_image_render() && - draw_ctx->v3d == NULL) && - (color_override == WORKBENCH_COLOR_OVERRIDE_TEXTURE) && - me && me->mloopuv; - const bool use_vertex_paint_drawing = !(DRW_state_is_image_render() && - draw_ctx->v3d == NULL) && - (color_override == WORKBENCH_COLOR_OVERRIDE_VERTEX) && - me && me->mloopcol; - - if (use_texture_paint_drawing) { - workbench_forward_cache_populate_texture_paint_mode(vedata, ob); - } - else if (use_vertex_paint_drawing) { - workbench_forward_cache_populate_vertex_paint_mode(vedata, ob); - } - else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { - struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); - for (int i = 0; i < materials_len; i++) { - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, use_sculpt_pbvh); - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp); - DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob); - DRW_shgroup_call(material->shgrp, geom_array[i], ob); - } - } - else if (ELEM(wpd->shading.color_type, - V3D_SHADING_SINGLE_COLOR, - V3D_SHADING_OBJECT_COLOR, - V3D_SHADING_RANDOM_COLOR, - V3D_SHADING_VERTEX_COLOR)) { - /* No material split needed */ - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, NULL, ob, use_sculpt_pbvh); - - if (use_sculpt_pbvh) { - material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, 0); - bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR); - /* TODO(fclem) make this call optional */ - DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false); - if (!is_wire) { - DRW_shgroup_call_sculpt(material->shgrp, ob, false, false, use_vcol); - } - } - else { - struct GPUBatch *geom = (color_type == V3D_SHADING_VERTEX_COLOR) ? - DRW_cache_mesh_surface_vertpaint_get(ob) : - DRW_cache_object_surface_get(ob); - if (geom) { - material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, 0); - /* TODO(fclem) make this call optional */ - DRW_shgroup_call(material->shgrp_object_outline, geom, ob); - if (!is_wire) { - DRW_shgroup_call(material->shgrp, geom, ob); - } - } - } - } - else { - /* Draw material color */ - if (use_sculpt_pbvh) { - struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len); - - for (int i = 0; i < materials_len; i++) { - struct Material *mat = BKE_object_material_get(ob, i + 1); - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - shgrps[i] = material->shgrp; - } - /* TODO(fclem) make this call optional */ - DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false); - if (!is_wire) { - DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false); - } - } - else { - struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); - memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len); - - struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get( - ob, gpumat_array, materials_len); - if (mat_geom) { - for (int i = 0; i < materials_len; i++) { - if (mat_geom[i] == NULL) { - continue; - } - - Material *mat = BKE_object_material_get(ob, i + 1); - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - /* TODO(fclem) make this call optional */ - DRW_shgroup_call(material->shgrp_object_outline, mat_geom[i], ob); - if (!is_wire) { - DRW_shgroup_call(material->shgrp, mat_geom[i], ob); - } - } - } - } - } - } -} - -void workbench_forward_cache_finish(WORKBENCH_Data *UNUSED(vedata)) -{ -} - -void workbench_forward_draw_scene(WORKBENCH_Data *vedata) -{ - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_FramebufferList *fbl = vedata->fbl; - WORKBENCH_PrivateData *wpd = stl->g_data; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - - if (dfbl->in_front_fb) { - /* TODO(fclem) This clear should be done in a global place. */ - GPU_framebuffer_bind(dfbl->in_front_fb); - GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f); - } - - if (workbench_is_taa_enabled(wpd)) { - workbench_taa_draw_scene_start(vedata); - } - - /* Write Depth + Object ID */ - const float clear_outline[4] = {0.0f}; - GPU_framebuffer_bind(fbl->object_outline_fb); - GPU_framebuffer_clear_color(fbl->object_outline_fb, clear_outline); - DRW_draw_pass(psl->object_outline_pass); - - if (XRAY_ALPHA(wpd) > 0.0) { - const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - GPU_framebuffer_bind(fbl->transparent_accum_fb); - GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color); - DRW_draw_pass(psl->transparent_accum_pass); - } - else { - /* TODO(fclem): this is unnecessary and takes up perf. - * Better change the composite frag shader to not use the tx. */ - const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - GPU_framebuffer_bind(fbl->transparent_accum_fb); - GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color); - } - - /* Composite */ - GPU_framebuffer_bind(fbl->composite_fb); - - if (DRW_state_is_scene_render()) { - float clear_color[4]; - workbench_clear_color_get(clear_color); - GPU_framebuffer_clear_color(fbl->composite_fb, clear_color); - } - - DRW_draw_pass(psl->composite_pass); - DRW_draw_pass(psl->volume_pass); - - /* Only when clipping is enabled. */ - if (psl->background_pass) { - DRW_draw_pass(psl->background_pass); - } - - /* Color correct and Anti aliasing */ - workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx); -} - -void workbench_forward_draw_finish(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - - workbench_private_data_free(wpd); - workbench_volume_smoke_textures_free(wpd); -} diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 5f1e3461d9f..246f5f88045 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -22,6 +22,8 @@ #include "workbench_private.h" +#include "BLI_memblock.h" + #include "BKE_image.h" #include "BKE_node.h" @@ -31,310 +33,78 @@ #include "DNA_node_types.h" #include "DNA_mesh_types.h" +#include "GPU_uniformbuffer.h" + #include "ED_uvedit.h" #define HSV_SATURATION 0.5 #define HSV_VALUE 0.8 -void workbench_material_update_data(WORKBENCH_PrivateData *wpd, - Object *ob, - Material *mat, - WORKBENCH_MaterialData *data, - int color_type) +void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd, + Object *ob, + Material *mat, + WORKBENCH_UBO_Material *data, + eV3DShadingColorType color_type) { - data->metallic = 0.0f; - data->roughness = 0.632455532f; /* sqrtf(0.4f); */ - data->alpha = wpd->shading.xray_alpha; + float metallic = 0.0f; + float roughness = 0.632455532f; /* sqrtf(0.4f); */ + float alpha = wpd->shading.xray_alpha; - if (color_type == V3D_SHADING_SINGLE_COLOR) { - copy_v3_v3(data->base_color, wpd->shading.single_color); - } - else if (color_type == V3D_SHADING_ERROR_COLOR) { - copy_v3_fl3(data->base_color, 0.8, 0.0, 0.8); - } - else if (color_type == V3D_SHADING_RANDOM_COLOR) { - uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name); - if (ob->id.lib) { - hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name); - } - - float hue = BLI_hash_int_01(hash); - float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE}; - hsv_to_rgb_v(hsv, data->base_color); - } - else if (ELEM(color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_VERTEX_COLOR)) { - data->alpha *= ob->color[3]; - copy_v3_v3(data->base_color, ob->color); - } - else { - /* V3D_SHADING_MATERIAL_COLOR or V3D_SHADING_TEXTURE_COLOR */ - if (mat) { - data->alpha *= mat->a; - copy_v3_v3(data->base_color, &mat->r); - if (workbench_is_specular_highlight_enabled(wpd)) { - data->metallic = mat->metallic; - data->roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */ - } - } - else { - copy_v3_fl(data->base_color, 0.8f); - } - } -} - -char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override) -{ - char *str = NULL; - bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color; - bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) && - !is_uniform_color; - - switch (color_override) { - case WORKBENCH_COLOR_OVERRIDE_TEXTURE: - use_textures = true; - use_vertex_colors = false; - is_hair = false; - break; - case WORKBENCH_COLOR_OVERRIDE_VERTEX: - use_textures = false; - use_vertex_colors = true; - is_hair = false; - is_tiled = false; + switch (color_type) { + case V3D_SHADING_SINGLE_COLOR: + copy_v3_v3(data->base_color, wpd->shading.single_color); break; - case WORKBENCH_COLOR_OVERRIDE_OFF: - break; - } - - DynStr *ds = BLI_dynstr_new(); - - if (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) { - BLI_dynstr_append(ds, "#define V3D_SHADING_OBJECT_OUTLINE\n"); - } - if (wpd->shading.flag & V3D_SHADING_SHADOW) { - BLI_dynstr_append(ds, "#define V3D_SHADING_SHADOW\n"); - } - if (SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) { - BLI_dynstr_append(ds, "#define WB_CAVITY\n"); - } - if (workbench_is_specular_highlight_enabled(wpd)) { - BLI_dynstr_append(ds, "#define V3D_SHADING_SPECULAR_HIGHLIGHT\n"); - } - if (STUDIOLIGHT_ENABLED(wpd)) { - BLI_dynstr_append(ds, "#define V3D_LIGHTING_STUDIO\n"); - } - if (FLAT_ENABLED(wpd)) { - BLI_dynstr_append(ds, "#define V3D_LIGHTING_FLAT\n"); - } - if (MATCAP_ENABLED(wpd)) { - BLI_dynstr_append(ds, "#define V3D_LIGHTING_MATCAP\n"); - } - if (OBJECT_ID_PASS_ENABLED(wpd)) { - BLI_dynstr_append(ds, "#define OBJECT_ID_PASS_ENABLED\n"); - } - if (workbench_is_matdata_pass_enabled(wpd)) { - BLI_dynstr_append(ds, "#define MATDATA_PASS_ENABLED\n"); - } - if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) { - BLI_dynstr_append(ds, "#define NORMAL_VIEWPORT_PASS_ENABLED\n"); - } - if (use_vertex_colors) { - BLI_dynstr_append(ds, "#define V3D_SHADING_VERTEX_COLOR\n"); - } - if (use_textures) { - BLI_dynstr_append(ds, "#define V3D_SHADING_TEXTURE_COLOR\n"); - } - if (NORMAL_ENCODING_ENABLED()) { - BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n"); - } - if (is_hair) { - BLI_dynstr_append(ds, "#define HAIR_SHADER\n"); - } - if (use_textures && is_tiled) { - BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n"); - } - - str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -uint workbench_material_get_hash(WORKBENCH_MaterialData *mat, bool is_ghost) -{ - union { - struct { - /* WHATCH: Keep in sync with View3DShading.color_type max value. */ - uchar color_type; - uchar diff_r; - uchar diff_g; - uchar diff_b; - - uchar alpha; - uchar ghost; - uchar metal; - uchar roughness; - - void *ima; - }; - /* HACK to ensure input is 4 uint long. */ - uint a[4]; - } input = {.color_type = (uchar)(mat->color_type), - .diff_r = (uchar)(mat->base_color[0] * 0xFF), - .diff_g = (uchar)(mat->base_color[1] * 0xFF), - .diff_b = (uchar)(mat->base_color[2] * 0xFF), - - .alpha = (uint)(mat->alpha * 0xFF), - .ghost = (uchar)is_ghost, - .metal = (uchar)(mat->metallic * 0xFF), - .roughness = (uchar)(mat->roughness * 0xFF), - - .ima = mat->ima}; - - BLI_assert(sizeof(input) == sizeof(uint) * 4); - - return BLI_ghashutil_uinthash_v4((uint *)&input); -} - -int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd) -{ - /* NOTE: change MAX_COMPOSITE_SHADERS accordingly when modifying this function. */ - int index = 0; - /* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */ - index = wpd->shading.light; - SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 2); - SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 3); - SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 4); - SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 5); - SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6); - BLI_assert(index < MAX_COMPOSITE_SHADERS); - return index; -} - -int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override) -{ - bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color; - bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) && - !is_uniform_color; - - switch (color_override) { - case WORKBENCH_COLOR_OVERRIDE_TEXTURE: - use_textures = true; - use_vertex_colors = false; - break; - case WORKBENCH_COLOR_OVERRIDE_VERTEX: - use_textures = false; - use_vertex_colors = true; - is_tiled = false; - break; - case WORKBENCH_COLOR_OVERRIDE_OFF: - break; - } - - /* NOTE: change MAX_PREPASS_SHADERS accordingly when modifying this function. */ - int index = 0; - SET_FLAG_FROM_TEST(index, is_hair, 1 << 0); - SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 1); - SET_FLAG_FROM_TEST(index, OBJECT_ID_PASS_ENABLED(wpd), 1 << 2); - SET_FLAG_FROM_TEST(index, NORMAL_VIEWPORT_PASS_ENABLED(wpd), 1 << 3); - SET_FLAG_FROM_TEST(index, MATCAP_ENABLED(wpd), 1 << 4); - SET_FLAG_FROM_TEST(index, use_textures, 1 << 5); - SET_FLAG_FROM_TEST(index, use_vertex_colors, 1 << 6); - SET_FLAG_FROM_TEST(index, is_tiled && use_textures, 1 << 7); - BLI_assert(index < MAX_PREPASS_SHADERS); - return index; -} - -int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override) -{ - bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color; - bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) && - !is_uniform_color; - - switch (color_override) { - case WORKBENCH_COLOR_OVERRIDE_TEXTURE: - use_textures = true; - use_vertex_colors = false; - is_hair = false; + case V3D_SHADING_RANDOM_COLOR: { + uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name); + if (ob->id.lib) { + hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name); + } + float hue = BLI_hash_int_01(hash); + float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE}; + hsv_to_rgb_v(hsv, data->base_color); break; - case WORKBENCH_COLOR_OVERRIDE_VERTEX: - use_textures = false; - use_vertex_colors = true; - is_hair = false; - is_tiled = false; + } + case V3D_SHADING_OBJECT_COLOR: + case V3D_SHADING_VERTEX_COLOR: + alpha *= ob->color[3]; + copy_v3_v3(data->base_color, ob->color); break; - case WORKBENCH_COLOR_OVERRIDE_OFF: + case V3D_SHADING_MATERIAL_COLOR: + case V3D_SHADING_TEXTURE_COLOR: + default: + if (mat) { + alpha *= mat->a; + copy_v3_v3(data->base_color, &mat->r); + metallic = mat->metallic; + roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */ + } + else { + copy_v3_fl(data->base_color, 0.8f); + } break; } - /* NOTE: change MAX_ACCUM_SHADERS accordingly when modifying this function. */ - int index = 0; - /* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */ - index = wpd->shading.light; - SET_FLAG_FROM_TEST(index, use_textures, 1 << 2); - SET_FLAG_FROM_TEST(index, use_vertex_colors, 1 << 3); - SET_FLAG_FROM_TEST(index, is_hair, 1 << 4); - /* 1 bits SHADOWS (only facing factor) */ - SET_FLAG_FROM_TEST(index, SHADOW_ENABLED(wpd), 1 << 5); - SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6); - SET_FLAG_FROM_TEST(index, is_tiled && use_textures, 1 << 7); - BLI_assert(index < MAX_ACCUM_SHADERS); - return index; + uint32_t packed_metallic = unit_float_to_uchar_clamp(metallic); + uint32_t packed_roughness = unit_float_to_uchar_clamp(roughness); + uint32_t packed_alpha = unit_float_to_uchar_clamp(alpha); + data->packed_data = (packed_alpha << 16u) | (packed_roughness << 8u) | packed_metallic; } -eV3DShadingColorType workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, - Image *ima, - Object *ob, - bool use_sculpt_pbvh) +/* Return correct material or empty default material if slot is empty. */ +BLI_INLINE Material *workbench_object_material_get(Object *ob, int mat_nr) { - eV3DShadingColorType color_type = wpd->shading.color_type; - const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; - - if ((color_type == V3D_SHADING_TEXTURE_COLOR) && - (ima == NULL || use_sculpt_pbvh || (ob->dt < OB_TEXTURE))) { - color_type = V3D_SHADING_MATERIAL_COLOR; + Material *ma = BKE_object_material_get(ob, mat_nr); + if (ma == NULL) { + ma = BKE_material_default_empty(); } - if (color_type == V3D_SHADING_VERTEX_COLOR && (me == NULL || me->mloopcol == NULL)) { - color_type = V3D_SHADING_OBJECT_COLOR; - } - - switch (workbench_object_color_override_get(ob)) { - /* Force V3D_SHADING_TEXTURE_COLOR for active object when in texture painting - * no matter the shading color that the user has chosen, when there is no - * texture we will render the object with the error color */ - case WORKBENCH_COLOR_OVERRIDE_TEXTURE: - color_type = ima ? V3D_SHADING_TEXTURE_COLOR : V3D_SHADING_ERROR_COLOR; - break; - - /* Force V3D_SHADING_VERTEX_COLOR for active object when in vertex painting - * no matter the shading color that the user has chosen, when there is no - * vertex color we will render the object with the error color */ - case WORKBENCH_COLOR_OVERRIDE_VERTEX: - color_type = V3D_SHADING_VERTEX_COLOR; - break; - - case WORKBENCH_COLOR_OVERRIDE_OFF: - break; - } - - return color_type; + return ma; } -void workbench_material_get_image_and_mat( - Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp, Material **r_mat) +BLI_INLINE void workbench_material_get_image( + Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp) { bNode *node; - *r_mat = BKE_object_material_get(ob, mat_nr); + ED_object_get_active_image(ob, mat_nr, r_image, r_iuser, &node, NULL); if (node && *r_image) { switch (node->type) { @@ -358,53 +128,170 @@ void workbench_material_get_image_and_mat( } } -void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd, - DRWShadingGroup *grp, - WORKBENCH_MaterialData *material, - Object *ob, - const bool deferred, - const bool is_tiled, - const int interp) +/* Return true if the current material ubo has changed and needs to be rebind. */ +BLI_INLINE bool workbench_material_chunk_select(WORKBENCH_PrivateData *wpd, + uint32_t id, + uint32_t *r_mat_id) { - if (deferred && !workbench_is_matdata_pass_enabled(wpd)) { - return; + bool resource_changed = false; + /* Divide in chunks of MAX_MATERIAL. */ + uint32_t chunk = id >> 12u; + *r_mat_id = id & 0xFFFu; + /* We need to add a new chunk. */ + while (chunk >= wpd->material_chunk_count) { + wpd->material_chunk_count++; + wpd->material_ubo_data_curr = BLI_memblock_alloc(wpd->material_ubo_data); + wpd->material_ubo_curr = workbench_material_ubo_alloc(wpd); + wpd->material_chunk_curr = chunk; + resource_changed = true; + } + /* We need to go back to a previous chunk. */ + if (wpd->material_chunk_curr != chunk) { + wpd->material_ubo_data_curr = BLI_memblock_elem_get(wpd->material_ubo_data, 0, chunk); + wpd->material_ubo_curr = BLI_memblock_elem_get(wpd->material_ubo, 0, chunk); + wpd->material_chunk_curr = chunk; + resource_changed = true; } + return resource_changed; +} - const bool use_highlight = workbench_is_specular_highlight_enabled(wpd); - const bool use_texture = (V3D_SHADING_TEXTURE_COLOR == workbench_material_determine_color_type( - wpd, material->ima, ob, false)); - if (use_texture) { - if (is_tiled) { - GPUTexture *array_tex = GPU_texture_from_blender( - material->ima, material->iuser, NULL, GL_TEXTURE_2D_ARRAY); - GPUTexture *data_tex = GPU_texture_from_blender( - material->ima, material->iuser, NULL, GL_TEXTURE_1D_ARRAY); - DRW_shgroup_uniform_texture(grp, "image_tile_array", array_tex); - DRW_shgroup_uniform_texture(grp, "image_tile_data", data_tex); - } - else { - GPUTexture *tex = GPU_texture_from_blender( - material->ima, material->iuser, NULL, GL_TEXTURE_2D); - DRW_shgroup_uniform_texture(grp, "image", tex); +DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd, + Object *ob, + int mat_nr, + eV3DShadingColorType color_type, + bool hair, + bool *r_transp) +{ + Image *ima = NULL; + ImageUser *iuser = NULL; + int interp; + const bool infront = (ob->dtx & OB_DRAWXRAY) != 0; + + if (color_type == V3D_SHADING_TEXTURE_COLOR) { + workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp); + if (ima == NULL) { + /* Fallback to material color. */ + color_type = V3D_SHADING_MATERIAL_COLOR; } - DRW_shgroup_uniform_bool_copy( - grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL)); - DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST)); } - DRW_shgroup_uniform_vec4(grp, "materialColorAndMetal", material->base_color, 1); + switch (color_type) { + case V3D_SHADING_TEXTURE_COLOR: { + return workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, hair); + } + case V3D_SHADING_MATERIAL_COLOR: { + /* For now, we use the same ubo for material and object coloring but with different indices. + * This means they are mutually exclusive. */ + BLI_assert( + ELEM(wpd->shading.color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR)); + + Material *ma = workbench_object_material_get(ob, mat_nr); + + const bool transp = wpd->shading.xray_alpha < 1.0f || ma->a < 1.0f; + WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][hair]; + + if (r_transp && transp) { + *r_transp = true; + } - if (use_highlight) { - DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1); + DRWShadingGroup **grp_mat = NULL; + /* A hashmap stores material shgroups to pack all similar drawcalls together. */ + if (BLI_ghash_ensure_p(prepass->material_hash, ma, (void ***)&grp_mat)) { + return *grp_mat; + } + + uint32_t mat_id, id = wpd->material_index++; + + workbench_material_chunk_select(wpd, id, &mat_id); + workbench_material_ubo_data(wpd, ob, ma, &wpd->material_ubo_data_curr[mat_id], color_type); + + DRWShadingGroup *grp = prepass->common_shgrp; + *grp_mat = grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", mat_id); + return grp; + } + case V3D_SHADING_VERTEX_COLOR: { + const bool transp = wpd->shading.xray_alpha < 1.0f; + DRWShadingGroup *grp = wpd->prepass[transp][infront][hair].vcol_shgrp; + return grp; + } + default: { + /* For now, we use the same ubo for material and object coloring but with different indices. + * This means they are mutually exclusive. */ + BLI_assert( + !ELEM(wpd->shading.color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR)); + + uint32_t mat_id, id = DRW_object_resource_id_get(ob); + + bool resource_changed = workbench_material_chunk_select(wpd, id, &mat_id); + workbench_material_ubo_data(wpd, ob, NULL, &wpd->material_ubo_data_curr[mat_id], color_type); + + const bool transp = wpd->shading.xray_alpha < 1.0f || ob->color[3] < 1.0f; + DRWShadingGroup *grp = wpd->prepass[transp][infront][hair].common_shgrp; + if (resource_changed) { + grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); + } + if (r_transp && transp) { + *r_transp = true; + } + return grp; + } } } -void workbench_material_copy(WORKBENCH_MaterialData *dest_material, - const WORKBENCH_MaterialData *source_material) +/* If ima is null, search appropriate image node but will fallback to purple texture otherwise. */ +DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, + Object *ob, + int mat_nr, + Image *ima, + ImageUser *iuser, + int interp, + bool hair) { - copy_v3_v3(dest_material->base_color, source_material->base_color); - dest_material->metallic = source_material->metallic; - dest_material->roughness = source_material->roughness; - dest_material->ima = source_material->ima; - dest_material->iuser = source_material->iuser; + GPUTexture *tex = NULL, *tex_tile_data = NULL; + + if (ima == NULL) { + workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp); + } + + if (ima) { + if (ima->source == IMA_SRC_TILED) { + tex = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_2D_ARRAY); + tex_tile_data = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_1D_ARRAY); + } + else { + tex = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_2D); + } + } + + if (tex == NULL) { + printf("Image not foudn\n"); + tex = wpd->dummy_image_tx; + } + + const bool infront = (ob->dtx & OB_DRAWXRAY) != 0; + const bool transp = wpd->shading.xray_alpha < 1.0f; + WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][hair]; + + DRWShadingGroup **grp_tex = NULL; + /* A hashmap stores image shgroups to pack all similar drawcalls together. */ + if (BLI_ghash_ensure_p(prepass->material_hash, tex, (void ***)&grp_tex)) { + return *grp_tex; + } + + DRWShadingGroup *grp = (tex_tile_data) ? prepass->image_tiled_shgrp : prepass->image_shgrp; + + *grp_tex = grp = DRW_shgroup_create_sub(grp); + if (tex_tile_data) { + DRW_shgroup_uniform_texture_persistent(grp, "imageTileArray", tex); + DRW_shgroup_uniform_texture_persistent(grp, "imageTileData", tex_tile_data); + } + else { + DRW_shgroup_uniform_texture_persistent(grp, "imageTexture", tex); + } + DRW_shgroup_uniform_bool_copy(grp, "imagePremult", (ima && ima->alpha_mode == IMA_ALPHA_PREMUL)); + DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST)); + return grp; } diff --git a/source/blender/draw/engines/workbench/workbench_opaque.c b/source/blender/draw/engines/workbench/workbench_opaque.c new file mode 100644 index 00000000000..08511ca092c --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_opaque.c @@ -0,0 +1,165 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Opaque Pipeline: + * + * Use deferred shading to render opaque surfaces. + * This decouple the shading cost from scene complexity. + * + * The rendering is broken down in two passes: + * - the pre-pass where we render all the surfaces and output material data. + * - the composite pass where we compute the final aspect of the pixels. + */ + +#include "DRW_render.h" + +#include "GPU_extensions.h" + +#include "workbench_engine.h" +#include "workbench_private.h" + +void workbench_opaque_engine_init(WORKBENCH_Data *data) +{ + WORKBENCH_FramebufferList *fbl = data->fbl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DrawEngineType *owner = (DrawEngineType *)&workbench_opaque_engine_init; + + /* Reused the same textures format for transparent pipeline to share the textures. */ + const eGPUTextureFormat col_tex_format = GPU_RGBA16F; + const eGPUTextureFormat nor_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16F : GPU_RGBA16F; + + wpd->material_buffer_tx = DRW_texture_pool_query_fullscreen(col_tex_format, owner); + wpd->normal_buffer_tx = DRW_texture_pool_query_fullscreen(nor_tex_format, owner); + + GPU_framebuffer_ensure_config(&fbl->opaque_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(wpd->material_buffer_tx), + GPU_ATTACHMENT_TEXTURE(wpd->normal_buffer_tx), + GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx), + }); +} + +void workbench_opaque_cache_init(WORKBENCH_Data *data) +{ + WORKBENCH_PassList *psl = data->psl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + struct GPUShader *sh; + DRWShadingGroup *grp; + + const bool use_matcap = (wpd->shading.light == V3D_LIGHTING_MATCAP); + + { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + + int opaque = 0; + for (int infront = 0; infront < 2; infront++) { + DRWPass *pass; + if (infront) { + DRW_PASS_CREATE(psl->opaque_infront_ps, state | wpd->cull_state | wpd->clip_state); + pass = psl->opaque_infront_ps; + } + else { + DRW_PASS_CREATE(psl->opaque_ps, state | wpd->cull_state | wpd->clip_state); + pass = psl->opaque_ps; + } + + for (int hair = 0; hair < 2; hair++) { + wpd->prepass[opaque][infront][hair].material_hash = BLI_ghash_ptr_new(__func__); + + sh = workbench_shader_opaque_get(wpd, hair); + + wpd->prepass[opaque][infront][hair].common_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1); + + wpd->prepass[opaque][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */ + + sh = workbench_shader_opaque_image_get(wpd, hair, false); + + wpd->prepass[opaque][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ + DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap); + + sh = workbench_shader_opaque_image_get(wpd, hair, true); + + wpd->prepass[opaque][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ + DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap); + } + } + } + { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_STENCIL_EQUAL; + + DRW_PASS_CREATE(psl->composite_ps, state); + + sh = workbench_shader_composite_get(wpd); + + grp = DRW_shgroup_create(sh, psl->composite_ps); + DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_texture_persistent(grp, "materialBuffer", wpd->material_buffer_tx); + DRW_shgroup_uniform_texture_persistent(grp, "normalBuffer", wpd->normal_buffer_tx); + DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false); + DRW_shgroup_stencil_mask(grp, 0x00); + + if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { + BKE_studiolight_ensure_flag(wpd->studio_light, + STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE | + STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE); + struct GPUTexture *diff_tx = wpd->studio_light->matcap_diffuse.gputexture; + struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture; + const bool use_spec = workbench_is_specular_highlight_enabled(wpd); + spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx; + DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx); + DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx); + } + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + if (SHADOW_ENABLED(wpd)) { + grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", true); + DRW_shgroup_state_disable(grp, DRW_STATE_STENCIL_EQUAL); + DRW_shgroup_state_enable(grp, DRW_STATE_STENCIL_NEQUAL); + DRW_shgroup_stencil_mask(grp, 0x00); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + } + { + DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_WRITE_STENCIL | + DRW_STATE_STENCIL_ALWAYS; + + DRW_PASS_CREATE(psl->merge_infront_ps, state); + + sh = workbench_shader_merge_infront_get(wpd); + + grp = DRW_shgroup_create(sh, psl->merge_infront_ps); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth_in_front); + DRW_shgroup_stencil_mask(grp, 0x00); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } +} diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index bb93864966e..a68b66e0f85 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -34,16 +34,14 @@ #include "workbench_engine.h" +extern struct DrawEngineType draw_engine_workbench; + #define WORKBENCH_ENGINE "BLENDER_WORKBENCH" -#define MAX_COMPOSITE_SHADERS (1 << 7) -#define MAX_PREPASS_SHADERS (1 << 8) -#define MAX_ACCUM_SHADERS (1 << 8) -#define MAX_CAVITY_SHADERS (1 << 3) - -#define TEXTURE_DRAWING_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) -#define VERTEX_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) -#define MATERIAL_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_MATERIAL_COLOR) -#define FLAT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_FLAT) + +#define MAX_MATERIAL (1 << 12) + +#define DEBUG_SHADOW_VOLUME 0 + #define STUDIOLIGHT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_STUDIO) #define MATCAP_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_MATCAP) #define USE_WORLD_ORIENTATION(wpd) ((wpd->shading.flag & V3D_SHADING_WORLD_ORIENTATION) != 0) @@ -63,45 +61,24 @@ (wpd->shading.cavity_type == V3D_SHADING_CAVITY_BOTH))) #define CAVITY_ENABLED(wpd) (CURVATURE_ENABLED(wpd) || SSAO_ENABLED(wpd)) #define SHADOW_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SHADOW) -#define GHOST_ENABLED(psl) \ - (!DRW_pass_is_empty(psl->ghost_prepass_pass) || !DRW_pass_is_empty(psl->ghost_prepass_hair_pass)) #define CULL_BACKFACE_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_BACKFACE_CULLING) != 0) -#define OIT_ENABLED(wpd) \ - (ELEM(wpd->shading.color_type, \ - V3D_SHADING_MATERIAL_COLOR, \ - V3D_SHADING_OBJECT_COLOR, \ - V3D_SHADING_TEXTURE_COLOR, \ - V3D_SHADING_VERTEX_COLOR)) - -#define IS_NAVIGATING(wpd) \ - ((DRW_context_state_get()->rv3d) && \ - (DRW_context_state_get()->rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING))) #define OBJECT_OUTLINE_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) #define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) -#define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) \ - (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd)) -#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) \ - (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) || SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) #define NORMAL_ENCODING_ENABLED() (true) -#define WORLD_CLIPPING_ENABLED(wpd) (wpd->world_clip_planes != NULL) struct RenderEngine; struct RenderLayer; struct rcti; typedef struct WORKBENCH_FramebufferList { - /* Deferred render buffers */ - struct GPUFrameBuffer *prepass_fb; - struct GPUFrameBuffer *ghost_prepass_fb; - struct GPUFrameBuffer *cavity_fb; - struct GPUFrameBuffer *composite_fb; - struct GPUFrameBuffer *id_clear_fb; + struct GPUFrameBuffer *opaque_fb; + struct GPUFrameBuffer *opaque_infront_fb; - struct GPUFrameBuffer *effect_fb; - struct GPUFrameBuffer *effect_taa_fb; - struct GPUFrameBuffer *depth_buffer_fb; - struct GPUFrameBuffer *color_only_fb; + struct GPUFrameBuffer *transp_accum_fb; + struct GPUFrameBuffer *transp_accum_infront_fb; + + struct GPUFrameBuffer *id_clear_fb; struct GPUFrameBuffer *dof_downsample_fb; struct GPUFrameBuffer *dof_coc_tile_h_fb; @@ -110,10 +87,9 @@ typedef struct WORKBENCH_FramebufferList { struct GPUFrameBuffer *dof_blur1_fb; struct GPUFrameBuffer *dof_blur2_fb; - /* Forward render buffers */ - struct GPUFrameBuffer *object_outline_fb; - struct GPUFrameBuffer *transparent_accum_fb; - struct GPUFrameBuffer *transparent_revealage_fb; + struct GPUFrameBuffer *antialiasing_fb; + struct GPUFrameBuffer *smaa_edge_fb; + struct GPUFrameBuffer *smaa_weight_fb; } WORKBENCH_FramebufferList; typedef struct WORKBENCH_TextureList { @@ -121,34 +97,35 @@ typedef struct WORKBENCH_TextureList { struct GPUTexture *coc_halfres_tx; struct GPUTexture *history_buffer_tx; struct GPUTexture *depth_buffer_tx; + struct GPUTexture *smaa_search_tx; + struct GPUTexture *smaa_area_tx; + struct GPUTexture *dummy_image_tx; + struct GPUTexture *dummy_volume_tx; + struct GPUTexture *dummy_coba_tx; } WORKBENCH_TextureList; typedef struct WORKBENCH_StorageList { - struct WORKBENCH_PrivateData *g_data; - struct WORKBENCH_EffectInfo *effects; + struct WORKBENCH_PrivateData *wpd; float *dof_ubo_data; } WORKBENCH_StorageList; typedef struct WORKBENCH_PassList { - /* deferred rendering */ - struct DRWPass *prepass_pass; - struct DRWPass *prepass_hair_pass; - struct DRWPass *ghost_prepass_pass; - struct DRWPass *ghost_prepass_hair_pass; - struct DRWPass *cavity_pass; - struct DRWPass *shadow_depth_pass_pass; - struct DRWPass *shadow_depth_pass_mani_pass; - struct DRWPass *shadow_depth_fail_pass; - struct DRWPass *shadow_depth_fail_mani_pass; - struct DRWPass *shadow_depth_fail_caps_pass; - struct DRWPass *shadow_depth_fail_caps_mani_pass; - struct DRWPass *composite_pass; - struct DRWPass *composite_shadow_pass; - struct DRWPass *oit_composite_pass; - struct DRWPass *background_pass; - struct DRWPass *background_pass_clip; - struct DRWPass *ghost_resolve_pass; - struct DRWPass *effect_aa_pass; + struct DRWPass *opaque_ps; + struct DRWPass *opaque_infront_ps; + + struct DRWPass *transp_resolve_ps; + struct DRWPass *transp_accum_ps; + struct DRWPass *transp_accum_infront_ps; + + struct DRWPass *shadow_ps[2]; + + struct DRWPass *merge_infront_ps; + + struct DRWPass *cavity_ps; + struct DRWPass *outline_ps; + + struct DRWPass *composite_ps; + struct DRWPass *dof_down_ps; struct DRWPass *dof_down2_ps; struct DRWPass *dof_flatten_v_ps; @@ -158,12 +135,13 @@ typedef struct WORKBENCH_PassList { struct DRWPass *dof_blur1_ps; struct DRWPass *dof_blur2_ps; struct DRWPass *dof_resolve_ps; - struct DRWPass *volume_pass; - /* forward rendering */ - struct DRWPass *transparent_accum_pass; - struct DRWPass *object_outline_pass; - struct DRWPass *depth_pass; + struct DRWPass *volume_ps; + + struct DRWPass *aa_accum_ps; + struct DRWPass *aa_edge_ps; + struct DRWPass *aa_weight_ps; + struct DRWPass *aa_resolve_ps; } WORKBENCH_PassList; typedef struct WORKBENCH_Data { @@ -180,84 +158,164 @@ typedef struct WORKBENCH_UBO_Light { float diffuse_color[3], wrapped; } WORKBENCH_UBO_Light; +typedef struct WORKBENCH_UBO_Material { + float base_color[3]; + /* Packed data into a int. Decoded in the shader. */ + uint32_t packed_data; +} WORKBENCH_UBO_Material; + typedef struct WORKBENCH_UBO_World { + float viewvecs[3][4]; + float viewport_size[2], viewport_size_inv[2]; float object_outline_color[4]; float shadow_direction_vs[4]; + float shadow_focus, shadow_shift, shadow_mul, shadow_add; WORKBENCH_UBO_Light lights[4]; float ambient_color[4]; - int num_lights; - int matcap_orientation; + + int cavity_sample_start; + int cavity_sample_end; + float cavity_sample_count_inv; + float cavity_jitter_scale; + + float cavity_valley_factor; + float cavity_ridge_factor; + float cavity_attenuation; + float cavity_distance; + float curvature_ridge; float curvature_valley; + float ui_scale; + float _pad0; + + int matcap_orientation; + int use_specular; /* Bools are 32bit ints in GLSL. */ + int _pad1; + int _pad2; } WORKBENCH_UBO_World; + BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16) +BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_Light, 16) +BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_Material, 16) -typedef struct WORKBENCH_PrivateData { +typedef struct WORKBENCH_Prepass { + /** Hash storing shading group for each Material or GPUTexture to reduce state changes. */ struct GHash *material_hash; - struct GHash *material_transp_hash; - struct GPUShader *prepass_sh; - struct GPUShader *prepass_hair_sh; - struct GPUShader *prepass_uniform_sh; - struct GPUShader *prepass_uniform_hair_sh; - struct GPUShader *prepass_textured_sh; - struct GPUShader *prepass_textured_array_sh; - struct GPUShader *prepass_vertex_sh; - struct GPUShader *composite_sh; - struct GPUShader *background_sh; - struct GPUShader *transparent_accum_sh; - struct GPUShader *transparent_accum_hair_sh; - struct GPUShader *transparent_accum_uniform_sh; - struct GPUShader *transparent_accum_uniform_hair_sh; - struct GPUShader *transparent_accum_textured_sh; - struct GPUShader *transparent_accum_textured_array_sh; - struct GPUShader *transparent_accum_vertex_sh; + /** First common (non-vcol and non-image colored) shading group to created subgroups. */ + struct DRWShadingGroup *common_shgrp; + /** First Vertex Color shading group to created subgroups. */ + struct DRWShadingGroup *vcol_shgrp; + /** First Image shading group to created subgroups. */ + struct DRWShadingGroup *image_shgrp; + /** First UDIM (tiled image) shading group to created subgroups. */ + struct DRWShadingGroup *image_tiled_shgrp; +} WORKBENCH_Prepass; + +typedef struct WORKBENCH_PrivateData { + /** ViewLayerData for faster access. */ + struct WORKBENCH_ViewLayerData *vldata; + /** Copy of draw_ctx->sh_cfg for faster access. */ + eGPUShaderConfig sh_cfg; + /** Global clip and cull states. */ + DRWState clip_state, cull_state; + /** Copy of scene->display.shading or v3d->shading for viewport. */ View3DShading shading; + /** Chosen studiolight or matcap. */ StudioLight *studio_light; + /** Copy of ctx_draw->scene for faster access. */ + struct Scene *scene; + /** Shorthand version of U global for user preferences. */ const UserDef *preferences; - /* Does this instance owns the `world_ubo` field. - * Normally the field is borrowed from `WORKBENCH_WorldData`. In case that - * there is no World attached to the scene the UBO cannot be cached and should - * be freed after using. */ - bool is_world_ubo_owner; + /** Copy of context mode for faster access. */ + eContextObjectMode ctx_mode; + /** Shorthand for wpd->vldata->world_ubo. */ struct GPUUniformBuffer *world_ubo; - struct DRWShadingGroup *shadow_shgrp; - struct DRWShadingGroup *depth_shgrp; - WORKBENCH_UBO_World world_data; - float shadow_multiplier; - float shadow_shift; - float shadow_focus; - float cached_shadow_direction[3]; + /** Background color to clear the color buffer with. */ + float background_color[4]; + + /* Shadow */ + /** Previous shadow direction to test if shadow has changed. */ + float shadow_cached_direction[3]; + /** Current shadow direction in world space. */ + float shadow_direction_ws[3]; + /** Shadow precomputed matrices. */ float shadow_mat[4][4]; float shadow_inv[4][4]; - /* Far plane of the view frustum. */ + /** Far plane of the view frustum. Used for shadow volume extrusion. */ float shadow_far_plane[4]; - /* Near plane corners in shadow space. */ - float shadow_near_corners[4][3]; - /* min and max of shadow_near_corners. allow fast test */ + /** Min and max of shadow_near_corners. Speed up culling test. */ float shadow_near_min[3]; float shadow_near_max[3]; - /* This is a parallelogram, so only 2 normal and distance to the edges. */ + /** This is a parallelogram, so only 2 normal and distance to the edges. */ float shadow_near_sides[2][4]; + /* Shadow shading groups. First array elem is for non-manifold geom and second for manifold. */ + struct DRWShadingGroup *shadow_pass_grp[2]; + struct DRWShadingGroup *shadow_fail_grp[2]; + struct DRWShadingGroup *shadow_fail_caps_grp[2]; + /** If the shadow has changed direction and ob bboxes needs to be updated. */ bool shadow_changed; - bool is_playback; - float (*world_clip_planes)[4]; + /* Temporal Antialiasing */ + /** Total number of samples to after which TAA stops accumulating samples. */ + int taa_sample_len; + /** Current TAA sample index in [0..taa_sample_len[ range. */ + int taa_sample; + /** Inverse of taa_sample to divide the accumulation buffer. */ + float taa_sample_inv; + /** If the view has been updated and TAA needs to be reset. */ + bool view_updated; + /** View */ + struct DRWView *view; + /** Last projection matrix to see if view is still valid. */ + float last_mat[4][4]; + + /* Smart Morphological Anti-Aliasing */ + /** Temp buffers to store edges and weights. */ + struct GPUTexture *smaa_edge_tx; + struct GPUTexture *smaa_weight_tx; + /** Weight of the smaa pass. */ + float smaa_mix_factor; + + /** Opaque pipeline buffers. */ + struct GPUTexture *material_buffer_tx; + struct GPUTexture *composite_buffer_tx; + struct GPUTexture *normal_buffer_tx; + /** Transparent pipeline buffers. */ + struct GPUTexture *accum_buffer_tx; + struct GPUTexture *reveal_buffer_tx; + /** Object IDs buffer for curvature & outline. */ + struct GPUTexture *object_id_tx; + + /** Prepass infos for each draw types [transparent][infront][hair]. */ + WORKBENCH_Prepass prepass[2][2][2]; + + /* Materials */ + /** Copy of vldata->material_ubo for faster access. */ + struct BLI_memblock *material_ubo; + /** Copy of vldata->material_ubo_data for faster access. */ + struct BLI_memblock *material_ubo_data; + /** Current material chunk being filled by workbench_material_setup_ex(). */ + WORKBENCH_UBO_Material *material_ubo_data_curr; + struct GPUUniformBuffer *material_ubo_curr; + /** Copy of txl->dummy_image_tx for faster access. */ + struct GPUTexture *dummy_image_tx; + /** Total number of used material chunk. */ + int material_chunk_count; + /** Index of current material chunk. */ + int material_chunk_curr; + /** Index of current material inside the material chunk. Only for material coloring mode. */ + int material_index; /* Volumes */ - bool volumes_do; + /** List of smoke domain textures to free after drawing. */ ListBase smoke_domains; - /* Ssao */ - float winmat[4][4]; - float viewvecs[3][4]; - float ssao_params[4]; - float ssao_settings[4]; - - /* Dof */ + /* Depth of Field */ + /** Depth of field temp buffers. */ struct GPUTexture *dof_blur_tx; struct GPUTexture *coc_temp_tx; struct GPUTexture *coc_tiles_tx[2]; - struct GPUUniformBuffer *dof_ubo; + /** Depth of field parameters. */ float dof_aperturesize; float dof_distance; float dof_invsensorsize; @@ -265,37 +323,15 @@ typedef struct WORKBENCH_PrivateData { float dof_blades; float dof_rotation; float dof_ratio; - bool dof_enabled; - /* Color Management */ - bool use_color_management; - bool use_color_render_settings; + /** True if any volume needs to be rendered. */ + bool volumes_do; + /** Convenience boolean. */ + bool dof_enabled; + bool is_playback; + bool is_navigating; } WORKBENCH_PrivateData; /* Transient data */ -typedef struct WORKBENCH_EffectInfo { - /** View */ - struct DRWView *view; - /** Last projection matrix to see if view is still valid. */ - float last_mat[4][4]; - int jitter_index; - float taa_mix_factor; - bool view_updated; -} WORKBENCH_EffectInfo; - -typedef struct WORKBENCH_MaterialData { - float base_color[3], metallic; - float roughness, alpha; - eV3DShadingColorType color_type; - int interp; - Image *ima; - ImageUser *iuser; - - /* Linked shgroup for drawing */ - DRWShadingGroup *shgrp; - /* forward rendering */ - DRWShadingGroup *shgrp_object_outline; -} WORKBENCH_MaterialData; - typedef struct WORKBENCH_ObjectData { DrawData dd; @@ -307,20 +343,21 @@ typedef struct WORKBENCH_ObjectData { bool shadow_bbox_dirty; } WORKBENCH_ObjectData; -typedef struct WORKBENCH_WorldData { - DrawData dd; - /* The cached `GPUUniformBuffer`, that is reused between draw calls. */ +typedef struct WORKBENCH_ViewLayerData { + /** Depth of field sample location array.*/ + struct GPUUniformBuffer *dof_sample_ubo; + /** All constant data used for a render loop.*/ struct GPUUniformBuffer *world_ubo; -} WORKBENCH_WorldData; - -/* Enumeration containing override options for base color rendering. - * This is used to during painting to force the base color to show what you are - * painting using the selected lighting model. */ -typedef enum WORKBENCH_ColorOverride { - WORKBENCH_COLOR_OVERRIDE_OFF = 0, - WORKBENCH_COLOR_OVERRIDE_TEXTURE = CTX_MODE_PAINT_TEXTURE, - WORKBENCH_COLOR_OVERRIDE_VERTEX = CTX_MODE_PAINT_VERTEX, -} WORKBENCH_ColorOverride; + /** Cavity sample location array.*/ + struct GPUUniformBuffer *cavity_sample_ubo; + /** Blue noise texture used to randomize the sampling of some effects.*/ + struct GPUTexture *cavity_jitter_tx; + /** Materials ubos allocated in a memblock for easy bookeeping. */ + struct BLI_memblock *material_ubo; + struct BLI_memblock *material_ubo_data; + /** Number of samples for which cavity_sample_ubo is valid. */ + int cavity_sample_count; +} WORKBENCH_ViewLayerData; /* inline helper functions */ BLI_INLINE bool workbench_is_specular_highlight_enabled(WORKBENCH_PrivateData *wpd) @@ -333,234 +370,129 @@ BLI_INLINE bool workbench_is_specular_highlight_enabled(WORKBENCH_PrivateData *w return false; } -BLI_INLINE bool workbench_is_taa_enabled(WORKBENCH_PrivateData *wpd) -{ - if (DRW_state_is_image_render()) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - if (draw_ctx->v3d) { - return draw_ctx->scene->display.viewport_aa > SCE_DISPLAY_AA_FXAA; - } - else { - return draw_ctx->scene->display.render_aa > SCE_DISPLAY_AA_FXAA; - } - } - else { - return !(IS_NAVIGATING(wpd) || wpd->is_playback) && - wpd->preferences->viewport_aa > SCE_DISPLAY_AA_FXAA; - } -} - -BLI_INLINE bool workbench_is_fxaa_enabled(WORKBENCH_PrivateData *wpd) -{ - if (DRW_state_is_image_render()) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - if (draw_ctx->v3d) { - return draw_ctx->scene->display.viewport_aa == SCE_DISPLAY_AA_FXAA; - } - else { - return draw_ctx->scene->display.render_aa == SCE_DISPLAY_AA_FXAA; - } - } - else { - if (wpd->preferences->viewport_aa == SCE_DISPLAY_AA_FXAA) { - return true; - } - - /* when navigating or animation playback use FXAA if scene uses TAA. */ - return (IS_NAVIGATING(wpd) || wpd->is_playback) && - wpd->preferences->viewport_aa > SCE_DISPLAY_AA_FXAA; - } -} - -/** Is texture paint mode enabled (globally) */ -BLI_INLINE bool workbench_is_in_texture_paint_mode(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - return draw_ctx->object_mode == OB_MODE_TEXTURE_PAINT; -} - -/** Is vertex paint mode enabled (globally) */ -BLI_INLINE bool workbench_is_in_vertex_paint_mode(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - return draw_ctx->object_mode == OB_MODE_VERTEX_PAINT; -} - -/* Must the `View3DShading.color_type` be overriden for the given object. */ -BLI_INLINE WORKBENCH_ColorOverride workbench_object_color_override_get(Object *ob) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - if (ob->type == OB_MESH && (draw_ctx->obact == ob)) { - const enum eContextObjectMode mode = CTX_data_mode_enum_ex( - draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode); - if (mode == CTX_MODE_PAINT_TEXTURE) { - return WORKBENCH_COLOR_OVERRIDE_TEXTURE; - } - else if (mode == CTX_MODE_PAINT_VERTEX) { - return WORKBENCH_COLOR_OVERRIDE_VERTEX; - } - } - - return WORKBENCH_COLOR_OVERRIDE_OFF; -} - -BLI_INLINE bool workbench_is_matdata_pass_enabled(WORKBENCH_PrivateData *wpd) -{ - return (wpd->shading.color_type != V3D_SHADING_SINGLE_COLOR || MATCAP_ENABLED(wpd)) || - workbench_is_in_texture_paint_mode() || workbench_is_in_vertex_paint_mode(); -} - -/** - * Get the default texture format to be used by the color and history buffers. - * - * Use GPU_RGBA16F for final renderings and for drawing textures. This - * allows displaying HDRI textures. Vertex Colors uses GPU_RGBA16 to resolve - * color banding issues (T66100). All other modes use GPU_RGBA8 to reduce - * bandwidth and gpu memory. - */ -BLI_INLINE eGPUTextureFormat workbench_color_texture_format(const WORKBENCH_PrivateData *wpd) -{ - eGPUTextureFormat result; - if (DRW_state_is_image_render() || workbench_is_in_texture_paint_mode() || - TEXTURE_DRAWING_ENABLED(wpd)) { - result = GPU_RGBA16F; - } - else { - result = GPU_RGBA16; - } - return result; -} - -/* workbench_deferred.c */ -void workbench_deferred_engine_init(WORKBENCH_Data *vedata); -void workbench_deferred_engine_free(void); -void workbench_deferred_draw_scene(WORKBENCH_Data *vedata); -void workbench_deferred_draw_finish(WORKBENCH_Data *vedata); -void workbench_deferred_cache_init(WORKBENCH_Data *vedata); -void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob); -void workbench_deferred_cache_finish(WORKBENCH_Data *vedata); - -/* workbench_forward.c */ -void workbench_forward_engine_init(WORKBENCH_Data *vedata); -void workbench_forward_engine_free(void); -void workbench_forward_draw_scene(WORKBENCH_Data *vedata); -void workbench_forward_draw_finish(WORKBENCH_Data *vedata); -void workbench_forward_cache_init(WORKBENCH_Data *vedata); -void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob); -void workbench_forward_cache_finish(WORKBENCH_Data *vedata); - -/* For OIT in deferred */ -void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg); -void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg); -WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data( - WORKBENCH_Data *vedata, - Object *ob, - Material *mat, - Image *ima, - ImageUser *iuser, - eV3DShadingColorType color_type, - int interp); - -/* workbench_effect_aa.c */ -void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx); -void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx); - -/* workbench_effect_fxaa.c */ -void workbench_fxaa_engine_init(void); -void workbench_fxaa_engine_free(void); -DRWPass *workbench_fxaa_create_pass(GPUTexture **color_buffer_tx); - -/* workbench_effect_taa.c */ -void workbench_taa_engine_init(WORKBENCH_Data *vedata); -void workbench_taa_engine_free(void); -DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_buffer_tx); -void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata); -void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata); -void workbench_taa_view_updated(WORKBENCH_Data *vedata); -int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata); -int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *vedata); - +/* workbench_opaque.c */ +void workbench_opaque_engine_init(WORKBENCH_Data *data); +void workbench_opaque_cache_init(WORKBENCH_Data *data); + +/* workbench_transparent.c */ +void workbench_transparent_engine_init(WORKBENCH_Data *data); +void workbench_transparent_cache_init(WORKBENCH_Data *data); +void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data); + +/* workbench_shadow.c */ +void workbench_shadow_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd); +void workbench_shadow_cache_init(WORKBENCH_Data *data); +void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const bool has_transp_mat); + +/* workbench_shader.c */ +GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, bool hair); +GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd, bool hair, bool tiled); +GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd); +GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *wpd); + +GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd, bool hair); +GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd, + bool hair, + bool tiled); +GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd); + +GPUShader *workbench_shader_shadow_pass_get(bool manifold); +GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap); + +GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature); +GPUShader *workbench_shader_outline_get(void); + +GPUShader *workbench_shader_antialiasing_accumulation_get(void); +GPUShader *workbench_shader_antialiasing_get(int stage); + +GPUShader *workbench_shader_volume_get(bool slice, bool coba, bool cubic); + +void workbench_shader_depth_of_field_get(GPUShader **prepare_sh, + GPUShader **downsample_sh, + GPUShader **blur1_sh, + GPUShader **blur2_sh, + GPUShader **resolve_sh); + +void workbench_shader_library_ensure(void); +void workbench_shader_free(void); + +/* workbench_effect_antialiasing.c */ +int workbench_antialiasing_sample_count_get(WORKBENCH_PrivateData *wpd); +void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata); +void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata); +void workbench_antialiasing_view_updated(WORKBENCH_Data *vedata); +bool workbench_antialiasing_setup(WORKBENCH_Data *vedata); +void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata); + +/* workbench_effect_cavity.c */ +void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd); +void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd); +void workbench_cavity_cache_init(WORKBENCH_Data *data); + +/* workbench_effect_outline.c */ +void workbench_outline_cache_init(WORKBENCH_Data *data); /* workbench_effect_dof.c */ -void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera); -void workbench_dof_engine_free(void); -void workbench_dof_create_pass(WORKBENCH_Data *vedata, - GPUTexture **dof_input, - GPUTexture *noise_tex); +void workbench_dof_engine_init(WORKBENCH_Data *vedata); +void workbench_dof_cache_init(WORKBENCH_Data *vedata); void workbench_dof_draw_pass(WORKBENCH_Data *vedata); /* workbench_materials.c */ -eV3DShadingColorType workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, - Image *ima, - Object *ob, - bool use_sculpt_pbvh); -void workbench_material_get_image_and_mat( - Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp, Material **r_mat); -char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override); -void workbench_material_update_data(WORKBENCH_PrivateData *wpd, - Object *ob, - Material *mat, - WORKBENCH_MaterialData *data, - int color_type); -uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost); -int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd); -int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override); -int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override); -void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd, - DRWShadingGroup *grp, - WORKBENCH_MaterialData *material, - Object *ob, - const bool deferred, - const bool is_tiled, - const int interp); -void workbench_material_copy(WORKBENCH_MaterialData *dest_material, - const WORKBENCH_MaterialData *source_material); - -/* workbench_studiolight.c */ -void studiolight_update_world(WORKBENCH_PrivateData *wpd, - StudioLight *sl, - WORKBENCH_UBO_World *wd); -void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3]); -bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed); -float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed); -bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed); +void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd, + Object *ob, + Material *mat, + WORKBENCH_UBO_Material *data, + eV3DShadingColorType color_type); + +DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd, + Object *ob, + int mat_nr, + eV3DShadingColorType color_type, + bool hair, + bool *r_transp); +DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, + Object *ob, + int mat_nr, + Image *ima, + ImageUser *iuser, + int interp, + bool hair); + +#define workbench_material_setup(wpd, ob, mat_nr, color_type, r_transp) \ + workbench_material_setup_ex(wpd, ob, mat_nr, color_type, false, r_transp) +#define workbench_image_setup(wpd, ob, mat_nr, ima, iuser, interp) \ + workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, false) + +#define workbench_material_hair_setup(wpd, ob, mat_nr, color_type) \ + workbench_material_setup_ex(wpd, ob, mat_nr, color_type, true, 0) +#define workbench_image_hair_setup(wpd, ob, mat_nr, ima, iuser, interp) \ + workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, true) /* workbench_data.c */ -void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info); void workbench_private_data_init(WORKBENCH_PrivateData *wpd); -void workbench_private_data_free(WORKBENCH_PrivateData *wpd); -void workbench_private_data_get_light_direction(float r_light_direction[3]); -void workbench_clear_color_get(float color[4]); +void workbench_update_world_ubo(WORKBENCH_PrivateData *wpd); +void workbench_update_material_ubos(WORKBENCH_PrivateData *wpd); +struct GPUUniformBuffer *workbench_material_ubo_alloc(WORKBENCH_PrivateData *wpd); /* workbench_volume.c */ -void workbench_volume_engine_init(void); -void workbench_volume_engine_free(void); +void workbench_volume_engine_init(WORKBENCH_Data *vedata); void workbench_volume_cache_init(WORKBENCH_Data *vedata); void workbench_volume_cache_populate(WORKBENCH_Data *vedata, - Scene *scene, - Object *ob, + struct Scene *UNUSED(scene), + struct Object *ob, struct ModifierData *md); -void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd); +void workbench_volume_draw_pass(WORKBENCH_Data *vedata); +void workbench_volume_draw_finish(WORKBENCH_Data *vedata); + +/* workbench_engine.c */ +void workbench_engine_init(void *ved); +void workbench_cache_init(void *ved); +void workbench_cache_populate(void *ved, Object *ob); +void workbench_cache_finish(void *ved); +void workbench_draw_sample(void *ved); +void workbench_draw_finish(void *ved); /* workbench_render.c */ -void workbench_render(WORKBENCH_Data *vedata, +void workbench_render(void *ved, struct RenderEngine *engine, struct RenderLayer *render_layer, const struct rcti *rect); diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c index 6e005e7ccaf..5a315e80a47 100644 --- a/source/blender/draw/engines/workbench/workbench_render.c +++ b/source/blender/draw/engines/workbench/workbench_render.c @@ -41,20 +41,12 @@ #include "workbench_private.h" -static void workbench_render_deferred_cache(void *vedata, - struct Object *ob, - struct RenderEngine *UNUSED(engine), - struct Depsgraph *UNUSED(depsgraph)) +static void workbench_render_cache(void *vedata, + struct Object *ob, + struct RenderEngine *UNUSED(engine), + struct Depsgraph *UNUSED(depsgraph)) { - workbench_deferred_solid_cache_populate(vedata, ob); -} - -static void workbench_render_forward_cache(void *vedata, - struct Object *ob, - struct RenderEngine *UNUSED(engine), - struct Depsgraph *UNUSED(depsgraph)) -{ - workbench_forward_cache_populate(vedata, ob); + workbench_cache_populate(vedata, ob); } static void workbench_render_matrices_init(RenderEngine *engine, Depsgraph *depsgraph) @@ -171,18 +163,11 @@ static void workbench_render_result_z(struct RenderLayer *rl, } } -static void workbench_render_framebuffers_finish(void) -{ -} - -void workbench_render(WORKBENCH_Data *data, - RenderEngine *engine, - RenderLayer *render_layer, - const rcti *rect) +void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer, const rcti *rect) { + WORKBENCH_Data *data = ved; DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene = draw_ctx->scene; Depsgraph *depsgraph = draw_ctx->depsgraph; workbench_render_matrices_init(engine, depsgraph); @@ -191,60 +176,32 @@ void workbench_render(WORKBENCH_Data *data, return; } - const bool deferred = !XRAY_FLAG_ENABLED(&scene->display); + workbench_engine_init(data); - if (deferred) { - /* Init engine. */ - workbench_deferred_engine_init(data); + workbench_cache_init(data); + DRW_render_object_iter(data, engine, depsgraph, workbench_render_cache); + workbench_cache_finish(data); - /* Init objects. */ - workbench_deferred_cache_init(data); - DRW_render_object_iter(data, engine, depsgraph, workbench_render_deferred_cache); - workbench_deferred_cache_finish(data); - DRW_render_instance_buffer_finish(); + DRW_render_instance_buffer_finish(); - /* Also we weed to have a correct fbo bound for DRW_hair_update */ - GPU_framebuffer_bind(dfbl->color_only_fb); - DRW_hair_update(); - - /* Draw. */ - int num_samples = workbench_taa_calculate_num_iterations(data); - for (int sample = 0; sample < num_samples; sample++) { - if (RE_engine_test_break(engine)) { - break; - } - workbench_deferred_draw_scene(data); - } + /* Also we weed to have a correct fbo bound for DRW_hair_update */ + GPU_framebuffer_bind(dfbl->default_fb); + DRW_hair_update(); - workbench_deferred_draw_finish(data); - } - else { - /* Init engine. */ - workbench_forward_engine_init(data); - - /* Init objects. */ - workbench_forward_cache_init(data); - DRW_render_object_iter(data, engine, depsgraph, workbench_render_forward_cache); - workbench_forward_cache_finish(data); - DRW_render_instance_buffer_finish(); - - /* Also we weed to have a correct fbo bound for DRW_hair_update */ - GPU_framebuffer_bind(dfbl->color_only_fb); - DRW_hair_update(); - - /* Draw. */ - int num_samples = workbench_taa_calculate_num_iterations(data); - for (int sample = 0; sample < num_samples; sample++) { - if (RE_engine_test_break(engine)) { - break; - } + GPU_framebuffer_bind(dfbl->default_fb); + GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f); - workbench_forward_draw_scene(data); + WORKBENCH_PrivateData *wpd = data->stl->wpd; + while (wpd->taa_sample < max_ii(1, wpd->taa_sample_len)) { + if (RE_engine_test_break(engine)) { + break; } - - workbench_forward_draw_finish(data); + workbench_update_world_ubo(wpd); + workbench_draw_sample(data); } + workbench_draw_finish(data); + /* Write render output. */ const char *viewname = RE_GetActiveRenderView(engine->re); RenderPass *rp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname); @@ -260,8 +217,6 @@ void workbench_render(WORKBENCH_Data *data, rp->rect); workbench_render_result_z(render_layer, viewname, rect); - - workbench_render_framebuffers_finish(); } void workbench_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer) diff --git a/source/blender/draw/engines/workbench/workbench_shader.c b/source/blender/draw/engines/workbench/workbench_shader.c new file mode 100644 index 00000000000..14a980fe628 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_shader.c @@ -0,0 +1,533 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "BLI_dynstr.h" + +#include "workbench_engine.h" +#include "workbench_private.h" + +extern char datatoc_common_hair_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; +extern char datatoc_common_smaa_lib_glsl[]; + +extern char datatoc_workbench_prepass_vert_glsl[]; +extern char datatoc_workbench_prepass_hair_vert_glsl[]; +extern char datatoc_workbench_prepass_frag_glsl[]; + +extern char datatoc_workbench_effect_cavity_frag_glsl[]; +extern char datatoc_workbench_effect_outline_frag_glsl[]; +extern char datatoc_workbench_effect_dof_frag_glsl[]; +extern char datatoc_workbench_effect_taa_frag_glsl[]; +extern char datatoc_workbench_effect_smaa_frag_glsl[]; +extern char datatoc_workbench_effect_smaa_vert_glsl[]; + +extern char datatoc_workbench_composite_frag_glsl[]; + +extern char datatoc_workbench_transparent_accum_frag_glsl[]; +extern char datatoc_workbench_transparent_resolve_frag_glsl[]; + +extern char datatoc_workbench_merge_infront_frag_glsl[]; + +extern char datatoc_workbench_shadow_vert_glsl[]; +extern char datatoc_workbench_shadow_geom_glsl[]; +extern char datatoc_workbench_shadow_caps_geom_glsl[]; +extern char datatoc_workbench_shadow_debug_frag_glsl[]; + +extern char datatoc_workbench_volume_vert_glsl[]; +extern char datatoc_workbench_volume_frag_glsl[]; + +extern char datatoc_workbench_cavity_lib_glsl[]; +extern char datatoc_workbench_common_lib_glsl[]; +extern char datatoc_workbench_curvature_lib_glsl[]; +extern char datatoc_workbench_data_lib_glsl[]; +extern char datatoc_workbench_image_lib_glsl[]; +extern char datatoc_workbench_matcap_lib_glsl[]; +extern char datatoc_workbench_material_lib_glsl[]; +extern char datatoc_workbench_shader_interface_lib_glsl[]; +extern char datatoc_workbench_world_light_lib_glsl[]; + +extern char datatoc_gpu_shader_depth_only_frag_glsl[]; +extern char datatoc_gpu_shader_common_obinfos_lib_glsl[]; + +/* Maximum number of variations. */ +#define MAX_LIGHTING 3 +#define MAX_COLOR 3 +#define MAX_GEOM 2 + +enum { + VOLUME_SH_SLICE = 0, + VOLUME_SH_COBA, + VOLUME_SH_CUBIC, +}; + +#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1)) + +static struct { + struct GPUShader *opaque_prepass_sh_cache[GPU_SHADER_CFG_LEN][MAX_GEOM][MAX_COLOR]; + struct GPUShader *transp_prepass_sh_cache[GPU_SHADER_CFG_LEN][MAX_GEOM][MAX_LIGHTING][MAX_COLOR]; + + struct GPUShader *opaque_composite_sh[MAX_LIGHTING]; + struct GPUShader *oit_resolve_sh; + struct GPUShader *outline_sh; + struct GPUShader *merge_infront_sh; + + struct GPUShader *shadow_depth_pass_sh[2]; + struct GPUShader *shadow_depth_fail_sh[2][2]; + + struct GPUShader *cavity_sh[2][2]; + + struct GPUShader *dof_prepare_sh; + struct GPUShader *dof_downsample_sh; + struct GPUShader *dof_blur1_sh; + struct GPUShader *dof_blur2_sh; + struct GPUShader *dof_resolve_sh; + + struct GPUShader *aa_accum_sh; + struct GPUShader *smaa_sh[3]; + + struct GPUShader *volume_sh[2][2][2]; + + struct DRWShaderLibrary *lib; +} e_data = {{{{NULL}}}}; + +void workbench_shader_library_ensure(void) +{ + if (e_data.lib == NULL) { + e_data.lib = DRW_shader_library_create(); + /* NOTE: Theses needs to be ordered by dependencies. */ + DRW_SHADER_LIB_ADD(e_data.lib, common_hair_lib); + DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib); + DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_shader_interface_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_common_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_image_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_material_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_data_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_matcap_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_cavity_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_curvature_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_world_light_lib); + } +} + +static char *workbench_build_defines( + WORKBENCH_PrivateData *wpd, bool textured, bool tiled, bool cavity, bool curvature) +{ + char *str = NULL; + + DynStr *ds = BLI_dynstr_new(); + + if (wpd && wpd->shading.light == V3D_LIGHTING_STUDIO) { + BLI_dynstr_append(ds, "#define V3D_LIGHTING_STUDIO\n"); + } + else if (wpd && wpd->shading.light == V3D_LIGHTING_MATCAP) { + BLI_dynstr_append(ds, "#define V3D_LIGHTING_MATCAP\n"); + } + else { + BLI_dynstr_append(ds, "#define V3D_LIGHTING_FLAT\n"); + } + + if (NORMAL_ENCODING_ENABLED()) { + BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n"); + } + + if (textured) { + BLI_dynstr_append(ds, "#define V3D_SHADING_TEXTURE_COLOR\n"); + } + if (tiled) { + BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n"); + } + if (cavity) { + BLI_dynstr_append(ds, "#define USE_CAVITY\n"); + } + if (curvature) { + BLI_dynstr_append(ds, "#define USE_CURVATURE\n"); + } + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + return str; +} + +static int workbench_color_index(WORKBENCH_PrivateData *UNUSED(wpd), bool textured, bool tiled) +{ + BLI_assert(2 < MAX_COLOR); + return (textured) ? (tiled ? 2 : 1) : 0; +} + +static GPUShader *workbench_shader_get_ex( + WORKBENCH_PrivateData *wpd, bool transp, bool hair, bool textured, bool tiled) +{ + int color = workbench_color_index(wpd, textured, tiled); + int light = wpd->shading.light; + BLI_assert(light < MAX_LIGHTING); + struct GPUShader **shader = + (transp) ? &e_data.transp_prepass_sh_cache[wpd->sh_cfg][hair][light][color] : + &e_data.opaque_prepass_sh_cache[wpd->sh_cfg][hair][color]; + + if (*shader == NULL) { + char *defines = workbench_build_defines(wpd, textured, tiled, false, false); + + char *frag_file = transp ? datatoc_workbench_transparent_accum_frag_glsl : + datatoc_workbench_prepass_frag_glsl; + char *frag_src = DRW_shader_library_create_shader_string(e_data.lib, frag_file); + + char *vert_file = hair ? datatoc_workbench_prepass_hair_vert_glsl : + datatoc_workbench_prepass_vert_glsl; + char *vert_src = DRW_shader_library_create_shader_string(e_data.lib, vert_file); + + const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[wpd->sh_cfg]; + + *shader = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg_data->lib, vert_src, NULL}, + .frag = (const char *[]){frag_src, NULL}, + .defs = (const char *[]){sh_cfg_data->def, + defines, + transp ? "#define TRANSPARENT_MATERIAL\n" : + "#define OPAQUE_MATERIAL\n", + NULL}, + }); + + MEM_freeN(defines); + MEM_freeN(frag_src); + MEM_freeN(vert_src); + } + return *shader; +} + +GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, bool hair) +{ + return workbench_shader_get_ex(wpd, false, hair, false, false); +} + +GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd, bool hair, bool tiled) +{ + return workbench_shader_get_ex(wpd, false, hair, true, tiled); +} + +GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd, bool hair) +{ + return workbench_shader_get_ex(wpd, true, hair, false, false); +} + +GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd, + bool hair, + bool tiled) +{ + return workbench_shader_get_ex(wpd, true, hair, true, tiled); +} + +GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd) +{ + int light = wpd->shading.light; + struct GPUShader **shader = &e_data.opaque_composite_sh[light]; + BLI_assert(light < MAX_LIGHTING); + + if (*shader == NULL) { + char *defines = workbench_build_defines(wpd, false, false, false, false); + char *frag = DRW_shader_library_create_shader_string(e_data.lib, + datatoc_workbench_composite_frag_glsl); + + *shader = DRW_shader_create_fullscreen(frag, defines); + + MEM_freeN(defines); + MEM_freeN(frag); + } + return *shader; +} + +GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *UNUSED(wpd)) +{ + if (e_data.merge_infront_sh == NULL) { + char *frag = DRW_shader_library_create_shader_string( + e_data.lib, datatoc_workbench_merge_infront_frag_glsl); + + e_data.merge_infront_sh = DRW_shader_create_fullscreen(frag, NULL); + + MEM_freeN(frag); + } + return e_data.merge_infront_sh; +} + +GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd) +{ + if (e_data.oit_resolve_sh == NULL) { + char *defines = workbench_build_defines(wpd, false, false, false, false); + + e_data.oit_resolve_sh = DRW_shader_create_fullscreen( + datatoc_workbench_transparent_resolve_frag_glsl, defines); + + MEM_freeN(defines); + } + return e_data.oit_resolve_sh; +} + +static GPUShader *workbench_shader_shadow_pass_get_ex(bool depth_pass, bool manifold, bool cap) +{ + struct GPUShader **shader = (depth_pass) ? &e_data.shadow_depth_pass_sh[manifold] : + &e_data.shadow_depth_fail_sh[manifold][cap]; + + if (*shader == NULL) { +#if DEBUG_SHADOW_VOLUME + const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl; +#else + const char *shadow_frag = datatoc_gpu_shader_depth_only_frag_glsl; +#endif + + *shader = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_workbench_shadow_vert_glsl, + NULL}, + .geom = (const char *[]){(cap) ? datatoc_workbench_shadow_caps_geom_glsl : + datatoc_workbench_shadow_geom_glsl, + NULL}, + .frag = (const char *[]){shadow_frag, NULL}, + .defs = (const char *[]){(depth_pass) ? "#define SHADOW_PASS\n" : "#define SHADOW_FAIL\n", + (manifold) ? "" : "#define DOUBLE_MANIFOLD\n", + NULL}, + }); + } + return *shader; +} + +GPUShader *workbench_shader_shadow_pass_get(bool manifold) +{ + return workbench_shader_shadow_pass_get_ex(true, manifold, false); +} + +GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap) +{ + return workbench_shader_shadow_pass_get_ex(false, manifold, cap); +} + +GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature) +{ + BLI_assert(cavity || curvature); + struct GPUShader **shader = &e_data.cavity_sh[cavity][curvature]; + + if (*shader == NULL) { + char *defines = workbench_build_defines(NULL, false, false, cavity, curvature); + char *frag = DRW_shader_library_create_shader_string( + e_data.lib, datatoc_workbench_effect_cavity_frag_glsl); + + *shader = DRW_shader_create_fullscreen(frag, defines); + + MEM_freeN(defines); + MEM_freeN(frag); + } + return *shader; +} + +GPUShader *workbench_shader_outline_get(void) +{ + if (e_data.outline_sh == NULL) { + char *frag = DRW_shader_library_create_shader_string( + e_data.lib, datatoc_workbench_effect_outline_frag_glsl); + + e_data.outline_sh = DRW_shader_create_fullscreen(frag, NULL); + + MEM_freeN(frag); + } + return e_data.outline_sh; +} + +void workbench_shader_depth_of_field_get(GPUShader **prepare_sh, + GPUShader **downsample_sh, + GPUShader **blur1_sh, + GPUShader **blur2_sh, + GPUShader **resolve_sh) +{ + if (e_data.dof_prepare_sh == NULL) { + e_data.dof_prepare_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define PREPARE\n"); + + e_data.dof_downsample_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define DOWNSAMPLE\n"); +#if 0 /* TODO(fclem) finish COC min_max optimization */ + e_data.dof_flatten_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define FLATTEN_VERTICAL\n"); + + e_data.dof_flatten_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define FLATTEN_HORIZONTAL\n"); + + e_data.dof_dilate_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define DILATE_VERTICAL\n"); + + e_data.dof_dilate_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define DILATE_HORIZONTAL\n"); +#endif + e_data.dof_blur1_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define BLUR1\n"); + + e_data.dof_blur2_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define BLUR2\n"); + + e_data.dof_resolve_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define RESOLVE\n"); + } + + *prepare_sh = e_data.dof_prepare_sh; + *downsample_sh = e_data.dof_downsample_sh; + *blur1_sh = e_data.dof_blur1_sh; + *blur2_sh = e_data.dof_blur2_sh; + *resolve_sh = e_data.dof_resolve_sh; +} + +GPUShader *workbench_shader_antialiasing_accumulation_get(void) +{ + if (e_data.aa_accum_sh == NULL) { + char *frag = DRW_shader_library_create_shader_string(e_data.lib, + datatoc_workbench_effect_taa_frag_glsl); + + e_data.aa_accum_sh = DRW_shader_create_fullscreen(frag, NULL); + + MEM_freeN(frag); + } + return e_data.aa_accum_sh; +} + +GPUShader *workbench_shader_antialiasing_get(int stage) +{ + BLI_assert(stage < 3); + if (!e_data.smaa_sh[stage]) { + char stage_define[32]; + BLI_snprintf(stage_define, sizeof(stage_define), "#define SMAA_STAGE %d\n", stage); + + e_data.smaa_sh[stage] = GPU_shader_create_from_arrays({ + .vert = + (const char *[]){ + "#define SMAA_INCLUDE_VS 1\n", + "#define SMAA_INCLUDE_PS 0\n", + "uniform vec4 viewportMetrics;\n", + datatoc_common_smaa_lib_glsl, + datatoc_workbench_effect_smaa_vert_glsl, + NULL, + }, + .frag = + (const char *[]){ + "#define SMAA_INCLUDE_VS 0\n", + "#define SMAA_INCLUDE_PS 1\n", + "uniform vec4 viewportMetrics;\n", + datatoc_common_smaa_lib_glsl, + datatoc_workbench_effect_smaa_frag_glsl, + NULL, + }, + .defs = + (const char *[]){ + "#define SMAA_GLSL_3\n", + "#define SMAA_RT_METRICS viewportMetrics\n", + "#define SMAA_PRESET_HIGH\n", + "#define SMAA_LUMA_WEIGHT float4(1.0, 1.0, 1.0, 1.0)\n", + "#define SMAA_NO_DISCARD\n", + stage_define, + NULL, + }, + }); + } + return e_data.smaa_sh[stage]; +} + +GPUShader *workbench_shader_volume_get(bool slice, bool coba, bool cubic) +{ + GPUShader **shader = &e_data.volume_sh[slice][coba][cubic]; + + if (*shader == NULL) { + DynStr *ds = BLI_dynstr_new(); + + if (slice) { + BLI_dynstr_append(ds, "#define VOLUME_SLICE\n"); + } + if (coba) { + BLI_dynstr_append(ds, "#define USE_COBA\n"); + } + if (cubic) { + BLI_dynstr_append(ds, "#define USE_TRICUBIC\n"); + } + + char *defines = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + char *vert = DRW_shader_library_create_shader_string(e_data.lib, + datatoc_workbench_volume_vert_glsl); + char *frag = DRW_shader_library_create_shader_string(e_data.lib, + datatoc_workbench_volume_frag_glsl); + + *shader = DRW_shader_create(vert, NULL, frag, defines); + + MEM_freeN(vert); + MEM_freeN(frag); + MEM_freeN(defines); + } + return *shader; +} + +void workbench_shader_free(void) +{ + for (int j = 0; j < sizeof(e_data.opaque_prepass_sh_cache) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.opaque_prepass_sh_cache[0][0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.transp_prepass_sh_cache) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.transp_prepass_sh_cache[0][0][0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.opaque_composite_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.opaque_composite_sh[0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.shadow_depth_pass_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.shadow_depth_pass_sh[0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.shadow_depth_fail_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.shadow_depth_fail_sh[0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.cavity_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.cavity_sh[0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.smaa_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.smaa_sh[0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.volume_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.volume_sh[0][0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + + DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh); + DRW_SHADER_FREE_SAFE(e_data.outline_sh); + DRW_SHADER_FREE_SAFE(e_data.merge_infront_sh); + + DRW_SHADER_FREE_SAFE(e_data.dof_prepare_sh); + DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh); + DRW_SHADER_FREE_SAFE(e_data.dof_blur1_sh); + DRW_SHADER_FREE_SAFE(e_data.dof_blur2_sh); + DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh); + + DRW_SHADER_FREE_SAFE(e_data.aa_accum_sh); + + DRW_SHADER_LIB_FREE_SAFE(e_data.lib); +} diff --git a/source/blender/draw/engines/workbench/workbench_shadow.c b/source/blender/draw/engines/workbench/workbench_shadow.c new file mode 100644 index 00000000000..efd0ad9134e --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_shadow.c @@ -0,0 +1,367 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Shadow: + * + * Use stencil shadow buffer to cast a sharp shadow over opaque surfaces. + * + * After the main pre-pass we render shadow volumes using custom depth & stencil states to + * set the stencil of shadowed area to anything but 0. + * + * Then the shading pass will shade the areas with stencil not equal 0 differently. + */ + +#include "DRW_render.h" + +#include "BKE_object.h" + +#include "BLI_math.h" + +#include "workbench_engine.h" +#include "workbench_private.h" + +static void compute_parallel_lines_nor_and_dist(const float v1[2], + const float v2[2], + const float v3[2], + float r_line[4]) +{ + sub_v2_v2v2(r_line, v2, v1); + /* Find orthogonal vector. */ + SWAP(float, r_line[0], r_line[1]); + r_line[0] = -r_line[0]; + /* Edge distances. */ + r_line[2] = dot_v2v2(r_line, v1); + r_line[3] = dot_v2v2(r_line, v3); + /* Make sure r_line[2] is the minimum. */ + if (r_line[2] > r_line[3]) { + SWAP(float, r_line[2], r_line[3]); + } +} + +static void workbench_shadow_update(WORKBENCH_PrivateData *wpd) +{ + wpd->shadow_changed = !compare_v3v3( + wpd->shadow_cached_direction, wpd->shadow_direction_ws, 1e-5f); + + if (wpd->shadow_changed) { + float up[3] = {0.0f, 0.0f, 1.0f}; + unit_m4(wpd->shadow_mat); + + /* TODO fix singularity. */ + copy_v3_v3(wpd->shadow_mat[2], wpd->shadow_direction_ws); + cross_v3_v3v3(wpd->shadow_mat[0], wpd->shadow_mat[2], up); + normalize_v3(wpd->shadow_mat[0]); + cross_v3_v3v3(wpd->shadow_mat[1], wpd->shadow_mat[2], wpd->shadow_mat[0]); + + invert_m4_m4(wpd->shadow_inv, wpd->shadow_mat); + + copy_v3_v3(wpd->shadow_cached_direction, wpd->shadow_direction_ws); + } + + float planes[6][4]; + DRW_culling_frustum_planes_get(NULL, planes); + /* we only need the far plane. */ + copy_v4_v4(wpd->shadow_far_plane, planes[2]); + + BoundBox frustum_corners; + DRW_culling_frustum_corners_get(NULL, &frustum_corners); + + float shadow_near_corners[4][3]; + mul_v3_mat3_m4v3(shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]); + mul_v3_mat3_m4v3(shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]); + mul_v3_mat3_m4v3(shadow_near_corners[2], wpd->shadow_inv, frustum_corners.vec[7]); + mul_v3_mat3_m4v3(shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]); + + INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max); + for (int i = 0; i < 4; i++) { + minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, shadow_near_corners[i]); + } + + compute_parallel_lines_nor_and_dist(shadow_near_corners[0], + shadow_near_corners[1], + shadow_near_corners[2], + wpd->shadow_near_sides[0]); + compute_parallel_lines_nor_and_dist(shadow_near_corners[1], + shadow_near_corners[2], + shadow_near_corners[0], + wpd->shadow_near_sides[1]); +} + +void workbench_shadow_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + + float view_matrix[4][4]; + DRW_view_viewmat_get(NULL, view_matrix, false); + + /* Turn the light in a way where it's more user friendly to control. */ + copy_v3_v3(wpd->shadow_direction_ws, scene->display.light_direction); + SWAP(float, wpd->shadow_direction_ws[2], wpd->shadow_direction_ws[1]); + wpd->shadow_direction_ws[2] = -wpd->shadow_direction_ws[2]; + wpd->shadow_direction_ws[0] = -wpd->shadow_direction_ws[0]; + + /* Shadow direction. */ + mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, wpd->shadow_direction_ws); + + /* Clamp to avoid overshadowing and shading errors. */ + float focus = clamp_f(scene->display.shadow_focus, 0.0001f, 0.99999f); + wd->shadow_shift = scene->display.shadow_shift; + wd->shadow_focus = 1.0f - focus * (1.0f - wd->shadow_shift); + + if (SHADOW_ENABLED(wpd)) { + wd->shadow_mul = wpd->shading.shadow_intensity; + wd->shadow_add = 1.0f - wd->shadow_mul; + } + else { + wd->shadow_mul = 0.0f; + wd->shadow_add = 1.0f; + } +} + +void workbench_shadow_cache_init(WORKBENCH_Data *data) +{ + WORKBENCH_PassList *psl = data->psl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + struct GPUShader *sh; + DRWShadingGroup *grp; + + if (SHADOW_ENABLED(wpd)) { + workbench_shadow_update(wpd); + +#if DEBUG_SHADOW_VOLUME + DRWState depth_pass_state = DRW_STATE_DEPTH_LESS; + DRWState depth_fail_state = DRW_STATE_DEPTH_GREATER_EQUAL; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL; +#else + DRWState depth_pass_state = DRW_STATE_WRITE_STENCIL_SHADOW_PASS; + DRWState depth_fail_state = DRW_STATE_WRITE_STENCIL_SHADOW_FAIL; + DRWState state = DRW_STATE_DEPTH_LESS | DRW_STATE_STENCIL_ALWAYS; +#endif + + /* TODO(fclem) Merge into one pass with subpasses. */ + DRW_PASS_CREATE(psl->shadow_ps[0], state | depth_pass_state); + DRW_PASS_CREATE(psl->shadow_ps[1], state | depth_fail_state); + + /* Stencil Shadow passes. */ + for (int manifold = 0; manifold < 2; manifold++) { + sh = workbench_shader_shadow_pass_get(manifold); + wpd->shadow_pass_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_ps[0]); + DRW_shgroup_stencil_mask(grp, 0xFF); /* Needed once to set the stencil state for the pass. */ + + sh = workbench_shader_shadow_fail_get(manifold, false); + wpd->shadow_fail_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_ps[1]); + DRW_shgroup_stencil_mask(grp, 0xFF); /* Needed once to set the stencil state for the pass. */ + + sh = workbench_shader_shadow_fail_get(manifold, true); + wpd->shadow_fail_caps_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_ps[1]); + } + } + else { + psl->shadow_ps[0] = NULL; + psl->shadow_ps[1] = NULL; + } +} + +static BoundBox *workbench_shadow_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd, + Object *ob, + WORKBENCH_ObjectData *oed) +{ + if (oed->shadow_bbox_dirty || wpd->shadow_changed) { + float tmp_mat[4][4]; + mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat); + + /* Get AABB in shadow space. */ + INIT_MINMAX(oed->shadow_min, oed->shadow_max); + + /* From object space to shadow space */ + BoundBox *bbox = BKE_object_boundbox_get(ob); + for (int i = 0; i < 8; i++) { + float corner[3]; + mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]); + minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner); + } + oed->shadow_depth = oed->shadow_max[2] - oed->shadow_min[2]; + /* Extend towards infinity. */ + oed->shadow_max[2] += 1e4f; + + /* Get extended AABB in world space. */ + BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max); + for (int i = 0; i < 8; i++) { + mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]); + } + oed->shadow_bbox_dirty = false; + } + + return &oed->shadow_bbox; +} + +static bool workbench_shadow_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, + Object *ob, + WORKBENCH_ObjectData *oed) +{ + BoundBox *shadow_bbox = workbench_shadow_object_shadow_bbox_get(wpd, ob, oed); + const DRWView *default_view = DRW_view_default_get(); + return DRW_culling_box_test(default_view, shadow_bbox); +} + +static float workbench_shadow_object_shadow_distance(WORKBENCH_PrivateData *wpd, + Object *ob, + WORKBENCH_ObjectData *oed) +{ + BoundBox *shadow_bbox = workbench_shadow_object_shadow_bbox_get(wpd, ob, oed); + + int corners[4] = {0, 3, 4, 7}; + float dist = 1e4f, dist_isect; + for (int i = 0; i < 4; i++) { + if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]], + wpd->shadow_cached_direction, + wpd->shadow_far_plane, + &dist_isect, + true)) { + if (dist_isect < dist) { + dist = dist_isect; + } + } + else { + /* All rays are parallels. If one fails, the other will too. */ + break; + } + } + return max_ii(dist - oed->shadow_depth, 0); +} + +static bool workbench_shadow_camera_in_object_shadow(WORKBENCH_PrivateData *wpd, + Object *ob, + WORKBENCH_ObjectData *oed) +{ + /* Just to be sure the min, max are updated. */ + workbench_shadow_object_shadow_bbox_get(wpd, ob, oed); + /* Test if near plane is in front of the shadow. */ + if (oed->shadow_min[2] > wpd->shadow_near_max[2]) { + return false; + } + + /* Separation Axis Theorem test */ + + /* Test bbox sides first (faster) */ + if ((oed->shadow_min[0] > wpd->shadow_near_max[0]) || + (oed->shadow_max[0] < wpd->shadow_near_min[0]) || + (oed->shadow_min[1] > wpd->shadow_near_max[1]) || + (oed->shadow_max[1] < wpd->shadow_near_min[1])) { + return false; + } + /* Test projected near rectangle sides */ + const float pts[4][2] = { + {oed->shadow_min[0], oed->shadow_min[1]}, + {oed->shadow_min[0], oed->shadow_max[1]}, + {oed->shadow_max[0], oed->shadow_min[1]}, + {oed->shadow_max[0], oed->shadow_max[1]}, + }; + + for (int i = 0; i < 2; i++) { + float min_dst = FLT_MAX, max_dst = -FLT_MAX; + for (int j = 0; j < 4; j++) { + float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]); + /* Do min max */ + if (min_dst > dst) { + min_dst = dst; + } + if (max_dst < dst) { + max_dst = dst; + } + } + + if ((wpd->shadow_near_sides[i][2] > max_dst) || (wpd->shadow_near_sides[i][3] < min_dst)) { + return false; + } + } + /* No separation axis found. Both shape intersect. */ + return true; +} + +static void workbench_init_object_data(DrawData *dd) +{ + WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd; + data->shadow_bbox_dirty = true; +} + +void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const bool has_transp_mat) +{ + WORKBENCH_PrivateData *wpd = data->stl->wpd; + + bool is_manifold; + struct GPUBatch *geom_shadow = DRW_cache_object_edge_detection_get(ob, &is_manifold); + if (geom_shadow == NULL) { + return; + } + + WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure( + &ob->id, + &draw_engine_workbench, + sizeof(WORKBENCH_ObjectData), + &workbench_init_object_data, + NULL); + + if (workbench_shadow_object_cast_visible_shadow(wpd, ob, engine_object_data)) { + mul_v3_mat3_m4v3(engine_object_data->shadow_dir, ob->imat, wpd->shadow_direction_ws); + + DRWShadingGroup *grp; + bool use_shadow_pass_technique = !workbench_shadow_camera_in_object_shadow( + wpd, ob, engine_object_data); + + /* Shadow pass technique needs object to be have all its surface opaque. */ + if (has_transp_mat) { + use_shadow_pass_technique = false; + } + + if (use_shadow_pass_technique) { + grp = DRW_shgroup_create_sub(wpd->shadow_pass_grp[is_manifold]); + DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); + DRW_shgroup_uniform_float_copy(grp, "lightDistance", 1e5f); + DRW_shgroup_call_no_cull(grp, geom_shadow, ob); +#if DEBUG_SHADOW_VOLUME + DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){1.0f, 0.0f, 0.0f, 1.0f}); +#endif + } + else { + float extrude_distance = workbench_shadow_object_shadow_distance( + wpd, ob, engine_object_data); + + /* TODO(fclem): only use caps if they are in the view frustum. */ + const bool need_caps = true; + if (need_caps) { + grp = DRW_shgroup_create_sub(wpd->shadow_fail_caps_grp[is_manifold]); + DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); + DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance); + DRW_shgroup_call_no_cull(grp, DRW_cache_object_surface_get(ob), ob); + } + + grp = DRW_shgroup_create_sub(wpd->shadow_fail_grp[is_manifold]); + DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); + DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance); + DRW_shgroup_call_no_cull(grp, geom_shadow, ob); +#if DEBUG_SHADOW_VOLUME + DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){0.0f, 1.0f, 0.0f, 1.0f}); +#endif + } + } +} diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c deleted file mode 100644 index 1fb0b394cb1..00000000000 --- a/source/blender/draw/engines/workbench/workbench_studiolight.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - */ -#include "BKE_studiolight.h" - -#include "workbench_private.h" - -#include "BKE_object.h" - -#include "BLI_math.h" - -void studiolight_update_world(WORKBENCH_PrivateData *wpd, - StudioLight *studiolight, - WORKBENCH_UBO_World *wd) -{ - float view_matrix[4][4], rot_matrix[4][4]; - DRW_view_viewmat_get(NULL, view_matrix, false); - - if (USE_WORLD_ORIENTATION(wpd)) { - axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z); - mul_m4_m4m4(rot_matrix, view_matrix, rot_matrix); - swap_v3_v3(rot_matrix[2], rot_matrix[1]); - negate_v3(rot_matrix[2]); - } - else { - unit_m4(rot_matrix); - } - - if (U.edit_studio_light) { - studiolight = BKE_studiolight_studio_edit_get(); - } - - /* Studio Lights. */ - for (int i = 0; i < 4; i++) { - WORKBENCH_UBO_Light *light = &wd->lights[i]; - - SolidLight *sl = &studiolight->light[i]; - if (sl->flag) { - copy_v3_v3(light->light_direction, sl->vec); - mul_mat3_m4_v3(rot_matrix, light->light_direction); - /* We should predivide the power by PI but that makes the lights really dim. */ - copy_v3_v3(light->specular_color, sl->spec); - copy_v3_v3(light->diffuse_color, sl->col); - light->wrapped = sl->smooth; - } - else { - copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f); - copy_v3_fl(light->specular_color, 0.0f); - copy_v3_fl(light->diffuse_color, 0.0f); - } - } - - copy_v3_v3(wd->ambient_color, studiolight->light_ambient); -} - -static void compute_parallel_lines_nor_and_dist(const float v1[2], - const float v2[2], - const float v3[2], - float r_line[4]) -{ - sub_v2_v2v2(r_line, v2, v1); - /* Find orthogonal vector. */ - SWAP(float, r_line[0], r_line[1]); - r_line[0] = -r_line[0]; - /* Edge distances. */ - r_line[2] = dot_v2v2(r_line, v1); - r_line[3] = dot_v2v2(r_line, v3); - /* Make sure r_line[2] is the minimum. */ - if (r_line[2] > r_line[3]) { - SWAP(float, r_line[2], r_line[3]); - } -} - -void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3]) -{ - wpd->shadow_changed = !compare_v3v3(wpd->cached_shadow_direction, light_direction, 1e-5f); - - if (wpd->shadow_changed) { - float up[3] = {0.0f, 0.0f, 1.0f}; - unit_m4(wpd->shadow_mat); - - /* TODO fix singularity. */ - copy_v3_v3(wpd->shadow_mat[2], light_direction); - cross_v3_v3v3(wpd->shadow_mat[0], wpd->shadow_mat[2], up); - normalize_v3(wpd->shadow_mat[0]); - cross_v3_v3v3(wpd->shadow_mat[1], wpd->shadow_mat[2], wpd->shadow_mat[0]); - - invert_m4_m4(wpd->shadow_inv, wpd->shadow_mat); - - copy_v3_v3(wpd->cached_shadow_direction, light_direction); - } - - float planes[6][4]; - DRW_culling_frustum_planes_get(NULL, planes); - /* we only need the far plane. */ - copy_v4_v4(wpd->shadow_far_plane, planes[2]); - - BoundBox frustum_corners; - DRW_culling_frustum_corners_get(NULL, &frustum_corners); - - mul_v3_mat3_m4v3(wpd->shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]); - mul_v3_mat3_m4v3(wpd->shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]); - mul_v3_mat3_m4v3(wpd->shadow_near_corners[2], wpd->shadow_inv, frustum_corners.vec[7]); - mul_v3_mat3_m4v3(wpd->shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]); - - INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max); - for (int i = 0; i < 4; i++) { - minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, wpd->shadow_near_corners[i]); - } - - compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[0], - wpd->shadow_near_corners[1], - wpd->shadow_near_corners[2], - wpd->shadow_near_sides[0]); - compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[1], - wpd->shadow_near_corners[2], - wpd->shadow_near_corners[0], - wpd->shadow_near_sides[1]); -} - -static BoundBox *studiolight_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed) -{ - if ((oed->shadow_bbox_dirty) || (wpd->shadow_changed)) { - float tmp_mat[4][4]; - mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat); - - /* Get AABB in shadow space. */ - INIT_MINMAX(oed->shadow_min, oed->shadow_max); - - /* From object space to shadow space */ - BoundBox *bbox = BKE_object_boundbox_get(ob); - for (int i = 0; i < 8; i++) { - float corner[3]; - mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]); - minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner); - } - oed->shadow_depth = oed->shadow_max[2] - oed->shadow_min[2]; - /* Extend towards infinity. */ - oed->shadow_max[2] += 1e4f; - - /* Get extended AABB in world space. */ - BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max); - for (int i = 0; i < 8; i++) { - mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]); - } - oed->shadow_bbox_dirty = false; - } - - return &oed->shadow_bbox; -} - -bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed) -{ - BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed); - const DRWView *default_view = DRW_view_default_get(); - return DRW_culling_box_test(default_view, shadow_bbox); -} - -float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed) -{ - BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed); - - int corners[4] = {0, 3, 4, 7}; - float dist = 1e4f, dist_isect; - for (int i = 0; i < 4; i++) { - if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]], - wpd->cached_shadow_direction, - wpd->shadow_far_plane, - &dist_isect, - true)) { - if (dist_isect < dist) { - dist = dist_isect; - } - } - else { - /* All rays are parallels. If one fails, the other will too. */ - break; - } - } - return max_ii(dist - oed->shadow_depth, 0); -} - -bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed) -{ - /* Just to be sure the min, max are updated. */ - studiolight_object_shadow_bbox_get(wpd, ob, oed); - - /* Test if near plane is in front of the shadow. */ - if (oed->shadow_min[2] > wpd->shadow_near_max[2]) { - return false; - } - - /* Separation Axis Theorem test */ - - /* Test bbox sides first (faster) */ - if ((oed->shadow_min[0] > wpd->shadow_near_max[0]) || - (oed->shadow_max[0] < wpd->shadow_near_min[0]) || - (oed->shadow_min[1] > wpd->shadow_near_max[1]) || - (oed->shadow_max[1] < wpd->shadow_near_min[1])) { - return false; - } - - /* Test projected near rectangle sides */ - const float pts[4][2] = { - {oed->shadow_min[0], oed->shadow_min[1]}, - {oed->shadow_min[0], oed->shadow_max[1]}, - {oed->shadow_max[0], oed->shadow_min[1]}, - {oed->shadow_max[0], oed->shadow_max[1]}, - }; - - for (int i = 0; i < 2; i++) { - float min_dst = FLT_MAX, max_dst = -FLT_MAX; - for (int j = 0; j < 4; j++) { - float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]); - /* Do min max */ - if (min_dst > dst) { - min_dst = dst; - } - if (max_dst < dst) { - max_dst = dst; - } - } - - if ((wpd->shadow_near_sides[i][2] > max_dst) || (wpd->shadow_near_sides[i][3] < min_dst)) { - return false; - } - } - - /* No separation axis found. Both shape intersect. */ - return true; -} diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c new file mode 100644 index 00000000000..39aa721a41c --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_transparent.c @@ -0,0 +1,180 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Transparent Pipeline: + * + * Use Weight Blended Order Independent Transparency to render transparent surfaces. + * + * The rendering is broken down in two passes: + * - the accumulation pass where we render all the surfaces and accumulate all the weights. + * - the resolve pass where we divide the accumulated information by the weights. + * + * An additional re-render of the transparent surfaces is sometime done in order to have their + * correct depth and object ids correctly written. + */ + +#include "DRW_render.h" + +#include "ED_view3d.h" + +#include "GPU_extensions.h" + +#include "workbench_engine.h" +#include "workbench_private.h" + +void workbench_transparent_engine_init(WORKBENCH_Data *data) +{ + WORKBENCH_FramebufferList *fbl = data->fbl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DrawEngineType *owner = (DrawEngineType *)&workbench_transparent_engine_init; + + /* Reuse same format as opaque pipeline to reuse the textures. */ + /* Note: Floating point texture is required for the reveal_tex as it is used for + * the alpha accumulation component (see accumulation shader for more explanation). */ + const eGPUTextureFormat accum_tex_format = GPU_RGBA16F; + const eGPUTextureFormat reveal_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16F : GPU_RGBA32F; + + wpd->accum_buffer_tx = DRW_texture_pool_query_fullscreen(accum_tex_format, owner); + wpd->reveal_buffer_tx = DRW_texture_pool_query_fullscreen(reveal_tex_format, owner); + + GPU_framebuffer_ensure_config(&fbl->transp_accum_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(wpd->accum_buffer_tx), + GPU_ATTACHMENT_TEXTURE(wpd->reveal_buffer_tx), + }); +} + +static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd, + DRWShadingGroup *grp) +{ + DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false); + + if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { + BKE_studiolight_ensure_flag(wpd->studio_light, + STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE | + STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE); + struct GPUTexture *diff_tx = wpd->studio_light->matcap_diffuse.gputexture; + struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture; + const bool use_spec = workbench_is_specular_highlight_enabled(wpd); + spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx; + DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx); + DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx); + } +} + +void workbench_transparent_cache_init(WORKBENCH_Data *data) +{ + WORKBENCH_PassList *psl = data->psl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + struct GPUShader *sh; + DRWShadingGroup *grp; + + { + int transp = 1; + for (int infront = 0; infront < 2; infront++) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_OIT; + + DRWPass *pass; + if (infront) { + DRW_PASS_CREATE(psl->transp_accum_infront_ps, state | wpd->cull_state | wpd->clip_state); + pass = psl->transp_accum_infront_ps; + } + else { + DRW_PASS_CREATE(psl->transp_accum_ps, state | wpd->cull_state | wpd->clip_state); + pass = psl->transp_accum_ps; + } + + for (int hair = 0; hair < 2; hair++) { + wpd->prepass[transp][infront][hair].material_hash = BLI_ghash_ptr_new(__func__); + + sh = workbench_shader_transparent_get(wpd, hair); + + wpd->prepass[transp][infront][hair].common_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1); + workbench_transparent_lighting_uniforms(wpd, grp); + + wpd->prepass[transp][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */ + + sh = workbench_shader_transparent_image_get(wpd, hair, false); + + wpd->prepass[transp][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ + workbench_transparent_lighting_uniforms(wpd, grp); + + sh = workbench_shader_transparent_image_get(wpd, hair, true); + + wpd->prepass[transp][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ + workbench_transparent_lighting_uniforms(wpd, grp); + } + } + } + { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; + + DRW_PASS_CREATE(psl->transp_resolve_ps, state); + + sh = workbench_shader_transparent_resolve_get(wpd); + + grp = DRW_shgroup_create(sh, psl->transp_resolve_ps); + DRW_shgroup_uniform_texture(grp, "transparentAccum", wpd->accum_buffer_tx); + DRW_shgroup_uniform_texture(grp, "transparentRevealage", wpd->reveal_buffer_tx); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } +} + +/* Redraw the transparent passes but with depth test + * to output correct outline IDs and depth. */ +void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data) +{ + WORKBENCH_PrivateData *wpd = data->stl->wpd; + WORKBENCH_FramebufferList *fbl = data->fbl; + WORKBENCH_PassList *psl = data->psl; + + const bool do_xray_depth_pass = XRAY_ALPHA(wpd) > 0.0f; + const bool do_transparent_depth_pass = psl->outline_ps || wpd->dof_enabled || do_xray_depth_pass; + + if (do_transparent_depth_pass) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + + if (!DRW_pass_is_empty(psl->transp_accum_ps)) { + GPU_framebuffer_bind(fbl->opaque_fb); + /* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */ + DRW_pass_state_set(psl->transp_accum_ps, state | wpd->cull_state | wpd->clip_state); + DRW_draw_pass(psl->transp_accum_ps); + } + + if (!DRW_pass_is_empty(psl->transp_accum_infront_ps)) { + GPU_framebuffer_bind(fbl->opaque_infront_fb); + /* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */ + DRW_pass_state_set(psl->transp_accum_infront_ps, state | wpd->cull_state | wpd->clip_state); + DRW_draw_pass(psl->transp_accum_infront_ps); + } + } +} diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c index 2f7296fb40f..a3072b834bd 100644 --- a/source/blender/draw/engines/workbench/workbench_volume.c +++ b/source/blender/draw/engines/workbench/workbench_volume.c @@ -35,87 +35,23 @@ #include "GPU_draw.h" -enum { - VOLUME_SH_SLICE = 0, - VOLUME_SH_COBA, - VOLUME_SH_CUBIC, -}; - -#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1)) - -static struct { - struct GPUShader *volume_sh[VOLUME_SH_MAX]; - struct GPUShader *volume_coba_sh; - struct GPUTexture *dummy_tex; - struct GPUTexture *dummy_coba_tex; -} e_data = {{NULL}}; - -extern char datatoc_workbench_volume_vert_glsl[]; -extern char datatoc_workbench_volume_frag_glsl[]; -extern char datatoc_common_view_lib_glsl[]; -extern char datatoc_gpu_shader_common_obinfos_lib_glsl[]; - -static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic) +void workbench_volume_engine_init(WORKBENCH_Data *vedata) { - int id = 0; - id += (slice) ? (1 << VOLUME_SH_SLICE) : 0; - id += (coba) ? (1 << VOLUME_SH_COBA) : 0; - id += (cubic) ? (1 << VOLUME_SH_CUBIC) : 0; - - if (!e_data.volume_sh[id]) { - DynStr *ds = BLI_dynstr_new(); - - if (slice) { - BLI_dynstr_append(ds, "#define VOLUME_SLICE\n"); - } - if (coba) { - BLI_dynstr_append(ds, "#define USE_COBA\n"); - } - if (cubic) { - BLI_dynstr_append(ds, "#define USE_TRICUBIC\n"); - } - - char *defines = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - - char *libs = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_gpu_shader_common_obinfos_lib_glsl); - - e_data.volume_sh[id] = DRW_shader_create_with_lib(datatoc_workbench_volume_vert_glsl, - NULL, - datatoc_workbench_volume_frag_glsl, - libs, - defines); - - MEM_freeN(libs); - MEM_freeN(defines); - } - - return e_data.volume_sh[id]; -} + WORKBENCH_TextureList *txl = vedata->txl; -void workbench_volume_engine_init(void) -{ - if (!e_data.dummy_tex) { + if (txl->dummy_volume_tx == NULL) { float pixel[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - e_data.dummy_tex = GPU_texture_create_3d(1, 1, 1, GPU_RGBA8, pixel, NULL); - e_data.dummy_coba_tex = GPU_texture_create_1d(1, GPU_RGBA8, pixel, NULL); + txl->dummy_volume_tx = GPU_texture_create_3d(1, 1, 1, GPU_RGBA8, pixel, NULL); + txl->dummy_coba_tx = GPU_texture_create_1d(1, GPU_RGBA8, pixel, NULL); } } -void workbench_volume_engine_free(void) -{ - for (int i = 0; i < VOLUME_SH_MAX; i++) { - DRW_SHADER_FREE_SAFE(e_data.volume_sh[i]); - } - DRW_TEXTURE_FREE_SAFE(e_data.dummy_tex); - DRW_TEXTURE_FREE_SAFE(e_data.dummy_coba_tex); -} - void workbench_volume_cache_init(WORKBENCH_Data *vedata) { - vedata->psl->volume_pass = DRW_pass_create( + vedata->psl->volume_ps = DRW_pass_create( "Volumes", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT); + + vedata->stl->wpd->volumes_do = false; } void workbench_volume_cache_populate(WORKBENCH_Data *vedata, @@ -125,8 +61,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, { FluidModifierData *mmd = (FluidModifierData *)md; FluidDomainSettings *mds = mmd->domain; - WORKBENCH_PrivateData *wpd = vedata->stl->g_data; - WORKBENCH_EffectInfo *effect_info = vedata->stl->effects; + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + WORKBENCH_TextureList *txl = vedata->txl; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); DRWShadingGroup *grp = NULL; @@ -146,14 +82,16 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, GPU_create_smoke(mmd, 1); } - if ((!mds->use_coba && mds->tex == NULL) || (mds->use_coba && mds->tex_field == NULL)) { + if ((!mds->use_coba && (mds->tex_density == NULL && mds->tex_color == NULL)) || + (mds->use_coba && mds->tex_field == NULL)) { return; } const bool use_slice = (mds->slice_method == FLUID_DOMAIN_SLICE_AXIS_ALIGNED && mds->axis_slice_method == AXIS_SLICE_SINGLE); const bool cubic_interp = (mds->interp_method == VOLUME_INTERP_CUBIC); - GPUShader *sh = volume_shader_get(use_slice, mds->use_coba, cubic_interp); + + GPUShader *sh = workbench_shader_volume_get(use_slice, mds->use_coba, cubic_interp); if (use_slice) { float invviewmat[4][4]; @@ -167,7 +105,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, /* 0.05f to achieve somewhat the same opacity as the full view. */ float step_length = max_ff(1e-16f, dim[axis] * 0.05f); - grp = DRW_shgroup_create(sh, vedata->psl->volume_pass); + grp = DRW_shgroup_create(sh, vedata->psl->volume_ps); DRW_shgroup_uniform_float_copy(grp, "slicePosition", mds->slice_depth); DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis); DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length); @@ -175,7 +113,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, } else { double noise_ofs; - BLI_halton_1d(3, 0.0, effect_info->jitter_index, &noise_ofs); + BLI_halton_1d(3, 0.0, wpd->taa_sample, &noise_ofs); float dim[3], step_length, max_slice; float slice_ct[3] = {mds->res[0], mds->res[1], mds->res[2]}; mul_v3_fl(slice_ct, max_ff(0.001f, mds->slice_per_voxel)); @@ -185,8 +123,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, mul_v3_v3(dim, slice_ct); step_length = len_v3(dim); - grp = DRW_shgroup_create(sh, vedata->psl->volume_pass); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); + grp = DRW_shgroup_create(sh, vedata->psl->volume_ps); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice); DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length); DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs); @@ -201,12 +139,13 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, static float white[3] = {1.0f, 1.0f, 1.0f}; bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 && (mds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0); - DRW_shgroup_uniform_texture(grp, "densityTexture", mds->tex); + DRW_shgroup_uniform_texture( + grp, "densityTexture", (mds->tex_color) ? mds->tex_color : mds->tex_density); DRW_shgroup_uniform_texture(grp, "shadowTexture", mds->tex_shadow); DRW_shgroup_uniform_texture( - grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : e_data.dummy_tex); + grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : txl->dummy_volume_tx); DRW_shgroup_uniform_texture( - grp, "flameColorTexture", (mds->tex_flame) ? mds->tex_flame_coba : e_data.dummy_coba_tex); + grp, "flameColorTexture", (mds->tex_flame) ? mds->tex_flame_coba : txl->dummy_coba_tx); DRW_shgroup_uniform_vec3( grp, "activeColor", (use_constant_color) ? mds->active_color : white, 1); } @@ -223,8 +162,22 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(mmd)); } -void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd) +void workbench_volume_draw_pass(WORKBENCH_Data *vedata) { + WORKBENCH_PassList *psl = vedata->psl; + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + + if (wpd->volumes_do) { + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->volume_ps); + } +} + +void workbench_volume_draw_finish(WORKBENCH_Data *vedata) +{ + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + /* Free Smoke Textures after rendering */ /* XXX This is a waste of processing and GPU bandwidth if nothing * is updated. But the problem is since Textures are stored in the @@ -236,4 +189,4 @@ void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd) GPU_free_smoke(mmd); } BLI_freelistN(&wpd->smoke_domains); -} +}
\ No newline at end of file diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index cc257b80daf..8ed7bb25336 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -81,6 +81,7 @@ typedef struct DRWPass DRWPass; typedef struct DRWShadingGroup DRWShadingGroup; typedef struct DRWUniform DRWUniform; typedef struct DRWView DRWView; +typedef struct DRWShaderLibrary DRWShaderLibrary; /* TODO Put it somewhere else? */ typedef struct BoundSphere { @@ -148,6 +149,8 @@ struct GPUTexture *DRW_texture_pool_query_2d(int w, int h, eGPUTextureFormat format, DrawEngineType *engine_type); +struct GPUTexture *DRW_texture_pool_query_fullscreen(eGPUTextureFormat format, + DrawEngineType *engine_type); struct GPUTexture *DRW_texture_create_1d(int w, eGPUTextureFormat format, @@ -163,6 +166,8 @@ struct GPUTexture *DRW_texture_create_cube(int w, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels); +struct GPUTexture *DRW_texture_create_cube_array( + int w, int d, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels); void DRW_texture_ensure_fullscreen_2d(struct GPUTexture **tex, eGPUTextureFormat format, @@ -211,16 +216,17 @@ struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *def struct GPUShader *DRW_shader_create_3d_depth_only(eGPUShaderConfig slot); struct GPUMaterial *DRW_shader_find_from_world(struct World *wo, const void *engine_type, - int options, + const int options, bool deferred); struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma, const void *engine_type, - int options, + const int options, bool deferred); struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, struct World *wo, const void *engine_type, - int options, + const int options, + const bool is_volume_shader, const char *vert, const char *geom, const char *frag_lib, @@ -229,7 +235,8 @@ struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, struct GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, struct Material *ma, const void *engine_type, - int options, + const int options, + const bool is_volume_shader, const char *vert, const char *geom, const char *frag_lib, @@ -244,51 +251,72 @@ void DRW_shader_free(struct GPUShader *shader); } \ } while (0) -/* Batches */ +DRWShaderLibrary *DRW_shader_library_create(void); + +/* Warning: Each library must be added after all its dependencies. */ +void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const char *lib_name); +#define DRW_SHADER_LIB_ADD(lib, lib_name) \ + DRW_shader_library_add_file(lib, datatoc_##lib_name##_glsl, STRINGIFY(lib_name) ".glsl") + +char *DRW_shader_library_create_shader_string(DRWShaderLibrary *lib, char *shader_code); + +void DRW_shader_library_free(DRWShaderLibrary *lib); +#define DRW_SHADER_LIB_FREE_SAFE(lib) \ + do { \ + if (lib != NULL) { \ + DRW_shader_library_free(lib); \ + lib = NULL; \ + } \ + } while (0) +/* Batches */ +/* DRWState is a bitmask that stores the current render state and the desired render state. Based + * on the differences the minimum state changes can be invoked to setup the desired render state. + * + * The Write Stencil, Stencil test, Depth test and Blend state options are mutual exclusive + * therefore they aren't ordered as a bit mask.*/ typedef enum { /** Write mask */ DRW_STATE_WRITE_DEPTH = (1 << 0), DRW_STATE_WRITE_COLOR = (1 << 1), + /* Write Stencil. These options are mutual exclusive and packed into 2 bits */ DRW_STATE_WRITE_STENCIL = (1 << 2), - DRW_STATE_WRITE_STENCIL_SHADOW_PASS = (1 << 3), - DRW_STATE_WRITE_STENCIL_SHADOW_FAIL = (1 << 4), - - /** Depth test */ - DRW_STATE_DEPTH_ALWAYS = (1 << 5), - DRW_STATE_DEPTH_LESS = (1 << 6), - DRW_STATE_DEPTH_LESS_EQUAL = (1 << 7), - DRW_STATE_DEPTH_EQUAL = (1 << 8), - DRW_STATE_DEPTH_GREATER = (1 << 9), - DRW_STATE_DEPTH_GREATER_EQUAL = (1 << 10), + DRW_STATE_WRITE_STENCIL_SHADOW_PASS = (2 << 2), + DRW_STATE_WRITE_STENCIL_SHADOW_FAIL = (3 << 2), + /** Depth test. These options are mutual exclusive and packed into 3 bits */ + DRW_STATE_DEPTH_ALWAYS = (1 << 4), + DRW_STATE_DEPTH_LESS = (2 << 4), + DRW_STATE_DEPTH_LESS_EQUAL = (3 << 4), + DRW_STATE_DEPTH_EQUAL = (4 << 4), + DRW_STATE_DEPTH_GREATER = (5 << 4), + DRW_STATE_DEPTH_GREATER_EQUAL = (6 << 4), /** Culling test */ - DRW_STATE_CULL_BACK = (1 << 11), - DRW_STATE_CULL_FRONT = (1 << 12), - /** Stencil test */ - DRW_STATE_STENCIL_ALWAYS = (1 << 13), - DRW_STATE_STENCIL_EQUAL = (1 << 14), - DRW_STATE_STENCIL_NEQUAL = (1 << 15), - - /** Blend state */ - DRW_STATE_BLEND_ADD = (1 << 16), + DRW_STATE_CULL_BACK = (1 << 7), + DRW_STATE_CULL_FRONT = (1 << 8), + /** Stencil test . These options are mutal exclusive and packed into 2 bits*/ + DRW_STATE_STENCIL_ALWAYS = (1 << 9), + DRW_STATE_STENCIL_EQUAL = (2 << 9), + DRW_STATE_STENCIL_NEQUAL = (3 << 9), + + /** Blend state. These options are mutual exclusive and packed into 4 bits */ + DRW_STATE_BLEND_ADD = (1 << 11), /** Same as additive but let alpha accumulate without premult. */ - DRW_STATE_BLEND_ADD_FULL = (1 << 17), + DRW_STATE_BLEND_ADD_FULL = (2 << 11), /** Standard alpha blending. */ - DRW_STATE_BLEND_ALPHA = (1 << 18), + DRW_STATE_BLEND_ALPHA = (3 << 11), /** Use that if color is already premult by alpha. */ - DRW_STATE_BLEND_ALPHA_PREMUL = (1 << 19), - DRW_STATE_BLEND_BACKGROUND = (1 << 20), - DRW_STATE_BLEND_OIT = (1 << 21), - DRW_STATE_BLEND_MUL = (1 << 22), - DRW_STATE_BLEND_SUB = (1 << 23), + DRW_STATE_BLEND_ALPHA_PREMUL = (4 << 11), + DRW_STATE_BLEND_BACKGROUND = (5 << 11), + DRW_STATE_BLEND_OIT = (6 << 11), + DRW_STATE_BLEND_MUL = (7 << 11), + DRW_STATE_BLEND_SUB = (8 << 11), /** Use dual source blending. WARNING: Only one color buffer allowed. */ - DRW_STATE_BLEND_CUSTOM = (1 << 24), + DRW_STATE_BLEND_CUSTOM = (9 << 11), + DRW_STATE_LOGIC_INVERT = (10 << 11), - DRW_STATE_IN_FRONT_SELECT = (1 << 25), - DRW_STATE_LOGIC_INVERT = (1 << 26), - DRW_STATE_SHADOW_OFFSET = (1 << 27), - DRW_STATE_CLIP_PLANES = (1 << 28), - // DRW_STATE_WIRE_SMOOTH = (1 << 29), /* UNUSED */ + DRW_STATE_IN_FRONT_SELECT = (1 << 27), + DRW_STATE_SHADOW_OFFSET = (1 << 28), + DRW_STATE_CLIP_PLANES = (1 << 29), DRW_STATE_FIRST_VERTEX_CONVENTION = (1 << 30), /** DO NOT USE. Assumed always enabled. Only used internally. */ DRW_STATE_PROGRAM_POINT_SIZE = (1u << 31), @@ -401,18 +429,21 @@ void DRW_buffer_add_entry_array(DRWCallBuffer *buffer, const void *attr[], uint DRW_buffer_add_entry_array(buffer, array, (sizeof(array) / sizeof(*array))); \ } while (0) +/* Can only be called during iter phase. */ +uint32_t DRW_object_resource_id_get(Object *UNUSED(ob)); + void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state); void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state); /* Reminders: * - (compare_mask & reference) is what is tested against (compare_mask & stencil_value) * stencil_value being the value stored in the stencil buffer. - * - (writemask & reference) is what gets written if the test condition is fullfiled. + * - (write-mask & reference) is what gets written if the test condition is fulfilled. **/ void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup, uint write_mask, uint reference, - uint comp_mask); + uint compare_mask); /* TODO remove this function. Obsolete version. mask is actually reference value. */ void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask); diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 24d3b7fa7b6..5818d84a7af 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -177,6 +177,11 @@ struct DRWShadingGroup *DRW_shgroup_hair_create(struct Object *object, struct DRWPass *hair_pass, struct GPUShader *shader); +struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object, + struct ParticleSystem *psys, + struct ModifierData *md, + struct DRWShadingGroup *shgrp); + struct DRWShadingGroup *DRW_shgroup_material_hair_create(struct Object *object, struct ParticleSystem *psys, struct ModifierData *md, diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 08256b931ba..c88071dc6d6 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -36,6 +36,7 @@ #include "GPU_batch.h" #include "GPU_shader.h" +#include "GPU_vertex_buffer.h" #include "draw_hair_private.h" @@ -62,6 +63,8 @@ static int g_tf_target_width; static int g_tf_target_height; #endif +static GPUVertBuf *g_dummy_vbo = NULL; +static GPUTexture *g_dummy_texture = NULL; static GPUShader *g_refine_shaders[PART_REFINE_MAX_SHADER] = {NULL}; static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */ @@ -102,12 +105,29 @@ void DRW_hair_init(void) #else g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_WRITE_COLOR); #endif + + if (g_dummy_vbo == NULL) { + /* initialize vertex format */ + GPUVertFormat format = {0}; + uint dummy_id = GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + + g_dummy_vbo = GPU_vertbuf_create_with_format(&format); + + float vert[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_vertbuf_data_alloc(g_dummy_vbo, 1); + GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert); + /* Create vbo immediately to bind to texture buffer. */ + GPU_vertbuf_use(g_dummy_vbo); + + g_dummy_texture = GPU_texture_create_from_vertbuf(g_dummy_vbo); + } } static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, ParticleSystem *psys, ModifierData *md, DRWPass *hair_pass, + DRWShadingGroup *shgrp_parent, struct GPUMaterial *gpu_mat, GPUShader *gpu_shader) { @@ -127,7 +147,10 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, object, psys, md, &hair_cache, subdiv, thickness_res); DRWShadingGroup *shgrp; - if (gpu_mat) { + if (shgrp_parent) { + shgrp = DRW_shgroup_create_sub(shgrp_parent); + } + else if (gpu_mat) { shgrp = DRW_shgroup_material_create(gpu_mat, hair_pass); } else if (gpu_shader) { @@ -151,6 +174,17 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, } } + /* Fix issue with certain driver not drawing anything if there is no texture bound to + * "ac", "au", "u" or "c". */ + if (hair_cache->num_uv_layers == 0) { + DRW_shgroup_uniform_texture(shgrp, "u", g_dummy_texture); + DRW_shgroup_uniform_texture(shgrp, "au", g_dummy_texture); + } + if (hair_cache->num_col_layers == 0) { + DRW_shgroup_uniform_texture(shgrp, "c", g_dummy_texture); + DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture); + } + if ((dupli_parent != NULL) && (dupli_object != NULL)) { if (dupli_object->type & OB_DUPLICOLLECTION) { copy_m4_m4(dupli_mat, dupli_parent->obmat); @@ -220,7 +254,15 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, DRWShadingGroup *DRW_shgroup_hair_create( Object *object, ParticleSystem *psys, ModifierData *md, DRWPass *hair_pass, GPUShader *shader) { - return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, shader); + return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, NULL, shader); +} + +DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, + ParticleSystem *psys, + ModifierData *md, + DRWShadingGroup *shgrp) +{ + return drw_shgroup_create_hair_procedural_ex(object, psys, md, NULL, shgrp, NULL, NULL); } DRWShadingGroup *DRW_shgroup_material_hair_create(Object *object, @@ -229,7 +271,7 @@ DRWShadingGroup *DRW_shgroup_material_hair_create(Object *object, DRWPass *hair_pass, struct GPUMaterial *material) { - return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, material, NULL); + return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, material, NULL); } void DRW_hair_update(void) @@ -313,4 +355,7 @@ void DRW_hair_free(void) for (int i = 0; i < PART_REFINE_MAX_SHADER; i++) { DRW_SHADER_FREE_SAFE(g_refine_shaders[i]); } + + GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo); + DRW_TEXTURE_FREE_SAFE(g_dummy_texture); } diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index b9711b4f88f..6d81d82a6cf 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1118,45 +1118,23 @@ static void use_drw_engine(DrawEngineType *engine) BLI_addtail(&DST.enabled_engines, ld); } -/** - * Use for external render engines. - */ -static void drw_engines_enable_external(void) -{ - use_drw_engine(DRW_engine_viewport_external_type.draw_engine); -} - -/* TODO revisit this when proper layering is implemented */ /* Gather all draw engines needed and store them in DST.enabled_engines * That also define the rendering order of engines */ -static void drw_engines_enable_from_engine(RenderEngineType *engine_type, - eDrawType drawtype, - bool use_xray) +static void drw_engines_enable_from_engine(RenderEngineType *engine_type, eDrawType drawtype) { switch (drawtype) { case OB_WIRE: - use_drw_engine(&draw_engine_workbench_transparent); - break; - case OB_SOLID: - if (use_xray) { - use_drw_engine(&draw_engine_workbench_transparent); - } - else { - use_drw_engine(&draw_engine_workbench_solid); - } + use_drw_engine(DRW_engine_viewport_workbench_type.draw_engine); break; - case OB_MATERIAL: case OB_RENDER: default: - /* TODO layers */ if (engine_type->draw_engine != NULL) { use_drw_engine(engine_type->draw_engine); } - - if ((engine_type->flag & RE_INTERNAL) == 0) { - drw_engines_enable_external(); + else if ((engine_type->flag & RE_INTERNAL) == 0) { + use_drw_engine(DRW_engine_viewport_external_type.draw_engine); } break; } @@ -1182,7 +1160,7 @@ static void drw_engines_enable(ViewLayer *UNUSED(view_layer), const eDrawType drawtype = v3d->shading.type; const bool use_xray = XRAY_ENABLED(v3d); - drw_engines_enable_from_engine(engine_type, drawtype, use_xray); + drw_engines_enable_from_engine(engine_type, drawtype); if (gpencil_engine_needed && ((drawtype >= OB_SOLID) || !use_xray)) { use_drw_engine(&draw_engine_gpencil_type); } @@ -1608,6 +1586,9 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph, GPU_blend(true); } + GPU_matrix_identity_set(); + GPU_matrix_identity_projection_set(); + GPU_viewport_unbind_from_offscreen(render_viewport, ofs, do_color_management); if (draw_background) { @@ -2646,9 +2627,6 @@ void DRW_engines_register(void) RE_engines_register(&DRW_engine_viewport_eevee_type); RE_engines_register(&DRW_engine_viewport_workbench_type); - DRW_engine_register(&draw_engine_workbench_solid); - DRW_engine_register(&draw_engine_workbench_transparent); - DRW_engine_register(&draw_engine_gpencil_type); DRW_engine_register(&draw_engine_overlay_type); diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 83142da051a..be0dd7751ed 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -562,6 +562,16 @@ static DRWResourceHandle drw_resource_handle_new(float (*obmat)[4], Object *ob) return handle; } +uint32_t DRW_object_resource_id_get(Object *UNUSED(ob)) +{ + DRWResourceHandle handle = DST.ob_handle; + if (handle == 0) { + /* Handle not yet allocated. Return next handle. */ + handle = DST.resource_handle; + } + return handle; +} + static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob) @@ -693,14 +703,14 @@ static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf, static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup, uint write_mask, uint reference, - uint comp_mask) + uint compare_mask) { BLI_assert(write_mask <= 0xFF); BLI_assert(reference <= 0xFF); - BLI_assert(comp_mask <= 0xFF); + BLI_assert(compare_mask <= 0xFF); DRWCommandSetStencil *cmd = drw_command_create(shgroup, DRW_CMD_STENCIL); cmd->write_mask = write_mask; - cmd->comp_mask = comp_mask; + cmd->comp_mask = compare_mask; cmd->ref = reference; } @@ -1341,9 +1351,9 @@ void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state) void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup, uint write_mask, uint reference, - uint comp_mask) + uint compare_mask) { - drw_command_set_stencil_mask(shgroup, write_mask, reference, comp_mask); + drw_command_set_stencil_mask(shgroup, write_mask, reference, compare_mask); } /* TODO remove this function. */ diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 85525ea7b55..3d1b43537b7 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -114,19 +114,20 @@ void drw_state_set(DRWState state) /* Stencil Write */ if (test) { glStencilMask(0xFF); - if (test & DRW_STATE_WRITE_STENCIL) { - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - } - else if (test & DRW_STATE_WRITE_STENCIL_SHADOW_PASS) { - glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_INCR_WRAP); - glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_DECR_WRAP); - } - else if (test & DRW_STATE_WRITE_STENCIL_SHADOW_FAIL) { - glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_KEEP); - glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_KEEP); - } - else { - BLI_assert(0); + switch (test) { + case DRW_STATE_WRITE_STENCIL: + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + break; + case DRW_STATE_WRITE_STENCIL_SHADOW_PASS: + glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_INCR_WRAP); + glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_DECR_WRAP); + break; + case DRW_STATE_WRITE_STENCIL_SHADOW_FAIL: + glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_KEEP); + glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_KEEP); + break; + default: + BLI_assert(0); } } else { @@ -191,26 +192,27 @@ void drw_state_set(DRWState state) if (test) { glEnable(GL_DEPTH_TEST); - if (state & DRW_STATE_DEPTH_LESS) { - glDepthFunc(GL_LESS); - } - else if (state & DRW_STATE_DEPTH_LESS_EQUAL) { - glDepthFunc(GL_LEQUAL); - } - else if (state & DRW_STATE_DEPTH_EQUAL) { - glDepthFunc(GL_EQUAL); - } - else if (state & DRW_STATE_DEPTH_GREATER) { - glDepthFunc(GL_GREATER); - } - else if (state & DRW_STATE_DEPTH_GREATER_EQUAL) { - glDepthFunc(GL_GEQUAL); - } - else if (state & DRW_STATE_DEPTH_ALWAYS) { - glDepthFunc(GL_ALWAYS); - } - else { - BLI_assert(0); + switch (test) { + case DRW_STATE_DEPTH_LESS: + glDepthFunc(GL_LESS); + break; + case DRW_STATE_DEPTH_LESS_EQUAL: + glDepthFunc(GL_LEQUAL); + break; + case DRW_STATE_DEPTH_EQUAL: + glDepthFunc(GL_EQUAL); + break; + case DRW_STATE_DEPTH_GREATER: + glDepthFunc(GL_GREATER); + break; + case DRW_STATE_DEPTH_GREATER_EQUAL: + glDepthFunc(GL_GEQUAL); + break; + case DRW_STATE_DEPTH_ALWAYS: + glDepthFunc(GL_ALWAYS); + break; + default: + BLI_assert(0); } } else { @@ -244,62 +246,63 @@ void drw_state_set(DRWState state) if (test) { glEnable(GL_BLEND); - if ((state & DRW_STATE_BLEND_ALPHA) != 0) { - glBlendFuncSeparate(GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA, /* RGB */ - GL_ONE, - GL_ONE_MINUS_SRC_ALPHA); /* Alpha */ - } - else if ((state & DRW_STATE_BLEND_BACKGROUND) != 0) { - /* Special blend to add color under and multiply dst by alpha. */ - glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, - GL_SRC_ALPHA, /* RGB */ - GL_ZERO, - GL_SRC_ALPHA); /* Alpha */ - } - else if ((state & DRW_STATE_BLEND_ALPHA_PREMUL) != 0) { - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } - else if ((state & DRW_STATE_BLEND_MUL) != 0) { - glBlendFunc(GL_DST_COLOR, GL_ZERO); - } - else if ((state & DRW_STATE_BLEND_OIT) != 0) { - glBlendFuncSeparate(GL_ONE, - GL_ONE, /* RGB */ - GL_ZERO, - GL_ONE_MINUS_SRC_ALPHA); /* Alpha */ - } - else if ((state & DRW_STATE_BLEND_ADD) != 0) { - /* Do not let alpha accumulate but premult the source RGB by it. */ - glBlendFuncSeparate(GL_SRC_ALPHA, - GL_ONE, /* RGB */ - GL_ZERO, - GL_ONE); /* Alpha */ - } - else if ((state & DRW_STATE_BLEND_ADD_FULL) != 0) { - /* Let alpha accumulate. */ - glBlendFunc(GL_ONE, GL_ONE); - } - else if ((state & DRW_STATE_BLEND_SUB) != 0) { - glBlendFunc(GL_ONE, GL_ONE); - } - else if ((state & DRW_STATE_BLEND_CUSTOM) != 0) { - /* Custom blend parameters using dual source blending. - * Can only be used with one Draw Buffer. */ - glBlendFunc(GL_ONE, GL_SRC1_COLOR); - } - else if ((state & DRW_STATE_LOGIC_INVERT) != 0) { - /* Replace logic op by blend func to support floating point framebuffer. */ - glBlendFuncSeparate(GL_ONE_MINUS_DST_COLOR, - GL_ZERO, /* RGB */ - GL_ZERO, - GL_ONE); /* Alpha */ - } - else { - BLI_assert(0); + switch (test) { + case DRW_STATE_BLEND_ALPHA: + glBlendFuncSeparate(GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, /* RGB */ + GL_ONE, + GL_ONE_MINUS_SRC_ALPHA); /* Alpha */ + break; + case DRW_STATE_BLEND_BACKGROUND: + /* Special blend to add color under and multiply dst by alpha. */ + glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, + GL_SRC_ALPHA, /* RGB */ + GL_ZERO, + GL_SRC_ALPHA); /* Alpha */ + break; + case DRW_STATE_BLEND_ALPHA_PREMUL: + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + break; + case DRW_STATE_BLEND_MUL: + glBlendFunc(GL_DST_COLOR, GL_ZERO); + break; + case DRW_STATE_BLEND_OIT: + glBlendFuncSeparate(GL_ONE, + GL_ONE, /* RGB */ + GL_ZERO, + GL_ONE_MINUS_SRC_ALPHA); /* Alpha */ + break; + case DRW_STATE_BLEND_ADD: + /* Do not let alpha accumulate but premult the source RGB by it. */ + glBlendFuncSeparate(GL_SRC_ALPHA, + GL_ONE, /* RGB */ + GL_ZERO, + GL_ONE); /* Alpha */ + break; + case DRW_STATE_BLEND_ADD_FULL: + /* Let alpha accumulate. */ + glBlendFunc(GL_ONE, GL_ONE); + break; + case DRW_STATE_BLEND_SUB: + glBlendFunc(GL_ONE, GL_ONE); + break; + case DRW_STATE_BLEND_CUSTOM: + /* Custom blend parameters using dual source blending. + * Can only be used with one Draw Buffer. */ + glBlendFunc(GL_ONE, GL_SRC1_COLOR); + break; + case DRW_STATE_LOGIC_INVERT: + /* Replace logic op by blend func to support floating point framebuffer. */ + glBlendFuncSeparate(GL_ONE_MINUS_DST_COLOR, + GL_ZERO, /* RGB */ + GL_ZERO, + GL_ONE); /* Alpha */ + break; + default: + BLI_assert(0); } - if ((state & DRW_STATE_BLEND_SUB) != 0) { + if (test == DRW_STATE_BLEND_SUB) { glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); } else { @@ -402,17 +405,17 @@ static void drw_stencil_state_set(uint write_mask, uint reference, uint compare_ /* Reminders: * - (compare_mask & reference) is what is tested against (compare_mask & stencil_value) * stencil_value being the value stored in the stencil buffer. - * - (writemask & reference) is what gets written if the test condition is fullfiled. + * - (write-mask & reference) is what gets written if the test condition is fulfilled. **/ glStencilMask(write_mask); - - if ((DST.state & DRW_STATE_STENCIL_ALWAYS) != 0) { + DRWState stencil_test = DST.state & DRW_STATE_STENCIL_TEST_ENABLED; + if (stencil_test == DRW_STATE_STENCIL_ALWAYS) { glStencilFunc(GL_ALWAYS, reference, compare_mask); } - else if ((DST.state & DRW_STATE_STENCIL_EQUAL) != 0) { + else if (stencil_test == DRW_STATE_STENCIL_EQUAL) { glStencilFunc(GL_EQUAL, reference, compare_mask); } - else if ((DST.state & DRW_STATE_STENCIL_NEQUAL) != 0) { + else if (stencil_test == DRW_STATE_STENCIL_NEQUAL) { glStencilFunc(GL_NOTEQUAL, reference, compare_mask); } } diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 9c34cdbac3b..7b08f44921f 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -24,6 +24,7 @@ #include "DNA_world_types.h" #include "DNA_material_types.h" +#include "BLI_dynstr.h" #include "BLI_listbase.h" #include "BLI_string_utils.h" #include "BLI_threads.h" @@ -282,6 +283,8 @@ void DRW_deferred_shader_remove(GPUMaterial *mat) /* -------------------------------------------------------------------- */ +/** \{ */ + GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, @@ -356,7 +359,7 @@ GPUShader *DRW_shader_create_3d_depth_only(eGPUShaderConfig sh_cfg) GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, - int options, + const int options, bool deferred) { GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options); @@ -372,7 +375,7 @@ GPUMaterial *DRW_shader_find_from_world(World *wo, GPUMaterial *DRW_shader_find_from_material(Material *ma, const void *engine_type, - int options, + const int options, bool deferred) { GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options); @@ -389,7 +392,8 @@ GPUMaterial *DRW_shader_find_from_material(Material *ma, GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, World *wo, const void *engine_type, - int options, + const int options, + const bool is_volume_shader, const char *vert, const char *geom, const char *frag_lib, @@ -409,6 +413,7 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, &wo->gpumaterial, engine_type, options, + is_volume_shader, vert, geom, frag_lib, @@ -426,7 +431,8 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, Material *ma, const void *engine_type, - int options, + const int options, + const bool is_volume_shader, const char *vert, const char *geom, const char *frag_lib, @@ -446,6 +452,7 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, &ma->gpumaterial, engine_type, options, + is_volume_shader, vert, geom, frag_lib, @@ -464,3 +471,129 @@ void DRW_shader_free(GPUShader *shader) { GPU_shader_free(shader); } + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Shader Library + * + * Simple include system for glsl files. + * + * Usage: Create a DRWShaderLibrary and add the library in the right order. + * You can have nested dependencies but each new library needs to have all its dependencies already + * added to the DRWShaderLibrary. + * Finally you can use DRW_shader_library_create_shader_string to get a shader string that also + * contains the needed libraries for this shader. + * \{ */ + +/* 32 because we use a 32bit bitmap. */ +#define MAX_LIB 32 +#define MAX_LIB_NAME 64 +#define MAX_LIB_DEPS 8 + +struct DRWShaderLibrary { + char *libs[MAX_LIB]; + char libs_name[MAX_LIB][MAX_LIB_NAME]; + uint32_t libs_deps[MAX_LIB]; +}; + +DRWShaderLibrary *DRW_shader_library_create(void) +{ + return MEM_callocN(sizeof(DRWShaderLibrary), "DRWShaderLibrary"); +} + +void DRW_shader_library_free(DRWShaderLibrary *lib) +{ + MEM_SAFE_FREE(lib); +} + +static int drw_shader_library_search(DRWShaderLibrary *lib, const char *name) +{ + for (int i = 0; i < MAX_LIB; i++) { + if (lib->libs[i]) { + if (!strncmp(lib->libs_name[i], name, strlen(lib->libs_name[i]))) { + return i; + } + } + else { + break; + } + } + return -1; +} + +/* Return bitmap of dependencies. */ +static uint32_t drw_shader_dependencies_get(DRWShaderLibrary *lib, char *lib_code) +{ + /* Search dependencies. */ + uint32_t deps = 0; + char *haystack = lib_code; + while ((haystack = strstr(haystack, "BLENDER_REQUIRE("))) { + haystack += 16; + int dep = drw_shader_library_search(lib, haystack); + if (dep == -1) { + printf( + "Error: Dependency not found.\n" + "This might be due to bad lib ordering.\n"); + BLI_assert(0); + } + else { + deps |= 1u << (uint32_t)dep; + } + } + return deps; +} + +void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const char *lib_name) +{ + int index = -1; + for (int i = 0; i < MAX_LIB; i++) { + if (lib->libs[i] == NULL) { + index = i; + break; + } + } + + if (index > -1) { + lib->libs[index] = lib_code; + BLI_strncpy(lib->libs_name[index], lib_name, MAX_LIB_NAME); + } + else { + printf("Error: Too many libraries. Cannot add %s.\n", lib_name); + BLI_assert(0); + } + + lib->libs_deps[index] = drw_shader_dependencies_get(lib, lib_code); +} + +/* Return an allocN'ed string containing the shader code with its dependencies prepended. + * Caller must free the string with MEM_freeN after use. */ +char *DRW_shader_library_create_shader_string(DRWShaderLibrary *lib, char *shader_code) +{ + uint32_t deps = drw_shader_dependencies_get(lib, shader_code); + + DynStr *ds = BLI_dynstr_new(); + /* Add all dependencies recursively. */ + for (int i = MAX_LIB - 1; i > -1; i--) { + if (lib->libs[i] && (deps & (1u << (uint32_t)i))) { + deps |= lib->libs_deps[i]; + } + } + /* Concatenate all needed libs into one string. */ + for (int i = 0; i < MAX_LIB; i++) { + if (deps & 1u) { + BLI_dynstr_append(ds, lib->libs[i]); + } + deps = deps >> 1; + } + + BLI_dynstr_append(ds, shader_code); + + char *str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + return str; +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c index 373810b2f7f..3f11fe9d11e 100644 --- a/source/blender/draw/intern/draw_manager_texture.c +++ b/source/blender/draw/intern/draw_manager_texture.c @@ -123,6 +123,15 @@ GPUTexture *DRW_texture_create_cube(int w, return tex; } +GPUTexture *DRW_texture_create_cube_array( + int w, int d, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex = GPU_texture_create_cube_array(w, d, format, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + return tex; +} + GPUTexture *DRW_texture_pool_query_2d(int w, int h, eGPUTextureFormat format, @@ -134,6 +143,13 @@ GPUTexture *DRW_texture_pool_query_2d(int w, return tex; } +GPUTexture *DRW_texture_pool_query_fullscreen(eGPUTextureFormat format, + DrawEngineType *engine_type) +{ + const float *size = DRW_viewport_size_get(); + return DRW_texture_pool_query_2d((int)size[0], (int)size[1], format, engine_type); +} + void DRW_texture_ensure_fullscreen_2d(GPUTexture **tex, eGPUTextureFormat format, DRWTextureFlag flags) diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index dcf0377ffc0..4b0a4bcf46b 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -1790,81 +1790,63 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, bDopeSheet *ads = ac->ads; size_t items = 0; - if (ads->filterflag & ADS_FILTER_GP_3DONLY) { - Scene *scene = (Scene *)ads->source; - ViewLayer *view_layer = (ViewLayer *)ac->view_layer; - Base *base; - - /* Active scene's GPencil block first - No parent item needed... */ - if (scene->gpd) { - items += animdata_filter_gpencil_data(anim_data, ads, scene->gpd, filter_mode); - } - - /* Objects in the scene */ - for (base = view_layer->object_bases.first; base; base = base->next) { - /* Only consider this object if it has got some GP data (saving on all the other tests) */ - if (base->object && (base->object->type == OB_GPENCIL)) { - Object *ob = base->object; - - /* firstly, check if object can be included, by the following factors: - * - if only visible, must check for layer and also viewport visibility - * --> while tools may demand only visible, user setting takes priority - * as user option controls whether sets of channels get included while - * tool-flag takes into account collapsed/open channels too - * - if only selected, must check if object is selected - * - there must be animation data to edit (this is done recursively as we - * try to add the channels) - */ - if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && - !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { - /* Layer visibility - we check both object and base, - * since these may not be in sync yet. */ - if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { - continue; - } - - /* outliner restrict-flag */ - if (ob->restrictflag & OB_RESTRICT_VIEWPORT) { - continue; - } + Scene *scene = (Scene *)ads->source; + ViewLayer *view_layer = (ViewLayer *)ac->view_layer; + Base *base; + + /* Active scene's GPencil block first - No parent item needed... */ + if (scene->gpd) { + items += animdata_filter_gpencil_data(anim_data, ads, scene->gpd, filter_mode); + } + + /* Objects in the scene */ + for (base = view_layer->object_bases.first; base; base = base->next) { + /* Only consider this object if it has got some GP data (saving on all the other tests) */ + if (base->object && (base->object->type == OB_GPENCIL)) { + Object *ob = base->object; + + /* firstly, check if object can be included, by the following factors: + * - if only visible, must check for layer and also viewport visibility + * --> while tools may demand only visible, user setting takes priority + * as user option controls whether sets of channels get included while + * tool-flag takes into account collapsed/open channels too + * - if only selected, must check if object is selected + * - there must be animation data to edit (this is done recursively as we + * try to add the channels) + */ + if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { + /* Layer visibility - we check both object and base, + * since these may not be in sync yet. */ + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { + continue; } - /* check selection and object type filters only for Object mode */ - if (ob->mode == OB_MODE_OBJECT) { - if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED))) { - /* only selected should be shown */ - continue; - } - } - /* check if object belongs to the filtering group if option to filter - * objects by the grouped status is on - * - used to ease the process of doing multiple-character choreographies - */ - if (ads->filter_grp != NULL) { - if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) { - continue; - } + /* outliner restrict-flag */ + if (ob->restrictflag & OB_RESTRICT_VIEWPORT) { + continue; } - - /* finally, include this object's grease pencil data-block. */ - /* XXX: Should we store these under expanders per item? */ - items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode); } - } - } - else { - bGPdata *gpd; - /* Grab all Grease Pencil data-blocks directly from main, - * but only those that seem to be useful somewhere */ - for (gpd = ac->bmain->gpencils.first; gpd; gpd = gpd->id.next) { - /* only show if gpd is used by something... */ - if (ID_REAL_USERS(gpd) < 1) { - continue; + /* check selection and object type filters only for Object mode */ + if (ob->mode == OB_MODE_OBJECT) { + if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED))) { + /* only selected should be shown */ + continue; + } + } + /* check if object belongs to the filtering group if option to filter + * objects by the grouped status is on + * - used to ease the process of doing multiple-character choreographies + */ + if (ads->filter_grp != NULL) { + if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) { + continue; + } } - /* add GP frames from this data-block. */ - items += animdata_filter_gpencil_data(anim_data, ads, gpd, filter_mode); + /* finally, include this object's grease pencil data-block. */ + /* XXX: Should we store these under expanders per item? */ + items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode); } } diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index 5b729c856c0..f631d08f3e4 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -177,8 +177,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) icon = RNA_struct_ui_icon(ptr.type); /* valid path - remove the invalid tag since we now know how to use it saving - * users manual effort to reenable using "Revive Disabled FCurves" [#29629] - */ + * users manual effort to re-enable using "Revive Disabled FCurves" T29629. */ fcu->flag &= ~FCURVE_DISABLED; } else { diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 0f288c0d8b8..47eb09cdf3d 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -1461,6 +1461,13 @@ static void select_similar_data_pchan(bContext *C, const size_t bytes_size, cons EditBone *ebone_act = CTX_data_active_bone(C); const bPoseChannel *pchan_active = BKE_pose_channel_find_name(obedit->pose, ebone_act->name); + + /* This will mostly happen for corner cases where the user tried to access this + * before having any valid pose data for the armature. */ + if (pchan_active == NULL) { + return; + } + const char *data_active = (const char *)POINTER_OFFSET(pchan_active, offset); for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_SELECTABLE(arm, ebone)) { diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c index d8cd4d20579..f7d22223b55 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c @@ -119,21 +119,25 @@ static void move_geom_draw(const wmGizmo *gz, immUniformColor4fv(color); + /* Use the final scale as a radius if it's not already applied to the final matrix. */ + const float radius = (gz->flag & WM_GIZMO_DRAW_NO_SCALE) ? gz->scale_final : 1.0f; + if (draw_style == ED_GIZMO_MOVE_STYLE_RING_2D) { if (filled) { - imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION); + imm_draw_circle_fill_2d(pos, 0, 0, radius, DIAL_RESOLUTION); } else { - imm_draw_circle_wire_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION); + imm_draw_circle_wire_2d(pos, 0, 0, radius, DIAL_RESOLUTION); } } else if (draw_style == ED_GIZMO_MOVE_STYLE_CROSS_2D) { + const float radius_diag = M_SQRT1_2 * radius; immBegin(GPU_PRIM_LINES, 4); - immVertex2f(pos, 1.0f, 1.0f); - immVertex2f(pos, -1.0f, -1.0f); + immVertex2f(pos, radius_diag, radius_diag); + immVertex2f(pos, -radius_diag, -radius_diag); - immVertex2f(pos, -1.0f, 1.0f); - immVertex2f(pos, 1.0f, -1.0f); + immVertex2f(pos, -radius_diag, radius_diag); + immVertex2f(pos, radius_diag, -radius_diag); immEnd(); } else { @@ -260,6 +264,9 @@ static int gizmo_move_modal(bContext *C, return OPERATOR_RUNNING_MODAL; } sub_v2_v2v2(prop_delta, mval_proj_curr, mval_proj_init); + if ((gz->flag & WM_GIZMO_DRAW_NO_SCALE) == 0) { + mul_v2_fl(prop_delta, gz->scale_final); + } prop_delta[2] = 0.0f; } @@ -394,8 +401,10 @@ static int gizmo_move_test_select(bContext *C, wmGizmo *gz, const int mval[2]) return -1; } - /* The 'gz->scale_final' is already applied when projecting. */ - if (len_squared_v2(point_local) < 1.0f) { + /* The 'gz->scale_final' is already applied to the projection + * when #WM_GIZMO_DRAW_NO_SCALE isn't set. */ + const float radius = (gz->flag & WM_GIZMO_DRAW_NO_SCALE) ? gz->scale_final : 1.0f; + if (len_squared_v2(point_local) < radius) { return 0; } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 56351fbfb9a..46788eba370 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -3280,8 +3280,10 @@ static void gpencil_add_guide_points(const tGPsdata *p, } } -/* Add fake points for missing mouse movements when the artist draw very fast creating an arc - * with the vertice in the midle of the segment and using the angle of the previous segment. */ +/** + * Add fake points for missing mouse movements when the artist draw very fast creating an arc + * with the vertex in the middle of the segment and using the angle of the previous segment. + */ static void gpencil_add_fake_points(const wmEvent *event, tGPsdata *p) { Brush *brush = p->brush; diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index adc009efd16..5db331280f8 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -231,8 +231,8 @@ static GP_Sculpt_Settings *gpsculpt_get_settings(Scene *scene) static bool gp_brush_invert_check(tGP_BrushEditData *gso) { /* The basic setting is the brush's setting (from the panel) */ - bool invert = ((gso->brush->gpencil_settings->sculpt_flag & GP_SCULPT_FLAG_INVERT) != 0); - + bool invert = ((gso->brush->gpencil_settings->sculpt_flag & GP_SCULPT_FLAG_INVERT) != 0) || + (gso->brush->gpencil_settings->sculpt_flag & BRUSH_DIR_IN); /* During runtime, the user can hold down the Ctrl key to invert the basic behavior */ if (gso->flag & GP_SCULPT_FLAG_INVERT) { invert ^= true; @@ -1744,7 +1744,8 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) { /* compute multiframe falloff factor */ if (gso->use_multiframe_falloff) { - /* Faloff depends on distance to active frame (relative to the overall frame range) */ + /* Falloff depends on distance to active frame + * (relative to the overall frame range). */ gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc( gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff); } diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index 5b5a306aa25..c730d1b493e 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -1099,10 +1099,9 @@ static bool gp_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpai LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* Always do active frame; Otherwise, only include selected frames */ if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) { - /* compute multiframe falloff factor */ + /* Compute multi-frame falloff factor. */ if (gso->use_multiframe_falloff) { - /* Faloff depends on distance to active frame (relative to the overall frame range) - */ + /* Falloff depends on distance to active frame (relative to the overall frame range) */ gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc( gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff); } diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c index 6b337afa559..c519129cdf7 100644 --- a/source/blender/editors/gpencil/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil/gpencil_weight_paint.c @@ -110,7 +110,7 @@ typedef struct tGP_BrushWeightpaintData { /* Start of new paint */ bool first; - /* Is multiframe editing enabled, and are we using falloff for that? */ + /* Is multi-frame editing enabled, and are we using falloff for that? */ bool is_multiframe; bool use_multiframe_falloff; @@ -127,10 +127,10 @@ typedef struct tGP_BrushWeightpaintData { /* - Effect 2D vector */ float dvec[2]; - /* - multiframe falloff factor */ + /* - multi-frame falloff factor. */ float mf_falloff; - /* brush geometry (bounding box) */ + /* brush geometry (bounding box). */ rcti brush_rect; /* Temp data to save selected points */ @@ -206,7 +206,7 @@ static float brush_influence_calc(tGP_BrushWeightpaintData *gso, const int radiu float brush_fallof = BKE_brush_curve_strength(brush, distance, (float)radius); influence *= brush_fallof; - /* apply multiframe falloff */ + /* apply multi-frame falloff */ influence *= gso->mf_falloff; /* return influence */ @@ -585,7 +585,7 @@ static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpai /* Active Frame or MultiFrame? */ if (gso->is_multiframe) { - /* init multiframe falloff options */ + /* init multi-frame falloff options */ int f_init = 0; int f_end = 0; @@ -596,10 +596,10 @@ static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpai LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* Always do active frame; Otherwise, only include selected frames */ if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) { - /* compute multiframe falloff factor */ + /* Compute multi-frame falloff factor. */ if (gso->use_multiframe_falloff) { - /* Faloff depends on distance to active frame (relative to the overall frame range) - */ + /* Falloff depends on distance to active frame + * (relative to the overall frame range). */ gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc( gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff); } @@ -656,7 +656,7 @@ static void gp_weightpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA * gso->brush_rect.xmax = mouse[0] + radius; gso->brush_rect.ymax = mouse[1] + radius; - /* Calc 2D direction vector and relative angle. */ + /* Calculate 2D direction vector and relative angle. */ brush_calc_dvec_2d(gso); changed = gp_weightpaint_brush_apply_to_layers(C, gso); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 277f330ad50..dba95c5106e 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -2382,6 +2382,9 @@ struct ID *UI_context_active_but_get_tab_ID(struct bContext *C); uiBut *UI_region_active_but_get(struct ARegion *region); uiBut *UI_region_but_find_rect_over(const struct ARegion *region, const struct rcti *isect); +uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region, + const int xy[2], + bool only_clip); /* uiFontStyle.align */ typedef enum eFontStyle_Align { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 6da9bacd865..833631f871d 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -8268,6 +8268,13 @@ uiBut *UI_region_but_find_rect_over(const ARegion *region, const rcti *rect_px) return ui_but_find_rect_over(region, rect_px); } +uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region, + const int xy[2], + bool only_clip) +{ + return ui_block_find_mouse_over_ex(region, xy[0], xy[1], only_clip); +} + /** * Version of #UI_context_active_but_get that also returns RNA property info. * Helper function for insert keyframe, reset to default, etc operators. diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 24977848ae4..a2e239884a3 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -951,6 +951,14 @@ bool ui_block_is_popover(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; bool ui_block_is_popup_any(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; +uiBlock *ui_block_find_mouse_over_ex(const struct ARegion *region, + const int x, + const int y, + bool only_clip); +uiBlock *ui_block_find_mouse_over(const struct ARegion *region, + const struct wmEvent *event, + bool only_clip); + uiBut *ui_region_find_first_but_test_flag(struct ARegion *region, int flag_include, int flag_exclude); diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c index 03434b12ddb..52488027662 100644 --- a/source/blender/editors/interface/interface_query.c +++ b/source/blender/editors/interface/interface_query.c @@ -505,6 +505,40 @@ bool UI_block_can_add_separator(const uiBlock *block) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Block (#uiBlock) Spatial + * \{ */ + +uiBlock *ui_block_find_mouse_over_ex(const ARegion *region, + const int x, + const int y, + bool only_clip) +{ + if (!ui_region_contains_point_px(region, x, y)) { + return NULL; + } + for (uiBlock *block = region->uiblocks.first; block; block = block->next) { + if (only_clip) { + if ((block->flag & UI_BLOCK_CLIP_EVENTS) == 0) { + continue; + } + } + float mx = x, my = y; + ui_window_to_block_fl(region, block, &mx, &my); + if (BLI_rctf_isect_pt(&block->rect, mx, my)) { + return block; + } + } + return NULL; +} + +uiBlock *ui_block_find_mouse_over(const ARegion *region, const wmEvent *event, bool only_clip) +{ + return ui_block_find_mouse_over_ex(region, event->x, event->y, only_clip); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Region (#ARegion) State * \{ */ diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index d688e2cb658..1c4bc33240a 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -349,7 +349,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op) if (ob->mode == OB_MODE_SCULPT) { ED_sculpt_undo_geometry_begin(ob, "mask slice"); /* TODO: The ideal functionality would be to preserve the current face sets and add a new one - * for the new triangles, but this datalayer needs to be rebuild in order to make sculpt mode + * for the new triangles, but this data-layer needs to be rebuild in order to make sculpt mode * not crash when modifying the geometry. */ CustomData_free_layers(&mesh->pdata, CD_SCULPT_FACE_SETS, mesh->totpoly); } diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index dc825871bb7..8f31fa0a1fa 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -943,7 +943,7 @@ BMVert *editbmesh_get_x_mirror_vert(Object *ob, } /** - * Wrapper for objectmode/editmode. + * Wrapper for object-mode/edit-mode. * * call #BM_mesh_elem_table_ensure first for editmesh. */ diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 94e210b7243..95d044554f1 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -890,14 +890,14 @@ enum { static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op) { - if (scene->eevee.light_cache != NULL) { + if (scene->eevee.light_cache_data != 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; + scene->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_GRID | LIGHTCACHE_UPDATE_CUBE; break; case LIGHTCACHE_SUBSET_CUBE: - scene->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_CUBE; + scene->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_CUBE; break; case LIGHTCACHE_SUBSET_DIRTY: /* Leave tag untouched. */ @@ -1046,7 +1046,7 @@ static bool light_cache_free_poll(bContext *C) { Scene *scene = CTX_data_scene(C); - return scene->eevee.light_cache; + return scene->eevee.light_cache_data; } static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op)) @@ -1057,12 +1057,12 @@ static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op)) wmWindowManager *wm = CTX_wm_manager(C); WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_LIGHT_BAKE); - if (!scene->eevee.light_cache) { + if (!scene->eevee.light_cache_data) { return OPERATOR_CANCELLED; } - EEVEE_lightcache_free(scene->eevee.light_cache); - scene->eevee.light_cache = NULL; + EEVEE_lightcache_free(scene->eevee.light_cache_data); + scene->eevee.light_cache_data = NULL; EEVEE_lightcache_info_update(&scene->eevee); diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c index ad940a8e87d..114cb54636a 100644 --- a/source/blender/editors/scene/scene_edit.c +++ b/source/blender/editors/scene/scene_edit.c @@ -182,6 +182,8 @@ bool ED_scene_view_layer_delete(Main *bmain, Scene *scene, ViewLayer *layer, Rep } } + BKE_scene_free_view_layer_depsgraph(scene, layer); + BKE_view_layer_free(layer); DEG_id_tag_update(&scene->id, 0); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 6fe1ba0b817..fed3c2f03a4 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -377,17 +377,6 @@ static void PALETTE_OT_extract_from_image(wmOperatorType *ot) } /* Sort Palette color by Hue and Saturation. */ -static bool palette_sort_poll(bContext *C) -{ - Paint *paint = BKE_paint_get_active_from_context(C); - Palette *palette = paint->palette; - if (palette) { - return true; - } - - return false; -} - static int palette_sort_exec(bContext *C, wmOperator *op) { const int type = RNA_enum_get(op->ptr, "type"); @@ -477,7 +466,7 @@ static void PALETTE_OT_sort(wmOperatorType *ot) /* api callbacks */ ot->exec = palette_sort_exec; - ot->poll = palette_sort_poll; + ot->poll = palette_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -522,7 +511,7 @@ static void PALETTE_OT_color_move(wmOperatorType *ot) /* api callbacks */ ot->exec = palette_color_move_exec; - ot->poll = palette_sort_poll; + ot->poll = palette_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -531,17 +520,6 @@ static void PALETTE_OT_color_move(wmOperatorType *ot) } /* Join Palette swatches. */ -static bool palette_join_poll(bContext *C) -{ - Paint *paint = BKE_paint_get_active_from_context(C); - Palette *palette = paint->palette; - if (palette) { - return true; - } - - return false; -} - static int palette_join_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -599,7 +577,7 @@ static void PALETTE_OT_join(wmOperatorType *ot) /* api callbacks */ ot->exec = palette_join_exec; - ot->poll = palette_join_poll; + ot->poll = palette_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index b25cdbe39c1..5a830a90092 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -7030,7 +7030,9 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po if (cache->first_time || !((brush->flag & BRUSH_ANCHORED) || (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) || - (brush->sculpt_tool == SCULPT_TOOL_ROTATE))) { + (brush->sculpt_tool == SCULPT_TOOL_ROTATE) || + (brush->sculpt_tool == SCULPT_TOOL_CLOTH && + brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB))) { RNA_float_get_array(ptr, "location", cache->true_location); } diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c index 038d0e5a08c..f2671b66f7f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c +++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c @@ -58,7 +58,6 @@ #include <math.h> #include <stdlib.h> - typedef struct MultiplaneScrapeSampleData { float area_cos[2][3]; float area_nos[2][3]; @@ -223,7 +222,6 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata, BKE_pbvh_vertex_iter_end; } - /* Public functions. */ /* Main Brush Function. */ @@ -400,9 +398,9 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, } void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr, - SculptSession *ss, - const float outline_col[3], - const float outline_alpha) + SculptSession *ss, + const float outline_col[3], + const float outline_alpha) { float local_mat_inv[4][4]; invert_m4_m4(local_mat_inv, ss->cache->stroke_local_mat); diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c index 7e32c3d2b5f..ee1496c96bb 100644 --- a/source/blender/editors/space_console/console_draw.c +++ b/source/blender/editors/space_console/console_draw.c @@ -38,14 +38,14 @@ #include "../space_info/textview.h" -static int console_line_data(struct TextViewContext *tvc, - uchar fg[4], - uchar UNUSED(bg[4]), - int *UNUSED(icon), - uchar UNUSED(icon_fg[4]), - uchar UNUSED(icon_bg[4])) +static enum eTextViewContext_LineFlag console_line_data(TextViewContext *tvc, + uchar fg[4], + uchar UNUSED(bg[4]), + int *UNUSED(icon), + uchar UNUSED(icon_fg[4]), + uchar UNUSED(icon_bg[4])) { - ConsoleLine *cl_iter = (ConsoleLine *)tvc->iter; + const ConsoleLine *cl_iter = tvc->iter; int fg_id = TH_TEXT; switch (cl_iter->type) { @@ -67,7 +67,7 @@ static int console_line_data(struct TextViewContext *tvc, return TVC_LINE_FG; } -void console_scrollback_prompt_begin(struct SpaceConsole *sc, ConsoleLine *cl_dummy) +void console_scrollback_prompt_begin(SpaceConsole *sc, ConsoleLine *cl_dummy) { /* fake the edit line being in the scroll buffer */ ConsoleLine *cl = sc->history.last; @@ -81,7 +81,7 @@ void console_scrollback_prompt_begin(struct SpaceConsole *sc, ConsoleLine *cl_du memcpy(cl_dummy->line + prompt_len, cl->line, cl->len + 1); BLI_addtail(&sc->scrollback, cl_dummy); } -void console_scrollback_prompt_end(struct SpaceConsole *sc, ConsoleLine *cl_dummy) +void console_scrollback_prompt_end(SpaceConsole *sc, ConsoleLine *cl_dummy) { MEM_freeN(cl_dummy->line); BLI_remlink(&sc->scrollback, cl_dummy); @@ -112,14 +112,13 @@ static int console_textview_step(TextViewContext *tvc) return ((tvc->iter = (void *)((Link *)tvc->iter)->prev) != NULL); } -static int console_textview_line_get(struct TextViewContext *tvc, const char **line, int *len) +static void console_textview_line_get(TextViewContext *tvc, const char **r_line, int *r_len) { - ConsoleLine *cl = (ConsoleLine *)tvc->iter; - *line = cl->line; - *len = cl->len; + const ConsoleLine *cl = tvc->iter; + *r_line = cl->line; + *r_len = cl->len; // printf("'%s' %d\n", *line, cl->len); BLI_assert(cl->line[cl->len] == '\0' && (cl->len == 0 || cl->line[cl->len - 1] != '\0')); - return 1; } static void console_cursor_wrap_offset( @@ -144,7 +143,7 @@ static void console_cursor_wrap_offset( return; } -static void console_textview_draw_cursor(struct TextViewContext *tvc, +static void console_textview_draw_cursor(TextViewContext *tvc, int cwidth, int columns, int descender) @@ -201,7 +200,7 @@ static void console_textview_draw_rect_calc(const ARegion *region, r_draw_rect_outer->ymax = region->winy; } -static int console_textview_main__internal(struct SpaceConsole *sc, +static int console_textview_main__internal(SpaceConsole *sc, const ARegion *region, const bool do_draw, const int mval[2], @@ -243,19 +242,19 @@ static int console_textview_main__internal(struct SpaceConsole *sc, return ret; } -void console_textview_main(struct SpaceConsole *sc, const ARegion *region) +void console_textview_main(SpaceConsole *sc, const ARegion *region) { const int mval[2] = {INT_MAX, INT_MAX}; console_textview_main__internal(sc, region, true, mval, NULL, NULL); } -int console_textview_height(struct SpaceConsole *sc, const ARegion *region) +int console_textview_height(SpaceConsole *sc, const ARegion *region) { const int mval[2] = {INT_MAX, INT_MAX}; return console_textview_main__internal(sc, region, false, mval, NULL, NULL); } -int console_char_pick(struct SpaceConsole *sc, const ARegion *region, const int mval[2]) +int console_char_pick(SpaceConsole *sc, const ARegion *region, const int mval[2]) { int r_mval_pick_offset = 0; void *mval_pick_item = NULL; diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c index 4d5f59cdb7c..0a5ca81484c 100644 --- a/source/blender/editors/space_info/info_draw.c +++ b/source/blender/editors/space_info/info_draw.c @@ -39,14 +39,14 @@ #include "textview.h" #include "GPU_framebuffer.h" -static int report_line_data(struct TextViewContext *tvc, - uchar fg[4], - uchar bg[4], - int *icon, - uchar icon_fg[4], - uchar icon_bg[4]) +static enum eTextViewContext_LineFlag report_line_data(TextViewContext *tvc, + uchar fg[4], + uchar bg[4], + int *r_icon, + uchar r_icon_fg[4], + uchar r_icon_bg[4]) { - Report *report = (Report *)tvc->iter; + const Report *report = tvc->iter; /* Same text color no matter what type of report. */ UI_GetThemeColor4ubv((report->flag & SELECT) ? TH_INFO_SELECTED_TEXT : TH_TEXT, fg); @@ -64,35 +64,35 @@ static int report_line_data(struct TextViewContext *tvc, if (report->type & RPT_ERROR_ALL) { icon_fg_id = TH_INFO_ERROR_TEXT; icon_bg_id = TH_INFO_ERROR; - *icon = ICON_CANCEL; + *r_icon = ICON_CANCEL; } else if (report->type & RPT_WARNING_ALL) { icon_fg_id = TH_INFO_WARNING_TEXT; icon_bg_id = TH_INFO_WARNING; - *icon = ICON_ERROR; + *r_icon = ICON_ERROR; } else if (report->type & RPT_INFO_ALL) { icon_fg_id = TH_INFO_INFO_TEXT; icon_bg_id = TH_INFO_INFO; - *icon = ICON_INFO; + *r_icon = ICON_INFO; } else if (report->type & RPT_DEBUG_ALL) { icon_fg_id = TH_INFO_DEBUG_TEXT; icon_bg_id = TH_INFO_DEBUG; - *icon = ICON_SYSTEM; + *r_icon = ICON_SYSTEM; } else if (report->type & RPT_PROPERTY) { icon_fg_id = TH_INFO_PROPERTY_TEXT; icon_bg_id = TH_INFO_PROPERTY; - *icon = ICON_OPTIONS; + *r_icon = ICON_OPTIONS; } else if (report->type & RPT_OPERATOR) { icon_fg_id = TH_INFO_OPERATOR_TEXT; icon_bg_id = TH_INFO_OPERATOR; - *icon = ICON_CHECKMARK; + *r_icon = ICON_CHECKMARK; } else { - *icon = ICON_NONE; + *r_icon = ICON_NONE; } if (report->flag & SELECT) { @@ -100,9 +100,9 @@ static int report_line_data(struct TextViewContext *tvc, icon_bg_id = TH_INFO_SELECTED_TEXT; } - if (*icon != ICON_NONE) { - UI_GetThemeColor4ubv(icon_fg_id, icon_fg); - UI_GetThemeColor4ubv(icon_bg_id, icon_bg); + if (*r_icon != ICON_NONE) { + UI_GetThemeColor4ubv(icon_fg_id, r_icon_fg); + UI_GetThemeColor4ubv(icon_bg_id, r_icon_bg); return TVC_LINE_FG | TVC_LINE_BG | TVC_LINE_ICON | TVC_LINE_ICON_FG | TVC_LINE_ICON_BG; } else { @@ -113,7 +113,7 @@ static int report_line_data(struct TextViewContext *tvc, /* reports! */ static void report_textview_init__internal(TextViewContext *tvc) { - Report *report = (Report *)tvc->iter; + const Report *report = tvc->iter; const char *str = report->message; const char *next_str = strchr(str + tvc->iter_char, '\n'); @@ -127,9 +127,9 @@ static void report_textview_init__internal(TextViewContext *tvc) static int report_textview_skip__internal(TextViewContext *tvc) { - SpaceInfo *sinfo = (SpaceInfo *)tvc->arg1; + const SpaceInfo *sinfo = tvc->arg1; const int report_mask = info_report_mask(sinfo); - while (tvc->iter && (((Report *)tvc->iter)->type & report_mask) == 0) { + while (tvc->iter && (((const Report *)tvc->iter)->type & report_mask) == 0) { tvc->iter = (void *)((Link *)tvc->iter)->prev; } return (tvc->iter != NULL); @@ -137,7 +137,7 @@ static int report_textview_skip__internal(TextViewContext *tvc) static int report_textview_begin(TextViewContext *tvc) { - ReportList *reports = (ReportList *)tvc->arg2; + const ReportList *reports = tvc->arg2; tvc->lheight = 14 * UI_DPI_FAC; tvc->sel_start = 0; @@ -170,7 +170,7 @@ static void report_textview_end(TextViewContext *UNUSED(tvc)) static int report_textview_step(TextViewContext *tvc) { /* simple case, but no newline support */ - Report *report = (Report *)tvc->iter; + const Report *report = tvc->iter; if (report->len <= tvc->iter_char_next) { tvc->iter = (void *)((Link *)tvc->iter)->prev; @@ -195,12 +195,11 @@ static int report_textview_step(TextViewContext *tvc) } } -static int report_textview_line_get(struct TextViewContext *tvc, const char **line, int *len) +static void report_textview_line_get(TextViewContext *tvc, const char **r_line, int *r_len) { - Report *report = (Report *)tvc->iter; - *line = report->message + tvc->iter_char; - *len = tvc->iter_char_next - tvc->iter_char; - return 1; + const Report *report = tvc->iter; + *r_line = report->message + tvc->iter_char; + *r_len = tvc->iter_char_next - tvc->iter_char; } static void info_textview_draw_rect_calc(const ARegion *region, @@ -220,9 +219,9 @@ static void info_textview_draw_rect_calc(const ARegion *region, r_draw_rect_outer->ymax = region->winy; } -static int info_textview_main__internal(struct SpaceInfo *sinfo, +static int info_textview_main__internal(const SpaceInfo *sinfo, const ARegion *region, - ReportList *reports, + const ReportList *reports, const bool do_draw, const int mval[2], void **r_mval_pick_item, @@ -259,9 +258,9 @@ static int info_textview_main__internal(struct SpaceInfo *sinfo, return ret; } -void *info_text_pick(struct SpaceInfo *sinfo, +void *info_text_pick(const SpaceInfo *sinfo, const ARegion *region, - ReportList *reports, + const ReportList *reports, int mval_y) { void *mval_pick_item = NULL; @@ -271,13 +270,13 @@ void *info_text_pick(struct SpaceInfo *sinfo, return (void *)mval_pick_item; } -int info_textview_height(struct SpaceInfo *sinfo, const ARegion *region, ReportList *reports) +int info_textview_height(const SpaceInfo *sinfo, const ARegion *region, const ReportList *reports) { int mval[2] = {INT_MAX, INT_MAX}; return info_textview_main__internal(sinfo, region, reports, false, mval, NULL, NULL); } -void info_textview_main(struct SpaceInfo *sinfo, const ARegion *region, ReportList *reports) +void info_textview_main(const SpaceInfo *sinfo, const ARegion *region, const ReportList *reports) { int mval[2] = {INT_MAX, INT_MAX}; info_textview_main__internal(sinfo, region, reports, true, mval, NULL, NULL); diff --git a/source/blender/editors/space_info/info_intern.h b/source/blender/editors/space_info/info_intern.h index 443a1659690..79bfb1fa047 100644 --- a/source/blender/editors/space_info/info_intern.h +++ b/source/blender/editors/space_info/info_intern.h @@ -45,19 +45,19 @@ void FILE_OT_find_missing_files(struct wmOperatorType *ot); void INFO_OT_reports_display_update(struct wmOperatorType *ot); /* info_draw.c */ -void *info_text_pick(struct SpaceInfo *sinfo, +void *info_text_pick(const struct SpaceInfo *sinfo, const struct ARegion *region, - ReportList *reports, + const struct ReportList *reports, int mouse_y); -int info_textview_height(struct SpaceInfo *sinfo, +int info_textview_height(const struct SpaceInfo *sinfo, const struct ARegion *region, - struct ReportList *reports); -void info_textview_main(struct SpaceInfo *sinfo, + const struct ReportList *reports); +void info_textview_main(const struct SpaceInfo *sinfo, const struct ARegion *region, - struct ReportList *reports); + const struct ReportList *reports); /* info_report.c */ -int info_report_mask(struct SpaceInfo *sinfo); +int info_report_mask(const struct SpaceInfo *sinfo); void INFO_OT_select_pick(struct wmOperatorType *ot); /* report selection */ void INFO_OT_select_all(struct wmOperatorType *ot); void INFO_OT_select_box(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c index 1b01ac95866..303e2bbaec9 100644 --- a/source/blender/editors/space_info/info_report.c +++ b/source/blender/editors/space_info/info_report.c @@ -72,7 +72,7 @@ static void reports_select_all(ReportList *reports, int report_mask, int action) } } -int info_report_mask(SpaceInfo *UNUSED(sinfo)) +int info_report_mask(const SpaceInfo *UNUSED(sinfo)) { #if 0 int report_mask = 0; diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h index a33ed91570d..54b7c477791 100644 --- a/source/blender/editors/space_info/textview.h +++ b/source/blender/editors/space_info/textview.h @@ -21,6 +21,14 @@ #ifndef __TEXTVIEW_H__ #define __TEXTVIEW_H__ +enum eTextViewContext_LineFlag { + TVC_LINE_FG = (1 << 0), + TVC_LINE_BG = (1 << 1), + TVC_LINE_ICON = (1 << 2), + TVC_LINE_ICON_FG = (1 << 3), + TVC_LINE_ICON_BG = (1 << 4) +}; + typedef struct TextViewContext { /** Font size scaled by the interface size. */ int lheight; @@ -40,22 +48,22 @@ typedef struct TextViewContext { /* callbacks */ int (*begin)(struct TextViewContext *tvc); void (*end)(struct TextViewContext *tvc); - void *arg1; - void *arg2; + const void *arg1; + const void *arg2; /* iterator */ int (*step)(struct TextViewContext *tvc); - int (*line_get)(struct TextViewContext *tvc, const char **, int *); - int (*line_data)(struct TextViewContext *tvc, - unsigned char fg[4], - unsigned char bg[4], - int *icon, - unsigned char icon_fg[4], - unsigned char icon_bg[4]); + void (*line_get)(struct TextViewContext *tvc, const char **r_line, int *r_len); + enum eTextViewContext_LineFlag (*line_data)(struct TextViewContext *tvc, + uchar fg[4], + uchar bg[4], + int *r_icon, + uchar r_icon_fg[4], + uchar r_icon_bg[4]); void (*draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns, int descender); /* constant theme colors */ void (*const_colors)(struct TextViewContext *tvc, unsigned char bg_sel[4]); - void *iter; + const void *iter; int iter_index; /** Char index, used for multi-line report display. */ int iter_char; @@ -72,12 +80,4 @@ int textview_draw(struct TextViewContext *tvc, void **r_mval_pick_item, int *r_mval_pick_offset); -enum { - TVC_LINE_FG = (1 << 0), - TVC_LINE_BG = (1 << 1), - TVC_LINE_ICON = (1 << 2), - TVC_LINE_ICON_FG = (1 << 3), - TVC_LINE_ICON_BG = (1 << 4) -}; - #endif /* __TEXTVIEW_H__ */ diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index d3c7374e782..951c26b69e0 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -981,6 +981,7 @@ void ED_spacetype_node(void) art->listener = node_region_listener; art->cursor = node_cursor; art->event_cursor = true; + art->clip_gizmo_events_by_ui = true; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 8c884783913..8ec7d5a166b 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1422,7 +1422,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win), static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(sa)) { Scene *scene = CTX_data_scene(C); - LightCache *lcache = scene->eevee.light_cache; + LightCache *lcache = scene->eevee.light_cache_data; if (lcache && (lcache->flag & LIGHTCACHE_UPDATE_AUTO) != 0) { lcache->flag &= ~LIGHTCACHE_UPDATE_AUTO; diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index bd92193206f..bfbc9b6825b 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1987,7 +1987,7 @@ static bool ed_object_select_pick(bContext *C, is_obedit = (vc.obedit != NULL); if (object) { - /* signal for view3d_opengl_select to skip editmode objects */ + /* Signal for #view3d_opengl_select to skip edit-mode objects. */ vc.obedit = NULL; } @@ -2003,7 +2003,7 @@ static bool ed_object_select_pick(bContext *C, /* This block uses the control key to make the object selected * by its center point rather than its contents */ - /* in editmode do not activate */ + /* In edit-mode do not activate. */ if (obcenter) { /* note; shift+alt goes to group-flush-selecting */ @@ -2337,11 +2337,11 @@ static int view3d_select_exec(bContext *C, wmOperator *op) bool toggle = RNA_boolean_get(op->ptr, "toggle"); bool center = RNA_boolean_get(op->ptr, "center"); bool enumerate = RNA_boolean_get(op->ptr, "enumerate"); - /* only force object select for editmode to support vertex parenting, - * or paint-select to allow pose bone select with vert/face select */ + /* Only force object select for edit-mode to support vertex parenting, + * or paint-select to allow pose bone select with vert/face select. */ bool object = (RNA_boolean_get(op->ptr, "object") && (obedit || BKE_paint_select_elem_test(obact) || - /* so its possible to select bones in weightpaint mode (LMB select) */ + /* so its possible to select bones in weight-paint mode (LMB select) */ (obact && (obact->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(obact)))); @@ -2358,8 +2358,8 @@ static int view3d_select_exec(bContext *C, wmOperator *op) obact = NULL; /* ack, this is incorrect but to do this correctly we would need an - * alternative editmode/objectmode keymap, this copies the functionality - * from 2.4x where Ctrl+Select in editmode does object select only */ + * alternative edit-mode/object-mode keymap, this copies the functionality + * from 2.4x where Ctrl+Select in edit-mode does object select only. */ center = false; } @@ -2493,12 +2493,12 @@ void VIEW3D_OT_select(wmOperatorType *ot) "center", 0, "Center", - "Use the object center when selecting, in editmode used to extend object selection"); + "Use the object center when selecting, in edit-mode used to extend object selection"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean( ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (editmode only)"); + prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (edit-mode only)"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_int_vector(ot->srna, @@ -3286,7 +3286,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) } FOREACH_OBJECT_IN_MODE_END; } - else { /* no editmode, unified for bones and objects */ + else { /* No edit-mode, unified for bones and objects. */ if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) { /* XXX, this is not selection, could be it's own operator. */ changed_multi = ED_sculpt_mask_box_select( diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c index 17e69ff38b8..efd7879c8b2 100644 --- a/source/blender/editors/transform/transform_convert_gpencil.c +++ b/source/blender/editors/transform/transform_convert_gpencil.c @@ -228,10 +228,11 @@ void createTransGPencil(bContext *C, TransInfo *t) for (gpf = init_gpf; gpf; gpf = gpf->next) { if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { - /* if multiframe and falloff, recalculate and save value */ + /* If multi-frame and falloff, recalculate and save value. */ float falloff = 1.0f; /* by default no falloff */ if ((is_multiedit) && (use_multiframe_falloff)) { - /* Faloff depends on distance to active frame (relative to the overall frame range) */ + /* Falloff depends on distance to active frame + * (relative to the overall frame range). */ falloff = BKE_gpencil_multiframe_falloff_calc( gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff); } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index bb4d50fcf54..716df24f195 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1102,7 +1102,7 @@ static void recalcData_objects(TransInfo *t) if (motionpath_update) { /* Update motion paths once for all transformed objects. */ - ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CHANGED); + ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CURRENT_FRAME); } if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) { diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c index 752d482fae2..2f305989f82 100644 --- a/source/blender/editors/transform/transform_mode_mirror.c +++ b/source/blender/editors/transform/transform_mode_mirror.c @@ -50,11 +50,9 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) char str[UI_MAX_DRAW_STR]; copy_v3_v3(t->values_final, t->values); - /* - * OPTIMIZATION: - * This still recalcs transformation on mouse move - * while it should only recalc on constraint change - * */ + /* OPTIMIZATION: + * This still recalculates transformation on mouse move + * while it should only recalculate on constraint change. */ /* if an axis has been selected */ if (t->con.mode & CON_APPLY) { diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 5ed27d9a648..f521fa3c702 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -95,18 +95,6 @@ void GPU_create_smoke_velocity(struct FluidModifierData *mmd); /* Delayed free of OpenGL buffers by main thread */ void GPU_free_unused_buffers(struct Main *bmain); -/* utilities */ -typedef enum eGPUAttrMask { - GPU_DEPTH_BUFFER_BIT = (1 << 0), - GPU_ENABLE_BIT = (1 << 1), - GPU_SCISSOR_BIT = (1 << 2), - GPU_VIEWPORT_BIT = (1 << 3), - GPU_BLEND_BIT = (1 << 4), -} eGPUAttrMask; - -void gpuPushAttr(eGPUAttrMask mask); -void gpuPopAttr(void); - #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 245f7f47510..4ffe4a53a52 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -44,6 +44,7 @@ int GPU_max_ubo_size(void); float GPU_max_line_width(void); void GPU_get_dfdy_factors(float fac[2]); bool GPU_arb_base_instance_is_supported(void); +bool GPU_arb_texture_cube_map_array_is_supported(void); bool GPU_mip_render_workaround(void); bool GPU_depth_blitting_workaround(void); bool GPU_unused_fb_slot_workaround(void); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 37fe30bc96b..da00306bf9f 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -98,12 +98,9 @@ typedef enum eGPUBuiltin { GPU_LOC_TO_VIEW_MATRIX = (1 << 13), GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14), GPU_OBJECT_INFO = (1 << 15), - GPU_VOLUME_DENSITY = (1 << 16), - GPU_VOLUME_FLAME = (1 << 17), - GPU_VOLUME_TEMPERATURE = (1 << 18), - GPU_BARYCENTRIC_TEXCO = (1 << 19), - GPU_BARYCENTRIC_DIST = (1 << 20), - GPU_WORLD_NORMAL = (1 << 21), + GPU_BARYCENTRIC_TEXCO = (1 << 16), + GPU_BARYCENTRIC_DIST = (1 << 17), + GPU_WORLD_NORMAL = (1 << 18), } eGPUBuiltin; typedef enum eGPUMatFlag { @@ -145,6 +142,7 @@ GPUNodeLink *GPU_image(GPUMaterial *mat, struct Image *ima, struct ImageUser *iu GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser); GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser); GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *layer); +GPUNodeLink *GPU_volume_grid(GPUMaterial *mat, const char *name); GPUNodeLink *GPU_builtin(eGPUBuiltin builtin); bool GPU_link(GPUMaterial *mat, const char *name, ...); @@ -178,7 +176,8 @@ GPUMaterial *GPU_material_from_nodetree(struct Scene *scene, struct bNodeTree *ntree, struct ListBase *gpumaterials, const void *engine_type, - int options, + const int options, + const bool is_volume_shader, const char *vert_code, const char *geom_code, const char *frag_lib, @@ -191,7 +190,6 @@ void GPU_materials_free(struct Main *bmain); struct Scene *GPU_material_scene(GPUMaterial *material); struct GPUPass *GPU_material_get_pass(GPUMaterial *material); -struct ListBase *GPU_material_get_inputs(GPUMaterial *material); struct Material *GPU_material_get_material(GPUMaterial *material); eGPUMaterialStatus GPU_material_status(GPUMaterial *mat); @@ -199,8 +197,10 @@ struct GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material); void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs); struct GPUUniformBuffer *GPU_material_create_sss_profile_ubo(void); -bool GPU_material_use_domain_surface(GPUMaterial *mat); -bool GPU_material_use_domain_volume(GPUMaterial *mat); +bool GPU_material_has_surface_output(GPUMaterial *mat); +bool GPU_material_has_volume_output(GPUMaterial *mat); + +bool GPU_material_is_volume_shader(GPUMaterial *mat); void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag); bool GPU_material_flag_get(GPUMaterial *mat, eGPUMatFlag flag); @@ -230,8 +230,16 @@ typedef struct GPUMaterialTexture { int users; } GPUMaterialTexture; +typedef struct GPUMaterialVolumeGrid { + struct GPUMaterialVolumeGrid *next, *prev; + char *name; + char sampler_name[32]; /* Name of sampler in GLSL. */ + int users; +} GPUMaterialVolumeGrid; + ListBase GPU_material_attributes(GPUMaterial *material); ListBase GPU_material_textures(GPUMaterial *material); +ListBase GPU_material_volume_grids(GPUMaterial *material); #ifdef __cplusplus } diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h index 894ef22e963..9ce91d31d69 100644 --- a/source/blender/gpu/GPU_state.h +++ b/source/blender/gpu/GPU_state.h @@ -65,6 +65,18 @@ void GPU_finish(void); void GPU_logic_op_invert_set(bool enable); +/* Attribute push & pop. */ +typedef enum eGPUAttrMask { + GPU_DEPTH_BUFFER_BIT = (1 << 0), + GPU_ENABLE_BIT = (1 << 1), + GPU_SCISSOR_BIT = (1 << 2), + GPU_VIEWPORT_BIT = (1 << 3), + GPU_BLEND_BIT = (1 << 4), +} eGPUAttrMask; + +void gpuPushAttr(eGPUAttrMask mask); +void gpuPopAttr(void); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 50b7c23059d..892452a2738 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -162,6 +162,12 @@ GPUTexture *GPU_texture_create_nD(int w, int samples, const bool can_rescale, char err_out[256]); +GPUTexture *GPU_texture_cube_create(int w, + int d, + const void *pixels, + eGPUTextureFormat tex_format, + eGPUDataFormat gpu_data_format, + char err_out[256]); GPUTexture *GPU_texture_create_1d(int w, eGPUTextureFormat data_type, @@ -185,6 +191,9 @@ GPUTexture *GPU_texture_create_cube(int w, eGPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_cube_array( + int w, int d, eGPUTextureFormat data_type, const float *pixels, char err_out[256]); + GPUTexture *GPU_texture_create_from_vertbuf(struct GPUVertBuf *vert); GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat data_type, const uint buffer); @@ -238,6 +247,7 @@ void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat); void GPU_texture_filters(GPUTexture *tex, eGPUFilterFunction min_filter, eGPUFilterFunction mag_filter); +void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels); void GPU_texture_attach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb, int attachment); int GPU_texture_detach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb); @@ -251,6 +261,7 @@ void GPU_texture_orig_size_set(GPUTexture *tex, int w, int h); int GPU_texture_layers(const GPUTexture *tex); eGPUTextureFormat GPU_texture_format(const GPUTexture *tex); int GPU_texture_samples(const GPUTexture *tex); +bool GPU_texture_array(const GPUTexture *tex); bool GPU_texture_cube(const GPUTexture *tex); bool GPU_texture_depth(const GPUTexture *tex); bool GPU_texture_stencil(const GPUTexture *tex); diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 553ecb65529..bcaa95c2f59 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -269,15 +269,6 @@ static const char *gpu_builtin_name(eGPUBuiltin builtin) else if (builtin == GPU_OBJECT_INFO) { return "unfobjectinfo"; } - else if (builtin == GPU_VOLUME_DENSITY) { - return "sampdensity"; - } - else if (builtin == GPU_VOLUME_FLAME) { - return "sampflame"; - } - else if (builtin == GPU_VOLUME_TEMPERATURE) { - return "unftemperature"; - } else if (builtin == GPU_BARYCENTRIC_TEXCO) { return "unfbarycentrictex"; } @@ -341,6 +332,11 @@ static int codegen_process_uniforms_functions(GPUMaterial *material, } } + /* Volume Grids */ + for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first; grid; grid = grid->next) { + BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", grid->sampler_name); + } + /* Print other uniforms */ for (node = graph->nodes.first; node; node = node->next) { for (input = node->inputs.first; input; input = input->next) { @@ -350,12 +346,7 @@ static int codegen_process_uniforms_functions(GPUMaterial *material, builtins |= input->builtin; name = gpu_builtin_name(input->builtin); - if (BLI_str_startswith(name, "samp")) { - if ((input->builtin == GPU_VOLUME_DENSITY) || (input->builtin == GPU_VOLUME_FLAME)) { - BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", name); - } - } - else if (BLI_str_startswith(name, "unf")) { + if (BLI_str_startswith(name, "unf")) { BLI_dynstr_appendf(ds, "uniform %s %s;\n", gpu_data_type_to_string(input->type), name); } else { @@ -438,6 +429,9 @@ static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph, GPUOutput *f else if (input->source == GPU_SOURCE_TEX_TILED_MAPPING) { BLI_dynstr_append(ds, input->texture->tiled_mapping_name); } + else if (input->source == GPU_SOURCE_VOLUME_GRID) { + BLI_dynstr_append(ds, input->volume_grid->sampler_name); + } else if (input->source == GPU_SOURCE_OUTPUT) { codegen_convert_datatype( ds, input->link->output->type, input->type, "tmp", input->link->output->id); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index d674f8600c2..33bc3ced5b2 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -861,6 +861,7 @@ static void gpu_texture_update_from_ibuf( * available. It is also required when requesting the GPUTexture for a render result. */ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf, int textarget) { +#ifndef GPU_STANDALONE if (ima == NULL) { return NULL; } @@ -919,10 +920,13 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf, GPU_texture_orig_size_set(*tex, ibuf_intern->x, ibuf_intern->y); return *tex; +#endif + return NULL; } GPUTexture *GPU_texture_from_movieclip(MovieClip *clip, MovieClipUser *cuser, int textarget) { +#ifndef GPU_STANDALONE if (clip == NULL) { return NULL; } @@ -945,6 +949,9 @@ GPUTexture *GPU_texture_from_movieclip(MovieClip *clip, MovieClipUser *cuser, in *tex = GPU_texture_from_bindcode(textarget, bindcode); return *tex; +#else + return NULL; +#endif } void GPU_free_texture_movieclip(struct MovieClip *clip) @@ -1270,6 +1277,7 @@ void GPU_create_gl_tex_compressed(unsigned int *bind, int textarget, Image *ima, * re-uploaded to OpenGL */ void GPU_paint_set_mipmap(Main *bmain, bool mipmap) { +#ifndef GPU_STANDALONE if (!GTS.domipmap) { return; } @@ -1321,10 +1329,12 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap) } } } +#endif /* GPU_STANDALONE */ } void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h) { +#ifndef GPU_STANDALONE ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser); @@ -1346,6 +1356,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i } BKE_image_release_ibuf(ima, ibuf, NULL); +#endif } static LinkNode *image_free_queue = NULL; @@ -1526,177 +1537,3 @@ void GPU_state_init(void) glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); } } - -/** \name Framebuffer color depth, for selection codes - * \{ */ - -#define STATE_STACK_DEPTH 16 - -typedef struct { - eGPUAttrMask mask; - - /* GL_ENABLE_BIT */ - uint is_blend : 1; - uint is_cull_face : 1; - uint is_depth_test : 1; - uint is_dither : 1; - uint is_lighting : 1; - uint is_line_smooth : 1; - uint is_color_logic_op : 1; - uint is_multisample : 1; - uint is_polygon_offset_line : 1; - uint is_polygon_offset_fill : 1; - uint is_polygon_smooth : 1; - uint is_sample_alpha_to_coverage : 1; - uint is_scissor_test : 1; - uint is_stencil_test : 1; - - bool is_clip_plane[6]; - - /* GL_DEPTH_BUFFER_BIT */ - /* uint is_depth_test : 1; */ - int depth_func; - double depth_clear_value; - bool depth_write_mask; - - /* GL_SCISSOR_BIT */ - int scissor_box[4]; - /* uint is_scissor_test : 1; */ - - /* GL_VIEWPORT_BIT */ - int viewport[4]; - double near_far[2]; -} GPUAttrValues; - -typedef struct { - GPUAttrValues attr_stack[STATE_STACK_DEPTH]; - uint top; -} GPUAttrStack; - -static GPUAttrStack state = { - .top = 0, -}; - -#define AttrStack state -#define Attr state.attr_stack[state.top] - -/** - * Replacement for glPush/PopAttributes - * - * We don't need to cover all the options of legacy OpenGL - * but simply the ones used by Blender. - */ -void gpuPushAttr(eGPUAttrMask mask) -{ - Attr.mask = mask; - - if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { - Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); - glGetIntegerv(GL_DEPTH_FUNC, &Attr.depth_func); - glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Attr.depth_clear_value); - glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Attr.depth_write_mask); - } - - if ((mask & GPU_ENABLE_BIT) != 0) { - Attr.is_blend = glIsEnabled(GL_BLEND); - - for (int i = 0; i < 6; i++) { - Attr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i); - } - - Attr.is_cull_face = glIsEnabled(GL_CULL_FACE); - Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); - Attr.is_dither = glIsEnabled(GL_DITHER); - Attr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH); - Attr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP); - Attr.is_multisample = glIsEnabled(GL_MULTISAMPLE); - Attr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE); - Attr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL); - Attr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH); - Attr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE); - Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); - Attr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST); - } - - if ((mask & GPU_SCISSOR_BIT) != 0) { - Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); - glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Attr.scissor_box); - } - - if ((mask & GPU_VIEWPORT_BIT) != 0) { - glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Attr.near_far); - glGetIntegerv(GL_VIEWPORT, (GLint *)&Attr.viewport); - } - - if ((mask & GPU_BLEND_BIT) != 0) { - Attr.is_blend = glIsEnabled(GL_BLEND); - } - - BLI_assert(AttrStack.top < STATE_STACK_DEPTH); - AttrStack.top++; -} - -static void restore_mask(GLenum cap, const bool value) -{ - if (value) { - glEnable(cap); - } - else { - glDisable(cap); - } -} - -void gpuPopAttr(void) -{ - BLI_assert(AttrStack.top > 0); - AttrStack.top--; - - GLint mask = Attr.mask; - - if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { - restore_mask(GL_DEPTH_TEST, Attr.is_depth_test); - glDepthFunc(Attr.depth_func); - glClearDepth(Attr.depth_clear_value); - glDepthMask(Attr.depth_write_mask); - } - - if ((mask & GPU_ENABLE_BIT) != 0) { - restore_mask(GL_BLEND, Attr.is_blend); - - for (int i = 0; i < 6; i++) { - restore_mask(GL_CLIP_PLANE0 + i, Attr.is_clip_plane[i]); - } - - restore_mask(GL_CULL_FACE, Attr.is_cull_face); - restore_mask(GL_DEPTH_TEST, Attr.is_depth_test); - restore_mask(GL_DITHER, Attr.is_dither); - restore_mask(GL_LINE_SMOOTH, Attr.is_line_smooth); - restore_mask(GL_COLOR_LOGIC_OP, Attr.is_color_logic_op); - restore_mask(GL_MULTISAMPLE, Attr.is_multisample); - restore_mask(GL_POLYGON_OFFSET_LINE, Attr.is_polygon_offset_line); - restore_mask(GL_POLYGON_OFFSET_FILL, Attr.is_polygon_offset_fill); - restore_mask(GL_POLYGON_SMOOTH, Attr.is_polygon_smooth); - restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Attr.is_sample_alpha_to_coverage); - restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test); - restore_mask(GL_STENCIL_TEST, Attr.is_stencil_test); - } - - if ((mask & GPU_VIEWPORT_BIT) != 0) { - glViewport(Attr.viewport[0], Attr.viewport[1], Attr.viewport[2], Attr.viewport[3]); - glDepthRange(Attr.near_far[0], Attr.near_far[1]); - } - - if ((mask & GPU_SCISSOR_BIT) != 0) { - restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test); - glScissor(Attr.scissor_box[0], Attr.scissor_box[1], Attr.scissor_box[2], Attr.scissor_box[3]); - } - - if ((mask & GPU_BLEND_BIT) != 0) { - restore_mask(GL_BLEND, Attr.is_blend); - } -} - -#undef Attr -#undef AttrStack - -/** \} */ diff --git a/source/blender/gpu/intern/gpu_draw_smoke.c b/source/blender/gpu/intern/gpu_draw_smoke.c index 5cca472148a..546faadbda4 100644 --- a/source/blender/gpu/intern/gpu_draw_smoke.c +++ b/source/blender/gpu/intern/gpu_draw_smoke.c @@ -122,13 +122,12 @@ static GPUTexture *create_transfer_function(int type, const struct ColorBand *co return tex; } -static void swizzle_texture_channel_rrrr(GPUTexture *tex) +static void swizzle_texture_channel_single(GPUTexture *tex) { + /* Swizzle texture channels so that we get useful RGBA values when sampling + * a texture with fewer channels, e.g. when using density as color. */ GPU_texture_bind(tex, 0); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); + GPU_texture_swizzle_channel_auto(tex, 1); GPU_texture_unbind(tex); } @@ -186,60 +185,59 @@ static GPUTexture *create_field_texture(FluidDomainSettings *mds) GPUTexture *tex = GPU_texture_create_nD( mds->res[0], mds->res[1], mds->res[2], 3, field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); - swizzle_texture_channel_rrrr(tex); + swizzle_texture_channel_single(tex); return tex; } static GPUTexture *create_density_texture(FluidDomainSettings *mds, int highres) { - float *data = NULL, *source; - int cell_count = (highres) ? manta_smoke_turbulence_get_cells(mds->fluid) : mds->total_cells; + int *dim = (highres) ? mds->res_noise : mds->res; + + float *data; + if (highres) { + data = manta_smoke_turbulence_get_density(mds->fluid); + } + else { + data = manta_smoke_get_density(mds->fluid); + } + + GPUTexture *tex = GPU_texture_create_nD( + dim[0], dim[1], dim[2], 3, data, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); + + swizzle_texture_channel_single(tex); + + return tex; +} + +static GPUTexture *create_color_texture(FluidDomainSettings *mds, int highres) +{ const bool has_color = (highres) ? manta_smoke_turbulence_has_colors(mds->fluid) : manta_smoke_has_colors(mds->fluid); + + if (!has_color) { + return NULL; + } + + int cell_count = (highres) ? manta_smoke_turbulence_get_cells(mds->fluid) : mds->total_cells; int *dim = (highres) ? mds->res_noise : mds->res; - eGPUTextureFormat format = (has_color) ? GPU_RGBA8 : GPU_R8; + float *data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture"); - if (has_color) { - data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture"); + if (data == NULL) { + return NULL; } if (highres) { - if (has_color) { - manta_smoke_turbulence_get_rgba(mds->fluid, data, 0); - } - else { - source = manta_smoke_turbulence_get_density(mds->fluid); - } + manta_smoke_turbulence_get_rgba(mds->fluid, data, 0); } else { - if (has_color) { - manta_smoke_get_rgba(mds->fluid, data, 0); - } - else { - source = manta_smoke_get_density(mds->fluid); - } + manta_smoke_get_rgba(mds->fluid, data, 0); } - GPUTexture *tex = GPU_texture_create_nD(dim[0], - dim[1], - dim[2], - 3, - (has_color) ? data : source, - format, - GPU_DATA_FLOAT, - 0, - true, - NULL); - if (data) { - MEM_freeN(data); - } + GPUTexture *tex = GPU_texture_create_nD( + dim[0], dim[1], dim[2], 3, data, GPU_RGBA8, GPU_DATA_FLOAT, 0, true, NULL); + + MEM_freeN(data); - if (format == GPU_R8) { - /* Swizzle the RGBA components to read the Red channel so - * that the shader stay the same for colored and non color - * density textures. */ - swizzle_texture_channel_rrrr(tex); - } return tex; } @@ -264,7 +262,7 @@ static GPUTexture *create_flame_texture(FluidDomainSettings *mds, int highres) GPUTexture *tex = GPU_texture_create_nD( dim[0], dim[1], dim[2], 3, source, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); - swizzle_texture_channel_rrrr(tex); + swizzle_texture_channel_single(tex); return tex; } @@ -280,35 +278,40 @@ static GPUTexture *create_flame_texture(FluidDomainSettings *mds, int highres) void GPU_free_smoke(FluidModifierData *mmd) { if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) { - if (mmd->domain->tex) { - GPU_texture_free(mmd->domain->tex); + if (mmd->domain->tex_density) { + GPU_texture_free(mmd->domain->tex_density); + mmd->domain->tex_density = NULL; + } + + if (mmd->domain->tex_color) { + GPU_texture_free(mmd->domain->tex_color); + mmd->domain->tex_color = NULL; } - mmd->domain->tex = NULL; if (mmd->domain->tex_shadow) { GPU_texture_free(mmd->domain->tex_shadow); + mmd->domain->tex_shadow = NULL; } - mmd->domain->tex_shadow = NULL; if (mmd->domain->tex_flame) { GPU_texture_free(mmd->domain->tex_flame); + mmd->domain->tex_flame = NULL; } - mmd->domain->tex_flame = NULL; if (mmd->domain->tex_flame_coba) { GPU_texture_free(mmd->domain->tex_flame_coba); + mmd->domain->tex_flame_coba = NULL; } - mmd->domain->tex_flame_coba = NULL; if (mmd->domain->tex_coba) { GPU_texture_free(mmd->domain->tex_coba); + mmd->domain->tex_coba = NULL; } - mmd->domain->tex_coba = NULL; if (mmd->domain->tex_field) { GPU_texture_free(mmd->domain->tex_field); + mmd->domain->tex_field = NULL; } - mmd->domain->tex_field = NULL; } } @@ -338,8 +341,11 @@ void GPU_create_smoke(FluidModifierData *mmd, int highres) if (mmd->type & MOD_FLUID_TYPE_DOMAIN) { FluidDomainSettings *mds = mmd->domain; - if (!mds->tex) { - mds->tex = create_density_texture(mds, highres); + if (!mds->tex_density) { + mds->tex_density = create_density_texture(mds, highres); + } + if (!mds->tex_color) { + mds->tex_color = create_color_texture(mds, highres); } if (!mds->tex_flame) { mds->tex_flame = create_flame_texture(mds, highres); diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 4676cc3b244..f497ed22bec 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -78,6 +78,8 @@ static struct GPUGlobal { /* Some Intel drivers have limited support for `GLEW_ARB_base_instance` so in * these cases it is best to indicate that it is not supported. See T67951 */ bool glew_arb_base_instance_is_supported; + /* Cubemap Array support. */ + bool glew_arb_texture_cube_map_array_is_supported; /* Some Intel drivers have issues with using mips as framebuffer targets if * GL_TEXTURE_MAX_LEVEL is higher than the target mip. * We need a workaround in this cases. */ @@ -197,6 +199,11 @@ bool GPU_arb_base_instance_is_supported(void) return GG.glew_arb_base_instance_is_supported; } +bool GPU_arb_texture_cube_map_array_is_supported(void) +{ + return GG.glew_arb_texture_cube_map_array_is_supported; +} + bool GPU_mip_render_workaround(void) { return GG.mip_render_workaround; @@ -281,6 +288,7 @@ void gpu_extensions_init(void) } GG.glew_arb_base_instance_is_supported = GLEW_ARB_base_instance; + GG.glew_arb_texture_cube_map_array_is_supported = GLEW_ARB_texture_cube_map_array; gpu_detect_mip_render_workaround(); if (G.debug & G_DEBUG_GPU_FORCE_WORKAROUNDS) { @@ -348,7 +356,11 @@ void gpu_extensions_exit(void) bool GPU_mem_stats_supported(void) { +#ifndef GPU_STANDALONE return (GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo) && (G.debug & G_DEBUG_GPU_MEM); +#else + return false; +#endif } void GPU_mem_stats_get(int *totalmem, int *freemem) diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c index bd3de96d636..671335ca702 100644 --- a/source/blender/gpu/intern/gpu_immediate.c +++ b/source/blender/gpu/intern/gpu_immediate.c @@ -23,7 +23,9 @@ * GPU immediate mode work-alike */ -#include "UI_resources.h" +#ifndef GPU_STANDALONE +# include "UI_resources.h" +#endif #include "GPU_attr_binding.h" #include "GPU_immediate.h" @@ -910,6 +912,8 @@ void immUniformColor4ubv(const uchar rgba[4]) immUniformColor4ub(rgba[0], rgba[1], rgba[2], rgba[3]); } +#ifndef GPU_STANDALONE + void immUniformThemeColor(int color_id) { float color[4]; @@ -958,3 +962,5 @@ void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset) UI_GetThemeColorShadeAlpha4ubv(colorid, coloffset, alphaoffset, col); immUniformColor4ub(col[0], col[1], col[2], col[3]); } + +#endif /* GPU_STANDALONE */ diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index c99b7fc8a67..96dc437e10b 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -64,12 +64,16 @@ void GPU_init(void) immInit(); } +#ifndef GPU_STANDALONE gpu_pbvh_init(); +#endif } void GPU_exit(void) { +#ifndef GPU_STANDALONE gpu_pbvh_exit(); +#endif if (!G.background) { immDestroy(); diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index b2658839d67..8a4a88d0663 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -70,6 +70,7 @@ struct GPUMaterial { const void *engine_type; /* attached engine type */ int options; /* to identify shader variations (shadow, probe, world background...) */ + bool is_volume_shader; /* is volumetric shader */ /* Nodes */ GPUNodeGraph graph; @@ -80,7 +81,8 @@ struct GPUMaterial { /* XXX: Should be in Material. But it depends on the output node * used and since the output selection is different for GPUMaterial... */ - int domain; + bool has_volume_output; + bool has_surface_output; /* Only used by Eevee to know which bsdf are used. */ int flag; @@ -109,8 +111,8 @@ struct GPUMaterial { }; enum { - GPU_DOMAIN_SURFACE = (1 << 0), - GPU_DOMAIN_VOLUME = (1 << 1), + GPU_USE_SURFACE_OUTPUT = (1 << 0), + GPU_USE_VOLUME_OUTPUT = (1 << 1), }; /* Functions */ @@ -567,6 +569,11 @@ ListBase GPU_material_textures(GPUMaterial *material) return material->graph.textures; } +ListBase GPU_material_volume_grids(GPUMaterial *material) +{ + return material->graph.volume_grids; +} + void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link) { if (!material->graph.outlink) { @@ -592,14 +599,19 @@ eGPUMaterialStatus GPU_material_status(GPUMaterial *mat) /* Code generation */ -bool GPU_material_use_domain_surface(GPUMaterial *mat) +bool GPU_material_has_surface_output(GPUMaterial *mat) +{ + return mat->has_surface_output; +} + +bool GPU_material_has_volume_output(GPUMaterial *mat) { - return (mat->domain & GPU_DOMAIN_SURFACE); + return mat->has_volume_output; } -bool GPU_material_use_domain_volume(GPUMaterial *mat) +bool GPU_material_is_volume_shader(GPUMaterial *mat) { - return (mat->domain & GPU_DOMAIN_VOLUME); + return mat->is_volume_shader; } void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag) @@ -636,7 +648,8 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, - int options, + const int options, + const bool is_volume_shader, const char *vert_code, const char *geom_code, const char *frag_lib, @@ -655,6 +668,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, mat->scene = scene; mat->engine_type = engine_type; mat->options = options; + mat->is_volume_shader = is_volume_shader; #ifndef NDEBUG BLI_snprintf(mat->name, sizeof(mat->name), "%s", name); #else @@ -670,8 +684,8 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, gpu_material_ramp_texture_build(mat); - SET_FLAG_FROM_TEST(mat->domain, has_surface_output, GPU_DOMAIN_SURFACE); - SET_FLAG_FROM_TEST(mat->domain, has_volume_output, GPU_DOMAIN_VOLUME); + mat->has_surface_output = has_surface_output; + mat->has_volume_output = has_volume_output; if (mat->graph.outlink) { /* HACK: this is only for eevee. We add the define here after the nodetree evaluation. */ diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index de35b43109f..0d5cc46c0b9 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -119,6 +119,10 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType input->source = GPU_SOURCE_TEX_TILED_MAPPING; input->texture = link->texture; break; + case GPU_NODE_LINK_VOLUME_GRID: + input->source = GPU_SOURCE_VOLUME_GRID; + input->volume_grid = link->volume_grid; + break; case GPU_NODE_LINK_ATTR: input->source = GPU_SOURCE_ATTR; input->attr = link->attr; @@ -321,6 +325,31 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, return tex; } +static GPUMaterialVolumeGrid *gpu_node_graph_add_volume_grid(GPUNodeGraph *graph, const char *name) +{ + /* Find existing volume grid. */ + int num_grids = 0; + GPUMaterialVolumeGrid *grid = graph->volume_grids.first; + for (; grid; grid = grid->next) { + if (STREQ(grid->name, name)) { + break; + } + num_grids++; + } + + /* Add new requested volume grid. */ + if (grid == NULL) { + grid = MEM_callocN(sizeof(*grid), __func__); + grid->name = BLI_strdup(name); + BLI_snprintf(grid->sampler_name, sizeof(grid->sampler_name), "vsamp%d", num_grids); + BLI_addtail(&graph->volume_grids, grid); + } + + grid->users++; + + return grid; +} + /* Creating Inputs */ GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const char *name) @@ -394,6 +423,30 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *ro return link; } +GPUNodeLink *GPU_volume_grid(GPUMaterial *mat, const char *name) +{ + /* NOTE: this could be optimized by automatically merging duplicate + * lookups of the same attribute. */ + GPUNodeGraph *graph = gpu_material_node_graph(mat); + GPUNodeLink *link = gpu_node_link_create(); + link->link_type = GPU_NODE_LINK_VOLUME_GRID; + link->volume_grid = gpu_node_graph_add_volume_grid(graph, name); + + /* Two special cases, where we adjust the output values of smoke grids to + * bring the into standard range without having to modify the grid values. */ + if (strcmp(name, "color") == 0) { + GPU_link(mat, "node_attribute_volume_color", link, &link); + } + else if (strcmp(name, "temperature") == 0) { + GPU_link(mat, "node_attribute_volume_temperature", link, &link); + } + else { + GPU_link(mat, "node_attribute_volume", link, &link); + } + + return link; +} + GPUNodeLink *GPU_builtin(eGPUBuiltin builtin) { GPUNodeLink *link = gpu_node_link_create(); @@ -537,6 +590,9 @@ static void gpu_inputs_free(ListBase *inputs) else if (ELEM(input->source, GPU_SOURCE_TEX, GPU_SOURCE_TEX_TILED_MAPPING)) { input->texture->users--; } + else if (ELEM(input->source, GPU_SOURCE_VOLUME_GRID)) { + input->volume_grid->users--; + } if (input->link) { gpu_node_link_free(input->link); @@ -579,6 +635,11 @@ void gpu_node_graph_free_nodes(GPUNodeGraph *graph) void gpu_node_graph_free(GPUNodeGraph *graph) { gpu_node_graph_free_nodes(graph); + + for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first; grid; grid = grid->next) { + MEM_SAFE_FREE(grid->name); + } + BLI_freelistN(&graph->volume_grids); BLI_freelistN(&graph->textures); BLI_freelistN(&graph->attributes); } @@ -637,4 +698,12 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph) BLI_freelinkN(&graph->textures, tex); } } + + for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first, *next = NULL; grid; grid = next) { + next = grid->next; + if (grid->users == 0) { + MEM_SAFE_FREE(grid->name); + BLI_freelinkN(&graph->volume_grids, grid); + } + } } diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h index 9214bd7f1ba..ceaeea2bfa8 100644 --- a/source/blender/gpu/intern/gpu_node_graph.h +++ b/source/blender/gpu/intern/gpu_node_graph.h @@ -48,6 +48,8 @@ typedef enum eGPUDataSource { GPU_SOURCE_STRUCT, GPU_SOURCE_TEX, GPU_SOURCE_TEX_TILED_MAPPING, + GPU_SOURCE_VOLUME_GRID, + GPU_SOURCE_VOLUME_GRID_TRANSFORM, } eGPUDataSource; typedef enum { @@ -59,6 +61,7 @@ typedef enum { GPU_NODE_LINK_IMAGE, GPU_NODE_LINK_IMAGE_TILED, GPU_NODE_LINK_IMAGE_TILED_MAPPING, + GPU_NODE_LINK_VOLUME_GRID, GPU_NODE_LINK_OUTPUT, GPU_NODE_LINK_UNIFORM, } GPUNodeLinkType; @@ -88,6 +91,8 @@ struct GPUNodeLink { eGPUBuiltin builtin; /* GPU_NODE_LINK_COLORBAND */ struct GPUTexture **colorband; + /* GPU_NODE_LINK_VOLUME_GRID */ + struct GPUMaterialVolumeGrid *volume_grid; /* GPU_NODE_LINK_OUTPUT */ struct GPUOutput *output; /* GPU_NODE_LINK_ATTR */ @@ -126,6 +131,8 @@ typedef struct GPUInput { struct GPUMaterialTexture *texture; /* GPU_SOURCE_ATTR */ struct GPUMaterialAttribute *attr; + /* GPU_SOURCE_VOLUME_GRID */ + struct GPUMaterialVolumeGrid *volume_grid; }; } GPUInput; @@ -139,6 +146,7 @@ typedef struct GPUNodeGraph { /* Requested attributes and textures. */ ListBase attributes; ListBase textures; + ListBase volume_grids; } GPUNodeGraph; /* Node Graph */ diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c index 1fb83b628e1..498de13e10f 100644 --- a/source/blender/gpu/intern/gpu_select_pick.c +++ b/source/blender/gpu/intern/gpu_select_pick.c @@ -30,6 +30,7 @@ #include "GPU_immediate.h" #include "GPU_draw.h" #include "GPU_select.h" +#include "GPU_state.h" #include "GPU_glew.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c index 6e8b062cff0..578546f3af9 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.c +++ b/source/blender/gpu/intern/gpu_select_sample_query.c @@ -26,9 +26,8 @@ #include <stdlib.h> -#include "GPU_immediate.h" -#include "GPU_draw.h" #include "GPU_select.h" +#include "GPU_state.h" #include "GPU_glew.h" #include "MEM_guardedalloc.h" @@ -37,10 +36,6 @@ #include "BLI_utildefines.h" -#include "PIL_time.h" - -#include "BKE_global.h" - #include "gpu_select_private.h" /* Ad hoc number of queries to allocate to skip doing many glGenQueries */ diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index c950a1daaa5..0993d69e14d 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -46,7 +46,7 @@ /* Adjust these constants as needed. */ #define MAX_DEFINE_LENGTH 256 -#define MAX_EXT_DEFINE_LENGTH 256 +#define MAX_EXT_DEFINE_LENGTH 512 /* Non-generated shaders */ extern char datatoc_gpu_shader_depth_only_frag_glsl[]; @@ -235,6 +235,10 @@ static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH]) if (GLEW_ARB_shader_draw_parameters) { strcat(defines, "#extension GL_ARB_shader_draw_parameters : enable\n"); } + if (GPU_arb_texture_cube_map_array_is_supported()) { + strcat(defines, "#extension GL_ARB_texture_cube_map_array : enable\n"); + strcat(defines, "#define GPU_ARB_texture_cube_map_array\n"); + } } static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH]) diff --git a/source/blender/gpu/intern/gpu_state.c b/source/blender/gpu/intern/gpu_state.c index caf97a620ab..9ff518aec1b 100644 --- a/source/blender/gpu/intern/gpu_state.c +++ b/source/blender/gpu/intern/gpu_state.c @@ -18,7 +18,12 @@ * \ingroup gpu */ -#include "DNA_userdef_types.h" +#ifndef GPU_STANDALONE +# include "DNA_userdef_types.h" +# define PIXELSIZE (U.pixelsize) +#else +# define PIXELSIZE (1.0f) +#endif #include "BLI_utildefines.h" @@ -107,7 +112,7 @@ void GPU_line_smooth(bool enable) void GPU_line_width(float width) { float max_size = GPU_max_line_width(); - float final_size = width * U.pixelsize; + float final_size = width * PIXELSIZE; /* Fix opengl errors on certain platform / drivers. */ CLAMP(final_size, 1.0f, max_size); glLineWidth(final_size); @@ -115,7 +120,7 @@ void GPU_line_width(float width) void GPU_point_size(float size) { - glPointSize(size * U.pixelsize); + glPointSize(size * PIXELSIZE); } void GPU_polygon_smooth(bool enable) @@ -189,3 +194,177 @@ void GPU_logic_op_invert_set(bool enable) glEnable(GL_DITHER); } } + +/** \name GPU Push/Pop State + * \{ */ + +#define STATE_STACK_DEPTH 16 + +typedef struct { + eGPUAttrMask mask; + + /* GL_ENABLE_BIT */ + uint is_blend : 1; + uint is_cull_face : 1; + uint is_depth_test : 1; + uint is_dither : 1; + uint is_lighting : 1; + uint is_line_smooth : 1; + uint is_color_logic_op : 1; + uint is_multisample : 1; + uint is_polygon_offset_line : 1; + uint is_polygon_offset_fill : 1; + uint is_polygon_smooth : 1; + uint is_sample_alpha_to_coverage : 1; + uint is_scissor_test : 1; + uint is_stencil_test : 1; + + bool is_clip_plane[6]; + + /* GL_DEPTH_BUFFER_BIT */ + /* uint is_depth_test : 1; */ + int depth_func; + double depth_clear_value; + bool depth_write_mask; + + /* GL_SCISSOR_BIT */ + int scissor_box[4]; + /* uint is_scissor_test : 1; */ + + /* GL_VIEWPORT_BIT */ + int viewport[4]; + double near_far[2]; +} GPUAttrValues; + +typedef struct { + GPUAttrValues attr_stack[STATE_STACK_DEPTH]; + uint top; +} GPUAttrStack; + +static GPUAttrStack state = { + .top = 0, +}; + +#define AttrStack state +#define Attr state.attr_stack[state.top] + +/** + * Replacement for glPush/PopAttributes + * + * We don't need to cover all the options of legacy OpenGL + * but simply the ones used by Blender. + */ +void gpuPushAttr(eGPUAttrMask mask) +{ + Attr.mask = mask; + + if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { + Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); + glGetIntegerv(GL_DEPTH_FUNC, &Attr.depth_func); + glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Attr.depth_clear_value); + glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Attr.depth_write_mask); + } + + if ((mask & GPU_ENABLE_BIT) != 0) { + Attr.is_blend = glIsEnabled(GL_BLEND); + + for (int i = 0; i < 6; i++) { + Attr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i); + } + + Attr.is_cull_face = glIsEnabled(GL_CULL_FACE); + Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); + Attr.is_dither = glIsEnabled(GL_DITHER); + Attr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH); + Attr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP); + Attr.is_multisample = glIsEnabled(GL_MULTISAMPLE); + Attr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE); + Attr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL); + Attr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH); + Attr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE); + Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + Attr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST); + } + + if ((mask & GPU_SCISSOR_BIT) != 0) { + Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Attr.scissor_box); + } + + if ((mask & GPU_VIEWPORT_BIT) != 0) { + glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Attr.near_far); + glGetIntegerv(GL_VIEWPORT, (GLint *)&Attr.viewport); + } + + if ((mask & GPU_BLEND_BIT) != 0) { + Attr.is_blend = glIsEnabled(GL_BLEND); + } + + BLI_assert(AttrStack.top < STATE_STACK_DEPTH); + AttrStack.top++; +} + +static void restore_mask(GLenum cap, const bool value) +{ + if (value) { + glEnable(cap); + } + else { + glDisable(cap); + } +} + +void gpuPopAttr(void) +{ + BLI_assert(AttrStack.top > 0); + AttrStack.top--; + + GLint mask = Attr.mask; + + if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { + restore_mask(GL_DEPTH_TEST, Attr.is_depth_test); + glDepthFunc(Attr.depth_func); + glClearDepth(Attr.depth_clear_value); + glDepthMask(Attr.depth_write_mask); + } + + if ((mask & GPU_ENABLE_BIT) != 0) { + restore_mask(GL_BLEND, Attr.is_blend); + + for (int i = 0; i < 6; i++) { + restore_mask(GL_CLIP_PLANE0 + i, Attr.is_clip_plane[i]); + } + + restore_mask(GL_CULL_FACE, Attr.is_cull_face); + restore_mask(GL_DEPTH_TEST, Attr.is_depth_test); + restore_mask(GL_DITHER, Attr.is_dither); + restore_mask(GL_LINE_SMOOTH, Attr.is_line_smooth); + restore_mask(GL_COLOR_LOGIC_OP, Attr.is_color_logic_op); + restore_mask(GL_MULTISAMPLE, Attr.is_multisample); + restore_mask(GL_POLYGON_OFFSET_LINE, Attr.is_polygon_offset_line); + restore_mask(GL_POLYGON_OFFSET_FILL, Attr.is_polygon_offset_fill); + restore_mask(GL_POLYGON_SMOOTH, Attr.is_polygon_smooth); + restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Attr.is_sample_alpha_to_coverage); + restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test); + restore_mask(GL_STENCIL_TEST, Attr.is_stencil_test); + } + + if ((mask & GPU_VIEWPORT_BIT) != 0) { + glViewport(Attr.viewport[0], Attr.viewport[1], Attr.viewport[2], Attr.viewport[3]); + glDepthRange(Attr.near_far[0], Attr.near_far[1]); + } + + if ((mask & GPU_SCISSOR_BIT) != 0) { + restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test); + glScissor(Attr.scissor_box[0], Attr.scissor_box[1], Attr.scissor_box[2], Attr.scissor_box[3]); + } + + if ((mask & GPU_BLEND_BIT) != 0) { + restore_mask(GL_BLEND, Attr.is_blend); + } +} + +#undef Attr +#undef AttrStack + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 9ef42592b55..7b51b03096f 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -109,7 +109,7 @@ static uint gpu_texture_memory_footprint_compute(GPUTexture *tex) return tex->bytesize * tex->w * tex->h * tex->d * samp; case GL_TEXTURE_CUBE_MAP: return tex->bytesize * 6 * tex->w * tex->h * samp; - case GL_TEXTURE_CUBE_MAP_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY_ARB: return tex->bytesize * 6 * tex->w * tex->h * tex->d * samp; default: return 0; @@ -138,6 +138,7 @@ static const char *gl_enum_to_str(GLenum e) #define ENUM_TO_STRING(e) [GL_##e] = STRINGIFY_ARG(e) static const char *enum_strings[] = { ENUM_TO_STRING(TEXTURE_CUBE_MAP), + ENUM_TO_STRING(TEXTURE_CUBE_MAP_ARRAY), ENUM_TO_STRING(TEXTURE_2D), ENUM_TO_STRING(TEXTURE_2D_ARRAY), ENUM_TO_STRING(TEXTURE_1D), @@ -202,6 +203,25 @@ static int gpu_get_component_count(eGPUTextureFormat format) } } +static uint gpu_get_data_format_bytesize(int comp, eGPUDataFormat data_format) +{ + switch (data_format) { + case GPU_DATA_FLOAT: + return sizeof(float) * comp; + case GPU_DATA_INT: + case GPU_DATA_UNSIGNED_INT: + return sizeof(int) * comp; + case GPU_DATA_UNSIGNED_INT_24_8: + case GPU_DATA_10_11_11_REV: + return sizeof(int); + case GPU_DATA_UNSIGNED_BYTE: + return sizeof(char) * comp; + default: + BLI_assert(0); + return 0; + } +} + /* Definitely not complete, edit according to the gl specification. */ static void gpu_validate_data_format(eGPUTextureFormat tex_format, eGPUDataFormat data_format) { @@ -679,6 +699,7 @@ GPUTexture *GPU_texture_create_nD(int w, } else { tex->target_base = tex->target = GL_TEXTURE_2D_ARRAY; + tex->format_flag |= GPU_FORMAT_ARRAY; } } else if (n == 1) { @@ -687,6 +708,7 @@ GPUTexture *GPU_texture_create_nD(int w, } else { tex->target_base = tex->target = GL_TEXTURE_1D_ARRAY; + tex->format_flag |= GPU_FORMAT_ARRAY; } } else if (n == 3) { @@ -839,17 +861,12 @@ GPUTexture *GPU_texture_create_nD(int w, return tex; } -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, - eGPUTextureFormat tex_format, - eGPUDataFormat gpu_data_format, - char err_out[256]) +GPUTexture *GPU_texture_cube_create(int w, + int d, + const void *pixels, + eGPUTextureFormat tex_format, + eGPUDataFormat gpu_data_format, + char err_out[256]) { GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->w = w; @@ -867,8 +884,21 @@ static GPUTexture *GPU_texture_cube_create(int w, tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP; } else { - BLI_assert(false && "Cubemap array Not implemented yet"); - // tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY; + tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY_ARB; + tex->format_flag |= GPU_FORMAT_ARRAY; + + if (!GPU_arb_texture_cube_map_array_is_supported()) { + fprintf(stderr, "ERROR: Attempt to create a cubemap array without hardware support!\n"); + BLI_assert(0); + GPU_texture_free(tex); + return NULL; + } + + if (d > GPU_max_texture_layers() / 6) { + BLI_assert(0); + GPU_texture_free(tex); + return NULL; + } } GLenum internalformat = gpu_get_gl_internalformat(tex_format); @@ -905,60 +935,42 @@ static GPUTexture *GPU_texture_cube_create(int w, glBindTexture(tex->target, tex->bindcode); /* Upload Texture */ - 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); + if (d == 0) { + const char *pixels_px, *pixels_py, *pixels_pz, *pixels_nx, *pixels_ny, *pixels_nz; + + if (pixels) { + size_t face_ofs = w * w * gpu_get_data_format_bytesize(tex->components, gpu_data_format); + pixels_px = (char *)pixels + 0 * face_ofs; + pixels_nx = (char *)pixels + 1 * face_ofs; + pixels_py = (char *)pixels + 2 * face_ofs; + pixels_ny = (char *)pixels + 3 * face_ofs; + pixels_pz = (char *)pixels + 4 * face_ofs; + pixels_nz = (char *)pixels + 5 * face_ofs; + } + else { + pixels_px = pixels_py = pixels_pz = pixels_nx = pixels_ny = pixels_nz = NULL; + } + + GLuint face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_px); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_nx); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_py); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_ny); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_pz); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_nz); + } + else { + glTexImage3D(tex->target, + 0, + internalformat, + tex->w, + tex->h, + tex->d * 6, + 0, + data_format, + data_type, + pixels); + } /* Texture Parameters */ if (GPU_texture_stencil(tex) || /* Does not support filtering */ @@ -1131,33 +1143,16 @@ GPUTexture *GPU_texture_create_cube(int w, char err_out[256]) { BLI_assert(w > 0); - const float *fpixels_px, *fpixels_py, *fpixels_pz, *fpixels_nx, *fpixels_ny, *fpixels_nz; - const int channels = gpu_get_component_count(tex_format); - - if (fpixels) { - int face_ofs = w * w * channels; - fpixels_px = fpixels + 0 * face_ofs; - fpixels_nx = fpixels + 1 * face_ofs; - fpixels_py = fpixels + 2 * face_ofs; - fpixels_ny = fpixels + 3 * face_ofs; - fpixels_pz = fpixels + 4 * face_ofs; - fpixels_nz = fpixels + 5 * face_ofs; - } - else { - fpixels_px = fpixels_py = fpixels_pz = fpixels_nx = fpixels_ny = fpixels_nz = NULL; - } + eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format); + return GPU_texture_cube_create(w, 0, fpixels, tex_format, data_format, err_out); +} - return GPU_texture_cube_create(w, - 0, - fpixels_px, - fpixels_py, - fpixels_pz, - fpixels_nx, - fpixels_ny, - fpixels_nz, - tex_format, - GPU_DATA_FLOAT, - err_out); +GPUTexture *GPU_texture_create_cube_array( + int w, int d, eGPUTextureFormat tex_format, const float *fpixels, char err_out[256]) +{ + BLI_assert(w > 0 && d > 0); + eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format); + return GPU_texture_cube_create(w, d, fpixels, tex_format, data_format, err_out); } GPUTexture *GPU_texture_create_from_vertbuf(GPUVertBuf *vert) @@ -1297,6 +1292,7 @@ void GPU_texture_add_mipmap(GPUTexture *tex, break; case GL_TEXTURE_3D: case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY_ARB: glTexImage3D(tex->target, miplvl, internalformat, @@ -1385,29 +1381,13 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl 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]); - samples_count *= (GPU_texture_cube(tex)) ? 6 : 1; + samples_count *= (GPU_texture_cube(tex) && !GPU_texture_array(tex)) ? 6 : 1; - 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; - } + size_t buf_size = samples_count * gpu_get_data_format_bytesize(tex->components, gpu_data_format); /* AMD Pro driver have a bug that write 8 bytes past buffer size * if the texture is big. (see T66573) */ @@ -1418,7 +1398,7 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl glBindTexture(tex->target, tex->bindcode); - if (GPU_texture_cube(tex)) { + if (GPU_texture_cube(tex) && !GPU_texture_array(tex)) { int cube_face_size = buf_size / 6; for (int i = 0; i < 6; i++) { glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, @@ -1648,6 +1628,17 @@ void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat) } } +void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels) +{ + WARN_NOT_BOUND(tex); + + glActiveTexture(GL_TEXTURE0 + tex->number); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, (channels >= 2) ? GL_GREEN : GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, (channels >= 3) ? GL_BLUE : GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, (channels >= 4) ? GL_ALPHA : GL_ONE); +} + static GLenum gpu_get_gl_filterfunction(eGPUFilterFunction filter) { switch (filter) { @@ -1752,6 +1743,11 @@ int GPU_texture_samples(const GPUTexture *tex) return tex->samples; } +bool GPU_texture_array(const GPUTexture *tex) +{ + return (tex->format_flag & GPU_FORMAT_ARRAY) != 0; +} + bool GPU_texture_depth(const GPUTexture *tex) { return (tex->format_flag & GPU_FORMAT_DEPTH) != 0; @@ -1817,8 +1813,12 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size) size[1] = max_ii(1, tex->h / div); } - if (tex->target == GL_TEXTURE_2D_ARRAY) { + if (GPU_texture_array(tex)) { size[2] = tex->d; + /* Return the number of face layers. */ + if (GPU_texture_cube(tex)) { + size[2] *= 6; + } } else if (tex->d > 0) { size[2] = max_ii(1, tex->d / div); diff --git a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl index aa1d437c307..9e1527a9e7f 100644 --- a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl +++ b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl @@ -1,7 +1,8 @@ -/* Need to be included after common_view_lib.glsl for resource_id. */ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + #ifndef GPU_OBINFOS_UBO -#define GPU_OBINFOS_UBO +# define GPU_OBINFOS_UBO struct ObjectInfos { vec4 drw_OrcoTexCoFactors[2]; vec4 drw_ObjectColor; @@ -13,7 +14,7 @@ layout(std140) uniform infoBlock /* DRW_RESOURCE_CHUNK_LEN = 512 */ ObjectInfos drw_infos[512]; }; -#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors) -#define ObjectInfo (drw_infos[resource_id].drw_Infos) -#define ObjectColor (drw_infos[resource_id].drw_ObjectColor) +# define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors) +# define ObjectInfo (drw_infos[resource_id].drw_Infos) +# define ObjectColor (drw_infos[resource_id].drw_ObjectColor) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl index 501aeb6f34e..a80cd3cb329 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl @@ -1,18 +1,21 @@ -void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf) + +/* Uniforms to convert smoke grid values into standard range. */ +uniform vec3 volumeColor = vec3(1.0); +uniform vec2 volumeTemperature = vec2(0.0); + +/* Generic volume attribute. */ +void node_attribute_volume(sampler3D tex, out vec3 outvec) { #if defined(MESH_SHADER) && defined(VOLUMETRICS) vec3 cos = volumeObjectLocalCoord; #else vec3 cos = vec3(0.0); #endif - outvec = texture(tex, cos).aaa; - outcol = vec4(outvec, 1.0); - outf = avg(outvec); + outvec = texture(tex, cos).rgb; } -uniform vec3 volumeColor = vec3(1.0); - -void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf) +/* Special color attribute for smoke. */ +void node_attribute_volume_color(sampler3D tex, out vec3 outvec) { #if defined(MESH_SHADER) && defined(VOLUMETRICS) vec3 cos = volumeObjectLocalCoord; @@ -20,69 +23,31 @@ void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec vec3 cos = vec3(0.0); #endif - vec4 value = texture(tex, cos).rgba; /* Density is premultiplied for interpolation, divide it out here. */ + vec4 value = texture(tex, cos).rgba; if (value.a > 1e-8) { value.rgb /= value.a; } outvec = value.rgb * volumeColor; - outcol = vec4(outvec, 1.0); - outf = avg(outvec); } -void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf) +/* Special temperature attribute for smoke. */ +void node_attribute_volume_temperature(sampler3D tex, out float outf) { #if defined(MESH_SHADER) && defined(VOLUMETRICS) vec3 cos = volumeObjectLocalCoord; #else vec3 cos = vec3(0.0); #endif - outf = texture(tex, cos).r; - outvec = vec3(outf, outf, outf); - outcol = vec4(outf, outf, outf, 1.0); -} -void node_attribute_volume_temperature( - sampler3D tex, vec2 temperature, out vec4 outcol, out vec3 outvec, out float outf) -{ -#if defined(MESH_SHADER) && defined(VOLUMETRICS) - vec3 cos = volumeObjectLocalCoord; -#else - vec3 cos = vec3(0.0); -#endif - float flame = texture(tex, cos).r; - - outf = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0; - outvec = vec3(outf, outf, outf); - outcol = vec4(outf, outf, outf, 1.0); -} - -void node_volume_info(sampler3D densitySampler, - sampler3D flameSampler, - vec2 temperature, - out vec4 outColor, - out float outDensity, - out float outFlame, - out float outTemprature) -{ -#if defined(MESH_SHADER) && defined(VOLUMETRICS) - vec3 p = volumeObjectLocalCoord; -#else - vec3 p = vec3(0.0); -#endif - - vec4 density = texture(densitySampler, p); - outDensity = density.a; - - /* Density is premultiplied for interpolation, divide it out here. */ - if (density.a > 1e-8) { - density.rgb /= density.a; + float value = texture(tex, cos).r; + if (volumeTemperature.x < volumeTemperature.y) { + outf = (value > 0.01) ? + volumeTemperature.x + value * (volumeTemperature.y - volumeTemperature.x) : + 0.0; + } + else { + outf = value; } - outColor = vec4(density.rgb * volumeColor, 1.0); - - float flame = texture(flameSampler, p).r; - outFlame = flame; - - outTemprature = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0; } diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc index a8ed2c5f2a5..a958a445a3d 100644 --- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc +++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc @@ -164,7 +164,7 @@ void AbstractHierarchyIterator::debug_print_export_graph(const ExportGraph &grap } } } - printf(" (Total graph size: %lu objects\n", total_graph_size); + printf(" (Total graph size: %zu objects\n", total_graph_size); } void AbstractHierarchyIterator::export_graph_construct() @@ -345,7 +345,7 @@ void AbstractHierarchyIterator::visit_dupli_object(DupliObject *dupli_object, } else { /* The parent object is NOT part of the duplicated collection. This means that the world - * transform of this dupliobject can be influenced by objects that are not part of its + * transform of this dupli-object can be influenced by objects that are not part of its * export graph. */ animation_check_include_parent = true; context->export_parent = duplicator; diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h b/source/blender/io/usd/intern/abstract_hierarchy_iterator.h index 8bca2ddd447..c121e3b704d 100644 --- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h +++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.h @@ -65,8 +65,8 @@ struct HierarchyContext { /* When weak_export=true, the object will be exported only as transform, and only if is an * ancestor of an object with weak_export=false. * - * In other words: when weak_export=true but this object has no children, or all decendants also - * have weak_export=true, this object (and by recursive reasoning all its decendants) will be + * In other words: when weak_export=true but this object has no children, or all descendants also + * have weak_export=true, this object (and by recursive reasoning all its descendants) will be * excluded from the export. * * The export hierarchy is kept as close to the the hierarchy in Blender as possible. As such, an @@ -222,7 +222,7 @@ class AbstractHierarchyIterator { * * When this returns true, only a transform writer is created and marked as * 'weak export'. In this case, the transform writer will be removed before - * exporting starts, unless a decendant of this object is to be exported. + * exporting starts, unless a descendant of this object is to be exported. * Dupli-object generated from this object will also be skipped. * * See HierarchyContext::weak_export. diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index 74005afaf31..cbf51fc15b3 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -58,7 +58,7 @@ bool USDGenericMeshWriter::is_supported(const HierarchyContext *context) const int base_flag; if (is_dupli) { - /* Construct the object's base flags from its dupliparent, just like is done in + /* Construct the object's base flags from its dupli-parent, just like is done in * deg_objects_dupli_iterator_next(). Without this, the visibility check below will fail. Doing * this here, instead of a more suitable location in AbstractHierarchyIterator, prevents * copying the Object for every dupli. */ diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 3ac93a96661..40916cbdc61 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -465,16 +465,20 @@ typedef enum ID_Type { if ((a) && (a)->id.newid) \ (a) = (void *)(a)->id.newid -/* id->flag (persitent). */ +/** id->flag (persitent). */ enum { - /* Don't delete the datablock even if unused. */ + /** Don't delete the datablock even if unused. */ LIB_FAKEUSER = 1 << 9, - /* The datablock structure is a sub-object of a different one. - * Direct persistent references are not allowed. */ - LIB_PRIVATE_DATA = 1 << 10, - /* Datablock is from a library and linked indirectly, with LIB_TAG_INDIRECT + /** + * The data-block is a sub-data of another one. + * Direct persistent references are not allowed. + */ + LIB_EMBEDDED_DATA = 1 << 10, + /** + * Datablock is from a library and linked indirectly, with LIB_TAG_INDIRECT * tag set. But the current .blend file also has a weak pointer to it that - * we want to restore if possible, and silently drop if it's missing. */ + * we want to restore if possible, and silently drop if it's missing. + */ LIB_INDIRECT_WEAK_LINK = 1 << 11, }; diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 4b696e29a52..5b9340ab3d9 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -764,10 +764,6 @@ typedef enum eDopeSheet_FilterFlag { /** show only F-Curves which are disabled/have errors - for debugging drivers */ ADS_FILTER_ONLY_ERRORS = (1 << 28), - /* GPencil Mode */ - /** GP Mode - Only show datablocks used in the scene */ - ADS_FILTER_GP_3DONLY = (1 << 29), - #if 0 /** combination filters (some only used at runtime) */ ADS_FILTER_NOOBDATA = (ADS_FILTER_NOCAM | ADS_FILTER_NOMAT | ADS_FILTER_NOLAM | diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h index 631c1b71732..f344e860d2e 100644 --- a/source/blender/makesdna/DNA_fluid_types.h +++ b/source/blender/makesdna/DNA_fluid_types.h @@ -256,7 +256,8 @@ typedef struct FluidDomainSettings { struct Collection *fluid_group; struct Collection *force_group; /* UNUSED */ struct Collection *effector_group; /* Effector objects group. */ - struct GPUTexture *tex; + struct GPUTexture *tex_density; + struct GPUTexture *tex_color; struct GPUTexture *tex_wt; struct GPUTexture *tex_shadow; struct GPUTexture *tex_flame; diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index 6ffdd60a094..d9cc549229d 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -160,6 +160,10 @@ typedef struct LightCacheTexture { typedef struct LightCache { int flag; + /** Version number to know if the cache data is compatible with this version of blender. */ + int version; + /** Type of data this cache contains. */ + int type; /* only a single cache for now */ /** Number of probes to use for rendering. */ int cube_len, grid_len; @@ -181,6 +185,14 @@ typedef struct LightCache { LightGridCache *grid_data; } LightCache; +/* Bump the version number for lightcache data structure changes. */ +#define LIGHTCACHE_STATIC_VERSION 1 + +/* LightCache->type */ +enum { + LIGHTCACHE_TYPE_STATIC = 0, +}; + /* LightCache->flag */ enum { LIGHTCACHE_BAKED = (1 << 0), diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 042cf7e874f..13c5a0913c6 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -1255,6 +1255,19 @@ typedef struct OceanModifierData { float foam_coverage; float time; + char _pad1[4]; + + /* Spectrum being used. */ + int spectrum; + + /* Common JONSWAP parameters. */ + /** + * This is the distance from a lee shore, called the fetch, or the distance + * over which the wind blows with constant velocity. + */ + float fetch_jonswap; + float sharpen_peak_jonswap; + int bakestart; int bakeend; @@ -1287,6 +1300,13 @@ enum { }; enum { + MOD_OCEAN_SPECTRUM_PHILLIPS = 0, + MOD_OCEAN_SPECTRUM_PIERSON_MOSKOWITZ = 1, + MOD_OCEAN_SPECTRUM_JONSWAP = 2, + MOD_OCEAN_SPECTRUM_TEXEL_MARSEN_ARSLOE = 3, +}; + +enum { MOD_OCEAN_GENERATE_FOAM = (1 << 0), MOD_OCEAN_GENERATE_NORMALS = (1 << 1), }; diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h index db3566710b4..4b6f079aa28 100644 --- a/source/blender/makesdna/DNA_scene_defaults.h +++ b/source/blender/makesdna/DNA_scene_defaults.h @@ -224,7 +224,7 @@ .shadow_cube_size = 512, \ .shadow_cascade_size = 1024, \ \ - .light_cache = NULL, \ + .light_cache_data = NULL, \ .light_threshold = 0.01f, \ \ .overscan = 3.0f, \ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 3a88cd0a33b..aac976fbabd 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -242,6 +242,7 @@ typedef struct SceneRenderLayer { #define SCE_LAY_STRAND (1 << 5) #define SCE_LAY_FRS (1 << 6) #define SCE_LAY_AO (1 << 7) +#define SCE_LAY_VOLUMES (1 << 8) /* flags between (1 << 8) and (1 << 15) are set to 1 already, for future options */ #define SCE_LAY_ALL_Z (1 << 15) @@ -1632,7 +1633,8 @@ typedef struct SceneEEVEE { int shadow_cube_size; int shadow_cascade_size; - struct LightCache *light_cache; + struct LightCache *light_cache DNA_DEPRECATED; + struct LightCache *light_cache_data; char light_cache_info[64]; float overscan; diff --git a/source/blender/makesdna/DNA_view3d_enums.h b/source/blender/makesdna/DNA_view3d_enums.h index 880a157cc3d..f8c772422bb 100644 --- a/source/blender/makesdna/DNA_view3d_enums.h +++ b/source/blender/makesdna/DNA_view3d_enums.h @@ -44,10 +44,6 @@ typedef enum eV3DShadingColorType { V3D_SHADING_TEXTURE_COLOR = 3, V3D_SHADING_OBJECT_COLOR = 4, V3D_SHADING_VERTEX_COLOR = 5, - - /* Is used to display the object using the error color. For example when in - * solid texture paint mode without any textures configured */ - V3D_SHADING_ERROR_COLOR = 999, } eV3DShadingColorType; /** #View3DShading.background_type */ diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index e0f3aff6364..b2d02600124 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -4654,8 +4654,8 @@ static const char *cpp_classes = " operator void*() { return ptr.data; }\n" " operator bool() { return ptr.data != NULL; }\n" "\n" - " bool operator==(const Pointer &other) { return ptr.data == other.ptr.data; }\n" - " bool operator!=(const Pointer &other) { return ptr.data != other.ptr.data; }\n" + " bool operator==(const Pointer &other) const { return ptr.data == other.ptr.data; }\n" + " bool operator!=(const Pointer &other) const { return ptr.data != other.ptr.data; }\n" "\n" " PointerRNA ptr;\n" "};\n" diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 8dd6e6982dd..33f9b2da280 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -5832,7 +5832,7 @@ ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path) *r_path = ""; } - if ((id != NULL) && (id->flag & LIB_PRIVATE_DATA)) { + if ((id != NULL) && (id->flag & LIB_EMBEDDED_DATA)) { switch (GS(id->name)) { case ID_NT: if (r_path) { diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 436e847b044..c85a94d9fc2 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -583,15 +583,6 @@ static void rna_def_dopesheet(BlenderRNA *brna) prop, "Display Movie Clips", "Include visualization of movie clip related animation data"); RNA_def_property_ui_icon(prop, ICON_TRACKER, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - - /* GPencil Mode Settings */ - prop = RNA_def_property(srna, "show_gpencil_3d_only", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_GP_3DONLY); - RNA_def_property_ui_text(prop, - "Active Scene Only", - "Only show Grease Pencil data-blocks used as part of the active scene"); - RNA_def_property_ui_icon(prop, ICON_SCENE_DATA, 0); - RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); } static void rna_def_action_group(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index 38ba7bcb047..7bd353cd441 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -720,7 +720,7 @@ static void rna_FluidModifier_color_grid_get(PointerRNA *ptr, float *values) manta_smoke_turbulence_get_rgba(mds->fluid, values, 0); } else { - manta_smoke_turbulence_get_rgba_from_density(mds->fluid, mds->active_color, values, 0); + manta_smoke_turbulence_get_rgba_fixed_color(mds->fluid, mds->active_color, values, 0); } } else { @@ -728,7 +728,7 @@ static void rna_FluidModifier_color_grid_get(PointerRNA *ptr, float *values) manta_smoke_get_rgba(mds->fluid, values, 0); } else { - manta_smoke_get_rgba_from_density(mds->fluid, mds->active_color, values, 0); + manta_smoke_get_rgba_fixed_color(mds->fluid, mds->active_color, values, 0); } } } diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 396c5a4e854..6440b140183 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -5178,6 +5178,30 @@ static void rna_def_modifier_ocean(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem spectrum_items[] = { + {MOD_OCEAN_SPECTRUM_PHILLIPS, + "PHILLIPS", + 0, + "Turbulent Ocean", + "Use for turbulent seas with foam"}, + {MOD_OCEAN_SPECTRUM_PIERSON_MOSKOWITZ, + "PIERSON_MOSKOWITZ", + 0, + "Established Ocean", + "Use for a large area, established ocean (Pierson-Moskowitz method)"}, + {MOD_OCEAN_SPECTRUM_JONSWAP, + "JONSWAP", + 0, + "Established Ocean (Sharp Peaks)", + "Use for sharp peaks ('JONSWAP', Pierson-Moskowitz method) with peak sharpening"}, + {MOD_OCEAN_SPECTRUM_TEXEL_MARSEN_ARSLOE, + "TEXEL_MARSEN_ARSLOE", + 0, + "Shallow Water", + "Use for shallow water ('JONSWAP', 'TMA' - Texel-Marsen-Arsloe method)"}, + {0, NULL, 0, NULL, NULL}, + }; + srna = RNA_def_struct(brna, "OceanModifier", "Modifier"); RNA_def_struct_ui_text(srna, "Ocean Modifier", "Simulate an ocean surface"); RNA_def_struct_sdna(srna, "OceanModifierData"); @@ -5324,6 +5348,29 @@ static void rna_def_modifier_ocean(BlenderRNA *brna) RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, -1); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "spectrum", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "spectrum"); + RNA_def_property_enum_items(prop, spectrum_items); + RNA_def_property_ui_text(prop, "Spectrum", "Spectrum to use"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop = RNA_def_property(srna, "fetch_jonswap", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "fetch_jonswap"); + RNA_def_property_range(prop, 0.0, FLT_MAX); + RNA_def_property_ui_text( + prop, + "Fetch", + "This is the distance from a lee shore, " + "called the fetch, or the distance over which the wind blows with constant velocity. " + "Used by 'JONSWAP' and 'TMA' models"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop = RNA_def_property(srna, "sharpen_peak_jonswap", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "sharpen_peak_jonswap"); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_text(prop, "Sharpen peak", "Peak sharpening for 'JONSWAP' and 'TMA' models"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + prop = RNA_def_property(srna, "random_seed", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "seed"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 9aeaf4e83dd..3747dd53b97 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -188,9 +188,9 @@ static void rna_ParticleHairKey_location_object_info(PointerRNA *ptr, * not a very efficient way of getting hair key location data, * but it's the best we've got at the present * - * IDEAS: include additional information in pointerRNA beforehand, - * for example a pointer to the ParticleStstemModifierData to which the - * hairkey belongs. + * IDEAS: include additional information in PointerRNA beforehand, + * for example a pointer to the ParticleSystemModifierData to which the + * hair-key belongs. */ for (md = ob->modifiers.first; md; md = md->next) { @@ -199,9 +199,9 @@ static void rna_ParticleHairKey_location_object_info(PointerRNA *ptr, if (psmd && psmd->mesh_final && psmd->psys) { psys = psmd->psys; for (i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) { - /* hairkeys are stored sequentially in memory, so we can + /* Hair-keys are stored sequentially in memory, so we can * find if it's the same particle by comparing pointers, - * without having to iterate over them all */ + * without having to iterate over them all. */ if ((hkey >= pa->hair) && (hkey < pa->hair + pa->totkey)) { *psmd_pt = psmd; *pa_pt = pa; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 27d742fd33c..f974d5c563f 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -4018,6 +4018,16 @@ void rna_def_view_layer_common(StructRNA *srna, const bool scene) RNA_def_property_clear_flag(prop, PROP_EDITABLE); } + prop = RNA_def_property(srna, "use_volumes", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_VOLUMES); + RNA_def_property_ui_text(prop, "Volumes", "Render volumes in this Layer"); + if (scene) { + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + } + else { + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + } + /* passes */ prop = RNA_def_property(srna, "use_pass_combined", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_COMBINED); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index ac0376c72af..a153c1dda1e 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -5040,8 +5040,16 @@ static void rna_def_userdef_system(BlenderRNA *brna) {2048, "SAMPLES_2048", 0, "2048 Samples", "Set audio mixing buffer size to 2048 samples"}, {4096, "SAMPLES_4096", 0, "4096 Samples", "Set audio mixing buffer size to 4096 samples"}, {8192, "SAMPLES_8192", 0, "8192 Samples", "Set audio mixing buffer size to 8192 samples"}, - {16384, "SAMPLES_16384", 0, "16384 Samples", "Set audio mixing buffer size to 16384 samples"}, - {32768, "SAMPLES_32768", 0, "32768 Samples", "Set audio mixing buffer size to 32768 samples"}, + {16384, + "SAMPLES_16384", + 0, + "16384 Samples", + "Set audio mixing buffer size to 16384 samples"}, + {32768, + "SAMPLES_32768", + 0, + "32768 Samples", + "Set audio mixing buffer size to 32768 samples"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 9ec4d58eb61..de08533753e 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -206,7 +206,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes Object *ob = ctx->object; if (harden_normals && (ob->type == OB_MESH) && !(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) { - modifier_setError(md, "Enable 'Auto Smooth' option in mesh settings for hardening"); + modifier_setError(md, "Enable 'Auto Smooth' in Object Data Properties"); harden_normals = false; } diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index 953b1b460c8..63c1b6f1ef0 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -179,7 +179,11 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla } else { tclmd->point_cache = BKE_ptcache_add(&tclmd->ptcaches); - tclmd->point_cache->step = 1; + if (clmd->point_cache != NULL) { + tclmd->point_cache->step = clmd->point_cache->step; + tclmd->point_cache->startframe = clmd->point_cache->startframe; + tclmd->point_cache->endframe = clmd->point_cache->endframe; + } } tclmd->sim_parms = MEM_dupallocN(clmd->sim_parms); diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c index 3e79dd91d2b..72cbe197251 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -220,7 +220,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes modifier_setError(md, "%s", BKE_reports_string(&reports, RPT_ERROR)); } else if ((dtmd->data_types & DT_TYPE_LNOR) && !(me->flag & ME_AUTOSMOOTH)) { - modifier_setError((ModifierData *)dtmd, "Enable 'Auto Smooth' option in mesh settings"); + modifier_setError((ModifierData *)dtmd, "Enable 'Auto Smooth' in Object Data Properties"); } else if (result->totvert > HIGH_POLY_WARNING || ((Mesh *)(ob_source->data))->totvert > HIGH_POLY_WARNING) { diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 720ca4ffa13..78d29edfd98 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -316,7 +316,7 @@ static void deformVerts_do(HookModifierData *hmd, * This should always be true and I don't generally like * "paranoid" style code like this, but old files can have * indices that are out of range because old blender did - * not correct them on exit editmode. - zr + * not correct them on exit edit-mode. - zr */ if (hmd->force == 0.0f) { diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 572d9505e4e..ace0c1b5eaf 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -494,7 +494,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) #endif { - modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' option in mesh settings"); + modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' in Object Data Properties"); return mesh; } diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index 62a5dd45e68..fec04e9916d 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -92,6 +92,10 @@ static void initData(ModifierData *md) omd->seed = 0; omd->time = 1.0; + omd->spectrum = MOD_OCEAN_SPECTRUM_PHILLIPS; + omd->sharpen_peak_jonswap = 0.0f; + omd->fetch_jonswap = 120.0f; + omd->size = 1.0; omd->repeat_x = 1; omd->repeat_y = 1; diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c index 48ccd9b83ed..af6de8447ec 100644 --- a/source/blender/modifiers/intern/MOD_softbody.c +++ b/source/blender/modifiers/intern/MOD_softbody.c @@ -69,6 +69,8 @@ static void updateDepsgraph(ModifierData *UNUSED(md), const ModifierUpdateDepsgr DEG_add_forcefield_relations( ctx->node, ctx->object, ctx->object->soft->effector_weights, true, 0, "Softbody Field"); } + /* We need own transformation as well. */ + DEG_add_modifier_to_transform_relation(ctx->node, "SoftBody Modifier"); } ModifierTypeInfo modifierType_Softbody = { diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index d9c05d8d4b4..04b503e588b 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -562,7 +562,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) #endif { - modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' option in mesh settings"); + modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' in Object Data Properties"); return mesh; } diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c index 79f02f5c243..6b5d46e250b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_attribute.c +++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c @@ -42,28 +42,18 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, { NodeShaderAttribute *attr = node->storage; - /* FIXME : if an attribute layer (like vertex color) has one of these names, - * it will not work as expected. */ - if (strcmp(attr->name, "density") == 0) { - return GPU_stack_link( - mat, node, "node_attribute_volume_density", in, out, GPU_builtin(GPU_VOLUME_DENSITY)); - } - else if (strcmp(attr->name, "color") == 0) { - return GPU_stack_link( - mat, node, "node_attribute_volume_color", in, out, GPU_builtin(GPU_VOLUME_DENSITY)); - } - else if (strcmp(attr->name, "flame") == 0) { - return GPU_stack_link( - mat, node, "node_attribute_volume_flame", in, out, GPU_builtin(GPU_VOLUME_FLAME)); - } - else if (strcmp(attr->name, "temperature") == 0) { - return GPU_stack_link(mat, - node, - "node_attribute_volume_temperature", - in, - out, - GPU_builtin(GPU_VOLUME_FLAME), - GPU_builtin(GPU_VOLUME_TEMPERATURE)); + if (GPU_material_is_volume_shader(mat)) { + if (out[0].hasoutput) { + out[0].link = GPU_volume_grid(mat, attr->name); + } + if (out[1].hasoutput) { + out[1].link = GPU_volume_grid(mat, attr->name); + } + if (out[2].hasoutput) { + out[2].link = GPU_volume_grid(mat, attr->name); + } + + return 1; } else { GPUNodeLink *cd_attr = GPU_attribute(mat, CD_AUTO_FROM_NAME, attr->name); diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_info.c b/source/blender/nodes/shader/nodes/node_shader_volume_info.c index 57fa2b7e582..7ccc00f1af3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_volume_info.c +++ b/source/blender/nodes/shader/nodes/node_shader_volume_info.c @@ -28,20 +28,25 @@ static bNodeSocketTemplate sh_node_volume_info_out[] = { }; static int node_shader_gpu_volume_info(GPUMaterial *mat, - bNode *node, + bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), - GPUNodeStack *in, + GPUNodeStack *UNUSED(in), GPUNodeStack *out) { + if (out[0].hasoutput) { + out[0].link = GPU_volume_grid(mat, "color"); + } + if (out[1].hasoutput) { + out[1].link = GPU_volume_grid(mat, "density"); + } + if (out[2].hasoutput) { + out[2].link = GPU_volume_grid(mat, "flame"); + } + if (out[3].hasoutput) { + out[3].link = GPU_volume_grid(mat, "temperature"); + } - return GPU_stack_link(mat, - node, - "node_volume_info", - in, - out, - GPU_builtin(GPU_VOLUME_DENSITY), - GPU_builtin(GPU_VOLUME_FLAME), - GPU_builtin(GPU_VOLUME_TEMPERATURE)); + return true; } void register_node_type_sh_volume_info(void) diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c index dc41d6b2531..92e1b3435c8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c @@ -54,42 +54,6 @@ static void node_shader_init_volume_principled(bNodeTree *UNUSED(ntree), bNode * } } -static void node_shader_gpu_volume_attribute(GPUMaterial *mat, - const char *name, - GPUNodeLink **outcol, - GPUNodeLink **outvec, - GPUNodeLink **outf) -{ - if (strcmp(name, "density") == 0) { - GPU_link(mat, - "node_attribute_volume_density", - GPU_builtin(GPU_VOLUME_DENSITY), - outcol, - outvec, - outf); - } - else if (strcmp(name, "color") == 0) { - GPU_link( - mat, "node_attribute_volume_color", GPU_builtin(GPU_VOLUME_DENSITY), outcol, outvec, outf); - } - else if (strcmp(name, "flame") == 0) { - GPU_link( - mat, "node_attribute_volume_flame", GPU_builtin(GPU_VOLUME_FLAME), outcol, outvec, outf); - } - else if (strcmp(name, "temperature") == 0) { - GPU_link(mat, - "node_attribute_volume_temperature", - GPU_builtin(GPU_VOLUME_FLAME), - GPU_builtin(GPU_VOLUME_TEMPERATURE), - outcol, - outvec, - outf); - } - else { - *outcol = *outvec = *outf = NULL; - } -} - static int node_shader_gpu_volume_principled(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), @@ -108,16 +72,19 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat, } bNodeSocketValueString *value = sock->default_value; - GPUNodeLink *outcol, *outvec, *outf; + const char *attribute_name = value->value; + if (attribute_name[0] == '\0') { + continue; + } if (STREQ(sock->name, "Density Attribute")) { - node_shader_gpu_volume_attribute(mat, value->value, &outcol, &outvec, &density); + density = GPU_volume_grid(mat, attribute_name); } else if (STREQ(sock->name, "Color Attribute")) { - node_shader_gpu_volume_attribute(mat, value->value, &color, &outvec, &outf); + color = GPU_volume_grid(mat, attribute_name); } else if (use_blackbody && STREQ(sock->name, "Temperature Attribute")) { - node_shader_gpu_volume_attribute(mat, value->value, &outcol, &outvec, &temperature); + temperature = GPU_volume_grid(mat, attribute_name); } } diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index ff81b4a15ff..c32ef3e6624 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -923,7 +923,7 @@ static PyObject *pyrna_struct_repr(BPy_StructRNA *self) if (DEG_get_original_id(id) != id) { ret = PyUnicode_FromFormat("Evaluated %s %R", BKE_idcode_to_name(GS(id->name)), tmp_str); } - else if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_PRIVATE_DATA) == 0) { + else if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_EMBEDDED_DATA) == 0) { ret = PyUnicode_FromFormat( "bpy.data.%s[%R]", BKE_idcode_to_name_plural(GS(id->name)), tmp_str); } diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c index 1c1a1a26e3b..6344ed39b1b 100644 --- a/source/blender/python/intern/bpy_rna_id_collection.c +++ b/source/blender/python/intern/bpy_rna_id_collection.c @@ -98,7 +98,7 @@ static int foreach_libblock_id_user_map_callback(LibraryIDLinkCallbackData *cb_d return IDWALK_RET_NOP; } - if (cb_flag & IDWALK_CB_PRIVATE) { + if (cb_flag & IDWALK_CB_EMBEDDED) { /* We skip private pointers themselves, like root node trees, we'll 'link' their own ID * pointers to their 'ID owner' instead. */ return IDWALK_RET_NOP; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 8728c887feb..c7556ec7516 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2498,6 +2498,164 @@ static int wm_handlers_do_keymap_with_gizmo_handler( return action; } +static int wm_handlers_do_gizmo_handler(bContext *C, + wmWindowManager *wm, + wmEventHandler_Gizmo *handler, + wmEvent *event, + ListBase *handlers, + const bool do_debug_handler) +{ + int action = WM_HANDLER_CONTINUE; + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + wmGizmoMap *gzmap = handler->gizmo_map; + BLI_assert(gzmap != NULL); + wmGizmo *gz = wm_gizmomap_highlight_get(gzmap); + + /* Needed so UI blocks over gizmos don't let events fall through to the gizmos, + * noticeable for the node editor - where dragging on a node should move it, see: T73212. */ + if (region->type->clip_gizmo_events_by_ui) { + if (UI_region_block_find_mouse_over(region, &event->x, true)) { + if (gz != NULL) { + WM_tooltip_clear(C, CTX_wm_window(C)); + wm_gizmomap_highlight_set(gzmap, C, NULL, 0); + } + return action; + } + } + + if (region->gizmo_map != handler->gizmo_map) { + WM_gizmomap_tag_refresh(handler->gizmo_map); + } + + wm_gizmomap_handler_context_gizmo(C, handler); + wm_region_mouse_co(C, event); + + /* Drag events use the previous click location to highlight the gizmos, + * Get the highlight again in case the user dragged off the gizmo. */ + const bool is_event_drag = ISTWEAK(event->type) || (event->val == KM_CLICK_DRAG); + const bool is_event_modifier = ISKEYMODIFIER(event->type); + + bool handle_highlight = false; + bool handle_keymap = false; + + /* handle gizmo highlighting */ + if (!wm_gizmomap_modal_get(gzmap) && + ((event->type == MOUSEMOVE) || is_event_modifier || is_event_drag)) { + handle_highlight = true; + if (is_event_modifier || is_event_drag) { + handle_keymap = true; + } + } + else { + handle_keymap = true; + } + + if (handle_highlight) { + struct { + wmGizmo *gz; + int part; + } prev = { + .gz = gz, + .part = gz ? gz->highlight_part : 0, + }; + int part = -1; + gz = wm_gizmomap_highlight_find(gzmap, C, event, &part); + + /* If no gizmos are/were active, don't clear tool-tips. */ + if (gz || prev.gz) { + if ((prev.gz != gz) || (prev.part != part)) { + WM_tooltip_clear(C, CTX_wm_window(C)); + } + } + + if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) { + if (gz != NULL) { + if (U.flag & USER_TOOLTIPS) { + WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init); + } + } + } + } + + /* Don't use from now on. */ + bool is_event_handle_all = gz && (gz->flag & WM_GIZMO_EVENT_HANDLE_ALL); + + if (handle_keymap) { + /* Handle highlight gizmo. */ + if (gz != NULL) { + bool keymap_poll = false; + wmGizmoGroup *gzgroup = gz->parent_gzgroup; + wmKeyMap *keymap = WM_keymap_active(wm, gz->keymap ? gz->keymap : gzgroup->type->keymap); + action |= wm_handlers_do_keymap_with_gizmo_handler( + C, event, handlers, handler, gzgroup, keymap, do_debug_handler, &keymap_poll); + +#ifdef USE_GIZMO_MOUSE_PRIORITY_HACK + if (((action & WM_HANDLER_BREAK) == 0) && !is_event_handle_all && keymap_poll) { + if ((event->val == KM_PRESS) && ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) { + + wmEvent event_test_click = *event; + event_test_click.val = KM_CLICK; + + wmEvent event_test_click_drag = *event; + event_test_click_drag.val = KM_CLICK_DRAG; + + wmEvent event_test_tweak = *event; + event_test_tweak.type = EVT_TWEAK_L + (event->type - LEFTMOUSE); + event_test_tweak.val = KM_ANY; + + for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { + if ((kmi->flag & KMI_INACTIVE) == 0) { + if (wm_eventmatch(&event_test_click, kmi) || + wm_eventmatch(&event_test_click_drag, kmi) || + wm_eventmatch(&event_test_tweak, kmi)) { + wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0); + if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) { + is_event_handle_all = true; + break; + } + } + } + } + } + } +#endif /* USE_GIZMO_MOUSE_PRIORITY_HACK */ + } + + /* Don't use from now on. */ + gz = NULL; + + /* Fallback to selected gizmo (when un-handled). */ + if ((action & WM_HANDLER_BREAK) == 0) { + if (WM_gizmomap_is_any_selected(gzmap)) { + const ListBase *groups = WM_gizmomap_group_list(gzmap); + for (wmGizmoGroup *gzgroup = groups->first; gzgroup; gzgroup = gzgroup->next) { + if (wm_gizmogroup_is_any_selected(gzgroup)) { + wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap); + action |= wm_handlers_do_keymap_with_gizmo_handler( + C, event, handlers, handler, gzgroup, keymap, do_debug_handler, NULL); + if (action & WM_HANDLER_BREAK) { + break; + } + } + } + } + } + } + + if (is_event_handle_all) { + if (action == WM_HANDLER_CONTINUE) { + action |= WM_HANDLER_BREAK | WM_HANDLER_MODAL; + } + } + + /* restore the area */ + CTX_wm_area_set(C, area); + CTX_wm_region_set(C, region); + + return action; +} + static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers) { const bool do_debug_handler = @@ -2609,142 +2767,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers } else if (handler_base->type == WM_HANDLER_TYPE_GIZMO) { wmEventHandler_Gizmo *handler = (wmEventHandler_Gizmo *)handler_base; - ScrArea *area = CTX_wm_area(C); - ARegion *region = CTX_wm_region(C); - wmGizmoMap *gzmap = handler->gizmo_map; - BLI_assert(gzmap != NULL); - wmGizmo *gz = wm_gizmomap_highlight_get(gzmap); - - if (region->gizmo_map != handler->gizmo_map) { - WM_gizmomap_tag_refresh(handler->gizmo_map); - } - - wm_gizmomap_handler_context_gizmo(C, handler); - wm_region_mouse_co(C, event); - - /* Drag events use the previous click location to highlight the gizmos, - * Get the highlight again in case the user dragged off the gizmo. */ - const bool is_event_drag = ISTWEAK(event->type) || (event->val == KM_CLICK_DRAG); - const bool is_event_modifier = ISKEYMODIFIER(event->type); - - bool handle_highlight = false; - bool handle_keymap = false; - - /* handle gizmo highlighting */ - if (!wm_gizmomap_modal_get(gzmap) && - ((event->type == MOUSEMOVE) || is_event_modifier || is_event_drag)) { - handle_highlight = true; - if (is_event_modifier || is_event_drag) { - handle_keymap = true; - } - } - else { - handle_keymap = true; - } - - if (handle_highlight) { - struct { - wmGizmo *gz; - int part; - } prev = { - .gz = gz, - .part = gz ? gz->highlight_part : 0, - }; - int part = -1; - gz = wm_gizmomap_highlight_find(gzmap, C, event, &part); - - /* If no gizmos are/were active, don't clear tool-tips. */ - if (gz || prev.gz) { - if ((prev.gz != gz) || (prev.part != part)) { - WM_tooltip_clear(C, CTX_wm_window(C)); - } - } - - if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) { - if (gz != NULL) { - if (U.flag & USER_TOOLTIPS) { - WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init); - } - } - } - } - - /* Don't use from now on. */ - bool is_event_handle_all = gz && (gz->flag & WM_GIZMO_EVENT_HANDLE_ALL); - - if (handle_keymap) { - /* Handle highlight gizmo. */ - if (gz != NULL) { - bool keymap_poll = false; - wmGizmoGroup *gzgroup = gz->parent_gzgroup; - wmKeyMap *keymap = WM_keymap_active(wm, - gz->keymap ? gz->keymap : gzgroup->type->keymap); - action |= wm_handlers_do_keymap_with_gizmo_handler( - C, event, handlers, handler, gzgroup, keymap, do_debug_handler, &keymap_poll); - -#ifdef USE_GIZMO_MOUSE_PRIORITY_HACK - if (((action & WM_HANDLER_BREAK) == 0) && !is_event_handle_all && keymap_poll) { - if ((event->val == KM_PRESS) && - ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) { - - wmEvent event_test_click = *event; - event_test_click.val = KM_CLICK; - - wmEvent event_test_click_drag = *event; - event_test_click_drag.val = KM_CLICK_DRAG; - - wmEvent event_test_tweak = *event; - event_test_tweak.type = EVT_TWEAK_L + (event->type - LEFTMOUSE); - event_test_tweak.val = KM_ANY; - - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { - if ((kmi->flag & KMI_INACTIVE) == 0) { - if (wm_eventmatch(&event_test_click, kmi) || - wm_eventmatch(&event_test_click_drag, kmi) || - wm_eventmatch(&event_test_tweak, kmi)) { - wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0); - if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) { - is_event_handle_all = true; - break; - } - } - } - } - } - } -#endif /* USE_GIZMO_MOUSE_PRIORITY_HACK */ - } - - /* Don't use from now on. */ - gz = NULL; - - /* Fallback to selected gizmo (when un-handled). */ - if ((action & WM_HANDLER_BREAK) == 0) { - if (WM_gizmomap_is_any_selected(gzmap)) { - const ListBase *groups = WM_gizmomap_group_list(gzmap); - for (wmGizmoGroup *gzgroup = groups->first; gzgroup; gzgroup = gzgroup->next) { - if (wm_gizmogroup_is_any_selected(gzgroup)) { - wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap); - action |= wm_handlers_do_keymap_with_gizmo_handler( - C, event, handlers, handler, gzgroup, keymap, do_debug_handler, NULL); - if (action & WM_HANDLER_BREAK) { - break; - } - } - } - } - } - } - - if (is_event_handle_all) { - if (action == WM_HANDLER_CONTINUE) { - action |= WM_HANDLER_BREAK | WM_HANDLER_MODAL; - } - } - - /* restore the area */ - CTX_wm_area_set(C, area); - CTX_wm_region_set(C, region); + action |= wm_handlers_do_gizmo_handler(C, wm, handler, event, handlers, do_debug_handler); } else if (handler_base->type == WM_HANDLER_TYPE_OP) { wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base; @@ -2915,6 +2938,21 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } } } + else if (ISMOUSE_WHEEL(event->type) || ISMOUSE_GESTURE(event->type)) { + /* Modifiers which can trigger click event's, + * however we don't want this if the mouse wheel has been used, see T74607. */ + if (wm_action_not_handled(action)) { + /* pass */ + } + else { + wmWindow *win = CTX_wm_window(C); + if (win) { + if (ISKEYMODIFIER(win->eventstate->prevtype)) { + win->eventstate->check_click = 0; + } + } + } + } return action; } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 16f2f822338..aab2acaac76 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -3340,7 +3340,7 @@ static int previews_id_ensure_callback(LibraryIDLinkCallbackData *cb_data) { const int cb_flag = cb_data->cb_flag; - if (cb_flag & IDWALK_CB_PRIVATE) { + if (cb_flag & IDWALK_CB_EMBEDDED) { return IDWALK_RET_NOP; } diff --git a/tests/python/eevee_render_tests.py b/tests/python/eevee_render_tests.py index a7130136d0a..0d9fd37b0d7 100755 --- a/tests/python/eevee_render_tests.py +++ b/tests/python/eevee_render_tests.py @@ -35,6 +35,13 @@ def setup(): # mat.use_screen_refraction = True mat.use_sss_translucency = True + # Workaround for crash with Mantaflow (T73921). + use_light_cache_bake = True + for ob in bpy.data.objects: + for mod in ob.modifiers: + if mod.type == 'FLUID': + use_light_cache_bake = False + cubemap = None grid = None # Does not work in edit mode @@ -79,7 +86,8 @@ def setup(): eevee.gi_visibility_resolution = '16' eevee.gi_irradiance_smoothing = 0 - bpy.ops.scene.light_cache_bake() + if use_light_cache_bake: + bpy.ops.scene.light_cache_bake() # When run from inside Blender, render and exit. |