Cycles: Add Blender UI and operators for texture cache

* Performance > Texture Cache panel with enable and auto-generate
  options.
* Operator to generate texture caches for all images used by
  shader nodes in a blend file.
* Texture cache directory preference with support for both
  absolute and image relative paths.
* Replace Simplify > Texture limit with Texture Resolution factor,
  that works with both full and tiled images.

The texture cache is enable by default but auto generate is not. This means
that if you are already image files with tiles and mipmaps it will use them,
like the attic, bistro or alab scenes. But it will not automatically generate
tx files.

Pull Request: https://projects.blender.org/blender/blender/pulls/154913
This commit is contained in:
Brecht Van Lommel 2026-02-15 02:38:34 +01:00
parent f791c7164f
commit e9b53b86f0
24 changed files with 413 additions and 52 deletions

View file

@ -4,10 +4,6 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
namespace blender {
struct Image;
@ -28,7 +24,3 @@ bool CCL_generate_texture_cache(const Image *image,
const char *texture_cache_directory = "");
} // namespace blender
#ifdef __cplusplus
}
#endif

View file

@ -178,16 +178,6 @@ enum_device_type = (
('ONEAPI', "oneAPI", "oneAPI", 6)
)
enum_texture_limit = (
('OFF', "No Limit", "No texture size limit", 0),
('128', "128", "Limit texture size to 128 pixels", 1),
('256', "256", "Limit texture size to 256 pixels", 2),
('512', "512", "Limit texture size to 512 pixels", 3),
('1024', "1024", "Limit texture size to 1024 pixels", 4),
('2048', "2048", "Limit texture size to 2048 pixels", 5),
('4096', "4096", "Limit texture size to 4096 pixels", 6),
('8192', "8192", "Limit texture size to 8192 pixels", 7),
)
enum_fast_gi_method = (
('REPLACE', "Replace", "Replace global illumination with ambient occlusion after a specified number of bounces"),
@ -1009,18 +999,20 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
subtype='FACTOR',
)
texture_limit: EnumProperty(
name="Viewport Texture Limit",
default='OFF',
description="Limit texture size used by viewport rendering",
items=enum_texture_limit
texture_resolution: FloatProperty(
name="Viewport Texture Resolution",
default=1.0,
description="Scale factor for texture resolution used by viewport rendering",
min=0.00001, max=1.0,
subtype='FACTOR',
)
texture_limit_render: EnumProperty(
name="Render Texture Limit",
default='OFF',
description="Limit texture size used by final rendering",
items=enum_texture_limit
texture_resolution_render: FloatProperty(
name="Render Texture Resolution",
default=1.0,
description="Scale factor for texture resolution used by final rendering",
min=0.0, max=1.0,
subtype='FACTOR',
)
use_fast_gi: BoolProperty(

View file

@ -878,6 +878,31 @@ class CYCLES_RENDER_PT_performance_memory(CyclesButtonsPanel, Panel):
layout.prop(cscene, "tile_size")
class CYCLES_RENDER_PT_performance_texture_cache(CyclesButtonsPanel, Panel):
bl_label = "Texture Cache"
bl_parent_id = "CYCLES_RENDER_PT_performance"
def draw_header(self, context):
rd = context.scene.render
self.layout.prop(rd, "use_texture_cache", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
rd = context.scene.render
col = layout.column()
col.active = rd.use_texture_cache
col.prop(rd, "use_auto_generate_texture_cache", text="Auto Generate")
row = col.split(factor=0.4)
row.label()
row.operator("render.generate_texture_cache", text="Generate All")
class CYCLES_RENDER_PT_performance_acceleration_structure(CyclesButtonsPanel, Panel):
bl_label = "Acceleration Structure"
bl_parent_id = "CYCLES_RENDER_PT_performance"
@ -2296,7 +2321,7 @@ class CYCLES_RENDER_PT_simplify_viewport(CyclesButtonsPanel, Panel):
col = layout.column()
col.prop(rd, "simplify_subdivision", text="Max Subdivision")
col.prop(rd, "simplify_child_particles", text="Child Particles")
col.prop(cscene, "texture_limit", text="Texture Limit")
col.prop(cscene, "texture_resolution", text="Texture Resolution")
col.prop(rd, "simplify_volumes", text="Volume Resolution")
col.prop(rd, "use_simplify_normals", text="Normals")
@ -2322,7 +2347,7 @@ class CYCLES_RENDER_PT_simplify_render(CyclesButtonsPanel, Panel):
col.prop(rd, "simplify_subdivision_render", text="Max Subdivision")
col.prop(rd, "simplify_child_particles_render", text="Child Particles")
col.prop(cscene, "texture_limit_render", text="Texture Limit")
col.prop(cscene, "texture_resolution_render", text="Texture Resolution")
class CYCLES_RENDER_PT_simplify_culling(CyclesButtonsPanel, Panel):
@ -2552,6 +2577,7 @@ classes = (
CYCLES_RENDER_PT_performance_compositor_denoise_settings,
CYCLES_RENDER_PT_performance_threads,
CYCLES_RENDER_PT_performance_memory,
CYCLES_RENDER_PT_performance_texture_cache,
CYCLES_RENDER_PT_performance_acceleration_structure,
CYCLES_RENDER_PT_performance_final_render,
CYCLES_RENDER_PT_performance_viewport,

View file

@ -101,7 +101,7 @@ def do_versions(self):
library_versions.setdefault(library.version, []).append(library)
# Do versioning per library, since they might have different versions.
max_need_versioning = (5, 0, 77)
max_need_versioning = (5, 2, 8)
for version, libraries in library_versions.items():
if version > max_need_versioning:
continue
@ -111,6 +111,17 @@ def do_versions(self):
if scene.library not in libraries:
continue
# Texture limit enum replaced with texture resolution float.
# Convert assuming a 1024 image resolution.
if version <= (5, 2, 8):
cscene = scene.cycles
for prop_old, prop_new in (("texture_limit", "texture_resolution"),
("texture_limit_render", "texture_resolution_render")):
texture_limit_enum = cscene.get(prop_old, 0)
if texture_limit_enum > 0:
limit_pixels = 1 << (texture_limit_enum + 6)
cscene[prop_new] = min(limit_pixels / 1024.0, 1.0)
# Auto tiling is always enabled now
if version <= (5, 0, 77):
cscene = scene.cycles

View file

@ -349,7 +349,7 @@ static void blender_camera_from_object(BlenderCamera *bcam,
}
else {
bcam->custom_filepath = blender_absolute_path(
b_data, b_camera.id, b_camera.custom_filepath);
b_data, &b_camera.id, b_camera.custom_filepath);
}
}
}

View file

@ -121,7 +121,7 @@ void BlenderSession::create_session()
const SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, *b_scene, background, pixelsize);
const SceneParams scene_params = BlenderSync::get_scene_params(
*b_scene, background, use_developer_ui);
b_userpref, *b_data, *b_scene, background, use_developer_ui);
const bool session_pause = BlenderSync::get_session_pause(*b_scene, background);
/* reset status/progress */
@ -208,7 +208,7 @@ void BlenderSession::reset_session(blender::Main &b_data, blender::Depsgraph &b_
const SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, *b_scene, background, pixelsize);
const SceneParams scene_params = BlenderSync::get_scene_params(
*b_scene, background, use_developer_ui);
b_userpref, b_data, *b_scene, background, use_developer_ui);
if (scene->params.modified(scene_params) || session->params.modified(session_params) ||
(this->b_render->mode & blender::R_PERSISTENT_DATA) == 0)
@ -782,7 +782,7 @@ void BlenderSession::synchronize(blender::Depsgraph &b_depsgraph_)
const SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, *b_scene, background, pixelsize);
const SceneParams scene_params = BlenderSync::get_scene_params(
*b_scene, background, use_developer_ui);
b_userpref, *b_data, *b_scene, background, use_developer_ui);
const bool session_pause = BlenderSync::get_session_pause(*b_scene, background);
if (session->params.modified(session_params) || scene->params.modified(scene_params)) {

View file

@ -255,7 +255,8 @@ static void set_default_value(ShaderInput *input,
}
case SocketType::STRING: {
const auto &default_value = *b_sock.default_value_typed<blender::bNodeSocketValueString>();
node->set(socket, (ustring)blender_absolute_path(b_data, b_id, default_value.value).c_str());
node->set(socket,
(ustring)blender_absolute_path(b_data, &b_id, default_value.value).c_str());
break;
}
default:
@ -812,7 +813,7 @@ static ShaderNode *add_node(Scene *scene,
}
else {
const string absolute_filepath = blender_absolute_path(
b_data, b_ntree.id, storage.filepath);
b_data, &b_ntree.id, storage.filepath);
node = OSLShaderManager::osl_node(graph, scene, absolute_filepath, "");
}
}
@ -1044,7 +1045,7 @@ static ShaderNode *add_node(Scene *scene,
IESLightNode *ies = graph->create_node<IESLightNode>();
switch (storage.mode) {
case blender::NODE_IES_EXTERNAL:
ies->set_filename(ustring(blender_absolute_path(b_data, b_ntree.id, storage.filepath)));
ies->set_filename(ustring(blender_absolute_path(b_data, &b_ntree.id, storage.filepath)));
break;
case blender::NODE_IES_INTERNAL:
ustring ies_content = ustring(get_text_datablock_content(b_node.id));

View file

@ -4,6 +4,8 @@
#include "BKE_appdir.hh"
#include "DEG_depsgraph_query.hh"
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
#include "DNA_world_types.h"
#include "RNA_prototypes.hh"
#include "RNA_types.hh"
@ -911,7 +913,9 @@ void BlenderSync::free_data_after_sync(blender::Depsgraph &b_depsgraph)
/* Scene Parameters */
SceneParams BlenderSync::get_scene_params(blender::Scene &b_scene,
SceneParams BlenderSync::get_scene_params(blender::UserDef &b_preferences,
blender::Main &b_data,
blender::Scene &b_scene,
const bool background,
const bool use_developer_ui)
{
@ -944,23 +948,27 @@ SceneParams BlenderSync::get_scene_params(blender::Scene &b_scene,
params.hair_shape = (CurveShapeType)get_enum(
csscene, "shape", CURVE_NUM_SHAPE_TYPES, CURVE_THICK);
int texture_limit;
float texture_resolution;
if (background) {
texture_limit = RNA_enum_get(&cscene, "texture_limit_render");
texture_resolution = RNA_float_get(&cscene, "texture_resolution_render");
}
else {
texture_limit = RNA_enum_get(&cscene, "texture_limit");
texture_resolution = RNA_float_get(&cscene, "texture_resolution");
}
if (texture_limit > 0 && (b_scene.r.mode & blender::R_SIMPLIFY) != 0) {
params.texture_resolution = 1 << (texture_limit + 6);
if (texture_resolution < 1.0f && (b_scene.r.mode & blender::R_SIMPLIFY) != 0) {
params.texture_resolution = texture_resolution;
}
else {
params.texture_resolution = 0;
params.texture_resolution = 1.0f;
}
params.bvh_layout = DebugFlags().cpu.bvh_layout;
params.background = background;
params.use_texture_cache = b_scene.r.scemode & blender::R_USE_TEXTURE_CACHE;
params.auto_texture_cache = b_scene.r.scemode & blender::R_TEXTURE_CACHE_AUTO_GENERATE;
params.texture_cache_path = blender_absolute_path(
b_data, nullptr, b_preferences.texture_cachedir);
return params;
}

View file

@ -4,6 +4,7 @@
#pragma once
#include "DNA_userdef_types.h"
#include "RNA_types.hh"
#include "blender/id_map.h"
@ -95,7 +96,9 @@ class BlenderSync {
void free_data_after_sync(blender::Depsgraph &b_depsgraph);
/* get parameters */
static SceneParams get_scene_params(blender::Scene &b_scene,
static SceneParams get_scene_params(blender::UserDef &b_preferences,
blender::Main &b_data,
blender::Scene &b_scene,
const bool background,
const bool use_developer_ui);
static SessionParams get_session_params(blender::RenderEngine &b_engine,

View file

@ -1,4 +1,4 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
/* SPDX-FileCopyrightText: 2011-2026 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */

View file

@ -477,14 +477,14 @@ static inline void set_string(blender::PointerRNA &ptr, const char *name, const
/* Relative Paths */
static inline string blender_absolute_path(blender::Main &b_data,
blender::ID &b_id,
blender::ID *b_id,
const string &path)
{
if (path.size() >= 2 && path[0] == '/' && path[1] == '/') {
string dirname;
if (b_id.lib) {
dirname = blender_absolute_path(b_data, b_id.lib->id, b_id.lib->filepath);
if (b_id && b_id->lib) {
dirname = blender_absolute_path(b_data, &b_id->lib->id, b_id->lib->filepath);
}
else {
dirname = b_data.filepath;

View file

@ -1657,6 +1657,7 @@ class USERPREF_PT_file_paths_render(FilePathsPanel, Panel):
paths = context.preferences.filepaths
col = self.layout.column()
col.prop(paths, "texture_cache_directory", text="Texture Cache")
col.prop(paths, "render_output_directory", text="Render Output")
col.prop(paths, "render_cache_directory", text="Render Cache")

View file

@ -30,7 +30,7 @@ namespace blender {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 14
#define BLENDER_FILE_SUBVERSION 15
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View file

@ -11,6 +11,7 @@
#include "DNA_ID.h"
#include "DNA_brush_types.h"
#include "DNA_curve_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "BLI_listbase_iterator.hh"
@ -195,6 +196,11 @@ void blo_do_versions_520(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
fix_single_point_curves_custom_knots(bmain);
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 502, 15)) {
for (Scene &scene : bmain->scenes) {
scene.r.scemode |= R_USE_TEXTURE_CACHE;
}
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.

View file

@ -21,6 +21,7 @@
#include "ED_screen.hh"
#include "UI_resources.hh"
#include "WM_api.hh"
#include "UI_interface_c.hh"
@ -212,6 +213,15 @@ void template_running_jobs(Layout *layout, bContext *C)
}
}
/* Blend file wide jobs. */
if (owner == nullptr) {
if (WM_jobs_test(wm, bmain, WM_JOB_TYPE_GENERATE_TEXTURE_CACHE)) {
owner = bmain;
cancel_fn = set_global_break;
icon = ICON_TEXTURE;
}
}
if (owner) {
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
const bool active = !(G.is_break || WM_jobs_is_stopped(wm, owner));

View file

@ -18,6 +18,7 @@ set(SRC
render_ops.cc
render_preview.cc
render_shading.cc
render_texture_cache.cc
render_update.cc
render_view.cc
@ -61,6 +62,11 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
if(WITH_CYCLES)
add_definitions(-DWITH_CYCLES)
list(APPEND INC ../../../../intern/cycles/blender)
endif()
blender_add_lib(bf_editor_render "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
# RNA_prototypes.hh

View file

@ -74,6 +74,10 @@ void TEXTURE_OT_slot_copy(wmOperatorType *ot);
void TEXTURE_OT_slot_paste(wmOperatorType *ot);
void TEXTURE_OT_slot_move(wmOperatorType *ot);
/* `render_texture_cache.cc` */
void RENDER_OT_generate_texture_cache(wmOperatorType *ot);
/* `render_internal.cc` */
/* Base class for all WM_JOB_TYPE_RENDER jobs. */

View file

@ -76,6 +76,10 @@ void ED_operatortypes_render()
WM_operatortype_append(TEXTURE_OT_slot_paste);
WM_operatortype_append(TEXTURE_OT_slot_move);
#ifdef WITH_CYCLES
WM_operatortype_append(RENDER_OT_generate_texture_cache);
#endif
/* `render_internal.cc` */
WM_operatortype_append(RENDER_OT_view_show);
WM_operatortype_append(RENDER_OT_render);

View file

@ -0,0 +1,262 @@
/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edrend
*/
#ifdef WITH_CYCLES
# include "render_intern.hh" /* own include */
# include <mutex>
# include "MEM_guardedalloc.h"
# include "DNA_image_types.h"
# include "DNA_userdef_types.h"
# include "DNA_windowmanager_enums.h"
# include "BLI_fileops.h"
# include "BLI_listbase.h"
# include "BLI_path_utils.hh"
# include "BLI_set.hh"
# include "BLI_string.h"
# include "BLI_task.hh"
# include "BLI_vector.hh"
# include "BKE_context.hh"
# include "BKE_global.hh"
# include "BKE_image.hh"
# include "BKE_lib_query.hh"
# include "BKE_main.hh"
# include "BKE_node.hh"
# include "BKE_report.hh"
# include "BLT_translation.hh"
# include "WM_api.hh"
# include "CCL_api.h"
namespace blender {
/* -------------------------------------------------------------------- */
/** \name Generate Texture Cache Operator
* \{ */
struct GenerateTextureCacheJob {
Main *bmain;
ReportList *reports;
};
static void generate_texture_cache(Main *bmain,
ReportList *reports,
wmJobWorkerStatus *worker_status = nullptr)
{
/* Gather images to generate for. */
blender::Set<const Image *> images;
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type != NTREE_SHADER) {
continue;
}
BKE_library_foreach_ID_link(
bmain,
&ntree->id,
[&](LibraryIDLinkCallbackData *cb_data) {
ID *image_id = *cb_data->id_pointer;
if (image_id && GS(image_id->name) == ID_IM) {
Image *image = blender::id_cast<Image *>(image_id);
images.add(image);
}
return IDWALK_RET_NOP;
},
nullptr,
IDWALK_READONLY);
}
FOREACH_NODETREE_END;
/* Gather filepaths to generate for, expanding UDIMs and sequences. */
blender::Set<std::pair<const Image *, std::string>> filepaths;
int total = 0;
for (const Image *image : images) {
if (ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
continue;
}
if (BKE_image_has_packedfile(image)) {
continue;
}
if (image->filepath[0] == '\0') {
continue;
}
/* Get regular absolute path. */
char filepath[FILE_MAX];
STRNCPY(filepath, image->filepath);
BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&image->id));
BLI_path_normalize(filepath);
/* Handle each UDIM tile. */
if (image->source == IMA_SRC_TILED) {
eUDIM_TILE_FORMAT tile_format = UDIM_TILE_FORMAT_NONE;
char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format);
if (tile_format != UDIM_TILE_FORMAT_NONE) {
for (const ImageTile &tile : image->tiles) {
char tile_filepath[FILE_MAX];
BKE_image_set_filepath_from_tile_number(
tile_filepath, udim_pattern, tile_format, tile.tile_number);
if (BLI_is_file(tile_filepath)) {
if (!CCL_has_texture_cache(image, tile_filepath, U.texture_cachedir)) {
filepaths.add({image, tile_filepath});
}
total++;
}
}
MEM_delete(udim_pattern);
continue;
}
}
if (image->source == IMA_SRC_SEQUENCE) {
/* TODO: Handle image sequence. */
}
/* Handle regular image. */
if (BLI_is_file(filepath)) {
if (!CCL_has_texture_cache(image, filepath, U.texture_cachedir)) {
filepaths.add({image, filepath});
}
total++;
}
}
/* Generate texture cache. */
std::atomic<int> completed = 0;
std::atomic<int> failed = 0;
std::mutex reports_mutex;
blender::threading::parallel_for_each(filepaths, [&](const auto &item) {
if (worker_status) {
if (G.is_break || worker_status->stop) {
return;
}
worker_status->progress = (completed + failed) / float(filepaths.size());
worker_status->do_update = true;
}
if (CCL_generate_texture_cache(item.first, item.second.c_str(), U.texture_cachedir)) {
completed++;
}
else {
std::scoped_lock lock(reports_mutex);
BKE_reportf(
reports, RPT_ERROR, "Failed to generate texture cache for: %s", item.second.c_str());
failed++;
}
});
/* Report stats. */
if (total == 0) {
BKE_report(reports, RPT_INFO, "No image files found to generate tx files");
}
else {
BKE_reportf(reports,
(failed) ? RPT_WARNING : RPT_INFO,
"Generated %d tx files, %d failed, %d up to date",
completed.load(),
failed.load(),
total - int(filepaths.size()));
}
}
static wmOperatorStatus generate_texture_cache_exec(bContext *C, wmOperator *op)
{
generate_texture_cache(CTX_data_main(C), op->reports);
return OPERATOR_FINISHED;
}
static void generate_texture_cache_startjob(void *customdata, wmJobWorkerStatus *worker_status)
{
GenerateTextureCacheJob *job = static_cast<GenerateTextureCacheJob *>(customdata);
generate_texture_cache(job->bmain, job->reports, worker_status);
}
static wmOperatorStatus generate_texture_cache_invoke(bContext *C,
wmOperator *op,
const wmEvent * /*event*/)
{
wmWindowManager *wm = CTX_wm_manager(C);
Main *bmain = CTX_data_main(C);
wmJob *wm_job = WM_jobs_get(wm,
CTX_wm_window(C),
bmain,
RPT_("Generating texture cache..."),
WM_JOB_PRIORITY | WM_JOB_PROGRESS,
WM_JOB_TYPE_GENERATE_TEXTURE_CACHE);
GenerateTextureCacheJob *job = MEM_new<GenerateTextureCacheJob>(__func__);
job->bmain = bmain;
job->reports = op->reports;
WM_jobs_customdata_set(wm_job, job, [](void *customdata) {
MEM_delete(static_cast<GenerateTextureCacheJob *>(customdata));
});
WM_jobs_timer(wm_job, 0.2, NC_WM | ND_JOB, 0);
WM_jobs_callbacks(wm_job, generate_texture_cache_startjob, nullptr, nullptr, nullptr);
G.is_break = false;
WM_jobs_start(wm, wm_job);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
static wmOperatorStatus generate_texture_cache_modal(bContext *C,
wmOperator * /*op*/,
const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
Main *bmain = CTX_data_main(C);
if (0 == WM_jobs_test(wm, bmain, WM_JOB_TYPE_GENERATE_TEXTURE_CACHE)) {
return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
}
return (event->type == EVT_ESCKEY) ? OPERATOR_RUNNING_MODAL : OPERATOR_PASS_THROUGH;
}
static void generate_texture_cache_cancel(bContext *C, wmOperator * /*op*/)
{
wmWindowManager *wm = CTX_wm_manager(C);
Main *bmain = CTX_data_main(C);
WM_jobs_kill_type(wm, bmain, WM_JOB_TYPE_GENERATE_TEXTURE_CACHE);
}
void RENDER_OT_generate_texture_cache(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Generate Texture Cache";
ot->idname = "RENDER_OT_generate_texture_cache";
ot->description = "Generate Cycles texture cache files for all images used in shader nodes";
/* API callbacks. */
ot->exec = generate_texture_cache_exec;
ot->invoke = generate_texture_cache_invoke;
ot->modal = generate_texture_cache_modal;
ot->cancel = generate_texture_cache_cancel;
/* flags */
ot->flag = OPTYPE_REGISTER;
}
/** \} */
} // namespace blender
#endif

View file

@ -782,6 +782,8 @@ enum {
R_SCEMODE_UNUSED_19 = 1 << 19, /* cleared */
R_EXR_CACHE_FILE = 1 << 20,
R_MULTIVIEW = 1 << 21,
R_USE_TEXTURE_CACHE = 1 << 22,
R_TEXTURE_CACHE_AUTO_GENERATE = 1 << 23,
};
/** #RenderData::stamp */
@ -886,7 +888,7 @@ struct RenderData {
/**
* Flags for render settings. Use bit-masking to access the settings.
*/
int scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION;
int scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION | R_USE_TEXTURE_CACHE;
/**
* Flags for render settings. Use bit-masking to access the settings.

View file

@ -897,6 +897,7 @@ struct UserDef {
/* EXR cache path */
char render_cachedir[/*FILE_MAXDIR*/ 768] = "";
char textudir[/*FILE_MAXDIR*/ 768] = "//";
char texture_cachedir[/*FILE_MAXDIR*/ 768] = "";
/* Deprecated, use #UserDef.script_directories instead. */
DNA_DEPRECATED char pythondir_legacy[/*FILE_MAXDIR*/ 768] = "";
char sounddir[/*FILE_MAXDIR*/ 768] = "//";

View file

@ -7699,6 +7699,27 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
"meshes in the viewport");
RNA_def_property_update(prop, 0, "rna_Scene_use_simplify_normals_update");
/* Texture Cache */
prop = RNA_def_property(srna, "use_texture_cache", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "scemode", R_USE_TEXTURE_CACHE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
prop,
"Texture Cache",
"Load texture tiles at appropriate resolution on demand to reduce memory usage. This avoids "
"loading all textures into memory, at the cost of extra disk space and some perforamnce");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr);
prop = RNA_def_property(srna, "use_auto_generate_texture_cache", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "scemode", R_TEXTURE_CACHE_AUTO_GENERATE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop,
"Auto Generate Texture Cache",
"Automatically create tx files from image files when rendering, if the "
"files do not exist or are outdated. The path to store the texture "
"cache files is configured in the preferences");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr);
/* Grease Pencil - Simplify Options */
prop = RNA_def_property(srna, "simplify_gpencil", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "simplify_gpencil", SIMPLIFY_GPENCIL_ENABLE);

View file

@ -7333,6 +7333,16 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Render Cache Path", "Where to cache raw render results");
RNA_def_property_flag(prop, PROP_PATH_SUPPORTS_BLEND_RELATIVE);
prop = RNA_def_property(srna, "texture_cache_directory", PROP_STRING, PROP_DIRPATH);
RNA_def_property_string_sdna(prop, nullptr, "texture_cachedir");
RNA_def_property_ui_text(
prop,
"Texture Cache Path",
"The directory for storing tx files generated from image files, for more efficient "
"rendering. Paths may be absolute, or relative to the image file. Leave blank to store "
"tx files in the same directory as image files");
RNA_def_property_flag(prop, PROP_PATH_SUPPORTS_BLEND_RELATIVE);
prop = RNA_def_property(srna, "image_editor", PROP_STRING, PROP_FILEPATH);
RNA_def_property_string_sdna(prop, nullptr, "image_editor");
RNA_def_property_ui_text(prop, "Image Editor", "Path to an image editor");

View file

@ -1885,6 +1885,7 @@ enum eWM_JobType {
WM_JOB_TYPE_CALCULATE_SIMULATION_NODES,
WM_JOB_TYPE_BAKE_GEOMETRY_NODES,
WM_JOB_TYPE_UV_PACK,
WM_JOB_TYPE_GENERATE_TEXTURE_CACHE,
/* Add as needed, bake, seq proxy build
* if having hard coded values is a problem. */
};