Cycles: Introduce scene host_update function
The longer-term goal is to separate host-only scene update from device update: make it possible to make kernel features depend on actual scene state and flags. This change makes it so shaders are compiled before kernel load, making checks like "has_volume" available at the kernel features calculation state. No functional changes are expected at this point. Differential Revision: https://developer.blender.org/D12795
This commit is contained in:
@@ -91,24 +91,20 @@ void OSLShaderManager::reset(Scene * /*scene*/)
|
||||
shading_system_init();
|
||||
}
|
||||
|
||||
void OSLShaderManager::device_update_specific(Device *device,
|
||||
DeviceScene *dscene,
|
||||
Scene *scene,
|
||||
Progress &progress)
|
||||
void OSLShaderManager::host_update_specific(Device *device, Scene *scene, Progress &progress)
|
||||
{
|
||||
if (!need_update())
|
||||
if (!need_update()) {
|
||||
return;
|
||||
}
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
if (scene->update_stats) {
|
||||
scene->update_stats->osl.times.add_entry({"device_update", time});
|
||||
scene->update_stats->osl.times.add_entry({"host_update", time});
|
||||
}
|
||||
});
|
||||
|
||||
VLOG(1) << "Total " << scene->shaders.size() << " shaders.";
|
||||
|
||||
device_free(device, dscene, scene);
|
||||
|
||||
/* set texture system */
|
||||
scene->image_manager->set_osl_texture_system((void *)ts);
|
||||
|
||||
@@ -116,13 +112,14 @@ void OSLShaderManager::device_update_specific(Device *device,
|
||||
OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
|
||||
Shader *background_shader = scene->background->get_shader(scene);
|
||||
|
||||
foreach (Shader *shader, scene->shaders) {
|
||||
for (Shader *shader : scene->shaders) {
|
||||
assert(shader->graph);
|
||||
|
||||
if (progress.get_cancel())
|
||||
if (progress.get_cancel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* we can only compile one shader at the time as the OSL ShadingSytem
|
||||
/* we can only compile one shader at the time as the OSL ShadingSystem
|
||||
* has a single state, but we put the lock here so different renders can
|
||||
* compile shaders alternating */
|
||||
thread_scoped_lock lock(ss_mutex);
|
||||
@@ -131,30 +128,15 @@ void OSLShaderManager::device_update_specific(Device *device,
|
||||
compiler.background = (shader == background_shader);
|
||||
compiler.compile(og, shader);
|
||||
|
||||
if (shader->get_use_mis() && shader->has_surface_emission)
|
||||
if (shader->get_use_mis() && shader->has_surface_emission) {
|
||||
scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
|
||||
}
|
||||
}
|
||||
|
||||
/* setup shader engine */
|
||||
og->ss = ss;
|
||||
og->ts = ts;
|
||||
og->services = services;
|
||||
|
||||
int background_id = scene->shader_manager->get_shader_id(background_shader);
|
||||
og->background_state = og->surface_state[background_id & SHADER_MASK];
|
||||
og->use = true;
|
||||
|
||||
foreach (Shader *shader, scene->shaders)
|
||||
shader->clear_modified();
|
||||
|
||||
update_flags = UPDATE_NONE;
|
||||
|
||||
/* add special builtin texture types */
|
||||
services->textures.insert(ustring("@ao"), new OSLTextureHandle(OSLTextureHandle::AO));
|
||||
services->textures.insert(ustring("@bevel"), new OSLTextureHandle(OSLTextureHandle::BEVEL));
|
||||
|
||||
device_update_common(device, dscene, scene, progress);
|
||||
|
||||
{
|
||||
/* Perform greedyjit optimization.
|
||||
*
|
||||
@@ -172,6 +154,43 @@ void OSLShaderManager::device_update_specific(Device *device,
|
||||
}
|
||||
}
|
||||
|
||||
void OSLShaderManager::device_update_specific(Device *device,
|
||||
DeviceScene *dscene,
|
||||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
if (scene->update_stats) {
|
||||
scene->update_stats->osl.times.add_entry({"device_update", time});
|
||||
}
|
||||
});
|
||||
|
||||
device_free(device, dscene, scene);
|
||||
|
||||
OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
|
||||
Shader *background_shader = scene->background->get_shader(scene);
|
||||
|
||||
/* Setup shader engine. */
|
||||
og->ss = ss;
|
||||
og->ts = ts;
|
||||
og->services = services;
|
||||
|
||||
const int background_id = scene->shader_manager->get_shader_id(background_shader);
|
||||
og->background_state = og->surface_state[background_id & SHADER_MASK];
|
||||
og->use = true;
|
||||
|
||||
foreach (Shader *shader, scene->shaders) {
|
||||
shader->clear_modified();
|
||||
}
|
||||
|
||||
update_flags = UPDATE_NONE;
|
||||
|
||||
device_update_common(device, dscene, scene, progress);
|
||||
}
|
||||
|
||||
void OSLShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
|
||||
{
|
||||
OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
|
||||
|
@@ -79,6 +79,8 @@ class OSLShaderManager : public ShaderManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
void host_update_specific(Device *device, Scene *scene, Progress &progress) override;
|
||||
|
||||
void device_update_specific(Device *device,
|
||||
DeviceScene *dscene,
|
||||
Scene *scene,
|
||||
|
@@ -228,6 +228,22 @@ void Scene::free_memory(bool final)
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::host_update(Device *device, Progress &progress)
|
||||
{
|
||||
if (update_stats) {
|
||||
update_stats->clear();
|
||||
}
|
||||
|
||||
scoped_callback_timer timer([this](double time) {
|
||||
if (update_stats) {
|
||||
update_stats->scene.times.add_entry({"host_update", time});
|
||||
}
|
||||
});
|
||||
|
||||
progress.set_status("Updating Shaders");
|
||||
shader_manager->host_update(device, this, progress);
|
||||
}
|
||||
|
||||
void Scene::device_update(Device *device_, Progress &progress)
|
||||
{
|
||||
if (!device)
|
||||
@@ -235,10 +251,6 @@ void Scene::device_update(Device *device_, Progress &progress)
|
||||
|
||||
bool print_stats = need_data_update();
|
||||
|
||||
if (update_stats) {
|
||||
update_stats->clear();
|
||||
}
|
||||
|
||||
scoped_callback_timer timer([this, print_stats](double time) {
|
||||
if (update_stats) {
|
||||
update_stats->scene.times.add_entry({"device_update", time});
|
||||
@@ -537,11 +549,17 @@ bool Scene::update(Progress &progress)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Load render kernels, before device update where we upload data to the GPU. */
|
||||
/* Update scene data on the host side.
|
||||
* Only updates which do not depend on the kernel (including kernel features). */
|
||||
progress.set_status("Updating Scene");
|
||||
MEM_GUARDED_CALL(&progress, host_update, device, progress);
|
||||
|
||||
/* Load render kernels. After host scene update so that the required kernel features are known.
|
||||
*/
|
||||
load_kernels(progress, false);
|
||||
|
||||
/* Upload scene data to the GPU. */
|
||||
progress.set_status("Updating Scene");
|
||||
/* Upload scene data to the device. */
|
||||
progress.set_status("Updating Scene Device");
|
||||
MEM_GUARDED_CALL(&progress, device_update, device, progress);
|
||||
|
||||
return true;
|
||||
|
@@ -251,6 +251,10 @@ class Scene : public NodeOwner {
|
||||
Scene(const SceneParams ¶ms, Device *device);
|
||||
~Scene();
|
||||
|
||||
/* NOTE: Device can only use used to access invariant data. For example, OSL globals is valid
|
||||
* but anything what is related on kernel and kernel features is not. */
|
||||
void host_update(Device *device, Progress &progress);
|
||||
|
||||
void device_update(Device *device, Progress &progress);
|
||||
|
||||
bool need_global_attribute(AttributeStandard std);
|
||||
|
@@ -462,10 +462,7 @@ int ShaderManager::get_shader_id(Shader *shader, bool smooth)
|
||||
return id;
|
||||
}
|
||||
|
||||
void ShaderManager::device_update(Device *device,
|
||||
DeviceScene *dscene,
|
||||
Scene *scene,
|
||||
Progress &progress)
|
||||
void ShaderManager::host_update(Device *device, Scene *scene, Progress &progress)
|
||||
{
|
||||
if (!need_update()) {
|
||||
return;
|
||||
@@ -483,6 +480,18 @@ void ShaderManager::device_update(Device *device,
|
||||
assert(scene->default_background->reference_count() != 0);
|
||||
assert(scene->default_empty->reference_count() != 0);
|
||||
|
||||
host_update_specific(device, scene, progress);
|
||||
}
|
||||
|
||||
void ShaderManager::device_update(Device *device,
|
||||
DeviceScene *dscene,
|
||||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update()) {
|
||||
return;
|
||||
}
|
||||
|
||||
device_update_specific(device, dscene, scene, progress);
|
||||
}
|
||||
|
||||
|
@@ -193,6 +193,9 @@ class ShaderManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
void host_update(Device *device, Scene *scene, Progress &progress);
|
||||
virtual void host_update_specific(Device *device, Scene *scene, Progress &progress) = 0;
|
||||
|
||||
/* device update */
|
||||
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
|
||||
virtual void device_update_specific(Device *device,
|
||||
|
@@ -47,10 +47,10 @@ void SVMShaderManager::reset(Scene * /*scene*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SVMShaderManager::device_update_shader(Scene *scene,
|
||||
Shader *shader,
|
||||
Progress *progress,
|
||||
array<int4> *svm_nodes)
|
||||
static void host_compile_shader(Scene *scene,
|
||||
Shader *shader,
|
||||
Progress *progress,
|
||||
array<int4> *svm_nodes)
|
||||
{
|
||||
if (progress->get_cancel()) {
|
||||
return;
|
||||
@@ -69,6 +69,32 @@ void SVMShaderManager::device_update_shader(Scene *scene,
|
||||
<< summary.full_report();
|
||||
}
|
||||
|
||||
void SVMShaderManager::host_update_specific(Device * /*device*/, Scene *scene, Progress &progress)
|
||||
{
|
||||
if (!need_update()) {
|
||||
return;
|
||||
}
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
if (scene->update_stats) {
|
||||
scene->update_stats->svm.times.add_entry({"host_update", time});
|
||||
}
|
||||
});
|
||||
|
||||
const int num_shaders = scene->shaders.size();
|
||||
|
||||
VLOG(1) << "Total " << num_shaders << " shaders.";
|
||||
|
||||
/* Build all shaders. */
|
||||
TaskPool task_pool;
|
||||
shader_svm_nodes_.resize(num_shaders);
|
||||
for (int i = 0; i < num_shaders; i++) {
|
||||
task_pool.push(function_bind(
|
||||
host_compile_shader, scene, scene->shaders[i], &progress, &shader_svm_nodes_[i]));
|
||||
}
|
||||
task_pool.wait_work();
|
||||
}
|
||||
|
||||
void SVMShaderManager::device_update_specific(Device *device,
|
||||
DeviceScene *dscene,
|
||||
Scene *scene,
|
||||
@@ -92,19 +118,6 @@ void SVMShaderManager::device_update_specific(Device *device,
|
||||
/* test if we need to update */
|
||||
device_free(device, dscene, scene);
|
||||
|
||||
/* Build all shaders. */
|
||||
TaskPool task_pool;
|
||||
vector<array<int4>> shader_svm_nodes(num_shaders);
|
||||
for (int i = 0; i < num_shaders; i++) {
|
||||
task_pool.push(function_bind(&SVMShaderManager::device_update_shader,
|
||||
this,
|
||||
scene,
|
||||
scene->shaders[i],
|
||||
&progress,
|
||||
&shader_svm_nodes[i]));
|
||||
}
|
||||
task_pool.wait_work();
|
||||
|
||||
if (progress.get_cancel()) {
|
||||
return;
|
||||
}
|
||||
@@ -114,7 +127,7 @@ void SVMShaderManager::device_update_specific(Device *device,
|
||||
int svm_nodes_size = num_shaders;
|
||||
for (int i = 0; i < num_shaders; i++) {
|
||||
/* Since we're not copying the local jump node, the size ends up being one node lower. */
|
||||
svm_nodes_size += shader_svm_nodes[i].size() - 1;
|
||||
svm_nodes_size += shader_svm_nodes_[i].size() - 1;
|
||||
}
|
||||
|
||||
int4 *svm_nodes = dscene->svm_nodes.alloc(svm_nodes_size);
|
||||
@@ -132,22 +145,22 @@ void SVMShaderManager::device_update_specific(Device *device,
|
||||
* Each compiled shader starts with a jump node that has offsets local
|
||||
* to the shader, so copy those and add the offset into the global node list. */
|
||||
int4 &global_jump_node = svm_nodes[shader->id];
|
||||
int4 &local_jump_node = shader_svm_nodes[i][0];
|
||||
int4 &local_jump_node = shader_svm_nodes_[i][0];
|
||||
|
||||
global_jump_node.x = NODE_SHADER_JUMP;
|
||||
global_jump_node.y = local_jump_node.y - 1 + node_offset;
|
||||
global_jump_node.z = local_jump_node.z - 1 + node_offset;
|
||||
global_jump_node.w = local_jump_node.w - 1 + node_offset;
|
||||
|
||||
node_offset += shader_svm_nodes[i].size() - 1;
|
||||
node_offset += shader_svm_nodes_[i].size() - 1;
|
||||
}
|
||||
|
||||
/* Copy the nodes of each shader into the correct location. */
|
||||
svm_nodes += num_shaders;
|
||||
for (int i = 0; i < num_shaders; i++) {
|
||||
int shader_size = shader_svm_nodes[i].size() - 1;
|
||||
int shader_size = shader_svm_nodes_[i].size() - 1;
|
||||
|
||||
memcpy(svm_nodes, &shader_svm_nodes[i][1], sizeof(int4) * shader_size);
|
||||
memcpy(svm_nodes, &shader_svm_nodes_[i][1], sizeof(int4) * shader_size);
|
||||
svm_nodes += shader_size;
|
||||
}
|
||||
|
||||
@@ -161,6 +174,8 @@ void SVMShaderManager::device_update_specific(Device *device,
|
||||
|
||||
update_flags = UPDATE_NONE;
|
||||
|
||||
shader_svm_nodes_.clear();
|
||||
|
||||
VLOG(1) << "Shader manager updated " << num_shaders << " shaders in " << time_dt() - start_time
|
||||
<< " seconds.";
|
||||
}
|
||||
|
@@ -46,6 +46,8 @@ class SVMShaderManager : public ShaderManager {
|
||||
|
||||
void reset(Scene *scene) override;
|
||||
|
||||
void host_update_specific(Device *device, Scene *scene, Progress &progress) override;
|
||||
|
||||
void device_update_specific(Device *device,
|
||||
DeviceScene *dscene,
|
||||
Scene *scene,
|
||||
@@ -53,10 +55,11 @@ class SVMShaderManager : public ShaderManager {
|
||||
void device_free(Device *device, DeviceScene *dscene, Scene *scene) override;
|
||||
|
||||
protected:
|
||||
void device_update_shader(Scene *scene,
|
||||
Shader *shader,
|
||||
Progress *progress,
|
||||
array<int4> *svm_nodes);
|
||||
/* Compiled shader nodes.
|
||||
*
|
||||
* The compilation happens in the `host_update_specific()`, and the `device_update_specific()`
|
||||
* moves these nodes to the device. */
|
||||
vector<array<int4>> shader_svm_nodes_;
|
||||
};
|
||||
|
||||
/* Graph Compiler */
|
||||
|
Reference in New Issue
Block a user