Merge branch 'master' into refactor-mesh-position-generic

This commit is contained in:
Hans Goudey 2022-12-09 16:15:08 -06:00
commit 0fe2a9c901
374 changed files with 7523 additions and 3376 deletions

View File

@ -23,13 +23,11 @@ elseif(APPLE)
set(BOOST_BUILD_COMMAND ./b2)
set(BOOST_BUILD_OPTIONS toolset=clang-darwin cxxflags=${PLATFORM_CXXFLAGS} linkflags=${PLATFORM_LDFLAGS} visibility=global --disable-icu boost.locale.icu=off)
set(BOOST_HARVEST_CMD echo .)
set(BOOST_PATCH_COMMAND echo .)
else()
set(BOOST_HARVEST_CMD echo .)
set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh)
set(BOOST_BUILD_COMMAND ./b2)
set(BOOST_BUILD_OPTIONS cxxflags=${PLATFORM_CXXFLAGS} --disable-icu boost.locale.icu=off)
set(BOOST_PATCH_COMMAND echo .)
endif()
set(JAM_FILE ${BUILD_DIR}/boost.user-config.jam)
@ -72,7 +70,7 @@ ExternalProject_Add(external_boost
URL_HASH ${BOOST_HASH_TYPE}=${BOOST_HASH}
PREFIX ${BUILD_DIR}/boost
UPDATE_COMMAND ""
PATCH_COMMAND ${BOOST_PATCH_COMMAND}
PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/boost/src/external_boost < ${PATCH_DIR}/boost.diff
CONFIGURE_COMMAND ${BOOST_CONFIGURE_COMMAND}
BUILD_COMMAND ${BOOST_BUILD_COMMAND} ${BOOST_BUILD_OPTIONS} -j${MAKE_THREADS} architecture=${BOOST_ARCHITECTURE} address-model=${BOOST_ADDRESS_MODEL} link=shared threading=multi ${BOOST_OPTIONS} --prefix=${LIBDIR}/boost install
BUILD_IN_SOURCE 1

View File

@ -63,6 +63,8 @@ endfunction()
# Ideally this would be done as part of the Blender build since it makes assumptions
# about where the files will be installed. However it would add patchelf as a new
# dependency for building.
#
# Also removes versioned symlinks, which give errors with macOS notarization.
if(APPLE)
set(set_rpath_cmd python3 ${CMAKE_CURRENT_SOURCE_DIR}/darwin/set_rpath.py @loader_path)
else()
@ -76,7 +78,11 @@ function(harvest_rpath_lib from to pattern)
cmake_policy(SET CMP0009 NEW)\n
file(GLOB_RECURSE shared_libs ${HARVEST_TARGET}/${to}/${pattern}) \n
foreach(f \${shared_libs}) \n
if(NOT IS_SYMLINK \${f})\n
if(IS_SYMLINK \${f})\n
if(APPLE)\n
file(REMOVE_RECURSE \${f})
endif()\n
else()\n
execute_process(COMMAND ${set_rpath_cmd} \${f}) \n
endif()\n
endforeach()")
@ -101,15 +107,21 @@ function(harvest_rpath_python from to pattern)
install(CODE "\
file(GLOB_RECURSE shared_libs ${HARVEST_TARGET}/${to}/${pattern}\.so*) \n
foreach(f \${shared_libs}) \n
get_filename_component(f_dir \${f} DIRECTORY) \n
file(RELATIVE_PATH relative_dir \${f_dir} ${HARVEST_TARGET}) \n
execute_process(COMMAND ${set_rpath_cmd}/\${relative_dir}../lib \${f}) \n
if(IS_SYMLINK \${f})\n
if(APPLE)\n
file(REMOVE_RECURSE \${f})
endif()\n
else()\n
get_filename_component(f_dir \${f} DIRECTORY) \n
file(RELATIVE_PATH relative_dir \${f_dir} ${HARVEST_TARGET}) \n
execute_process(COMMAND ${set_rpath_cmd}/\${relative_dir}../lib \${f}) \n
endif()\n
endforeach()")
endfunction()
harvest(alembic/include alembic/include "*.h")
harvest(alembic/lib/libAlembic.a alembic/lib/libAlembic.a)
harvest(alembic/bin alembic/bin "*")
harvest_rpath_bin(alembic/bin alembic/bin "*")
harvest(brotli/include brotli/include "*.h")
harvest(brotli/lib brotli/lib "*.a")
harvest(boost/include boost/include "*")
@ -151,7 +163,7 @@ harvest(llvm/lib llvm/lib "libLLVM*.a")
harvest(llvm/lib llvm/lib "libclang*.a")
harvest(llvm/lib/clang llvm/lib/clang "*.h")
if(APPLE)
harvest(openmp/lib openmp/lib "*")
harvest(openmp/lib openmp/lib "libomp.dylib")
harvest(openmp/include openmp/include "*.h")
endif()
if(BLENDER_PLATFORM_ARM)
@ -242,9 +254,8 @@ harvest(usd/lib/usd usd/lib/usd "*")
harvest_rpath_python(usd/lib/python/pxr python/lib/python${PYTHON_SHORT_VERSION}/site-packages/pxr "*")
harvest(usd/plugin usd/plugin "*")
harvest(materialx/include materialx/include "*.h")
harvest(materialx/lib materialx/lib "*")
harvest_rpath_lib(materialx/lib materialx/lib "*${SHAREDLIBEXT}*")
harvest(materialx/libraries materialx/libraries "*")
harvest(materialx/python materialx/python "*")
harvest(materialx/lib/cmake/MaterialX materialx/lib/cmake/MaterialX "*.cmake")
harvest_rpath_python(materialx/python/MaterialX python/lib/python${PYTHON_SHORT_VERSION}/site-packages/MaterialX "*")
# We do not need anything from the resources folder, but the MaterialX config

View File

@ -32,13 +32,11 @@ if(WIN32)
# Python will download its own deps and there's very little we can do about
# that beyond placing some code in their externals dir before it tries.
# the foldernames *HAVE* to match the ones inside pythons get_externals.cmd.
# python 3.10.8 still ships zlib 1.2.12, replace it with our 1.2.13
# copy until they update. Same rules apply to openssl foldernames HAVE to match
# regardless of the version actually in there.
PATCH_COMMAND mkdir ${PYTHON_EXTERNALS_FOLDER_DOS} &&
mklink /J ${PYTHON_EXTERNALS_FOLDER_DOS}\\zlib-1.2.12 ${ZLIB_SOURCE_FOLDER_DOS} &&
mklink /J ${PYTHON_EXTERNALS_FOLDER_DOS}\\zlib-1.2.13 ${ZLIB_SOURCE_FOLDER_DOS} &&
mklink /J ${PYTHON_EXTERNALS_FOLDER_DOS}\\openssl-1.1.1q ${SSL_SOURCE_FOLDER_DOS} &&
${CMAKE_COMMAND} -E copy ${ZLIB_SOURCE_FOLDER}/../external_zlib-build/zconf.h ${PYTHON_EXTERNALS_FOLDER}/zlib-1.2.12/zconf.h &&
${CMAKE_COMMAND} -E copy ${ZLIB_SOURCE_FOLDER}/../external_zlib-build/zconf.h ${PYTHON_EXTERNALS_FOLDER}/zlib-1.2.13/zconf.h &&
${PATCH_CMD} --verbose -p1 -d ${BUILD_DIR}/python/src/external_python < ${PATCH_DIR}/python_windows.diff
CONFIGURE_COMMAND echo "."
BUILD_COMMAND ${CONFIGURE_ENV_MSVC} && cd ${BUILD_DIR}/python/src/external_python/pcbuild/ && set IncludeTkinter=false && set LDFLAGS=/DEBUG && call prepare_ssl.bat && call build.bat -e -p x64 -c ${BUILD_MODE}

View File

@ -15,7 +15,9 @@ ExternalProject_Add(external_python_site_packages
CONFIGURE_COMMAND ${PIP_CONFIGURE_COMMAND}
BUILD_COMMAND ""
PREFIX ${BUILD_DIR}/site_packages
INSTALL_COMMAND ${PYTHON_BINARY} -m pip install --no-cache-dir ${SITE_PACKAGES_EXTRA} cython==${CYTHON_VERSION} idna==${IDNA_VERSION} charset-normalizer==${CHARSET_NORMALIZER_VERSION} urllib3==${URLLIB3_VERSION} certifi==${CERTIFI_VERSION} requests==${REQUESTS_VERSION} zstandard==${ZSTANDARD_VERSION} autopep8==${AUTOPEP8_VERSION} pycodestyle==${PYCODESTYLE_VERSION} toml==${TOML_VERSION} meson==${MESON_VERSION} --no-binary :all:
# setuptools is downgraded to 63.2.0 (same as python 3.10.8) since numpy 1.23.x seemingly has
# issues building on windows with the newer versions that ships with python 3.10.9+
INSTALL_COMMAND ${PYTHON_BINARY} -m pip install --no-cache-dir ${SITE_PACKAGES_EXTRA} setuptools==63.2.0 cython==${CYTHON_VERSION} idna==${IDNA_VERSION} charset-normalizer==${CHARSET_NORMALIZER_VERSION} urllib3==${URLLIB3_VERSION} certifi==${CERTIFI_VERSION} requests==${REQUESTS_VERSION} zstandard==${ZSTANDARD_VERSION} autopep8==${AUTOPEP8_VERSION} pycodestyle==${PYCODESTYLE_VERSION} toml==${TOML_VERSION} meson==${MESON_VERSION} --no-binary :all:
)
if(USE_PIP_NUMPY)

View File

@ -201,6 +201,11 @@ set(OSL_HASH 53211da86c34ba6e0344998c1a6d219c)
set(OSL_HASH_TYPE MD5)
set(OSL_FILE OpenShadingLanguage-${OSL_VERSION}.tar.gz)
# NOTE: When updating the python version, it's required to check the versions of
# it wants to use in PCbuild/get_externals.bat for the following dependencies:
# BZIP2, FFI, SQLITE and change the versions in this file as well. For compliance
# reasons there can be no exceptions to this.
set(PYTHON_VERSION 3.10.9)
set(PYTHON_SHORT_VERSION 3.10)
set(PYTHON_SHORT_VERSION_NO_DOTS 310)
@ -240,10 +245,10 @@ set(PYCODESTYLE_VERSION 2.8.0)
set(TOML_VERSION 0.10.2)
set(MESON_VERSION 0.63.0)
set(NUMPY_VERSION 1.23.2)
set(NUMPY_VERSION 1.23.5)
set(NUMPY_SHORT_VERSION 1.23)
set(NUMPY_URI https://github.com/numpy/numpy/releases/download/v${NUMPY_VERSION}/numpy-${NUMPY_VERSION}.tar.gz)
set(NUMPY_HASH 9bf2a361509797de14ceee607387fe0f)
set(NUMPY_HASH 8b2692a511a3795f3af8af2cd7566a15)
set(NUMPY_HASH_TYPE MD5)
set(NUMPY_FILE numpy-${NUMPY_VERSION}.tar.gz)
set(NUMPY_CPE "cpe:2.3:a:numpy:numpy:${NUMPY_VERSION}:*:*:*:*:*:*:*")
@ -437,9 +442,7 @@ set(LZMA_HASH 5117f930900b341493827d63aa910ff5e011e0b994197c3b71c08a20228a42df)
set(LZMA_HASH_TYPE SHA256)
set(LZMA_FILE xz-${LZMA_VERSION}.tar.bz2)
# NOTE: This will *HAVE* to match the version python ships on windows which
# is hardcoded in pythons PCbuild/get_externals.bat. For compliance reasons there
# can be no exceptions to this.
# NOTE: Python's build has been modified to use our ssl version.
set(SSL_VERSION 1.1.1q)
set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz)
set(SSL_HASH d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca)
@ -450,10 +453,10 @@ set(SSL_CPE "cpe:2.3:a:openssl:openssl:${SSL_VERSION}:*:*:*:*:*:*:*")
# Note: This will *HAVE* to match the version python ships on windows which
# is hardcoded in pythons PCbuild/get_externals.bat for compliance reasons there
# can be no exceptions to this.
set(SQLITE_VERSION 3.37.2)
set(SQLLITE_LONG_VERSION 3370200)
set(SQLITE_VERSION 3.39.4)
set(SQLLITE_LONG_VERSION 3390400)
set(SQLITE_URI https://www.sqlite.org/2022/sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz)
set(SQLITE_HASH e56faacadfb4154f8fbd0f2a3f827d13706b70a1)
set(SQLITE_HASH c4c5c39269d1b9bb1487cff580c1f583608229b2)
set(SQLITE_HASH_TYPE SHA1)
set(SQLITE_FILE sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz)
set(SQLITE_CPE "cpe:2.3:a:sqlite:sqlite:${SQLITE_VERSION}:*:*:*:*:*:*:*")

View File

@ -1,9 +1,19 @@
#!/usr/bin/env python3
# macOS utility to remove all rpaths and add a new one.
import os
import re
import subprocess
import sys
# Strip version numbers from dependenciesm macOS notarizatiom fails
# with version symlinks.
def strip_lib_version(name):
name = re.sub(r'(\.[0-9]+)+.dylib', '.dylib', name)
name = re.sub(r'(\.[0-9]+)+.so', '.so', name)
name = re.sub(r'(\.[0-9]+)+.cpython', '.cpython', name)
return name
rpath = sys.argv[1]
file = sys.argv[2]
@ -17,3 +27,18 @@ for i, token in enumerate(tokens):
subprocess.run(['install_name_tool', '-delete_rpath', old_rpath, file])
subprocess.run(['install_name_tool', '-add_rpath', rpath, file])
# Strip version from dependencies.
p = subprocess.run(['otool', '-L', file], capture_output=True)
tokens = p.stdout.split()
for i, token in enumerate(tokens):
token = token.decode("utf-8")
if token.startswith("@rpath"):
new_token = strip_lib_version(token)
subprocess.run(['install_name_tool', '-change', token, new_token, file])
# Strip version from library itself.
new_file = strip_lib_version(file)
new_id = '@rpath/' + os.path.basename(new_file)
os.rename(file, new_file)
subprocess.run(['install_name_tool', '-id', new_id, new_file])

View File

@ -0,0 +1,12 @@
--- a/boost/python//detail/wrap_python.hpp 2022-12-09 19:16:17
+++ b/boost/python//detail/wrap_python.hpp 2022-12-09 19:18:08
@@ -206,7 +206,8 @@
#ifdef DEBUG_UNDEFINED_FROM_WRAP_PYTHON_H
# undef DEBUG_UNDEFINED_FROM_WRAP_PYTHON_H
-# define _DEBUG
+// BLENDER: TBB excepts this to have a value.
+# define _DEBUG 1
# ifdef _CRT_NOFORCE_MANIFEST_DEFINED_FROM_WRAP_PYTHON_H
# undef _CRT_NOFORCE_MANIFEST_DEFINED_FROM_WRAP_PYTHON_H
# undef _CRT_NOFORCE_MANIFEST

View File

@ -36,3 +36,39 @@ index a97a755..07ce853 100644
if (self.compiler.find_library_file(self.lib_dirs, lib_name)):
ffi_lib = lib_name
break
--- a/Modules/posixmodule.c 2022-12-09 21:44:03
+++ b/Modules/posixmodule.c 2022-12-09 21:39:46
@@ -10564,10 +10564,15 @@
Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_MKFIFOAT
if (dir_fd != DEFAULT_DIR_FD) {
+// BLENDER: disable also at compile time for compatibility when linking with older Xcode.
+// https://github.com/python/cpython/issues/97897
+#ifndef __APPLE__
if (HAVE_MKFIFOAT_RUNTIME) {
result = mkfifoat(dir_fd, path->narrow, mode);
+ } else
+#endif
+ {
- } else {
mkfifoat_unavailable = 1;
result = 0;
}
@@ -10638,10 +10633,15 @@
Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_MKNODAT
if (dir_fd != DEFAULT_DIR_FD) {
+// BLENDER: disable also at compile time for compatibility when linking with older Xcode.
+// https://github.com/python/cpython/issues/97897
+#ifndef __APPLE__
if (HAVE_MKNODAT_RUNTIME) {
result = mknodat(dir_fd, path->narrow, mode, device);
+ } else
+#endif
+ {
- } else {
mknodat_unavailable = 1;
result = 0;
}

View File

@ -30,3 +30,19 @@ diff -ru ./src/video/SDL_video.c ./src/video/SDL_video.c
if (SDL_strcmp(_this->name, "cocoa") == 0) { /* don't do this for X11, etc */
if (Cocoa_IsWindowInFullscreenSpace(window)) {
return SDL_FALSE;
--- CMakeLists.txt 2022-12-09 20:40:00
+++ CMakeLists.txt 2022-12-09 20:40:00
@@ -526,6 +526,13 @@
list(APPEND EXTRA_CFLAGS "-fno-strict-aliasing")
endif()
+ # BLENDER: make libs compatible with older Xcode.
+ # https://github.com/KhronosGroup/MoltenVK/issues/1756
+ check_c_compiler_flag(-fno-objc-msgsend-selector-stubs HAVE_GCC_NO_OBJC_MSGSEND_SELECTOR_STUBS)
+ if(HAVE_GCC_NO_OBJC_MSGSEND_SELECTOR_STUBS)
+ list(APPEND EXTRA_CFLAGS "-fno-objc-msgsend-selector-stubs")
+ endif()
+
check_c_compiler_flag(-Wdeclaration-after-statement HAVE_GCC_WDECLARATION_AFTER_STATEMENT)
if(HAVE_GCC_WDECLARATION_AFTER_STATEMENT)
check_c_compiler_flag(-Werror=declaration-after-statement HAVE_GCC_WERROR_DECLARATION_AFTER_STATEMENT)

View File

@ -1206,7 +1206,7 @@ class CyclesWorldSettings(bpy.types.PropertyGroup):
)
homogeneous_volume: BoolProperty(
name="Homogeneous Volume",
description="When using volume rendering, assume volume has the same density everywhere"
description="When using volume rendering, assume volume has the same density everywhere "
"(not using any textures), for faster rendering",
default=False,
)

View File

@ -193,7 +193,7 @@ class CYCLES_RENDER_PT_sampling_viewport(CyclesButtonsPanel, Panel):
if cscene.use_preview_adaptive_sampling:
col = layout.column(align=True)
col.prop(cscene, "preview_samples", text=" Max Samples")
col.prop(cscene, "preview_samples", text="Max Samples")
col.prop(cscene, "preview_adaptive_min_samples", text="Min Samples")
else:
layout.prop(cscene, "preview_samples", text="Samples")
@ -255,7 +255,7 @@ class CYCLES_RENDER_PT_sampling_render(CyclesButtonsPanel, Panel):
col = layout.column(align=True)
if cscene.use_adaptive_sampling:
col.prop(cscene, "samples", text=" Max Samples")
col.prop(cscene, "samples", text="Max Samples")
col.prop(cscene, "adaptive_min_samples", text="Min Samples")
else:
col.prop(cscene, "samples", text="Samples")

View File

@ -337,10 +337,12 @@ static bool addGPULut1D2D(OCIO_GPUTextures &textures,
* It depends on more than height. So check instead by looking at the source. */
std::string sampler1D_name = std::string("sampler1D ") + sampler_name;
if (strstr(shader_desc->getShaderText(), sampler1D_name.c_str()) != nullptr) {
lut.texture = GPU_texture_create_1d(texture_name, width, 1, format, values);
lut.texture = GPU_texture_create_1d_ex(
texture_name, width, 1, format, GPU_TEXTURE_USAGE_SHADER_READ, values);
}
else {
lut.texture = GPU_texture_create_2d(texture_name, width, height, 1, format, values);
lut.texture = GPU_texture_create_2d_ex(
texture_name, width, height, 1, format, GPU_TEXTURE_USAGE_SHADER_READ, values);
}
if (lut.texture == nullptr) {
return false;
@ -372,8 +374,15 @@ static bool addGPULut3D(OCIO_GPUTextures &textures,
}
OCIO_GPULutTexture lut;
lut.texture = GPU_texture_create_3d(
texture_name, edgelen, edgelen, edgelen, 1, GPU_RGB16F, GPU_DATA_FLOAT, values);
lut.texture = GPU_texture_create_3d_ex(texture_name,
edgelen,
edgelen,
edgelen,
1,
GPU_RGB16F,
GPU_DATA_FLOAT,
GPU_TEXTURE_USAGE_SHADER_READ,
values);
if (lut.texture == nullptr) {
return false;
}
@ -442,7 +451,8 @@ static bool createGPUCurveMapping(OCIO_GPUCurveMappping &curvemap,
if (curve_mapping_settings) {
int lut_size = curve_mapping_settings->lut_size;
curvemap.texture = GPU_texture_create_1d("OCIOCurveMap", lut_size, 1, GPU_RGBA16F, nullptr);
curvemap.texture = GPU_texture_create_1d_ex(
"OCIOCurveMap", lut_size, 1, GPU_RGBA16F, GPU_TEXTURE_USAGE_SHADER_READ, nullptr);
GPU_texture_filter_mode(curvemap.texture, false);
GPU_texture_wrap_mode(curvemap.texture, false, true);

View File

@ -171,7 +171,7 @@ colorspaces:
name: Non-Color
family: raw
description: |
Color space used for images which contains non-color data (i.e. normal maps)
Color space used for images which contain non-color data (e.g. normal maps)
equalitygroup:
bitdepth: 32f
isdata: true

View File

@ -214,7 +214,7 @@ class AddPresetBase:
class ExecutePreset(Operator):
"""Execute a preset"""
"""Load a preset"""
bl_idname = "script.execute_preset"
bl_label = "Execute a Python Preset"

View File

@ -228,8 +228,8 @@ def lightmap_uvpack(
"""
BOX_DIV if the maximum division of the UV map that
a box may be consolidated into.
Basically, a lower value will be slower but waist less space
and a higher value will have more clumpy boxes but more wasted space
A lower value will create more clumpy boxes and more wasted space,
and a higher value will be slower but waste less space
"""
import time
from math import sqrt
@ -623,7 +623,10 @@ class LightMapPack(Operator):
# UV Packing...
PREF_BOX_DIV: IntProperty(
name="Pack Quality",
description="Pre-packing before the complex boxpack",
description=(
"Quality of the packing. "
"Higher values will be slower but waste less space"
),
min=1, max=48,
default=12,
)

View File

@ -2084,7 +2084,7 @@ class WM_OT_operator_cheat_sheet(Operator):
# Add-on Operators
class WM_OT_owner_enable(Operator):
"""Enable workspace owner ID"""
"""Enable add-on for workspace"""
bl_idname = "wm.owner_enable"
bl_label = "Enable Add-on"
@ -2099,9 +2099,9 @@ class WM_OT_owner_enable(Operator):
class WM_OT_owner_disable(Operator):
"""Enable workspace owner ID"""
"""Disable add-on for workspace"""
bl_idname = "wm.owner_disable"
bl_label = "Disable UI Tag"
bl_label = "Disable Add-on"
owner_id: StringProperty(
name="UI Tag",

View File

@ -140,6 +140,7 @@ class NODE_MT_geometry_node_GEO_INPUT(Menu):
node_add_menu.add_node_type(layout, "FunctionNodeInputBool")
node_add_menu.add_node_type(layout, "GeometryNodeCollectionInfo")
node_add_menu.add_node_type(layout, "FunctionNodeInputColor")
node_add_menu.add_node_type(layout, "GeometryNodeInputImage")
node_add_menu.add_node_type(layout, "GeometryNodeImageInfo")
node_add_menu.add_node_type(layout, "FunctionNodeInputInt")
node_add_menu.add_node_type(layout, "GeometryNodeIsViewport")

View File

@ -428,7 +428,7 @@ class PHYSICS_PT_fire(PhysicButtonsPanel, Panel):
col.prop(domain, "flame_max_temp", text="Temperature Maximum")
col.prop(domain, "flame_ignition", text="Minimum")
row = col.row()
row.prop(domain, "flame_smoke_color", text="Flame Color")
row.prop(domain, "flame_smoke_color", text="Smoke Color")
class PHYSICS_PT_liquid(PhysicButtonsPanel, Panel):

View File

@ -214,8 +214,12 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel, Panel):
col = flow.column()
col.prop(softbody, "spring_length", text="Length")
col.prop(softbody, "use_edge_collision", text="Collision Edge")
col.prop(softbody, "use_face_collision", text="Face")
col.separator()
col = flow.column(align=True, heading="Collision")
col.prop(softbody, "use_edge_collision", text="Edge", toggle=False)
col.prop(softbody, "use_face_collision", text="Face", toggle=False)
class PHYSICS_PT_softbody_edge_aerodynamics(PhysicButtonsPanel, Panel):

View File

@ -2196,7 +2196,7 @@ class SEQUENCER_PT_cache_settings(SequencerButtonsPanel, Panel):
col = layout.column(heading="Cache", align=True)
col.prop(ed, "use_cache_raw", text="Raw")
col.prop(ed, "use_cache_preprocessed", text="Pre-Processed")
col.prop(ed, "use_cache_preprocessed", text="Preprocessed")
col.prop(ed, "use_cache_composite", text="Composite")
col.prop(ed, "use_cache_final", text="Final")
@ -2315,7 +2315,7 @@ class SEQUENCER_PT_strip_cache(SequencerButtonsPanel, Panel):
col = layout.column(heading="Cache")
col.prop(strip, "use_cache_raw", text="Raw")
col.prop(strip, "use_cache_preprocessed", text="Pre-Processed")
col.prop(strip, "use_cache_preprocessed", text="Preprocessed")
col.prop(strip, "use_cache_composite", text="Composite")

View File

@ -1199,7 +1199,8 @@ void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, const int x,
if (gc->texture) {
GPU_texture_free(gc->texture);
}
gc->texture = GPU_texture_create_2d(__func__, w, h, 1, GPU_R8, NULL);
gc->texture = GPU_texture_create_2d_ex(
__func__, w, h, 1, GPU_R8, GPU_TEXTURE_USAGE_SHADER_READ, NULL);
gc->bitmap_len_landed = 0;
}

View File

@ -493,9 +493,7 @@ void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh);
* Used when defining an empty custom loop normals data layer,
* to keep same shading as with auto-smooth!
*/
void BKE_edges_sharp_from_angle_set(const float (*positions)[3],
int numVerts,
struct MEdge *medges,
void BKE_edges_sharp_from_angle_set(struct MEdge *medges,
int numEdges,
const struct MLoop *mloops,
int numLoops,

View File

@ -1542,6 +1542,7 @@ struct TexResult;
#define GEO_NODE_SET_CURVE_NORMAL 1188
#define GEO_NODE_IMAGE_INFO 1189
#define GEO_NODE_BLUR_ATTRIBUTE 1190
#define GEO_NODE_IMAGE 1191
/** \} */

View File

@ -1001,7 +1001,7 @@ static void blendfile_link_append_proxies_convert(Main *bmain, ReportList *repor
RPT_WARNING,
"Proxies have been removed from Blender (%d proxies were automatically converted "
"to library overrides, %d proxies could not be converted and were cleared). "
"Please consider re-saving any library .blend file with the newest Blender version",
"Consider re-saving any library .blend file with the newest Blender version",
bf_reports.count.proxies_to_lib_overrides_success,
bf_reports.count.proxies_to_lib_overrides_failures);
}

View File

@ -571,7 +571,7 @@ void BKE_crazyspace_api_displacement_to_original(struct Object *object,
if (vertex_index < 0 || vertex_index >= object->runtime.crazyspace_verts_num) {
BKE_reportf(reports,
RPT_ERROR,
"Invalid vertex index %d (expected to be within 0 to %d range))",
"Invalid vertex index %d (expected to be within 0 to %d range)",
vertex_index,
object->runtime.crazyspace_verts_num);
return;

View File

@ -6,7 +6,7 @@
#include <algorithm>
#include "BLI_math_rotation.hh"
#include "BLI_math_rotation_legacy.hh"
#include "BLI_math_vector.hh"
#include "BKE_curves.hh"

View File

@ -13,7 +13,7 @@
#include "BLI_bounds.hh"
#include "BLI_index_mask_ops.hh"
#include "BLI_length_parameterize.hh"
#include "BLI_math_rotation.hh"
#include "BLI_math_rotation_legacy.hh"
#include "BLI_task.hh"
#include "DNA_curves_types.h"
@ -519,7 +519,7 @@ void CurvesGeometry::ensure_evaluated_offsets() const
this->runtime->bezier_evaluated_offsets.resize(this->points_num());
}
else {
this->runtime->bezier_evaluated_offsets.clear_and_make_inline();
this->runtime->bezier_evaluated_offsets.clear_and_shrink();
}
calculate_evaluated_offsets(
@ -605,7 +605,7 @@ Span<float3> CurvesGeometry::evaluated_positions() const
this->runtime->position_cache_mutex.ensure([&]() {
if (this->is_single_type(CURVE_TYPE_POLY)) {
this->runtime->evaluated_positions_span = this->positions();
this->runtime->evaluated_position_cache.clear_and_make_inline();
this->runtime->evaluated_position_cache.clear_and_shrink();
return;
}

View File

@ -111,7 +111,8 @@ static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multivi
tile_info[3] = tile_runtime->tilearray_size[1] / array_h;
}
GPUTexture *tex = GPU_texture_create_1d_array(ima->id.name + 2, width, 2, 1, GPU_RGBA32F, data);
GPUTexture *tex = GPU_texture_create_1d_array_ex(
ima->id.name + 2, width, 2, 1, GPU_RGBA32F, GPU_TEXTURE_USAGE_SHADER_READ, data);
GPU_texture_mipmap_mode(tex, false, false);
MEM_freeN(data);

View File

@ -1812,7 +1812,7 @@ struct SplitFaceNewVert {
struct SplitFaceNewVert *next;
int new_index;
int orig_index;
float *vnor;
const float *vnor;
};
struct SplitFaceNewEdge {
@ -1823,82 +1823,79 @@ struct SplitFaceNewEdge {
int v2;
};
/* Detect needed new vertices, and update accordingly loops' vertex indices.
* WARNING! Leaves mesh in invalid state. */
static int split_faces_prepare_new_verts(Mesh *mesh,
MLoopNorSpaceArray *lnors_spacearr,
/**
* Detect necessary new vertices, and update loop vertex indices accordingly.
* \warning Leaves mesh in invalid state.
* \param lnors_spacearr: Mandatory because trying to do the job in simple way without that data is
* doomed to fail, even when only dealing with smooth/flat faces one can find cases that no simple
* algorithm can handle properly.
*/
static int split_faces_prepare_new_verts(Mesh &mesh,
const MLoopNorSpaceArray &lnors_spacearr,
SplitFaceNewVert **new_verts,
MemArena *memarena)
MemArena &memarena)
{
/* This is now mandatory, trying to do the job in simple way without that data is doomed to fail,
* even when only dealing with smooth/flat faces one can find cases that no simple algorithm
* can handle properly. */
BLI_assert(lnors_spacearr != nullptr);
const int loops_len = mesh->totloop;
int verts_len = mesh->totvert;
MutableSpan<MLoop> loops = mesh->loops_for_write();
BKE_mesh_vertex_normals_ensure(mesh);
float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh);
const int loops_len = mesh.totloop;
int verts_len = mesh.totvert;
MutableSpan<MLoop> loops = mesh.loops_for_write();
BKE_mesh_vertex_normals_ensure(&mesh);
float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(&mesh);
BitVector<> verts_used(verts_len, false);
BitVector<> done_loops(loops_len, false);
MLoop *ml = loops.data();
MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
BLI_assert(lnors_spacearr.data_type == MLNOR_SPACEARR_LOOP_INDEX);
BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX);
for (int loop_idx = 0; loop_idx < loops_len; loop_idx++) {
if (done_loops[loop_idx]) {
continue;
}
const MLoopNorSpace &lnor_space = *lnors_spacearr.lspacearr[loop_idx];
const int vert_idx = loops[loop_idx].v;
const bool vert_used = verts_used[vert_idx];
/* If vert is already used by another smooth fan, we need a new vert for this one. */
const int new_vert_idx = vert_used ? verts_len++ : vert_idx;
for (int loop_idx = 0; loop_idx < loops_len; loop_idx++, ml++, lnor_space++) {
if (!done_loops[loop_idx]) {
const int vert_idx = ml->v;
const bool vert_used = verts_used[vert_idx];
/* If vert is already used by another smooth fan, we need a new vert for this one. */
const int new_vert_idx = vert_used ? verts_len++ : vert_idx;
BLI_assert(*lnor_space);
if ((*lnor_space)->flags & MLNOR_SPACE_IS_SINGLE) {
/* Single loop in this fan... */
BLI_assert(POINTER_AS_INT((*lnor_space)->loops) == loop_idx);
done_loops[loop_idx].set();
if (lnor_space.flags & MLNOR_SPACE_IS_SINGLE) {
/* Single loop in this fan... */
BLI_assert(POINTER_AS_INT(lnor_space.loops) == loop_idx);
done_loops[loop_idx].set();
if (vert_used) {
loops[loop_idx].v = new_vert_idx;
}
}
else {
for (const LinkNode *lnode = lnor_space.loops; lnode; lnode = lnode->next) {
const int ml_fan_idx = POINTER_AS_INT(lnode->link);
done_loops[ml_fan_idx].set();
if (vert_used) {
ml->v = new_vert_idx;
}
}
else {
for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) {
const int ml_fan_idx = POINTER_AS_INT(lnode->link);
done_loops[ml_fan_idx].set();
if (vert_used) {
loops[ml_fan_idx].v = new_vert_idx;
}
loops[ml_fan_idx].v = new_vert_idx;
}
}
}
if (!vert_used) {
verts_used[vert_idx].set();
/* We need to update that vertex's normal here, we won't go over it again. */
/* This is important! *DO NOT* set vnor to final computed lnor,
* vnor should always be defined to 'automatic normal' value computed from its polys,
* not some custom normal.
* Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
copy_v3_v3(vert_normals[vert_idx], (*lnor_space)->vec_lnor);
}
else {
/* Add new vert to list. */
SplitFaceNewVert *new_vert = (SplitFaceNewVert *)BLI_memarena_alloc(memarena,
sizeof(*new_vert));
new_vert->orig_index = vert_idx;
new_vert->new_index = new_vert_idx;
new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */
new_vert->next = *new_verts;
*new_verts = new_vert;
}
if (!vert_used) {
verts_used[vert_idx].set();
/* We need to update that vertex's normal here, we won't go over it again. */
/* This is important! *DO NOT* set vnor to final computed lnor,
* vnor should always be defined to 'automatic normal' value computed from its polys,
* not some custom normal.
* Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
copy_v3_v3(vert_normals[vert_idx], lnor_space.vec_lnor);
}
else {
/* Add new vert to list. */
SplitFaceNewVert *new_vert = static_cast<SplitFaceNewVert *>(
BLI_memarena_alloc(&memarena, sizeof(*new_vert)));
new_vert->orig_index = vert_idx;
new_vert->new_index = new_vert_idx;
new_vert->vnor = lnor_space.vec_lnor; /* See note above. */
new_vert->next = *new_verts;
*new_verts = new_vert;
}
}
return verts_len - mesh->totvert;
return verts_len - mesh.totvert;
}
/* Detect needed new edges, and update accordingly loops' edge indices.
@ -2025,7 +2022,7 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
/* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */
const int num_new_verts = split_faces_prepare_new_verts(
mesh, &lnors_spacearr, &new_verts, memarena);
*mesh, lnors_spacearr, &new_verts, *memarena);
if (num_new_verts > 0) {
/* Reminder: beyond this point, there is no way out, mesh is in invalid state

View File

@ -39,6 +39,7 @@
using blender::BitVector;
using blender::float3;
using blender::int2;
using blender::MutableSpan;
using blender::short2;
using blender::Span;
@ -773,10 +774,10 @@ struct LoopSplitTaskDataCommon {
/* Read-only. */
Span<float3> positions;
MutableSpan<MEdge> edges;
Span<MEdge> edges;
Span<MLoop> loops;
Span<MPoly> polys;
int (*edge_to_loops)[2];
MutableSpan<int2> edge_to_loops;
Span<int> loop_to_poly;
Span<float3> polynors;
Span<float3> vert_normals;
@ -787,76 +788,57 @@ struct LoopSplitTaskDataCommon {
/* See comment about edge_to_loops below. */
#define IS_EDGE_SHARP(_e2l) ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID)
static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
static void mesh_edges_sharp_tag(const Span<MEdge> edges,
const Span<MPoly> polys,
const Span<MLoop> loops,
const Span<int> loop_to_poly_map,
const Span<float3> poly_normals,
const bool check_angle,
const float split_angle,
const bool do_sharp_edges_tag)
MutableSpan<int2> edge_to_loops,
BitVector<> *r_sharp_edges)
{
MutableSpan<MEdge> edges = data->edges;
const Span<MPoly> polys = data->polys;
const Span<MLoop> loops = data->loops;
const Span<int> loop_to_poly = data->loop_to_poly;
MutableSpan<float3> loopnors = data->loopnors; /* NOTE: loopnors may be empty here. */
const Span<float3> polynors = data->polynors;
int(*edge_to_loops)[2] = data->edge_to_loops;
BitVector sharp_edges;
if (do_sharp_edges_tag) {
sharp_edges.resize(edges.size(), false);
}
using namespace blender;
const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
for (const int mp_index : polys.index_range()) {
const MPoly &poly = polys[mp_index];
int *e2l;
int ml_curr_index = poly.loopstart;
const int ml_last_index = (ml_curr_index + poly.totloop) - 1;
for (const int poly_i : polys.index_range()) {
const MPoly &poly = polys[poly_i];
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
const int vert_i = loops[loop_index].v;
const int edge_i = loops[loop_index].e;
const MLoop *ml_curr = &loops[ml_curr_index];
for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++) {
e2l = edge_to_loops[ml_curr->e];
/* Pre-populate all loop normals as if their verts were all-smooth,
* this way we don't have to compute those later!
*/
if (!loopnors.is_empty()) {
copy_v3_v3(loopnors[ml_curr_index], data->vert_normals[ml_curr->v]);
}
int2 &e2l = edge_to_loops[edge_i];
/* Check whether current edge might be smooth or sharp */
if ((e2l[0] | e2l[1]) == 0) {
/* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */
e2l[0] = ml_curr_index;
e2l[0] = loop_index;
/* We have to check this here too, else we might miss some flat faces!!! */
e2l[1] = (poly.flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID;
}
else if (e2l[1] == INDEX_UNSET) {
const bool is_angle_sharp = (check_angle &&
dot_v3v3(polynors[loop_to_poly[e2l[0]]], polynors[mp_index]) <
split_angle_cos);
dot_v3v3(poly_normals[loop_to_poly_map[e2l[0]]],
poly_normals[poly_i]) < split_angle_cos);
/* Second loop using this edge, time to test its sharpness.
* An edge is sharp if it is tagged as such, or its face is not smooth,
* or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the
* same vertex, or angle between both its polys' normals is above split_angle value.
*/
if (!(poly.flag & ME_SMOOTH) || (edges[ml_curr->e].flag & ME_SHARP) ||
ml_curr->v == loops[e2l[0]].v || is_angle_sharp) {
if (!(poly.flag & ME_SMOOTH) || (edges[edge_i].flag & ME_SHARP) ||
vert_i == loops[e2l[0]].v || is_angle_sharp) {
/* NOTE: we are sure that loop != 0 here ;). */
e2l[1] = INDEX_INVALID;
/* We want to avoid tagging edges as sharp when it is already defined as such by
* other causes than angle threshold. */
if (do_sharp_edges_tag && is_angle_sharp) {
sharp_edges[ml_curr->e].set();
if (r_sharp_edges && is_angle_sharp) {
(*r_sharp_edges)[edge_i].set();
}
}
else {
e2l[1] = ml_curr_index;
e2l[1] = loop_index;
}
}
else if (!IS_EDGE_SHARP(e2l)) {
@ -865,27 +847,16 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
/* We want to avoid tagging edges as sharp when it is already defined as such by
* other causes than angle threshold. */
if (do_sharp_edges_tag) {
sharp_edges[ml_curr->e].reset();
if (r_sharp_edges) {
(*r_sharp_edges)[edge_i].reset();
}
}
/* Else, edge is already 'disqualified' (i.e. sharp)! */
}
}
/* If requested, do actual tagging of edges as sharp in another loop. */
if (do_sharp_edges_tag) {
for (const int i : edges.index_range()) {
if (sharp_edges[i]) {
edges[i].flag |= ME_SHARP;
}
}
}
}
void BKE_edges_sharp_from_angle_set(const float (*positions)[3],
const int numVerts,
struct MEdge *medges,
void BKE_edges_sharp_from_angle_set(MEdge *medges,
const int numEdges,
const MLoop *mloops,
const int numLoops,
@ -902,25 +873,30 @@ void BKE_edges_sharp_from_angle_set(const float (*positions)[3],
}
/* Mapping edge -> loops. See #BKE_mesh_normals_loop_split for details. */
int(*edge_to_loops)[2] = (int(*)[2])MEM_calloc_arrayN(
size_t(numEdges), sizeof(*edge_to_loops), __func__);
Array<int2> edge_to_loops(numEdges, int2(0));
/* Simple mapping from a loop to its polygon index. */
const Array<int> loop_to_poly = mesh_topology::build_loop_to_poly_map({mpolys, numPolys},
numLoops);
LoopSplitTaskDataCommon common_data = {};
common_data.positions = {reinterpret_cast<const float3 *>(positions), numVerts};
common_data.edges = {medges, numEdges};
common_data.polys = {mpolys, numPolys};
common_data.loops = {mloops, numLoops};
common_data.edge_to_loops = edge_to_loops;
common_data.loop_to_poly = loop_to_poly;
common_data.polynors = {reinterpret_cast<const float3 *>(polynors), numPolys};
BitVector<> sharp_edges(numEdges, false);
mesh_edges_sharp_tag({medges, numEdges},
{mpolys, numPolys},
{mloops, numLoops},
loop_to_poly,
{reinterpret_cast<const float3 *>(polynors), numPolys},
true,
split_angle,
edge_to_loops,
&sharp_edges);
mesh_edges_sharp_tag(&common_data, true, split_angle, true);
MEM_freeN(edge_to_loops);
threading::parallel_for(IndexRange(numEdges), 4096, [&](const IndexRange range) {
for (const int edge_i : range) {
if (sharp_edges[edge_i]) {
medges[edge_i].flag |= ME_SHARP;
}
}
});
}
static void loop_manifold_fan_around_vert_next(const Span<MLoop> loops,
@ -1038,7 +1014,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
const Span<MEdge> edges = common_data->edges;
const Span<MPoly> polys = common_data->polys;
const Span<MLoop> loops = common_data->loops;
const int(*edge_to_loops)[2] = common_data->edge_to_loops;
const Span<int2> edge_to_loops = common_data->edge_to_loops;
const Span<int> loop_to_poly = common_data->loop_to_poly;
const Span<float3> polynors = common_data->polynors;
@ -1285,7 +1261,7 @@ static void loop_split_worker(TaskPool *__restrict pool, void *taskdata)
*/
static bool loop_split_generator_check_cyclic_smooth_fan(const Span<MLoop> mloops,
const Span<MPoly> mpolys,
const int (*edge_to_loops)[2],
const Span<int2> edge_to_loops,
const Span<int> loop_to_poly,
const int *e2l_prev,
BitVector<> &skip_loops,
@ -1359,7 +1335,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
const Span<MLoop> loops = common_data->loops;
const Span<MPoly> polys = common_data->polys;
const Span<int> loop_to_poly = common_data->loop_to_poly;
const int(*edge_to_loops)[2] = common_data->edge_to_loops;
const Span<int2> edge_to_loops = common_data->edge_to_loops;
BitVector<> skip_loops(loops.size(), false);
@ -1577,8 +1553,7 @@ void BKE_mesh_normals_loop_split(const float (*positions)[3],
* However, if needed, we can store the negated value of loop index instead of INDEX_INVALID
* to retrieve the real value later in code).
* Note also that loose edges always have both values set to 0! */
int(*edge_to_loops)[2] = (int(*)[2])MEM_calloc_arrayN(
size_t(numEdges), sizeof(*edge_to_loops), __func__);
Array<int2> edge_to_loops(numEdges, int2(0));
/* Simple mapping from a loop to its polygon index. */
Span<int> loop_to_poly;
@ -1608,22 +1583,44 @@ void BKE_mesh_normals_loop_split(const float (*positions)[3],
BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops, MLNOR_SPACEARR_LOOP_INDEX);
}
const Span<MPoly> polys(mpolys, numPolys);
const Span<MLoop> loops(mloops, numLoops);
/* Init data common to all tasks. */
LoopSplitTaskDataCommon common_data;
common_data.lnors_spacearr = r_lnors_spacearr;
common_data.loopnors = {reinterpret_cast<float3 *>(r_loopnors), numLoops};
common_data.clnors_data = {reinterpret_cast<short2 *>(clnors_data), clnors_data ? numLoops : 0};
common_data.positions = {reinterpret_cast<const float3 *>(positions), numVerts};
common_data.edges = {const_cast<MEdge *>(medges), numEdges};
common_data.polys = {mpolys, numPolys};
common_data.loops = {mloops, numLoops};
common_data.edges = {medges, numEdges};
common_data.polys = polys;
common_data.loops = loops;
common_data.edge_to_loops = edge_to_loops;
common_data.loop_to_poly = loop_to_poly;
common_data.polynors = {reinterpret_cast<const float3 *>(polynors), numPolys};
common_data.vert_normals = {reinterpret_cast<const float3 *>(vert_normals), numVerts};
/* Pre-populate all loop normals as if their verts were all smooth.
* This way we don't have to compute those later! */
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
for (const int poly_i : range) {
const MPoly &poly = polys[poly_i];
for (const int loop_i : IndexRange(poly.loopstart, poly.totloop)) {
copy_v3_v3(r_loopnors[loop_i], vert_normals[loops[loop_i].v]);
}
}
});
/* This first loop check which edges are actually smooth, and compute edge vectors. */
mesh_edges_sharp_tag(&common_data, check_angle, split_angle, false);
mesh_edges_sharp_tag({medges, numEdges},
polys,
loops,
loop_to_poly,
{reinterpret_cast<const float3 *>(polynors), numPolys},
check_angle,
split_angle,
edge_to_loops,
nullptr);
if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
/* Not enough loops to be worth the whole threading overhead. */
@ -1639,8 +1636,6 @@ void BKE_mesh_normals_loop_split(const float (*positions)[3],
BLI_task_pool_free(task_pool);
}
MEM_freeN(edge_to_loops);
if (r_lnors_spacearr) {
if (r_lnors_spacearr == &_lnors_spacearr) {
BKE_lnor_spacearr_free(r_lnors_spacearr);
@ -1737,7 +1732,10 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
* matching given custom lnors.
* Note this code *will never* unsharp edges! And quite obviously,
* when we set custom normals per vertices, running this is absolutely useless. */
if (!use_vertices) {
if (use_vertices) {
done_loops.fill(true);
}
else {
for (int i = 0; i < numLoops; i++) {
if (!lnors_spacearr.lspacearr[i]) {
/* This should not happen in theory, but in some rare case (probably ugly geometry)
@ -1749,70 +1747,71 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
}
continue;
}
if (done_loops[i]) {
continue;
}
if (!done_loops[i]) {
/* Notes:
* - In case of mono-loop smooth fan, we have nothing to do.
* - Loops in this linklist are ordered (in reversed order compared to how they were
* discovered by BKE_mesh_normals_loop_split(), but this is not a problem).
* Which means if we find a mismatching clnor,
* we know all remaining loops will have to be in a new, different smooth fan/lnor space.
* - In smooth fan case, we compare each clnor against a ref one,
* to avoid small differences adding up into a real big one in the end!
*/
if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
done_loops[i].set();
continue;
/* Notes:
* - In case of mono-loop smooth fan, we have nothing to do.
* - Loops in this linklist are ordered (in reversed order compared to how they were
* discovered by BKE_mesh_normals_loop_split(), but this is not a problem).
* Which means if we find a mismatching clnor,
* we know all remaining loops will have to be in a new, different smooth fan/lnor space.
* - In smooth fan case, we compare each clnor against a ref one,
* to avoid small differences adding up into a real big one in the end!
*/
if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
done_loops[i].set();
continue;
}
LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
const MLoop *prev_ml = nullptr;
const float *org_nor = nullptr;
while (loops) {
const int lidx = POINTER_AS_INT(loops->link);
const MLoop *ml = &mloops[lidx];
const int nidx = lidx;
float *nor = r_custom_loopnors[nidx];
if (!org_nor) {
org_nor = nor;
}
else if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
/* Current normal differs too much from org one, we have to tag the edge between
* previous loop's face and current's one as sharp.
* We know those two loops do not point to the same edge,
* since we do not allow reversed winding in a same smooth fan. */
const MPoly *mp = &mpolys[loop_to_poly[lidx]];
const MLoop *mlp =
&mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
org_nor = nor;
}
LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
const MLoop *prev_ml = nullptr;
const float *org_nor = nullptr;
prev_ml = ml;
loops = loops->next;
done_loops[lidx].set();
}
while (loops) {
const int lidx = POINTER_AS_INT(loops->link);
const MLoop *ml = &mloops[lidx];
const int nidx = lidx;
float *nor = r_custom_loopnors[nidx];
/* We also have to check between last and first loops,
* otherwise we may miss some sharp edges here!
* This is just a simplified version of above while loop.
* See T45984. */
loops = lnors_spacearr.lspacearr[i]->loops;
if (loops && org_nor) {
const int lidx = POINTER_AS_INT(loops->link);
const MLoop *ml = &mloops[lidx];
const int nidx = lidx;
float *nor = r_custom_loopnors[nidx];
if (!org_nor) {
org_nor = nor;
}
else if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
/* Current normal differs too much from org one, we have to tag the edge between
* previous loop's face and current's one as sharp.
* We know those two loops do not point to the same edge,
* since we do not allow reversed winding in a same smooth fan. */
const MPoly *mp = &mpolys[loop_to_poly[lidx]];
const MLoop *mlp =
&mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
org_nor = nor;
}
prev_ml = ml;
loops = loops->next;
done_loops[lidx].set();
}
/* We also have to check between last and first loops,
* otherwise we may miss some sharp edges here!
* This is just a simplified version of above while loop.
* See T45984. */
loops = lnors_spacearr.lspacearr[i]->loops;
if (loops && org_nor) {
const int lidx = POINTER_AS_INT(loops->link);
const MLoop *ml = &mloops[lidx];
const int nidx = lidx;
float *nor = r_custom_loopnors[nidx];
if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
const MPoly *mp = &mpolys[loop_to_poly[lidx]];
const MLoop *mlp =
&mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
}
if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
const MPoly *mp = &mpolys[loop_to_poly[lidx]];
const MLoop *mlp =
&mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
}
}
}
@ -1836,9 +1835,6 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
&lnors_spacearr,
nullptr);
}
else {
done_loops.fill(true);
}
/* And we just have to convert plain object-space custom normals to our
* lnor space-encoded ones. */

View File

@ -509,20 +509,15 @@ static void determine_group_output_states(const bNodeTree &tree,
FieldInferencingInterface &new_inferencing_interface,
const Span<SocketFieldState> field_state_by_socket_id)
{
for (const bNode *group_output_node : tree.nodes_by_type("NodeGroupOutput")) {
/* Ignore inactive group output nodes. */
if (!(group_output_node->flag & NODE_DO_OUTPUT)) {
continue;
}
/* Determine dependencies of all group outputs. */
for (const bNodeSocket *group_output_socket :
group_output_node->input_sockets().drop_back(1)) {
OutputFieldDependency field_dependency = find_group_output_dependencies(
*group_output_socket, field_state_by_socket_id);
new_inferencing_interface.outputs[group_output_socket->index()] = std::move(
field_dependency);
}
break;
const bNode *group_output_node = tree.group_output_node();
if (!group_output_node) {
return;
}
for (const bNodeSocket *group_output_socket : group_output_node->input_sockets().drop_back(1)) {
OutputFieldDependency field_dependency = find_group_output_dependencies(
*group_output_socket, field_state_by_socket_id);
new_inferencing_interface.outputs[group_output_socket->index()] = std::move(field_dependency);
}
}

View File

@ -883,13 +883,13 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
if (ob->id.lib) {
BLO_reportf_wrap(reports,
RPT_INFO,
TIP_("Proxy lost from object %s lib %s\n"),
TIP_("Proxy lost from object %s lib %s\n"),
ob->id.name + 2,
ob->id.lib->filepath);
}
else {
BLO_reportf_wrap(
reports, RPT_INFO, TIP_("Proxy lost from object %s lib <NONE>\n"), ob->id.name + 2);
reports, RPT_INFO, TIP_("Proxy lost from object %s lib <NONE>\n"), ob->id.name + 2);
}
reports->count.missing_obproxies++;
}

View File

@ -478,8 +478,13 @@ static void studiolight_create_equirect_radiance_gputexture(StudioLight *sl)
BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
ImBuf *ibuf = sl->equirect_radiance_buffer;
sl->equirect_radiance_gputexture = GPU_texture_create_2d(
"studiolight_radiance", ibuf->x, ibuf->y, 1, GPU_RGBA16F, ibuf->rect_float);
sl->equirect_radiance_gputexture = GPU_texture_create_2d_ex("studiolight_radiance",
ibuf->x,
ibuf->y,
1,
GPU_RGBA16F,
GPU_TEXTURE_USAGE_SHADER_READ,
ibuf->rect_float);
GPUTexture *tex = sl->equirect_radiance_gputexture;
GPU_texture_filter_mode(tex, true);
GPU_texture_wrap_mode(tex, true, true);
@ -499,7 +504,8 @@ static void studiolight_create_matcap_gputexture(StudioLightImage *sli)
copy_v3_v3(*offset3, *offset4);
}
sli->gputexture = GPU_texture_create_2d("matcap", ibuf->x, ibuf->y, 1, GPU_R11F_G11F_B10F, NULL);
sli->gputexture = GPU_texture_create_2d_ex(
"matcap", ibuf->x, ibuf->y, 1, GPU_R11F_G11F_B10F, GPU_TEXTURE_USAGE_SHADER_READ, NULL);
GPU_texture_update(sli->gputexture, GPU_DATA_FLOAT, gpu_matcap_3components);
MEM_SAFE_FREE(gpu_matcap_3components);
@ -533,8 +539,13 @@ static void studiolight_create_equirect_irradiance_gputexture(StudioLight *sl)
if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED);
ImBuf *ibuf = sl->equirect_irradiance_buffer;
sl->equirect_irradiance_gputexture = GPU_texture_create_2d(
"studiolight_irradiance", ibuf->x, ibuf->y, 1, GPU_RGBA16F, ibuf->rect_float);
sl->equirect_irradiance_gputexture = GPU_texture_create_2d_ex("studiolight_irradiance",
ibuf->x,
ibuf->y,
1,
GPU_RGBA16F,
GPU_TEXTURE_USAGE_SHADER_READ,
ibuf->rect_float);
GPUTexture *tex = sl->equirect_irradiance_gputexture;
GPU_texture_filter_mode(tex, true);
GPU_texture_wrap_mode(tex, true, true);

View File

@ -990,6 +990,15 @@ class Map {
occupied_and_removed_slots_ = 0;
}
/**
* Removes all key-value-pairs from the map and frees any allocated memory.
*/
void clear_and_shrink()
{
std::destroy_at(this);
new (this) Map(NoExceptConstructor{});
}
/**
* Get the number of collisions that the probing strategy has to go through to find the key or
* determine that it is not in the map.

View File

@ -4,11 +4,9 @@
/** \file
* \ingroup bli
* Some of the functions below have very similar alternatives in the standard library. However, it
* is rather annoying to use those when debugging. Therefore, some more specialized and easier to
* debug functions are provided here.
*/
#include <algorithm>
#include <memory>
#include <new>
#include <type_traits>
@ -33,280 +31,66 @@ template<typename T>
inline constexpr bool is_trivially_move_constructible_extended_v =
is_trivial_extended_v<T> || std::is_trivially_move_constructible_v<T>;
/**
* Call the destructor on n consecutive values. For trivially destructible types, this does
* nothing.
*
* Exception Safety: Destructors shouldn't throw exceptions.
*
* Before:
* ptr: initialized
* After:
* ptr: uninitialized
*/
template<typename T> void destruct_n(T *ptr, int64_t n)
{
BLI_assert(n >= 0);
static_assert(std::is_nothrow_destructible_v<T>,
"This should be true for all types. Destructors are noexcept by default.");
/* This is not strictly necessary, because the loop below will be optimized away anyway. It is
* nice to make behavior this explicitly, though. */
if (is_trivially_destructible_extended_v<T>) {
return;
}
for (int64_t i = 0; i < n; i++) {
ptr[i].~T();
}
std::destroy_n(ptr, n);
}
/**
* Call the default constructor on n consecutive elements. For trivially constructible types, this
* does nothing.
*
* Exception Safety: Strong.
*
* Before:
* ptr: uninitialized
* After:
* ptr: initialized
*/
template<typename T> void default_construct_n(T *ptr, int64_t n)
{
BLI_assert(n >= 0);
/* This is not strictly necessary, because the loop below will be optimized away anyway. It is
* nice to make behavior this explicitly, though. */
if (std::is_trivially_constructible_v<T>) {
return;
}
int64_t current = 0;
try {
for (; current < n; current++) {
new (static_cast<void *>(ptr + current)) T;
}
}
catch (...) {
destruct_n(ptr, current);
throw;
}
std::uninitialized_default_construct_n(ptr, n);
}
/**
* Copy n values from src to dst.
*
* Exception Safety: Basic.
*
* Before:
* src: initialized
* dst: initialized
* After:
* src: initialized
* dst: initialized
*/
template<typename T> void initialized_copy_n(const T *src, int64_t n, T *dst)
{
BLI_assert(n >= 0);
for (int64_t i = 0; i < n; i++) {
dst[i] = src[i];
}
std::copy_n(src, n, dst);
}
/**
* Copy n values from src to dst.
*
* Exception Safety: Strong.
*
* Before:
* src: initialized
* dst: uninitialized
* After:
* src: initialized
* dst: initialized
*/
template<typename T> void uninitialized_copy_n(const T *src, int64_t n, T *dst)
{
BLI_assert(n >= 0);
int64_t current = 0;
try {
for (; current < n; current++) {
new (static_cast<void *>(dst + current)) T(src[current]);
}
}
catch (...) {
destruct_n(dst, current);
throw;
}
std::uninitialized_copy_n(src, n, dst);
}
/**
* Convert n values from type `From` to type `To`.
*
* Exception Safety: Strong.
*
* Before:
* src: initialized
* dst: uninitialized
* After:
* src: initialized
* dst: initialized
*/
template<typename From, typename To>
void uninitialized_convert_n(const From *src, int64_t n, To *dst)
{
BLI_assert(n >= 0);
int64_t current = 0;
try {
for (; current < n; current++) {
new (static_cast<void *>(dst + current)) To(static_cast<To>(src[current]));
}
}
catch (...) {
destruct_n(dst, current);
throw;
}
std::uninitialized_copy_n(src, n, dst);
}
/**
* Move n values from src to dst.
*
* Exception Safety: Basic.
*
* Before:
* src: initialized
* dst: initialized
* After:
* src: initialized, moved-from
* dst: initialized
*/
template<typename T> void initialized_move_n(T *src, int64_t n, T *dst)
{
BLI_assert(n >= 0);
for (int64_t i = 0; i < n; i++) {
dst[i] = std::move(src[i]);
}
std::copy_n(std::make_move_iterator(src), n, dst);
}
/**
* Move n values from src to dst.
*
* Exception Safety: Basic.
*
* Before:
* src: initialized
* dst: uninitialized
* After:
* src: initialized, moved-from
* dst: initialized
*/
template<typename T> void uninitialized_move_n(T *src, int64_t n, T *dst)
{
BLI_assert(n >= 0);
int64_t current = 0;
try {
for (; current < n; current++) {
new (static_cast<void *>(dst + current)) T(std::move(src[current]));
}
}
catch (...) {
destruct_n(dst, current);
throw;
}
std::uninitialized_copy_n(std::make_move_iterator(src), n, dst);
}
/**
* Relocate n values from src to dst. Relocation is a move followed by destruction of the src
* value.
*
* Exception Safety: Basic.
*
* Before:
* src: initialized
* dst: initialized
* After:
* src: uninitialized
* dst: initialized
*/
template<typename T> void initialized_relocate_n(T *src, int64_t n, T *dst)
{
BLI_assert(n >= 0);
initialized_move_n(src, n, dst);
destruct_n(src, n);
}
/**
* Relocate n values from src to dst. Relocation is a move followed by destruction of the src
* value.
*
* Exception Safety: Basic.
*
* Before:
* src: initialized
* dst: uninitialized
* After:
* src: uninitialized
* dst: initialized
*/
template<typename T> void uninitialized_relocate_n(T *src, int64_t n, T *dst)
{
BLI_assert(n >= 0);
uninitialized_move_n(src, n, dst);
destruct_n(src, n);
}
/**
* Copy the value to n consecutive elements.
*
* Exception Safety: Basic.
*
* Before:
* dst: initialized
* After:
* dst: initialized
*/
template<typename T> void initialized_fill_n(T *dst, int64_t n, const T &value)
{
BLI_assert(n >= 0);
for (int64_t i = 0; i < n; i++) {
dst[i] = value;
}
std::fill_n(dst, n, value);
}
/**
* Copy the value to n consecutive elements.
*
* Exception Safety: Strong.
*
* Before:
* dst: uninitialized
* After:
* dst: initialized
*/
template<typename T> void uninitialized_fill_n(T *dst, int64_t n, const T &value)
{
BLI_assert(n >= 0);
int64_t current = 0;
try {
for (; current < n; current++) {
new (static_cast<void *>(dst + current)) T(value);
}
}
catch (...) {
destruct_n(dst, current);
throw;
}
std::uninitialized_fill_n(dst, n, value);
}
template<typename T> struct DestructValueAtAddress {

View File

@ -150,6 +150,11 @@ template<typename Key, typename Value> class MultiValueMap {
{
map_.clear();
}
void clear_and_shrink()
{
map_.clear_and_shrink();
}
};
} // namespace blender

View File

@ -542,6 +542,15 @@ class Set {
occupied_and_removed_slots_ = 0;
}
/**
* Removes all keys from the set and frees any allocated memory.
*/
void clear_and_shrink()
{
std::destroy_at(this);
new (this) Set(NoExceptConstructor{});
}
/**
* Creates a new slot array and reinserts all keys inside of that. This method can be used to get
* rid of removed slots. Also this is useful for benchmarking the grow function.

View File

@ -329,6 +329,15 @@ class Stack {
top_ = top_chunk_->begin;
}
/**
* Removes all elements from the stack and frees any allocated memory.
*/
void clear_and_shrink()
{
std::destroy_at(this);
new (this) Stack(NoExceptConstructor{});
}
/* This should only be called by unit tests. */
bool is_invariant_maintained() const
{

View File

@ -410,7 +410,7 @@ class Vector {
* Afterwards the vector has 0 elements and any allocated memory
* will be freed.
*/
void clear_and_make_inline()
void clear_and_shrink()
{
destruct_n(begin_, this->size());
if (!this->is_inline()) {

View File

@ -560,6 +560,15 @@ class VectorSet {
occupied_and_removed_slots_ = 0;
}
/**
* Removes all keys from the set and frees any allocated memory.
*/
void clear_and_shrink()
{
std::destroy_at(this);
new (this) VectorSet(NoExceptConstructor{});
}
/**
* Get the number of collisions that the probing strategy has to go through to find the key or
* determine that it is not in the set.

View File

@ -272,7 +272,7 @@ set(SRC
BLI_math_matrix.h
BLI_math_mpq.hh
BLI_math_rotation.h
BLI_math_rotation.hh
BLI_math_rotation_legacy.hh
BLI_math_solvers.h
BLI_math_statistics.h
BLI_math_time.h

View File

@ -5,7 +5,7 @@
*/
#include "BLI_math_base.h"
#include "BLI_math_rotation.hh"
#include "BLI_math_rotation_legacy.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"

View File

@ -5,7 +5,7 @@
#include "BLI_math_base.h"
#include "BLI_math_matrix.h"
#include "BLI_math_rotation.h"
#include "BLI_math_rotation.hh"
#include "BLI_math_rotation_legacy.hh"
#include "BLI_math_vector.hh"
#include "BLI_vector.hh"

View File

@ -7,121 +7,6 @@
namespace blender::tests {
namespace {
struct MyValue {
static inline int alive = 0;
MyValue()
{
if (alive == 15) {
throw std::exception();
}
alive++;
}
MyValue(const MyValue & /*other*/)
{
if (alive == 15) {
throw std::exception();
}
alive++;
}
~MyValue()
{
alive--;
}
};
} // namespace
TEST(memory_utils, DefaultConstructN_ActuallyCallsConstructor)
{
constexpr int amount = 10;
TypedBuffer<MyValue, amount> buffer;
EXPECT_EQ(MyValue::alive, 0);
default_construct_n(buffer.ptr(), amount);
EXPECT_EQ(MyValue::alive, amount);
destruct_n(buffer.ptr(), amount);
EXPECT_EQ(MyValue::alive, 0);
}
TEST(memory_utils, DefaultConstructN_StrongExceptionSafety)
{
constexpr int amount = 20;
TypedBuffer<MyValue, amount> buffer;
EXPECT_EQ(MyValue::alive, 0);
EXPECT_THROW(default_construct_n(buffer.ptr(), amount), std::exception);
EXPECT_EQ(MyValue::alive, 0);
}
TEST(memory_utils, UninitializedCopyN_ActuallyCopies)
{
constexpr int amount = 5;
TypedBuffer<MyValue, amount> buffer1;
TypedBuffer<MyValue, amount> buffer2;
EXPECT_EQ(MyValue::alive, 0);
default_construct_n(buffer1.ptr(), amount);
EXPECT_EQ(MyValue::alive, amount);
uninitialized_copy_n(buffer1.ptr(), amount, buffer2.ptr());
EXPECT_EQ(MyValue::alive, 2 * amount);
destruct_n(buffer1.ptr(), amount);
EXPECT_EQ(MyValue::alive, amount);
destruct_n(buffer2.ptr(), amount);
EXPECT_EQ(MyValue::alive, 0);
}
TEST(memory_utils, UninitializedCopyN_StrongExceptionSafety)
{
constexpr int amount = 10;
TypedBuffer<MyValue, amount> buffer1;
TypedBuffer<MyValue, amount> buffer2;
EXPECT_EQ(MyValue::alive, 0);
default_construct_n(buffer1.ptr(), amount);
EXPECT_EQ(MyValue::alive, amount);
EXPECT_THROW(uninitialized_copy_n(buffer1.ptr(), amount, buffer2.ptr()), std::exception);
EXPECT_EQ(MyValue::alive, amount);
destruct_n(buffer1.ptr(), amount);
EXPECT_EQ(MyValue::alive, 0);
}
TEST(memory_utils, UninitializedFillN_ActuallyCopies)
{
constexpr int amount = 10;
TypedBuffer<MyValue, amount> buffer;
EXPECT_EQ(MyValue::alive, 0);
{
MyValue value;
EXPECT_EQ(MyValue::alive, 1);
uninitialized_fill_n(buffer.ptr(), amount, value);
EXPECT_EQ(MyValue::alive, 1 + amount);
destruct_n(buffer.ptr(), amount);
EXPECT_EQ(MyValue::alive, 1);
}
EXPECT_EQ(MyValue::alive, 0);
}
TEST(memory_utils, UninitializedFillN_StrongExceptionSafety)
{
constexpr int amount = 20;
TypedBuffer<MyValue, amount> buffer;
EXPECT_EQ(MyValue::alive, 0);
{
MyValue value;
EXPECT_EQ(MyValue::alive, 1);
EXPECT_THROW(uninitialized_fill_n(buffer.ptr(), amount, value), std::exception);
EXPECT_EQ(MyValue::alive, 1);
}
EXPECT_EQ(MyValue::alive, 0);
}
class TestBaseClass {
virtual void mymethod(){};
};

View File

@ -301,7 +301,7 @@ static void oldnewmap_clear(OldNewMap *onm)
MEM_freeN(new_addr.newp);
}
}
onm->map.clear();
onm->map.clear_and_shrink();
}
static void oldnewmap_free(OldNewMap *onm)

View File

@ -266,7 +266,7 @@ static void opencl_initialize(const bool use_opencl)
static void opencl_deinitialize()
{
g_work_scheduler.opencl.devices.clear_and_make_inline();
g_work_scheduler.opencl.devices.clear_and_shrink();
if (g_work_scheduler.opencl.program) {
clReleaseProgram(g_work_scheduler.opencl.program);
@ -364,7 +364,7 @@ static void threading_model_queue_deinitialize()
{
/* deinitialize CPU threads */
if (g_work_scheduler.queue.initialized) {
g_work_scheduler.queue.devices.clear_and_make_inline();
g_work_scheduler.queue.devices.clear_and_shrink();
BLI_thread_local_delete(g_thread_device);
g_work_scheduler.queue.initialized = false;

View File

@ -60,8 +60,10 @@ set(SRC
COM_utilities.hh
algorithms/intern/algorithm_parallel_reduction.cc
algorithms/intern/symmetric_separable_blur.cc
algorithms/COM_algorithm_parallel_reduction.hh
algorithms/COM_algorithm_symmetric_separable_blur.hh
cached_resources/intern/morphological_distance_feather_weights.cc
cached_resources/intern/symmetric_blur_weights.cc
@ -96,6 +98,14 @@ set(GLSL_SRC
shaders/compositor_ellipse_mask.glsl
shaders/compositor_filter.glsl
shaders/compositor_flip.glsl
shaders/compositor_glare_ghost_accumulate.glsl
shaders/compositor_glare_ghost_base.glsl
shaders/compositor_glare_highlights.glsl
shaders/compositor_glare_mix.glsl
shaders/compositor_glare_simple_star_anti_diagonal_pass.glsl
shaders/compositor_glare_simple_star_diagonal_pass.glsl
shaders/compositor_glare_simple_star_horizontal_pass.glsl
shaders/compositor_glare_simple_star_vertical_pass.glsl
shaders/compositor_image_crop.glsl
shaders/compositor_morphological_distance.glsl
shaders/compositor_morphological_distance_feather.glsl
@ -129,6 +139,7 @@ set(GLSL_SRC
shaders/library/gpu_shader_compositor_gamma.glsl
shaders/library/gpu_shader_compositor_hue_correct.glsl
shaders/library/gpu_shader_compositor_hue_saturation_value.glsl
shaders/library/gpu_shader_compositor_image_diagonals.glsl
shaders/library/gpu_shader_compositor_invert.glsl
shaders/library/gpu_shader_compositor_luminance_matte.glsl
shaders/library/gpu_shader_compositor_main.glsl
@ -181,6 +192,7 @@ set(SRC_SHADER_CREATE_INFOS
shaders/infos/compositor_ellipse_mask_info.hh
shaders/infos/compositor_filter_info.hh
shaders/infos/compositor_flip_info.hh
shaders/infos/compositor_glare_info.hh
shaders/infos/compositor_image_crop_info.hh
shaders/infos/compositor_morphological_distance_feather_info.hh
shaders/infos/compositor_morphological_distance_info.hh

View File

@ -105,6 +105,11 @@ class Result {
* and release the result's texture. */
Result(ResultType type, TexturePool &texture_pool);
/* Identical to the standard constructor but initializes the reference count to 1. This is useful
* to construct temporary results that are created and released by the developer manually, which
* are typically used in operations that need temporary intermediate results. */
static Result Temporary(ResultType type, TexturePool &texture_pool);
/* Declare the result to be a texture result, allocate a texture of an appropriate type with
* the size of the given domain from the result's texture pool, and set the domain of the result
* to the given domain. */
@ -125,8 +130,9 @@ class Result {
void bind_as_texture(GPUShader *shader, const char *texture_name) const;
/* Bind the texture of the result to the image unit with the given name in the currently bound
* given shader. */
void bind_as_image(GPUShader *shader, const char *image_name) const;
* given shader. If read is true, a memory barrier will be inserted for image reads to ensure any
* prior writes to the images are reflected before reading from it. */
void bind_as_image(GPUShader *shader, const char *image_name, bool read = false) const;
/* Unbind the texture which was previously bound using bind_as_texture. */
void unbind_as_texture() const;

View File

@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "BLI_math_vec_types.hh"
#include "COM_context.hh"
#include "COM_result.hh"
namespace blender::realtime_compositor {
/* Blur the input using a horizontal and a vertical separable blur passes given a certain radius
* and filter type using SymmetricSeparableBlurWeights. The output is written to the given output
* result, which will be allocated internally and is thus expected not to be previously allocated.
* If extend_bounds is true, the output will have an extra radius amount of pixels on the boundary
* of the image, where blurring can take place assuming a fully transparent out of bound values. If
* gamma_correct is true, the input will be gamma corrected before blurring and then uncorrected
* after blurring, using a gamma coefficient of 2. */
void symmetric_separable_blur(Context &context,
Result &input,
Result &output,
float2 radius,
int filter_type,
bool extend_bounds,
bool gamma_correct);
} // namespace blender::realtime_compositor

View File

@ -0,0 +1,132 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_math_base.hh"
#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.hh"
#include "GPU_shader.h"
#include "GPU_texture.h"
#include "COM_context.hh"
#include "COM_utilities.hh"
#include "COM_algorithm_symmetric_separable_blur.hh"
#include "COM_symmetric_separable_blur_weights.hh"
namespace blender::realtime_compositor {
static Result horizontal_pass(Context &context,
Result &input,
float radius,
int filter_type,
bool extend_bounds,
bool gamma_correct)
{
GPUShader *shader = context.shader_manager().get("compositor_symmetric_separable_blur");
GPU_shader_bind(shader);
GPU_shader_uniform_1b(shader, "extend_bounds", extend_bounds);
GPU_shader_uniform_1b(shader, "gamma_correct_input", gamma_correct);
GPU_shader_uniform_1b(shader, "gamma_uncorrect_output", false);
input.bind_as_texture(shader, "input_tx");
const SymmetricSeparableBlurWeights &weights =
context.cache_manager().get_symmetric_separable_blur_weights(filter_type, radius);
weights.bind_as_texture(shader, "weights_tx");
Domain domain = input.domain();
if (extend_bounds) {
domain.size.x += int(math::ceil(radius)) * 2;
}
/* We allocate an output image of a transposed size, that is, with a height equivalent to the
* width of the input and vice versa. This is done as a performance optimization. The shader
* will blur the image horizontally and write it to the intermediate output transposed. Then
* the vertical pass will execute the same horizontal blur shader, but since its input is
* transposed, it will effectively do a vertical blur and write to the output transposed,
* effectively undoing the transposition in the horizontal pass. This is done to improve
* spatial cache locality in the shader and to avoid having two separate shaders for each blur
* pass. */
const int2 transposed_domain = int2(domain.size.y, domain.size.x);
Result output = Result::Temporary(ResultType::Color, context.texture_pool());
output.allocate_texture(transposed_domain);
output.bind_as_image(shader, "output_img");
compute_dispatch_threads_at_least(shader, domain.size);
GPU_shader_unbind();
input.unbind_as_texture();
weights.unbind_as_texture();
output.unbind_as_image();
return output;
}
static void vertical_pass(Context &context,
Result &original_input,
Result &horizontal_pass_result,
Result &output,
float2 radius,
int filter_type,
bool extend_bounds,
bool gamma_correct)
{
GPUShader *shader = context.shader_manager().get("compositor_symmetric_separable_blur");
GPU_shader_bind(shader);
GPU_shader_uniform_1b(shader, "extend_bounds", extend_bounds);
GPU_shader_uniform_1b(shader, "gamma_correct_input", false);
GPU_shader_uniform_1b(shader, "gamma_uncorrect_output", gamma_correct);
horizontal_pass_result.bind_as_texture(shader, "input_tx");
const SymmetricSeparableBlurWeights &weights =
context.cache_manager().get_symmetric_separable_blur_weights(filter_type, radius.y);
weights.bind_as_texture(shader, "weights_tx");
Domain domain = original_input.domain();
if (extend_bounds) {
/* Add a radius amount of pixels in both sides of the image, hence the multiply by 2. */
domain.size += int2(math::ceil(radius)) * 2;
}
output.allocate_texture(domain);
output.bind_as_image(shader, "output_img");
/* Notice that the domain is transposed, see the note on the horizontal pass method for more
* information on the reasoning behind this. */
compute_dispatch_threads_at_least(shader, int2(domain.size.y, domain.size.x));
GPU_shader_unbind();
horizontal_pass_result.unbind_as_texture();
output.unbind_as_image();
weights.unbind_as_texture();
}
void symmetric_separable_blur(Context &context,
Result &input,
Result &output,
float2 radius,
int filter_type,
bool extend_bounds,
bool gamma_correct)
{
Result horizontal_pass_result = horizontal_pass(
context, input, radius.x, filter_type, extend_bounds, gamma_correct);
vertical_pass(context,
input,
horizontal_pass_result,
output,
radius,
filter_type,
extend_bounds,
gamma_correct);
horizontal_pass_result.release();
}
} // namespace blender::realtime_compositor

View File

@ -18,6 +18,13 @@ Result::Result(ResultType type, TexturePool &texture_pool)
{
}
Result Result::Temporary(ResultType type, TexturePool &texture_pool)
{
Result result = Result(type, texture_pool);
result.increment_reference_count();
return result;
}
void Result::allocate_texture(Domain domain)
{
is_single_value_ = false;
@ -79,8 +86,13 @@ void Result::bind_as_texture(GPUShader *shader, const char *texture_name) const
GPU_texture_bind(texture_, texture_image_unit);
}
void Result::bind_as_image(GPUShader *shader, const char *image_name) const
void Result::bind_as_image(GPUShader *shader, const char *image_name, bool read) const
{
/* Make sure any prior writes to the texture are reflected before reading from it. */
if (read) {
GPU_memory_barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
const int image_unit = GPU_shader_get_texture_binding(shader, image_name);
GPU_texture_image_bind(texture_, image_unit);
}

View File

@ -0,0 +1,37 @@
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
void main()
{
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
ivec2 input_size = texture_size(input_ghost_tx);
/* Add 0.5 to evaluate the input sampler at the center of the pixel and divide by the image size
* to get the coordinates into the sampler's expected [0, 1] range*/
vec2 coordinates = (vec2(texel) + vec2(0.5)) / input_size;
/* We accumulate four variants of the input ghost texture, each is scaled by some amount and
* possibly multiplied by some color as a form of color modulation. */
vec4 accumulated_ghost = vec4(0.0);
for (int i = 0; i < 4; i++) {
float scale = scales[i];
vec4 color_modulator = color_modulators[i];
/* Scale the coordinates for the ghost, pre subtract 0.5 and post add 0.5 to use 0.5 as the
* origin of the scaling. */
vec2 scaled_coordinates = (coordinates - 0.5) * scale + 0.5;
/* The value of the ghost is attenuated by a scalar multiple of the inverse distance to the
* center, such that it is maximum at the center and become zero further from the center,
* making sure to take the scale into account. The scaler multiple of 1 / 4 is chosen using
* visual judgement. */
float distance_to_center = distance(coordinates, vec2(0.5)) * 2.0;
float attenuator = max(0.0, 1.0 - distance_to_center * abs(scale)) / 4.0;
/* Accumulate the scaled ghost after attenuating and color modulating its value. */
vec4 multiplier = attenuator * color_modulator;
accumulated_ghost += texture(input_ghost_tx, scaled_coordinates) * multiplier;
}
vec4 current_accumulated_ghost = imageLoad(accumulated_ghost_img, texel);
imageStore(accumulated_ghost_img, texel, current_accumulated_ghost + accumulated_ghost);
}

View File

@ -0,0 +1,37 @@
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
void main()
{
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
ivec2 input_size = texture_size(small_ghost_tx);
/* Add 0.5 to evaluate the input sampler at the center of the pixel and divide by the image size
* to get the coordinates into the sampler's expected [0, 1] range*/
vec2 coordinates = (vec2(texel) + vec2(0.5)) / input_size;
/* The small ghost is scaled down with the origin as the center of the image by a factor of 2.13,
* while the big ghost is flipped and scaled up with the origin as the center of the image by a
* factor of 0.97. Note that 1) The negative scale implements the flipping. 2) Factors larger
* than 1 actually scales down the image since the factor multiplies the coordinates and not the
* images itself. 3) The values are arbitrarily chosen using visual judgement. */
float small_ghost_scale = 2.13;
float big_ghost_scale = -0.97;
/* Scale the coordinates for the small and big ghosts, pre subtract 0.5 and post add 0.5 to use
* 0.5 as the origin of the scaling. Notice that the big ghost is flipped due to the negative
* scale. */
vec2 small_ghost_coordinates = (coordinates - 0.5) * small_ghost_scale + 0.5;
vec2 big_ghost_coordinates = (coordinates - 0.5) * big_ghost_scale + 0.5;
/* The values of the ghosts are attenuated by the inverse distance to the center, such that they
* are maximum at the center and become zero further from the center, making sure to take the
* aforementioned scale into account. */
float distance_to_center = distance(coordinates, vec2(0.5)) * 2.0;
float small_ghost_attenuator = max(0.0, 1.0 - distance_to_center * small_ghost_scale);
float big_ghost_attenuator = max(0.0, 1.0 - distance_to_center * abs(big_ghost_scale));
vec4 small_ghost = texture(small_ghost_tx, small_ghost_coordinates) * small_ghost_attenuator;
vec4 big_ghost = texture(big_ghost_tx, big_ghost_coordinates) * big_ghost_attenuator;
imageStore(combined_ghost_img, texel, small_ghost + big_ghost);
}

View File

@ -0,0 +1,31 @@
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
void main()
{
/* The dispatch domain covers the output image size, which might be a fraction of the input image
* size, so you will notice the output image size used throughout the shader instead of the input
* one. */
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
/* Since the output image might be a fraction of the input image size, and since we want to
* evaluate the input sampler at the center of the output pixel, we add an offset equal to half
* the number of input pixels that covers a single output pixel. In case the input and output
* have the same size, this will be 0.5, which is the offset required to evaluate the sampler at
* the center of the pixel. */
vec2 offset = (texture_size(input_tx) / imageSize(output_img)) / 2.0;
/* Add the aforementioned offset and divide by the output image size to get the coordinates into
* the sampler's expected [0, 1] range. */
vec2 normalized_coordinates = (vec2(texel) + offset) / imageSize(output_img);
vec4 input_color = texture(input_tx, normalized_coordinates);
float luminance = dot(input_color.rgb, luminance_coefficients);
/* The pixel whose luminance is less than the threshold luminance is not considered part of the
* highlights and is given a value of zero. Otherwise, the pixel is considered part of the
* highlights, whose value is the difference to the threshold value clamped to zero. */
bool is_highlights = luminance >= threshold;
vec3 highlights = is_highlights ? max(vec3(0.0), input_color.rgb - threshold) : vec3(0.0);
imageStore(output_img, texel, vec4(highlights, 1.0));
}

View File

@ -0,0 +1,28 @@
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
void main()
{
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
/* Add 0.5 to evaluate the input sampler at the center of the pixel and divide by the input image
* size to get the relevant coordinates into the sampler's expected [0, 1] range. Make sure the
* input color is not negative to avoid a subtractive effect when mixing the glare. */
vec2 normalized_coordinates = (vec2(texel) + vec2(0.5)) / texture_size(input_tx);
vec4 glare_color = texture(glare_tx, normalized_coordinates);
vec4 input_color = max(vec4(0.0), texture_load(input_tx, texel));
/* The mix factor is in the range [-1, 1] and linearly interpolate between the three values such
* that:
* 1 => Glare only.
* 0 => Input + Glare.
* -1 => Input only.
* We implement that as a weighted sum as follows. When the mix factor is 1, the glare weight
* should be 1 and the input weight should be 0. When the mix factor is -1, the glare weight
* should be 0 and the input weight should be 1. When the mix factor is 0, both weights should
* be 1. This can be expressed using the following compact min max expressions. */
float input_weight = 1.0 - max(0.0, mix_factor);
float glare_weight = 1.0 + min(0.0, mix_factor);
vec3 highlights = input_weight * input_color.rgb + glare_weight * glare_color.rgb;
imageStore(output_img, texel, vec4(highlights, input_color.a));
}

View File

@ -0,0 +1,55 @@
#pragma BLENDER_REQUIRE(gpu_shader_compositor_image_diagonals.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
void main()
{
ivec2 size = imageSize(anti_diagonal_img);
int index = int(gl_GlobalInvocationID.x);
int anti_diagonal_length = compute_anti_diagonal_length(size, index);
ivec2 start = compute_anti_diagonal_start(size, index);
ivec2 direction = get_anti_diagonal_direction();
ivec2 end = start + (anti_diagonal_length - 1) * direction;
/* For each iteration, apply a causal filter followed by a non causal filters along the anti
* diagonal mapped to the current thread invocation. */
for (int i = 0; i < iterations; i++) {
/* Causal Pass:
* Sequentially apply a causal filter running from the start of the anti diagonal to its end by
* mixing the value of the pixel in the anti diagonal with the average value of the previous
* output and next input in the same anti diagonal. */
for (int j = 0; j < anti_diagonal_length; j++) {
ivec2 texel = start + j * direction;
vec4 previous_output = imageLoad(anti_diagonal_img, texel - i * direction);
vec4 current_input = imageLoad(anti_diagonal_img, texel);
vec4 next_input = imageLoad(anti_diagonal_img, texel + i * direction);
vec4 neighbour_average = (previous_output + next_input) / 2.0;
vec4 causal_output = mix(current_input, neighbour_average, fade_factor);
imageStore(anti_diagonal_img, texel, causal_output);
}
/* Non Causal Pass:
* Sequentially apply a non causal filter running from the end of the diagonal to its start by
* mixing the value of the pixel in the diagonal with the average value of the previous output
* and next input in the same diagonal. */
for (int j = 0; j < anti_diagonal_length; j++) {
ivec2 texel = end - j * direction;
vec4 previous_output = imageLoad(anti_diagonal_img, texel + i * direction);
vec4 current_input = imageLoad(anti_diagonal_img, texel);
vec4 next_input = imageLoad(anti_diagonal_img, texel - i * direction);
vec4 neighbour_average = (previous_output + next_input) / 2.0;
vec4 non_causal_output = mix(current_input, neighbour_average, fade_factor);
imageStore(anti_diagonal_img, texel, non_causal_output);
}
}
/* For each pixel in the anti diagonal mapped to the current invocation thread, add the result of
* the diagonal pass to the vertical pass. */
for (int j = 0; j < anti_diagonal_length; j++) {
ivec2 texel = start + j * direction;
vec4 horizontal = texture_load(diagonal_tx, texel);
vec4 vertical = imageLoad(anti_diagonal_img, texel);
imageStore(anti_diagonal_img, texel, horizontal + vertical);
}
}

View File

@ -0,0 +1,45 @@
#pragma BLENDER_REQUIRE(gpu_shader_compositor_image_diagonals.glsl)
void main()
{
ivec2 size = imageSize(diagonal_img);
int index = int(gl_GlobalInvocationID.x);
int diagonal_length = compute_diagonal_length(size, index);
ivec2 start = compute_diagonal_start(size, index);
ivec2 direction = get_diagonal_direction();
ivec2 end = start + (diagonal_length - 1) * direction;
/* For each iteration, apply a causal filter followed by a non causal filters along the diagonal
* mapped to the current thread invocation. */
for (int i = 0; i < iterations; i++) {
/* Causal Pass:
* Sequentially apply a causal filter running from the start of the diagonal to its end by
* mixing the value of the pixel in the diagonal with the average value of the previous output
* and next input in the same diagonal. */
for (int j = 0; j < diagonal_length; j++) {
ivec2 texel = start + j * direction;
vec4 previous_output = imageLoad(diagonal_img, texel - i * direction);
vec4 current_input = imageLoad(diagonal_img, texel);
vec4 next_input = imageLoad(diagonal_img, texel + i * direction);
vec4 neighbour_average = (previous_output + next_input) / 2.0;
vec4 causal_output = mix(current_input, neighbour_average, fade_factor);
imageStore(diagonal_img, texel, causal_output);
}
/* Non Causal Pass:
* Sequentially apply a non causal filter running from the end of the diagonal to its start by
* mixing the value of the pixel in the diagonal with the average value of the previous output
* and next input in the same diagonal. */
for (int j = 0; j < diagonal_length; j++) {
ivec2 texel = end - j * direction;
vec4 previous_output = imageLoad(diagonal_img, texel + i * direction);
vec4 current_input = imageLoad(diagonal_img, texel);
vec4 next_input = imageLoad(diagonal_img, texel - i * direction);
vec4 neighbour_average = (previous_output + next_input) / 2.0;
vec4 non_causal_output = mix(current_input, neighbour_average, fade_factor);
imageStore(diagonal_img, texel, non_causal_output);
}
}
}

View File

@ -0,0 +1,38 @@
void main()
{
int width = imageSize(horizontal_img).x;
/* For each iteration, apply a causal filter followed by a non causal filters along the row
* mapped to the current thread invocation. */
for (int i = 0; i < iterations; i++) {
/* Causal Pass:
* Sequentially apply a causal filter running from left to right by mixing the value of the
* pixel in the row with the average value of the previous output and next input in the same
* row. */
for (int x = 0; x < width; x++) {
ivec2 texel = ivec2(x, gl_GlobalInvocationID.x);
vec4 previous_output = imageLoad(horizontal_img, texel - ivec2(i, 0));
vec4 current_input = imageLoad(horizontal_img, texel);
vec4 next_input = imageLoad(horizontal_img, texel + ivec2(i, 0));
vec4 neighbour_average = (previous_output + next_input) / 2.0;
vec4 causal_output = mix(current_input, neighbour_average, fade_factor);
imageStore(horizontal_img, texel, causal_output);
}
/* Non Causal Pass:
* Sequentially apply a non causal filter running from right to left by mixing the value of the
* pixel in the row with the average value of the previous output and next input in the same
* row. */
for (int x = width - 1; x >= 0; x--) {
ivec2 texel = ivec2(x, gl_GlobalInvocationID.x);
vec4 previous_output = imageLoad(horizontal_img, texel + ivec2(i, 0));
vec4 current_input = imageLoad(horizontal_img, texel);
vec4 next_input = imageLoad(horizontal_img, texel - ivec2(i, 0));
vec4 neighbour_average = (previous_output + next_input) / 2.0;
vec4 non_causal_output = mix(current_input, neighbour_average, fade_factor);
imageStore(horizontal_img, texel, non_causal_output);
}
}
}

View File

@ -0,0 +1,49 @@
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
void main()
{
int height = imageSize(vertical_img).y;
/* For each iteration, apply a causal filter followed by a non causal filters along the column
* mapped to the current thread invocation. */
for (int i = 0; i < iterations; i++) {
/* Causal Pass:
* Sequentially apply a causal filter running from bottom to top by mixing the value of the
* pixel in the column with the average value of the previous output and next input in the same
* column. */
for (int y = 0; y < height; y++) {
ivec2 texel = ivec2(gl_GlobalInvocationID.x, y);
vec4 previous_output = imageLoad(vertical_img, texel - ivec2(0, i));
vec4 current_input = imageLoad(vertical_img, texel);
vec4 next_input = imageLoad(vertical_img, texel + ivec2(0, i));
vec4 neighbour_average = (previous_output + next_input) / 2.0;
vec4 causal_output = mix(current_input, neighbour_average, fade_factor);
imageStore(vertical_img, texel, causal_output);
}
/* Non Causal Pass:
* Sequentially apply a non causal filter running from top to bottom by mixing the value of the
* pixel in the column with the average value of the previous output and next input in the same
* column. */
for (int y = height - 1; y >= 0; y--) {
ivec2 texel = ivec2(gl_GlobalInvocationID.x, y);
vec4 previous_output = imageLoad(vertical_img, texel + ivec2(0, i));
vec4 current_input = imageLoad(vertical_img, texel);
vec4 next_input = imageLoad(vertical_img, texel - ivec2(0, i));
vec4 neighbour_average = (previous_output + next_input) / 2.0;
vec4 non_causal_output = mix(current_input, neighbour_average, fade_factor);
imageStore(vertical_img, texel, non_causal_output);
}
}
/* For each pixel in the column mapped to the current invocation thread, add the result of the
* horizontal pass to the vertical pass. */
for (int y = 0; y < height; y++) {
ivec2 texel = ivec2(gl_GlobalInvocationID.x, y);
vec4 horizontal = texture_load(horizontal_tx, texel);
vec4 vertical = imageLoad(vertical_img, texel);
imageStore(vertical_img, texel, horizontal + vertical);
}
}

View File

@ -0,0 +1,84 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_create_info.hh"
/* -------
* Common.
* ------- */
GPU_SHADER_CREATE_INFO(compositor_glare_highlights)
.local_group_size(16, 16)
.push_constant(Type::FLOAT, "threshold")
.push_constant(Type::VEC3, "luminance_coefficients")
.sampler(0, ImageType::FLOAT_2D, "input_tx")
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
.compute_source("compositor_glare_highlights.glsl")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(compositor_glare_mix)
.local_group_size(16, 16)
.push_constant(Type::FLOAT, "mix_factor")
.sampler(0, ImageType::FLOAT_2D, "input_tx")
.sampler(1, ImageType::FLOAT_2D, "glare_tx")
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
.compute_source("compositor_glare_mix.glsl")
.do_static_compilation(true);
/* ------------
* Ghost Glare.
* ------------ */
GPU_SHADER_CREATE_INFO(compositor_glare_ghost_base)
.local_group_size(16, 16)
.sampler(0, ImageType::FLOAT_2D, "small_ghost_tx")
.sampler(1, ImageType::FLOAT_2D, "big_ghost_tx")
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "combined_ghost_img")
.compute_source("compositor_glare_ghost_base.glsl")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(compositor_glare_ghost_accumulate)
.local_group_size(16, 16)
.push_constant(Type::VEC4, "scales")
.push_constant(Type::VEC4, "color_modulators", 4)
.sampler(0, ImageType::FLOAT_2D, "input_ghost_tx")
.image(0, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "accumulated_ghost_img")
.compute_source("compositor_glare_ghost_accumulate.glsl")
.do_static_compilation(true);
/* -----------
* Simple Star
* ----------- */
GPU_SHADER_CREATE_INFO(compositor_glare_simple_star_horizontal_pass)
.local_group_size(16)
.push_constant(Type::INT, "iterations")
.push_constant(Type::FLOAT, "fade_factor")
.image(0, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "horizontal_img")
.compute_source("compositor_glare_simple_star_horizontal_pass.glsl")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(compositor_glare_simple_star_vertical_pass)
.local_group_size(16)
.push_constant(Type::INT, "iterations")
.push_constant(Type::FLOAT, "fade_factor")
.sampler(0, ImageType::FLOAT_2D, "horizontal_tx")
.image(0, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "vertical_img")
.compute_source("compositor_glare_simple_star_vertical_pass.glsl")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(compositor_glare_simple_star_diagonal_pass)
.local_group_size(16)
.push_constant(Type::INT, "iterations")
.push_constant(Type::FLOAT, "fade_factor")
.image(0, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "diagonal_img")
.compute_source("compositor_glare_simple_star_diagonal_pass.glsl")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(compositor_glare_simple_star_anti_diagonal_pass)
.local_group_size(16)
.push_constant(Type::INT, "iterations")
.push_constant(Type::FLOAT, "fade_factor")
.sampler(0, ImageType::FLOAT_2D, "diagonal_tx")
.image(0, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "anti_diagonal_img")
.compute_source("compositor_glare_simple_star_anti_diagonal_pass.glsl")
.do_static_compilation(true);

View File

@ -0,0 +1,170 @@
/* Computes the number of diagonals in the matrix of the given size, where the diagonals are
* indexed from the upper left corner to the lower right corner such that their start is at the
* left and bottom edges of the matrix as shown in the diagram below. The numbers in the diagram
* denote the index of the diagonal. The number of diagonals is then intuitively the number of
* values on the left and bottom edges, which is equal to:
*
* Number Of Diagonals => width + height - 1
*
* Notice that the minus one is due to the shared value in the corner.
*
* Width = 6
* +---+---+---+---+---+---+
* | 0 | 1 | 2 | 3 | 4 | 5 |
* +---+---+---+---+---+---+
* | 1 | 2 | 3 | 4 | 5 | 6 | Height = 3
* +---+---+---+---+---+---+
* | 2 | 3 | 4 | 5 | 6 | 7 |
* +---+---+---+---+---+---+
*/
int compute_number_of_diagonals(ivec2 size)
{
return size.x + size.y - 1;
}
/* Computes the number of values in the diagonal of the given index in the matrix with the given
* size, where the diagonals are indexed from the upper left corner to the lower right corner such
* that their start is at the left and bottom edges of the matrix as shown in the diagram below.
* The numbers in the diagram denote the index of the diagonal and its length.
*
* Width = 6
* +---+---+---+---+---+---+
* 1 | 0 | 1 | 2 | 3 | 4 | 5 |
* +---+---+---+---+---+---+
* 2 | 1 | 2 | 3 | 4 | 5 | 6 | Height = 3
* +---+---+---+---+---+---+
* | 2 | 3 | 4 | 5 | 6 | 7 |
* +---+---+---+---+---+---+
* 3 3 3 3 2 1
*
* To derive the length of the diagonal from the index, we note that the lengths of the diagonals
* start at 1 and linearly increase up to the length of the longest diagonal, then remain constant
* until it linearly decrease to 1 at the end. The length of the longest diagonal is intuitively
* the smaller of the width and height of the matrix. The linearly increasing and constant parts of
* the sequence can be described using the following compact equation:
*
* Length => min(Longest Length, index + 1)
*
* While the constant and deceasing end parts of the sequence can be described using the following
* compact equation:
*
* Length => min(Longest Length, Number Of Diagonals - index)
*
* All three parts of the sequence can then be combined using the minimum operation because they
* all share the same maximum value, that is, the longest length:
*
* Length => min(Longest Length, index + 1, Number Of Diagonals - index)
*
*/
int compute_diagonal_length(ivec2 size, int diagonal_index)
{
int length_of_longest_diagonal = min(size.x, size.y);
int start_sequence = diagonal_index + 1;
int end_sequence = compute_number_of_diagonals(size) - diagonal_index;
return min(length_of_longest_diagonal, min(start_sequence, end_sequence));
}
/* Computes the position of the start of the diagonal of the given index in the matrix with the
* given size, where the diagonals are indexed from the upper left corner to the lower right corner
* such that their start is at the left and bottom edges of the matrix as shown in the diagram
* below. The numbers in the diagram denote the index of the diagonal and the position of its
* start.
*
* Width = 6
* +-----+-----+-----+-----+-----+-----+
* (0, 2) | 0 | 1 | 2 | 3 | 4 | 5 |
* +-----+-----+-----+-----+-----+-----+
* (0, 1) | 1 | 2 | 3 | 4 | 5 | 6 | Height = 3
* +-----+-----+-----+-----+-----+-----+
* | 2 | 3 | 4 | 5 | 6 | 7 |
* +-----+-----+-----+-----+-----+-----+
* (0, 0) (1,0) (2,0) (3,0) (4,0) (5,0)
*
* To derive the start position from the index, we consider each axis separately. For the X
* position, indices up to (height - 1) have zero x positions, while other indices linearly
* increase from (height) to the end. Which can be described using the compact equation:
*
* X => max(0, index - (height - 1))
*
* For the Y position, indices up to (height - 1) linearly decrease from (height - 1) to zero,
* while other indices are zero. Which can be described using the compact equation:
*
* Y => max(0, (height - 1) - index)
*
*/
ivec2 compute_diagonal_start(ivec2 size, int index)
{
return ivec2(max(0, index - (size.y - 1)), max(0, (size.y - 1) - index));
}
/* Computes a direction vector such that when added to the position of a value in a matrix will
* yield the position of the next value in the same diagonal. According to the choice of the start
* of the diagonal in compute_diagonal_start, this is (1, 1). */
ivec2 get_diagonal_direction()
{
return ivec2(1);
}
/* Computes the number of values in the anti diagonal of the given index in the matrix with the
* given size, where the anti diagonals are indexed from the lower left corner to the upper right
* corner such that that their start is at the bottom and right edges of the matrix as shown in the
* diagram below. The numbers in the diagram denote the index of the anti diagonal and its length.
*
* Width = 6
* +---+---+---+---+---+---+
* | 2 | 3 | 4 | 5 | 6 | 7 | 1
* +---+---+---+---+---+---+
* Height = 3 | 1 | 2 | 3 | 4 | 5 | 6 | 2
* +---+---+---+---+---+---+
* | 0 | 1 | 2 | 3 | 4 | 5 |
* +---+---+---+---+---+---+
* 1 2 3 3 3 3
*
* The length of the anti diagonal is identical to the length of the diagonal of the same index, as
* can be seen by comparing the above diagram with the one in the compute_diagonal_length function,
* since the anti diagonals are merely flipped diagonals. */
int compute_anti_diagonal_length(ivec2 size, int diagonal_index)
{
return compute_diagonal_length(size, diagonal_index);
}
/* Computes the position of the start of the anti diagonal of the given index in the matrix with
* the given size, where the anti diagonals are indexed from the lower left corner to the upper
* right corner such that their start is at the bottom and right edges of the matrix as shown in
* the diagram below. The numbers in the diagram denote the index of the anti diagonal and the
* position of its start.
*
* Width = 6
* +-----+-----+-----+-----+-----+-----+
* | 2 | 3 | 4 | 5 | 6 | 7 | (5,2)
* +-----+-----+-----+-----+-----+-----+
* Height = 3 | 1 | 2 | 3 | 4 | 5 | 6 | (5,1)
* +-----+-----+-----+-----+-----+-----+
* | 0 | 1 | 2 | 3 | 4 | 5 |
* +-----+-----+-----+-----+-----+-----+
* (0,0) (1,0) (2,0) (3,0) (4,0) (5,0)
*
* To derive the start position from the index, we consider each axis separately. For the X
* position, indices up to (width - 1) linearly increase from zero, while other indices are all
* (width - 1). Which can be described using the compact equation:
*
* X => min((width - 1), index)
*
* For the Y position, indices up to (width - 1) are zero, while other indices linearly increase
* from zero to (height - 1). Which can be described using the compact equation:
*
* Y => max(0, index - (width - 1))
*
*/
ivec2 compute_anti_diagonal_start(ivec2 size, int index)
{
return ivec2(min(size.x - 1, index), max(0, index - (size.x - 1)));
}
/* Computes a direction vector such that when added to the position of a value in a matrix will
* yield the position of the next value in the same anti diagonal. According to the choice of the
* start of the anti diagonal in compute_anti_diagonal_start, this is (-1, 1). */
ivec2 get_anti_diagonal_direction()
{
return ivec2(-1, 1);
}

View File

@ -256,6 +256,7 @@ set(SRC
engines/eevee/eevee_lightcache.h
engines/eevee/eevee_lut.h
engines/eevee/eevee_private.h
engines/eevee/engine_eevee_shared_defines.h
engines/eevee_next/eevee_camera.hh
engines/eevee_next/eevee_cryptomatte.hh
engines/eevee_next/eevee_depth_of_field.hh
@ -316,6 +317,7 @@ set(GLSL_SRC
engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl
engines/eevee/shaders/lightprobe_geom.glsl
engines/eevee/shaders/lightprobe_vert.glsl
engines/eevee/shaders/lightprobe_vert_no_geom.glsl
engines/eevee/shaders/lightprobe_cube_display_frag.glsl
engines/eevee/shaders/lightprobe_cube_display_vert.glsl
engines/eevee/shaders/lightprobe_grid_display_frag.glsl
@ -381,7 +383,6 @@ set(GLSL_SRC
engines/eevee/shaders/raytrace_lib.glsl
engines/eevee/shaders/renderpass_lib.glsl
engines/eevee/shaders/renderpass_postprocess_frag.glsl
engines/eevee/shaders/cryptomatte_lib.glsl
engines/eevee/shaders/cryptomatte_frag.glsl
engines/eevee/shaders/cryptomatte_vert.glsl
engines/eevee/shaders/ltc_lib.glsl
@ -400,6 +401,8 @@ set(GLSL_SRC
engines/eevee/shaders/volumetric_scatter_frag.glsl
engines/eevee/shaders/volumetric_integration_frag.glsl
engines/eevee/shaders/world_vert.glsl
engines/eevee/shaders/infos/engine_eevee_legacy_shared.h
engines/eevee/engine_eevee_shared_defines.h
engines/eevee_next/shaders/eevee_attributes_lib.glsl
engines/eevee_next/shaders/eevee_camera_lib.glsl
@ -474,9 +477,11 @@ set(GLSL_SRC
engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl
engines/workbench/shaders/workbench_prepass_vert.glsl
engines/workbench/shaders/workbench_shadow_caps_geom.glsl
engines/workbench/shaders/workbench_shadow_caps_vert_no_geom.glsl
engines/workbench/shaders/workbench_shadow_debug_frag.glsl
engines/workbench/shaders/workbench_shadow_geom.glsl
engines/workbench/shaders/workbench_shadow_vert.glsl
engines/workbench/shaders/workbench_shadow_vert_no_geom.glsl
engines/workbench/shaders/workbench_transparent_accum_frag.glsl
engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
engines/workbench/shaders/workbench_volume_frag.glsl
@ -550,6 +555,7 @@ set(GLSL_SRC
engines/basic/shaders/basic_conservative_depth_geom.glsl
engines/basic/shaders/basic_depth_vert.glsl
engines/basic/shaders/basic_depth_vert_conservative_no_geom.glsl
engines/basic/shaders/basic_depth_curves_vert.glsl
engines/basic/shaders/basic_depth_pointcloud_vert.glsl
engines/basic/shaders/basic_depth_frag.glsl
@ -602,6 +608,7 @@ set(GLSL_SRC
engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl
engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl
engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl
engines/overlay/shaders/overlay_edit_uv_edges_vert_no_geom.glsl
engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl
engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl
@ -639,6 +646,7 @@ set(GLSL_SRC
engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl
engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl
engines/overlay/shaders/overlay_outline_prepass_vert.glsl
engines/overlay/shaders/overlay_outline_prepass_vert_no_geom.glsl
engines/overlay/shaders/overlay_paint_face_vert.glsl
engines/overlay/shaders/overlay_paint_point_vert.glsl
engines/overlay/shaders/overlay_paint_texture_frag.glsl

View File

@ -7,9 +7,19 @@ void main()
{
GPU_INTEL_VERTEX_SHADER_WORKAROUND
vec3 world_pos = pointcloud_get_pos();
vec3 world_pos, world_nor;
float world_radius;
pointcloud_get_pos_nor_radius(world_pos, world_nor, world_radius);
gl_Position = point_world_to_ndc(world_pos);
#ifdef CONSERVATIVE_RASTER
/* Avoid expense of geometry shader by ensuring rastered pointcloud primitive
* covers at least a whole pixel. */
int i = gl_VertexID % 3;
vec2 ofs = (i == 0) ? vec2(-1.0) : ((i == 1) ? vec2(2.0, -1.0) : vec2(-1.0, 2.0));
gl_Position.xy += sizeViewportInv * gl_Position.w * ofs;
#endif
view_clipping_distances(world_pos);
}

View File

@ -0,0 +1,75 @@
#pragma USE_SSBO_VERTEX_FETCH(TriangleList, 3)
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
void main()
{
/* Calculate triangle vertex info. */
int output_triangle_id = gl_VertexID / 3;
int output_triangle_vertex_id = gl_VertexID % 3;
int base_vertex_id = 0;
if (vertex_fetch_get_input_prim_type() == GPU_PRIM_TRIS) {
base_vertex_id = output_triangle_id * 3;
}
else if (vertex_fetch_get_input_prim_type() == GPU_PRIM_TRI_STRIP) {
base_vertex_id = output_triangle_id;
}
/* NOTE: Triangle fan unsupported in Metal. Will be conveted upfront. */
/** Perform vertex shader calculations per input vertex. **/
/* input pos vertex attribute. */
vec3 in_pos[3];
/* Calculated per-vertex world pos. */
vec3 world_pos[3];
/* Output gl_Position per vertex. */
vec3 ndc_pos[3];
/* Geometry shader normalized position. */
vec3 pos[3];
for (int i = 0; i < 3; i++) {
in_pos[0] = vertex_fetch_attribute(base_vertex_id + i, pos, vec3);
world_pos[0] = point_object_to_world(in_pos[i]);
ndc_pos[i] = point_world_to_ndc(world_pos[i]);
pos[i] = ndc_pos[i].xyz / ndc_pos[i].w;
}
/** Geometry Shader equivalent calculation
* In this no_geom mode using SSBO vertex fetch, rather than emitting 3 vertices, the vertex
* shader is invocated 3 times, and output is determined based on vertex ID within a triangle
* 0..2. **/
vec3 plane = normalize(cross(pos[1] - pos[0], pos[2] - pos[0]));
/* Compute NDC bound box. */
vec4 bbox = vec4(min(min(pos[0].xy, pos[1].xy), pos[2].xy),
max(max(pos[0].xy, pos[1].xy), pos[2].xy));
/* Convert to pixel space. */
bbox = (bbox * 0.5 + 0.5) * sizeViewport.xyxy;
/* Detect failure cases where triangles would produce no fragments. */
bvec2 is_subpixel = lessThan(bbox.zw - bbox.xy, vec2(1.0));
/* View aligned triangle. */
const float threshold = 0.00001;
bool is_coplanar = abs(plane.z) < threshold;
/* Determine output position per-vertex in each triangle */
gl_Position = ndc_pos[output_triangle_vertex_id];
if (all(is_subpixel)) {
vec2 ofs = (i == 0) ? vec2(-1.0) : ((i == 1) ? vec2(2.0, -1.0) : vec2(-1.0, 2.0));
/* HACK: Fix cases where the triangle is too small make it cover at least one pixel. */
gl_Position.xy += sizeViewportInv * gl_Position.w * ofs;
}
/* Test if the triangle is almost parallel with the view to avoid precision issues. */
else if (any(is_subpixel) || is_coplanar) {
/* HACK: Fix cases where the triangle is Parallel to the view by deforming it slightly. */
vec2 ofs = (i == 0) ? vec2(-1.0) : ((i == 1) ? vec2(1.0, -1.0) : vec2(1.0));
gl_Position.xy += sizeViewportInv * gl_Position.w * ofs;
}
else {
/* Triangle expansion should happen here, but we decide to not implement it for
* depth precision & performance reasons. */
}
/* Assign vertex shader clipping distances. */
view_clipping_distances(world_pos[output_triangle_vertex_id]);
}

View File

@ -30,6 +30,18 @@ GPU_SHADER_CREATE_INFO(basic_pointcloud)
GPU_SHADER_CREATE_INFO(basic_curves)
.vertex_source("basic_depth_curves_vert.glsl")
.additional_info("draw_hair");
/* Geometry-shader alterantive paths. */
GPU_SHADER_CREATE_INFO(basic_mesh_conservative_no_geom)
.vertex_in(0, Type::VEC3, "pos")
.vertex_source("basic_depth_vert_conservative_no_geom.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(basic_pointcloud_conservative_no_geom)
.define("CONSERVATIVE_RASTER")
.vertex_source("basic_depth_pointcloud_vert.glsl")
.additional_info("draw_pointcloud");
/** \} */
/* -------------------------------------------------------------------- */
@ -45,6 +57,7 @@ GPU_SHADER_CREATE_INFO(basic_curves)
#define BASIC_CONSERVATIVE_VARIATIONS(prefix, ...) \
BASIC_CLIPPING_VARIATIONS(prefix##_conservative, "basic_conservative", __VA_ARGS__) \
BASIC_CLIPPING_VARIATIONS(prefix##_conservative_no_geom, __VA_ARGS__) \
BASIC_CLIPPING_VARIATIONS(prefix, __VA_ARGS__)
#define BASIC_OBTYPE_VARIATIONS(prefix, ...) \

View File

@ -362,9 +362,13 @@ static void dof_bokeh_pass_init(EEVEE_FramebufferList *fbl,
DRW_shgroup_uniform_vec2_copy(grp, "bokehAnisotropyInv", fx->dof_bokeh_aniso_inv);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
fx->dof_bokeh_gather_lut_tx = DRW_texture_pool_query_2d(UNPACK2(res), GPU_RG16F, owner);
fx->dof_bokeh_scatter_lut_tx = DRW_texture_pool_query_2d(UNPACK2(res), GPU_R16F, owner);
fx->dof_bokeh_resolve_lut_tx = DRW_texture_pool_query_2d(UNPACK2(res), GPU_R16F, owner);
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
fx->dof_bokeh_gather_lut_tx = DRW_texture_pool_query_2d_ex(
UNPACK2(res), GPU_RG16F, usage, owner);
fx->dof_bokeh_scatter_lut_tx = DRW_texture_pool_query_2d_ex(
UNPACK2(res), GPU_R16F, usage, owner);
fx->dof_bokeh_resolve_lut_tx = DRW_texture_pool_query_2d_ex(
UNPACK2(res), GPU_R16F, usage, owner);
GPU_framebuffer_ensure_config(&fbl->dof_bokeh_fb,
{
@ -398,8 +402,10 @@ static void dof_setup_pass_init(EEVEE_FramebufferList *fbl,
DRW_shgroup_uniform_float_copy(grp, "bokehMaxSize", fx->dof_bokeh_max_size);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
fx->dof_half_res_color_tx = DRW_texture_pool_query_2d(UNPACK2(res), COLOR_FORMAT, owner);
fx->dof_half_res_coc_tx = DRW_texture_pool_query_2d(UNPACK2(res), GPU_RG16F, owner);
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
fx->dof_half_res_color_tx = DRW_texture_pool_query_2d_ex(
UNPACK2(res), COLOR_FORMAT, usage, owner);
fx->dof_half_res_coc_tx = DRW_texture_pool_query_2d_ex(UNPACK2(res), GPU_RG16F, usage, owner);
GPU_framebuffer_ensure_config(&fbl->dof_setup_fb,
{
@ -429,8 +435,11 @@ static void dof_flatten_tiles_pass_init(EEVEE_FramebufferList *fbl,
grp, "halfResCocBuffer", &fx->dof_half_res_coc_tx, NO_FILTERING);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
fx->dof_coc_tiles_fg_tx = DRW_texture_pool_query_2d(UNPACK2(res), FG_TILE_FORMAT, owner);
fx->dof_coc_tiles_bg_tx = DRW_texture_pool_query_2d(UNPACK2(res), BG_TILE_FORMAT, owner);
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
fx->dof_coc_tiles_fg_tx = DRW_texture_pool_query_2d_ex(
UNPACK2(res), FG_TILE_FORMAT, usage, owner);
fx->dof_coc_tiles_bg_tx = DRW_texture_pool_query_2d_ex(
UNPACK2(res), BG_TILE_FORMAT, usage, owner);
GPU_framebuffer_ensure_config(&fbl->dof_flatten_tiles_fb,
{
@ -468,9 +477,11 @@ static void dof_dilate_tiles_pass_init(EEVEE_FramebufferList *fbl,
DRW_shgroup_uniform_int(grp, "ringWidthMultiplier", &fx->dof_dilate_ring_width_multiplier, 1);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
fx->dof_coc_dilated_tiles_fg_tx = DRW_texture_pool_query_2d(UNPACK2(res), FG_TILE_FORMAT, owner);
fx->dof_coc_dilated_tiles_bg_tx = DRW_texture_pool_query_2d(UNPACK2(res), BG_TILE_FORMAT, owner);
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
fx->dof_coc_dilated_tiles_fg_tx = DRW_texture_pool_query_2d_ex(
UNPACK2(res), FG_TILE_FORMAT, usage, owner);
fx->dof_coc_dilated_tiles_bg_tx = DRW_texture_pool_query_2d_ex(
UNPACK2(res), BG_TILE_FORMAT, usage, owner);
GPU_framebuffer_ensure_config(&fbl->dof_dilate_tiles_fb,
{
@ -563,7 +574,9 @@ static void dof_reduce_pass_init(EEVEE_FramebufferList *fbl,
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
void *owner = (void *)&EEVEE_depth_of_field_init;
fx->dof_downsample_tx = DRW_texture_pool_query_2d(UNPACK2(quater_res), COLOR_FORMAT, owner);
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
fx->dof_downsample_tx = DRW_texture_pool_query_2d_ex(
UNPACK2(quater_res), COLOR_FORMAT, usage, owner);
GPU_framebuffer_ensure_config(&fbl->dof_downsample_fb,
{
@ -593,7 +606,9 @@ static void dof_reduce_pass_init(EEVEE_FramebufferList *fbl,
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
void *owner = (void *)&EEVEE_depth_of_field_init;
fx->dof_scatter_src_tx = DRW_texture_pool_query_2d(UNPACK2(res), GPU_R11F_G11F_B10F, owner);
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
fx->dof_scatter_src_tx = DRW_texture_pool_query_2d_ex(
UNPACK2(res), GPU_R11F_G11F_B10F, usage, owner);
}
{
@ -622,10 +637,12 @@ static void dof_reduce_pass_init(EEVEE_FramebufferList *fbl,
if (txl->dof_reduced_color == NULL) {
/* Color needs to be signed format here. See note in shader for explanation. */
/* Do not use texture pool because of needs mipmaps. */
txl->dof_reduced_color = GPU_texture_create_2d(
"dof_reduced_color", UNPACK2(res), mip_count, GPU_RGBA16F, NULL);
txl->dof_reduced_coc = GPU_texture_create_2d(
"dof_reduced_coc", UNPACK2(res), mip_count, GPU_R16F, NULL);
eGPUTextureUsage tex_flags = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT |
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW;
txl->dof_reduced_color = GPU_texture_create_2d_ex(
"dof_reduced_color", UNPACK2(res), mip_count, GPU_RGBA16F, tex_flags, NULL);
txl->dof_reduced_coc = GPU_texture_create_2d_ex(
"dof_reduced_coc", UNPACK2(res), mip_count, GPU_R16F, tex_flags, NULL);
}
GPU_framebuffer_ensure_config(&fbl->dof_reduce_fb,
@ -681,8 +698,10 @@ static void dof_gather_pass_init(EEVEE_FramebufferList *fbl,
/* Reuse textures from the setup pass. */
/* NOTE: We could use the texture pool do that for us but it does not track usage and it might
* backfire (it does in practice). */
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
fx->dof_fg_holefill_color_tx = fx->dof_half_res_color_tx;
fx->dof_fg_holefill_weight_tx = DRW_texture_pool_query_2d(UNPACK2(res), GPU_R16F, owner);
fx->dof_fg_holefill_weight_tx = DRW_texture_pool_query_2d_ex(
UNPACK2(res), GPU_R16F, usage, owner);
GPU_framebuffer_ensure_config(&fbl->dof_gather_fg_holefill_fb,
{
@ -714,9 +733,9 @@ static void dof_gather_pass_init(EEVEE_FramebufferList *fbl,
negate_v2(fx->dof_bokeh_aniso);
}
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
fx->dof_fg_color_tx = DRW_texture_pool_query_2d(UNPACK2(res), COLOR_FORMAT, owner);
fx->dof_fg_weight_tx = DRW_texture_pool_query_2d(UNPACK2(res), GPU_R16F, owner);
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
fx->dof_fg_color_tx = DRW_texture_pool_query_2d_ex(UNPACK2(res), COLOR_FORMAT, usage, owner);
fx->dof_fg_weight_tx = DRW_texture_pool_query_2d_ex(UNPACK2(res), GPU_R16F, usage, owner);
/* Reuse textures from the setup pass. */
/* NOTE: We could use the texture pool do that for us but it does not track usage and it might
* backfire (it does in practice). */
@ -752,8 +771,9 @@ static void dof_gather_pass_init(EEVEE_FramebufferList *fbl,
}
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
fx->dof_bg_color_tx = DRW_texture_pool_query_2d(UNPACK2(res), COLOR_FORMAT, owner);
fx->dof_bg_weight_tx = DRW_texture_pool_query_2d(UNPACK2(res), GPU_R16F, owner);
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
fx->dof_bg_color_tx = DRW_texture_pool_query_2d_ex(UNPACK2(res), COLOR_FORMAT, usage, owner);
fx->dof_bg_weight_tx = DRW_texture_pool_query_2d_ex(UNPACK2(res), GPU_R16F, usage, owner);
/* Reuse, since only used for scatter. Foreground is processed before background. */
fx->dof_bg_occlusion_tx = fx->dof_fg_occlusion_tx;

View File

@ -327,6 +327,8 @@ LightCache *EEVEE_lightcache_create(const int grid_len,
const int vis_size,
const int irr_size[3])
{
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT |
GPU_TEXTURE_USAGE_HOST_READ;
LightCache *light_cache = MEM_callocN(sizeof(LightCache), "LightCache");
light_cache->version = LIGHTCACHE_STATIC_VERSION;
@ -335,8 +337,8 @@ LightCache *EEVEE_lightcache_create(const int grid_len,
light_cache->cube_data = MEM_callocN(sizeof(EEVEE_LightProbe) * cube_len, "EEVEE_LightProbe");
light_cache->grid_data = MEM_callocN(sizeof(EEVEE_LightGrid) * grid_len, "EEVEE_LightGrid");
light_cache->grid_tx.tex = DRW_texture_create_2d_array(
irr_size[0], irr_size[1], irr_size[2], IRRADIANCE_FORMAT, DRW_TEX_FILTER, NULL);
light_cache->grid_tx.tex = DRW_texture_create_2d_array_ex(
irr_size[0], irr_size[1], irr_size[2], IRRADIANCE_FORMAT, usage, DRW_TEX_FILTER, NULL);
light_cache->grid_tx.tex_size[0] = irr_size[0];
light_cache->grid_tx.tex_size[1] = irr_size[1];
light_cache->grid_tx.tex_size[2] = irr_size[2];
@ -345,12 +347,12 @@ LightCache *EEVEE_lightcache_create(const int grid_len,
/* Try to create a cubemap array. */
DRWTextureFlag cube_texflag = DRW_TEX_FILTER | DRW_TEX_MIPMAP;
light_cache->cube_tx.tex = DRW_texture_create_cube_array(
cube_size, cube_len, GPU_R11F_G11F_B10F, cube_texflag, NULL);
light_cache->cube_tx.tex = DRW_texture_create_cube_array_ex(
cube_size, cube_len, GPU_R11F_G11F_B10F, usage, cube_texflag, NULL);
if (light_cache->cube_tx.tex == NULL) {
/* Try fallback to 2D array. */
light_cache->cube_tx.tex = DRW_texture_create_2d_array(
cube_size, cube_size, cube_len * 6, GPU_R11F_G11F_B10F, cube_texflag, NULL);
light_cache->cube_tx.tex = DRW_texture_create_2d_array_ex(
cube_size, cube_size, cube_len * 6, GPU_R11F_G11F_B10F, usage, cube_texflag, NULL);
}
light_cache->cube_tx.tex_size[0] = cube_size;
@ -393,8 +395,13 @@ static bool eevee_lightcache_static_load(LightCache *lcache)
}
if (lcache->grid_tx.tex == NULL) {
lcache->grid_tx.tex = GPU_texture_create_2d_array(
"lightcache_irradiance", UNPACK3(lcache->grid_tx.tex_size), 1, IRRADIANCE_FORMAT, NULL);
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
lcache->grid_tx.tex = GPU_texture_create_2d_array_ex("lightcache_irradiance",
UNPACK3(lcache->grid_tx.tex_size),
1,
IRRADIANCE_FORMAT,
usage,
NULL);
GPU_texture_update(lcache->grid_tx.tex, GPU_DATA_UBYTE, lcache->grid_tx.data);
if (lcache->grid_tx.tex == NULL) {
@ -406,21 +413,27 @@ static bool eevee_lightcache_static_load(LightCache *lcache)
}
if (lcache->cube_tx.tex == NULL) {
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT |
GPU_TEXTURE_USAGE_HOST_READ;
/* Try to create a cubemap array. */
lcache->cube_tx.tex = GPU_texture_create_cube_array("lightcache_cubemaps",
lcache->cube_tx.tex_size[0],
lcache->cube_tx.tex_size[2] / 6,
lcache->mips_len + 1,
GPU_R11F_G11F_B10F,
NULL);
lcache->cube_tx.tex = GPU_texture_create_cube_array_ex("lightcache_cubemaps",
lcache->cube_tx.tex_size[0],
lcache->cube_tx.tex_size[2] / 6,
lcache->mips_len + 1,
GPU_R11F_G11F_B10F,
usage,
NULL);
if (lcache->cube_tx.tex == NULL) {
/* Try fallback to 2D array. */
lcache->cube_tx.tex = GPU_texture_create_2d_array("lightcache_cubemaps_fallback",
UNPACK3(lcache->cube_tx.tex_size),
lcache->mips_len + 1,
GPU_R11F_G11F_B10F,
NULL);
lcache->cube_tx.tex = GPU_texture_create_2d_array_ex("lightcache_cubemaps_fallback",
UNPACK3(lcache->cube_tx.tex_size),
lcache->mips_len + 1,
GPU_R11F_G11F_B10F,
usage,
NULL);
}
if (lcache->cube_tx.tex == NULL) {
@ -610,19 +623,22 @@ static void eevee_lightbake_context_enable(EEVEE_LightBake *lbake)
static void eevee_lightbake_context_disable(EEVEE_LightBake *lbake)
{
GPU_render_end();
if (GPU_use_main_context_workaround() && !BLI_thread_is_main()) {
DRW_opengl_context_disable();
GPU_render_end();
GPU_context_main_unlock();
return;
}
if (lbake->gl_context) {
DRW_gpu_render_context_disable(lbake->gpu_context);
GPU_render_end();
DRW_opengl_render_context_disable(lbake->gl_context);
}
else {
DRW_opengl_context_disable();
GPU_render_end();
}
}
@ -666,9 +682,11 @@ static void eevee_lightbake_count_probes(EEVEE_LightBake *lbake)
static void eevee_lightbake_create_render_target(EEVEE_LightBake *lbake, int rt_res)
{
lbake->rt_depth = DRW_texture_create_cube(rt_res, GPU_DEPTH_COMPONENT24, 0, NULL);
lbake->rt_color = DRW_texture_create_cube(
rt_res, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT |
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW;
lbake->rt_depth = DRW_texture_create_cube_ex(rt_res, GPU_DEPTH_COMPONENT24, usage, 0, NULL);
lbake->rt_color = DRW_texture_create_cube_ex(
rt_res, GPU_RGBA16F, usage, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
for (int i = 0; i < 6; i++) {
GPU_framebuffer_ensure_config(&lbake->rt_fb[i],
@ -694,12 +712,13 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake)
lbake->cube_prb = MEM_callocN(sizeof(LightProbe *) * lbake->cube_len, "EEVEE Cube visgroup ptr");
lbake->grid_prb = MEM_callocN(sizeof(LightProbe *) * lbake->grid_len, "EEVEE Grid visgroup ptr");
lbake->grid_prev = DRW_texture_create_2d_array(lbake->irr_size[0],
lbake->irr_size[1],
lbake->irr_size[2],
IRRADIANCE_FORMAT,
DRW_TEX_FILTER,
NULL);
lbake->grid_prev = DRW_texture_create_2d_array_ex(lbake->irr_size[0],
lbake->irr_size[1],
lbake->irr_size[2],
IRRADIANCE_FORMAT,
GPU_TEXTURE_USAGE_SHADER_READ,
DRW_TEX_FILTER,
NULL);
/* Ensure Light Cache is ready to accept new data. If not recreate one.
* WARNING: All the following must be threadsafe. It's currently protected
@ -980,12 +999,13 @@ static void eevee_lightbake_copy_irradiance(EEVEE_LightBake *lbake, LightCache *
/* Copy texture by reading back and re-uploading it. */
float *tex = GPU_texture_read(lcache->grid_tx.tex, GPU_DATA_FLOAT, 0);
lbake->grid_prev = DRW_texture_create_2d_array(lbake->irr_size[0],
lbake->irr_size[1],
lbake->irr_size[2],
IRRADIANCE_FORMAT,
DRW_TEX_FILTER,
tex);
lbake->grid_prev = DRW_texture_create_2d_array_ex(lbake->irr_size[0],
lbake->irr_size[1],
lbake->irr_size[2],
IRRADIANCE_FORMAT,
GPU_TEXTURE_USAGE_SHADER_READ,
DRW_TEX_FILTER,
tex);
MEM_freeN(tex);
}

View File

@ -79,7 +79,7 @@ static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *fx = stl->effects;
/* XXX TODO: OPTIMIZATION: This is a complete waist of texture memory.
/* XXX TODO: OPTIMIZATION: This is a complete waste of texture memory.
* Instead of allocating each planar probe for each viewport,
* only alloc them once using the biggest viewport resolution. */

View File

@ -63,7 +63,7 @@ float *EEVEE_lut_update_ggx_btdf(int lut_size, int lut_depth)
DRWPass *pass = DRW_pass_create(__func__, DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_ggx_refraction_lut_sh_get(), pass);
DRW_shgroup_uniform_float_copy(grp, "sampleCount", 64.0f); /* Actual sample count is squared. */
DRW_shgroup_uniform_float(grp, "z", &roughness, 1);
DRW_shgroup_uniform_float(grp, "z_factor", &roughness, 1);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
GPUTexture *tex = DRW_texture_create_2d_array(lut_size, lut_size, lut_depth, GPU_RG16F, 0, NULL);

View File

@ -64,17 +64,17 @@ int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda
1 + ((int)fs_size[0] / EEVEE_VELOCITY_TILE_SIZE),
1 + ((int)fs_size[1] / EEVEE_VELOCITY_TILE_SIZE),
};
effects->velocity_tiles_x_tx = DRW_texture_pool_query_2d(
tx_size[0], fs_size[1], GPU_RGBA16, &draw_engine_eevee_type);
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
effects->velocity_tiles_x_tx = DRW_texture_pool_query_2d_ex(
tx_size[0], fs_size[1], GPU_RGBA16, usage, &draw_engine_eevee_type);
GPU_framebuffer_ensure_config(&fbl->velocity_tiles_fb[0],
{
GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_TEXTURE(effects->velocity_tiles_x_tx),
});
effects->velocity_tiles_tx = DRW_texture_pool_query_2d(
tx_size[0], tx_size[1], GPU_RGBA16, &draw_engine_eevee_type);
effects->velocity_tiles_tx = DRW_texture_pool_query_2d_ex(
tx_size[0], tx_size[1], GPU_RGBA16, usage, &draw_engine_eevee_type);
GPU_framebuffer_ensure_config(&fbl->velocity_tiles_fb[1],
{
GPU_ATTACHMENT_NONE,

View File

@ -17,6 +17,8 @@
#include "BKE_camera.h"
#include "engine_eevee_shared_defines.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -28,18 +30,6 @@ struct RenderLayer;
extern struct DrawEngineType draw_engine_eevee_type;
/* Minimum UBO is 16384 bytes */
#define MAX_PROBE 128 /* TODO: find size by dividing UBO max size by probe data size. */
#define MAX_GRID 64 /* TODO: find size by dividing UBO max size by grid data size. */
#define MAX_PLANAR 16 /* TODO: find size by dividing UBO max size by grid data size. */
#define MAX_LIGHT 128 /* TODO: find size by dividing UBO max size by light data size. */
#define MAX_CASCADE_NUM 4
#define MAX_SHADOW 128 /* TODO: Make this depends on #GL_MAX_ARRAY_TEXTURE_LAYERS. */
#define MAX_SHADOW_CASCADE 8
#define MAX_SHADOW_CUBE (MAX_SHADOW - MAX_CASCADE_NUM * MAX_SHADOW_CASCADE)
#define MAX_BLOOM_STEP 16
#define MAX_AOVS 64
/* Special value chosen to not be altered by depth of field sample count. */
#define TAA_MAX_SAMPLE 10000926
@ -55,23 +45,7 @@ extern struct DrawEngineType draw_engine_eevee_type;
# define SHADER_IRRADIANCE "#define IRRADIANCE_HL2\n"
#endif
/* Macro causes over indentation. */
/* clang-format off */
#define SHADER_DEFINES \
"#define EEVEE_ENGINE\n" \
"#define MAX_PROBE " STRINGIFY(MAX_PROBE) "\n" \
"#define MAX_GRID " STRINGIFY(MAX_GRID) "\n" \
"#define MAX_PLANAR " STRINGIFY(MAX_PLANAR) "\n" \
"#define MAX_LIGHT " STRINGIFY(MAX_LIGHT) "\n" \
"#define MAX_SHADOW " STRINGIFY(MAX_SHADOW) "\n" \
"#define MAX_SHADOW_CUBE " STRINGIFY(MAX_SHADOW_CUBE) "\n" \
"#define MAX_SHADOW_CASCADE " STRINGIFY(MAX_SHADOW_CASCADE) "\n" \
"#define MAX_CASCADE_NUM " STRINGIFY(MAX_CASCADE_NUM) "\n" \
SHADER_IRRADIANCE
/* clang-format on */
#define EEVEE_PROBE_MAX min_ii(MAX_PROBE, GPU_max_texture_layers() / 6)
#define EEVEE_VELOCITY_TILE_SIZE 32
#define USE_VOLUME_OPTI (GPU_shader_image_load_store_support())
#define SWAP_DOUBLE_BUFFERS() \
@ -194,19 +168,6 @@ typedef enum EEVEE_DofGatherPass {
DOF_GATHER_MAX_PASS,
} EEVEE_DofGatherPass;
#define DOF_TILE_DIVISOR 16
#define DOF_BOKEH_LUT_SIZE 32
#define DOF_GATHER_RING_COUNT 5
#define DOF_DILATE_RING_COUNT 3
#define DOF_FAST_GATHER_COC_ERROR 0.05
#define DOF_SHADER_DEFINES \
"#define DOF_TILE_DIVISOR " STRINGIFY(DOF_TILE_DIVISOR) "\n" \
"#define DOF_BOKEH_LUT_SIZE " STRINGIFY(DOF_BOKEH_LUT_SIZE) "\n" \
"#define DOF_GATHER_RING_COUNT " STRINGIFY(DOF_GATHER_RING_COUNT) "\n" \
"#define DOF_DILATE_RING_COUNT " STRINGIFY(DOF_DILATE_RING_COUNT) "\n" \
"#define DOF_FAST_GATHER_COC_ERROR " STRINGIFY(DOF_FAST_GATHER_COC_ERROR) "\n"
/* ************ PROBE UBO ************* */
/* They are the same struct as their Cache siblings.
@ -1295,13 +1256,14 @@ struct GPUMaterial *EEVEE_material_get(
EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options);
void EEVEE_shaders_free(void);
void eevee_shader_extra_init(void);
void eevee_shader_extra_exit(void);
void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
GPUCodegenOutput *codegen,
char *frag,
GPUCodegenOutput *codegen_,
char *vert,
char *geom,
char *frag,
const char *vert_info_name,
const char *geom_info_name,
const char *frag_info_name,
char *defines);
GPUShader *eevee_shaders_sh_create_helper(const char *name,
const char *vert_name,

File diff suppressed because it is too large Load Diff

View File

@ -17,33 +17,14 @@
using blender::gpu::shader::StageInterfaceInfo;
static StageInterfaceInfo *stage_interface = nullptr;
void eevee_shader_extra_init()
{
if (stage_interface != nullptr) {
return;
}
using namespace blender::gpu::shader;
stage_interface = new StageInterfaceInfo("ShaderStageInterface", "");
stage_interface->smooth(Type::VEC3, "worldPosition");
stage_interface->smooth(Type::VEC3, "viewPosition");
stage_interface->smooth(Type::VEC3, "worldNormal");
stage_interface->smooth(Type::VEC3, "viewNormal");
stage_interface->flat(Type::INT, "resourceIDFrag");
}
void eevee_shader_extra_exit()
{
delete stage_interface;
}
void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
GPUCodegenOutput *codegen_,
char *frag,
char *vert,
char *geom,
char *frag,
const char *vert_info_name,
const char *geom_info_name,
const char *frag_info_name,
char *defines)
{
using namespace blender::gpu::shader;
@ -58,7 +39,17 @@ void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
GPUCodegenOutput &codegen = *codegen_;
ShaderCreateInfo &info = *reinterpret_cast<ShaderCreateInfo *>(codegen.create_info);
info.legacy_resource_location(true);
/* Append stage-specific create info. */
if (vert_info_name) {
info.additional_info(vert_info_name);
}
if (geom_info_name) {
info.additional_info(geom_info_name);
}
if (frag_info_name) {
info.additional_info(frag_info_name);
}
info.auto_resource_location(true);
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_SUBSURFACE)) {
@ -76,6 +67,12 @@ void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
info.define("USE_BARYCENTRICS");
}
/* Lookdev - Add FragDepth. */
if (options & VAR_MAT_LOOKDEV) {
info.define("LOOKDEV");
info.depth_write(DepthWrite::ANY);
}
std::stringstream attr_load;
const bool do_fragment_attrib_load = is_background || is_volume;
@ -124,7 +121,6 @@ void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
if (!is_volume) {
info.define("EEVEE_GENERATED_INTERFACE");
info.vertex_out(*stage_interface);
}
attr_load << "void attrib_load()\n";

View File

@ -0,0 +1,30 @@
#ifndef GPU_SHADER_EEVEE_LEGACY_DEFINES
#define GPU_SHADER_EEVEE_LEGACY_DEFINES
#ifdef GPU_SHADER
# define EEVEE_ENGINE
#endif
/* Minimum UBO is 16384 bytes. */
#define MAX_PROBE 128 /* TODO: find size by dividing UBO max size by probe data size. */
#define MAX_GRID 64 /* TODO: find size by dividing UBO max size by grid data size. */
#define MAX_PLANAR 16 /* TODO: find size by dividing UBO max size by grid data size. */
#define MAX_LIGHT 128 /* TODO: find size by dividing UBO max size by light data size. */
#define MAX_CASCADE_NUM 4
#define MAX_SHADOW 128 /* TODO: Make this depends on #GL_MAX_ARRAY_TEXTURE_LAYERS. */
#define MAX_SHADOW_CASCADE 8
#define MAX_SHADOW_CUBE (MAX_SHADOW - MAX_CASCADE_NUM * MAX_SHADOW_CASCADE)
#define MAX_BLOOM_STEP 16
#define MAX_AOVS 64
/* Motion Blur. */
#define EEVEE_VELOCITY_TILE_SIZE 32
/* Depth of Field*/
#define DOF_TILE_DIVISOR 16
#define DOF_BOKEH_LUT_SIZE 32
#define DOF_GATHER_RING_COUNT 5
#define DOF_DILATE_RING_COUNT 3
#define DOF_FAST_GATHER_COC_ERROR 0.05
#endif

View File

@ -2,6 +2,7 @@
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
#pragma BLENDER_REQUIRE(raytrace_lib.glsl)
#pragma BLENDER_REQUIRE(surface_lib.glsl)
/* Based on Practical Realtime Strategies for Accurate Indirect Occlusion
* http://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pdf
@ -30,8 +31,6 @@
# define gl_FragCoord vec4(0.0)
#endif
uniform sampler2D horizonBuffer;
/* aoSettings flags */
#define USE_AO 1
#define USE_BENT_NORMAL 2

View File

@ -2,10 +2,6 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(surface_lib.glsl)
in vec2 pos;
RESOURCE_ID_VARYING
void main()
{
GPU_INTEL_VERTEX_SHADER_WORKAROUND

View File

@ -1,10 +1,6 @@
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
uniform float sampleCount;
out vec2 FragColor;
void main()
{
/* Make sure coordinates are covering the whole [0..1] range at texel center. */

View File

@ -1,11 +1,6 @@
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
uniform float sampleCount;
uniform float z;
out vec4 FragColor;
void main()
{
float x = floor(gl_FragCoord.x) / (LUT_SIZE - 1.0);
@ -23,7 +18,7 @@ void main()
y += critical_cos;
float NV = clamp(y, 1e-4, 0.9999);
float a = z * z;
float a = z_factor * z_factor;
float a2 = clamp(a * a, 1e-8, 0.9999);
vec3 V = vec3(sqrt(1.0 - NV * NV), 0.0, NV);
@ -72,7 +67,7 @@ void main()
btdf_accum /= sampleCount * sampleCount;
fresnel_accum /= sampleCount * sampleCount;
if (z == 0.0) {
if (z_factor == 0.0) {
/* Perfect mirror. Increased precision because the roughness is clamped. */
fresnel_accum = F_eta(ior, NV);
}

View File

@ -4,13 +4,6 @@
/* #pragma (common_uniforms_lib.glsl) */
/* #pragma (renderpass_lib.glsl) */
#ifndef VOLUMETRICS
uniform int outputSsrId; /* Default = 1; */
uniform int outputSssId; /* Default = 1; */
#endif
struct Closure {
#ifdef VOLUMETRICS
vec3 absorption;

View File

@ -1,6 +1,8 @@
#define COMMON_UNIFORMS_LIB
#if !defined(USE_GPU_SHADER_CREATE_INFO)
/* keep in sync with CommonUniformBlock */
layout(std140) uniform common_block
{
mat4 pastViewProjectionMatrix;
@ -49,6 +51,14 @@ layout(std140) uniform common_block
vec4 planarClipPlane;
};
#endif /* !USE_GPU_SHADER_CREATE_INFO */
#ifdef USE_GPU_SHADER_CREATE_INFO
# ifndef EEVEE_SHADER_SHARED_H
# error Missing eevee_legacy_common_lib additional create info on shader create info
# endif
#endif
/* rayType (keep in sync with ray_type) */
#define EEVEE_RAY_CAMERA 0
#define EEVEE_RAY_SHADOW 1

View File

@ -8,8 +8,12 @@
* tables.
* \{ */
#if !defined(USE_GPU_SHADER_CREATE_INFO)
uniform sampler2DArray utilTex;
#endif
#define LUT_SIZE 64
#define LTC_MAT_LAYER 0

View File

@ -1,5 +1,3 @@
uniform vec4 cryptohash;
out vec4 fragColor;
void main()
{

View File

@ -1,19 +0,0 @@
/* NOTE: this lib is included in the cryptomatte vertex shader to work around the issue that eevee
* cannot use create infos for its static shaders. Keep in sync with draw_shader_shared.h */
#ifdef HAIR_SHADER
/* Define the maximum number of attribute we allow in a curves UBO.
* This should be kept in sync with `GPU_ATTR_MAX` */
# define DRW_ATTRIBUTE_PER_CURVES_MAX 15
struct CurvesInfos {
/* Per attribute scope, follows loading order.
* NOTE: uint as bool in GLSL is 4 bytes.
* NOTE: GLSL pad arrays of scalar to 16 bytes (std140). */
uvec4 is_point_attribute[DRW_ATTRIBUTE_PER_CURVES_MAX];
};
layout(std140) uniform drw_curves
{
CurvesInfos _drw_curves;
};
# define drw_curves (_drw_curves)
#endif

View File

@ -3,5 +3,4 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_attribute_lib.glsl)
#pragma BLENDER_REQUIRE(cryptomatte_lib.glsl)
#pragma BLENDER_REQUIRE(surface_vert.glsl)

View File

@ -60,7 +60,14 @@ vec3 cubemap_adj_xy(float face)
}
}
# ifdef GPU_METAL
template<typename T>
vec4 cubemap_seamless(thread _mtl_combined_image_sampler_2d_array<T, access::sample> *tex,
vec4 cubevec,
float lod)
# else
vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod)
# endif
{
/* Manual Cube map Layer indexing. */
float face = cubemap_face_index(cubevec.xyz);
@ -116,7 +123,14 @@ vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod)
}
}
# ifdef GPU_METAL
template<typename T, access A>
vec4 textureLod_cubemapArray(thread _mtl_combined_image_sampler_2d_array<T, A> tex,
vec4 cubevec,
float lod)
# else
vec4 textureLod_cubemapArray(sampler2DArray tex, vec4 cubevec, float lod)
# endif
{
float lod1 = floor(lod);
float lod2 = ceil(lod);

View File

@ -28,26 +28,6 @@
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
uniform sampler2D sourceBuffer; /* Buffer to filter */
uniform vec2 sourceBufferTexelSize;
/* Step Blit */
uniform vec4 curveThreshold;
uniform float clampIntensity;
/* Step Upsample */
uniform sampler2D baseBuffer; /* Previous accumulation buffer */
uniform vec2 baseBufferTexelSize;
uniform float sampleScale;
/* Step Resolve */
uniform vec3 bloomColor;
uniform bool bloomAddBase;
in vec4 uvcoordsvar;
out vec4 FragColor;
/* -------------- Utils ------------- */
/* 3-tap median filter */

View File

@ -9,16 +9,6 @@
#pragma BLENDER_REQUIRE(effect_dof_lib.glsl)
uniform float bokehSides;
uniform float bokehRotation;
uniform vec2 bokehAnisotropyInv;
in vec4 uvcoordsvar;
layout(location = 0) out vec2 outGatherLut;
layout(location = 1) out float outScatterLut;
layout(location = 2) out float outResolveLut;
float polygon_sides_length(float sides_count)
{
return 2.0 * sin(M_PI / sides_count);

View File

@ -6,18 +6,6 @@
#pragma BLENDER_REQUIRE(effect_dof_lib.glsl)
/* 1/16th of fullres. */
uniform sampler2D cocTilesFgBuffer;
uniform sampler2D cocTilesBgBuffer;
uniform int ringCount;
uniform int ringWidthMultiplier;
uniform bool dilateSlightFocus;
/* 1/16th of fullres. Same format as input. */
layout(location = 0) out vec4 outFgCoc;
layout(location = 1) out vec3 outBgCoc;
const float tile_to_fullres_factor = float(DOF_TILE_DIVISOR);
/* Error introduced by the random offset of the gathering kernel's center. */

View File

@ -8,13 +8,6 @@
#pragma BLENDER_REQUIRE(effect_dof_lib.glsl)
/* Half resolution. */
uniform sampler2D colorBuffer;
uniform sampler2D cocBuffer;
/* Quarter resolution. */
layout(location = 0) out vec4 outColor;
void main()
{
vec2 halfres_texel_size = 1.0 / vec2(textureSize(colorBuffer, 0).xy);

View File

@ -8,14 +8,6 @@
#pragma BLENDER_REQUIRE(effect_dof_lib.glsl)
uniform sampler2D colorBuffer;
uniform sampler2D weightBuffer;
in vec4 uvcoordsvar;
layout(location = 0) out vec4 outColor;
layout(location = 1) out float outWeight;
/* From:
* Implementing Median Filters in XC4000E FPGAs
* JOHN L. SMITH, Univision Technologies Inc., Billerica, MA

View File

@ -9,13 +9,6 @@
#pragma BLENDER_REQUIRE(effect_dof_lib.glsl)
/* Half resolution. */
uniform sampler2D halfResCocBuffer;
/* 1/8th of halfResCocBuffer resolution. So 1/16th of fullres. */
layout(location = 0) out vec4 outFgCoc;
layout(location = 1) out vec3 outBgCoc;
const int halfres_tile_divisor = DOF_TILE_DIVISOR / 2;
void main()

View File

@ -12,32 +12,7 @@
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
#pragma BLENDER_REQUIRE(effect_dof_lib.glsl)
/* Mipmapped input buffers, halfres but with padding to ensure mipmap alignment. */
uniform sampler2D colorBuffer;
uniform sampler2D cocBuffer;
/* Same input buffer but with a bilinear sampler object. */
uniform sampler2D colorBufferBilinear;
/* CoC Min&Max tile buffer at 1/16th of fullres. */
uniform sampler2D cocTilesFgBuffer;
uniform sampler2D cocTilesBgBuffer;
uniform sampler2D bokehLut;
/* Used to correct the padding in the color and CoC buffers. */
uniform vec2 gatherInputUvCorrection;
uniform vec2 gatherOutputTexelSize;
uniform vec2 bokehAnisotropy;
layout(location = 0) out vec4 outColor;
layout(location = 1) out float outWeight;
#ifndef DOF_HOLEFILL_PASS
layout(location = 2) out vec2 outOcclusion;
#else
#ifdef DOF_HOLEFILL_PASS
/* Dirty global variable that isn't used. So it should get optimized out. */
vec2 outOcclusion;
#endif

View File

@ -2,8 +2,6 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
uniform vec4 cocParams;
#define cocMul cocParams[0] /* distance * aperturesize * invsensorsize */
#define cocBias cocParams[1] /* aperturesize * invsensorsize */
#define cocNear cocParams[2] /* Near view depths value. */

View File

@ -6,31 +6,8 @@
#pragma BLENDER_REQUIRE(effect_dof_lib.glsl)
/** Inputs:
* COPY_PASS: Is output of setup pass (halfres) and downsample pass (quarter res).
* REDUCE_PASS: Is previous Gather input miplvl (halfres >> miplvl).
*/
uniform sampler2D colorBuffer;
uniform sampler2D cocBuffer;
uniform sampler2D downsampledBuffer;
uniform vec2 bokehAnisotropy;
uniform float scatterColorThreshold;
uniform float scatterCocThreshold;
uniform float scatterColorNeighborMax;
uniform float colorNeighborClamping;
/** Outputs:
* COPY_PASS: Gather input mip0.
* REDUCE_PASS: Is next Gather input miplvl (halfres >> miplvl).
*/
layout(location = 0) out vec4 outColor;
layout(location = 1) out float outCoc;
#ifdef COPY_PASS
layout(location = 2) out vec3 outScatterColor;
/* NOTE: Do not compare alpha as it is not scattered by the scatter pass. */
float dof_scatter_neighborhood_rejection(vec3 color)
{

View File

@ -10,28 +10,6 @@
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
#pragma BLENDER_REQUIRE(effect_dof_lib.glsl)
uniform sampler2D fullResColorBuffer;
uniform sampler2D fullResDepthBuffer;
uniform sampler2D bgColorBuffer;
uniform sampler2D bgWeightBuffer;
uniform sampler2D bgTileBuffer;
uniform sampler2D fgColorBuffer;
uniform sampler2D fgWeightBuffer;
uniform sampler2D fgTileBuffer;
uniform sampler2D holefillColorBuffer;
uniform sampler2D holefillWeightBuffer;
uniform sampler2D bokehLut;
uniform float bokehMaxSize;
in vec4 uvcoordsvar;
out vec4 fragColor;
void dof_slight_focus_gather(float radius, out vec4 out_color, out float out_weight)
{
/* offset coord to avoid correlation with sampling pattern. */

View File

@ -8,22 +8,6 @@
#pragma BLENDER_REQUIRE(effect_dof_lib.glsl)
uniform sampler2D occlusionBuffer;
uniform sampler2D bokehLut;
uniform vec2 bokehAnisotropyInv;
flat in vec4 color1;
flat in vec4 color2;
flat in vec4 color3;
flat in vec4 color4;
flat in vec4 weights;
flat in vec4 cocs;
flat in vec2 spritepos;
flat in float spritesize; /* MaxCoC */
layout(location = 0) out vec4 fragColor;
float bokeh_shape(vec2 center)
{
vec2 co = gl_FragCoord.xy - center;

View File

@ -1,27 +1,6 @@
#pragma BLENDER_REQUIRE(effect_dof_lib.glsl)
uniform vec2 targetTexelSize;
uniform int spritePerRow;
uniform vec2 bokehAnisotropy;
uniform sampler2D colorBuffer;
uniform sampler2D cocBuffer;
/* Scatter pass, calculate a triangle covering the CoC.
* We render to a half resolution target with double width so we can
* separate near and far fields. We also generate only one triangle per group of 4 pixels
* to limit overdraw. */
flat out vec4 color1;
flat out vec4 color2;
flat out vec4 color3;
flat out vec4 color4;
flat out vec4 weights;
flat out vec4 cocs;
flat out vec2 spritepos;
flat out float spritesize;
/* Load 4 Circle of confusion values. texel_co is centered around the 4 taps. */
vec4 fetch_cocs(vec2 texel_co)
{

View File

@ -8,16 +8,6 @@
#pragma BLENDER_REQUIRE(effect_dof_lib.glsl)
/* Full resolution. */
uniform sampler2D colorBuffer;
uniform sampler2D depthBuffer;
uniform float bokehMaxSize;
/* Half resolution. */
layout(location = 0) out vec4 outColor;
layout(location = 1) out vec2 outCoc; /* x: Downsample CoC, y: Max slight focus abs CoC */
void main()
{
vec2 fullres_texel_size = 1.0 / vec2(textureSize(colorBuffer, 0).xy);

View File

@ -4,39 +4,36 @@
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
uniform samplerCube source;
uniform float texelSize;
flat in int fFace;
out vec4 FragColor;
const vec3 maj_axes[6] = vec3[6](vec3(1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, -1.0, 0.0),
vec3(0.0, 0.0, 1.0),
vec3(0.0, 0.0, -1.0));
const vec3 x_axis[6] = vec3[6](vec3(0.0, 0.0, -1.0),
vec3(0.0, 0.0, 1.0),
vec3(1.0, 0.0, 0.0),
vec3(1.0, 0.0, 0.0),
vec3(1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0));
const vec3 y_axis[6] = vec3[6](vec3(0.0, -1.0, 0.0),
vec3(0.0, -1.0, 0.0),
vec3(0.0, 0.0, 1.0),
vec3(0.0, 0.0, -1.0),
vec3(0.0, -1.0, 0.0),
vec3(0.0, -1.0, 0.0));
void main()
{
/* Global scope arrays get allocated using local memory in Metal. Moving inside function scope to
* reduce register pressure. */
const vec3 maj_axes[6] = vec3[6](vec3(1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, -1.0, 0.0),
vec3(0.0, 0.0, 1.0),
vec3(0.0, 0.0, -1.0));
const vec3 x_axis[6] = vec3[6](vec3(0.0, 0.0, -1.0),
vec3(0.0, 0.0, 1.0),
vec3(1.0, 0.0, 0.0),
vec3(1.0, 0.0, 0.0),
vec3(1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0));
const vec3 y_axis[6] = vec3[6](vec3(0.0, -1.0, 0.0),
vec3(0.0, -1.0, 0.0),
vec3(0.0, 0.0, 1.0),
vec3(0.0, 0.0, -1.0),
vec3(0.0, -1.0, 0.0),
vec3(0.0, -1.0, 0.0));
vec2 uvs = gl_FragCoord.xy * texelSize;
uvs = 2.0 * uvs - 1.0;
vec3 cubevec = x_axis[fFace] * uvs.x + y_axis[fFace] * uvs.y + maj_axes[fFace];
vec3 cubevec = x_axis[geom_iface.fFace] * uvs.x + y_axis[geom_iface.fFace] * uvs.y +
maj_axes[geom_iface.fFace];
FragColor = textureLod(source, cubevec, 0.0);
}

Some files were not shown because too many files have changed in this diff Show More