Mesh: Replace MLoop struct with generic attributes #104424
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}:*:*:*:*:*:*:*")
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 int *corner_verts,
|
||||
const int *corner_edges,
|
||||
|
|
|
@ -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
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1801,7 +1801,7 @@ struct SplitFaceNewVert {
|
|||
struct SplitFaceNewVert *next;
|
||||
int new_index;
|
||||
int orig_index;
|
||||
float *vnor;
|
||||
const float *vnor;
|
||||
};
|
||||
|
||||
struct SplitFaceNewEdge {
|
||||
|
@ -1812,81 +1812,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<int> corner_verts = mesh->corner_verts_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<int> corner_verts = mesh.corner_verts_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);
|
||||
|
||||
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 = corner_verts[loop_idx];
|
||||
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++, lnor_space++) {
|
||||
if (!done_loops[loop_idx]) {
|
||||
const int vert_idx = corner_verts[loop_idx];
|
||||
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) {
|
||||
corner_verts[loop_idx] = 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) {
|
||||
corner_verts[loop_idx] = 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) {
|
||||
corner_verts[ml_fan_idx] = new_vert_idx;
|
||||
}
|
||||
corner_verts[ml_fan_idx] = 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.
|
||||
|
@ -2014,7 +2012,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
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
using blender::BitVector;
|
||||
using blender::float3;
|
||||
using blender::int2;
|
||||
using blender::MutableSpan;
|
||||
using blender::short2;
|
||||
using blender::Span;
|
||||
|
@ -771,11 +772,11 @@ struct LoopSplitTaskDataCommon {
|
|||
|
||||
/* Read-only. */
|
||||
Span<float3> positions;
|
||||
MutableSpan<MEdge> edges;
|
||||
Span<MEdge> edges;
|
||||
Span<int> corner_verts;
|
||||
Span<int> corner_edges;
|
||||
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;
|
||||
|
@ -786,58 +787,39 @@ 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<int> corner_verts,
|
||||
const Span<int> corner_edges,
|
||||
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<int> corner_verts = data->corner_verts;
|
||||
const Span<int> corner_edges = data->corner_edges;
|
||||
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 = corner_verts[loop_index];
|
||||
const int edge_i = corner_edges[loop_index];
|
||||
|
||||
for (; ml_curr_index <= ml_last_index; ml_curr_index++) {
|
||||
const int vert_i = corner_verts[ml_curr_index];
|
||||
const int edge_i = corner_edges[ml_curr_index];
|
||||
e2l = edge_to_loops[edge_i];
|
||||
|
||||
/* 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[vert_i]);
|
||||
}
|
||||
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,
|
||||
|
@ -851,12 +833,12 @@ 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 && is_angle_sharp) {
|
||||
sharp_edges[edge_i].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[edge_i].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 int *corner_verts,
|
||||
const int *corner_edges,
|
||||
|
@ -903,26 +874,31 @@ 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.corner_verts = {corner_verts, numLoops};
|
||||
common_data.corner_edges = {corner_edges, 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},
|
||||
{corner_verts, numLoops},
|
||||
{corner_edges, 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<int> corner_verts,
|
||||
|
@ -1044,7 +1020,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
|
|||
const Span<MPoly> polys = common_data->polys;
|
||||
const Span<int> corner_verts = common_data->corner_verts;
|
||||
const Span<int> corner_edges = common_data->corner_edges;
|
||||
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;
|
||||
|
||||
|
@ -1286,7 +1262,7 @@ static void loop_split_worker(TaskPool *__restrict pool, void *taskdata)
|
|||
static bool loop_split_generator_check_cyclic_smooth_fan(const Span<int> corner_verts,
|
||||
const Span<int> corner_edges,
|
||||
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,
|
||||
|
@ -1357,7 +1333,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
|
|||
const Span<int> corner_edges = common_data->corner_edges;
|
||||
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(corner_verts.size(), false);
|
||||
|
||||
|
@ -1572,8 +1548,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;
|
||||
|
@ -1603,6 +1578,8 @@ 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);
|
||||
|
||||
/* Init data common to all tasks. */
|
||||
LoopSplitTaskDataCommon common_data;
|
||||
common_data.lnors_spacearr = r_lnors_spacearr;
|
||||
|
@ -1618,8 +1595,28 @@ void BKE_mesh_normals_loop_split(const float (*positions)[3],
|
|||
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[corner_verts[loop_i]]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/* 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,
|
||||
{corner_verts, numLoops},
|
||||
{corner_edges, numLoops},
|
||||
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. */
|
||||
|
@ -1635,8 +1632,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);
|
||||
|
@ -1735,7 +1730,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)
|
||||
|
@ -1747,70 +1745,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;
|
||||
int corner_prev = -1;
|
||||
const float *org_nor = nullptr;
|
||||
|
||||
while (loops) {
|
||||
const int lidx = POINTER_AS_INT(loops->link);
|
||||
HooglyBoogly marked this conversation as resolved
Outdated
|
||||
float *nor = r_custom_loopnors[lidx];
|
||||
|
||||
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 int mlp = (lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1;
|
||||
const int edge = corner_edges[lidx];
|
||||
const int edge_p = corner_edges[mlp];
|
||||
const int prev_edge = corner_edges[corner_prev];
|
||||
medges[prev_edge == edge_p ? prev_edge : edge].flag |= ME_SHARP;
|
||||
|
||||
org_nor = nor;
|
||||
}
|
||||
|
||||
LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
|
||||
int corner_prev = -1;
|
||||
const float *org_nor = nullptr;
|
||||
corner_prev = lidx;
|
||||
loops = loops->next;
|
||||
done_loops[lidx].set();
|
||||
}
|
||||
|
||||
while (loops) {
|
||||
const int lidx = POINTER_AS_INT(loops->link);
|
||||
float *nor = r_custom_loopnors[lidx];
|
||||
/* 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);
|
||||
float *nor = r_custom_loopnors[lidx];
|
||||
|
||||
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 int mlp = (lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1;
|
||||
const int edge = corner_edges[lidx];
|
||||
const int edge_p = corner_edges[mlp];
|
||||
const int prev_edge = corner_edges[corner_prev];
|
||||
medges[prev_edge == edge_p ? prev_edge : edge].flag |= ME_SHARP;
|
||||
|
||||
org_nor = nor;
|
||||
}
|
||||
|
||||
corner_prev = lidx;
|
||||
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);
|
||||
float *nor = r_custom_loopnors[lidx];
|
||||
|
||||
if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
|
||||
const MPoly *mp = &mpolys[loop_to_poly[lidx]];
|
||||
const int mlp = (lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1;
|
||||
const int edge = corner_edges[lidx];
|
||||
const int edge_p = corner_edges[mlp];
|
||||
const int prev_edge = corner_edges[corner_prev];
|
||||
medges[prev_edge == edge_p ? prev_edge : edge].flag |= ME_SHARP;
|
||||
}
|
||||
if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
|
||||
const MPoly *mp = &mpolys[loop_to_poly[lidx]];
|
||||
const int mlp = (lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1;
|
||||
const int edge = corner_edges[lidx];
|
||||
const int edge_p = corner_edges[mlp];
|
||||
const int prev_edge = corner_edges[corner_prev];
|
||||
medges[prev_edge == edge_p ? prev_edge : edge].flag |= ME_SHARP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1835,9 +1834,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. */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -150,6 +150,11 @@ template<typename Key, typename Value> class MultiValueMap {
|
|||
{
|
||||
map_.clear();
|
||||
}
|
||||
|
||||
void clear_and_shrink()
|
||||
{
|
||||
map_.clear_and_shrink();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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(){};
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
|
@ -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, ...) \
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
@ -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";
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
uniform vec4 cryptohash;
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue
This does not build in a debug build.