2014-01-02 21:05:07 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2011-2014 Blender Foundation
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "bake.h"
|
2014-06-06 12:40:09 +00:00
|
|
|
#include "integrator.h"
|
2014-01-02 21:05:07 +00:00
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
2014-07-28 17:29:03 +00:00
|
|
|
BakeData::BakeData(const int object, const size_t tri_offset, const size_t num_pixels):
|
2014-01-02 21:05:07 +00:00
|
|
|
m_object(object),
|
|
|
|
m_tri_offset(tri_offset),
|
|
|
|
m_num_pixels(num_pixels)
|
|
|
|
{
|
|
|
|
m_primitive.resize(num_pixels);
|
|
|
|
m_u.resize(num_pixels);
|
|
|
|
m_v.resize(num_pixels);
|
2014-05-07 20:26:24 +00:00
|
|
|
m_dudx.resize(num_pixels);
|
|
|
|
m_dudy.resize(num_pixels);
|
|
|
|
m_dvdx.resize(num_pixels);
|
|
|
|
m_dvdy.resize(num_pixels);
|
2014-01-02 21:05:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BakeData::~BakeData()
|
|
|
|
{
|
|
|
|
m_primitive.clear();
|
|
|
|
m_u.clear();
|
|
|
|
m_v.clear();
|
2014-05-07 20:26:24 +00:00
|
|
|
m_dudx.clear();
|
|
|
|
m_dudy.clear();
|
|
|
|
m_dvdx.clear();
|
|
|
|
m_dvdy.clear();
|
2014-01-02 21:05:07 +00:00
|
|
|
}
|
|
|
|
|
2014-05-07 20:26:24 +00:00
|
|
|
void BakeData::set(int i, int prim, float uv[2], float dudx, float dudy, float dvdx, float dvdy)
|
2014-01-02 21:05:07 +00:00
|
|
|
{
|
|
|
|
m_primitive[i] = (prim == -1 ? -1 : m_tri_offset + prim);
|
|
|
|
m_u[i] = uv[0];
|
|
|
|
m_v[i] = uv[1];
|
2014-05-07 20:26:24 +00:00
|
|
|
m_dudx[i] = dudx;
|
|
|
|
m_dudy[i] = dudy;
|
|
|
|
m_dvdx[i] = dvdx;
|
|
|
|
m_dvdy[i] = dvdy;
|
2014-01-02 21:05:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int BakeData::object()
|
|
|
|
{
|
|
|
|
return m_object;
|
|
|
|
}
|
|
|
|
|
2014-07-28 17:29:03 +00:00
|
|
|
size_t BakeData::size()
|
2014-01-02 21:05:07 +00:00
|
|
|
{
|
|
|
|
return m_num_pixels;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BakeData::is_valid(int i)
|
|
|
|
{
|
|
|
|
return m_primitive[i] != -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint4 BakeData::data(int i)
|
|
|
|
{
|
|
|
|
return make_uint4(
|
|
|
|
m_object,
|
|
|
|
m_primitive[i],
|
|
|
|
__float_as_int(m_u[i]),
|
|
|
|
__float_as_int(m_v[i])
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-05-07 20:26:24 +00:00
|
|
|
uint4 BakeData::differentials(int i)
|
|
|
|
{
|
|
|
|
return make_uint4(
|
|
|
|
__float_as_int(m_dudx[i]),
|
|
|
|
__float_as_int(m_dudy[i]),
|
|
|
|
__float_as_int(m_dvdx[i]),
|
|
|
|
__float_as_int(m_dvdy[i])
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-01-02 21:05:07 +00:00
|
|
|
BakeManager::BakeManager()
|
|
|
|
{
|
|
|
|
m_bake_data = NULL;
|
|
|
|
m_is_baking = false;
|
|
|
|
need_update = true;
|
2014-07-31 23:04:57 +00:00
|
|
|
m_shader_limit = 512 * 512;
|
2014-01-02 21:05:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BakeManager::~BakeManager()
|
|
|
|
{
|
|
|
|
if(m_bake_data)
|
|
|
|
delete m_bake_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BakeManager::get_baking()
|
|
|
|
{
|
|
|
|
return m_is_baking;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BakeManager::set_baking(const bool value)
|
|
|
|
{
|
|
|
|
m_is_baking = value;
|
|
|
|
}
|
|
|
|
|
2014-07-28 17:29:03 +00:00
|
|
|
BakeData *BakeManager::init(const int object, const size_t tri_offset, const size_t num_pixels)
|
2014-01-02 21:05:07 +00:00
|
|
|
{
|
|
|
|
m_bake_data = new BakeData(object, tri_offset, num_pixels);
|
|
|
|
return m_bake_data;
|
|
|
|
}
|
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
void BakeManager::set_shader_limit(const size_t x, const size_t y)
|
|
|
|
{
|
|
|
|
m_shader_limit = x * y;
|
2014-08-15 13:44:50 +00:00
|
|
|
m_shader_limit = (size_t)pow(2, ceil(log(m_shader_limit)/log(2)));
|
2014-07-31 23:04:57 +00:00
|
|
|
}
|
|
|
|
|
2014-01-02 21:05:07 +00:00
|
|
|
bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress, ShaderEvalType shader_type, BakeData *bake_data, float result[])
|
|
|
|
{
|
2014-07-31 23:04:57 +00:00
|
|
|
size_t num_pixels = bake_data->size();
|
2014-01-02 21:05:07 +00:00
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
progress.reset_sample();
|
|
|
|
this->num_parts = 0;
|
2014-01-02 21:05:07 +00:00
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
/* calculate the total parts for the progress bar */
|
|
|
|
for(size_t shader_offset = 0; shader_offset < num_pixels; shader_offset += m_shader_limit) {
|
2014-08-15 13:44:50 +00:00
|
|
|
size_t shader_size = (size_t)fminf(num_pixels - shader_offset, m_shader_limit);
|
2014-01-02 21:05:07 +00:00
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
DeviceTask task(DeviceTask::SHADER);
|
|
|
|
task.shader_w = shader_size;
|
2014-01-02 21:05:07 +00:00
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
this->num_parts += device->get_split_task_count(task);
|
|
|
|
}
|
2014-01-02 21:05:07 +00:00
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
this->num_samples = is_aa_pass(shader_type)? scene->integrator->aa_samples : 1;
|
2014-01-02 21:05:07 +00:00
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
for(size_t shader_offset = 0; shader_offset < num_pixels; shader_offset += m_shader_limit) {
|
2014-08-15 13:44:50 +00:00
|
|
|
size_t shader_size = (size_t)fminf(num_pixels - shader_offset, m_shader_limit);
|
2014-01-02 21:05:07 +00:00
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
/* setup input for device task */
|
|
|
|
device_vector<uint4> d_input;
|
|
|
|
uint4 *d_input_data = d_input.resize(shader_size * 2);
|
|
|
|
size_t d_input_size = 0;
|
2014-07-22 21:41:01 +00:00
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
for(size_t i = shader_offset; i < (shader_offset + shader_size); i++) {
|
|
|
|
d_input_data[d_input_size++] = bake_data->data(i);
|
|
|
|
d_input_data[d_input_size++] = bake_data->differentials(i);
|
|
|
|
}
|
2014-01-02 21:05:07 +00:00
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
if(d_input_size == 0) {
|
|
|
|
m_is_baking = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* run device task */
|
|
|
|
device_vector<float4> d_output;
|
|
|
|
d_output.resize(shader_size);
|
|
|
|
|
|
|
|
/* needs to be up to data for attribute access */
|
|
|
|
device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
|
|
|
|
|
|
|
|
device->mem_alloc(d_input, MEM_READ_ONLY);
|
|
|
|
device->mem_copy_to(d_input);
|
|
|
|
device->mem_alloc(d_output, MEM_WRITE_ONLY);
|
|
|
|
|
|
|
|
DeviceTask task(DeviceTask::SHADER);
|
|
|
|
task.shader_input = d_input.device_pointer;
|
|
|
|
task.shader_output = d_output.device_pointer;
|
|
|
|
task.shader_eval_type = shader_type;
|
|
|
|
task.shader_x = 0;
|
2014-08-19 09:39:40 +00:00
|
|
|
task.offset = shader_offset;
|
2014-07-31 23:04:57 +00:00
|
|
|
task.shader_w = d_output.size();
|
|
|
|
task.num_samples = this->num_samples;
|
|
|
|
task.get_cancel = function_bind(&Progress::get_cancel, &progress);
|
|
|
|
task.update_progress_sample = function_bind(&Progress::increment_sample_update, &progress);
|
|
|
|
|
|
|
|
device->task_add(task);
|
|
|
|
device->task_wait();
|
|
|
|
|
|
|
|
if(progress.get_cancel()) {
|
|
|
|
device->mem_free(d_input);
|
|
|
|
device->mem_free(d_output);
|
|
|
|
m_is_baking = false;
|
|
|
|
return false;
|
|
|
|
}
|
2014-01-02 21:05:07 +00:00
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
device->mem_copy_from(d_output, 0, 1, d_output.size(), sizeof(float4));
|
2014-01-02 21:05:07 +00:00
|
|
|
device->mem_free(d_input);
|
|
|
|
device->mem_free(d_output);
|
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
/* read result */
|
|
|
|
int k = 0;
|
2014-01-02 21:05:07 +00:00
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
float4 *offset = (float4*)d_output.data_pointer;
|
2014-01-02 21:05:07 +00:00
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
size_t depth = 4;
|
|
|
|
for(size_t i=shader_offset; i < (shader_offset + shader_size); i++) {
|
|
|
|
size_t index = i * depth;
|
|
|
|
float4 out = offset[k++];
|
2014-01-02 21:05:07 +00:00
|
|
|
|
2014-07-31 23:04:57 +00:00
|
|
|
if(bake_data->is_valid(i)) {
|
|
|
|
for(size_t j=0; j < 4; j++) {
|
|
|
|
result[index + j] = out[j];
|
|
|
|
}
|
2014-01-02 21:05:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_is_baking = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BakeManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
|
|
|
|
{
|
|
|
|
if(!need_update)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(progress.get_cancel()) return;
|
|
|
|
|
|
|
|
need_update = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BakeManager::device_free(Device *device, DeviceScene *dscene)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-06-06 12:40:09 +00:00
|
|
|
bool BakeManager::is_aa_pass(ShaderEvalType type)
|
|
|
|
{
|
|
|
|
switch(type) {
|
|
|
|
case SHADER_EVAL_UV:
|
|
|
|
case SHADER_EVAL_NORMAL:
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BakeManager::is_light_pass(ShaderEvalType type)
|
|
|
|
{
|
|
|
|
switch(type) {
|
|
|
|
case SHADER_EVAL_AO:
|
|
|
|
case SHADER_EVAL_COMBINED:
|
|
|
|
case SHADER_EVAL_SHADOW:
|
|
|
|
case SHADER_EVAL_DIFFUSE_DIRECT:
|
|
|
|
case SHADER_EVAL_GLOSSY_DIRECT:
|
|
|
|
case SHADER_EVAL_TRANSMISSION_DIRECT:
|
|
|
|
case SHADER_EVAL_SUBSURFACE_DIRECT:
|
|
|
|
case SHADER_EVAL_DIFFUSE_INDIRECT:
|
|
|
|
case SHADER_EVAL_GLOSSY_INDIRECT:
|
|
|
|
case SHADER_EVAL_TRANSMISSION_INDIRECT:
|
|
|
|
case SHADER_EVAL_SUBSURFACE_INDIRECT:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-02 21:05:07 +00:00
|
|
|
CCL_NAMESPACE_END
|