Cycles: merge of changes from tomato branch.
Regular rendering now works tiled, and supports save buffers to save memory during render and cache render results. Brick texture node by Thomas. http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/Textures#Brick_Texture Image texture Blended Box Mapping. http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/Textures#Image_Texture http://mango.blender.org/production/blended_box/ Various bug fixes by Sergey and Campbell. * Fix for reading freed memory in some node setups. * Fix incorrect memory read when synchronizing mesh motion. * Fix crash appearing when direct light usage is different on different layers. * Fix for vector pass gives wrong result in some circumstances. * Fix for wrong resolution used for rendering Render Layer node. * Option to cancel rendering when doing initial synchronization. * No more texture limit when using CPU render. * Many fixes for new tiled rendering.
This commit is contained in:
@@ -66,12 +66,13 @@ static void session_print(const string& str)
|
|||||||
|
|
||||||
static void session_print_status()
|
static void session_print_status()
|
||||||
{
|
{
|
||||||
int sample;
|
int sample, tile;
|
||||||
double total_time, sample_time;
|
double total_time, sample_time;
|
||||||
string status, substatus;
|
string status, substatus;
|
||||||
|
|
||||||
/* get status */
|
/* get status */
|
||||||
options.session->progress.get_sample(sample, total_time, sample_time);
|
sample = options.session->progress.get_sample();
|
||||||
|
options.session->progress.get_tile(tile, total_time, sample_time);
|
||||||
options.session->progress.get_status(status, substatus);
|
options.session->progress.get_status(status, substatus);
|
||||||
|
|
||||||
if(substatus != "")
|
if(substatus != "")
|
||||||
@@ -111,7 +112,7 @@ static void session_init()
|
|||||||
|
|
||||||
static void scene_init(int width, int height)
|
static void scene_init(int width, int height)
|
||||||
{
|
{
|
||||||
options.scene = new Scene(options.scene_params);
|
options.scene = new Scene(options.scene_params, options.session_params.device);
|
||||||
xml_read_file(options.scene, options.filepath.c_str());
|
xml_read_file(options.scene, options.filepath.c_str());
|
||||||
|
|
||||||
if (width == 0 || height == 0) {
|
if (width == 0 || height == 0) {
|
||||||
@@ -147,11 +148,12 @@ static void display_info(Progress& progress)
|
|||||||
latency = (elapsed - last);
|
latency = (elapsed - last);
|
||||||
last = elapsed;
|
last = elapsed;
|
||||||
|
|
||||||
int sample;
|
int sample, tile;
|
||||||
double total_time, sample_time;
|
double total_time, sample_time;
|
||||||
string status, substatus;
|
string status, substatus;
|
||||||
|
|
||||||
progress.get_sample(sample, total_time, sample_time);
|
sample = progress.get_sample();
|
||||||
|
progress.get_tile(tile, total_time, sample_time);
|
||||||
progress.get_status(status, substatus);
|
progress.get_status(status, substatus);
|
||||||
|
|
||||||
if(substatus != "")
|
if(substatus != "")
|
||||||
|
|||||||
@@ -379,6 +379,9 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
|
|||||||
else if(string_iequals(node.name(), "checker_texture")) {
|
else if(string_iequals(node.name(), "checker_texture")) {
|
||||||
snode = new CheckerTextureNode();
|
snode = new CheckerTextureNode();
|
||||||
}
|
}
|
||||||
|
else if(string_iequals(node.name(), "brick_texture")) {
|
||||||
|
snode = new BrickTextureNode();
|
||||||
|
}
|
||||||
else if(string_iequals(node.name(), "gradient_texture")) {
|
else if(string_iequals(node.name(), "gradient_texture")) {
|
||||||
GradientTextureNode *blend = new GradientTextureNode();
|
GradientTextureNode *blend = new GradientTextureNode();
|
||||||
xml_read_enum(&blend->type, GradientTextureNode::type_enum, node, "type");
|
xml_read_enum(&blend->type, GradientTextureNode::type_enum, node, "type");
|
||||||
|
|||||||
@@ -241,12 +241,14 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
|||||||
min=1, max=4096,
|
min=1, max=4096,
|
||||||
default=1024,
|
default=1024,
|
||||||
)
|
)
|
||||||
cls.debug_min_size = IntProperty(
|
|
||||||
name="Min Size",
|
cls.resolution_divider = IntProperty(
|
||||||
description="",
|
name="Resolution Divider",
|
||||||
min=1, max=4096,
|
description="For viewport render, the number of lower resolutions to render before the full resolution",
|
||||||
default=64,
|
min=1, max=512,
|
||||||
|
default=4,
|
||||||
)
|
)
|
||||||
|
|
||||||
cls.debug_reset_timeout = FloatProperty(
|
cls.debug_reset_timeout = FloatProperty(
|
||||||
name="Reset timeout",
|
name="Reset timeout",
|
||||||
description="",
|
description="",
|
||||||
|
|||||||
@@ -197,8 +197,13 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
|
|||||||
|
|
||||||
sub = col.column(align=True)
|
sub = col.column(align=True)
|
||||||
sub.label(text="Tiles:")
|
sub.label(text="Tiles:")
|
||||||
sub.prop(cscene, "debug_tile_size")
|
|
||||||
sub.prop(cscene, "debug_min_size")
|
sub.prop(rd, "parts_x", text="X")
|
||||||
|
sub.prop(rd, "parts_y", text="Y")
|
||||||
|
|
||||||
|
subsub = sub.column()
|
||||||
|
subsub.enabled = not rd.use_border
|
||||||
|
subsub.prop(rd, "use_save_buffers")
|
||||||
|
|
||||||
col = split.column()
|
col = split.column()
|
||||||
|
|
||||||
@@ -208,6 +213,10 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
|
|||||||
sub.prop(cscene, "debug_use_spatial_splits")
|
sub.prop(cscene, "debug_use_spatial_splits")
|
||||||
sub.prop(cscene, "use_cache")
|
sub.prop(cscene, "use_cache")
|
||||||
|
|
||||||
|
sub = col.column(align=True)
|
||||||
|
sub.label(text="Viewport:")
|
||||||
|
sub.prop(cscene, "resolution_divider")
|
||||||
|
|
||||||
|
|
||||||
class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
|
class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
|
||||||
bl_label = "Layers"
|
bl_label = "Layers"
|
||||||
|
|||||||
@@ -317,11 +317,11 @@ void BlenderSync::sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion)
|
|||||||
BL::Mesh::vertices_iterator v;
|
BL::Mesh::vertices_iterator v;
|
||||||
AttributeStandard std = (motion == -1)? ATTR_STD_MOTION_PRE: ATTR_STD_MOTION_POST;
|
AttributeStandard std = (motion == -1)? ATTR_STD_MOTION_PRE: ATTR_STD_MOTION_POST;
|
||||||
Attribute *attr_M = mesh->attributes.add(std);
|
Attribute *attr_M = mesh->attributes.add(std);
|
||||||
float3 *M = attr_M->data_float3();
|
float3 *M = attr_M->data_float3(), *cur_M;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < size; ++v, M++, i++)
|
for(b_mesh.vertices.begin(v), cur_M = M; v != b_mesh.vertices.end() && i < size; ++v, cur_M++, i++)
|
||||||
*M = get_float3(v->co());
|
*cur_M = get_float3(v->co());
|
||||||
|
|
||||||
/* if number of vertices changed, or if coordinates stayed the same, drop it */
|
/* if number of vertices changed, or if coordinates stayed the same, drop it */
|
||||||
if(i != size || memcmp(M, &mesh->verts[0], sizeof(float3)*size) == 0)
|
if(i != size || memcmp(M, &mesh->verts[0], sizeof(float3)*size) == 0)
|
||||||
|
|||||||
@@ -300,14 +300,16 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
|
|||||||
BL::Scene b_sce = b_scene;
|
BL::Scene b_sce = b_scene;
|
||||||
int particle_offset = 1; /* first particle is dummy for regular, non-instanced objects */
|
int particle_offset = 1; /* first particle is dummy for regular, non-instanced objects */
|
||||||
|
|
||||||
for(; b_sce; b_sce = b_sce.background_set()) {
|
bool cancel = false;
|
||||||
for(b_sce.objects.begin(b_ob); b_ob != b_sce.objects.end(); ++b_ob) {
|
|
||||||
|
for(; b_sce && !cancel; b_sce = b_sce.background_set()) {
|
||||||
|
for(b_sce.objects.begin(b_ob); b_ob != b_sce.objects.end() && !cancel; ++b_ob) {
|
||||||
bool hide = (render_layer.use_viewport_visibility)? b_ob->hide(): b_ob->hide_render();
|
bool hide = (render_layer.use_viewport_visibility)? b_ob->hide(): b_ob->hide_render();
|
||||||
uint ob_layer = get_layer(b_ob->layers(), b_ob->layers_local_view(), object_is_light(*b_ob));
|
uint ob_layer = get_layer(b_ob->layers(), b_ob->layers_local_view(), render_layer.use_localview, object_is_light(*b_ob));
|
||||||
CYCLES_LOCAL_LAYER_HACK(render_layer.use_localview, ob_layer);
|
|
||||||
hide = hide || !(ob_layer & scene_layer);
|
hide = hide || !(ob_layer & scene_layer);
|
||||||
|
|
||||||
if(!hide) {
|
if(!hide) {
|
||||||
|
progress.set_status("Synchronizing object", (*b_ob).name());
|
||||||
|
|
||||||
int num_particles = object_count_particles(*b_ob);
|
int num_particles = object_count_particles(*b_ob);
|
||||||
|
|
||||||
@@ -349,10 +351,12 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
|
|||||||
|
|
||||||
particle_offset += num_particles;
|
particle_offset += num_particles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cancel = progress.get_cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!motion) {
|
if(!cancel && !motion) {
|
||||||
sync_background_light();
|
sync_background_light();
|
||||||
|
|
||||||
/* handle removed data and modified pointers */
|
/* handle removed data and modified pointers */
|
||||||
|
|||||||
@@ -199,8 +199,7 @@ void BlenderSync::sync_particle_systems()
|
|||||||
for(; b_sce; b_sce = b_sce.background_set()) {
|
for(; b_sce; b_sce = b_sce.background_set()) {
|
||||||
for(b_sce.objects.begin(b_ob); b_ob != b_sce.objects.end(); ++b_ob) {
|
for(b_sce.objects.begin(b_ob); b_ob != b_sce.objects.end(); ++b_ob) {
|
||||||
bool hide = (render_layer.use_viewport_visibility)? b_ob->hide(): b_ob->hide_render();
|
bool hide = (render_layer.use_viewport_visibility)? b_ob->hide(): b_ob->hide_render();
|
||||||
uint ob_layer = get_layer(b_ob->layers(), b_ob->layers_local_view(), object_is_light(*b_ob));
|
uint ob_layer = get_layer(b_ob->layers(), b_ob->layers_local_view(), render_layer.use_localview, object_is_light(*b_ob));
|
||||||
CYCLES_LOCAL_LAYER_HACK(render_layer.use_localview, ob_layer);
|
|
||||||
hide = hide || !(ob_layer & scene_layer);
|
hide = hide || !(ob_layer & scene_layer);
|
||||||
|
|
||||||
if(!hide) {
|
if(!hide) {
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ static PyObject *create_func(PyObject *self, PyObject *args)
|
|||||||
/* create session */
|
/* create session */
|
||||||
BlenderSession *session;
|
BlenderSession *session;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
|
||||||
if(rv3d) {
|
if(rv3d) {
|
||||||
/* interactive session */
|
/* interactive session */
|
||||||
int width = region.width();
|
int width = region.width();
|
||||||
@@ -91,7 +93,9 @@ static PyObject *create_func(PyObject *self, PyObject *args)
|
|||||||
/* offline session */
|
/* offline session */
|
||||||
session = new BlenderSession(engine, userpref, data, scene);
|
session = new BlenderSession(engine, userpref, data, scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
return PyLong_FromVoidPtr(session);
|
return PyLong_FromVoidPtr(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,9 +140,13 @@ static PyObject *draw_func(PyObject *self, PyObject *args)
|
|||||||
|
|
||||||
static PyObject *sync_func(PyObject *self, PyObject *value)
|
static PyObject *sync_func(PyObject *self, PyObject *value)
|
||||||
{
|
{
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
|
||||||
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
|
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
|
||||||
session->synchronize();
|
session->synchronize();
|
||||||
|
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,14 +42,13 @@ CCL_NAMESPACE_BEGIN
|
|||||||
BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
|
BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
|
||||||
BL::BlendData b_data_, BL::Scene b_scene_)
|
BL::BlendData b_data_, BL::Scene b_scene_)
|
||||||
: b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_scene(b_scene_),
|
: b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_scene(b_scene_),
|
||||||
b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL),
|
b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL)
|
||||||
b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL)
|
|
||||||
{
|
{
|
||||||
/* offline render */
|
/* offline render */
|
||||||
BL::RenderSettings r = b_scene.render();
|
|
||||||
|
|
||||||
width = (int)(r.resolution_x()*r.resolution_percentage()/100);
|
width = b_engine.resolution_x();
|
||||||
height = (int)(r.resolution_y()*r.resolution_percentage()/100);
|
height = b_engine.resolution_y();
|
||||||
|
|
||||||
background = true;
|
background = true;
|
||||||
last_redraw_time = 0.0f;
|
last_redraw_time = 0.0f;
|
||||||
|
|
||||||
@@ -60,7 +59,7 @@ BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b
|
|||||||
BL::BlendData b_data_, BL::Scene b_scene_,
|
BL::BlendData b_data_, BL::Scene b_scene_,
|
||||||
BL::SpaceView3D b_v3d_, BL::RegionView3D b_rv3d_, int width_, int height_)
|
BL::SpaceView3D b_v3d_, BL::RegionView3D b_rv3d_, int width_, int height_)
|
||||||
: b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_scene(b_scene_),
|
: b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_scene(b_scene_),
|
||||||
b_v3d(b_v3d_), b_rv3d(b_rv3d_), b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL)
|
b_v3d(b_v3d_), b_rv3d(b_rv3d_)
|
||||||
{
|
{
|
||||||
/* 3d view render */
|
/* 3d view render */
|
||||||
width = width_;
|
width = width_;
|
||||||
@@ -80,23 +79,14 @@ BlenderSession::~BlenderSession()
|
|||||||
void BlenderSession::create_session()
|
void BlenderSession::create_session()
|
||||||
{
|
{
|
||||||
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
|
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
|
||||||
SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
|
SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
|
||||||
|
|
||||||
/* reset status/progress */
|
/* reset status/progress */
|
||||||
last_status = "";
|
last_status = "";
|
||||||
last_progress = -1.0f;
|
last_progress = -1.0f;
|
||||||
|
|
||||||
/* create scene */
|
/* create scene */
|
||||||
scene = new Scene(scene_params);
|
scene = new Scene(scene_params, session_params.device);
|
||||||
|
|
||||||
/* create sync */
|
|
||||||
sync = new BlenderSync(b_data, b_scene, scene, !background);
|
|
||||||
sync->sync_data(b_v3d, b_engine.camera_override());
|
|
||||||
|
|
||||||
if(b_rv3d)
|
|
||||||
sync->sync_view(b_v3d, b_rv3d, width, height);
|
|
||||||
else
|
|
||||||
sync->sync_camera(b_engine.camera_override(), width, height);
|
|
||||||
|
|
||||||
/* create session */
|
/* create session */
|
||||||
session = new Session(session_params);
|
session = new Session(session_params);
|
||||||
@@ -105,6 +95,15 @@ void BlenderSession::create_session()
|
|||||||
session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
|
session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
|
||||||
session->set_pause(BlenderSync::get_session_pause(b_scene, background));
|
session->set_pause(BlenderSync::get_session_pause(b_scene, background));
|
||||||
|
|
||||||
|
/* create sync */
|
||||||
|
sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
|
||||||
|
sync->sync_data(b_v3d, b_engine.camera_override());
|
||||||
|
|
||||||
|
if(b_rv3d)
|
||||||
|
sync->sync_view(b_v3d, b_rv3d, width, height);
|
||||||
|
else
|
||||||
|
sync->sync_camera(b_engine.camera_override(), width, height);
|
||||||
|
|
||||||
/* set buffer parameters */
|
/* set buffer parameters */
|
||||||
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, scene->camera, width, height);
|
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, scene->camera, width, height);
|
||||||
session->reset(buffer_params, session_params.samples);
|
session->reset(buffer_params, session_params.samples);
|
||||||
@@ -177,35 +176,100 @@ static PassType get_pass_type(BL::RenderPass b_pass)
|
|||||||
return PASS_NONE;
|
return PASS_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlenderSession::render()
|
static BL::RenderResult begin_render_result(BL::RenderEngine b_engine, int x, int y, int w, int h, const char *layername)
|
||||||
{
|
{
|
||||||
/* get buffer parameters */
|
RenderResult *rrp = RE_engine_begin_result((RenderEngine*)b_engine.ptr.data, x, y, w, h, layername);
|
||||||
SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
|
|
||||||
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, scene->camera, width, height);
|
|
||||||
int w = buffer_params.width, h = buffer_params.height;
|
|
||||||
|
|
||||||
/* create render result */
|
|
||||||
RenderResult *rrp = RE_engine_begin_result((RenderEngine*)b_engine.ptr.data, 0, 0, w, h);
|
|
||||||
PointerRNA rrptr;
|
PointerRNA rrptr;
|
||||||
RNA_pointer_create(NULL, &RNA_RenderResult, rrp, &rrptr);
|
RNA_pointer_create(NULL, &RNA_RenderResult, rrp, &rrptr);
|
||||||
b_rr = BL::RenderResult(rrptr);
|
return BL::RenderResult(rrptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void end_render_result(BL::RenderEngine b_engine, BL::RenderResult b_rr, bool cancel = false)
|
||||||
|
{
|
||||||
|
RE_engine_end_result((RenderEngine*)b_engine.ptr.data, (RenderResult*)b_rr.ptr.data, (int)cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_update_only)
|
||||||
|
{
|
||||||
|
BufferParams& params = rtile.buffers->params;
|
||||||
|
int x = params.full_x - session->tile_manager.params.full_x;
|
||||||
|
int y = params.full_y - session->tile_manager.params.full_y;
|
||||||
|
int w = params.width;
|
||||||
|
int h = params.height;
|
||||||
|
|
||||||
|
/* get render result */
|
||||||
|
BL::RenderResult b_rr = begin_render_result(b_engine, x, y, w, h, b_rlay_name.c_str());
|
||||||
|
|
||||||
|
/* can happen if the intersected rectangle gives 0 width or height */
|
||||||
|
if (b_rr.ptr.data == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BL::RenderResult::layers_iterator b_single_rlay;
|
||||||
|
b_rr.layers.begin(b_single_rlay);
|
||||||
|
BL::RenderLayer b_rlay = *b_single_rlay;
|
||||||
|
|
||||||
|
if (do_update_only) {
|
||||||
|
/* update only needed */
|
||||||
|
update_render_result(b_rr, b_rlay, rtile);
|
||||||
|
end_render_result(b_engine, b_rr, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* write result */
|
||||||
|
write_render_result(b_rr, b_rlay, rtile);
|
||||||
|
end_render_result(b_engine, b_rr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::write_render_tile(RenderTile& rtile)
|
||||||
|
{
|
||||||
|
do_write_update_render_tile(rtile, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::update_render_tile(RenderTile& rtile)
|
||||||
|
{
|
||||||
|
do_write_update_render_tile(rtile, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::render()
|
||||||
|
{
|
||||||
|
/* set callback to write out render results */
|
||||||
|
session->write_render_tile_cb = function_bind(&BlenderSession::write_render_tile, this, _1);
|
||||||
|
session->update_render_tile_cb = function_bind(&BlenderSession::update_render_tile, this, _1);
|
||||||
|
|
||||||
|
/* get buffer parameters */
|
||||||
|
SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
|
||||||
|
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, scene->camera, width, height);
|
||||||
|
|
||||||
BL::RenderSettings r = b_scene.render();
|
|
||||||
BL::RenderResult::layers_iterator b_iter;
|
|
||||||
BL::RenderLayers b_rr_layers(r.ptr);
|
|
||||||
|
|
||||||
/* render each layer */
|
/* render each layer */
|
||||||
for(b_rr.layers.begin(b_iter); b_iter != b_rr.layers.end(); ++b_iter) {
|
BL::RenderSettings r = b_scene.render();
|
||||||
/* set layer */
|
BL::RenderSettings::layers_iterator b_iter;
|
||||||
b_rlay = *b_iter;
|
|
||||||
|
for(r.layers.begin(b_iter); b_iter != r.layers.end(); ++b_iter) {
|
||||||
|
b_rlay_name = b_iter->name();
|
||||||
|
|
||||||
|
/* temporary render result to find needed passes */
|
||||||
|
BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_rlay_name.c_str());
|
||||||
|
BL::RenderResult::layers_iterator b_single_rlay;
|
||||||
|
b_rr.layers.begin(b_single_rlay);
|
||||||
|
|
||||||
|
/* layer will be missing if it was disabled in the UI */
|
||||||
|
if(b_single_rlay == b_rr.layers.end()) {
|
||||||
|
end_render_result(b_engine, b_rr, true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BL::RenderLayer b_rlay = *b_single_rlay;
|
||||||
|
|
||||||
/* add passes */
|
/* add passes */
|
||||||
vector<Pass> passes;
|
vector<Pass> passes;
|
||||||
Pass::add(PASS_COMBINED, passes);
|
Pass::add(PASS_COMBINED, passes);
|
||||||
|
|
||||||
if(session_params.device.advanced_shading) {
|
if(session_params.device.advanced_shading) {
|
||||||
|
|
||||||
|
/* loop over passes */
|
||||||
BL::RenderLayer::passes_iterator b_pass_iter;
|
BL::RenderLayer::passes_iterator b_pass_iter;
|
||||||
|
|
||||||
for(b_rlay.passes.begin(b_pass_iter); b_pass_iter != b_rlay.passes.end(); ++b_pass_iter) {
|
for(b_rlay.passes.begin(b_pass_iter); b_pass_iter != b_rlay.passes.end(); ++b_pass_iter) {
|
||||||
BL::RenderPass b_pass(*b_pass_iter);
|
BL::RenderPass b_pass(*b_pass_iter);
|
||||||
PassType pass_type = get_pass_type(b_pass);
|
PassType pass_type = get_pass_type(b_pass);
|
||||||
@@ -217,13 +281,16 @@ void BlenderSession::render()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* free result without merging */
|
||||||
|
end_render_result(b_engine, b_rr, true);
|
||||||
|
|
||||||
buffer_params.passes = passes;
|
buffer_params.passes = passes;
|
||||||
scene->film->tag_passes_update(scene, passes);
|
scene->film->tag_passes_update(scene, passes);
|
||||||
scene->film->tag_update(scene);
|
scene->film->tag_update(scene);
|
||||||
scene->integrator->tag_update(scene);
|
scene->integrator->tag_update(scene);
|
||||||
|
|
||||||
/* update scene */
|
/* update scene */
|
||||||
sync->sync_data(b_v3d, b_engine.camera_override(), b_iter->name().c_str());
|
sync->sync_data(b_v3d, b_engine.camera_override(), b_rlay_name.c_str());
|
||||||
|
|
||||||
/* update session */
|
/* update session */
|
||||||
int samples = sync->get_layer_samples();
|
int samples = sync->get_layer_samples();
|
||||||
@@ -235,19 +302,16 @@ void BlenderSession::render()
|
|||||||
|
|
||||||
if(session->progress.get_cancel())
|
if(session->progress.get_cancel())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* write result */
|
|
||||||
write_render_result();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* delete render result */
|
/* clear callback */
|
||||||
RE_engine_end_result((RenderEngine*)b_engine.ptr.data, (RenderResult*)b_rr.ptr.data);
|
session->write_render_tile_cb = NULL;
|
||||||
|
session->update_render_tile_cb = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlenderSession::write_render_result()
|
void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile, bool do_update_only)
|
||||||
{
|
{
|
||||||
/* get state */
|
RenderBuffers *buffers = rtile.buffers;
|
||||||
RenderBuffers *buffers = session->buffers;
|
|
||||||
|
|
||||||
/* copy data from device */
|
/* copy data from device */
|
||||||
if(!buffers->copy_from_device())
|
if(!buffers->copy_from_device())
|
||||||
@@ -255,41 +319,49 @@ void BlenderSession::write_render_result()
|
|||||||
|
|
||||||
BufferParams& params = buffers->params;
|
BufferParams& params = buffers->params;
|
||||||
float exposure = scene->film->exposure;
|
float exposure = scene->film->exposure;
|
||||||
double total_time, sample_time;
|
|
||||||
int sample;
|
|
||||||
|
|
||||||
session->progress.get_sample(sample, total_time, sample_time);
|
|
||||||
|
|
||||||
vector<float> pixels(params.width*params.height*4);
|
vector<float> pixels(params.width*params.height*4);
|
||||||
|
|
||||||
/* copy each pass */
|
if (!do_update_only) {
|
||||||
BL::RenderLayer::passes_iterator b_iter;
|
/* copy each pass */
|
||||||
|
BL::RenderLayer::passes_iterator b_iter;
|
||||||
for(b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
|
|
||||||
BL::RenderPass b_pass(*b_iter);
|
|
||||||
|
|
||||||
/* find matching pass type */
|
for(b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
|
||||||
PassType pass_type = get_pass_type(b_pass);
|
BL::RenderPass b_pass(*b_iter);
|
||||||
int components = b_pass.channels();
|
|
||||||
|
|
||||||
/* copy pixels */
|
/* find matching pass type */
|
||||||
if(buffers->get_pass(pass_type, exposure, sample, components, &pixels[0]))
|
PassType pass_type = get_pass_type(b_pass);
|
||||||
rna_RenderPass_rect_set(&b_pass.ptr, &pixels[0]);
|
int components = b_pass.channels();
|
||||||
|
|
||||||
|
/* copy pixels */
|
||||||
|
if(buffers->get_pass_rect(pass_type, exposure, rtile.sample, components, &pixels[0]))
|
||||||
|
rna_RenderPass_rect_set(&b_pass.ptr, &pixels[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy combined pass */
|
/* copy combined pass */
|
||||||
if(buffers->get_pass(PASS_COMBINED, exposure, sample, 4, &pixels[0]))
|
if(buffers->get_pass_rect(PASS_COMBINED, exposure, rtile.sample, 4, &pixels[0]))
|
||||||
rna_RenderLayer_rect_set(&b_rlay.ptr, &pixels[0]);
|
rna_RenderLayer_rect_set(&b_rlay.ptr, &pixels[0]);
|
||||||
|
|
||||||
/* tag result as updated */
|
/* tag result as updated */
|
||||||
RE_engine_update_result((RenderEngine*)b_engine.ptr.data, (RenderResult*)b_rr.ptr.data);
|
RE_engine_update_result((RenderEngine*)b_engine.ptr.data, (RenderResult*)b_rr.ptr.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BlenderSession::write_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile)
|
||||||
|
{
|
||||||
|
do_write_update_render_result(b_rr, b_rlay, rtile, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlenderSession::update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile)
|
||||||
|
{
|
||||||
|
do_write_update_render_result(b_rr, b_rlay, rtile, true);
|
||||||
|
}
|
||||||
|
|
||||||
void BlenderSession::synchronize()
|
void BlenderSession::synchronize()
|
||||||
{
|
{
|
||||||
/* on session/scene parameter changes, we recreate session entirely */
|
/* on session/scene parameter changes, we recreate session entirely */
|
||||||
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
|
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
|
||||||
SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
|
SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
|
||||||
|
|
||||||
if(session->params.modified(session_params) ||
|
if(session->params.modified(session_params) ||
|
||||||
scene->params.modified(scene_params))
|
scene->params.modified(scene_params))
|
||||||
@@ -364,7 +436,7 @@ bool BlenderSession::draw(int w, int h)
|
|||||||
|
|
||||||
/* reset if requested */
|
/* reset if requested */
|
||||||
if(reset) {
|
if(reset) {
|
||||||
SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
|
SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
|
||||||
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, scene->camera, w, h);
|
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, scene->camera, w, h);
|
||||||
|
|
||||||
session->reset(buffer_params, session_params.samples);
|
session->reset(buffer_params, session_params.samples);
|
||||||
@@ -387,11 +459,16 @@ void BlenderSession::get_status(string& status, string& substatus)
|
|||||||
|
|
||||||
void BlenderSession::get_progress(float& progress, double& total_time)
|
void BlenderSession::get_progress(float& progress, double& total_time)
|
||||||
{
|
{
|
||||||
double sample_time;
|
double tile_time;
|
||||||
int sample;
|
int tile, sample, samples_per_tile;
|
||||||
|
int tile_total = session->tile_manager.state.num_tiles;
|
||||||
|
|
||||||
session->progress.get_sample(sample, total_time, sample_time);
|
session->progress.get_tile(tile, total_time, tile_time);
|
||||||
progress = ((float)sample/(float)session->params.samples);
|
|
||||||
|
sample = session->progress.get_sample();
|
||||||
|
samples_per_tile = session->tile_manager.state.num_samples;
|
||||||
|
|
||||||
|
progress = ((float)sample/(float)(tile_total * samples_per_tile));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlenderSession::update_status_progress()
|
void BlenderSession::update_status_progress()
|
||||||
@@ -404,8 +481,13 @@ void BlenderSession::update_status_progress()
|
|||||||
get_status(status, substatus);
|
get_status(status, substatus);
|
||||||
get_progress(progress, total_time);
|
get_progress(progress, total_time);
|
||||||
|
|
||||||
|
timestatus = b_scene.name();
|
||||||
|
if(b_rlay_name != "")
|
||||||
|
timestatus += ", " + b_rlay_name;
|
||||||
|
timestatus += " | ";
|
||||||
|
|
||||||
BLI_timestr(total_time, time_str);
|
BLI_timestr(total_time, time_str);
|
||||||
timestatus = "Elapsed: " + string(time_str) + " | ";
|
timestatus += "Elapsed: " + string(time_str) + " | ";
|
||||||
|
|
||||||
if(substatus.size() > 0)
|
if(substatus.size() > 0)
|
||||||
status += " | " + substatus;
|
status += " | " + substatus;
|
||||||
@@ -435,7 +517,6 @@ void BlenderSession::tag_redraw()
|
|||||||
|
|
||||||
/* offline render, redraw if timeout passed */
|
/* offline render, redraw if timeout passed */
|
||||||
if(time_dt() - last_redraw_time > 1.0) {
|
if(time_dt() - last_redraw_time > 1.0) {
|
||||||
write_render_result();
|
|
||||||
engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
|
engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
|
||||||
last_redraw_time = time_dt();
|
last_redraw_time = time_dt();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ CCL_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
class Scene;
|
class Scene;
|
||||||
class Session;
|
class Session;
|
||||||
|
class RenderBuffers;
|
||||||
|
class RenderTile;
|
||||||
|
|
||||||
class BlenderSession {
|
class BlenderSession {
|
||||||
public:
|
public:
|
||||||
@@ -46,7 +48,14 @@ public:
|
|||||||
|
|
||||||
/* offline render */
|
/* offline render */
|
||||||
void render();
|
void render();
|
||||||
void write_render_result();
|
|
||||||
|
void write_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile);
|
||||||
|
void write_render_tile(RenderTile& rtile);
|
||||||
|
|
||||||
|
/* update functions are used to update display buffer only after sample was rendered
|
||||||
|
* only needed for better visual feedback */
|
||||||
|
void update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile);
|
||||||
|
void update_render_tile(RenderTile& rtile);
|
||||||
|
|
||||||
/* interactive updates */
|
/* interactive updates */
|
||||||
void synchronize();
|
void synchronize();
|
||||||
@@ -72,13 +81,16 @@ public:
|
|||||||
BL::Scene b_scene;
|
BL::Scene b_scene;
|
||||||
BL::SpaceView3D b_v3d;
|
BL::SpaceView3D b_v3d;
|
||||||
BL::RegionView3D b_rv3d;
|
BL::RegionView3D b_rv3d;
|
||||||
BL::RenderResult b_rr;
|
string b_rlay_name;
|
||||||
BL::RenderLayer b_rlay;
|
|
||||||
|
|
||||||
string last_status;
|
string last_status;
|
||||||
float last_progress;
|
float last_progress;
|
||||||
|
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void do_write_update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile, bool do_update_only);
|
||||||
|
void do_write_update_render_tile(RenderTile& rtile, bool do_update_only);
|
||||||
};
|
};
|
||||||
|
|
||||||
CCL_NAMESPACE_END
|
CCL_NAMESPACE_END
|
||||||
|
|||||||
@@ -406,6 +406,8 @@ static ShaderNode *add_node(BL::BlendData b_data, BL::Scene b_scene, ShaderGraph
|
|||||||
if(b_image)
|
if(b_image)
|
||||||
image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
|
image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
|
||||||
image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
|
image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
|
||||||
|
image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()];
|
||||||
|
image->projection_blend = b_image_node.projection_blend();
|
||||||
get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
|
get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
|
||||||
node = image;
|
node = image;
|
||||||
break;
|
break;
|
||||||
@@ -461,6 +463,17 @@ static ShaderNode *add_node(BL::BlendData b_data, BL::Scene b_scene, ShaderGraph
|
|||||||
node = checker;
|
node = checker;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case BL::ShaderNode::type_TEX_BRICK: {
|
||||||
|
BL::ShaderNodeTexBrick b_brick_node(b_node);
|
||||||
|
BrickTextureNode *brick = new BrickTextureNode();
|
||||||
|
brick->offset = b_brick_node.offset();
|
||||||
|
brick->offset_frequency = b_brick_node.offset_frequency();
|
||||||
|
brick->squash = b_brick_node.squash();
|
||||||
|
brick->squash_frequency = b_brick_node.squash_frequency();
|
||||||
|
get_tex_mapping(&brick->tex_mapping, b_brick_node.texture_mapping());
|
||||||
|
node = brick;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case BL::ShaderNode::type_TEX_NOISE: {
|
case BL::ShaderNode::type_TEX_NOISE: {
|
||||||
BL::ShaderNodeTexNoise b_noise_node(b_node);
|
BL::ShaderNodeTexNoise b_noise_node(b_node);
|
||||||
NoiseTextureNode *noise = new NoiseTextureNode();
|
NoiseTextureNode *noise = new NoiseTextureNode();
|
||||||
|
|||||||
@@ -40,8 +40,9 @@ CCL_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
/* Constructor */
|
/* Constructor */
|
||||||
|
|
||||||
BlenderSync::BlenderSync(BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_)
|
BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_, Progress &progress_)
|
||||||
: b_data(b_data_), b_scene(b_scene_),
|
: b_engine(b_engine_),
|
||||||
|
b_data(b_data_), b_scene(b_scene_),
|
||||||
shader_map(&scene_->shaders),
|
shader_map(&scene_->shaders),
|
||||||
object_map(&scene_->objects),
|
object_map(&scene_->objects),
|
||||||
mesh_map(&scene_->meshes),
|
mesh_map(&scene_->meshes),
|
||||||
@@ -49,7 +50,8 @@ BlenderSync::BlenderSync(BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene
|
|||||||
particle_system_map(&scene_->particle_systems),
|
particle_system_map(&scene_->particle_systems),
|
||||||
world_map(NULL),
|
world_map(NULL),
|
||||||
world_recalc(false),
|
world_recalc(false),
|
||||||
experimental(false)
|
experimental(false),
|
||||||
|
progress(progress_)
|
||||||
{
|
{
|
||||||
scene = scene_;
|
scene = scene_;
|
||||||
preview = preview_;
|
preview = preview_;
|
||||||
@@ -229,8 +231,7 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D b_v3d, const char *layer)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
render_layer.use_localview = (b_v3d.local_view() ? true : false);
|
render_layer.use_localview = (b_v3d.local_view() ? true : false);
|
||||||
render_layer.scene_layer = get_layer(b_v3d.layers(), b_v3d.layers_local_view());
|
render_layer.scene_layer = get_layer(b_v3d.layers(), b_v3d.layers_local_view(), render_layer.use_localview);
|
||||||
CYCLES_LOCAL_LAYER_HACK(render_layer.use_localview, render_layer.scene_layer);
|
|
||||||
render_layer.layer = render_layer.scene_layer;
|
render_layer.layer = render_layer.scene_layer;
|
||||||
render_layer.holdout_layer = 0;
|
render_layer.holdout_layer = 0;
|
||||||
render_layer.material_override = PointerRNA_NULL;
|
render_layer.material_override = PointerRNA_NULL;
|
||||||
@@ -296,7 +297,7 @@ bool BlenderSync::get_session_pause(BL::Scene b_scene, bool background)
|
|||||||
return (background)? false: get_boolean(cscene, "preview_pause");
|
return (background)? false: get_boolean(cscene, "preview_pause");
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionParams BlenderSync::get_session_params(BL::UserPreferences b_userpref, BL::Scene b_scene, bool background)
|
SessionParams BlenderSync::get_session_params(BL::RenderEngine b_engine, BL::UserPreferences b_userpref, BL::Scene b_scene, bool background)
|
||||||
{
|
{
|
||||||
SessionParams params;
|
SessionParams params;
|
||||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||||
@@ -350,25 +351,39 @@ SessionParams BlenderSync::get_session_params(BL::UserPreferences b_userpref, BL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tiles */
|
||||||
|
if(params.device.type != DEVICE_CPU && !background) {
|
||||||
|
/* currently GPU could be much slower than CPU when using tiles,
|
||||||
|
* still need to be investigated, but meanwhile make it possible
|
||||||
|
* to work in viewport smoothly
|
||||||
|
*/
|
||||||
|
int debug_tile_size = get_int(cscene, "debug_tile_size");
|
||||||
|
|
||||||
|
params.tile_size = make_int2(debug_tile_size, debug_tile_size);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int tile_x = b_engine.tile_x();
|
||||||
|
int tile_y = b_engine.tile_y();
|
||||||
|
|
||||||
|
params.tile_size = make_int2(tile_x, tile_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
params.resolution = 1 << get_int(cscene, "resolution_divider");
|
||||||
|
|
||||||
/* other parameters */
|
/* other parameters */
|
||||||
params.threads = b_scene.render().threads();
|
params.threads = b_scene.render().threads();
|
||||||
params.tile_size = get_int(cscene, "debug_tile_size");
|
|
||||||
params.min_size = get_int(cscene, "debug_min_size");
|
|
||||||
params.cancel_timeout = get_float(cscene, "debug_cancel_timeout");
|
params.cancel_timeout = get_float(cscene, "debug_cancel_timeout");
|
||||||
params.reset_timeout = get_float(cscene, "debug_reset_timeout");
|
params.reset_timeout = get_float(cscene, "debug_reset_timeout");
|
||||||
params.text_timeout = get_float(cscene, "debug_text_timeout");
|
params.text_timeout = get_float(cscene, "debug_text_timeout");
|
||||||
|
|
||||||
if(background) {
|
if(background) {
|
||||||
params.progressive = true;
|
params.progressive = false;
|
||||||
params.min_size = INT_MAX;
|
params.resolution = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
params.progressive = true;
|
params.progressive = true;
|
||||||
|
|
||||||
/* todo: multi device only works with single tiles now */
|
|
||||||
if(params.device.type == DEVICE_MULTI)
|
|
||||||
params.tile_size = INT_MAX;
|
|
||||||
|
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class ShaderNode;
|
|||||||
|
|
||||||
class BlenderSync {
|
class BlenderSync {
|
||||||
public:
|
public:
|
||||||
BlenderSync(BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_);
|
BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_, Progress &progress_);
|
||||||
~BlenderSync();
|
~BlenderSync();
|
||||||
|
|
||||||
/* sync */
|
/* sync */
|
||||||
@@ -61,7 +61,7 @@ public:
|
|||||||
|
|
||||||
/* get parameters */
|
/* get parameters */
|
||||||
static SceneParams get_scene_params(BL::Scene b_scene, bool background);
|
static SceneParams get_scene_params(BL::Scene b_scene, bool background);
|
||||||
static SessionParams get_session_params(BL::UserPreferences b_userpref, BL::Scene b_scene, bool background);
|
static SessionParams get_session_params(BL::RenderEngine b_engine, BL::UserPreferences b_userpref, BL::Scene b_scene, bool background);
|
||||||
static bool get_session_pause(BL::Scene b_scene, bool background);
|
static bool get_session_pause(BL::Scene b_scene, bool background);
|
||||||
static BufferParams get_buffer_params(BL::Scene b_scene, Camera *cam, int width, int height);
|
static BufferParams get_buffer_params(BL::Scene b_scene, Camera *cam, int width, int height);
|
||||||
|
|
||||||
@@ -97,6 +97,7 @@ private:
|
|||||||
int object_count_particles(BL::Object b_ob);
|
int object_count_particles(BL::Object b_ob);
|
||||||
|
|
||||||
/* variables */
|
/* variables */
|
||||||
|
BL::RenderEngine b_engine;
|
||||||
BL::BlendData b_data;
|
BL::BlendData b_data;
|
||||||
BL::Scene b_scene;
|
BL::Scene b_scene;
|
||||||
|
|
||||||
@@ -132,21 +133,9 @@ private:
|
|||||||
bool use_localview;
|
bool use_localview;
|
||||||
int samples;
|
int samples;
|
||||||
} render_layer;
|
} render_layer;
|
||||||
};
|
|
||||||
|
|
||||||
/* we don't have spare bits for localview (normally 20-28)
|
Progress &progress;
|
||||||
* because PATH_RAY_LAYER_SHIFT uses 20-32.
|
};
|
||||||
* So - check if we have localview and if so, shift local
|
|
||||||
* view bits down to 1-8, since this is done for the view
|
|
||||||
* port only - it should be OK and not conflict with
|
|
||||||
* render layers. - Campbell.
|
|
||||||
*
|
|
||||||
* ... as an alternative we could use uint64_t
|
|
||||||
*/
|
|
||||||
#define CYCLES_LOCAL_LAYER_HACK(use_localview, layer) \
|
|
||||||
if (use_localview) { \
|
|
||||||
layer >>= 20; \
|
|
||||||
} (void)0
|
|
||||||
|
|
||||||
CCL_NAMESPACE_END
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ void rna_Object_create_duplilist(void *ob, void *reports, void *sce);
|
|||||||
void rna_Object_free_duplilist(void *ob, void *reports);
|
void rna_Object_free_duplilist(void *ob, void *reports);
|
||||||
void rna_RenderLayer_rect_set(PointerRNA *ptr, const float *values);
|
void rna_RenderLayer_rect_set(PointerRNA *ptr, const float *values);
|
||||||
void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values);
|
void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values);
|
||||||
struct RenderResult *RE_engine_begin_result(struct RenderEngine *engine, int x, int y, int w, int h);
|
struct RenderResult *RE_engine_begin_result(struct RenderEngine *engine, int x, int y, int w, int h, const char *layername);
|
||||||
void RE_engine_update_result(struct RenderEngine *engine, struct RenderResult *result);
|
void RE_engine_update_result(struct RenderEngine *engine, struct RenderResult *result);
|
||||||
void RE_engine_end_result(struct RenderEngine *engine, struct RenderResult *result);
|
void RE_engine_end_result(struct RenderEngine *engine, struct RenderResult *result, int cancel);
|
||||||
int RE_engine_test_break(struct RenderEngine *engine);
|
int RE_engine_test_break(struct RenderEngine *engine);
|
||||||
void RE_engine_update_stats(struct RenderEngine *engine, const char *stats, const char *info);
|
void RE_engine_update_stats(struct RenderEngine *engine, const char *stats, const char *info);
|
||||||
void RE_engine_update_progress(struct RenderEngine *engine, float progress);
|
void RE_engine_update_progress(struct RenderEngine *engine, float progress);
|
||||||
@@ -55,7 +55,6 @@ void rna_ColorRamp_eval(void *coba, float position, float color[4]);
|
|||||||
void rna_Scene_frame_set(void *scene, int frame, float subframe);
|
void rna_Scene_frame_set(void *scene, int frame, float subframe);
|
||||||
void BKE_image_user_frame_calc(void *iuser, int cfra, int fieldnr);
|
void BKE_image_user_frame_calc(void *iuser, int cfra, int fieldnr);
|
||||||
void BKE_image_user_file_path(void *iuser, void *ima, char *path);
|
void BKE_image_user_file_path(void *iuser, void *ima, char *path);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
@@ -171,7 +170,7 @@ static inline uint get_layer(BL::Array<int, 20> array)
|
|||||||
return layer;
|
return layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint get_layer(BL::Array<int, 20> array, BL::Array<int, 8> local_array, bool is_light = false)
|
static inline uint get_layer(BL::Array<int, 20> array, BL::Array<int, 8> local_array, bool use_local, bool is_light = false)
|
||||||
{
|
{
|
||||||
uint layer = 0;
|
uint layer = 0;
|
||||||
|
|
||||||
@@ -189,7 +188,14 @@ static inline uint get_layer(BL::Array<int, 20> array, BL::Array<int, 8> local_a
|
|||||||
if(local_array[i])
|
if(local_array[i])
|
||||||
layer |= (1 << (20+i));
|
layer |= (1 << (20+i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* we don't have spare bits for localview (normally 20-28) because
|
||||||
|
* PATH_RAY_LAYER_SHIFT uses 20-32. So - check if we have localview and if
|
||||||
|
* so, shift local view bits down to 1-8, since this is done for the view
|
||||||
|
* port only - it should be OK and not conflict with render layers. */
|
||||||
|
if(use_local)
|
||||||
|
layer >>= 20;
|
||||||
|
|
||||||
return layer;
|
return layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ set(SRC
|
|||||||
device_multi.cpp
|
device_multi.cpp
|
||||||
device_network.cpp
|
device_network.cpp
|
||||||
device_opencl.cpp
|
device_opencl.cpp
|
||||||
|
device_task.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SRC_HEADERS
|
set(SRC_HEADERS
|
||||||
@@ -24,6 +25,7 @@ set(SRC_HEADERS
|
|||||||
device_memory.h
|
device_memory.h
|
||||||
device_intern.h
|
device_intern.h
|
||||||
device_network.h
|
device_network.h
|
||||||
|
device_task.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_definitions(-DGLEW_STATIC)
|
add_definitions(-DGLEW_STATIC)
|
||||||
|
|||||||
@@ -33,65 +33,6 @@
|
|||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/* Device Task */
|
|
||||||
|
|
||||||
DeviceTask::DeviceTask(Type type_)
|
|
||||||
: type(type_), x(0), y(0), w(0), h(0), rng_state(0), rgba(0), buffer(0),
|
|
||||||
sample(0), resolution(0),
|
|
||||||
shader_input(0), shader_output(0),
|
|
||||||
shader_eval_type(0), shader_x(0), shader_w(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceTask::split_max_size(list<DeviceTask>& tasks, int max_size)
|
|
||||||
{
|
|
||||||
int num;
|
|
||||||
|
|
||||||
if(type == SHADER) {
|
|
||||||
num = (shader_w + max_size - 1)/max_size;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
max_size = max(1, max_size/w);
|
|
||||||
num = (h + max_size - 1)/max_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
split(tasks, num);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceTask::split(list<DeviceTask>& tasks, int num)
|
|
||||||
{
|
|
||||||
if(type == SHADER) {
|
|
||||||
num = min(shader_w, num);
|
|
||||||
|
|
||||||
for(int i = 0; i < num; i++) {
|
|
||||||
int tx = shader_x + (shader_w/num)*i;
|
|
||||||
int tw = (i == num-1)? shader_w - i*(shader_w/num): shader_w/num;
|
|
||||||
|
|
||||||
DeviceTask task = *this;
|
|
||||||
|
|
||||||
task.shader_x = tx;
|
|
||||||
task.shader_w = tw;
|
|
||||||
|
|
||||||
tasks.push_back(task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
num = min(h, num);
|
|
||||||
|
|
||||||
for(int i = 0; i < num; i++) {
|
|
||||||
int ty = y + (h/num)*i;
|
|
||||||
int th = (i == num-1)? h - i*(h/num): h/num;
|
|
||||||
|
|
||||||
DeviceTask task = *this;
|
|
||||||
|
|
||||||
task.y = ty;
|
|
||||||
task.h = th;
|
|
||||||
|
|
||||||
tasks.push_back(task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Device */
|
/* Device */
|
||||||
|
|
||||||
void Device::pixels_alloc(device_memory& mem)
|
void Device::pixels_alloc(device_memory& mem)
|
||||||
|
|||||||
@@ -22,10 +22,10 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "device_memory.h"
|
#include "device_memory.h"
|
||||||
|
#include "device_task.h"
|
||||||
|
|
||||||
#include "util_list.h"
|
#include "util_list.h"
|
||||||
#include "util_string.h"
|
#include "util_string.h"
|
||||||
#include "util_task.h"
|
|
||||||
#include "util_thread.h"
|
#include "util_thread.h"
|
||||||
#include "util_types.h"
|
#include "util_types.h"
|
||||||
#include "util_vector.h"
|
#include "util_vector.h"
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
class Progress;
|
class Progress;
|
||||||
|
class RenderTile;
|
||||||
|
|
||||||
/* Device Types */
|
/* Device Types */
|
||||||
|
|
||||||
@@ -67,32 +68,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Device Task */
|
|
||||||
|
|
||||||
class DeviceTask : public Task {
|
|
||||||
public:
|
|
||||||
typedef enum { PATH_TRACE, TONEMAP, SHADER } Type;
|
|
||||||
Type type;
|
|
||||||
|
|
||||||
int x, y, w, h;
|
|
||||||
device_ptr rng_state;
|
|
||||||
device_ptr rgba;
|
|
||||||
device_ptr buffer;
|
|
||||||
int sample;
|
|
||||||
int resolution;
|
|
||||||
int offset, stride;
|
|
||||||
|
|
||||||
device_ptr shader_input;
|
|
||||||
device_ptr shader_output;
|
|
||||||
int shader_eval_type;
|
|
||||||
int shader_x, shader_w;
|
|
||||||
|
|
||||||
DeviceTask(Type type = PATH_TRACE);
|
|
||||||
|
|
||||||
void split(list<DeviceTask>& tasks, int num);
|
|
||||||
void split_max_size(list<DeviceTask>& tasks, int max_size);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Device */
|
/* Device */
|
||||||
|
|
||||||
class Device {
|
class Device {
|
||||||
@@ -150,6 +125,10 @@ public:
|
|||||||
void server_run();
|
void server_run();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* multi device */
|
||||||
|
virtual void map_tile(Device *sub_device, RenderTile& tile) {}
|
||||||
|
virtual int device_number(Device *sub_device) { return 0; }
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
static Device *create(DeviceInfo& info, bool background = true, int threads = 0);
|
static Device *create(DeviceInfo& info, bool background = true, int threads = 0);
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include "osl_shader.h"
|
#include "osl_shader.h"
|
||||||
|
|
||||||
|
#include "buffers.h"
|
||||||
|
|
||||||
#include "util_debug.h"
|
#include "util_debug.h"
|
||||||
#include "util_foreach.h"
|
#include "util_foreach.h"
|
||||||
#include "util_function.h"
|
#include "util_function.h"
|
||||||
@@ -141,28 +143,56 @@ public:
|
|||||||
OSLShader::thread_init(kg);
|
OSLShader::thread_init(kg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
RenderTile tile;
|
||||||
|
|
||||||
|
while(task.acquire_tile(this, tile)) {
|
||||||
|
float *render_buffer = (float*)tile.buffer;
|
||||||
|
uint *rng_state = (uint*)tile.rng_state;
|
||||||
|
int start_sample = tile.start_sample;
|
||||||
|
int end_sample = tile.start_sample + tile.num_samples;
|
||||||
|
|
||||||
#ifdef WITH_OPTIMIZED_KERNEL
|
#ifdef WITH_OPTIMIZED_KERNEL
|
||||||
if(system_cpu_support_optimized()) {
|
if(system_cpu_support_optimized()) {
|
||||||
for(int y = task.y; y < task.y + task.h; y++) {
|
for(int sample = start_sample; sample < end_sample; sample++) {
|
||||||
for(int x = task.x; x < task.x + task.w; x++)
|
if (task.get_cancel() || task_pool.cancelled())
|
||||||
kernel_cpu_optimized_path_trace(kg, (float*)task.buffer, (unsigned int*)task.rng_state,
|
break;
|
||||||
task.sample, x, y, task.offset, task.stride);
|
|
||||||
|
|
||||||
if(task_pool.cancelled())
|
for(int y = tile.y; y < tile.y + tile.h; y++) {
|
||||||
break;
|
for(int x = tile.x; x < tile.x + tile.w; x++) {
|
||||||
|
kernel_cpu_optimized_path_trace(kg, render_buffer, rng_state,
|
||||||
|
sample, x, y, tile.offset, tile.stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tile.sample = sample + 1;
|
||||||
|
|
||||||
|
task.update_progress(tile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
for(int y = task.y; y < task.y + task.h; y++) {
|
for(int sample = start_sample; sample < end_sample; sample++) {
|
||||||
for(int x = task.x; x < task.x + task.w; x++)
|
if (task.get_cancel() || task_pool.cancelled())
|
||||||
kernel_cpu_path_trace(kg, (float*)task.buffer, (unsigned int*)task.rng_state,
|
break;
|
||||||
task.sample, x, y, task.offset, task.stride);
|
|
||||||
|
|
||||||
if(task_pool.cancelled())
|
for(int y = tile.y; y < tile.y + tile.h; y++) {
|
||||||
break;
|
for(int x = tile.x; x < tile.x + tile.w; x++) {
|
||||||
|
kernel_cpu_path_trace(kg, render_buffer, rng_state,
|
||||||
|
sample, x, y, tile.offset, tile.stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tile.sample = sample + 1;
|
||||||
|
|
||||||
|
task.update_progress(tile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task.release_tile(tile);
|
||||||
|
|
||||||
|
if(task_pool.cancelled())
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_OSL
|
#ifdef WITH_OSL
|
||||||
@@ -228,8 +258,7 @@ public:
|
|||||||
/* split task into smaller ones, more than number of threads for uneven
|
/* split task into smaller ones, more than number of threads for uneven
|
||||||
* workloads where some parts of the image render slower than others */
|
* workloads where some parts of the image render slower than others */
|
||||||
list<DeviceTask> tasks;
|
list<DeviceTask> tasks;
|
||||||
|
task.split(tasks, TaskScheduler::num_threads()+1);
|
||||||
task.split(tasks, TaskScheduler::num_threads()*10);
|
|
||||||
|
|
||||||
foreach(DeviceTask& task, tasks)
|
foreach(DeviceTask& task, tasks)
|
||||||
task_pool.push(new CPUDeviceTask(this, task));
|
task_pool.push(new CPUDeviceTask(this, task));
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "device_intern.h"
|
#include "device_intern.h"
|
||||||
|
|
||||||
|
#include "buffers.h"
|
||||||
|
|
||||||
#include "util_cuda.h"
|
#include "util_cuda.h"
|
||||||
#include "util_debug.h"
|
#include "util_debug.h"
|
||||||
#include "util_map.h"
|
#include "util_map.h"
|
||||||
@@ -37,6 +39,7 @@ CCL_NAMESPACE_BEGIN
|
|||||||
class CUDADevice : public Device
|
class CUDADevice : public Device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
TaskPool task_pool;
|
||||||
CUdevice cuDevice;
|
CUdevice cuDevice;
|
||||||
CUcontext cuContext;
|
CUcontext cuContext;
|
||||||
CUmodule cuModule;
|
CUmodule cuModule;
|
||||||
@@ -192,6 +195,8 @@ public:
|
|||||||
|
|
||||||
~CUDADevice()
|
~CUDADevice()
|
||||||
{
|
{
|
||||||
|
task_pool.stop();
|
||||||
|
|
||||||
cuda_push_context();
|
cuda_push_context();
|
||||||
cuda_assert(cuCtxDetach(cuContext))
|
cuda_assert(cuCtxDetach(cuContext))
|
||||||
}
|
}
|
||||||
@@ -466,13 +471,13 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void path_trace(DeviceTask& task)
|
void path_trace(RenderTile& rtile, int sample)
|
||||||
{
|
{
|
||||||
cuda_push_context();
|
cuda_push_context();
|
||||||
|
|
||||||
CUfunction cuPathTrace;
|
CUfunction cuPathTrace;
|
||||||
CUdeviceptr d_buffer = cuda_device_ptr(task.buffer);
|
CUdeviceptr d_buffer = cuda_device_ptr(rtile.buffer);
|
||||||
CUdeviceptr d_rng_state = cuda_device_ptr(task.rng_state);
|
CUdeviceptr d_rng_state = cuda_device_ptr(rtile.rng_state);
|
||||||
|
|
||||||
/* get kernel function */
|
/* get kernel function */
|
||||||
cuda_assert(cuModuleGetFunction(&cuPathTrace, cuModule, "kernel_cuda_path_trace"))
|
cuda_assert(cuModuleGetFunction(&cuPathTrace, cuModule, "kernel_cuda_path_trace"))
|
||||||
@@ -486,29 +491,28 @@ public:
|
|||||||
cuda_assert(cuParamSetv(cuPathTrace, offset, &d_rng_state, sizeof(d_rng_state)))
|
cuda_assert(cuParamSetv(cuPathTrace, offset, &d_rng_state, sizeof(d_rng_state)))
|
||||||
offset += sizeof(d_rng_state);
|
offset += sizeof(d_rng_state);
|
||||||
|
|
||||||
int sample = task.sample;
|
|
||||||
offset = align_up(offset, __alignof(sample));
|
offset = align_up(offset, __alignof(sample));
|
||||||
|
|
||||||
cuda_assert(cuParamSeti(cuPathTrace, offset, task.sample))
|
cuda_assert(cuParamSeti(cuPathTrace, offset, sample))
|
||||||
offset += sizeof(task.sample);
|
offset += sizeof(sample);
|
||||||
|
|
||||||
cuda_assert(cuParamSeti(cuPathTrace, offset, task.x))
|
cuda_assert(cuParamSeti(cuPathTrace, offset, rtile.x))
|
||||||
offset += sizeof(task.x);
|
offset += sizeof(rtile.x);
|
||||||
|
|
||||||
cuda_assert(cuParamSeti(cuPathTrace, offset, task.y))
|
cuda_assert(cuParamSeti(cuPathTrace, offset, rtile.y))
|
||||||
offset += sizeof(task.y);
|
offset += sizeof(rtile.y);
|
||||||
|
|
||||||
cuda_assert(cuParamSeti(cuPathTrace, offset, task.w))
|
cuda_assert(cuParamSeti(cuPathTrace, offset, rtile.w))
|
||||||
offset += sizeof(task.w);
|
offset += sizeof(rtile.w);
|
||||||
|
|
||||||
cuda_assert(cuParamSeti(cuPathTrace, offset, task.h))
|
cuda_assert(cuParamSeti(cuPathTrace, offset, rtile.h))
|
||||||
offset += sizeof(task.h);
|
offset += sizeof(rtile.h);
|
||||||
|
|
||||||
cuda_assert(cuParamSeti(cuPathTrace, offset, task.offset))
|
cuda_assert(cuParamSeti(cuPathTrace, offset, rtile.offset))
|
||||||
offset += sizeof(task.offset);
|
offset += sizeof(rtile.offset);
|
||||||
|
|
||||||
cuda_assert(cuParamSeti(cuPathTrace, offset, task.stride))
|
cuda_assert(cuParamSeti(cuPathTrace, offset, rtile.stride))
|
||||||
offset += sizeof(task.stride);
|
offset += sizeof(rtile.stride);
|
||||||
|
|
||||||
cuda_assert(cuParamSetSize(cuPathTrace, offset))
|
cuda_assert(cuParamSetSize(cuPathTrace, offset))
|
||||||
|
|
||||||
@@ -520,23 +524,25 @@ public:
|
|||||||
int xthreads = 8;
|
int xthreads = 8;
|
||||||
int ythreads = 8;
|
int ythreads = 8;
|
||||||
#endif
|
#endif
|
||||||
int xblocks = (task.w + xthreads - 1)/xthreads;
|
int xblocks = (rtile.w + xthreads - 1)/xthreads;
|
||||||
int yblocks = (task.h + ythreads - 1)/ythreads;
|
int yblocks = (rtile.h + ythreads - 1)/ythreads;
|
||||||
|
|
||||||
cuda_assert(cuFuncSetCacheConfig(cuPathTrace, CU_FUNC_CACHE_PREFER_L1))
|
cuda_assert(cuFuncSetCacheConfig(cuPathTrace, CU_FUNC_CACHE_PREFER_L1))
|
||||||
cuda_assert(cuFuncSetBlockShape(cuPathTrace, xthreads, ythreads, 1))
|
cuda_assert(cuFuncSetBlockShape(cuPathTrace, xthreads, ythreads, 1))
|
||||||
cuda_assert(cuLaunchGrid(cuPathTrace, xblocks, yblocks))
|
cuda_assert(cuLaunchGrid(cuPathTrace, xblocks, yblocks))
|
||||||
|
|
||||||
|
cuda_assert(cuCtxSynchronize())
|
||||||
|
|
||||||
cuda_pop_context();
|
cuda_pop_context();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tonemap(DeviceTask& task)
|
void tonemap(DeviceTask& task, device_ptr buffer, device_ptr rgba)
|
||||||
{
|
{
|
||||||
cuda_push_context();
|
cuda_push_context();
|
||||||
|
|
||||||
CUfunction cuFilmConvert;
|
CUfunction cuFilmConvert;
|
||||||
CUdeviceptr d_rgba = map_pixels(task.rgba);
|
CUdeviceptr d_rgba = map_pixels(rgba);
|
||||||
CUdeviceptr d_buffer = cuda_device_ptr(task.buffer);
|
CUdeviceptr d_buffer = cuda_device_ptr(buffer);
|
||||||
|
|
||||||
/* get kernel function */
|
/* get kernel function */
|
||||||
cuda_assert(cuModuleGetFunction(&cuFilmConvert, cuModule, "kernel_cuda_tonemap"))
|
cuda_assert(cuModuleGetFunction(&cuFilmConvert, cuModule, "kernel_cuda_tonemap"))
|
||||||
@@ -820,27 +826,71 @@ public:
|
|||||||
Device::draw_pixels(mem, y, w, h, dy, width, height, transparent);
|
Device::draw_pixels(mem, y, w, h, dy, width, height, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void thread_run(DeviceTask *task)
|
||||||
|
{
|
||||||
|
if(task->type == DeviceTask::PATH_TRACE) {
|
||||||
|
RenderTile tile;
|
||||||
|
|
||||||
|
/* keep rendering tiles until done */
|
||||||
|
while(task->acquire_tile(this, tile)) {
|
||||||
|
int start_sample = tile.start_sample;
|
||||||
|
int end_sample = tile.start_sample + tile.num_samples;
|
||||||
|
|
||||||
|
for(int sample = start_sample; sample < end_sample; sample++) {
|
||||||
|
if (task->get_cancel())
|
||||||
|
break;
|
||||||
|
|
||||||
|
path_trace(tile, sample);
|
||||||
|
|
||||||
|
tile.sample = sample + 1;
|
||||||
|
|
||||||
|
task->update_progress(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
task->release_tile(tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(task->type == DeviceTask::SHADER) {
|
||||||
|
shader(*task);
|
||||||
|
|
||||||
|
cuda_push_context();
|
||||||
|
cuda_assert(cuCtxSynchronize())
|
||||||
|
cuda_pop_context();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CUDADeviceTask : public DeviceTask {
|
||||||
|
public:
|
||||||
|
CUDADeviceTask(CUDADevice *device, DeviceTask& task)
|
||||||
|
: DeviceTask(task)
|
||||||
|
{
|
||||||
|
run = function_bind(&CUDADevice::thread_run, device, this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void task_add(DeviceTask& task)
|
void task_add(DeviceTask& task)
|
||||||
{
|
{
|
||||||
if(task.type == DeviceTask::TONEMAP)
|
if(task.type == DeviceTask::TONEMAP) {
|
||||||
tonemap(task);
|
/* must be done in main thread due to opengl access */
|
||||||
else if(task.type == DeviceTask::PATH_TRACE)
|
tonemap(task, task.buffer, task.rgba);
|
||||||
path_trace(task);
|
|
||||||
else if(task.type == DeviceTask::SHADER)
|
cuda_push_context();
|
||||||
shader(task);
|
cuda_assert(cuCtxSynchronize())
|
||||||
|
cuda_pop_context();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
task_pool.push(new CUDADeviceTask(this, task));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void task_wait()
|
void task_wait()
|
||||||
{
|
{
|
||||||
cuda_push_context();
|
task_pool.wait_work();
|
||||||
|
|
||||||
cuda_assert(cuCtxSynchronize())
|
|
||||||
|
|
||||||
cuda_pop_context();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void task_cancel()
|
void task_cancel()
|
||||||
{
|
{
|
||||||
|
task_pool.cancel();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
#include "device_intern.h"
|
#include "device_intern.h"
|
||||||
#include "device_network.h"
|
#include "device_network.h"
|
||||||
|
|
||||||
|
#include "buffers.h"
|
||||||
|
|
||||||
#include "util_foreach.h"
|
#include "util_foreach.h"
|
||||||
#include "util_list.h"
|
#include "util_list.h"
|
||||||
#include "util_map.h"
|
#include "util_map.h"
|
||||||
@@ -255,6 +257,30 @@ public:
|
|||||||
rgba.device_pointer = tmp;
|
rgba.device_pointer = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void map_tile(Device *sub_device, RenderTile& tile)
|
||||||
|
{
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
if(sub.device == sub_device) {
|
||||||
|
if(tile.buffer) tile.buffer = sub.ptr_map[tile.buffer];
|
||||||
|
if(tile.rng_state) tile.rng_state = sub.ptr_map[tile.rng_state];
|
||||||
|
if(tile.rgba) tile.rgba = sub.ptr_map[tile.rgba];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int device_number(Device *sub_device)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
foreach(SubDevice& sub, devices) {
|
||||||
|
if(sub.device == sub_device)
|
||||||
|
return i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void task_add(DeviceTask& task)
|
void task_add(DeviceTask& task)
|
||||||
{
|
{
|
||||||
list<DeviceTask> tasks;
|
list<DeviceTask> tasks;
|
||||||
@@ -266,7 +292,6 @@ public:
|
|||||||
tasks.pop_front();
|
tasks.pop_front();
|
||||||
|
|
||||||
if(task.buffer) subtask.buffer = sub.ptr_map[task.buffer];
|
if(task.buffer) subtask.buffer = sub.ptr_map[task.buffer];
|
||||||
if(task.rng_state) subtask.rng_state = sub.ptr_map[task.rng_state];
|
|
||||||
if(task.rgba) subtask.rgba = sub.ptr_map[task.rgba];
|
if(task.rgba) subtask.rgba = sub.ptr_map[task.rgba];
|
||||||
if(task.shader_input) subtask.shader_input = sub.ptr_map[task.shader_input];
|
if(task.shader_input) subtask.shader_input = sub.ptr_map[task.shader_input];
|
||||||
if(task.shader_output) subtask.shader_output = sub.ptr_map[task.shader_output];
|
if(task.shader_output) subtask.shader_output = sub.ptr_map[task.shader_output];
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "device_intern.h"
|
#include "device_intern.h"
|
||||||
|
|
||||||
|
#include "buffers.h"
|
||||||
|
|
||||||
#include "util_foreach.h"
|
#include "util_foreach.h"
|
||||||
#include "util_map.h"
|
#include "util_map.h"
|
||||||
#include "util_math.h"
|
#include "util_math.h"
|
||||||
@@ -41,6 +43,7 @@ CCL_NAMESPACE_BEGIN
|
|||||||
class OpenCLDevice : public Device
|
class OpenCLDevice : public Device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
TaskPool task_pool;
|
||||||
cl_context cxContext;
|
cl_context cxContext;
|
||||||
cl_command_queue cqCommandQueue;
|
cl_command_queue cqCommandQueue;
|
||||||
cl_platform_id cpPlatform;
|
cl_platform_id cpPlatform;
|
||||||
@@ -435,6 +438,8 @@ public:
|
|||||||
|
|
||||||
~OpenCLDevice()
|
~OpenCLDevice()
|
||||||
{
|
{
|
||||||
|
task_pool.stop();
|
||||||
|
|
||||||
if(null_mem)
|
if(null_mem)
|
||||||
clReleaseMemObject(CL_MEM_PTR(null_mem));
|
clReleaseMemObject(CL_MEM_PTR(null_mem));
|
||||||
|
|
||||||
@@ -540,19 +545,19 @@ public:
|
|||||||
return global_size + ((r == 0)? 0: group_size - r);
|
return global_size + ((r == 0)? 0: group_size - r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void path_trace(DeviceTask& task)
|
void path_trace(RenderTile& rtile, int sample)
|
||||||
{
|
{
|
||||||
/* cast arguments to cl types */
|
/* cast arguments to cl types */
|
||||||
cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
|
cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
|
||||||
cl_mem d_buffer = CL_MEM_PTR(task.buffer);
|
cl_mem d_buffer = CL_MEM_PTR(rtile.buffer);
|
||||||
cl_mem d_rng_state = CL_MEM_PTR(task.rng_state);
|
cl_mem d_rng_state = CL_MEM_PTR(rtile.rng_state);
|
||||||
cl_int d_x = task.x;
|
cl_int d_x = rtile.x;
|
||||||
cl_int d_y = task.y;
|
cl_int d_y = rtile.y;
|
||||||
cl_int d_w = task.w;
|
cl_int d_w = rtile.w;
|
||||||
cl_int d_h = task.h;
|
cl_int d_h = rtile.h;
|
||||||
cl_int d_sample = task.sample;
|
cl_int d_sample = sample;
|
||||||
cl_int d_offset = task.offset;
|
cl_int d_offset = rtile.offset;
|
||||||
cl_int d_stride = task.stride;
|
cl_int d_stride = rtile.stride;
|
||||||
|
|
||||||
/* sample arguments */
|
/* sample arguments */
|
||||||
int narg = 0;
|
int narg = 0;
|
||||||
@@ -613,12 +618,12 @@ public:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tonemap(DeviceTask& task)
|
void tonemap(DeviceTask& task, device_ptr buffer, device_ptr rgba)
|
||||||
{
|
{
|
||||||
/* cast arguments to cl types */
|
/* cast arguments to cl types */
|
||||||
cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
|
cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
|
||||||
cl_mem d_rgba = CL_MEM_PTR(task.rgba);
|
cl_mem d_rgba = CL_MEM_PTR(rgba);
|
||||||
cl_mem d_buffer = CL_MEM_PTR(task.buffer);
|
cl_mem d_buffer = CL_MEM_PTR(buffer);
|
||||||
cl_int d_x = task.x;
|
cl_int d_x = task.x;
|
||||||
cl_int d_y = task.y;
|
cl_int d_y = task.y;
|
||||||
cl_int d_w = task.w;
|
cl_int d_w = task.w;
|
||||||
@@ -667,30 +672,57 @@ public:
|
|||||||
opencl_assert(clFinish(cqCommandQueue));
|
opencl_assert(clFinish(cqCommandQueue));
|
||||||
}
|
}
|
||||||
|
|
||||||
void task_add(DeviceTask& maintask)
|
void thread_run(DeviceTask *task)
|
||||||
{
|
{
|
||||||
list<DeviceTask> tasks;
|
if(task->type == DeviceTask::TONEMAP) {
|
||||||
|
tonemap(*task, task->buffer, task->rgba);
|
||||||
/* arbitrary limit to work around apple ATI opencl issue */
|
|
||||||
if(platform_name == "Apple")
|
|
||||||
maintask.split_max_size(tasks, 76800);
|
|
||||||
else
|
|
||||||
tasks.push_back(maintask);
|
|
||||||
|
|
||||||
foreach(DeviceTask& task, tasks) {
|
|
||||||
if(task.type == DeviceTask::TONEMAP)
|
|
||||||
tonemap(task);
|
|
||||||
else if(task.type == DeviceTask::PATH_TRACE)
|
|
||||||
path_trace(task);
|
|
||||||
}
|
}
|
||||||
|
else if(task->type == DeviceTask::PATH_TRACE) {
|
||||||
|
RenderTile tile;
|
||||||
|
|
||||||
|
/* keep rendering tiles until done */
|
||||||
|
while(task->acquire_tile(this, tile)) {
|
||||||
|
int start_sample = tile.start_sample;
|
||||||
|
int end_sample = tile.start_sample + tile.num_samples;
|
||||||
|
|
||||||
|
for(int sample = start_sample; sample < end_sample; sample++) {
|
||||||
|
if (task->get_cancel())
|
||||||
|
break;
|
||||||
|
|
||||||
|
path_trace(tile, sample);
|
||||||
|
|
||||||
|
tile.sample = sample + 1;
|
||||||
|
|
||||||
|
task->update_progress(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
task->release_tile(tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OpenCLDeviceTask : public DeviceTask {
|
||||||
|
public:
|
||||||
|
OpenCLDeviceTask(OpenCLDevice *device, DeviceTask& task)
|
||||||
|
: DeviceTask(task)
|
||||||
|
{
|
||||||
|
run = function_bind(&OpenCLDevice::thread_run, device, this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void task_add(DeviceTask& task)
|
||||||
|
{
|
||||||
|
task_pool.push(new OpenCLDeviceTask(this, task));
|
||||||
}
|
}
|
||||||
|
|
||||||
void task_wait()
|
void task_wait()
|
||||||
{
|
{
|
||||||
|
task_pool.wait_work();
|
||||||
}
|
}
|
||||||
|
|
||||||
void task_cancel()
|
void task_cancel()
|
||||||
{
|
{
|
||||||
|
task_pool.cancel();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
113
intern/cycles/device/device_task.cpp
Normal file
113
intern/cycles/device/device_task.cpp
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "device_task.h"
|
||||||
|
|
||||||
|
#include "util_algorithm.h"
|
||||||
|
#include "util_time.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Device Task */
|
||||||
|
|
||||||
|
DeviceTask::DeviceTask(Type type_)
|
||||||
|
: type(type_), x(0), y(0), w(0), h(0), rgba(0), buffer(0),
|
||||||
|
sample(0), num_samples(1), resolution(0),
|
||||||
|
shader_input(0), shader_output(0),
|
||||||
|
shader_eval_type(0), shader_x(0), shader_w(0)
|
||||||
|
{
|
||||||
|
last_update_time = time_dt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceTask::split_max_size(list<DeviceTask>& tasks, int max_size)
|
||||||
|
{
|
||||||
|
int num;
|
||||||
|
|
||||||
|
if(type == SHADER) {
|
||||||
|
num = (shader_w + max_size - 1)/max_size;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
max_size = max(1, max_size/w);
|
||||||
|
num = (h + max_size - 1)/max_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
split(tasks, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceTask::split(list<DeviceTask>& tasks, int num)
|
||||||
|
{
|
||||||
|
if(type == SHADER) {
|
||||||
|
num = min(shader_w, num);
|
||||||
|
|
||||||
|
for(int i = 0; i < num; i++) {
|
||||||
|
int tx = shader_x + (shader_w/num)*i;
|
||||||
|
int tw = (i == num-1)? shader_w - i*(shader_w/num): shader_w/num;
|
||||||
|
|
||||||
|
DeviceTask task = *this;
|
||||||
|
|
||||||
|
task.shader_x = tx;
|
||||||
|
task.shader_w = tw;
|
||||||
|
|
||||||
|
tasks.push_back(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(type == PATH_TRACE) {
|
||||||
|
for(int i = 0; i < num; i++)
|
||||||
|
tasks.push_back(*this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
num = min(h, num);
|
||||||
|
|
||||||
|
for(int i = 0; i < num; i++) {
|
||||||
|
int ty = y + (h/num)*i;
|
||||||
|
int th = (i == num-1)? h - i*(h/num): h/num;
|
||||||
|
|
||||||
|
DeviceTask task = *this;
|
||||||
|
|
||||||
|
task.y = ty;
|
||||||
|
task.h = th;
|
||||||
|
|
||||||
|
tasks.push_back(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceTask::update_progress(RenderTile &rtile)
|
||||||
|
{
|
||||||
|
if (type != PATH_TRACE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(update_progress_sample)
|
||||||
|
update_progress_sample();
|
||||||
|
|
||||||
|
if(update_tile_sample) {
|
||||||
|
double current_time = time_dt();
|
||||||
|
|
||||||
|
if (current_time - last_update_time >= 1.0f) {
|
||||||
|
update_tile_sample(rtile);
|
||||||
|
|
||||||
|
last_update_time = current_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
75
intern/cycles/device/device_task.h
Normal file
75
intern/cycles/device/device_task.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Blender Foundation.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DEVICE_TASK_H__
|
||||||
|
#define __DEVICE_TASK_H__
|
||||||
|
|
||||||
|
#include "device_memory.h"
|
||||||
|
|
||||||
|
#include "util_function.h"
|
||||||
|
#include "util_list.h"
|
||||||
|
#include "util_task.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Device Task */
|
||||||
|
|
||||||
|
class Device;
|
||||||
|
class RenderBuffers;
|
||||||
|
class RenderTile;
|
||||||
|
class Tile;
|
||||||
|
|
||||||
|
class DeviceTask : public Task {
|
||||||
|
public:
|
||||||
|
typedef enum { PATH_TRACE, TONEMAP, SHADER } Type;
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
int x, y, w, h;
|
||||||
|
device_ptr rgba;
|
||||||
|
device_ptr buffer;
|
||||||
|
int sample;
|
||||||
|
int num_samples;
|
||||||
|
int resolution;
|
||||||
|
int offset, stride;
|
||||||
|
|
||||||
|
device_ptr shader_input;
|
||||||
|
device_ptr shader_output;
|
||||||
|
int shader_eval_type;
|
||||||
|
int shader_x, shader_w;
|
||||||
|
|
||||||
|
DeviceTask(Type type = PATH_TRACE);
|
||||||
|
|
||||||
|
void split(list<DeviceTask>& tasks, int num);
|
||||||
|
void split_max_size(list<DeviceTask>& tasks, int max_size);
|
||||||
|
|
||||||
|
void update_progress(RenderTile &rtile);
|
||||||
|
|
||||||
|
boost::function<bool(Device *device, RenderTile&)> acquire_tile;
|
||||||
|
boost::function<void(void)> update_progress_sample;
|
||||||
|
boost::function<void(RenderTile&)> update_tile_sample;
|
||||||
|
boost::function<void(RenderTile&)> release_tile;
|
||||||
|
boost::function<bool(void)> get_cancel;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
double last_update_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __DEVICE_TASK_H__ */
|
||||||
|
|
||||||
@@ -61,6 +61,7 @@ set(SRC_SVM_HEADERS
|
|||||||
svm/svm_closure.h
|
svm/svm_closure.h
|
||||||
svm/svm_convert.h
|
svm/svm_convert.h
|
||||||
svm/svm_checker.h
|
svm/svm_checker.h
|
||||||
|
svm/svm_brick.h
|
||||||
svm/svm_displace.h
|
svm/svm_displace.h
|
||||||
svm/svm_fresnel.h
|
svm/svm_fresnel.h
|
||||||
svm/svm_gamma.h
|
svm/svm_gamma.h
|
||||||
|
|||||||
@@ -87,14 +87,10 @@ void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t
|
|||||||
else if(strstr(name, "__tex_image_float")) {
|
else if(strstr(name, "__tex_image_float")) {
|
||||||
texture_image_float4 *tex = NULL;
|
texture_image_float4 *tex = NULL;
|
||||||
int id = atoi(name + strlen("__tex_image_float_"));
|
int id = atoi(name + strlen("__tex_image_float_"));
|
||||||
|
int array_index = id;
|
||||||
|
|
||||||
switch(id) {
|
if (array_index >= 0 && array_index < MAX_FLOAT_IMAGES) {
|
||||||
case 95: tex = &kg->__tex_image_float_095; break;
|
tex = &kg->texture_float_images[array_index];
|
||||||
case 96: tex = &kg->__tex_image_float_096; break;
|
|
||||||
case 97: tex = &kg->__tex_image_float_097; break;
|
|
||||||
case 98: tex = &kg->__tex_image_float_098; break;
|
|
||||||
case 99: tex = &kg->__tex_image_float_099; break;
|
|
||||||
default: break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tex) {
|
if(tex) {
|
||||||
@@ -106,104 +102,10 @@ void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t
|
|||||||
else if(strstr(name, "__tex_image")) {
|
else if(strstr(name, "__tex_image")) {
|
||||||
texture_image_uchar4 *tex = NULL;
|
texture_image_uchar4 *tex = NULL;
|
||||||
int id = atoi(name + strlen("__tex_image_"));
|
int id = atoi(name + strlen("__tex_image_"));
|
||||||
|
int array_index = id - MAX_FLOAT_IMAGES;
|
||||||
|
|
||||||
switch(id) {
|
if (array_index >= 0 && array_index < MAX_BYTE_IMAGES) {
|
||||||
case 0: tex = &kg->__tex_image_000; break;
|
tex = &kg->texture_byte_images[array_index];
|
||||||
case 1: tex = &kg->__tex_image_001; break;
|
|
||||||
case 2: tex = &kg->__tex_image_002; break;
|
|
||||||
case 3: tex = &kg->__tex_image_003; break;
|
|
||||||
case 4: tex = &kg->__tex_image_004; break;
|
|
||||||
case 5: tex = &kg->__tex_image_005; break;
|
|
||||||
case 6: tex = &kg->__tex_image_006; break;
|
|
||||||
case 7: tex = &kg->__tex_image_007; break;
|
|
||||||
case 8: tex = &kg->__tex_image_008; break;
|
|
||||||
case 9: tex = &kg->__tex_image_009; break;
|
|
||||||
case 10: tex = &kg->__tex_image_010; break;
|
|
||||||
case 11: tex = &kg->__tex_image_011; break;
|
|
||||||
case 12: tex = &kg->__tex_image_012; break;
|
|
||||||
case 13: tex = &kg->__tex_image_013; break;
|
|
||||||
case 14: tex = &kg->__tex_image_014; break;
|
|
||||||
case 15: tex = &kg->__tex_image_015; break;
|
|
||||||
case 16: tex = &kg->__tex_image_016; break;
|
|
||||||
case 17: tex = &kg->__tex_image_017; break;
|
|
||||||
case 18: tex = &kg->__tex_image_018; break;
|
|
||||||
case 19: tex = &kg->__tex_image_019; break;
|
|
||||||
case 20: tex = &kg->__tex_image_020; break;
|
|
||||||
case 21: tex = &kg->__tex_image_021; break;
|
|
||||||
case 22: tex = &kg->__tex_image_022; break;
|
|
||||||
case 23: tex = &kg->__tex_image_023; break;
|
|
||||||
case 24: tex = &kg->__tex_image_024; break;
|
|
||||||
case 25: tex = &kg->__tex_image_025; break;
|
|
||||||
case 26: tex = &kg->__tex_image_026; break;
|
|
||||||
case 27: tex = &kg->__tex_image_027; break;
|
|
||||||
case 28: tex = &kg->__tex_image_028; break;
|
|
||||||
case 29: tex = &kg->__tex_image_029; break;
|
|
||||||
case 30: tex = &kg->__tex_image_030; break;
|
|
||||||
case 31: tex = &kg->__tex_image_031; break;
|
|
||||||
case 32: tex = &kg->__tex_image_032; break;
|
|
||||||
case 33: tex = &kg->__tex_image_033; break;
|
|
||||||
case 34: tex = &kg->__tex_image_034; break;
|
|
||||||
case 35: tex = &kg->__tex_image_035; break;
|
|
||||||
case 36: tex = &kg->__tex_image_036; break;
|
|
||||||
case 37: tex = &kg->__tex_image_037; break;
|
|
||||||
case 38: tex = &kg->__tex_image_038; break;
|
|
||||||
case 39: tex = &kg->__tex_image_039; break;
|
|
||||||
case 40: tex = &kg->__tex_image_040; break;
|
|
||||||
case 41: tex = &kg->__tex_image_041; break;
|
|
||||||
case 42: tex = &kg->__tex_image_042; break;
|
|
||||||
case 43: tex = &kg->__tex_image_043; break;
|
|
||||||
case 44: tex = &kg->__tex_image_044; break;
|
|
||||||
case 45: tex = &kg->__tex_image_045; break;
|
|
||||||
case 46: tex = &kg->__tex_image_046; break;
|
|
||||||
case 47: tex = &kg->__tex_image_047; break;
|
|
||||||
case 48: tex = &kg->__tex_image_048; break;
|
|
||||||
case 49: tex = &kg->__tex_image_049; break;
|
|
||||||
case 50: tex = &kg->__tex_image_050; break;
|
|
||||||
case 51: tex = &kg->__tex_image_051; break;
|
|
||||||
case 52: tex = &kg->__tex_image_052; break;
|
|
||||||
case 53: tex = &kg->__tex_image_053; break;
|
|
||||||
case 54: tex = &kg->__tex_image_054; break;
|
|
||||||
case 55: tex = &kg->__tex_image_055; break;
|
|
||||||
case 56: tex = &kg->__tex_image_056; break;
|
|
||||||
case 57: tex = &kg->__tex_image_057; break;
|
|
||||||
case 58: tex = &kg->__tex_image_058; break;
|
|
||||||
case 59: tex = &kg->__tex_image_059; break;
|
|
||||||
case 60: tex = &kg->__tex_image_060; break;
|
|
||||||
case 61: tex = &kg->__tex_image_061; break;
|
|
||||||
case 62: tex = &kg->__tex_image_062; break;
|
|
||||||
case 63: tex = &kg->__tex_image_063; break;
|
|
||||||
case 64: tex = &kg->__tex_image_064; break;
|
|
||||||
case 65: tex = &kg->__tex_image_065; break;
|
|
||||||
case 66: tex = &kg->__tex_image_066; break;
|
|
||||||
case 67: tex = &kg->__tex_image_067; break;
|
|
||||||
case 68: tex = &kg->__tex_image_068; break;
|
|
||||||
case 69: tex = &kg->__tex_image_069; break;
|
|
||||||
case 70: tex = &kg->__tex_image_070; break;
|
|
||||||
case 71: tex = &kg->__tex_image_071; break;
|
|
||||||
case 72: tex = &kg->__tex_image_072; break;
|
|
||||||
case 73: tex = &kg->__tex_image_073; break;
|
|
||||||
case 74: tex = &kg->__tex_image_074; break;
|
|
||||||
case 75: tex = &kg->__tex_image_075; break;
|
|
||||||
case 76: tex = &kg->__tex_image_076; break;
|
|
||||||
case 77: tex = &kg->__tex_image_077; break;
|
|
||||||
case 78: tex = &kg->__tex_image_078; break;
|
|
||||||
case 79: tex = &kg->__tex_image_079; break;
|
|
||||||
case 80: tex = &kg->__tex_image_080; break;
|
|
||||||
case 81: tex = &kg->__tex_image_081; break;
|
|
||||||
case 82: tex = &kg->__tex_image_082; break;
|
|
||||||
case 83: tex = &kg->__tex_image_083; break;
|
|
||||||
case 84: tex = &kg->__tex_image_084; break;
|
|
||||||
case 85: tex = &kg->__tex_image_085; break;
|
|
||||||
case 86: tex = &kg->__tex_image_086; break;
|
|
||||||
case 87: tex = &kg->__tex_image_087; break;
|
|
||||||
case 88: tex = &kg->__tex_image_088; break;
|
|
||||||
case 89: tex = &kg->__tex_image_089; break;
|
|
||||||
case 90: tex = &kg->__tex_image_090; break;
|
|
||||||
case 91: tex = &kg->__tex_image_091; break;
|
|
||||||
case 92: tex = &kg->__tex_image_092; break;
|
|
||||||
case 93: tex = &kg->__tex_image_093; break;
|
|
||||||
case 94: tex = &kg->__tex_image_094; break;
|
|
||||||
default: break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tex) {
|
if(tex) {
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ typedef texture_image<uchar4> texture_image_uchar4;
|
|||||||
#define kernel_tex_fetch_m128(tex, index) (kg->tex.fetch_m128(index))
|
#define kernel_tex_fetch_m128(tex, index) (kg->tex.fetch_m128(index))
|
||||||
#define kernel_tex_fetch_m128i(tex, index) (kg->tex.fetch_m128i(index))
|
#define kernel_tex_fetch_m128i(tex, index) (kg->tex.fetch_m128i(index))
|
||||||
#define kernel_tex_interp(tex, t, size) (kg->tex.interp(t, size))
|
#define kernel_tex_interp(tex, t, size) (kg->tex.interp(t, size))
|
||||||
#define kernel_tex_image_interp(tex, x, y) (kg->tex.interp(x, y))
|
#define kernel_tex_image_interp(tex, x, y) ((tex < MAX_FLOAT_IMAGES) ? kg->texture_float_images[tex].interp(x, y) : kg->texture_byte_images[tex - MAX_FLOAT_IMAGES].interp(x, y))
|
||||||
|
|
||||||
#define kernel_data (kg->__data)
|
#define kernel_data (kg->__data)
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,15 @@ CCL_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
#ifdef __KERNEL_CPU__
|
#ifdef __KERNEL_CPU__
|
||||||
|
|
||||||
|
#define MAX_BYTE_IMAGES 512
|
||||||
|
#define MAX_FLOAT_IMAGES 5
|
||||||
|
|
||||||
typedef struct KernelGlobals {
|
typedef struct KernelGlobals {
|
||||||
|
texture_image_uchar4 texture_byte_images[MAX_BYTE_IMAGES];
|
||||||
|
texture_image_float4 texture_float_images[MAX_FLOAT_IMAGES];
|
||||||
|
|
||||||
#define KERNEL_TEX(type, ttype, name) ttype name;
|
#define KERNEL_TEX(type, ttype, name) ttype name;
|
||||||
#define KERNEL_IMAGE_TEX(type, ttype, name) ttype name;
|
#define KERNEL_IMAGE_TEX(type, ttype, name)
|
||||||
#include "kernel_textures.h"
|
#include "kernel_textures.h"
|
||||||
|
|
||||||
KernelData __data;
|
KernelData __data;
|
||||||
|
|||||||
@@ -689,7 +689,7 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
|
|||||||
if(kernel_data.integrator.use_ambient_occlusion) {
|
if(kernel_data.integrator.use_ambient_occlusion) {
|
||||||
int num_samples = kernel_data.integrator.ao_samples;
|
int num_samples = kernel_data.integrator.ao_samples;
|
||||||
float num_samples_inv = 1.0f/num_samples;
|
float num_samples_inv = 1.0f/num_samples;
|
||||||
float ao_factor = kernel_data.background.ao_factor/num_samples;
|
float ao_factor = kernel_data.background.ao_factor;
|
||||||
|
|
||||||
for(int j = 0; j < num_samples; j++) {
|
for(int j = 0; j < num_samples; j++) {
|
||||||
/* todo: solve correlation */
|
/* todo: solve correlation */
|
||||||
|
|||||||
@@ -66,12 +66,14 @@ KERNEL_TEX(float, texture_float, __filter_table)
|
|||||||
/* sobol */
|
/* sobol */
|
||||||
KERNEL_TEX(uint, texture_uint, __sobol_directions)
|
KERNEL_TEX(uint, texture_uint, __sobol_directions)
|
||||||
|
|
||||||
|
/* full-float image */
|
||||||
|
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_000)
|
||||||
|
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_001)
|
||||||
|
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_002)
|
||||||
|
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_003)
|
||||||
|
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_004)
|
||||||
|
|
||||||
/* image */
|
/* image */
|
||||||
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_000)
|
|
||||||
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_001)
|
|
||||||
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_002)
|
|
||||||
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_003)
|
|
||||||
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_004)
|
|
||||||
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_005)
|
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_005)
|
||||||
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_006)
|
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_006)
|
||||||
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_007)
|
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_007)
|
||||||
@@ -162,13 +164,11 @@ KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_091)
|
|||||||
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_092)
|
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_092)
|
||||||
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_093)
|
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_093)
|
||||||
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_094)
|
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_094)
|
||||||
|
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_095)
|
||||||
/* full-float image */
|
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_096)
|
||||||
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_095)
|
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_097)
|
||||||
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_096)
|
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_098)
|
||||||
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_097)
|
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_099)
|
||||||
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_098)
|
|
||||||
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_099)
|
|
||||||
|
|
||||||
/* packed image (opencl) */
|
/* packed image (opencl) */
|
||||||
KERNEL_TEX(uchar4, texture_uchar4, __tex_image_packed)
|
KERNEL_TEX(uchar4, texture_uchar4, __tex_image_packed)
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ CCL_NAMESPACE_END
|
|||||||
#include "svm_value.h"
|
#include "svm_value.h"
|
||||||
#include "svm_voronoi.h"
|
#include "svm_voronoi.h"
|
||||||
#include "svm_checker.h"
|
#include "svm_checker.h"
|
||||||
|
#include "svm_brick.h"
|
||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@@ -220,6 +221,9 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT
|
|||||||
case NODE_TEX_IMAGE:
|
case NODE_TEX_IMAGE:
|
||||||
svm_node_tex_image(kg, sd, stack, node);
|
svm_node_tex_image(kg, sd, stack, node);
|
||||||
break;
|
break;
|
||||||
|
case NODE_TEX_IMAGE_BOX:
|
||||||
|
svm_node_tex_image_box(kg, sd, stack, node);
|
||||||
|
break;
|
||||||
case NODE_TEX_ENVIRONMENT:
|
case NODE_TEX_ENVIRONMENT:
|
||||||
svm_node_tex_environment(kg, sd, stack, node);
|
svm_node_tex_environment(kg, sd, stack, node);
|
||||||
break;
|
break;
|
||||||
@@ -249,6 +253,9 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT
|
|||||||
case NODE_TEX_CHECKER:
|
case NODE_TEX_CHECKER:
|
||||||
svm_node_tex_checker(kg, sd, stack, node, &offset);
|
svm_node_tex_checker(kg, sd, stack, node, &offset);
|
||||||
break;
|
break;
|
||||||
|
case NODE_TEX_BRICK:
|
||||||
|
svm_node_tex_brick(kg, sd, stack, node, &offset);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
case NODE_CAMERA:
|
case NODE_CAMERA:
|
||||||
svm_node_camera(kg, sd, stack, node.y, node.z, node.w);
|
svm_node_camera(kg, sd, stack, node.y, node.z, node.w);
|
||||||
|
|||||||
114
intern/cycles/kernel/svm/svm_brick.h
Normal file
114
intern/cycles/kernel/svm/svm_brick.h
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Blender Foundation.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Brick */
|
||||||
|
|
||||||
|
__device_noinline float brick_noise(int n) /* fast integer noise */
|
||||||
|
{
|
||||||
|
int nn;
|
||||||
|
n = (n >> 13) ^ n;
|
||||||
|
nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
|
||||||
|
return 0.5f * ((float)nn / 1073741824.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
__device_noinline float svm_brick(float3 p, float scale, float mortar_size, float bias,
|
||||||
|
float brick_width, float row_height, float offset_amount, int offset_frequency,
|
||||||
|
float squash_amount, int squash_frequency, float *tint)
|
||||||
|
{
|
||||||
|
p *= scale;
|
||||||
|
|
||||||
|
int bricknum, rownum;
|
||||||
|
float offset = 0.0f;
|
||||||
|
float x, y;
|
||||||
|
|
||||||
|
rownum = (int)floor(p.y / row_height);
|
||||||
|
|
||||||
|
if(offset_frequency && squash_frequency) {
|
||||||
|
brick_width *= ((int)(rownum) % squash_frequency ) ? 1.0f : squash_amount; /* squash */
|
||||||
|
offset = ((int)(rownum) % offset_frequency ) ? 0 : (brick_width*offset_amount); /* offset */
|
||||||
|
}
|
||||||
|
|
||||||
|
bricknum = (int)floor((p.x+offset) / brick_width);
|
||||||
|
|
||||||
|
x = (p.x+offset) - brick_width*bricknum;
|
||||||
|
y = p.y - row_height*rownum;
|
||||||
|
|
||||||
|
*tint = clamp((brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0f, 1.0f);
|
||||||
|
|
||||||
|
return (x < mortar_size || y < mortar_size ||
|
||||||
|
x > (brick_width - mortar_size) ||
|
||||||
|
y > (row_height - mortar_size)) ? 1.0f : 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
__device void svm_node_tex_brick(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
|
||||||
|
{
|
||||||
|
uint4 node2 = read_node(kg, offset);
|
||||||
|
uint4 node3 = read_node(kg, offset);
|
||||||
|
|
||||||
|
/* Input and Output Sockets */
|
||||||
|
uint co_offset, color1_offset, color2_offset, mortar_offset, scale_offset;
|
||||||
|
uint mortar_size_offset, bias_offset, brick_width_offset, row_height_offset;
|
||||||
|
uint color_offset, fac_offset;
|
||||||
|
|
||||||
|
/* RNA properties */
|
||||||
|
uint offset_frequency, squash_frequency;
|
||||||
|
|
||||||
|
float tint = 0;
|
||||||
|
|
||||||
|
decode_node_uchar4(node.y, &co_offset, &color1_offset, &color2_offset, &mortar_offset);
|
||||||
|
decode_node_uchar4(node.z, &scale_offset, &mortar_size_offset, &bias_offset, &brick_width_offset);
|
||||||
|
decode_node_uchar4(node.w, &row_height_offset, &color_offset, &fac_offset, NULL);
|
||||||
|
|
||||||
|
decode_node_uchar4(node2.x, &offset_frequency, &squash_frequency, NULL, NULL);
|
||||||
|
|
||||||
|
float3 co = stack_load_float3(stack, co_offset);
|
||||||
|
|
||||||
|
float3 color1 = stack_load_float3(stack, color1_offset);
|
||||||
|
float3 color2 = stack_load_float3(stack, color2_offset);
|
||||||
|
float3 mortar = stack_load_float3(stack, mortar_offset);
|
||||||
|
|
||||||
|
float scale = stack_load_float_default(stack, scale_offset, node2.y);
|
||||||
|
float mortar_size = stack_load_float_default(stack, mortar_size_offset, node2.z);
|
||||||
|
float bias = stack_load_float_default(stack, bias_offset, node2.w);
|
||||||
|
float brick_width = stack_load_float_default(stack, brick_width_offset, node3.x);
|
||||||
|
float row_height = stack_load_float_default(stack, row_height_offset, node3.y);
|
||||||
|
float offset_amount = __int_as_float(node3.z);
|
||||||
|
float squash_amount = __int_as_float(node3.w);
|
||||||
|
|
||||||
|
float f = svm_brick(co, scale, mortar_size, bias, brick_width, row_height,
|
||||||
|
offset_amount, offset_frequency, squash_amount, squash_frequency,
|
||||||
|
&tint);
|
||||||
|
|
||||||
|
if(f != 1.0f) {
|
||||||
|
float facm = 1.0f - tint;
|
||||||
|
|
||||||
|
color1.x = facm * (color1.x) + tint * color2.x;
|
||||||
|
color1.y = facm * (color1.y) + tint * color2.y;
|
||||||
|
color1.z = facm * (color1.z) + tint * color2.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(stack_valid(color_offset))
|
||||||
|
stack_store_float3(stack, color_offset, (f == 1.0f)? mortar: color1);
|
||||||
|
if(stack_valid(fac_offset))
|
||||||
|
stack_store_float(stack, fac_offset, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ __device_inline float svm_image_texture_frac(float x, int *ix)
|
|||||||
return x - (float)i;
|
return x - (float)i;
|
||||||
}
|
}
|
||||||
|
|
||||||
__device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y)
|
__device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb)
|
||||||
{
|
{
|
||||||
uint4 info = kernel_tex_fetch(__tex_image_packed_info, id);
|
uint4 info = kernel_tex_fetch(__tex_image_packed_info, id);
|
||||||
uint width = info.x;
|
uint width = info.x;
|
||||||
@@ -82,15 +82,24 @@ __device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y)
|
|||||||
r += ty*(1.0f - tx)*svm_image_texture_read(kg, offset + ix + niy*width);
|
r += ty*(1.0f - tx)*svm_image_texture_read(kg, offset + ix + niy*width);
|
||||||
r += ty*tx*svm_image_texture_read(kg, offset + nix + niy*width);
|
r += ty*tx*svm_image_texture_read(kg, offset + nix + niy*width);
|
||||||
|
|
||||||
|
if(srgb) {
|
||||||
|
r.x = color_srgb_to_scene_linear(r.x);
|
||||||
|
r.y = color_srgb_to_scene_linear(r.y);
|
||||||
|
r.z = color_srgb_to_scene_linear(r.z);
|
||||||
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
__device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y)
|
__device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb)
|
||||||
{
|
{
|
||||||
float4 r;
|
float4 r;
|
||||||
|
|
||||||
|
#ifdef __KERNEL_CPU__
|
||||||
|
r = kernel_tex_image_interp(id, x, y);
|
||||||
|
#else
|
||||||
/* not particularly proud of this massive switch, what are the
|
/* not particularly proud of this massive switch, what are the
|
||||||
* alternatives?
|
* alternatives?
|
||||||
* - use a single big 1D texture, and do our own lookup/filtering
|
* - use a single big 1D texture, and do our own lookup/filtering
|
||||||
@@ -101,11 +110,11 @@ __device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y)
|
|||||||
* we still need some for other storage */
|
* we still need some for other storage */
|
||||||
|
|
||||||
switch(id) {
|
switch(id) {
|
||||||
case 0: r = kernel_tex_image_interp(__tex_image_000, x, y); break;
|
case 0: r = kernel_tex_image_interp(__tex_image_float_000, x, y); break;
|
||||||
case 1: r = kernel_tex_image_interp(__tex_image_001, x, y); break;
|
case 1: r = kernel_tex_image_interp(__tex_image_float_001, x, y); break;
|
||||||
case 2: r = kernel_tex_image_interp(__tex_image_002, x, y); break;
|
case 2: r = kernel_tex_image_interp(__tex_image_float_002, x, y); break;
|
||||||
case 3: r = kernel_tex_image_interp(__tex_image_003, x, y); break;
|
case 3: r = kernel_tex_image_interp(__tex_image_float_003, x, y); break;
|
||||||
case 4: r = kernel_tex_image_interp(__tex_image_004, x, y); break;
|
case 4: r = kernel_tex_image_interp(__tex_image_float_004, x, y); break;
|
||||||
case 5: r = kernel_tex_image_interp(__tex_image_005, x, y); break;
|
case 5: r = kernel_tex_image_interp(__tex_image_005, x, y); break;
|
||||||
case 6: r = kernel_tex_image_interp(__tex_image_006, x, y); break;
|
case 6: r = kernel_tex_image_interp(__tex_image_006, x, y); break;
|
||||||
case 7: r = kernel_tex_image_interp(__tex_image_007, x, y); break;
|
case 7: r = kernel_tex_image_interp(__tex_image_007, x, y); break;
|
||||||
@@ -196,15 +205,22 @@ __device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y)
|
|||||||
case 92: r = kernel_tex_image_interp(__tex_image_092, x, y); break;
|
case 92: r = kernel_tex_image_interp(__tex_image_092, x, y); break;
|
||||||
case 93: r = kernel_tex_image_interp(__tex_image_093, x, y); break;
|
case 93: r = kernel_tex_image_interp(__tex_image_093, x, y); break;
|
||||||
case 94: r = kernel_tex_image_interp(__tex_image_094, x, y); break;
|
case 94: r = kernel_tex_image_interp(__tex_image_094, x, y); break;
|
||||||
case 95: r = kernel_tex_image_interp(__tex_image_float_095, x, y); break;
|
case 95: r = kernel_tex_image_interp(__tex_image_095, x, y); break;
|
||||||
case 96: r = kernel_tex_image_interp(__tex_image_float_096, x, y); break;
|
case 96: r = kernel_tex_image_interp(__tex_image_096, x, y); break;
|
||||||
case 97: r = kernel_tex_image_interp(__tex_image_float_097, x, y); break;
|
case 97: r = kernel_tex_image_interp(__tex_image_097, x, y); break;
|
||||||
case 98: r = kernel_tex_image_interp(__tex_image_float_098, x, y); break;
|
case 98: r = kernel_tex_image_interp(__tex_image_098, x, y); break;
|
||||||
case 99: r = kernel_tex_image_interp(__tex_image_float_099, x, y); break;
|
case 99: r = kernel_tex_image_interp(__tex_image_099, x, y); break;
|
||||||
default:
|
default:
|
||||||
kernel_assert(0);
|
kernel_assert(0);
|
||||||
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(srgb) {
|
||||||
|
r.x = color_srgb_to_scene_linear(r.x);
|
||||||
|
r.y = color_srgb_to_scene_linear(r.y);
|
||||||
|
r.z = color_srgb_to_scene_linear(r.z);
|
||||||
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -219,21 +235,102 @@ __device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *stack
|
|||||||
decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &srgb);
|
decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &srgb);
|
||||||
|
|
||||||
float3 co = stack_load_float3(stack, co_offset);
|
float3 co = stack_load_float3(stack, co_offset);
|
||||||
float4 f = svm_image_texture(kg, id, co.x, co.y);
|
float4 f = svm_image_texture(kg, id, co.x, co.y, srgb);
|
||||||
float3 r = make_float3(f.x, f.y, f.z);
|
|
||||||
|
|
||||||
if(srgb) {
|
|
||||||
r.x = color_srgb_to_scene_linear(r.x);
|
|
||||||
r.y = color_srgb_to_scene_linear(r.y);
|
|
||||||
r.z = color_srgb_to_scene_linear(r.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stack_valid(out_offset))
|
if(stack_valid(out_offset))
|
||||||
stack_store_float3(stack, out_offset, r);
|
stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
|
||||||
if(stack_valid(alpha_offset))
|
if(stack_valid(alpha_offset))
|
||||||
stack_store_float(stack, alpha_offset, f.w);
|
stack_store_float(stack, alpha_offset, f.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
|
||||||
|
{
|
||||||
|
/* get object space normal */
|
||||||
|
float3 N = sd->N;
|
||||||
|
|
||||||
|
N = sd->N;
|
||||||
|
if(sd->object != ~0)
|
||||||
|
object_inverse_normal_transform(kg, sd, &N);
|
||||||
|
|
||||||
|
/* project from direction vector to barycentric coordinates in triangles */
|
||||||
|
N.x = fabsf(N.x);
|
||||||
|
N.y = fabsf(N.y);
|
||||||
|
N.z = fabsf(N.z);
|
||||||
|
|
||||||
|
N /= (N.x + N.y + N.z);
|
||||||
|
|
||||||
|
/* basic idea is to think of this as a triangle, each corner representing
|
||||||
|
* one of the 3 faces of the cube. in the corners we have single textures,
|
||||||
|
* in between we blend between two textures, and in the middle we a blend
|
||||||
|
* between three textures.
|
||||||
|
*
|
||||||
|
* the Nxyz values are the barycentric coordinates in an equilateral
|
||||||
|
* triangle, which in case of blending in the middle has a smaller
|
||||||
|
* equilateral triangle where 3 textures blend. this divides things into
|
||||||
|
* 7 zones, with an if() test for each zone */
|
||||||
|
|
||||||
|
float3 weight = make_float3(0.0f, 0.0f, 0.0f);
|
||||||
|
float blend = __int_as_float(node.w);
|
||||||
|
float limit = 0.5f*(1.0f + blend);
|
||||||
|
|
||||||
|
/* first test for corners with single texture */
|
||||||
|
if(N.x > limit*(N.x + N.y) && N.x > limit*(N.x + N.z)) {
|
||||||
|
weight.x = 1.0f;
|
||||||
|
}
|
||||||
|
else if(N.y > limit*(N.x + N.y) && N.y > limit*(N.y + N.z)) {
|
||||||
|
weight.y = 1.0f;
|
||||||
|
}
|
||||||
|
else if(N.z > limit*(N.x + N.z) && N.z > limit*(N.y + N.z)) {
|
||||||
|
weight.z = 1.0f;
|
||||||
|
}
|
||||||
|
else if(blend > 0.0f) {
|
||||||
|
/* in case of blending, test for mixes between two textures */
|
||||||
|
if(N.z < (1.0f - limit)*(N.y + N.x)) {
|
||||||
|
weight.x = N.x/(N.x + N.y);
|
||||||
|
weight.x = clamp((weight.x - 0.5f*(1.0f - blend))/blend, 0.0f, 1.0f);
|
||||||
|
weight.y = 1.0f - weight.x;
|
||||||
|
}
|
||||||
|
else if(N.x < (1.0f - limit)*(N.y + N.z)) {
|
||||||
|
weight.y = N.y/(N.y + N.z);
|
||||||
|
weight.y = clamp((weight.y - 0.5f*(1.0f - blend))/blend, 0.0f, 1.0f);
|
||||||
|
weight.z = 1.0f - weight.y;
|
||||||
|
}
|
||||||
|
else if(N.y < (1.0f - limit)*(N.x + N.z)) {
|
||||||
|
weight.x = N.x/(N.x + N.z);
|
||||||
|
weight.x = clamp((weight.x - 0.5f*(1.0f - blend))/blend, 0.0f, 1.0f);
|
||||||
|
weight.z = 1.0f - weight.x;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* last case, we have a mix between three */
|
||||||
|
weight.x = ((2.0f - limit)*N.x + (limit - 1.0f))/(2.0f*limit - 1.0f);
|
||||||
|
weight.y = ((2.0f - limit)*N.y + (limit - 1.0f))/(2.0f*limit - 1.0f);
|
||||||
|
weight.z = ((2.0f - limit)*N.z + (limit - 1.0f))/(2.0f*limit - 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now fetch textures */
|
||||||
|
uint co_offset, out_offset, alpha_offset, srgb;
|
||||||
|
decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &srgb);
|
||||||
|
|
||||||
|
float3 co = stack_load_float3(stack, co_offset);
|
||||||
|
uint id = node.y;
|
||||||
|
|
||||||
|
float4 f = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
if(weight.x > 0.0f)
|
||||||
|
f += weight.x*svm_image_texture(kg, id, co.y, co.z, srgb);
|
||||||
|
if(weight.y > 0.0f)
|
||||||
|
f += weight.y*svm_image_texture(kg, id, co.x, co.z, srgb);
|
||||||
|
if(weight.z > 0.0f)
|
||||||
|
f += weight.z*svm_image_texture(kg, id, co.y, co.x, srgb);
|
||||||
|
|
||||||
|
if(stack_valid(out_offset))
|
||||||
|
stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
|
||||||
|
if(stack_valid(alpha_offset))
|
||||||
|
stack_store_float(stack, alpha_offset, f.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
__device void svm_node_tex_environment(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
|
__device void svm_node_tex_environment(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
|
||||||
{
|
{
|
||||||
uint id = node.y;
|
uint id = node.y;
|
||||||
@@ -252,17 +349,10 @@ __device void svm_node_tex_environment(KernelGlobals *kg, ShaderData *sd, float
|
|||||||
else
|
else
|
||||||
uv = direction_to_mirrorball(co);
|
uv = direction_to_mirrorball(co);
|
||||||
|
|
||||||
float4 f = svm_image_texture(kg, id, uv.x, uv.y);
|
float4 f = svm_image_texture(kg, id, uv.x, uv.y, srgb);
|
||||||
float3 r = make_float3(f.x, f.y, f.z);
|
|
||||||
|
|
||||||
if(srgb) {
|
|
||||||
r.x = color_srgb_to_scene_linear(r.x);
|
|
||||||
r.y = color_srgb_to_scene_linear(r.y);
|
|
||||||
r.z = color_srgb_to_scene_linear(r.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stack_valid(out_offset))
|
if(stack_valid(out_offset))
|
||||||
stack_store_float3(stack, out_offset, r);
|
stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
|
||||||
if(stack_valid(alpha_offset))
|
if(stack_valid(alpha_offset))
|
||||||
stack_store_float(stack, alpha_offset, f.w);
|
stack_store_float(stack, alpha_offset, f.w);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ typedef enum NodeType {
|
|||||||
NODE_MIX_CLOSURE,
|
NODE_MIX_CLOSURE,
|
||||||
NODE_JUMP,
|
NODE_JUMP,
|
||||||
NODE_TEX_IMAGE,
|
NODE_TEX_IMAGE,
|
||||||
|
NODE_TEX_IMAGE_BOX,
|
||||||
NODE_TEX_SKY,
|
NODE_TEX_SKY,
|
||||||
NODE_GEOMETRY,
|
NODE_GEOMETRY,
|
||||||
NODE_LIGHT_PATH,
|
NODE_LIGHT_PATH,
|
||||||
@@ -89,7 +90,8 @@ typedef enum NodeType {
|
|||||||
NODE_MIN_MAX,
|
NODE_MIN_MAX,
|
||||||
NODE_LIGHT_FALLOFF,
|
NODE_LIGHT_FALLOFF,
|
||||||
NODE_OBJECT_INFO,
|
NODE_OBJECT_INFO,
|
||||||
NODE_PARTICLE_INFO
|
NODE_PARTICLE_INFO,
|
||||||
|
NODE_TEX_BRICK
|
||||||
} NodeType;
|
} NodeType;
|
||||||
|
|
||||||
typedef enum NodeAttributeType {
|
typedef enum NodeAttributeType {
|
||||||
|
|||||||
@@ -74,6 +74,29 @@ int BufferParams::get_passes_size()
|
|||||||
return align_up(size, 4);
|
return align_up(size, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Render Buffer Task */
|
||||||
|
|
||||||
|
RenderTile::RenderTile()
|
||||||
|
{
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
w = 0;
|
||||||
|
h = 0;
|
||||||
|
|
||||||
|
start_sample = 0;
|
||||||
|
num_samples = 0;
|
||||||
|
resolution = 0;
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
stride = 0;
|
||||||
|
|
||||||
|
buffer = 0;
|
||||||
|
rng_state = 0;
|
||||||
|
rgba = 0;
|
||||||
|
|
||||||
|
buffers = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Render Buffers */
|
/* Render Buffers */
|
||||||
|
|
||||||
RenderBuffers::RenderBuffers(Device *device_)
|
RenderBuffers::RenderBuffers(Device *device_)
|
||||||
@@ -135,7 +158,7 @@ bool RenderBuffers::copy_from_device()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderBuffers::get_pass(PassType type, float exposure, int sample, int components, float *pixels)
|
bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int components, float *pixels)
|
||||||
{
|
{
|
||||||
int pass_offset = 0;
|
int pass_offset = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -67,12 +67,11 @@ class RenderBuffers {
|
|||||||
public:
|
public:
|
||||||
/* buffer parameters */
|
/* buffer parameters */
|
||||||
BufferParams params;
|
BufferParams params;
|
||||||
|
|
||||||
/* float buffer */
|
/* float buffer */
|
||||||
device_vector<float> buffer;
|
device_vector<float> buffer;
|
||||||
/* random number generator state */
|
/* random number generator state */
|
||||||
device_vector<uint> rng_state;
|
device_vector<uint> rng_state;
|
||||||
/* mutex, must be locked manually by callers */
|
|
||||||
thread_mutex mutex;
|
|
||||||
|
|
||||||
RenderBuffers(Device *device);
|
RenderBuffers(Device *device);
|
||||||
~RenderBuffers();
|
~RenderBuffers();
|
||||||
@@ -80,7 +79,7 @@ public:
|
|||||||
void reset(Device *device, BufferParams& params);
|
void reset(Device *device, BufferParams& params);
|
||||||
|
|
||||||
bool copy_from_device();
|
bool copy_from_device();
|
||||||
bool get_pass(PassType type, float exposure, int sample, int components, float *pixels);
|
bool get_pass_rect(PassType type, float exposure, int sample, int components, float *pixels);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void device_free();
|
void device_free();
|
||||||
@@ -105,8 +104,6 @@ public:
|
|||||||
bool transparent;
|
bool transparent;
|
||||||
/* byte buffer for tonemapped result */
|
/* byte buffer for tonemapped result */
|
||||||
device_vector<uchar4> rgba;
|
device_vector<uchar4> rgba;
|
||||||
/* mutex, must be locked manually by callers */
|
|
||||||
thread_mutex mutex;
|
|
||||||
|
|
||||||
DisplayBuffer(Device *device);
|
DisplayBuffer(Device *device);
|
||||||
~DisplayBuffer();
|
~DisplayBuffer();
|
||||||
@@ -124,6 +121,28 @@ protected:
|
|||||||
Device *device;
|
Device *device;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Render Tile
|
||||||
|
* Rendering task on a buffer */
|
||||||
|
|
||||||
|
class RenderTile {
|
||||||
|
public:
|
||||||
|
int x, y, w, h;
|
||||||
|
int start_sample;
|
||||||
|
int num_samples;
|
||||||
|
int sample;
|
||||||
|
int resolution;
|
||||||
|
int offset;
|
||||||
|
int stride;
|
||||||
|
|
||||||
|
device_ptr buffer;
|
||||||
|
device_ptr rng_state;
|
||||||
|
device_ptr rgba;
|
||||||
|
|
||||||
|
RenderBuffers *buffers;
|
||||||
|
|
||||||
|
RenderTile();
|
||||||
|
};
|
||||||
|
|
||||||
CCL_NAMESPACE_END
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
#endif /* __BUFFERS_H__ */
|
#endif /* __BUFFERS_H__ */
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ Camera::Camera()
|
|||||||
|
|
||||||
need_update = true;
|
need_update = true;
|
||||||
need_device_update = true;
|
need_device_update = true;
|
||||||
|
previous_need_motion = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Camera::~Camera()
|
Camera::~Camera()
|
||||||
@@ -140,8 +141,17 @@ void Camera::update()
|
|||||||
|
|
||||||
void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
||||||
{
|
{
|
||||||
|
Scene::MotionType need_motion = scene->need_motion();
|
||||||
|
|
||||||
update();
|
update();
|
||||||
|
|
||||||
|
if (previous_need_motion != need_motion) {
|
||||||
|
/* scene's motion model could have been changed since previous device
|
||||||
|
* camera update this could happen for example in case when one render
|
||||||
|
* layer has got motion pass and another not */
|
||||||
|
need_device_update = true;
|
||||||
|
}
|
||||||
|
|
||||||
if(!need_device_update)
|
if(!need_device_update)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -159,7 +169,6 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
|||||||
kcam->worldtocamera = transform_inverse(cameratoworld);
|
kcam->worldtocamera = transform_inverse(cameratoworld);
|
||||||
|
|
||||||
/* camera motion */
|
/* camera motion */
|
||||||
Scene::MotionType need_motion = scene->need_motion();
|
|
||||||
kcam->have_motion = 0;
|
kcam->have_motion = 0;
|
||||||
|
|
||||||
if(need_motion == Scene::MOTION_PASS) {
|
if(need_motion == Scene::MOTION_PASS) {
|
||||||
@@ -226,6 +235,7 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
|||||||
kcam->cliplength = (farclip == FLT_MAX)? FLT_MAX: farclip - nearclip;
|
kcam->cliplength = (farclip == FLT_MAX)? FLT_MAX: farclip - nearclip;
|
||||||
|
|
||||||
need_device_update = false;
|
need_device_update = false;
|
||||||
|
previous_need_motion = need_motion;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::device_free(Device *device, DeviceScene *dscene)
|
void Camera::device_free(Device *device, DeviceScene *dscene)
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ public:
|
|||||||
/* update */
|
/* update */
|
||||||
bool need_update;
|
bool need_update;
|
||||||
bool need_device_update;
|
bool need_device_update;
|
||||||
|
int previous_need_motion;
|
||||||
|
|
||||||
/* functions */
|
/* functions */
|
||||||
Camera();
|
Camera();
|
||||||
|
|||||||
@@ -402,6 +402,20 @@ void ShaderGraph::clean()
|
|||||||
/* break cycles */
|
/* break cycles */
|
||||||
break_cycles(output(), visited, on_stack);
|
break_cycles(output(), visited, on_stack);
|
||||||
|
|
||||||
|
/* disconnect unused nodes */
|
||||||
|
foreach(ShaderNode *node, nodes) {
|
||||||
|
if(!visited[node->id]) {
|
||||||
|
foreach(ShaderInput *to, node->inputs) {
|
||||||
|
ShaderOutput *from = to->link;
|
||||||
|
|
||||||
|
if (from) {
|
||||||
|
to->link = NULL;
|
||||||
|
from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* remove unused nodes */
|
/* remove unused nodes */
|
||||||
foreach(ShaderNode *node, nodes) {
|
foreach(ShaderNode *node, nodes) {
|
||||||
if(visited[node->id])
|
if(visited[node->id])
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ ImageManager::ImageManager()
|
|||||||
need_update = true;
|
need_update = true;
|
||||||
pack_images = false;
|
pack_images = false;
|
||||||
osl_texture_system = NULL;
|
osl_texture_system = NULL;
|
||||||
|
|
||||||
|
tex_num_images = TEX_NUM_IMAGES;
|
||||||
|
tex_num_float_images = TEX_NUM_FLOAT_IMAGES;
|
||||||
|
tex_image_byte_start = TEX_IMAGE_BYTE_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageManager::~ImageManager()
|
ImageManager::~ImageManager()
|
||||||
@@ -56,6 +60,13 @@ void ImageManager::set_osl_texture_system(void *texture_system)
|
|||||||
osl_texture_system = texture_system;
|
osl_texture_system = texture_system;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageManager::set_extended_image_limits(void)
|
||||||
|
{
|
||||||
|
tex_num_images = TEX_EXTENDED_NUM_IMAGES;
|
||||||
|
tex_num_float_images = TEX_EXTENDED_NUM_FLOAT_IMAGES;
|
||||||
|
tex_image_byte_start = TEX_EXTENDED_IMAGE_BYTE_START;
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_float_image(const string& filename)
|
static bool is_float_image(const string& filename)
|
||||||
{
|
{
|
||||||
ImageInput *in = ImageInput::create(filename);
|
ImageInput *in = ImageInput::create(filename);
|
||||||
@@ -97,7 +108,7 @@ int ImageManager::add_image(const string& filename, bool& is_float)
|
|||||||
for(slot = 0; slot < float_images.size(); slot++) {
|
for(slot = 0; slot < float_images.size(); slot++) {
|
||||||
if(float_images[slot] && float_images[slot]->filename == filename) {
|
if(float_images[slot] && float_images[slot]->filename == filename) {
|
||||||
float_images[slot]->users++;
|
float_images[slot]->users++;
|
||||||
return slot+TEX_IMAGE_FLOAT_START;
|
return slot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,8 +121,8 @@ int ImageManager::add_image(const string& filename, bool& is_float)
|
|||||||
if(slot == float_images.size()) {
|
if(slot == float_images.size()) {
|
||||||
/* max images limit reached */
|
/* max images limit reached */
|
||||||
if(float_images.size() == TEX_NUM_FLOAT_IMAGES) {
|
if(float_images.size() == TEX_NUM_FLOAT_IMAGES) {
|
||||||
printf("ImageManager::add_image: byte image limit reached %d, skipping '%s'\n",
|
printf("ImageManager::add_image: float image limit reached %d, skipping '%s'\n",
|
||||||
TEX_NUM_IMAGES, filename.c_str());
|
tex_num_float_images, filename.c_str());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,14 +136,12 @@ int ImageManager::add_image(const string& filename, bool& is_float)
|
|||||||
img->users = 1;
|
img->users = 1;
|
||||||
|
|
||||||
float_images[slot] = img;
|
float_images[slot] = img;
|
||||||
/* report slot out of total set of textures */
|
|
||||||
slot += TEX_IMAGE_FLOAT_START;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for(slot = 0; slot < images.size(); slot++) {
|
for(slot = 0; slot < images.size(); slot++) {
|
||||||
if(images[slot] && images[slot]->filename == filename) {
|
if(images[slot] && images[slot]->filename == filename) {
|
||||||
images[slot]->users++;
|
images[slot]->users++;
|
||||||
return slot;
|
return slot+tex_image_byte_start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,9 +153,9 @@ int ImageManager::add_image(const string& filename, bool& is_float)
|
|||||||
|
|
||||||
if(slot == images.size()) {
|
if(slot == images.size()) {
|
||||||
/* max images limit reached */
|
/* max images limit reached */
|
||||||
if(images.size() == TEX_NUM_IMAGES) {
|
if(images.size() == tex_num_images) {
|
||||||
printf("ImageManager::add_image: byte image limit reached %d, skipping '%s'\n",
|
printf("ImageManager::add_image: byte image limit reached %d, skipping '%s'\n",
|
||||||
TEX_NUM_IMAGES, filename.c_str());
|
tex_num_images, filename.c_str());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,6 +169,8 @@ int ImageManager::add_image(const string& filename, bool& is_float)
|
|||||||
img->users = 1;
|
img->users = 1;
|
||||||
|
|
||||||
images[slot] = img;
|
images[slot] = img;
|
||||||
|
|
||||||
|
slot += tex_image_byte_start;
|
||||||
}
|
}
|
||||||
need_update = true;
|
need_update = true;
|
||||||
|
|
||||||
@@ -340,20 +351,20 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int sl
|
|||||||
Image *img;
|
Image *img;
|
||||||
bool is_float;
|
bool is_float;
|
||||||
|
|
||||||
if(slot < TEX_IMAGE_FLOAT_START) {
|
if(slot >= tex_image_byte_start) {
|
||||||
img = images[slot];
|
img = images[slot - tex_image_byte_start];
|
||||||
is_float = false;
|
is_float = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
img = float_images[slot - TEX_IMAGE_FLOAT_START];
|
img = float_images[slot];
|
||||||
is_float = true;
|
is_float = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_float) {
|
if(is_float) {
|
||||||
string filename = path_filename(float_images[slot - TEX_IMAGE_FLOAT_START]->filename);
|
string filename = path_filename(float_images[slot]->filename);
|
||||||
progress->set_status("Updating Images", "Loading " + filename);
|
progress->set_status("Updating Images", "Loading " + filename);
|
||||||
|
|
||||||
device_vector<float4>& tex_img = dscene->tex_float_image[slot - TEX_IMAGE_FLOAT_START];
|
device_vector<float4>& tex_img = dscene->tex_float_image[slot];
|
||||||
|
|
||||||
if(tex_img.device_pointer)
|
if(tex_img.device_pointer)
|
||||||
device->tex_free(tex_img);
|
device->tex_free(tex_img);
|
||||||
@@ -377,10 +388,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int sl
|
|||||||
device->tex_alloc(name.c_str(), tex_img, true, true);
|
device->tex_alloc(name.c_str(), tex_img, true, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
string filename = path_filename(images[slot]->filename);
|
string filename = path_filename(images[slot - tex_image_byte_start]->filename);
|
||||||
progress->set_status("Updating Images", "Loading " + filename);
|
progress->set_status("Updating Images", "Loading " + filename);
|
||||||
|
|
||||||
device_vector<uchar4>& tex_img = dscene->tex_image[slot];
|
device_vector<uchar4>& tex_img = dscene->tex_image[slot - tex_image_byte_start];
|
||||||
|
|
||||||
if(tex_img.device_pointer)
|
if(tex_img.device_pointer)
|
||||||
device->tex_free(tex_img);
|
device->tex_free(tex_img);
|
||||||
@@ -412,12 +423,12 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, int sl
|
|||||||
Image *img;
|
Image *img;
|
||||||
bool is_float;
|
bool is_float;
|
||||||
|
|
||||||
if(slot < TEX_IMAGE_FLOAT_START) {
|
if(slot >= tex_image_byte_start) {
|
||||||
img = images[slot];
|
img = images[slot - tex_image_byte_start];
|
||||||
is_float = false;
|
is_float = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
img = float_images[slot - TEX_IMAGE_FLOAT_START];
|
img = float_images[slot];
|
||||||
is_float = true;
|
is_float = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,18 +440,18 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, int sl
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if(is_float) {
|
else if(is_float) {
|
||||||
device->tex_free(dscene->tex_float_image[slot - TEX_IMAGE_FLOAT_START]);
|
device->tex_free(dscene->tex_float_image[slot]);
|
||||||
dscene->tex_float_image[slot - TEX_IMAGE_FLOAT_START].clear();
|
dscene->tex_float_image[slot].clear();
|
||||||
|
|
||||||
delete float_images[slot - TEX_IMAGE_FLOAT_START];
|
delete float_images[slot];
|
||||||
float_images[slot - TEX_IMAGE_FLOAT_START] = NULL;
|
float_images[slot] = NULL;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
device->tex_free(dscene->tex_image[slot]);
|
device->tex_free(dscene->tex_image[slot - tex_image_byte_start]);
|
||||||
dscene->tex_image[slot].clear();
|
dscene->tex_image[slot - tex_image_byte_start].clear();
|
||||||
|
|
||||||
delete images[slot];
|
delete images[slot - tex_image_byte_start];
|
||||||
images[slot] = NULL;
|
images[slot - tex_image_byte_start] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -457,11 +468,11 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress&
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(images[slot]->users == 0) {
|
if(images[slot]->users == 0) {
|
||||||
device_free_image(device, dscene, slot);
|
device_free_image(device, dscene, slot + tex_image_byte_start);
|
||||||
}
|
}
|
||||||
else if(images[slot]->need_load) {
|
else if(images[slot]->need_load) {
|
||||||
if(!osl_texture_system)
|
if(!osl_texture_system)
|
||||||
pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot, &progress));
|
pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot + tex_image_byte_start, &progress));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,11 +481,11 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress&
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(float_images[slot]->users == 0) {
|
if(float_images[slot]->users == 0) {
|
||||||
device_free_image(device, dscene, slot + TEX_IMAGE_FLOAT_START);
|
device_free_image(device, dscene, slot);
|
||||||
}
|
}
|
||||||
else if(float_images[slot]->need_load) {
|
else if(float_images[slot]->need_load) {
|
||||||
if(!osl_texture_system)
|
if(!osl_texture_system)
|
||||||
pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot + TEX_IMAGE_FLOAT_START, &progress));
|
pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot, &progress));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,9 +537,9 @@ void ImageManager::device_pack_images(Device *device, DeviceScene *dscene, Progr
|
|||||||
void ImageManager::device_free(Device *device, DeviceScene *dscene)
|
void ImageManager::device_free(Device *device, DeviceScene *dscene)
|
||||||
{
|
{
|
||||||
for(size_t slot = 0; slot < images.size(); slot++)
|
for(size_t slot = 0; slot < images.size(); slot++)
|
||||||
device_free_image(device, dscene, slot);
|
device_free_image(device, dscene, slot + tex_image_byte_start);
|
||||||
for(size_t slot = 0; slot < float_images.size(); slot++)
|
for(size_t slot = 0; slot < float_images.size(); slot++)
|
||||||
device_free_image(device, dscene, slot + TEX_IMAGE_FLOAT_START);
|
device_free_image(device, dscene, slot);
|
||||||
|
|
||||||
device->tex_free(dscene->tex_image_packed);
|
device->tex_free(dscene->tex_image_packed);
|
||||||
dscene->tex_image_packed.clear();
|
dscene->tex_image_packed.clear();
|
||||||
|
|||||||
@@ -28,8 +28,11 @@ CCL_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
#define TEX_NUM_FLOAT_IMAGES 5
|
#define TEX_NUM_FLOAT_IMAGES 5
|
||||||
#define TEX_NUM_IMAGES 95
|
#define TEX_NUM_IMAGES 95
|
||||||
#define TEX_IMAGE_MAX (TEX_NUM_IMAGES + TEX_NUM_FLOAT_IMAGES)
|
#define TEX_IMAGE_BYTE_START TEX_NUM_FLOAT_IMAGES
|
||||||
#define TEX_IMAGE_FLOAT_START TEX_NUM_IMAGES
|
|
||||||
|
#define TEX_EXTENDED_NUM_FLOAT_IMAGES 5
|
||||||
|
#define TEX_EXTENDED_NUM_IMAGES 512
|
||||||
|
#define TEX_EXTENDED_IMAGE_BYTE_START TEX_EXTENDED_NUM_FLOAT_IMAGES
|
||||||
|
|
||||||
/* color to use when textures are not found */
|
/* color to use when textures are not found */
|
||||||
#define TEX_IMAGE_MISSING_R 1
|
#define TEX_IMAGE_MISSING_R 1
|
||||||
@@ -55,9 +58,15 @@ public:
|
|||||||
void set_osl_texture_system(void *texture_system);
|
void set_osl_texture_system(void *texture_system);
|
||||||
void set_pack_images(bool pack_images_);
|
void set_pack_images(bool pack_images_);
|
||||||
|
|
||||||
|
void set_extended_image_limits(void);
|
||||||
|
|
||||||
bool need_update;
|
bool need_update;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int tex_num_images;
|
||||||
|
int tex_num_float_images;
|
||||||
|
int tex_image_byte_start;
|
||||||
|
|
||||||
struct Image {
|
struct Image {
|
||||||
string filename;
|
string filename;
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,18 @@ static ShaderEnum color_space_init()
|
|||||||
return enm;
|
return enm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ShaderEnum image_projection_init()
|
||||||
|
{
|
||||||
|
ShaderEnum enm;
|
||||||
|
|
||||||
|
enm.insert("Flat", 0);
|
||||||
|
enm.insert("Box", 1);
|
||||||
|
|
||||||
|
return enm;
|
||||||
|
}
|
||||||
|
|
||||||
ShaderEnum ImageTextureNode::color_space_enum = color_space_init();
|
ShaderEnum ImageTextureNode::color_space_enum = color_space_init();
|
||||||
|
ShaderEnum ImageTextureNode::projection_enum = image_projection_init();
|
||||||
|
|
||||||
ImageTextureNode::ImageTextureNode()
|
ImageTextureNode::ImageTextureNode()
|
||||||
: TextureNode("image_texture")
|
: TextureNode("image_texture")
|
||||||
@@ -122,6 +133,8 @@ ImageTextureNode::ImageTextureNode()
|
|||||||
is_float = false;
|
is_float = false;
|
||||||
filename = "";
|
filename = "";
|
||||||
color_space = ustring("Color");
|
color_space = ustring("Color");
|
||||||
|
projection = ustring("Flat");;
|
||||||
|
projection_blend = 0.0f;
|
||||||
|
|
||||||
add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_UV);
|
add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_UV);
|
||||||
add_output("Color", SHADER_SOCKET_COLOR);
|
add_output("Color", SHADER_SOCKET_COLOR);
|
||||||
@@ -169,13 +182,25 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
|
|||||||
tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
|
tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler.add_node(NODE_TEX_IMAGE,
|
if(projection == "Flat") {
|
||||||
slot,
|
compiler.add_node(NODE_TEX_IMAGE,
|
||||||
compiler.encode_uchar4(
|
slot,
|
||||||
vector_offset,
|
compiler.encode_uchar4(
|
||||||
color_out->stack_offset,
|
vector_offset,
|
||||||
alpha_out->stack_offset,
|
color_out->stack_offset,
|
||||||
srgb));
|
alpha_out->stack_offset,
|
||||||
|
srgb));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
compiler.add_node(NODE_TEX_IMAGE_BOX,
|
||||||
|
slot,
|
||||||
|
compiler.encode_uchar4(
|
||||||
|
vector_offset,
|
||||||
|
color_out->stack_offset,
|
||||||
|
alpha_out->stack_offset,
|
||||||
|
srgb),
|
||||||
|
__float_as_int(projection_blend));
|
||||||
|
}
|
||||||
|
|
||||||
if(vector_offset != vector_in->stack_offset)
|
if(vector_offset != vector_in->stack_offset)
|
||||||
compiler.stack_clear_offset(vector_in->type, vector_offset);
|
compiler.stack_clear_offset(vector_in->type, vector_offset);
|
||||||
@@ -205,7 +230,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
|
|||||||
|
|
||||||
/* Environment Texture */
|
/* Environment Texture */
|
||||||
|
|
||||||
static ShaderEnum projection_init()
|
static ShaderEnum env_projection_init()
|
||||||
{
|
{
|
||||||
ShaderEnum enm;
|
ShaderEnum enm;
|
||||||
|
|
||||||
@@ -216,7 +241,7 @@ static ShaderEnum projection_init()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init();
|
ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init();
|
||||||
ShaderEnum EnvironmentTextureNode::projection_enum = projection_init();
|
ShaderEnum EnvironmentTextureNode::projection_enum = env_projection_init();
|
||||||
|
|
||||||
EnvironmentTextureNode::EnvironmentTextureNode()
|
EnvironmentTextureNode::EnvironmentTextureNode()
|
||||||
: TextureNode("environment_texture")
|
: TextureNode("environment_texture")
|
||||||
@@ -873,6 +898,98 @@ void CheckerTextureNode::compile(OSLCompiler& compiler)
|
|||||||
compiler.add(this, "node_checker_texture");
|
compiler.add(this, "node_checker_texture");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Brick Texture */
|
||||||
|
|
||||||
|
BrickTextureNode::BrickTextureNode()
|
||||||
|
: TextureNode("brick_texture")
|
||||||
|
{
|
||||||
|
offset = 0.5f;
|
||||||
|
offset_frequency = 2;
|
||||||
|
squash = 1.0f;
|
||||||
|
squash_frequency = 2;
|
||||||
|
|
||||||
|
add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
|
||||||
|
add_input("Color1", SHADER_SOCKET_COLOR);
|
||||||
|
add_input("Color2", SHADER_SOCKET_COLOR);
|
||||||
|
add_input("Mortar", SHADER_SOCKET_COLOR);
|
||||||
|
add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f);
|
||||||
|
add_input("Mortar Size", SHADER_SOCKET_FLOAT, 0.02f);
|
||||||
|
add_input("Bias", SHADER_SOCKET_FLOAT, 0.0f);
|
||||||
|
add_input("Brick Width", SHADER_SOCKET_FLOAT, 0.5f);
|
||||||
|
add_input("Row Height", SHADER_SOCKET_FLOAT, 0.25f);
|
||||||
|
|
||||||
|
add_output("Color", SHADER_SOCKET_COLOR);
|
||||||
|
add_output("Fac", SHADER_SOCKET_FLOAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrickTextureNode::compile(SVMCompiler& compiler)
|
||||||
|
{
|
||||||
|
ShaderInput *vector_in = input("Vector");
|
||||||
|
ShaderInput *color1_in = input("Color1");
|
||||||
|
ShaderInput *color2_in = input("Color2");
|
||||||
|
ShaderInput *mortar_in = input("Mortar");
|
||||||
|
ShaderInput *scale_in = input("Scale");
|
||||||
|
ShaderInput *mortar_size_in = input("Mortar Size");
|
||||||
|
ShaderInput *bias_in = input("Bias");
|
||||||
|
ShaderInput *brick_width_in = input("Brick Width");
|
||||||
|
ShaderInput *row_height_in = input("Row Height");
|
||||||
|
|
||||||
|
ShaderOutput *color_out = output("Color");
|
||||||
|
ShaderOutput *fac_out = output("Fac");
|
||||||
|
|
||||||
|
compiler.stack_assign(vector_in);
|
||||||
|
compiler.stack_assign(color1_in);
|
||||||
|
compiler.stack_assign(color2_in);
|
||||||
|
compiler.stack_assign(mortar_in);
|
||||||
|
if(scale_in->link) compiler.stack_assign(scale_in);
|
||||||
|
if(mortar_size_in->link) compiler.stack_assign(mortar_size_in);
|
||||||
|
if(bias_in->link) compiler.stack_assign(bias_in);
|
||||||
|
if(brick_width_in->link) compiler.stack_assign(brick_width_in);
|
||||||
|
if(row_height_in->link) compiler.stack_assign(row_height_in);
|
||||||
|
|
||||||
|
int vector_offset = vector_in->stack_offset;
|
||||||
|
|
||||||
|
if(!tex_mapping.skip()) {
|
||||||
|
vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
|
||||||
|
tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!color_out->links.empty())
|
||||||
|
compiler.stack_assign(color_out);
|
||||||
|
if(!fac_out->links.empty())
|
||||||
|
compiler.stack_assign(fac_out);
|
||||||
|
|
||||||
|
compiler.add_node(NODE_TEX_BRICK,
|
||||||
|
compiler.encode_uchar4(vector_offset,
|
||||||
|
color1_in->stack_offset, color2_in->stack_offset, mortar_in->stack_offset),
|
||||||
|
compiler.encode_uchar4(scale_in->stack_offset,
|
||||||
|
mortar_size_in->stack_offset, bias_in->stack_offset, brick_width_in->stack_offset),
|
||||||
|
compiler.encode_uchar4(row_height_in->stack_offset,
|
||||||
|
color_out->stack_offset, fac_out->stack_offset));
|
||||||
|
|
||||||
|
compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency),
|
||||||
|
__float_as_int(scale_in->value.x),
|
||||||
|
__float_as_int(mortar_size_in->value.x),
|
||||||
|
__float_as_int(bias_in->value.x));
|
||||||
|
|
||||||
|
compiler.add_node(__float_as_int(brick_width_in->value.x),
|
||||||
|
__float_as_int(row_height_in->value.x),
|
||||||
|
__float_as_int(offset),
|
||||||
|
__float_as_int(squash));
|
||||||
|
|
||||||
|
if(vector_offset != vector_in->stack_offset)
|
||||||
|
compiler.stack_clear_offset(vector_in->type, vector_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrickTextureNode::compile(OSLCompiler& compiler)
|
||||||
|
{
|
||||||
|
compiler.parameter("Offset", offset);
|
||||||
|
compiler.parameter("Offset Frequency", offset_frequency);
|
||||||
|
compiler.parameter("Squash", squash);
|
||||||
|
compiler.parameter("Squash Frequency", squash_frequency);
|
||||||
|
compiler.add(this, "node_brick_texture");
|
||||||
|
}
|
||||||
|
|
||||||
/* Normal */
|
/* Normal */
|
||||||
|
|
||||||
NormalNode::NormalNode()
|
NormalNode::NormalNode()
|
||||||
|
|||||||
@@ -70,8 +70,11 @@ public:
|
|||||||
bool is_float;
|
bool is_float;
|
||||||
string filename;
|
string filename;
|
||||||
ustring color_space;
|
ustring color_space;
|
||||||
|
ustring projection;
|
||||||
|
float projection_blend;
|
||||||
|
|
||||||
static ShaderEnum color_space_enum;
|
static ShaderEnum color_space_enum;
|
||||||
|
static ShaderEnum projection_enum;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EnvironmentTextureNode : public TextureNode {
|
class EnvironmentTextureNode : public TextureNode {
|
||||||
@@ -155,6 +158,14 @@ public:
|
|||||||
SHADER_NODE_CLASS(CheckerTextureNode)
|
SHADER_NODE_CLASS(CheckerTextureNode)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BrickTextureNode : public TextureNode {
|
||||||
|
public:
|
||||||
|
SHADER_NODE_CLASS(BrickTextureNode)
|
||||||
|
|
||||||
|
float offset, squash;
|
||||||
|
int offset_frequency, squash_frequency;
|
||||||
|
};
|
||||||
|
|
||||||
class MappingNode : public ShaderNode {
|
class MappingNode : public ShaderNode {
|
||||||
public:
|
public:
|
||||||
SHADER_NODE_CLASS(MappingNode)
|
SHADER_NODE_CLASS(MappingNode)
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
Scene::Scene(const SceneParams& params_)
|
Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
|
||||||
: params(params_)
|
: params(params_)
|
||||||
{
|
{
|
||||||
device = NULL;
|
device = NULL;
|
||||||
@@ -55,6 +55,9 @@ Scene::Scene(const SceneParams& params_)
|
|||||||
image_manager = new ImageManager();
|
image_manager = new ImageManager();
|
||||||
shader_manager = ShaderManager::create(this);
|
shader_manager = ShaderManager::create(this);
|
||||||
particle_system_manager = new ParticleSystemManager();
|
particle_system_manager = new ParticleSystemManager();
|
||||||
|
|
||||||
|
if (device_info_.type == DEVICE_CPU)
|
||||||
|
image_manager->set_extended_image_limits();
|
||||||
}
|
}
|
||||||
|
|
||||||
Scene::~Scene()
|
Scene::~Scene()
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class AttributeRequestSet;
|
|||||||
class Background;
|
class Background;
|
||||||
class Camera;
|
class Camera;
|
||||||
class Device;
|
class Device;
|
||||||
|
class DeviceInfo;
|
||||||
class Film;
|
class Film;
|
||||||
class Filter;
|
class Filter;
|
||||||
class Integrator;
|
class Integrator;
|
||||||
@@ -99,8 +100,8 @@ public:
|
|||||||
device_vector<uint> sobol_directions;
|
device_vector<uint> sobol_directions;
|
||||||
|
|
||||||
/* images */
|
/* images */
|
||||||
device_vector<uchar4> tex_image[TEX_NUM_IMAGES];
|
device_vector<uchar4> tex_image[TEX_EXTENDED_NUM_IMAGES];
|
||||||
device_vector<float4> tex_float_image[TEX_NUM_FLOAT_IMAGES];
|
device_vector<float4> tex_float_image[TEX_EXTENDED_NUM_FLOAT_IMAGES];
|
||||||
|
|
||||||
/* opencl images */
|
/* opencl images */
|
||||||
device_vector<uchar4> tex_image_packed;
|
device_vector<uchar4> tex_image_packed;
|
||||||
@@ -183,7 +184,7 @@ public:
|
|||||||
/* mutex must be locked manually by callers */
|
/* mutex must be locked manually by callers */
|
||||||
thread_mutex mutex;
|
thread_mutex mutex;
|
||||||
|
|
||||||
Scene(const SceneParams& params);
|
Scene(const SceneParams& params, const DeviceInfo& device_info);
|
||||||
~Scene();
|
~Scene();
|
||||||
|
|
||||||
void device_update(Device *device, Progress& progress);
|
void device_update(Device *device, Progress& progress);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "util_foreach.h"
|
#include "util_foreach.h"
|
||||||
#include "util_function.h"
|
#include "util_function.h"
|
||||||
|
#include "util_math.h"
|
||||||
#include "util_opengl.h"
|
#include "util_opengl.h"
|
||||||
#include "util_task.h"
|
#include "util_task.h"
|
||||||
#include "util_time.h"
|
#include "util_time.h"
|
||||||
@@ -35,15 +36,23 @@ CCL_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
Session::Session(const SessionParams& params_)
|
Session::Session(const SessionParams& params_)
|
||||||
: params(params_),
|
: params(params_),
|
||||||
tile_manager(params.progressive, params.samples, params.tile_size, params.min_size)
|
tile_manager(params.progressive, params.samples, params.tile_size, params.resolution,
|
||||||
|
(params.background)? 1: max(params.device.multi_devices.size(), 1))
|
||||||
{
|
{
|
||||||
device_use_gl = ((params.device.type != DEVICE_CPU) && !params.background);
|
device_use_gl = ((params.device.type != DEVICE_CPU) && !params.background);
|
||||||
|
|
||||||
TaskScheduler::init(params.threads);
|
TaskScheduler::init(params.threads);
|
||||||
|
|
||||||
device = Device::create(params.device, params.background, params.threads);
|
device = Device::create(params.device, params.background, params.threads);
|
||||||
buffers = new RenderBuffers(device);
|
|
||||||
display = new DisplayBuffer(device);
|
if(params.background) {
|
||||||
|
buffers = NULL;
|
||||||
|
display = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buffers = new RenderBuffers(device);
|
||||||
|
display = new DisplayBuffer(device);
|
||||||
|
}
|
||||||
|
|
||||||
session_thread = NULL;
|
session_thread = NULL;
|
||||||
scene = NULL;
|
scene = NULL;
|
||||||
@@ -52,7 +61,6 @@ Session::Session(const SessionParams& params_)
|
|||||||
reset_time = 0.0;
|
reset_time = 0.0;
|
||||||
preview_time = 0.0;
|
preview_time = 0.0;
|
||||||
paused_time = 0.0;
|
paused_time = 0.0;
|
||||||
sample = 0;
|
|
||||||
|
|
||||||
delayed_reset.do_reset = false;
|
delayed_reset.do_reset = false;
|
||||||
delayed_reset.samples = 0;
|
delayed_reset.samples = 0;
|
||||||
@@ -81,7 +89,7 @@ Session::~Session()
|
|||||||
wait();
|
wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(params.output_path != "") {
|
if(display && params.output_path != "") {
|
||||||
tonemap();
|
tonemap();
|
||||||
|
|
||||||
progress.set_status("Writing Image", params.output_path);
|
progress.set_status("Writing Image", params.output_path);
|
||||||
@@ -118,8 +126,8 @@ void Session::reset_gpu(BufferParams& buffer_params, int samples)
|
|||||||
/* block for buffer acces and reset immediately. we can't do this
|
/* block for buffer acces and reset immediately. we can't do this
|
||||||
* in the thread, because we need to allocate an OpenGL buffer, and
|
* in the thread, because we need to allocate an OpenGL buffer, and
|
||||||
* that only works in the main thread */
|
* that only works in the main thread */
|
||||||
thread_scoped_lock display_lock(display->mutex);
|
thread_scoped_lock display_lock(display_mutex);
|
||||||
thread_scoped_lock buffers_lock(buffers->mutex);
|
thread_scoped_lock buffers_lock(buffers_mutex);
|
||||||
|
|
||||||
display_outdated = true;
|
display_outdated = true;
|
||||||
reset_time = time_dt();
|
reset_time = time_dt();
|
||||||
@@ -135,7 +143,7 @@ void Session::reset_gpu(BufferParams& buffer_params, int samples)
|
|||||||
bool Session::draw_gpu(BufferParams& buffer_params)
|
bool Session::draw_gpu(BufferParams& buffer_params)
|
||||||
{
|
{
|
||||||
/* block for buffer access */
|
/* block for buffer access */
|
||||||
thread_scoped_lock display_lock(display->mutex);
|
thread_scoped_lock display_lock(display_mutex);
|
||||||
|
|
||||||
/* first check we already rendered something */
|
/* first check we already rendered something */
|
||||||
if(gpu_draw_ready) {
|
if(gpu_draw_ready) {
|
||||||
@@ -145,7 +153,7 @@ bool Session::draw_gpu(BufferParams& buffer_params)
|
|||||||
/* for CUDA we need to do tonemapping still, since we can
|
/* for CUDA we need to do tonemapping still, since we can
|
||||||
* only access GL buffers from the main thread */
|
* only access GL buffers from the main thread */
|
||||||
if(gpu_need_tonemap) {
|
if(gpu_need_tonemap) {
|
||||||
thread_scoped_lock buffers_lock(buffers->mutex);
|
thread_scoped_lock buffers_lock(buffers_mutex);
|
||||||
tonemap();
|
tonemap();
|
||||||
gpu_need_tonemap = false;
|
gpu_need_tonemap = false;
|
||||||
gpu_need_tonemap_cond.notify_all();
|
gpu_need_tonemap_cond.notify_all();
|
||||||
@@ -226,23 +234,18 @@ void Session::run_gpu()
|
|||||||
/* buffers mutex is locked entirely while rendering each
|
/* buffers mutex is locked entirely while rendering each
|
||||||
* sample, and released/reacquired on each iteration to allow
|
* sample, and released/reacquired on each iteration to allow
|
||||||
* reset and draw in between */
|
* reset and draw in between */
|
||||||
thread_scoped_lock buffers_lock(buffers->mutex);
|
thread_scoped_lock buffers_lock(buffers_mutex);
|
||||||
|
|
||||||
/* update status and timing */
|
/* update status and timing */
|
||||||
update_status_time();
|
update_status_time();
|
||||||
|
|
||||||
/* path trace */
|
/* path trace */
|
||||||
foreach(Tile& tile, tile_manager.state.tiles) {
|
path_trace();
|
||||||
path_trace(tile);
|
|
||||||
|
|
||||||
device->task_wait();
|
device->task_wait();
|
||||||
|
|
||||||
if(device->error_message() != "")
|
if(device->error_message() != "")
|
||||||
progress.set_cancel(device->error_message());
|
progress.set_cancel(device->error_message());
|
||||||
|
|
||||||
if(progress.get_cancel())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update status and timing */
|
/* update status and timing */
|
||||||
update_status_time();
|
update_status_time();
|
||||||
@@ -289,7 +292,7 @@ void Session::reset_cpu(BufferParams& buffer_params, int samples)
|
|||||||
|
|
||||||
bool Session::draw_cpu(BufferParams& buffer_params)
|
bool Session::draw_cpu(BufferParams& buffer_params)
|
||||||
{
|
{
|
||||||
thread_scoped_lock display_lock(display->mutex);
|
thread_scoped_lock display_lock(display_mutex);
|
||||||
|
|
||||||
/* first check we already rendered something */
|
/* first check we already rendered something */
|
||||||
if(display->draw_ready()) {
|
if(display->draw_ready()) {
|
||||||
@@ -308,13 +311,101 @@ bool Session::draw_cpu(BufferParams& buffer_params)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Session::acquire_tile(Device *tile_device, RenderTile& rtile)
|
||||||
|
{
|
||||||
|
if(progress.get_cancel())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
thread_scoped_lock tile_lock(tile_mutex);
|
||||||
|
|
||||||
|
/* get next tile from manager */
|
||||||
|
Tile tile;
|
||||||
|
int device_num = device->device_number(tile_device);
|
||||||
|
|
||||||
|
if(!tile_manager.next_tile(tile, device_num))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* fill render tile */
|
||||||
|
rtile.x = tile_manager.state.buffer.full_x + tile.x;
|
||||||
|
rtile.y = tile_manager.state.buffer.full_y + tile.y;
|
||||||
|
rtile.w = tile.w;
|
||||||
|
rtile.h = tile.h;
|
||||||
|
rtile.start_sample = tile_manager.state.sample;
|
||||||
|
rtile.num_samples = tile_manager.state.num_samples;
|
||||||
|
rtile.resolution = tile_manager.state.resolution;
|
||||||
|
|
||||||
|
tile_lock.unlock();
|
||||||
|
|
||||||
|
/* in case of a permant buffer, return it, otherwise we will allocate
|
||||||
|
* a new temporary buffer */
|
||||||
|
if(!write_render_tile_cb) {
|
||||||
|
tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride);
|
||||||
|
|
||||||
|
rtile.buffer = buffers->buffer.device_pointer;
|
||||||
|
rtile.rng_state = buffers->rng_state.device_pointer;
|
||||||
|
rtile.rgba = display->rgba.device_pointer;
|
||||||
|
rtile.buffers = buffers;
|
||||||
|
|
||||||
|
device->map_tile(tile_device, rtile);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill buffer parameters */
|
||||||
|
BufferParams buffer_params = tile_manager.params;
|
||||||
|
buffer_params.full_x = rtile.x;
|
||||||
|
buffer_params.full_y = rtile.y;
|
||||||
|
buffer_params.width = rtile.w;
|
||||||
|
buffer_params.height = rtile.h;
|
||||||
|
|
||||||
|
buffer_params.get_offset_stride(rtile.offset, rtile.stride);
|
||||||
|
|
||||||
|
/* allocate buffers */
|
||||||
|
RenderBuffers *tilebuffers = new RenderBuffers(tile_device);
|
||||||
|
tilebuffers->reset(tile_device, buffer_params);
|
||||||
|
|
||||||
|
rtile.buffer = tilebuffers->buffer.device_pointer;
|
||||||
|
rtile.rng_state = tilebuffers->rng_state.device_pointer;
|
||||||
|
rtile.rgba = 0;
|
||||||
|
rtile.buffers = tilebuffers;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::update_tile_sample(RenderTile& rtile)
|
||||||
|
{
|
||||||
|
thread_scoped_lock tile_lock(tile_mutex);
|
||||||
|
|
||||||
|
if(update_render_tile_cb) {
|
||||||
|
/* todo: optimize this by making it thread safe and removing lock */
|
||||||
|
|
||||||
|
update_render_tile_cb(rtile);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_status_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::release_tile(RenderTile& rtile)
|
||||||
|
{
|
||||||
|
thread_scoped_lock tile_lock(tile_mutex);
|
||||||
|
|
||||||
|
if(write_render_tile_cb) {
|
||||||
|
/* todo: optimize this by making it thread safe and removing lock */
|
||||||
|
write_render_tile_cb(rtile);
|
||||||
|
|
||||||
|
delete rtile.buffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_status_time();
|
||||||
|
}
|
||||||
|
|
||||||
void Session::run_cpu()
|
void Session::run_cpu()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
/* reset once to start */
|
/* reset once to start */
|
||||||
thread_scoped_lock reset_lock(delayed_reset.mutex);
|
thread_scoped_lock reset_lock(delayed_reset.mutex);
|
||||||
thread_scoped_lock buffers_lock(buffers->mutex);
|
thread_scoped_lock buffers_lock(buffers_mutex);
|
||||||
thread_scoped_lock display_lock(display->mutex);
|
thread_scoped_lock display_lock(display_mutex);
|
||||||
|
|
||||||
reset_(delayed_reset.params, delayed_reset.samples);
|
reset_(delayed_reset.params, delayed_reset.samples);
|
||||||
delayed_reset.do_reset = false;
|
delayed_reset.do_reset = false;
|
||||||
@@ -364,7 +455,7 @@ void Session::run_cpu()
|
|||||||
/* buffers mutex is locked entirely while rendering each
|
/* buffers mutex is locked entirely while rendering each
|
||||||
* sample, and released/reacquired on each iteration to allow
|
* sample, and released/reacquired on each iteration to allow
|
||||||
* reset and draw in between */
|
* reset and draw in between */
|
||||||
thread_scoped_lock buffers_lock(buffers->mutex);
|
thread_scoped_lock buffers_lock(buffers_mutex);
|
||||||
|
|
||||||
/* update scene */
|
/* update scene */
|
||||||
update_scene();
|
update_scene();
|
||||||
@@ -379,8 +470,7 @@ void Session::run_cpu()
|
|||||||
update_status_time();
|
update_status_time();
|
||||||
|
|
||||||
/* path trace */
|
/* path trace */
|
||||||
foreach(Tile& tile, tile_manager.state.tiles)
|
path_trace();
|
||||||
path_trace(tile);
|
|
||||||
|
|
||||||
/* update status and timing */
|
/* update status and timing */
|
||||||
update_status_time();
|
update_status_time();
|
||||||
@@ -396,8 +486,8 @@ void Session::run_cpu()
|
|||||||
|
|
||||||
{
|
{
|
||||||
thread_scoped_lock reset_lock(delayed_reset.mutex);
|
thread_scoped_lock reset_lock(delayed_reset.mutex);
|
||||||
thread_scoped_lock buffers_lock(buffers->mutex);
|
thread_scoped_lock buffers_lock(buffers_mutex);
|
||||||
thread_scoped_lock display_lock(display->mutex);
|
thread_scoped_lock display_lock(display_mutex);
|
||||||
|
|
||||||
if(delayed_reset.do_reset) {
|
if(delayed_reset.do_reset) {
|
||||||
/* reset rendering if request from main thread */
|
/* reset rendering if request from main thread */
|
||||||
@@ -442,6 +532,9 @@ void Session::run()
|
|||||||
|
|
||||||
/* run */
|
/* run */
|
||||||
if(!progress.get_cancel()) {
|
if(!progress.get_cancel()) {
|
||||||
|
/* reset number of rendered samples */
|
||||||
|
progress.reset_sample();
|
||||||
|
|
||||||
if(device_use_gl)
|
if(device_use_gl)
|
||||||
run_gpu();
|
run_gpu();
|
||||||
else
|
else
|
||||||
@@ -465,10 +558,12 @@ bool Session::draw(BufferParams& buffer_params)
|
|||||||
|
|
||||||
void Session::reset_(BufferParams& buffer_params, int samples)
|
void Session::reset_(BufferParams& buffer_params, int samples)
|
||||||
{
|
{
|
||||||
if(buffer_params.modified(buffers->params)) {
|
if(buffers) {
|
||||||
gpu_draw_ready = false;
|
if(buffer_params.modified(buffers->params)) {
|
||||||
buffers->reset(device, buffer_params);
|
gpu_draw_ready = false;
|
||||||
display->reset(device, buffer_params);
|
buffers->reset(device, buffer_params);
|
||||||
|
display->reset(device, buffer_params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tile_manager.reset(buffer_params, samples);
|
tile_manager.reset(buffer_params, samples);
|
||||||
@@ -476,7 +571,6 @@ void Session::reset_(BufferParams& buffer_params, int samples)
|
|||||||
start_time = time_dt();
|
start_time = time_dt();
|
||||||
preview_time = 0.0;
|
preview_time = 0.0;
|
||||||
paused_time = 0.0;
|
paused_time = 0.0;
|
||||||
sample = 0;
|
|
||||||
|
|
||||||
if(!params.background)
|
if(!params.background)
|
||||||
progress.set_start_time(start_time + paused_time);
|
progress.set_start_time(start_time + paused_time);
|
||||||
@@ -532,8 +626,6 @@ void Session::update_scene()
|
|||||||
{
|
{
|
||||||
thread_scoped_lock scene_lock(scene->mutex);
|
thread_scoped_lock scene_lock(scene->mutex);
|
||||||
|
|
||||||
progress.set_status("Updating Scene");
|
|
||||||
|
|
||||||
/* update camera if dimensions changed for progressive render. the camera
|
/* update camera if dimensions changed for progressive render. the camera
|
||||||
* knows nothing about progressive or cropped rendering, it just gets the
|
* knows nothing about progressive or cropped rendering, it just gets the
|
||||||
* image dimensions passed in */
|
* image dimensions passed in */
|
||||||
@@ -548,20 +640,47 @@ void Session::update_scene()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* update scene */
|
/* update scene */
|
||||||
if(scene->need_update())
|
if(scene->need_update()) {
|
||||||
|
progress.set_status("Updating Scene");
|
||||||
scene->device_update(device, progress);
|
scene->device_update(device, progress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::update_status_time(bool show_pause, bool show_done)
|
void Session::update_status_time(bool show_pause, bool show_done)
|
||||||
{
|
{
|
||||||
int sample = tile_manager.state.sample;
|
int sample = tile_manager.state.sample;
|
||||||
int resolution = tile_manager.state.resolution;
|
int resolution = tile_manager.state.resolution;
|
||||||
|
int num_tiles = tile_manager.state.num_tiles;
|
||||||
|
int tile = tile_manager.state.num_rendered_tiles;
|
||||||
|
|
||||||
/* update status */
|
/* update status */
|
||||||
string status, substatus;
|
string status, substatus;
|
||||||
|
|
||||||
if(!params.progressive)
|
if(!params.progressive) {
|
||||||
substatus = "Path Tracing";
|
substatus = string_printf("Path Tracing Tile %d/%d", tile, num_tiles);
|
||||||
|
|
||||||
|
if(params.device.type == DEVICE_CUDA || params.device.type == DEVICE_OPENCL ||
|
||||||
|
(params.device.type == DEVICE_CPU && num_tiles == 1)) {
|
||||||
|
/* when rendering on GPU multithreading happens within single tile, as in
|
||||||
|
* tiles are handling sequentially and in this case we could display
|
||||||
|
* currently rendering sample number
|
||||||
|
* this helps a lot from feedback point of view.
|
||||||
|
* also display the info on CPU, when using 1 tile only
|
||||||
|
*/
|
||||||
|
|
||||||
|
int sample = progress.get_sample(), num_samples = tile_manager.state.num_samples;
|
||||||
|
|
||||||
|
if(tile > 1) {
|
||||||
|
/* sample counter is global for all tiles, subtract samples
|
||||||
|
* from already finished tiles to get sample counter for
|
||||||
|
* current tile only
|
||||||
|
*/
|
||||||
|
sample -= (tile - 1) * num_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
substatus += string_printf(", Sample %d/%d", sample, num_samples);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if(params.samples == INT_MAX)
|
else if(params.samples == INT_MAX)
|
||||||
substatus = string_printf("Path Tracing Sample %d", sample+1);
|
substatus = string_printf("Path Tracing Sample %d", sample+1);
|
||||||
else
|
else
|
||||||
@@ -580,28 +699,29 @@ void Session::update_status_time(bool show_pause, bool show_done)
|
|||||||
if(preview_time == 0.0 && resolution == 1)
|
if(preview_time == 0.0 && resolution == 1)
|
||||||
preview_time = time_dt();
|
preview_time = time_dt();
|
||||||
|
|
||||||
double sample_time = (sample == 0)? 0.0: (time_dt() - preview_time - paused_time)/(sample);
|
double tile_time = (tile == 0)? 0.0: (time_dt() - preview_time - paused_time)/(sample);
|
||||||
|
|
||||||
/* negative can happen when we pause a bit before rendering, can discard that */
|
/* negative can happen when we pause a bit before rendering, can discard that */
|
||||||
if(preview_time < 0.0) preview_time = 0.0;
|
if(preview_time < 0.0) preview_time = 0.0;
|
||||||
|
|
||||||
progress.set_sample(sample + 1, sample_time);
|
progress.set_tile(tile, tile_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::path_trace(Tile& tile)
|
void Session::update_progress_sample()
|
||||||
|
{
|
||||||
|
progress.increment_sample();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::path_trace()
|
||||||
{
|
{
|
||||||
/* add path trace task */
|
/* add path trace task */
|
||||||
DeviceTask task(DeviceTask::PATH_TRACE);
|
DeviceTask task(DeviceTask::PATH_TRACE);
|
||||||
|
|
||||||
task.x = tile_manager.state.buffer.full_x + tile.x;
|
task.acquire_tile = function_bind(&Session::acquire_tile, this, _1, _2);
|
||||||
task.y = tile_manager.state.buffer.full_y + tile.y;
|
task.release_tile = function_bind(&Session::release_tile, this, _1);
|
||||||
task.w = tile.w;
|
task.get_cancel = function_bind(&Progress::get_cancel, &this->progress);
|
||||||
task.h = tile.h;
|
task.update_tile_sample = function_bind(&Session::update_tile_sample, this, _1);
|
||||||
task.buffer = buffers->buffer.device_pointer;
|
task.update_progress_sample = function_bind(&Session::update_progress_sample, this);
|
||||||
task.rng_state = buffers->rng_state.device_pointer;
|
|
||||||
task.sample = tile_manager.state.sample;
|
|
||||||
task.resolution = tile_manager.state.resolution;
|
|
||||||
tile_manager.state.buffer.get_offset_stride(task.offset, task.stride);
|
|
||||||
|
|
||||||
device->task_add(task);
|
device->task_add(task);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ public:
|
|||||||
bool progressive;
|
bool progressive;
|
||||||
bool experimental;
|
bool experimental;
|
||||||
int samples;
|
int samples;
|
||||||
int tile_size;
|
int2 tile_size;
|
||||||
int min_size;
|
int resolution;
|
||||||
int threads;
|
int threads;
|
||||||
|
|
||||||
double cancel_timeout;
|
double cancel_timeout;
|
||||||
@@ -63,8 +63,8 @@ public:
|
|||||||
progressive = false;
|
progressive = false;
|
||||||
experimental = false;
|
experimental = false;
|
||||||
samples = INT_MAX;
|
samples = INT_MAX;
|
||||||
tile_size = 64;
|
tile_size = make_int2(64, 64);
|
||||||
min_size = 64;
|
resolution = 4;
|
||||||
threads = 0;
|
threads = 0;
|
||||||
|
|
||||||
cancel_timeout = 0.1;
|
cancel_timeout = 0.1;
|
||||||
@@ -81,7 +81,7 @@ public:
|
|||||||
&& progressive == params.progressive
|
&& progressive == params.progressive
|
||||||
&& experimental == params.experimental
|
&& experimental == params.experimental
|
||||||
&& tile_size == params.tile_size
|
&& tile_size == params.tile_size
|
||||||
&& min_size == params.min_size
|
&& resolution == params.resolution
|
||||||
&& threads == params.threads
|
&& threads == params.threads
|
||||||
&& cancel_timeout == params.cancel_timeout
|
&& cancel_timeout == params.cancel_timeout
|
||||||
&& reset_timeout == params.reset_timeout
|
&& reset_timeout == params.reset_timeout
|
||||||
@@ -102,7 +102,10 @@ public:
|
|||||||
DisplayBuffer *display;
|
DisplayBuffer *display;
|
||||||
Progress progress;
|
Progress progress;
|
||||||
SessionParams params;
|
SessionParams params;
|
||||||
int sample;
|
TileManager tile_manager;
|
||||||
|
|
||||||
|
boost::function<void(RenderTile&)> write_render_tile_cb;
|
||||||
|
boost::function<void(RenderTile&)> update_render_tile_cb;
|
||||||
|
|
||||||
Session(const SessionParams& params);
|
Session(const SessionParams& params);
|
||||||
~Session();
|
~Session();
|
||||||
@@ -130,7 +133,7 @@ protected:
|
|||||||
void update_status_time(bool show_pause = false, bool show_done = false);
|
void update_status_time(bool show_pause = false, bool show_done = false);
|
||||||
|
|
||||||
void tonemap();
|
void tonemap();
|
||||||
void path_trace(Tile& tile);
|
void path_trace();
|
||||||
void reset_(BufferParams& params, int samples);
|
void reset_(BufferParams& params, int samples);
|
||||||
|
|
||||||
void run_cpu();
|
void run_cpu();
|
||||||
@@ -141,7 +144,12 @@ protected:
|
|||||||
bool draw_gpu(BufferParams& params);
|
bool draw_gpu(BufferParams& params);
|
||||||
void reset_gpu(BufferParams& params, int samples);
|
void reset_gpu(BufferParams& params, int samples);
|
||||||
|
|
||||||
TileManager tile_manager;
|
bool acquire_tile(Device *tile_device, RenderTile& tile);
|
||||||
|
void update_tile_sample(RenderTile& tile);
|
||||||
|
void release_tile(RenderTile& tile);
|
||||||
|
|
||||||
|
void update_progress_sample();
|
||||||
|
|
||||||
bool device_use_gl;
|
bool device_use_gl;
|
||||||
|
|
||||||
thread *session_thread;
|
thread *session_thread;
|
||||||
@@ -155,6 +163,9 @@ protected:
|
|||||||
bool pause;
|
bool pause;
|
||||||
thread_condition_variable pause_cond;
|
thread_condition_variable pause_cond;
|
||||||
thread_mutex pause_mutex;
|
thread_mutex pause_mutex;
|
||||||
|
thread_mutex tile_mutex;
|
||||||
|
thread_mutex buffers_mutex;
|
||||||
|
thread_mutex display_mutex;
|
||||||
|
|
||||||
bool kernels_loaded;
|
bool kernels_loaded;
|
||||||
|
|
||||||
|
|||||||
@@ -19,14 +19,16 @@
|
|||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
|
|
||||||
#include "util_algorithm.h"
|
#include "util_algorithm.h"
|
||||||
|
#include "util_types.h"
|
||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
TileManager::TileManager(bool progressive_, int samples_, int tile_size_, int min_size_)
|
TileManager::TileManager(bool progressive_, int num_samples_, int2 tile_size_, int resolution_, int num_devices_)
|
||||||
{
|
{
|
||||||
progressive = progressive_;
|
progressive = progressive_;
|
||||||
tile_size = tile_size_;
|
tile_size = tile_size_;
|
||||||
min_size = min_size_;
|
resolution = resolution_;
|
||||||
|
num_devices = num_devices_;
|
||||||
|
|
||||||
BufferParams buffer_params;
|
BufferParams buffer_params;
|
||||||
reset(buffer_params, 0);
|
reset(buffer_params, 0);
|
||||||
@@ -36,34 +38,24 @@ TileManager::~TileManager()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileManager::reset(BufferParams& params_, int samples_)
|
void TileManager::reset(BufferParams& params_, int num_samples_)
|
||||||
{
|
{
|
||||||
params = params_;
|
params = params_;
|
||||||
|
|
||||||
start_resolution = 1;
|
num_samples = num_samples_;
|
||||||
|
|
||||||
int w = params.width, h = params.height;
|
|
||||||
|
|
||||||
if(min_size != INT_MAX) {
|
|
||||||
while(w*h > min_size*min_size) {
|
|
||||||
w = max(1, w/2);
|
|
||||||
h = max(1, h/2);
|
|
||||||
|
|
||||||
start_resolution *= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
samples = samples_;
|
|
||||||
|
|
||||||
state.buffer = BufferParams();
|
state.buffer = BufferParams();
|
||||||
state.sample = -1;
|
state.sample = -1;
|
||||||
state.resolution = start_resolution;
|
state.num_tiles = 0;
|
||||||
|
state.num_rendered_tiles = 0;
|
||||||
|
state.num_samples = 0;
|
||||||
|
state.resolution = resolution;
|
||||||
state.tiles.clear();
|
state.tiles.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileManager::set_samples(int samples_)
|
void TileManager::set_samples(int num_samples_)
|
||||||
{
|
{
|
||||||
samples = samples_;
|
num_samples = num_samples_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileManager::set_tiles()
|
void TileManager::set_tiles()
|
||||||
@@ -71,24 +63,34 @@ void TileManager::set_tiles()
|
|||||||
int resolution = state.resolution;
|
int resolution = state.resolution;
|
||||||
int image_w = max(1, params.width/resolution);
|
int image_w = max(1, params.width/resolution);
|
||||||
int image_h = max(1, params.height/resolution);
|
int image_h = max(1, params.height/resolution);
|
||||||
int tile_w = (tile_size >= image_w)? 1: (image_w + tile_size - 1)/tile_size;
|
|
||||||
int tile_h = (tile_size >= image_h)? 1: (image_h + tile_size - 1)/tile_size;
|
|
||||||
int sub_w = image_w/tile_w;
|
|
||||||
int sub_h = image_h/tile_h;
|
|
||||||
|
|
||||||
state.tiles.clear();
|
state.tiles.clear();
|
||||||
|
|
||||||
for(int tile_y = 0; tile_y < tile_h; tile_y++) {
|
int num = min(image_h, num_devices);
|
||||||
for(int tile_x = 0; tile_x < tile_w; tile_x++) {
|
|
||||||
int x = tile_x * sub_w;
|
|
||||||
int y = tile_y * sub_h;
|
|
||||||
int w = (tile_x == tile_w-1)? image_w - x: sub_w;
|
|
||||||
int h = (tile_y == tile_h-1)? image_h - y: sub_h;
|
|
||||||
|
|
||||||
state.tiles.push_back(Tile(x, y, w, h));
|
for(int device = 0; device < num; device++) {
|
||||||
|
int device_y = (image_h/num)*device;
|
||||||
|
int device_h = (device == num-1)? image_h - device*(image_h/num): image_h/num;
|
||||||
|
|
||||||
|
int tile_w = (tile_size.x >= image_w)? 1: (image_w + tile_size.x - 1)/tile_size.x;
|
||||||
|
int tile_h = (tile_size.y >= device_h)? 1: (device_h + tile_size.y - 1)/tile_size.y;
|
||||||
|
int sub_w = (image_w + tile_w - 1)/tile_w;
|
||||||
|
int sub_h = (device_h + tile_h - 1)/tile_h;
|
||||||
|
|
||||||
|
for(int tile_y = 0; tile_y < tile_h; tile_y++) {
|
||||||
|
for(int tile_x = 0; tile_x < tile_w; tile_x++) {
|
||||||
|
int x = tile_x * sub_w;
|
||||||
|
int y = tile_y * sub_h;
|
||||||
|
int w = (tile_x == tile_w-1)? image_w - x: sub_w;
|
||||||
|
int h = (tile_y == tile_h-1)? device_h - y: sub_h;
|
||||||
|
|
||||||
|
state.tiles.push_back(Tile(x, y + device_y, w, h, device));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.num_tiles = state.tiles.size();
|
||||||
|
|
||||||
state.buffer.width = image_w;
|
state.buffer.width = image_w;
|
||||||
state.buffer.height = image_h;
|
state.buffer.height = image_h;
|
||||||
|
|
||||||
@@ -98,9 +100,74 @@ void TileManager::set_tiles()
|
|||||||
state.buffer.full_height = max(1, params.full_height/resolution);
|
state.buffer.full_height = max(1, params.full_height/resolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list<Tile>::iterator TileManager::next_center_tile(int device)
|
||||||
|
{
|
||||||
|
list<Tile>::iterator iter, best = state.tiles.end();
|
||||||
|
|
||||||
|
int resolution = state.resolution;
|
||||||
|
int image_w = max(1, params.width/resolution);
|
||||||
|
int image_h = max(1, params.height/resolution);
|
||||||
|
|
||||||
|
int num = min(image_h, num_devices);
|
||||||
|
|
||||||
|
int device_y = (image_h / num) * device;
|
||||||
|
int device_h = (device == num - 1) ? image_h - device * (image_h / num) : image_h / num;
|
||||||
|
|
||||||
|
int64_t centx = image_w / 2, centy = device_y + device_h / 2, tot = 1;
|
||||||
|
int64_t mindist = (int64_t) image_w * (int64_t) device_h;
|
||||||
|
|
||||||
|
/* find center of rendering tiles, image center counts for 1 too */
|
||||||
|
for(iter = state.tiles.begin(); iter != state.tiles.end(); iter++) {
|
||||||
|
if(iter->rendering) {
|
||||||
|
Tile &cur_tile = *iter;
|
||||||
|
centx += cur_tile.x + cur_tile.w / 2;
|
||||||
|
centy += cur_tile.y + cur_tile.h / 2;
|
||||||
|
tot++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
centx /= tot;
|
||||||
|
centy /= tot;
|
||||||
|
|
||||||
|
/* closest of the non-rendering tiles */
|
||||||
|
for(iter = state.tiles.begin(); iter != state.tiles.end(); iter++) {
|
||||||
|
if(iter->device == device && iter->rendering == false) {
|
||||||
|
Tile &cur_tile = *iter;
|
||||||
|
|
||||||
|
int64_t distx = centx - (cur_tile.x + cur_tile.w / 2);
|
||||||
|
int64_t disty = centy - (cur_tile.y + cur_tile.h / 2);
|
||||||
|
distx = (int64_t) sqrt((double)distx * distx + disty * disty);
|
||||||
|
|
||||||
|
if(distx < mindist) {
|
||||||
|
best = iter;
|
||||||
|
mindist = distx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TileManager::next_tile(Tile& tile, int device)
|
||||||
|
{
|
||||||
|
list<Tile>::iterator tile_it;
|
||||||
|
|
||||||
|
tile_it = next_center_tile(device);
|
||||||
|
|
||||||
|
if(tile_it != state.tiles.end()) {
|
||||||
|
tile_it->rendering = true;
|
||||||
|
tile = *tile_it;
|
||||||
|
state.num_rendered_tiles++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool TileManager::done()
|
bool TileManager::done()
|
||||||
{
|
{
|
||||||
return (state.sample+1 >= samples && state.resolution == 1);
|
return (state.sample+state.num_samples >= num_samples && state.resolution == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TileManager::next()
|
bool TileManager::next()
|
||||||
@@ -111,10 +178,17 @@ bool TileManager::next()
|
|||||||
if(progressive && state.resolution > 1) {
|
if(progressive && state.resolution > 1) {
|
||||||
state.sample = 0;
|
state.sample = 0;
|
||||||
state.resolution /= 2;
|
state.resolution /= 2;
|
||||||
|
state.num_samples = 1;
|
||||||
set_tiles();
|
set_tiles();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
state.sample++;
|
state.sample++;
|
||||||
|
|
||||||
|
if(progressive)
|
||||||
|
state.num_samples = 1;
|
||||||
|
else
|
||||||
|
state.num_samples = num_samples;
|
||||||
|
|
||||||
state.resolution = 1;
|
state.resolution = 1;
|
||||||
set_tiles();
|
set_tiles();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,9 +31,14 @@ CCL_NAMESPACE_BEGIN
|
|||||||
class Tile {
|
class Tile {
|
||||||
public:
|
public:
|
||||||
int x, y, w, h;
|
int x, y, w, h;
|
||||||
|
int device;
|
||||||
|
bool rendering;
|
||||||
|
|
||||||
Tile(int x_, int y_, int w_, int h_)
|
Tile()
|
||||||
: x(x_), y(y_), w(w_), h(h_) {}
|
{}
|
||||||
|
|
||||||
|
Tile(int x_, int y_, int w_, int h_, int device_)
|
||||||
|
: x(x_), y(y_), w(w_), h(h_), device(device_), rendering(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Tile Manager */
|
/* Tile Manager */
|
||||||
@@ -45,27 +50,34 @@ public:
|
|||||||
struct State {
|
struct State {
|
||||||
BufferParams buffer;
|
BufferParams buffer;
|
||||||
int sample;
|
int sample;
|
||||||
|
int num_samples;
|
||||||
int resolution;
|
int resolution;
|
||||||
|
int num_tiles;
|
||||||
|
int num_rendered_tiles;
|
||||||
list<Tile> tiles;
|
list<Tile> tiles;
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
TileManager(bool progressive, int samples, int tile_size, int min_size);
|
TileManager(bool progressive, int num_samples, int2 tile_size, int resolution, int num_devices = 1);
|
||||||
~TileManager();
|
~TileManager();
|
||||||
|
|
||||||
void reset(BufferParams& params, int samples);
|
void reset(BufferParams& params, int num_samples);
|
||||||
void set_samples(int samples);
|
void set_samples(int num_samples);
|
||||||
bool next();
|
bool next();
|
||||||
|
bool next_tile(Tile& tile, int device = 0);
|
||||||
bool done();
|
bool done();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void set_tiles();
|
void set_tiles();
|
||||||
|
|
||||||
bool progressive;
|
bool progressive;
|
||||||
int samples;
|
int num_samples;
|
||||||
int tile_size;
|
int2 tile_size;
|
||||||
int min_size;
|
int resolution;
|
||||||
|
int num_devices;
|
||||||
|
|
||||||
int start_resolution;
|
int start_resolution;
|
||||||
|
|
||||||
|
list<Tile>::iterator next_center_tile(int device = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
CCL_NAMESPACE_END
|
CCL_NAMESPACE_END
|
||||||
|
|||||||
@@ -277,6 +277,11 @@ __device_inline float cross(const float2 a, const float2 b)
|
|||||||
|
|
||||||
#ifndef __KERNEL_OPENCL__
|
#ifndef __KERNEL_OPENCL__
|
||||||
|
|
||||||
|
__device_inline bool operator==(const int2 a, const int2 b)
|
||||||
|
{
|
||||||
|
return (a.x == b.x && a.y == b.y);
|
||||||
|
}
|
||||||
|
|
||||||
__device_inline float len(const float2 a)
|
__device_inline float len(const float2 a)
|
||||||
{
|
{
|
||||||
return sqrtf(dot(a, a));
|
return sqrtf(dot(a, a));
|
||||||
|
|||||||
@@ -36,10 +36,11 @@ class Progress {
|
|||||||
public:
|
public:
|
||||||
Progress()
|
Progress()
|
||||||
{
|
{
|
||||||
|
tile = 0;
|
||||||
sample = 0;
|
sample = 0;
|
||||||
start_time = time_dt();
|
start_time = time_dt();
|
||||||
total_time = 0.0f;
|
total_time = 0.0f;
|
||||||
sample_time = 0.0f;
|
tile_time = 0.0f;
|
||||||
status = "Initializing";
|
status = "Initializing";
|
||||||
substatus = "";
|
substatus = "";
|
||||||
update_cb = NULL;
|
update_cb = NULL;
|
||||||
@@ -57,8 +58,10 @@ public:
|
|||||||
{
|
{
|
||||||
thread_scoped_lock lock(progress.progress_mutex);
|
thread_scoped_lock lock(progress.progress_mutex);
|
||||||
|
|
||||||
progress.get_sample(sample, total_time, sample_time);
|
|
||||||
progress.get_status(status, substatus);
|
progress.get_status(status, substatus);
|
||||||
|
progress.get_tile(tile, total_time, tile_time);
|
||||||
|
|
||||||
|
sample = progress.get_sample();
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -90,7 +93,7 @@ public:
|
|||||||
cancel_cb = function;
|
cancel_cb = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sample and timing information */
|
/* tile and timing information */
|
||||||
|
|
||||||
void set_start_time(double start_time_)
|
void set_start_time(double start_time_)
|
||||||
{
|
{
|
||||||
@@ -99,22 +102,41 @@ public:
|
|||||||
start_time = start_time_;
|
start_time = start_time_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_sample(int sample_, double sample_time_)
|
void set_tile(int tile_, double tile_time_)
|
||||||
{
|
{
|
||||||
thread_scoped_lock lock(progress_mutex);
|
thread_scoped_lock lock(progress_mutex);
|
||||||
|
|
||||||
sample = sample_;
|
tile = tile_;
|
||||||
total_time = time_dt() - start_time;
|
total_time = time_dt() - start_time;
|
||||||
sample_time = sample_time_;
|
tile_time = tile_time_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_sample(int& sample_, double& total_time_, double& sample_time_)
|
void get_tile(int& tile_, double& total_time_, double& tile_time_)
|
||||||
{
|
{
|
||||||
thread_scoped_lock lock(progress_mutex);
|
thread_scoped_lock lock(progress_mutex);
|
||||||
|
|
||||||
sample_ = sample;
|
tile_ = tile;
|
||||||
total_time_ = (total_time > 0.0)? total_time: 0.0;
|
total_time_ = (total_time > 0.0)? total_time: 0.0;
|
||||||
sample_time_ = sample_time;
|
tile_time_ = tile_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_sample()
|
||||||
|
{
|
||||||
|
thread_scoped_lock lock(progress_mutex);
|
||||||
|
|
||||||
|
sample = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void increment_sample()
|
||||||
|
{
|
||||||
|
thread_scoped_lock lock(progress_mutex);
|
||||||
|
|
||||||
|
sample++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_sample()
|
||||||
|
{
|
||||||
|
return sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* status messages */
|
/* status messages */
|
||||||
@@ -170,11 +192,12 @@ protected:
|
|||||||
boost::function<void(void)> update_cb;
|
boost::function<void(void)> update_cb;
|
||||||
boost::function<void(void)> cancel_cb;
|
boost::function<void(void)> cancel_cb;
|
||||||
|
|
||||||
int sample;
|
int tile; /* counter for rendered tiles */
|
||||||
|
int sample; /* counter of rendered samples, global for all tiles */
|
||||||
|
|
||||||
double start_time;
|
double start_time;
|
||||||
double total_time;
|
double total_time;
|
||||||
double sample_time;
|
double tile_time;
|
||||||
|
|
||||||
string status;
|
string status;
|
||||||
string substatus;
|
string substatus;
|
||||||
|
|||||||
@@ -546,6 +546,7 @@ struct ShadeResult;
|
|||||||
#define SH_NODE_LIGHT_FALLOFF 166
|
#define SH_NODE_LIGHT_FALLOFF 166
|
||||||
#define SH_NODE_OBJECT_INFO 167
|
#define SH_NODE_OBJECT_INFO 167
|
||||||
#define SH_NODE_PARTICLE_INFO 168
|
#define SH_NODE_PARTICLE_INFO 168
|
||||||
|
#define SH_NODE_TEX_BRICK 169
|
||||||
|
|
||||||
/* custom defines options for Material node */
|
/* custom defines options for Material node */
|
||||||
#define SH_NODE_MAT_DIFF 1
|
#define SH_NODE_MAT_DIFF 1
|
||||||
|
|||||||
@@ -2263,6 +2263,7 @@ static void registerShaderNodes(bNodeTreeType *ttype)
|
|||||||
register_node_type_sh_tex_gradient(ttype);
|
register_node_type_sh_tex_gradient(ttype);
|
||||||
register_node_type_sh_tex_magic(ttype);
|
register_node_type_sh_tex_magic(ttype);
|
||||||
register_node_type_sh_tex_checker(ttype);
|
register_node_type_sh_tex_checker(ttype);
|
||||||
|
register_node_type_sh_tex_brick(ttype);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void registerTextureNodes(bNodeTreeType *ttype)
|
static void registerTextureNodes(bNodeTreeType *ttype)
|
||||||
|
|||||||
@@ -1324,6 +1324,10 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
|
|||||||
|
|
||||||
uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
|
uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
|
||||||
uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
|
uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
|
||||||
|
uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
|
||||||
|
|
||||||
|
if(RNA_enum_get(ptr, "projection") == SHD_PROJ_BOX)
|
||||||
|
uiItemR(layout, ptr, "projection_blend", 0, "Blend", ICON_NONE);
|
||||||
|
|
||||||
/* note: image user properties used directly here, unlike compositor image node,
|
/* note: image user properties used directly here, unlike compositor image node,
|
||||||
* which redefines them in the node struct RNA to get proper updates.
|
* which redefines them in the node struct RNA to get proper updates.
|
||||||
@@ -1359,6 +1363,19 @@ static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), Po
|
|||||||
uiItemR(layout, ptr, "turbulence_depth", 0, NULL, ICON_NONE);
|
uiItemR(layout, ptr, "turbulence_depth", 0, NULL, ICON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
uiLayout *col;
|
||||||
|
|
||||||
|
col = uiLayoutColumn(layout, TRUE);
|
||||||
|
uiItemR(col, ptr, "offset", 0, IFACE_("Offset"), ICON_NONE);
|
||||||
|
uiItemR(col, ptr, "offset_frequency", 0, IFACE_("Frequency"), ICON_NONE);
|
||||||
|
|
||||||
|
col = uiLayoutColumn(layout, TRUE);
|
||||||
|
uiItemR(col, ptr, "squash", 0, IFACE_("Squash"), ICON_NONE);
|
||||||
|
uiItemR(col, ptr, "squash_frequency", 0, IFACE_("Frequency"), ICON_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
|
static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
uiItemR(layout, ptr, "wave_type", 0, "", ICON_NONE);
|
uiItemR(layout, ptr, "wave_type", 0, "", ICON_NONE);
|
||||||
@@ -1443,6 +1460,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
|
|||||||
case SH_NODE_TEX_MAGIC:
|
case SH_NODE_TEX_MAGIC:
|
||||||
ntype->uifunc = node_shader_buts_tex_magic;
|
ntype->uifunc = node_shader_buts_tex_magic;
|
||||||
break;
|
break;
|
||||||
|
case SH_NODE_TEX_BRICK:
|
||||||
|
ntype->uifunc = node_shader_buts_tex_brick;
|
||||||
|
break;
|
||||||
case SH_NODE_TEX_WAVE:
|
case SH_NODE_TEX_WAVE:
|
||||||
ntype->uifunc = node_shader_buts_tex_wave;
|
ntype->uifunc = node_shader_buts_tex_wave;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -2827,13 +2827,21 @@ static int view3d_main_area_draw_engine(const bContext *C, ARegion *ar, int draw
|
|||||||
|
|
||||||
/* create render engine */
|
/* create render engine */
|
||||||
if (!rv3d->render_engine) {
|
if (!rv3d->render_engine) {
|
||||||
|
RenderEngine *engine;
|
||||||
|
|
||||||
type = RE_engines_find(scene->r.engine);
|
type = RE_engines_find(scene->r.engine);
|
||||||
|
|
||||||
if (!(type->view_update && type->view_draw))
|
if (!(type->view_update && type->view_draw))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rv3d->render_engine = RE_engine_create(type);
|
engine = RE_engine_create(type);
|
||||||
type->view_update(rv3d->render_engine, C);
|
|
||||||
|
engine->tile_x = scene->r.xparts;
|
||||||
|
engine->tile_y = scene->r.yparts;
|
||||||
|
|
||||||
|
type->view_update(engine, C);
|
||||||
|
|
||||||
|
rv3d->render_engine = engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup view matrices */
|
/* setup view matrices */
|
||||||
|
|||||||
@@ -2114,6 +2114,12 @@ void node_tex_checker(vec3 co, vec4 color1, vec4 color2, float scale, out vec4 c
|
|||||||
fac = 1.0;
|
fac = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void node_tex_brick(vec3 co, vec4 color1, vec4 color2, vec4 mortar, float scale, float mortar_size, float bias, float brick_width, float row_height, out vec4 color, out float fac)
|
||||||
|
{
|
||||||
|
color = vec4(1.0);
|
||||||
|
fac = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
|
void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
|
||||||
{
|
{
|
||||||
color = vec4(1.0);
|
color = vec4(1.0);
|
||||||
|
|||||||
@@ -614,17 +614,27 @@ typedef struct NodeTexSky {
|
|||||||
typedef struct NodeTexImage {
|
typedef struct NodeTexImage {
|
||||||
NodeTexBase base;
|
NodeTexBase base;
|
||||||
ImageUser iuser;
|
ImageUser iuser;
|
||||||
int color_space, pad;
|
int color_space;
|
||||||
|
int projection;
|
||||||
|
float projection_blend;
|
||||||
|
int pad;
|
||||||
} NodeTexImage;
|
} NodeTexImage;
|
||||||
|
|
||||||
typedef struct NodeTexChecker {
|
typedef struct NodeTexChecker {
|
||||||
NodeTexBase base;
|
NodeTexBase base;
|
||||||
} NodeTexChecker;
|
} NodeTexChecker;
|
||||||
|
|
||||||
|
typedef struct NodeTexBrick {
|
||||||
|
NodeTexBase base;
|
||||||
|
int offset_freq, squash_freq;
|
||||||
|
float offset, squash;
|
||||||
|
} NodeTexBrick;
|
||||||
|
|
||||||
typedef struct NodeTexEnvironment {
|
typedef struct NodeTexEnvironment {
|
||||||
NodeTexBase base;
|
NodeTexBase base;
|
||||||
ImageUser iuser;
|
ImageUser iuser;
|
||||||
int color_space, projection;
|
int color_space;
|
||||||
|
int projection;
|
||||||
} NodeTexEnvironment;
|
} NodeTexEnvironment;
|
||||||
|
|
||||||
typedef struct NodeTexGradient {
|
typedef struct NodeTexGradient {
|
||||||
@@ -764,6 +774,10 @@ typedef struct NodeTrackPosData {
|
|||||||
#define SHD_PROJ_EQUIRECTANGULAR 0
|
#define SHD_PROJ_EQUIRECTANGULAR 0
|
||||||
#define SHD_PROJ_MIRROR_BALL 1
|
#define SHD_PROJ_MIRROR_BALL 1
|
||||||
|
|
||||||
|
/* image texture */
|
||||||
|
#define SHD_PROJ_FLAT 0
|
||||||
|
#define SHD_PROJ_BOX 1
|
||||||
|
|
||||||
/* blur node */
|
/* blur node */
|
||||||
#define CMP_NODE_BLUR_ASPECT_NONE 0
|
#define CMP_NODE_BLUR_ASPECT_NONE 0
|
||||||
#define CMP_NODE_BLUR_ASPECT_Y 1
|
#define CMP_NODE_BLUR_ASPECT_Y 1
|
||||||
|
|||||||
@@ -1526,6 +1526,15 @@ static void def_sh_tex_image(StructRNA *srna)
|
|||||||
{0, NULL, 0, NULL, NULL}
|
{0, NULL, 0, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const EnumPropertyItem prop_projection_items[] = {
|
||||||
|
{SHD_PROJ_FLAT, "FLAT", 0, "Flat",
|
||||||
|
"Image is projected flat using the X and Y coordinates of the texture vector"},
|
||||||
|
{SHD_PROJ_BOX, "BOX", 0, "Box",
|
||||||
|
"Image is projected using different components for each side of the object space bounding box"},
|
||||||
|
{0, NULL, 0, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
PropertyRNA *prop;
|
PropertyRNA *prop;
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
|
prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
|
||||||
@@ -1543,6 +1552,15 @@ static void def_sh_tex_image(StructRNA *srna)
|
|||||||
RNA_def_property_ui_text(prop, "Color Space", "Image file color space");
|
RNA_def_property_ui_text(prop, "Color Space", "Image file color space");
|
||||||
RNA_def_property_update(prop, 0, "rna_Node_update");
|
RNA_def_property_update(prop, 0, "rna_Node_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "projection", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_enum_items(prop, prop_projection_items);
|
||||||
|
RNA_def_property_ui_text(prop, "Projection", "Method to project 2D image on object with a 3D texture vector");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Node_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "projection_blend", PROP_FLOAT, PROP_FACTOR);
|
||||||
|
RNA_def_property_ui_text(prop, "Projection Blend", "For box projection, amount of blend to use between sides");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Node_update");
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE);
|
prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE);
|
||||||
RNA_def_property_flag(prop, PROP_NEVER_NULL);
|
RNA_def_property_flag(prop, PROP_NEVER_NULL);
|
||||||
RNA_def_property_pointer_sdna(prop, NULL, "iuser");
|
RNA_def_property_pointer_sdna(prop, NULL, "iuser");
|
||||||
@@ -1588,6 +1606,43 @@ static void def_sh_tex_checker(StructRNA *srna)
|
|||||||
def_sh_tex(srna);
|
def_sh_tex(srna);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void def_sh_tex_brick(StructRNA *srna)
|
||||||
|
{
|
||||||
|
PropertyRNA *prop;
|
||||||
|
|
||||||
|
RNA_def_struct_sdna_from(srna, "NodeTexBrick", "storage");
|
||||||
|
def_sh_tex(srna);
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "offset_frequency", PROP_INT, PROP_NONE);
|
||||||
|
RNA_def_property_int_sdna(prop, NULL, "offset_freq");
|
||||||
|
RNA_def_property_int_default(prop, 2);
|
||||||
|
RNA_def_property_range(prop, 1, 99);
|
||||||
|
RNA_def_property_ui_text(prop, "Offset Frequency", "");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Node_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "squash_frequency", PROP_INT, PROP_NONE);
|
||||||
|
RNA_def_property_int_sdna(prop, NULL, "squash_freq");
|
||||||
|
RNA_def_property_int_default(prop, 2);
|
||||||
|
RNA_def_property_range(prop, 1, 99);
|
||||||
|
RNA_def_property_ui_text(prop, "Squash Frequency", "");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Node_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE);
|
||||||
|
RNA_def_property_float_sdna(prop, NULL, "offset");
|
||||||
|
RNA_def_property_float_default(prop, 0.5f);
|
||||||
|
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||||
|
RNA_def_property_ui_text(prop, "Offset Amount", "");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Node_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "squash", PROP_FLOAT, PROP_NONE);
|
||||||
|
RNA_def_property_float_sdna(prop, NULL, "squash");
|
||||||
|
RNA_def_property_float_default(prop, 1.0f);
|
||||||
|
RNA_def_property_range(prop, 0.0f, 99.0f);
|
||||||
|
RNA_def_property_ui_text(prop, "Squash Amount", "");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Node_update");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static void def_sh_tex_magic(StructRNA *srna)
|
static void def_sh_tex_magic(StructRNA *srna)
|
||||||
{
|
{
|
||||||
PropertyRNA *prop;
|
PropertyRNA *prop;
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ DefNode( ShaderNode, SH_NODE_TEX_WAVE, def_sh_tex_wave, "TE
|
|||||||
DefNode( ShaderNode, SH_NODE_TEX_MUSGRAVE, def_sh_tex_musgrave, "TEX_MUSGRAVE", TexMusgrave, "Musgrave Texture", "" )
|
DefNode( ShaderNode, SH_NODE_TEX_MUSGRAVE, def_sh_tex_musgrave, "TEX_MUSGRAVE", TexMusgrave, "Musgrave Texture", "" )
|
||||||
DefNode( ShaderNode, SH_NODE_TEX_VORONOI, def_sh_tex_voronoi, "TEX_VORONOI", TexVoronoi, "Voronoi Texture", "" )
|
DefNode( ShaderNode, SH_NODE_TEX_VORONOI, def_sh_tex_voronoi, "TEX_VORONOI", TexVoronoi, "Voronoi Texture", "" )
|
||||||
DefNode( ShaderNode, SH_NODE_TEX_CHECKER, def_sh_tex_checker, "TEX_CHECKER", TexChecker, "Checker Texture", "" )
|
DefNode( ShaderNode, SH_NODE_TEX_CHECKER, def_sh_tex_checker, "TEX_CHECKER", TexChecker, "Checker Texture", "" )
|
||||||
|
DefNode( ShaderNode, SH_NODE_TEX_BRICK, def_sh_tex_brick, "TEX_BRICK", TexBrick, "Brick Texture", "" )
|
||||||
DefNode( ShaderNode, SH_NODE_TEX_COORD, 0, "TEX_COORD", TexCoord, "Texture Coordinate","" )
|
DefNode( ShaderNode, SH_NODE_TEX_COORD, 0, "TEX_COORD", TexCoord, "Texture Coordinate","" )
|
||||||
|
|
||||||
DefNode( CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
|
DefNode( CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
|
||||||
|
|||||||
@@ -317,6 +317,7 @@ static void rna_def_render_engine(BlenderRNA *brna)
|
|||||||
RNA_def_property_flag(prop, PROP_REQUIRED);
|
RNA_def_property_flag(prop, PROP_REQUIRED);
|
||||||
prop = RNA_def_int(func, "h", 0, 0, INT_MAX, "Height", "", 0, INT_MAX);
|
prop = RNA_def_int(func, "h", 0, 0, INT_MAX, "Height", "", 0, INT_MAX);
|
||||||
RNA_def_property_flag(prop, PROP_REQUIRED);
|
RNA_def_property_flag(prop, PROP_REQUIRED);
|
||||||
|
prop = RNA_def_string(func, "layer", "", 0, "Layer", "Single layer to get render result for");
|
||||||
prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
|
prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
|
||||||
RNA_def_function_return(func, prop);
|
RNA_def_function_return(func, prop);
|
||||||
|
|
||||||
@@ -326,6 +327,7 @@ static void rna_def_render_engine(BlenderRNA *brna)
|
|||||||
|
|
||||||
func = RNA_def_function(srna, "end_result", "RE_engine_end_result");
|
func = RNA_def_function(srna, "end_result", "RE_engine_end_result");
|
||||||
prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
|
prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
|
||||||
|
prop = RNA_def_boolean(func, "cancel", 0, "Cancel", "Don't merge back results");
|
||||||
RNA_def_property_flag(prop, PROP_REQUIRED);
|
RNA_def_property_flag(prop, PROP_REQUIRED);
|
||||||
|
|
||||||
func = RNA_def_function(srna, "test_break", "RE_engine_test_break");
|
func = RNA_def_function(srna, "test_break", "RE_engine_test_break");
|
||||||
@@ -360,6 +362,19 @@ static void rna_def_render_engine(BlenderRNA *brna)
|
|||||||
RNA_def_property_pointer_sdna(prop, NULL, "camera_override");
|
RNA_def_property_pointer_sdna(prop, NULL, "camera_override");
|
||||||
RNA_def_property_struct_type(prop, "Object");
|
RNA_def_property_struct_type(prop, "Object");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "tile_x", PROP_INT, PROP_UNSIGNED);
|
||||||
|
RNA_def_property_int_sdna(prop, NULL, "tile_x");
|
||||||
|
prop = RNA_def_property(srna, "tile_y", PROP_INT, PROP_UNSIGNED);
|
||||||
|
RNA_def_property_int_sdna(prop, NULL, "tile_y");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "resolution_x", PROP_INT, PROP_NONE);
|
||||||
|
RNA_def_property_int_sdna(prop, NULL, "resolution_x");
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "resolution_y", PROP_INT, PROP_NONE);
|
||||||
|
RNA_def_property_int_sdna(prop, NULL, "resolution_y");
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
|
|
||||||
/* registration */
|
/* registration */
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
|
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ set(SRC
|
|||||||
shader/nodes/node_shader_tex_voronoi.c
|
shader/nodes/node_shader_tex_voronoi.c
|
||||||
shader/nodes/node_shader_tex_wave.c
|
shader/nodes/node_shader_tex_wave.c
|
||||||
shader/nodes/node_shader_tex_checker.c
|
shader/nodes/node_shader_tex_checker.c
|
||||||
|
shader/nodes/node_shader_tex_brick.c
|
||||||
shader/node_shader_tree.c
|
shader/node_shader_tree.c
|
||||||
shader/node_shader_util.c
|
shader/node_shader_util.c
|
||||||
|
|
||||||
|
|||||||
90
source/blender/nodes/shader/nodes/node_shader_tex_brick.c
Normal file
90
source/blender/nodes/shader/nodes/node_shader_tex_brick.c
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* The Original Code is Copyright (C) 2005 Blender Foundation.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* The Original Code is: all of this file.
|
||||||
|
*
|
||||||
|
* Contributor(s): none yet.
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../node_shader_util.h"
|
||||||
|
|
||||||
|
/* **************** OUTPUT ******************** */
|
||||||
|
|
||||||
|
static bNodeSocketTemplate sh_node_tex_brick_in[]= {
|
||||||
|
{ SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
|
||||||
|
{ SOCK_RGBA, 1, N_("Color1"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
|
||||||
|
{ SOCK_RGBA, 1, N_("Color2"), 0.2f, 0.2f, 0.2f, 1.0f, 0.0f, 1.0f},
|
||||||
|
{ SOCK_RGBA, 1, N_("Mortar"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
||||||
|
{ SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
|
||||||
|
{ SOCK_FLOAT, 1, N_("Mortar Size"), 0.02f, 0.0f, 0.0f, 0.0f, 0.0f, 0.125f},
|
||||||
|
{ SOCK_FLOAT, 1, N_("Bias"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f},
|
||||||
|
{ SOCK_FLOAT, 1, N_("Brick Width"), 0.5f, 0.0f, 0.0f, 0.0f, 0.01f, 100.0f},
|
||||||
|
{ SOCK_FLOAT, 1, N_("Row Height"), 0.25f, 0.0f, 0.0f, 0.0f, 0.01f, 100.0f},
|
||||||
|
{ -1, 0, "" }
|
||||||
|
};
|
||||||
|
|
||||||
|
static bNodeSocketTemplate sh_node_tex_brick_out[]= {
|
||||||
|
{ SOCK_RGBA, 0, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
||||||
|
{ SOCK_FLOAT, 0, N_("Fac"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
||||||
|
{ -1, 0, "" }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
|
||||||
|
{
|
||||||
|
NodeTexBrick *tex = MEM_callocN(sizeof(NodeTexBrick), "NodeTexBrick");
|
||||||
|
default_tex_mapping(&tex->base.tex_mapping);
|
||||||
|
default_color_mapping(&tex->base.color_mapping);
|
||||||
|
|
||||||
|
tex->offset = 0.5f;
|
||||||
|
tex->squash = 1.0f;
|
||||||
|
tex->offset_freq = 2;
|
||||||
|
tex->squash_freq = 2;
|
||||||
|
|
||||||
|
node->storage = tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int node_shader_gpu_tex_brick(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out)
|
||||||
|
{
|
||||||
|
if (!in[0].link)
|
||||||
|
in[0].link = GPU_attribute(CD_ORCO, "");
|
||||||
|
|
||||||
|
node_shader_gpu_tex_mapping(mat, node, in, out);
|
||||||
|
|
||||||
|
return GPU_stack_link(mat, "node_tex_brick", in, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* node type definition */
|
||||||
|
void register_node_type_sh_tex_brick(bNodeTreeType *ttype)
|
||||||
|
{
|
||||||
|
static bNodeType ntype;
|
||||||
|
|
||||||
|
node_type_base(ttype, &ntype, SH_NODE_TEX_BRICK, "Brick Texture", NODE_CLASS_TEXTURE, NODE_OPTIONS);
|
||||||
|
node_type_compatibility(&ntype, NODE_NEW_SHADING);
|
||||||
|
node_type_socket_templates(&ntype, sh_node_tex_brick_in, sh_node_tex_brick_out);
|
||||||
|
node_type_size(&ntype, 150, 60, 200);
|
||||||
|
node_type_init(&ntype, node_shader_init_tex_brick);
|
||||||
|
node_type_storage(&ntype, "NodeTexBrick", node_free_standard_storage, node_copy_standard_storage);
|
||||||
|
node_type_exec(&ntype, NULL);
|
||||||
|
node_type_gpu(&ntype, node_shader_gpu_tex_brick);
|
||||||
|
|
||||||
|
nodeRegisterType(ttype, &ntype);
|
||||||
|
}
|
||||||
@@ -86,9 +86,14 @@ typedef struct RenderEngine {
|
|||||||
int flag;
|
int flag;
|
||||||
struct Object *camera_override;
|
struct Object *camera_override;
|
||||||
|
|
||||||
|
int tile_x;
|
||||||
|
int tile_y;
|
||||||
|
|
||||||
struct Render *re;
|
struct Render *re;
|
||||||
ListBase fullresult;
|
ListBase fullresult;
|
||||||
char *text;
|
char *text;
|
||||||
|
|
||||||
|
int resolution_x, resolution_y;
|
||||||
} RenderEngine;
|
} RenderEngine;
|
||||||
|
|
||||||
RenderEngine *RE_engine_create(RenderEngineType *type);
|
RenderEngine *RE_engine_create(RenderEngineType *type);
|
||||||
@@ -97,9 +102,9 @@ void RE_engine_free(RenderEngine *engine);
|
|||||||
void RE_layer_load_from_file(struct RenderLayer *layer, struct ReportList *reports, const char *filename, int x, int y);
|
void RE_layer_load_from_file(struct RenderLayer *layer, struct ReportList *reports, const char *filename, int x, int y);
|
||||||
void RE_result_load_from_file(struct RenderResult *result, struct ReportList *reports, const char *filename);
|
void RE_result_load_from_file(struct RenderResult *result, struct ReportList *reports, const char *filename);
|
||||||
|
|
||||||
struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h);
|
struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername);
|
||||||
void RE_engine_update_result(RenderEngine *engine, struct RenderResult *result);
|
void RE_engine_update_result(RenderEngine *engine, struct RenderResult *result);
|
||||||
void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result);
|
void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel);
|
||||||
|
|
||||||
int RE_engine_test_break(RenderEngine *engine);
|
int RE_engine_test_break(RenderEngine *engine);
|
||||||
void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info);
|
void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info);
|
||||||
|
|||||||
@@ -92,6 +92,9 @@ typedef struct RenderLayer {
|
|||||||
float *acolrect; /* 4 float, optional transparent buffer, needs storage for display updates */
|
float *acolrect; /* 4 float, optional transparent buffer, needs storage for display updates */
|
||||||
float *scolrect; /* 4 float, optional strand buffer, needs storage for display updates */
|
float *scolrect; /* 4 float, optional strand buffer, needs storage for display updates */
|
||||||
int rectx, recty;
|
int rectx, recty;
|
||||||
|
|
||||||
|
/* optional saved endresult on disk */
|
||||||
|
void *exrhandle;
|
||||||
|
|
||||||
ListBase passes;
|
ListBase passes;
|
||||||
|
|
||||||
@@ -124,7 +127,7 @@ typedef struct RenderResult {
|
|||||||
volatile RenderLayer *renlay;
|
volatile RenderLayer *renlay;
|
||||||
|
|
||||||
/* optional saved endresult on disk */
|
/* optional saved endresult on disk */
|
||||||
void *exrhandle;
|
int do_exr_tile;
|
||||||
|
|
||||||
/* for render results in Image, verify validity for sequences */
|
/* for render results in Image, verify validity for sequences */
|
||||||
int framenr;
|
int framenr;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ struct Object;
|
|||||||
void free_sample_tables(Render *re);
|
void free_sample_tables(Render *re);
|
||||||
void make_sample_tables(Render *re);
|
void make_sample_tables(Render *re);
|
||||||
|
|
||||||
void initparts(Render *re);
|
void initparts(Render *re, int do_crop);
|
||||||
void freeparts(Render *re);
|
void freeparts(Render *re);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
#define RR_USE_MEM 0
|
#define RR_USE_MEM 0
|
||||||
#define RR_USE_EXR 1
|
#define RR_USE_EXR 1
|
||||||
|
|
||||||
|
#define RR_ALL_LAYERS NULL
|
||||||
|
|
||||||
struct ImBuf;
|
struct ImBuf;
|
||||||
struct ListBase;
|
struct ListBase;
|
||||||
struct Render;
|
struct Render;
|
||||||
@@ -49,7 +51,7 @@ struct rcti;
|
|||||||
/* New */
|
/* New */
|
||||||
|
|
||||||
struct RenderResult *render_result_new(struct Render *re,
|
struct RenderResult *render_result_new(struct Render *re,
|
||||||
struct rcti *partrct, int crop, int savebuffers);
|
struct rcti *partrct, int crop, int savebuffers, const char *layername);
|
||||||
struct RenderResult *render_result_new_full_sample(struct Render *re,
|
struct RenderResult *render_result_new_full_sample(struct Render *re,
|
||||||
struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers);
|
struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers);
|
||||||
|
|
||||||
@@ -76,9 +78,9 @@ void render_result_exr_file_end(struct Render *re);
|
|||||||
|
|
||||||
void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart);
|
void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart);
|
||||||
|
|
||||||
void render_result_exr_file_path(struct Scene *scene, int sample, char *filepath);
|
void render_result_exr_file_path(struct Scene *scene, const char *layname, int sample, char *filepath);
|
||||||
int render_result_exr_file_read(struct Render *re, int sample);
|
int render_result_exr_file_read(struct Render *re, int sample);
|
||||||
int render_result_exr_file_read_path(struct RenderResult *rr, const char *filepath);
|
int render_result_exr_file_read_path(struct RenderResult *rr, struct RenderLayer *rl_single, const char *filepath);
|
||||||
|
|
||||||
/* Combined Pixel Rect */
|
/* Combined Pixel Rect */
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@
|
|||||||
#include "RE_engine.h"
|
#include "RE_engine.h"
|
||||||
#include "RE_pipeline.h"
|
#include "RE_pipeline.h"
|
||||||
|
|
||||||
|
#include "initrender.h"
|
||||||
#include "render_types.h"
|
#include "render_types.h"
|
||||||
#include "render_result.h"
|
#include "render_result.h"
|
||||||
|
|
||||||
@@ -149,7 +150,7 @@ void RE_engine_free(RenderEngine *engine)
|
|||||||
|
|
||||||
/* Render Results */
|
/* Render Results */
|
||||||
|
|
||||||
RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h)
|
RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername)
|
||||||
{
|
{
|
||||||
Render *re = engine->re;
|
Render *re = engine->re;
|
||||||
RenderResult *result;
|
RenderResult *result;
|
||||||
@@ -172,7 +173,9 @@ RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w,
|
|||||||
disprect.ymin = y;
|
disprect.ymin = y;
|
||||||
disprect.ymax = y + h;
|
disprect.ymax = y + h;
|
||||||
|
|
||||||
result = render_result_new(re, &disprect, 0, RR_USE_MEM);
|
result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername);
|
||||||
|
|
||||||
|
/* todo: make this thread safe */
|
||||||
|
|
||||||
/* can be NULL if we CLAMP the width or height to 0 */
|
/* can be NULL if we CLAMP the width or height to 0 */
|
||||||
if (result) {
|
if (result) {
|
||||||
@@ -197,25 +200,41 @@ void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RE_engine_end_result(RenderEngine *engine, RenderResult *result)
|
void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel)
|
||||||
{
|
{
|
||||||
Render *re = engine->re;
|
Render *re = engine->re;
|
||||||
|
RenderPart *pa;
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* merge. on break, don't merge in result for preview renders, looks nicer */
|
/* merge. on break, don't merge in result for preview renders, looks nicer */
|
||||||
if (!(re->test_break(re->tbh) && (re->r.scemode & R_PREVIEWBUTS)))
|
if (!cancel) {
|
||||||
render_result_merge(re->result, result);
|
/* for exr tile render, detect tiles that are done */
|
||||||
|
for (pa = re->parts.first; pa; pa = pa->next) {
|
||||||
|
if (result->tilerect.xmin == pa->disprect.xmin &&
|
||||||
|
result->tilerect.ymin == pa->disprect.ymin &&
|
||||||
|
result->tilerect.xmax == pa->disprect.xmax &&
|
||||||
|
result->tilerect.ymax == pa->disprect.ymax) {
|
||||||
|
pa->ready = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* draw */
|
if (re->result->do_exr_tile)
|
||||||
if (!re->test_break(re->tbh)) {
|
render_result_exr_file_merge(re->result, result);
|
||||||
result->renlay = result->layers.first; /* weak, draws first layer always */
|
else if (!(re->test_break(re->tbh) && (re->r.scemode & R_PREVIEWBUTS)))
|
||||||
re->display_draw(re->ddh, result, NULL);
|
render_result_merge(re->result, result);
|
||||||
|
|
||||||
|
/* draw */
|
||||||
|
if (!re->test_break(re->tbh)) {
|
||||||
|
result->renlay = result->layers.first; /* weak, draws first layer always */
|
||||||
|
re->display_draw(re->ddh, result, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free */
|
/* free */
|
||||||
render_result_free_list(&engine->fullresult, result);
|
BLI_remlink(&engine->fullresult, result);
|
||||||
|
render_result_free(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cancel */
|
/* Cancel */
|
||||||
@@ -294,12 +313,16 @@ int RE_engine_render(Render *re, int do_all)
|
|||||||
/* create render result */
|
/* create render result */
|
||||||
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
||||||
if (re->result == NULL || !(re->r.scemode & R_PREVIEWBUTS)) {
|
if (re->result == NULL || !(re->r.scemode & R_PREVIEWBUTS)) {
|
||||||
|
int savebuffers;
|
||||||
|
|
||||||
if (re->result)
|
if (re->result)
|
||||||
render_result_free(re->result);
|
render_result_free(re->result);
|
||||||
re->result = render_result_new(re, &re->disprect, 0, 0);
|
|
||||||
|
savebuffers = (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM;
|
||||||
|
re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS);
|
||||||
}
|
}
|
||||||
BLI_rw_mutex_unlock(&re->resultmutex);
|
BLI_rw_mutex_unlock(&re->resultmutex);
|
||||||
|
|
||||||
if (re->result == NULL)
|
if (re->result == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -318,14 +341,35 @@ int RE_engine_render(Render *re, int do_all)
|
|||||||
engine->flag |= RE_ENGINE_PREVIEW;
|
engine->flag |= RE_ENGINE_PREVIEW;
|
||||||
engine->camera_override = re->camera_override;
|
engine->camera_override = re->camera_override;
|
||||||
|
|
||||||
|
engine->resolution_x = re->winx;
|
||||||
|
engine->resolution_y = re->winy;
|
||||||
|
|
||||||
if ((re->r.scemode & (R_NO_FRAME_UPDATE | R_PREVIEWBUTS)) == 0)
|
if ((re->r.scemode & (R_NO_FRAME_UPDATE | R_PREVIEWBUTS)) == 0)
|
||||||
BKE_scene_update_for_newframe(re->main, re->scene, re->lay);
|
BKE_scene_update_for_newframe(re->main, re->scene, re->lay);
|
||||||
|
|
||||||
|
initparts(re, FALSE);
|
||||||
|
engine->tile_x = re->partx;
|
||||||
|
engine->tile_y = re->party;
|
||||||
|
|
||||||
|
if (re->result->do_exr_tile)
|
||||||
|
render_result_exr_file_begin(re);
|
||||||
|
|
||||||
if (type->update)
|
if (type->update)
|
||||||
type->update(engine, re->main, re->scene);
|
type->update(engine, re->main, re->scene);
|
||||||
|
|
||||||
if (type->render)
|
if (type->render)
|
||||||
type->render(engine, re->scene);
|
type->render(engine, re->scene);
|
||||||
|
|
||||||
|
if (re->result->do_exr_tile) {
|
||||||
|
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
||||||
|
render_result_exr_file_end(re);
|
||||||
|
BLI_rw_mutex_unlock(&re->resultmutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
engine->tile_x = 0;
|
||||||
|
engine->tile_y = 0;
|
||||||
|
freeparts(re);
|
||||||
|
|
||||||
render_result_free_list(&engine->fullresult, engine->fullresult.first);
|
render_result_free_list(&engine->fullresult, engine->fullresult.first);
|
||||||
|
|
||||||
RE_engine_free(engine);
|
RE_engine_free(engine);
|
||||||
|
|||||||
@@ -537,7 +537,7 @@ void freeparts(Render *re)
|
|||||||
BLI_freelistN(&re->parts);
|
BLI_freelistN(&re->parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initparts(Render *re)
|
void initparts(Render *re, int do_crop)
|
||||||
{
|
{
|
||||||
int nr, xd, yd, partx, party, xparts, yparts;
|
int nr, xd, yd, partx, party, xparts, yparts;
|
||||||
int xminb, xmaxb, yminb, ymaxb;
|
int xminb, xmaxb, yminb, ymaxb;
|
||||||
@@ -618,7 +618,7 @@ void initparts(Render *re)
|
|||||||
RenderPart *pa = MEM_callocN(sizeof(RenderPart), "new part");
|
RenderPart *pa = MEM_callocN(sizeof(RenderPart), "new part");
|
||||||
|
|
||||||
/* Non-box filters need 2 pixels extra to work */
|
/* Non-box filters need 2 pixels extra to work */
|
||||||
if ((re->r.filtertype || (re->r.mode & R_EDGE))) {
|
if (do_crop && (re->r.filtertype || (re->r.mode & R_EDGE))) {
|
||||||
pa->crop = 2;
|
pa->crop = 2;
|
||||||
disprect.xmin -= pa->crop;
|
disprect.xmin -= pa->crop;
|
||||||
disprect.ymin -= pa->crop;
|
disprect.ymin -= pa->crop;
|
||||||
|
|||||||
@@ -640,7 +640,7 @@ static void *do_part_thread(void *pa_v)
|
|||||||
if (!R.sss_points && (R.r.scemode & R_FULL_SAMPLE))
|
if (!R.sss_points && (R.r.scemode & R_FULL_SAMPLE))
|
||||||
pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM);
|
pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM);
|
||||||
else
|
else
|
||||||
pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM);
|
pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM, RR_ALL_LAYERS);
|
||||||
|
|
||||||
if (R.sss_points)
|
if (R.sss_points)
|
||||||
zbufshade_sss_tile(pa);
|
zbufshade_sss_tile(pa);
|
||||||
@@ -650,7 +650,7 @@ static void *do_part_thread(void *pa_v)
|
|||||||
zbufshade_tile(pa);
|
zbufshade_tile(pa);
|
||||||
|
|
||||||
/* merge too on break! */
|
/* merge too on break! */
|
||||||
if (R.result->exrhandle) {
|
if (R.result->do_exr_tile) {
|
||||||
render_result_exr_file_merge(R.result, pa->result);
|
render_result_exr_file_merge(R.result, pa->result);
|
||||||
}
|
}
|
||||||
else if (render_display_draw_enabled(&R)) {
|
else if (render_display_draw_enabled(&R)) {
|
||||||
@@ -794,12 +794,12 @@ static void threaded_tile_processor(Render *re)
|
|||||||
render_result_free(re->result);
|
render_result_free(re->result);
|
||||||
|
|
||||||
if (re->sss_points && render_display_draw_enabled(re))
|
if (re->sss_points && render_display_draw_enabled(re))
|
||||||
re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM);
|
re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
|
||||||
else if (re->r.scemode & R_FULL_SAMPLE)
|
else if (re->r.scemode & R_FULL_SAMPLE)
|
||||||
re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR);
|
re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR);
|
||||||
else
|
else
|
||||||
re->result = render_result_new(re, &re->disprect, 0,
|
re->result = render_result_new(re, &re->disprect, 0,
|
||||||
(re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM);
|
(re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM, RR_ALL_LAYERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
BLI_rw_mutex_unlock(&re->resultmutex);
|
BLI_rw_mutex_unlock(&re->resultmutex);
|
||||||
@@ -809,9 +809,9 @@ static void threaded_tile_processor(Render *re)
|
|||||||
|
|
||||||
/* warning; no return here without closing exr file */
|
/* warning; no return here without closing exr file */
|
||||||
|
|
||||||
initparts(re);
|
initparts(re, TRUE);
|
||||||
|
|
||||||
if (re->result->exrhandle)
|
if (re->result->do_exr_tile)
|
||||||
render_result_exr_file_begin(re);
|
render_result_exr_file_begin(re);
|
||||||
|
|
||||||
BLI_init_threads(&threads, do_part_thread, re->r.threads);
|
BLI_init_threads(&threads, do_part_thread, re->r.threads);
|
||||||
@@ -891,7 +891,7 @@ static void threaded_tile_processor(Render *re)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (re->result->exrhandle) {
|
if (re->result->do_exr_tile) {
|
||||||
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
||||||
render_result_exr_file_end(re);
|
render_result_exr_file_end(re);
|
||||||
BLI_rw_mutex_unlock(&re->resultmutex);
|
BLI_rw_mutex_unlock(&re->resultmutex);
|
||||||
@@ -1044,7 +1044,7 @@ static void do_render_blur_3d(Render *re)
|
|||||||
int blur = re->r.mblur_samples;
|
int blur = re->r.mblur_samples;
|
||||||
|
|
||||||
/* create accumulation render result */
|
/* create accumulation render result */
|
||||||
rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM);
|
rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
|
||||||
|
|
||||||
/* do the blur steps */
|
/* do the blur steps */
|
||||||
while (blur--) {
|
while (blur--) {
|
||||||
@@ -1169,7 +1169,7 @@ static void do_render_fields_3d(Render *re)
|
|||||||
re->disprect.ymax *= 2;
|
re->disprect.ymax *= 2;
|
||||||
|
|
||||||
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
||||||
re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM);
|
re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
|
||||||
|
|
||||||
if (rr2) {
|
if (rr2) {
|
||||||
if (re->r.mode & R_ODDFIELD)
|
if (re->r.mode & R_ODDFIELD)
|
||||||
@@ -1232,7 +1232,7 @@ static void do_render_fields_blur_3d(Render *re)
|
|||||||
re->rectx = re->winx;
|
re->rectx = re->winx;
|
||||||
re->recty = re->winy;
|
re->recty = re->winy;
|
||||||
|
|
||||||
rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM);
|
rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
|
||||||
|
|
||||||
render_result_merge(rres, re->result);
|
render_result_merge(rres, re->result);
|
||||||
render_result_free(re->result);
|
render_result_free(re->result);
|
||||||
@@ -1552,7 +1552,7 @@ static void do_render_composite_fields_blur_3d(Render *re)
|
|||||||
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
||||||
|
|
||||||
render_result_free(re->result);
|
render_result_free(re->result);
|
||||||
re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM);
|
re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
|
||||||
|
|
||||||
BLI_rw_mutex_unlock(&re->resultmutex);
|
BLI_rw_mutex_unlock(&re->resultmutex);
|
||||||
|
|
||||||
@@ -1847,7 +1847,7 @@ int RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *r
|
|||||||
if (scene->r.scemode & (R_EXR_TILE_FILE | R_FULL_SAMPLE)) {
|
if (scene->r.scemode & (R_EXR_TILE_FILE | R_FULL_SAMPLE)) {
|
||||||
char str[FILE_MAX];
|
char str[FILE_MAX];
|
||||||
|
|
||||||
render_result_exr_file_path(scene, 0, str);
|
render_result_exr_file_path(scene, "", 0, str);
|
||||||
|
|
||||||
if (BLI_file_is_writable(str) == 0) {
|
if (BLI_file_is_writable(str) == 0) {
|
||||||
BKE_report(reports, RPT_ERROR, "Can not save render buffers, check the temp default path");
|
BKE_report(reports, RPT_ERROR, "Can not save render buffers, check the temp default path");
|
||||||
@@ -1931,7 +1931,7 @@ static void validate_render_settings(Render *re)
|
|||||||
|
|
||||||
if (RE_engine_is_external(re)) {
|
if (RE_engine_is_external(re)) {
|
||||||
/* not supported yet */
|
/* not supported yet */
|
||||||
re->r.scemode &= ~(R_EXR_TILE_FILE | R_FULL_SAMPLE);
|
re->r.scemode &= ~(R_FULL_SAMPLE);
|
||||||
re->r.mode &= ~(R_FIELDS | R_MBLUR);
|
re->r.mode &= ~(R_FIELDS | R_MBLUR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2421,7 +2421,7 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char
|
|||||||
|
|
||||||
void RE_result_load_from_file(RenderResult *result, ReportList *reports, const char *filename)
|
void RE_result_load_from_file(RenderResult *result, ReportList *reports, const char *filename)
|
||||||
{
|
{
|
||||||
if (!render_result_exr_file_read_path(result, filename)) {
|
if (!render_result_exr_file_read_path(result, NULL, filename)) {
|
||||||
BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to load '%s'\n", filename);
|
BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to load '%s'\n", filename);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -384,10 +384,10 @@ static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channel
|
|||||||
rpass->recty = rl->recty;
|
rpass->recty = rl->recty;
|
||||||
BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name));
|
BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name));
|
||||||
|
|
||||||
if (rr->exrhandle) {
|
if (rl->exrhandle) {
|
||||||
int a;
|
int a;
|
||||||
for (a = 0; a < channels; a++)
|
for (a = 0; a < channels; a++)
|
||||||
IMB_exr_add_channel(rr->exrhandle, rl->name, get_pass_name(passtype, a), 0, 0, NULL);
|
IMB_exr_add_channel(rl->exrhandle, rl->name, get_pass_name(passtype, a), 0, 0, NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
float *rect;
|
float *rect;
|
||||||
@@ -413,7 +413,7 @@ static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channel
|
|||||||
/* will read info from Render *re to define layers */
|
/* will read info from Render *re to define layers */
|
||||||
/* called in threads */
|
/* called in threads */
|
||||||
/* re->winx,winy is coordinate space of entire image, partrct the part within */
|
/* re->winx,winy is coordinate space of entire image, partrct the part within */
|
||||||
RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuffers)
|
RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuffers, const char *layername)
|
||||||
{
|
{
|
||||||
RenderResult *rr;
|
RenderResult *rr;
|
||||||
RenderLayer *rl;
|
RenderLayer *rl;
|
||||||
@@ -435,17 +435,21 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
|
|||||||
|
|
||||||
/* tilerect is relative coordinates within render disprect. do not subtract crop yet */
|
/* tilerect is relative coordinates within render disprect. do not subtract crop yet */
|
||||||
rr->tilerect.xmin = partrct->xmin - re->disprect.xmin;
|
rr->tilerect.xmin = partrct->xmin - re->disprect.xmin;
|
||||||
rr->tilerect.xmax = partrct->xmax - re->disprect.xmax;
|
rr->tilerect.xmax = partrct->xmax - re->disprect.xmin;
|
||||||
rr->tilerect.ymin = partrct->ymin - re->disprect.ymin;
|
rr->tilerect.ymin = partrct->ymin - re->disprect.ymin;
|
||||||
rr->tilerect.ymax = partrct->ymax - re->disprect.ymax;
|
rr->tilerect.ymax = partrct->ymax - re->disprect.ymin;
|
||||||
|
|
||||||
if (savebuffers) {
|
if (savebuffers) {
|
||||||
rr->exrhandle = IMB_exr_get_handle();
|
rr->do_exr_tile = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check renderdata for amount of layers */
|
/* check renderdata for amount of layers */
|
||||||
for (nr = 0, srl = re->r.layers.first; srl; srl = srl->next, nr++) {
|
for (nr = 0, srl = re->r.layers.first; srl; srl = srl->next, nr++) {
|
||||||
|
|
||||||
|
if (layername && layername[0])
|
||||||
|
if (strcmp(srl->name, layername) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
if ((re->r.scemode & R_SINGLE_LAYER) && nr != re->r.actlay)
|
if ((re->r.scemode & R_SINGLE_LAYER) && nr != re->r.actlay)
|
||||||
continue;
|
continue;
|
||||||
if (srl->layflag & SCE_LAY_DISABLE)
|
if (srl->layflag & SCE_LAY_DISABLE)
|
||||||
@@ -466,11 +470,13 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
|
|||||||
rl->rectx = rectx;
|
rl->rectx = rectx;
|
||||||
rl->recty = recty;
|
rl->recty = recty;
|
||||||
|
|
||||||
if (rr->exrhandle) {
|
if (rr->do_exr_tile) {
|
||||||
IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
|
rl->exrhandle = IMB_exr_get_handle();
|
||||||
IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.G", 0, 0, NULL);
|
|
||||||
IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.B", 0, 0, NULL);
|
IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
|
||||||
IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.A", 0, 0, NULL);
|
IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.G", 0, 0, NULL);
|
||||||
|
IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.B", 0, 0, NULL);
|
||||||
|
IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.A", 0, 0, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba");
|
rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba");
|
||||||
@@ -532,7 +538,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
|
|||||||
|
|
||||||
}
|
}
|
||||||
/* sss, previewrender and envmap don't do layers, so we make a default one */
|
/* sss, previewrender and envmap don't do layers, so we make a default one */
|
||||||
if (rr->layers.first == NULL) {
|
if (rr->layers.first == NULL && !(layername && layername[0])) {
|
||||||
rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
|
rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
|
||||||
BLI_addtail(&rr->layers, rl);
|
BLI_addtail(&rr->layers, rl);
|
||||||
|
|
||||||
@@ -540,11 +546,13 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
|
|||||||
rl->recty = recty;
|
rl->recty = recty;
|
||||||
|
|
||||||
/* duplicate code... */
|
/* duplicate code... */
|
||||||
if (rr->exrhandle) {
|
if (rr->do_exr_tile) {
|
||||||
IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
|
rl->exrhandle = IMB_exr_get_handle();
|
||||||
IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.G", 0, 0, NULL);
|
|
||||||
IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.B", 0, 0, NULL);
|
IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
|
||||||
IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.A", 0, 0, NULL);
|
IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.G", 0, 0, NULL);
|
||||||
|
IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.B", 0, 0, NULL);
|
||||||
|
IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.A", 0, 0, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba");
|
rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba");
|
||||||
@@ -570,10 +578,10 @@ RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *part
|
|||||||
int a;
|
int a;
|
||||||
|
|
||||||
if (re->osa == 0)
|
if (re->osa == 0)
|
||||||
return render_result_new(re, partrct, crop, savebuffers);
|
return render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS);
|
||||||
|
|
||||||
for (a = 0; a < re->osa; a++) {
|
for (a = 0; a < re->osa; a++) {
|
||||||
RenderResult *rr = render_result_new(re, partrct, crop, savebuffers);
|
RenderResult *rr = render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS);
|
||||||
BLI_addtail(lb, rr);
|
BLI_addtail(lb, rr);
|
||||||
rr->sample_nr = a;
|
rr->sample_nr = a;
|
||||||
}
|
}
|
||||||
@@ -682,15 +690,18 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
|
|||||||
RenderLayer *rl, *rlp;
|
RenderLayer *rl, *rlp;
|
||||||
RenderPass *rpass, *rpassp;
|
RenderPass *rpass, *rpassp;
|
||||||
|
|
||||||
for (rl = rr->layers.first, rlp = rrpart->layers.first; rl && rlp; rl = rl->next, rlp = rlp->next) {
|
for (rl = rr->layers.first; rl; rl = rl->next) {
|
||||||
|
for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) {
|
||||||
/* combined */
|
if (strcmp(rlp->name, rl->name) == 0) {
|
||||||
if (rl->rectf && rlp->rectf)
|
/* combined */
|
||||||
do_merge_tile(rr, rrpart, rl->rectf, rlp->rectf, 4);
|
if (rl->rectf && rlp->rectf)
|
||||||
|
do_merge_tile(rr, rrpart, rl->rectf, rlp->rectf, 4);
|
||||||
/* passes are allocated in sync */
|
|
||||||
for (rpass = rl->passes.first, rpassp = rlp->passes.first; rpass && rpassp; rpass = rpass->next, rpassp = rpassp->next) {
|
/* passes are allocated in sync */
|
||||||
do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels);
|
for (rpass = rl->passes.first, rpassp = rlp->passes.first; rpass && rpassp; rpass = rpass->next, rpassp = rpassp->next) {
|
||||||
|
do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -827,13 +838,16 @@ void render_result_single_layer_end(Render *re)
|
|||||||
|
|
||||||
static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart)
|
static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart)
|
||||||
{
|
{
|
||||||
RenderLayer *rlp;
|
RenderLayer *rlp, *rl;
|
||||||
RenderPass *rpassp;
|
RenderPass *rpassp;
|
||||||
int offs, partx, party;
|
int offs, partx, party;
|
||||||
|
|
||||||
BLI_lock_thread(LOCK_IMAGE);
|
BLI_lock_thread(LOCK_IMAGE);
|
||||||
|
|
||||||
for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) {
|
for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) {
|
||||||
|
for (rl = rr->layers.first; rl; rl = rl->next)
|
||||||
|
if (strcmp(rl->name, rlp->name) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
if (rrpart->crop) { /* filters add pixel extra */
|
if (rrpart->crop) { /* filters add pixel extra */
|
||||||
offs = (rrpart->crop + rrpart->crop * rrpart->rectx);
|
offs = (rrpart->crop + rrpart->crop * rrpart->rectx);
|
||||||
@@ -846,7 +860,7 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart)
|
|||||||
if (rlp->rectf) {
|
if (rlp->rectf) {
|
||||||
int a, xstride = 4;
|
int a, xstride = 4;
|
||||||
for (a = 0; a < xstride; a++)
|
for (a = 0; a < xstride; a++)
|
||||||
IMB_exr_set_channel(rr->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a),
|
IMB_exr_set_channel(rl->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a),
|
||||||
xstride, xstride * rrpart->rectx, rlp->rectf + a + xstride * offs);
|
xstride, xstride * rrpart->rectx, rlp->rectf + a + xstride * offs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -854,7 +868,7 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart)
|
|||||||
for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) {
|
for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) {
|
||||||
int a, xstride = rpassp->channels;
|
int a, xstride = rpassp->channels;
|
||||||
for (a = 0; a < xstride; a++)
|
for (a = 0; a < xstride; a++)
|
||||||
IMB_exr_set_channel(rr->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a),
|
IMB_exr_set_channel(rl->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a),
|
||||||
xstride, xstride * rrpart->rectx, rpassp->rect + a + xstride * offs);
|
xstride, xstride * rrpart->rectx, rpassp->rect + a + xstride * offs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -862,7 +876,14 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart)
|
|||||||
|
|
||||||
party = rrpart->tilerect.ymin + rrpart->crop;
|
party = rrpart->tilerect.ymin + rrpart->crop;
|
||||||
partx = rrpart->tilerect.xmin + rrpart->crop;
|
partx = rrpart->tilerect.xmin + rrpart->crop;
|
||||||
IMB_exrtile_write_channels(rr->exrhandle, partx, party, 0);
|
|
||||||
|
for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) {
|
||||||
|
for (rl = rr->layers.first; rl; rl = rl->next)
|
||||||
|
if (strcmp(rl->name, rlp->name) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0);
|
||||||
|
}
|
||||||
|
|
||||||
BLI_unlock_thread(LOCK_IMAGE);
|
BLI_unlock_thread(LOCK_IMAGE);
|
||||||
}
|
}
|
||||||
@@ -871,15 +892,18 @@ static void save_empty_result_tiles(Render *re)
|
|||||||
{
|
{
|
||||||
RenderPart *pa;
|
RenderPart *pa;
|
||||||
RenderResult *rr;
|
RenderResult *rr;
|
||||||
|
RenderLayer *rl;
|
||||||
|
|
||||||
for (rr = re->result; rr; rr = rr->next) {
|
for (rr = re->result; rr; rr = rr->next) {
|
||||||
IMB_exrtile_clear_channels(rr->exrhandle);
|
for (rl = rr->layers.first; rl; rl = rl->next) {
|
||||||
|
IMB_exrtile_clear_channels(rl->exrhandle);
|
||||||
|
|
||||||
for (pa = re->parts.first; pa; pa = pa->next) {
|
for (pa = re->parts.first; pa; pa = pa->next) {
|
||||||
if (pa->ready == 0) {
|
if (pa->ready == 0) {
|
||||||
int party = pa->disprect.ymin - re->disprect.ymin + pa->crop;
|
int party = pa->disprect.ymin - re->disprect.ymin + pa->crop;
|
||||||
int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop;
|
int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop;
|
||||||
IMB_exrtile_write_channels(rr->exrhandle, partx, party, 0);
|
IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -889,13 +913,15 @@ static void save_empty_result_tiles(Render *re)
|
|||||||
void render_result_exr_file_begin(Render *re)
|
void render_result_exr_file_begin(Render *re)
|
||||||
{
|
{
|
||||||
RenderResult *rr;
|
RenderResult *rr;
|
||||||
|
RenderLayer *rl;
|
||||||
char str[FILE_MAX];
|
char str[FILE_MAX];
|
||||||
|
|
||||||
for (rr = re->result; rr; rr = rr->next) {
|
for (rr = re->result; rr; rr = rr->next) {
|
||||||
render_result_exr_file_path(re->scene, rr->sample_nr, str);
|
for (rl = rr->layers.first; rl; rl = rl->next) {
|
||||||
|
render_result_exr_file_path(re->scene, rl->name, rr->sample_nr, str);
|
||||||
printf("write exr tmp file, %dx%d, %s\n", rr->rectx, rr->recty, str);
|
printf("write exr tmp file, %dx%d, %s\n", rr->rectx, rr->recty, str);
|
||||||
IMB_exrtile_begin_write(rr->exrhandle, str, 0, rr->rectx, rr->recty, re->partx, re->party);
|
IMB_exrtile_begin_write(rl->exrhandle, str, 0, rr->rectx, rr->recty, re->partx, re->party);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -903,12 +929,17 @@ void render_result_exr_file_begin(Render *re)
|
|||||||
void render_result_exr_file_end(Render *re)
|
void render_result_exr_file_end(Render *re)
|
||||||
{
|
{
|
||||||
RenderResult *rr;
|
RenderResult *rr;
|
||||||
|
RenderLayer *rl;
|
||||||
|
|
||||||
save_empty_result_tiles(re);
|
save_empty_result_tiles(re);
|
||||||
|
|
||||||
for (rr = re->result; rr; rr = rr->next) {
|
for (rr = re->result; rr; rr = rr->next) {
|
||||||
IMB_exr_close(rr->exrhandle);
|
for (rl = rr->layers.first; rl; rl = rl->next) {
|
||||||
rr->exrhandle = NULL;
|
IMB_exr_close(rl->exrhandle);
|
||||||
|
rl->exrhandle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rr->do_exr_tile = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
render_result_free_list(&re->fullresult, re->result);
|
render_result_free_list(&re->fullresult, re->result);
|
||||||
@@ -925,17 +956,17 @@ void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* path to temporary exr file */
|
/* path to temporary exr file */
|
||||||
void render_result_exr_file_path(Scene *scene, int sample, char *filepath)
|
void render_result_exr_file_path(Scene *scene, const char *layname, int sample, char *filepath)
|
||||||
{
|
{
|
||||||
char di[FILE_MAX], name[FILE_MAXFILE + MAX_ID_NAME + 100], fi[FILE_MAXFILE];
|
char di[FILE_MAX], name[FILE_MAXFILE + MAX_ID_NAME + MAX_ID_NAME + 100], fi[FILE_MAXFILE];
|
||||||
|
|
||||||
BLI_strncpy(di, G.main->name, FILE_MAX);
|
BLI_strncpy(di, G.main->name, FILE_MAX);
|
||||||
BLI_splitdirstring(di, fi);
|
BLI_splitdirstring(di, fi);
|
||||||
|
|
||||||
if (sample == 0)
|
if (sample == 0)
|
||||||
BLI_snprintf(name, sizeof(name), "%s_%s.exr", fi, scene->id.name + 2);
|
BLI_snprintf(name, sizeof(name), "%s_%s_%s.exr", fi, scene->id.name + 2, layname);
|
||||||
else
|
else
|
||||||
BLI_snprintf(name, sizeof(name), "%s_%s%d.exr", fi, scene->id.name + 2, sample);
|
BLI_snprintf(name, sizeof(name), "%s_%s_%s%d.exr", fi, scene->id.name + 2, layname, sample);
|
||||||
|
|
||||||
BLI_make_file_string("/", filepath, BLI_temporary_dir(), name);
|
BLI_make_file_string("/", filepath, BLI_temporary_dir(), name);
|
||||||
}
|
}
|
||||||
@@ -943,29 +974,30 @@ void render_result_exr_file_path(Scene *scene, int sample, char *filepath)
|
|||||||
/* only for temp buffer files, makes exact copy of render result */
|
/* only for temp buffer files, makes exact copy of render result */
|
||||||
int render_result_exr_file_read(Render *re, int sample)
|
int render_result_exr_file_read(Render *re, int sample)
|
||||||
{
|
{
|
||||||
|
RenderLayer *rl;
|
||||||
char str[FILE_MAX];
|
char str[FILE_MAX];
|
||||||
int success;
|
int success = TRUE;
|
||||||
|
|
||||||
RE_FreeRenderResult(re->result);
|
RE_FreeRenderResult(re->result);
|
||||||
re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM);
|
re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
|
||||||
|
|
||||||
render_result_exr_file_path(re->scene, sample, str);
|
for (rl = re->result->layers.first; rl; rl = rl->next) {
|
||||||
printf("read exr tmp file: %s\n", str);
|
|
||||||
|
|
||||||
if (render_result_exr_file_read_path(re->result, str)) {
|
render_result_exr_file_path(re->scene, rl->name, sample, str);
|
||||||
success = TRUE;
|
printf("read exr tmp file: %s\n", str);
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("cannot read: %s\n", str);
|
|
||||||
success = FALSE;
|
|
||||||
|
|
||||||
|
if (!render_result_exr_file_read_path(re->result, rl, str)) {
|
||||||
|
printf("cannot read: %s\n", str);
|
||||||
|
success = FALSE;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called for reading temp files, and for external engines */
|
/* called for reading temp files, and for external engines */
|
||||||
int render_result_exr_file_read_path(RenderResult *rr, const char *filepath)
|
int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, const char *filepath)
|
||||||
{
|
{
|
||||||
RenderLayer *rl;
|
RenderLayer *rl;
|
||||||
RenderPass *rpass;
|
RenderPass *rpass;
|
||||||
@@ -988,6 +1020,9 @@ int render_result_exr_file_read_path(RenderResult *rr, const char *filepath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (rl = rr->layers.first; rl; rl = rl->next) {
|
for (rl = rr->layers.first; rl; rl = rl->next) {
|
||||||
|
if (rl_single && rl_single != rl)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* combined */
|
/* combined */
|
||||||
if (rl->rectf) {
|
if (rl->rectf) {
|
||||||
int a, xstride = 4;
|
int a, xstride = 4;
|
||||||
|
|||||||
Reference in New Issue
Block a user