Merge branch 'master' into blender2.8

This commit is contained in:
2017-09-28 03:05:46 +10:00
27 changed files with 2193 additions and 999 deletions

View File

@@ -111,6 +111,16 @@ public:
virtual int2 split_kernel_global_size(device_memory& kg, device_memory& data, DeviceTask *task); virtual int2 split_kernel_global_size(device_memory& kg, device_memory& data, DeviceTask *task);
}; };
/* Utility to push/pop CUDA context. */
class CUDAContextScope {
public:
CUDAContextScope(CUDADevice *device);
~CUDAContextScope();
private:
CUDADevice *device;
};
class CUDADevice : public Device class CUDADevice : public Device
{ {
public: public:
@@ -206,16 +216,6 @@ public:
cuda_error_documentation(); cuda_error_documentation();
} }
void cuda_push_context()
{
cuda_assert(cuCtxSetCurrent(cuContext));
}
void cuda_pop_context()
{
cuda_assert(cuCtxSetCurrent(NULL));
}
CUDADevice(DeviceInfo& info, Stats &stats, bool background_) CUDADevice(DeviceInfo& info, Stats &stats, bool background_)
: Device(info, stats, background_) : Device(info, stats, background_)
{ {
@@ -263,7 +263,8 @@ public:
cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevId); cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevId);
cuDevArchitecture = major*100 + minor*10; cuDevArchitecture = major*100 + minor*10;
cuda_pop_context(); /* Pop context set by cuCtxCreate. */
cuCtxPopCurrent(NULL);
} }
~CUDADevice() ~CUDADevice()
@@ -519,7 +520,7 @@ public:
return false; return false;
/* open module */ /* open module */
cuda_push_context(); CUDAContextScope scope(this);
string cubin_data; string cubin_data;
CUresult result; CUresult result;
@@ -540,8 +541,6 @@ public:
if(cuda_error_(result, "cuModuleLoad")) if(cuda_error_(result, "cuModuleLoad"))
cuda_error_message(string_printf("Failed loading CUDA kernel %s.", filter_cubin.c_str())); cuda_error_message(string_printf("Failed loading CUDA kernel %s.", filter_cubin.c_str()));
cuda_pop_context();
return (result == CUDA_SUCCESS); return (result == CUDA_SUCCESS);
} }
@@ -556,36 +555,36 @@ public:
void mem_alloc(const char *name, device_memory& mem, MemoryType /*type*/) void mem_alloc(const char *name, device_memory& mem, MemoryType /*type*/)
{ {
CUDAContextScope scope(this);
if(name) { if(name) {
VLOG(1) << "Buffer allocate: " << name << ", " VLOG(1) << "Buffer allocate: " << name << ", "
<< string_human_readable_number(mem.memory_size()) << " bytes. (" << string_human_readable_number(mem.memory_size()) << " bytes. ("
<< string_human_readable_size(mem.memory_size()) << ")"; << string_human_readable_size(mem.memory_size()) << ")";
} }
cuda_push_context();
CUdeviceptr device_pointer; CUdeviceptr device_pointer;
size_t size = mem.memory_size(); size_t size = mem.memory_size();
cuda_assert(cuMemAlloc(&device_pointer, size)); cuda_assert(cuMemAlloc(&device_pointer, size));
mem.device_pointer = (device_ptr)device_pointer; mem.device_pointer = (device_ptr)device_pointer;
mem.device_size = size; mem.device_size = size;
stats.mem_alloc(size); stats.mem_alloc(size);
cuda_pop_context();
} }
void mem_copy_to(device_memory& mem) void mem_copy_to(device_memory& mem)
{ {
cuda_push_context(); CUDAContextScope scope(this);
if(mem.device_pointer) if(mem.device_pointer)
cuda_assert(cuMemcpyHtoD(cuda_device_ptr(mem.device_pointer), (void*)mem.data_pointer, mem.memory_size())); cuda_assert(cuMemcpyHtoD(cuda_device_ptr(mem.device_pointer), (void*)mem.data_pointer, mem.memory_size()));
cuda_pop_context();
} }
void mem_copy_from(device_memory& mem, int y, int w, int h, int elem) void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
{ {
CUDAContextScope scope(this);
size_t offset = elem*y*w; size_t offset = elem*y*w;
size_t size = elem*w*h; size_t size = elem*w*h;
cuda_push_context();
if(mem.device_pointer) { if(mem.device_pointer) {
cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset, cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset,
(CUdeviceptr)(mem.device_pointer + offset), size)); (CUdeviceptr)(mem.device_pointer + offset), size));
@@ -593,7 +592,6 @@ public:
else { else {
memset((char*)mem.data_pointer + offset, 0, size); memset((char*)mem.data_pointer + offset, 0, size);
} }
cuda_pop_context();
} }
void mem_zero(device_memory& mem) void mem_zero(device_memory& mem)
@@ -602,18 +600,17 @@ public:
memset((void*)mem.data_pointer, 0, mem.memory_size()); memset((void*)mem.data_pointer, 0, mem.memory_size());
} }
cuda_push_context(); if(mem.device_pointer) {
if(mem.device_pointer) CUDAContextScope scope(this);
cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size())); cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size()));
cuda_pop_context(); }
} }
void mem_free(device_memory& mem) void mem_free(device_memory& mem)
{ {
if(mem.device_pointer) { if(mem.device_pointer) {
cuda_push_context(); CUDAContextScope scope(this);
cuda_assert(cuMemFree(cuda_device_ptr(mem.device_pointer))); cuda_assert(cuMemFree(cuda_device_ptr(mem.device_pointer)));
cuda_pop_context();
mem.device_pointer = 0; mem.device_pointer = 0;
@@ -629,14 +626,13 @@ public:
void const_copy_to(const char *name, void *host, size_t size) void const_copy_to(const char *name, void *host, size_t size)
{ {
CUDAContextScope scope(this);
CUdeviceptr mem; CUdeviceptr mem;
size_t bytes; size_t bytes;
cuda_push_context();
cuda_assert(cuModuleGetGlobal(&mem, &bytes, cuModule, name)); cuda_assert(cuModuleGetGlobal(&mem, &bytes, cuModule, name));
//assert(bytes == size); //assert(bytes == size);
cuda_assert(cuMemcpyHtoD(mem, host, size)); cuda_assert(cuMemcpyHtoD(mem, host, size));
cuda_pop_context();
} }
void tex_alloc(const char *name, void tex_alloc(const char *name,
@@ -644,6 +640,8 @@ public:
InterpolationType interpolation, InterpolationType interpolation,
ExtensionType extension) ExtensionType extension)
{ {
CUDAContextScope scope(this);
VLOG(1) << "Texture allocate: " << name << ", " VLOG(1) << "Texture allocate: " << name << ", "
<< string_human_readable_number(mem.memory_size()) << " bytes. (" << string_human_readable_number(mem.memory_size()) << " bytes. ("
<< string_human_readable_size(mem.memory_size()) << ")"; << string_human_readable_size(mem.memory_size()) << ")";
@@ -706,9 +704,7 @@ public:
tokens[3].c_str()); tokens[3].c_str());
} }
cuda_push_context();
cuda_assert(cuModuleGetTexRef(&texref, cuModule, bind_name.c_str())); cuda_assert(cuModuleGetTexRef(&texref, cuModule, bind_name.c_str()));
cuda_pop_context();
if(!texref) { if(!texref) {
return; return;
@@ -721,8 +717,6 @@ public:
mem_alloc(NULL, mem, MEM_READ_ONLY); mem_alloc(NULL, mem, MEM_READ_ONLY);
mem_copy_to(mem); mem_copy_to(mem);
cuda_push_context();
CUdeviceptr cumem; CUdeviceptr cumem;
size_t cubytes; size_t cubytes;
@@ -738,28 +732,20 @@ public:
uint32_t ptr = (uint32_t)mem.device_pointer; uint32_t ptr = (uint32_t)mem.device_pointer;
cuda_assert(cuMemcpyHtoD(cumem, (void*)&ptr, cubytes)); cuda_assert(cuMemcpyHtoD(cumem, (void*)&ptr, cubytes));
} }
cuda_pop_context();
} }
else { else {
mem_alloc(NULL, mem, MEM_READ_ONLY); mem_alloc(NULL, mem, MEM_READ_ONLY);
mem_copy_to(mem); mem_copy_to(mem);
cuda_push_context();
cuda_assert(cuTexRefSetAddress(NULL, texref, cuda_device_ptr(mem.device_pointer), size)); cuda_assert(cuTexRefSetAddress(NULL, texref, cuda_device_ptr(mem.device_pointer), size));
cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_POINT)); cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_POINT));
cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_READ_AS_INTEGER)); cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_READ_AS_INTEGER));
cuda_pop_context();
} }
} }
/* Texture Storage */ /* Texture Storage */
else { else {
CUarray handle = NULL; CUarray handle = NULL;
cuda_push_context();
if(mem.data_depth > 1) { if(mem.data_depth > 1) {
CUDA_ARRAY3D_DESCRIPTOR desc; CUDA_ARRAY3D_DESCRIPTOR desc;
@@ -784,7 +770,6 @@ public:
} }
if(!handle) { if(!handle) {
cuda_pop_context();
return; return;
} }
@@ -877,14 +862,10 @@ public:
cuda_assert(cuTexRefSetFilterMode(texref, filter_mode)); cuda_assert(cuTexRefSetFilterMode(texref, filter_mode));
cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_NORMALIZED_COORDINATES)); cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_NORMALIZED_COORDINATES));
} }
cuda_pop_context();
} }
/* Fermi, Data and Image Textures */ /* Fermi, Data and Image Textures */
if(!has_bindless_textures) { if(!has_bindless_textures) {
cuda_push_context();
cuda_assert(cuTexRefSetAddressMode(texref, 0, address_mode)); cuda_assert(cuTexRefSetAddressMode(texref, 0, address_mode));
cuda_assert(cuTexRefSetAddressMode(texref, 1, address_mode)); cuda_assert(cuTexRefSetAddressMode(texref, 1, address_mode));
if(mem.data_depth > 1) { if(mem.data_depth > 1) {
@@ -892,8 +873,6 @@ public:
} }
cuda_assert(cuTexRefSetFormat(texref, format, mem.data_elements)); cuda_assert(cuTexRefSetFormat(texref, format, mem.data_elements));
cuda_pop_context();
} }
/* Fermi and Kepler */ /* Fermi and Kepler */
@@ -904,9 +883,8 @@ public:
{ {
if(mem.device_pointer) { if(mem.device_pointer) {
if(tex_interp_map[mem.device_pointer]) { if(tex_interp_map[mem.device_pointer]) {
cuda_push_context(); CUDAContextScope scope(this);
cuArrayDestroy((CUarray)mem.device_pointer); cuArrayDestroy((CUarray)mem.device_pointer);
cuda_pop_context();
/* Free CUtexObject (Bindless Textures) */ /* Free CUtexObject (Bindless Textures) */
if(info.has_bindless_textures && tex_bindless_map[mem.device_pointer]) { if(info.has_bindless_textures && tex_bindless_map[mem.device_pointer]) {
@@ -960,7 +938,7 @@ public:
if(have_error()) if(have_error())
return false; return false;
cuda_push_context(); CUDAContextScope scope(this);
int4 rect = task->rect; int4 rect = task->rect;
int w = align_up(rect.z-rect.x, 4); int w = align_up(rect.z-rect.x, 4);
@@ -1017,7 +995,6 @@ public:
CUDA_LAUNCH_KERNEL(cuNLMNormalize, normalize_args); CUDA_LAUNCH_KERNEL(cuNLMNormalize, normalize_args);
cuda_assert(cuCtxSynchronize()); cuda_assert(cuCtxSynchronize());
cuda_pop_context();
return !have_error(); return !have_error();
} }
@@ -1026,7 +1003,7 @@ public:
if(have_error()) if(have_error())
return false; return false;
cuda_push_context(); CUDAContextScope scope(this);
CUfunction cuFilterConstructTransform; CUfunction cuFilterConstructTransform;
cuda_assert(cuModuleGetFunction(&cuFilterConstructTransform, cuFilterModule, "kernel_cuda_filter_construct_transform")); cuda_assert(cuModuleGetFunction(&cuFilterConstructTransform, cuFilterModule, "kernel_cuda_filter_construct_transform"));
@@ -1046,7 +1023,6 @@ public:
CUDA_LAUNCH_KERNEL(cuFilterConstructTransform, args); CUDA_LAUNCH_KERNEL(cuFilterConstructTransform, args);
cuda_assert(cuCtxSynchronize()); cuda_assert(cuCtxSynchronize());
cuda_pop_context();
return !have_error(); return !have_error();
} }
@@ -1058,11 +1034,11 @@ public:
if(have_error()) if(have_error())
return false; return false;
CUDAContextScope scope(this);
mem_zero(task->storage.XtWX); mem_zero(task->storage.XtWX);
mem_zero(task->storage.XtWY); mem_zero(task->storage.XtWY);
cuda_push_context();
CUfunction cuNLMCalcDifference, cuNLMBlur, cuNLMCalcWeight, cuNLMConstructGramian, cuFinalize; CUfunction cuNLMCalcDifference, cuNLMBlur, cuNLMCalcWeight, cuNLMConstructGramian, cuFinalize;
cuda_assert(cuModuleGetFunction(&cuNLMCalcDifference, cuFilterModule, "kernel_cuda_filter_nlm_calc_difference")); cuda_assert(cuModuleGetFunction(&cuNLMCalcDifference, cuFilterModule, "kernel_cuda_filter_nlm_calc_difference"));
cuda_assert(cuModuleGetFunction(&cuNLMBlur, cuFilterModule, "kernel_cuda_filter_nlm_blur")); cuda_assert(cuModuleGetFunction(&cuNLMBlur, cuFilterModule, "kernel_cuda_filter_nlm_blur"));
@@ -1150,7 +1126,6 @@ public:
CUDA_LAUNCH_KERNEL(cuFinalize, finalize_args); CUDA_LAUNCH_KERNEL(cuFinalize, finalize_args);
cuda_assert(cuCtxSynchronize()); cuda_assert(cuCtxSynchronize());
cuda_pop_context();
return !have_error(); return !have_error();
} }
@@ -1161,7 +1136,7 @@ public:
if(have_error()) if(have_error())
return false; return false;
cuda_push_context(); CUDAContextScope scope(this);
CUfunction cuFilterCombineHalves; CUfunction cuFilterCombineHalves;
cuda_assert(cuModuleGetFunction(&cuFilterCombineHalves, cuFilterModule, "kernel_cuda_filter_combine_halves")); cuda_assert(cuModuleGetFunction(&cuFilterCombineHalves, cuFilterModule, "kernel_cuda_filter_combine_halves"));
@@ -1179,7 +1154,6 @@ public:
CUDA_LAUNCH_KERNEL(cuFilterCombineHalves, args); CUDA_LAUNCH_KERNEL(cuFilterCombineHalves, args);
cuda_assert(cuCtxSynchronize()); cuda_assert(cuCtxSynchronize());
cuda_pop_context();
return !have_error(); return !have_error();
} }
@@ -1190,7 +1164,7 @@ public:
if(have_error()) if(have_error())
return false; return false;
cuda_push_context(); CUDAContextScope scope(this);
CUfunction cuFilterDivideShadow; CUfunction cuFilterDivideShadow;
cuda_assert(cuModuleGetFunction(&cuFilterDivideShadow, cuFilterModule, "kernel_cuda_filter_divide_shadow")); cuda_assert(cuModuleGetFunction(&cuFilterDivideShadow, cuFilterModule, "kernel_cuda_filter_divide_shadow"));
@@ -1214,7 +1188,6 @@ public:
CUDA_LAUNCH_KERNEL(cuFilterDivideShadow, args); CUDA_LAUNCH_KERNEL(cuFilterDivideShadow, args);
cuda_assert(cuCtxSynchronize()); cuda_assert(cuCtxSynchronize());
cuda_pop_context();
return !have_error(); return !have_error();
} }
@@ -1227,7 +1200,7 @@ public:
if(have_error()) if(have_error())
return false; return false;
cuda_push_context(); CUDAContextScope scope(this);
CUfunction cuFilterGetFeature; CUfunction cuFilterGetFeature;
cuda_assert(cuModuleGetFunction(&cuFilterGetFeature, cuFilterModule, "kernel_cuda_filter_get_feature")); cuda_assert(cuModuleGetFunction(&cuFilterGetFeature, cuFilterModule, "kernel_cuda_filter_get_feature"));
@@ -1250,7 +1223,6 @@ public:
CUDA_LAUNCH_KERNEL(cuFilterGetFeature, args); CUDA_LAUNCH_KERNEL(cuFilterGetFeature, args);
cuda_assert(cuCtxSynchronize()); cuda_assert(cuCtxSynchronize());
cuda_pop_context();
return !have_error(); return !have_error();
} }
@@ -1263,7 +1235,7 @@ public:
if(have_error()) if(have_error())
return false; return false;
cuda_push_context(); CUDAContextScope scope(this);
CUfunction cuFilterDetectOutliers; CUfunction cuFilterDetectOutliers;
cuda_assert(cuModuleGetFunction(&cuFilterDetectOutliers, cuFilterModule, "kernel_cuda_filter_detect_outliers")); cuda_assert(cuModuleGetFunction(&cuFilterDetectOutliers, cuFilterModule, "kernel_cuda_filter_detect_outliers"));
@@ -1282,7 +1254,6 @@ public:
CUDA_LAUNCH_KERNEL(cuFilterDetectOutliers, args); CUDA_LAUNCH_KERNEL(cuFilterDetectOutliers, args);
cuda_assert(cuCtxSynchronize()); cuda_assert(cuCtxSynchronize());
cuda_pop_context();
return !have_error(); return !have_error();
} }
@@ -1319,7 +1290,7 @@ public:
if(have_error()) if(have_error())
return; return;
cuda_push_context(); CUDAContextScope scope(this);
CUfunction cuPathTrace; CUfunction cuPathTrace;
CUdeviceptr d_buffer = cuda_device_ptr(rtile.buffer); CUdeviceptr d_buffer = cuda_device_ptr(rtile.buffer);
@@ -1333,8 +1304,9 @@ public:
cuda_assert(cuModuleGetFunction(&cuPathTrace, cuModule, "kernel_cuda_path_trace")); cuda_assert(cuModuleGetFunction(&cuPathTrace, cuModule, "kernel_cuda_path_trace"));
} }
if(have_error()) if(have_error()) {
return; return;
}
/* pass in parameters */ /* pass in parameters */
void *args[] = {&d_buffer, void *args[] = {&d_buffer,
@@ -1370,8 +1342,6 @@ public:
0, 0, args, 0)); 0, 0, args, 0));
cuda_assert(cuCtxSynchronize()); cuda_assert(cuCtxSynchronize());
cuda_pop_context();
} }
void film_convert(DeviceTask& task, device_ptr buffer, device_ptr rgba_byte, device_ptr rgba_half) void film_convert(DeviceTask& task, device_ptr buffer, device_ptr rgba_byte, device_ptr rgba_half)
@@ -1379,7 +1349,7 @@ public:
if(have_error()) if(have_error())
return; return;
cuda_push_context(); CUDAContextScope scope(this);
CUfunction cuFilmConvert; CUfunction cuFilmConvert;
CUdeviceptr d_rgba = map_pixels((rgba_byte)? rgba_byte: rgba_half); CUdeviceptr d_rgba = map_pixels((rgba_byte)? rgba_byte: rgba_half);
@@ -1424,8 +1394,6 @@ public:
0, 0, args, 0)); 0, 0, args, 0));
unmap_pixels((rgba_byte)? rgba_byte: rgba_half); unmap_pixels((rgba_byte)? rgba_byte: rgba_half);
cuda_pop_context();
} }
void shader(DeviceTask& task) void shader(DeviceTask& task)
@@ -1433,7 +1401,7 @@ public:
if(have_error()) if(have_error())
return; return;
cuda_push_context(); CUDAContextScope scope(this);
CUfunction cuShader; CUfunction cuShader;
CUdeviceptr d_input = cuda_device_ptr(task.shader_input); CUdeviceptr d_input = cuda_device_ptr(task.shader_input);
@@ -1498,8 +1466,6 @@ public:
task.update_progress(NULL); task.update_progress(NULL);
} }
cuda_pop_context();
} }
CUdeviceptr map_pixels(device_ptr mem) CUdeviceptr map_pixels(device_ptr mem)
@@ -1535,7 +1501,7 @@ public:
pmem.w = mem.data_width; pmem.w = mem.data_width;
pmem.h = mem.data_height; pmem.h = mem.data_height;
cuda_push_context(); CUDAContextScope scope(this);
glGenBuffers(1, &pmem.cuPBO); glGenBuffers(1, &pmem.cuPBO);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO);
@@ -1559,8 +1525,6 @@ public:
CUresult result = cuGraphicsGLRegisterBuffer(&pmem.cuPBOresource, pmem.cuPBO, CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE); CUresult result = cuGraphicsGLRegisterBuffer(&pmem.cuPBOresource, pmem.cuPBO, CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE);
if(result == CUDA_SUCCESS) { if(result == CUDA_SUCCESS) {
cuda_pop_context();
mem.device_pointer = pmem.cuTexId; mem.device_pointer = pmem.cuTexId;
pixel_mem_map[mem.device_pointer] = pmem; pixel_mem_map[mem.device_pointer] = pmem;
@@ -1574,8 +1538,6 @@ public:
glDeleteBuffers(1, &pmem.cuPBO); glDeleteBuffers(1, &pmem.cuPBO);
glDeleteTextures(1, &pmem.cuTexId); glDeleteTextures(1, &pmem.cuTexId);
cuda_pop_context();
background = true; background = true;
} }
} }
@@ -1588,7 +1550,7 @@ public:
if(!background) { if(!background) {
PixelMem pmem = pixel_mem_map[mem.device_pointer]; PixelMem pmem = pixel_mem_map[mem.device_pointer];
cuda_push_context(); CUDAContextScope scope(this);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO);
uchar *pixels = (uchar*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_ONLY); uchar *pixels = (uchar*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_ONLY);
@@ -1597,8 +1559,6 @@ public:
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
cuda_pop_context();
return; return;
} }
@@ -1611,14 +1571,12 @@ public:
if(!background) { if(!background) {
PixelMem pmem = pixel_mem_map[mem.device_pointer]; PixelMem pmem = pixel_mem_map[mem.device_pointer];
cuda_push_context(); CUDAContextScope scope(this);
cuda_assert(cuGraphicsUnregisterResource(pmem.cuPBOresource)); cuda_assert(cuGraphicsUnregisterResource(pmem.cuPBOresource));
glDeleteBuffers(1, &pmem.cuPBO); glDeleteBuffers(1, &pmem.cuPBO);
glDeleteTextures(1, &pmem.cuTexId); glDeleteTextures(1, &pmem.cuTexId);
cuda_pop_context();
pixel_mem_map.erase(pixel_mem_map.find(mem.device_pointer)); pixel_mem_map.erase(pixel_mem_map.find(mem.device_pointer));
mem.device_pointer = 0; mem.device_pointer = 0;
@@ -1643,7 +1601,7 @@ public:
PixelMem pmem = pixel_mem_map[mem.device_pointer]; PixelMem pmem = pixel_mem_map[mem.device_pointer];
float *vpointer; float *vpointer;
cuda_push_context(); CUDAContextScope scope(this);
/* for multi devices, this assumes the inefficient method that we allocate /* for multi devices, this assumes the inefficient method that we allocate
* all pixels on the device even though we only render to a subset */ * all pixels on the device even though we only render to a subset */
@@ -1749,8 +1707,6 @@ public:
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
cuda_pop_context();
return; return;
} }
@@ -1759,6 +1715,8 @@ public:
void thread_run(DeviceTask *task) void thread_run(DeviceTask *task)
{ {
CUDAContextScope scope(this);
if(task->type == DeviceTask::RENDER) { if(task->type == DeviceTask::RENDER) {
RenderTile tile; RenderTile tile;
@@ -1826,9 +1784,7 @@ public:
shader(*task); shader(*task);
cuda_push_context();
cuda_assert(cuCtxSynchronize()); cuda_assert(cuCtxSynchronize());
cuda_pop_context();
} }
} }
@@ -1849,12 +1805,11 @@ public:
void task_add(DeviceTask& task) void task_add(DeviceTask& task)
{ {
if(task.type == DeviceTask::FILM_CONVERT) { if(task.type == DeviceTask::FILM_CONVERT) {
CUDAContextScope scope(this);
/* must be done in main thread due to opengl access */ /* must be done in main thread due to opengl access */
film_convert(task, task.buffer, task.rgba_byte, task.rgba_half); film_convert(task, task.buffer, task.rgba_byte, task.rgba_half);
cuda_push_context();
cuda_assert(cuCtxSynchronize()); cuda_assert(cuCtxSynchronize());
cuda_pop_context();
} }
else { else {
task_pool.push(new CUDADeviceTask(this, task)); task_pool.push(new CUDADeviceTask(this, task));
@@ -1873,6 +1828,7 @@ public:
friend class CUDASplitKernelFunction; friend class CUDASplitKernelFunction;
friend class CUDASplitKernel; friend class CUDASplitKernel;
friend class CUDAContextScope;
}; };
/* redefine the cuda_assert macro so it can be used outside of the CUDADevice class /* redefine the cuda_assert macro so it can be used outside of the CUDADevice class
@@ -1893,6 +1849,20 @@ public:
} \ } \
} (void)0 } (void)0
/* CUDA context scope. */
CUDAContextScope::CUDAContextScope(CUDADevice *device)
: device(device)
{
cuda_assert(cuCtxPushCurrent(device->cuContext));
}
CUDAContextScope::~CUDAContextScope()
{
cuda_assert(cuCtxPopCurrent(NULL));
}
/* split kernel */ /* split kernel */
class CUDASplitKernelFunction : public SplitKernelFunction{ class CUDASplitKernelFunction : public SplitKernelFunction{
@@ -1910,11 +1880,11 @@ public:
/* enqueue the kernel, returns false if there is an error */ /* enqueue the kernel, returns false if there is an error */
bool enqueue(const KernelDimensions &dim, void *args[]) bool enqueue(const KernelDimensions &dim, void *args[])
{ {
device->cuda_push_context();
if(device->have_error()) if(device->have_error())
return false; return false;
CUDAContextScope scope(device);
/* we ignore dim.local_size for now, as this is faster */ /* we ignore dim.local_size for now, as this is faster */
int threads_per_block; int threads_per_block;
cuda_assert(cuFuncGetAttribute(&threads_per_block, CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, func)); cuda_assert(cuFuncGetAttribute(&threads_per_block, CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, func));
@@ -1928,8 +1898,6 @@ public:
threads_per_block, 1, 1, /* threads */ threads_per_block, 1, 1, /* threads */
0, 0, args, 0)); 0, 0, args, 0));
device->cuda_pop_context();
return !device->have_error(); return !device->have_error();
} }
}; };
@@ -1940,12 +1908,12 @@ CUDASplitKernel::CUDASplitKernel(CUDADevice *device) : DeviceSplitKernel(device)
uint64_t CUDASplitKernel::state_buffer_size(device_memory& /*kg*/, device_memory& /*data*/, size_t num_threads) uint64_t CUDASplitKernel::state_buffer_size(device_memory& /*kg*/, device_memory& /*data*/, size_t num_threads)
{ {
CUDAContextScope scope(device);
device_vector<uint64_t> size_buffer; device_vector<uint64_t> size_buffer;
size_buffer.resize(1); size_buffer.resize(1);
device->mem_alloc(NULL, size_buffer, MEM_READ_WRITE); device->mem_alloc(NULL, size_buffer, MEM_READ_WRITE);
device->cuda_push_context();
uint threads = num_threads; uint threads = num_threads;
CUdeviceptr d_size = device->cuda_device_ptr(size_buffer.device_pointer); CUdeviceptr d_size = device->cuda_device_ptr(size_buffer.device_pointer);
@@ -1967,8 +1935,6 @@ uint64_t CUDASplitKernel::state_buffer_size(device_memory& /*kg*/, device_memory
1, 1, 1, 1, 1, 1,
0, 0, (void**)&args, 0)); 0, 0, (void**)&args, 0));
device->cuda_pop_context();
device->mem_copy_from(size_buffer, 0, 1, 1, sizeof(uint64_t)); device->mem_copy_from(size_buffer, 0, 1, 1, sizeof(uint64_t));
device->mem_free(size_buffer); device->mem_free(size_buffer);
@@ -1986,7 +1952,7 @@ bool CUDASplitKernel::enqueue_split_kernel_data_init(const KernelDimensions& dim
device_memory& use_queues_flag, device_memory& use_queues_flag,
device_memory& work_pool_wgs) device_memory& work_pool_wgs)
{ {
device->cuda_push_context(); CUDAContextScope scope(device);
CUdeviceptr d_split_data = device->cuda_device_ptr(split_data.device_pointer); CUdeviceptr d_split_data = device->cuda_device_ptr(split_data.device_pointer);
CUdeviceptr d_ray_state = device->cuda_device_ptr(ray_state.device_pointer); CUdeviceptr d_ray_state = device->cuda_device_ptr(ray_state.device_pointer);
@@ -2050,26 +2016,21 @@ bool CUDASplitKernel::enqueue_split_kernel_data_init(const KernelDimensions& dim
CUDASplitKernelFunction(device, data_init).enqueue(dim, (void**)&args); CUDASplitKernelFunction(device, data_init).enqueue(dim, (void**)&args);
device->cuda_pop_context();
return !device->have_error(); return !device->have_error();
} }
SplitKernelFunction* CUDASplitKernel::get_split_kernel_function(const string& kernel_name, SplitKernelFunction* CUDASplitKernel::get_split_kernel_function(const string& kernel_name,
const DeviceRequestedFeatures&) const DeviceRequestedFeatures&)
{ {
CUDAContextScope scope(device);
CUfunction func; CUfunction func;
device->cuda_push_context();
cuda_assert(cuModuleGetFunction(&func, device->cuModule, (string("kernel_cuda_") + kernel_name).data())); cuda_assert(cuModuleGetFunction(&func, device->cuModule, (string("kernel_cuda_") + kernel_name).data()));
if(device->have_error()) { if(device->have_error()) {
device->cuda_error_message(string_printf("kernel \"kernel_cuda_%s\" not found in module", kernel_name.data())); device->cuda_error_message(string_printf("kernel \"kernel_cuda_%s\" not found in module", kernel_name.data()));
return NULL; return NULL;
} }
device->cuda_pop_context();
return new CUDASplitKernelFunction(device, func); return new CUDASplitKernelFunction(device, func);
} }
@@ -2080,12 +2041,11 @@ int2 CUDASplitKernel::split_kernel_local_size()
int2 CUDASplitKernel::split_kernel_global_size(device_memory& kg, device_memory& data, DeviceTask * /*task*/) int2 CUDASplitKernel::split_kernel_global_size(device_memory& kg, device_memory& data, DeviceTask * /*task*/)
{ {
CUDAContextScope scope(device);
size_t free; size_t free;
size_t total; size_t total;
device->cuda_push_context();
cuda_assert(cuMemGetInfo(&free, &total)); cuda_assert(cuMemGetInfo(&free, &total));
device->cuda_pop_context();
VLOG(1) << "Maximum device allocation size: " VLOG(1) << "Maximum device allocation size: "
<< string_human_readable_number(free) << " bytes. (" << string_human_readable_number(free) << " bytes. ("

View File

@@ -51,6 +51,19 @@ def draw_keyframing_tools(context, layout):
row.operator("anim.keyframe_delete_v3d", text="Remove") row.operator("anim.keyframe_delete_v3d", text="Remove")
# Used by vertex & weight paint
def draw_vpaint_symmetry(layout, vpaint):
col = layout.column(align=True)
col.label(text="Mirror:")
row = col.row(align=True)
row.prop(vpaint, "use_symmetry_x", text="X", toggle=True)
row.prop(vpaint, "use_symmetry_y", text="Y", toggle=True)
row.prop(vpaint, "use_symmetry_z", text="Z", toggle=True)
col = layout.column()
col.prop(vpaint, "radial_symmetry", text="Radial")
# ********** default tools for object-mode **************** # ********** default tools for object-mode ****************
@@ -1134,7 +1147,11 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
self.prop_unified_color_picker(col, context, brush, "color", value_slider=True) self.prop_unified_color_picker(col, context, brush, "color", value_slider=True)
if settings.palette: if settings.palette:
col.template_palette(settings, "palette", color=True) col.template_palette(settings, "palette", color=True)
self.prop_unified_color(col, context, brush, "color", text="") row = col.row(align=True)
self.prop_unified_color(row, context, brush, "color", text="")
self.prop_unified_color(row, context, brush, "secondary_color", text="")
row.separator()
row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="")
col.separator() col.separator()
row = col.row(align=True) row = col.row(align=True)
@@ -1717,6 +1734,19 @@ class VIEW3D_PT_tools_weightpaint(View3DPanel, Panel):
props.data_type = 'VGROUP_WEIGHTS' props.data_type = 'VGROUP_WEIGHTS'
class VIEW3D_PT_tools_weightpaint_symmetry(Panel, View3DPaintPanel):
bl_category = "Tools"
bl_context = "weightpaint"
bl_options = {'DEFAULT_CLOSED'}
bl_label = "Symmetry"
def draw(self, context):
layout = self.layout
toolsettings = context.tool_settings
wpaint = toolsettings.weight_paint
draw_vpaint_symmetry(layout, wpaint)
class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel): class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel):
bl_category = "Options" bl_category = "Options"
bl_context = "weightpaint" bl_context = "weightpaint"
@@ -1779,6 +1809,20 @@ class VIEW3D_PT_tools_vertexpaint(Panel, View3DPaintPanel):
#~ col.label(text="Multiply:") #~ col.label(text="Multiply:")
#~ col.prop(vpaint, "mul", text="") #~ col.prop(vpaint, "mul", text="")
class VIEW3D_PT_tools_vertexpaint_symmetry(Panel, View3DPaintPanel):
bl_category = "Tools"
bl_context = "vertexpaint"
bl_options = {'DEFAULT_CLOSED'}
bl_label = "Symmetry"
def draw(self, context):
layout = self.layout
toolsettings = context.tool_settings
vpaint = toolsettings.vertex_paint
draw_vpaint_symmetry(layout, vpaint)
# ********** default tools for texture-paint **************** # ********** default tools for texture-paint ****************
@@ -2058,8 +2102,10 @@ classes = (
VIEW3D_PT_sculpt_symmetry, VIEW3D_PT_sculpt_symmetry,
VIEW3D_PT_tools_brush_appearance, VIEW3D_PT_tools_brush_appearance,
VIEW3D_PT_tools_weightpaint, VIEW3D_PT_tools_weightpaint,
VIEW3D_PT_tools_weightpaint_symmetry,
VIEW3D_PT_tools_weightpaint_options, VIEW3D_PT_tools_weightpaint_options,
VIEW3D_PT_tools_vertexpaint, VIEW3D_PT_tools_vertexpaint,
VIEW3D_PT_tools_vertexpaint_symmetry,
VIEW3D_PT_tools_imagepaint_external, VIEW3D_PT_tools_imagepaint_external,
VIEW3D_PT_tools_imagepaint_symmetry, VIEW3D_PT_tools_imagepaint_symmetry,
VIEW3D_PT_tools_projectpaint, VIEW3D_PT_tools_projectpaint,

View File

@@ -162,6 +162,14 @@ void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct B
void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]); void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]);
/* Used for both vertex color and weight paint */
struct SculptVertexPaintGeomMap {
int *vert_map_mem;
struct MeshElemMap *vert_to_loop;
int *poly_map_mem;
struct MeshElemMap *vert_to_poly;
};
/* Session data (mode-specific) */ /* Session data (mode-specific) */
typedef struct SculptSession { typedef struct SculptSession {
@@ -207,10 +215,38 @@ typedef struct SculptSession {
struct SculptStroke *stroke; struct SculptStroke *stroke;
struct StrokeCache *cache; struct StrokeCache *cache;
union {
struct {
struct SculptVertexPaintGeomMap gmap;
/* For non-airbrush painting to re-apply from the original (MLoop aligned). */
unsigned int *previous_color;
} vpaint;
struct {
struct SculptVertexPaintGeomMap gmap;
/* Vertex aligned arrays of weights. */
/* For non-airbrush painting to re-apply from the original. */
float *previous_weight;
/* Keep track of how much each vertex has been painted (non-airbrush only). */
float *alpha_weight;
} wpaint;
//struct {
//ToDo: identify sculpt-only fields
//} sculpt;
} mode;
int mode_type;
/* This flag prevents PBVH from being freed when creating the vp_handle for texture paint. */
bool building_vp_handle;
} SculptSession; } SculptSession;
void BKE_sculptsession_free(struct Object *ob); void BKE_sculptsession_free(struct Object *ob);
void BKE_sculptsession_free_deformMats(struct SculptSession *ss); void BKE_sculptsession_free_deformMats(struct SculptSession *ss);
void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss);
void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder); void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder);
void BKE_sculptsession_bm_to_me_for_render(struct Object *object); void BKE_sculptsession_bm_to_me_for_render(struct Object *object);
void BKE_sculpt_update_mesh_elements( void BKE_sculpt_update_mesh_elements(

View File

@@ -33,6 +33,7 @@
struct Gwn_Batch; struct Gwn_Batch;
struct CCGElem; struct CCGElem;
struct CCGKey; struct CCGKey;
struct CCGDerivedMesh;
struct CustomData; struct CustomData;
struct DMFlagMat; struct DMFlagMat;
struct MPoly; struct MPoly;
@@ -72,7 +73,7 @@ void BKE_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems,
struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats, struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats,
unsigned int **grid_hidden); unsigned int **grid_hidden);
void BKE_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, bool smooth_shading, struct BMLog *log, const int cd_vert_node_offset, const int cd_face_node_offset); void BKE_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, bool smooth_shading, struct BMLog *log, const int cd_vert_node_offset, const int cd_face_node_offset);
void BKE_pbvh_set_ccgdm(PBVH *bvh, struct CCGDerivedMesh *ccgdm);
void BKE_pbvh_free(PBVH *bvh); void BKE_pbvh_free(PBVH *bvh);
void BKE_pbvh_free_layer_disp(PBVH *bvh); void BKE_pbvh_free_layer_disp(PBVH *bvh);
@@ -119,6 +120,7 @@ void BKE_pbvh_raycast_project_ray_root(
void BKE_pbvh_node_draw(PBVHNode *node, void *data); void BKE_pbvh_node_draw(PBVHNode *node, void *data);
void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3],
int (*setMaterial)(int matnr, void *attribs), bool wireframe, bool fast); int (*setMaterial)(int matnr, void *attribs), bool wireframe, bool fast);
void BKE_pbvh_draw_BB(PBVH *bvh);
void BKE_pbvh_draw_cb( void BKE_pbvh_draw_cb(
PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast, PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast,
void (*draw_fn)(void *user_data, struct Gwn_Batch *batch), void *user_data); void (*draw_fn)(void *user_data, struct Gwn_Batch *batch), void *user_data);
@@ -145,6 +147,7 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
/* multires level, only valid for type == PBVH_GRIDS */ /* multires level, only valid for type == PBVH_GRIDS */
void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key); void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key);
struct CCGDerivedMesh *BKE_pbvh_get_ccgdm(const PBVH *bvh);
/* Only valid for type == PBVH_BMESH */ /* Only valid for type == PBVH_BMESH */
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh); struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);

View File

@@ -2666,7 +2666,7 @@ static void mesh_build_data(
ob->lastDataMask = dataMask; ob->lastDataMask = dataMask;
ob->lastNeedMapping = need_mapping; ob->lastNeedMapping = need_mapping;
if ((ob->mode & OB_MODE_SCULPT) && ob->sculpt) { if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
/* create PBVH immediately (would be created on the fly too, /* create PBVH immediately (would be created on the fly too,
* but this avoids waiting on first stroke) */ * but this avoids waiting on first stroke) */

View File

@@ -551,6 +551,11 @@ static void cdDM_drawMappedFaces(
const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
if (cddm->pbvh) {
if (G.debug_value == 14)
BKE_pbvh_draw_BB(cddm->pbvh);
}
/* fist, setup common buffers */ /* fist, setup common buffers */
GPU_vertex_setup(dm); GPU_vertex_setup(dm);
GPU_triangle_setup(dm); GPU_triangle_setup(dm);

View File

@@ -2736,7 +2736,7 @@ void BKE_object_sculpt_modifiers_changed(Object *ob)
{ {
SculptSession *ss = ob->sculpt; SculptSession *ss = ob->sculpt;
if (ss) { if (ss && ss->building_vp_handle == false) {
if (!ss->cache) { if (!ss->cache) {
/* we free pbvh on changes, except during sculpt since it can't deal with /* we free pbvh on changes, except during sculpt since it can't deal with
* changing PVBH node organization, we hope topology does not change in * changing PVBH node organization, we hope topology does not change in
@@ -2747,6 +2747,9 @@ void BKE_object_sculpt_modifiers_changed(Object *ob)
} }
BKE_sculptsession_free_deformMats(ob->sculpt); BKE_sculptsession_free_deformMats(ob->sculpt);
/* In vertex/weight paint, force maps to be rebuilt. */
BKE_sculptsession_free_vwpaint_data(ob->sculpt);
} }
else { else {
PBVHNode **nodes; PBVHNode **nodes;

View File

@@ -676,6 +676,29 @@ void BKE_sculptsession_free_deformMats(SculptSession *ss)
MEM_SAFE_FREE(ss->deform_imats); MEM_SAFE_FREE(ss->deform_imats);
} }
void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss)
{
struct SculptVertexPaintGeomMap *gmap = NULL;
if (ss->mode_type == OB_MODE_VERTEX_PAINT) {
gmap = &ss->mode.vpaint.gmap;
MEM_SAFE_FREE(ss->mode.vpaint.previous_color);
}
else if (ss->mode_type == OB_MODE_WEIGHT_PAINT) {
gmap = &ss->mode.wpaint.gmap;
MEM_SAFE_FREE(ss->mode.wpaint.alpha_weight);
MEM_SAFE_FREE(ss->mode.wpaint.previous_weight);
}
else {
return;
}
MEM_SAFE_FREE(gmap->vert_to_loop);
MEM_SAFE_FREE(gmap->vert_map_mem);
MEM_SAFE_FREE(gmap->vert_to_poly);
MEM_SAFE_FREE(gmap->poly_map_mem);
}
/* Write out the sculpt dynamic-topology BMesh to the Mesh */ /* Write out the sculpt dynamic-topology BMesh to the Mesh */
static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder) static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
{ {
@@ -717,10 +740,7 @@ void BKE_sculptsession_bm_to_me_for_render(Object *object)
*/ */
BKE_object_free_derived_caches(object); BKE_object_free_derived_caches(object);
if (object->sculpt->pbvh) { MEM_SAFE_FREE(object->sculpt->pbvh);
BKE_pbvh_free(object->sculpt->pbvh);
object->sculpt->pbvh = NULL;
}
sculptsession_bm_to_me_update_data_only(object, false); sculptsession_bm_to_me_update_data_only(object, false);
@@ -767,6 +787,8 @@ void BKE_sculptsession_free(Object *ob)
if (ss->deform_imats) if (ss->deform_imats)
MEM_freeN(ss->deform_imats); MEM_freeN(ss->deform_imats);
BKE_sculptsession_free_vwpaint_data(ob->sculpt);
MEM_freeN(ss); MEM_freeN(ss);
ob->sculpt = NULL; ob->sculpt = NULL;
@@ -852,6 +874,8 @@ void BKE_sculpt_update_mesh_elements(
ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob); ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob);
ss->show_diffuse_color = (sd->flags & SCULPT_SHOW_DIFFUSE) != 0; ss->show_diffuse_color = (sd->flags & SCULPT_SHOW_DIFFUSE) != 0;
ss->building_vp_handle = false;
if (need_mask) { if (need_mask) {
if (mmd == NULL) { if (mmd == NULL) {
if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) { if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) {
@@ -880,7 +904,8 @@ void BKE_sculpt_update_mesh_elements(
dm = mesh_get_derived_final(eval_ctx, scene, ob, CD_MASK_BAREMESH); dm = mesh_get_derived_final(eval_ctx, scene, ob, CD_MASK_BAREMESH);
if (mmd) { /* VWPaint require mesh info for loop lookup, so require sculpt mode here */
if (mmd && ob->mode & OB_MODE_SCULPT) {
ss->multires = mmd; ss->multires = mmd;
ss->totvert = dm->getNumVerts(dm); ss->totvert = dm->getNumVerts(dm);
ss->totpoly = dm->getNumPolys(dm); ss->totpoly = dm->getNumPolys(dm);

View File

@@ -34,6 +34,7 @@
#include "BKE_pbvh.h" #include "BKE_pbvh.h"
#include "BKE_ccg.h" #include "BKE_ccg.h"
#include "BKE_subsurf.h"
#include "BKE_DerivedMesh.h" #include "BKE_DerivedMesh.h"
#include "BKE_global.h" #include "BKE_global.h"
#include "BKE_mesh.h" /* for BKE_mesh_calc_normals */ #include "BKE_mesh.h" /* for BKE_mesh_calc_normals */
@@ -607,6 +608,10 @@ void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids,
MEM_freeN(prim_bbc); MEM_freeN(prim_bbc);
} }
void BKE_pbvh_set_ccgdm(PBVH *bvh, CCGDerivedMesh *ccgdm) {
bvh->ccgdm = ccgdm;
}
PBVH *BKE_pbvh_new(void) PBVH *BKE_pbvh_new(void)
{ {
PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh"); PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh");
@@ -1157,7 +1162,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
} }
} }
static void pbvh_draw_BB(PBVH *bvh) void BKE_pbvh_draw_BB(PBVH *bvh)
{ {
unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
@@ -1331,6 +1336,11 @@ void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key)
*key = bvh->gridkey; *key = bvh->gridkey;
} }
CCGDerivedMesh *BKE_pbvh_get_ccgdm(const PBVH *bvh) {
return bvh->ccgdm;
}
BMesh *BKE_pbvh_get_bmesh(PBVH *bvh) BMesh *BKE_pbvh_get_bmesh(PBVH *bvh)
{ {
BLI_assert(bvh->type == PBVH_BMESH); BLI_assert(bvh->type == PBVH_BMESH);
@@ -1844,7 +1854,7 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3],
} }
if (G.debug_value == 14) if (G.debug_value == 14)
pbvh_draw_BB(bvh); BKE_pbvh_draw_BB(bvh);
} }
struct PBVHNodeDrawCallbackData { struct PBVHNodeDrawCallbackData {

View File

@@ -149,6 +149,8 @@ struct PBVH {
* objects in sculpt mode with different sizes at the same time, so now storing that common gpu buffer * objects in sculpt mode with different sizes at the same time, so now storing that common gpu buffer
* in an opaque pointer per pbvh. See T47637. */ * in an opaque pointer per pbvh. See T47637. */
struct GridCommonGPUBuffer *grid_common_gpu_buffer; struct GridCommonGPUBuffer *grid_common_gpu_buffer;
/* The ccgdm is required for CD_ORIGINDEX lookup in vertex paint + multires */
struct CCGDerivedMesh *ccgdm;
/* Only used during BVH build and update, /* Only used during BVH build and update,
* don't need to remain valid after */ * don't need to remain valid after */

View File

@@ -346,16 +346,10 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
ToolSettings *ts = sce_dst->toolsettings = MEM_dupallocN(sce_dst->toolsettings); ToolSettings *ts = sce_dst->toolsettings = MEM_dupallocN(sce_dst->toolsettings);
if (ts->vpaint) { if (ts->vpaint) {
ts->vpaint = MEM_dupallocN(ts->vpaint); ts->vpaint = MEM_dupallocN(ts->vpaint);
ts->vpaint->paintcursor = NULL;
ts->vpaint->vpaint_prev = NULL;
ts->vpaint->wpaint_prev = NULL;
BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, flag_subdata); BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, flag_subdata);
} }
if (ts->wpaint) { if (ts->wpaint) {
ts->wpaint = MEM_dupallocN(ts->wpaint); ts->wpaint = MEM_dupallocN(ts->wpaint);
ts->wpaint->paintcursor = NULL;
ts->wpaint->vpaint_prev = NULL;
ts->wpaint->wpaint_prev = NULL;
BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, flag_subdata); BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, flag_subdata);
} }
if (ts->sculpt) { if (ts->sculpt) {
@@ -464,16 +458,10 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
if (ts) { if (ts) {
if (ts->vpaint) { if (ts->vpaint) {
ts->vpaint = MEM_dupallocN(ts->vpaint); ts->vpaint = MEM_dupallocN(ts->vpaint);
ts->vpaint->paintcursor = NULL;
ts->vpaint->vpaint_prev = NULL;
ts->vpaint->wpaint_prev = NULL;
BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, 0); BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, 0);
} }
if (ts->wpaint) { if (ts->wpaint) {
ts->wpaint = MEM_dupallocN(ts->wpaint); ts->wpaint = MEM_dupallocN(ts->wpaint);
ts->wpaint->paintcursor = NULL;
ts->wpaint->vpaint_prev = NULL;
ts->wpaint->wpaint_prev = NULL;
BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, 0); BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, 0);
} }
if (ts->sculpt) { if (ts->sculpt) {

View File

@@ -3429,6 +3429,11 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
int gridFaces = gridSize - 1, totface; int gridFaces = gridSize - 1, totface;
int prev_mat_nr = -1; int prev_mat_nr = -1;
if (ccgdm->pbvh) {
if (G.debug_value == 14)
BKE_pbvh_draw_BB(ccgdm->pbvh);
}
#ifdef WITH_OPENSUBDIV #ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) { if (ccgdm->useGpuBackend) {
int new_matnr; int new_matnr;
@@ -4162,7 +4167,8 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
if (!ob->sculpt) if (!ob->sculpt)
return NULL; return NULL;
grid_pbvh = ccgDM_use_grid_pbvh(ccgdm); /* In vwpaint, we always use a grid_pbvh for multires/subsurf */
grid_pbvh = (!(ob->mode & OB_MODE_SCULPT) || ccgDM_use_grid_pbvh(ccgdm));
if (ob->sculpt->pbvh) { if (ob->sculpt->pbvh) {
if (grid_pbvh) { if (grid_pbvh) {
@@ -4178,12 +4184,18 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
ccgdm->pbvh = ob->sculpt->pbvh; ccgdm->pbvh = ob->sculpt->pbvh;
} }
if (ccgdm->pbvh) if (ccgdm->pbvh) {
/* For vertex paint, keep track of ccgdm */
if (!(ob->mode & OB_MODE_SCULPT)) {
BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm);
}
return ccgdm->pbvh; return ccgdm->pbvh;
}
/* no pbvh exists yet, we need to create one. only in case of multires /* no pbvh exists yet, we need to create one. only in case of multires
* we build a pbvh over the modified mesh, in other cases the base mesh * we build a pbvh over the modified mesh, in other cases the base mesh
* is being sculpted, so we build a pbvh from that. */ * is being sculpted, so we build a pbvh from that. */
/* Note: vwpaint always builds a pbvh over the modified mesh. */
if (grid_pbvh) { if (grid_pbvh) {
ccgdm_create_grids(dm); ccgdm_create_grids(dm);
@@ -4214,6 +4226,10 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
if (ccgdm->pbvh) if (ccgdm->pbvh)
pbvh_show_diffuse_color_set(ccgdm->pbvh, ob->sculpt->show_diffuse_color); pbvh_show_diffuse_color_set(ccgdm->pbvh, ob->sculpt->show_diffuse_color);
/* For vertex paint, keep track of ccgdm */
if (!(ob->mode & OB_MODE_SCULPT) && ccgdm->pbvh) {
BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm);
}
return ccgdm->pbvh; return ccgdm->pbvh;
} }

View File

@@ -6130,16 +6130,6 @@ static void direct_link_scene(FileData *fd, Scene *sce, Main *bmain)
sce->toolsettings->particle.scene_layer = NULL; sce->toolsettings->particle.scene_layer = NULL;
sce->toolsettings->particle.object = NULL; sce->toolsettings->particle.object = NULL;
sce->toolsettings->gp_sculpt.paintcursor = NULL; sce->toolsettings->gp_sculpt.paintcursor = NULL;
/* in rare cases this is needed, see [#33806] */
if (sce->toolsettings->vpaint) {
sce->toolsettings->vpaint->vpaint_prev = NULL;
sce->toolsettings->vpaint->tot = 0;
}
if (sce->toolsettings->wpaint) {
sce->toolsettings->wpaint->wpaint_prev = NULL;
sce->toolsettings->wpaint->tot = 0;
}
/* relink grease pencil drawing brushes */ /* relink grease pencil drawing brushes */
link_list(fd, &sce->toolsettings->gp_brushes); link_list(fd, &sce->toolsettings->gp_brushes);

View File

@@ -60,6 +60,7 @@
#include "DNA_genfile.h" #include "DNA_genfile.h"
#include "BKE_animsys.h" #include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_colortools.h" #include "BKE_colortools.h"
#include "BKE_library.h" #include "BKE_library.h"
#include "BKE_main.h" #include "BKE_main.h"
@@ -1702,6 +1703,24 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
} }
} }
} }
{
Brush *br;
br = (Brush *)BKE_libblock_find_name_ex(main, ID_BR, "Average");
if (!br) {
br = BKE_brush_add(main, "Average", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT);
br->vertexpaint_tool = PAINT_BLEND_AVERAGE;
br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT;
}
br = (Brush *)BKE_libblock_find_name_ex(main, ID_BR, "Smear");
if (!br) {
br = BKE_brush_add(main, "Smear", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT);
br->vertexpaint_tool = PAINT_BLEND_SMEAR;
br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT;
}
}
} }
} }

View File

@@ -140,6 +140,16 @@ void BLO_update_defaults_startup_blend(Main *bmain)
sculpt->detail_size = 12; sculpt->detail_size = 12;
} }
if (ts->vpaint) {
VPaint *vp = ts->vpaint;
vp->radial_symm[0] = vp->radial_symm[1] = vp->radial_symm[2] = 1;
}
if (ts->wpaint) {
VPaint *wp = ts->wpaint;
wp->radial_symm[0] = wp->radial_symm[1] = wp->radial_symm[2] = 1;
}
if (ts->gp_sculpt.brush[0].size == 0) { if (ts->gp_sculpt.brush[0].size == 0) {
GP_BrushEdit_Settings *gset = &ts->gp_sculpt; GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
GP_EditBrush_Data *brush; GP_EditBrush_Data *brush;

View File

@@ -1470,7 +1470,20 @@ void PAINT_OT_texture_paint_toggle(wmOperatorType *ot)
static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op)) static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op))
{ {
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
Brush *br = image_paint_brush(C);
Brush *br;
Object *ob = CTX_data_active_object(C);
if (!(ob && (ob->mode & OB_MODE_VERTEX_PAINT))) {
br = image_paint_brush(C);
}
else {
/* At the moment, wpaint does not support the color flipper.
* So for now we're only handling vpaint */
ToolSettings *ts = CTX_data_tool_settings(C);
VPaint *vp = ts->vpaint;
br = BKE_paint_brush(&vp->paint);
}
if (ups->flag & UNIFIED_PAINT_COLOR) { if (ups->flag & UNIFIED_PAINT_COLOR) {
swap_v3_v3(ups->rgb, ups->secondary_rgb); swap_v3_v3(ups->rgb, ups->secondary_rgb);
} }
@@ -1489,7 +1502,12 @@ static int brush_colors_flip_poll(bContext *C)
if (br->imagepaint_tool == PAINT_TOOL_DRAW) if (br->imagepaint_tool == PAINT_TOOL_DRAW)
return 1; return 1;
} }
else {
Object *ob = CTX_data_active_object(C);
if (ob && (ob->mode & OB_MODE_VERTEX_PAINT)) {
return 1;
}
}
return 0; return 0;
} }

View File

@@ -97,7 +97,7 @@ int vertex_paint_poll(struct bContext *C);
int vertex_paint_mode_poll(struct bContext *C); int vertex_paint_mode_poll(struct bContext *C);
bool ED_vpaint_fill(struct Object *ob, unsigned int paintcol); bool ED_vpaint_fill(struct Object *ob, unsigned int paintcol);
bool ED_wpaint_fill(struct VPaint *wp, struct Object *ob, float paintweight); bool ED_wpaint_fill(struct Object *ob, float paintweight);
bool ED_vpaint_smooth(struct Object *ob); bool ED_vpaint_smooth(struct Object *ob);

View File

@@ -1613,6 +1613,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
keymap->poll = vertex_paint_mode_poll; keymap->poll = vertex_paint_mode_poll;
WM_keymap_verify_item(keymap, "PAINT_OT_vertex_paint", LEFTMOUSE, KM_PRESS, 0, 0); WM_keymap_verify_item(keymap, "PAINT_OT_vertex_paint", LEFTMOUSE, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PAINT_OT_brush_colors_flip", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PAINT_OT_sample_color", SKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "PAINT_OT_sample_color", SKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, WM_keymap_add_item(keymap,

File diff suppressed because it is too large Load Diff

View File

@@ -39,7 +39,6 @@
#include "BLI_blenlib.h" #include "BLI_blenlib.h"
#include "BLI_dial.h" #include "BLI_dial.h"
#include "BLI_task.h" #include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include "BLI_ghash.h" #include "BLI_ghash.h"
@@ -166,111 +165,12 @@ static bool sculpt_brush_needs_rake_rotation(const Brush *brush)
return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f); return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f);
} }
/* Factor of brush to have rake point following behind
* (could be configurable but this is reasonable default). */
#define SCULPT_RAKE_BRUSH_FACTOR 0.25f
struct SculptRakeData {
float follow_dist;
float follow_co[3];
};
typedef enum StrokeFlags { typedef enum StrokeFlags {
CLIP_X = 1, CLIP_X = 1,
CLIP_Y = 2, CLIP_Y = 2,
CLIP_Z = 4 CLIP_Z = 4
} StrokeFlags; } StrokeFlags;
/* Cache stroke properties. Used because
* RNA property lookup isn't particularly fast.
*
* For descriptions of these settings, check the operator properties.
*/
typedef struct StrokeCache {
/* Invariants */
float initial_radius;
float scale[3];
int flag;
float clip_tolerance[3];
float initial_mouse[2];
/* Variants */
float radius;
float radius_squared;
float true_location[3];
float location[3];
bool pen_flip;
bool invert;
float pressure;
float mouse[2];
float bstrength;
float normal_weight; /* from brush (with optional override) */
/* The rest is temporary storage that isn't saved as a property */
bool first_time; /* Beginning of stroke may do some things special */
/* from ED_view3d_ob_project_mat_get() */
float projection_mat[4][4];
/* Clean this up! */
ViewContext *vc;
Brush *brush;
float special_rotation;
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3], orig_grab_location[3];
/* screen-space rotation defined by mouse motion */
float rake_rotation[4], rake_rotation_symmetry[4];
bool is_rake_rotation_valid;
struct SculptRakeData rake_data;
int symmetry; /* Symmetry index between 0 and 7 bit combo 0 is Brush only;
* 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/
float true_view_normal[3];
float view_normal[3];
/* sculpt_normal gets calculated by calc_sculpt_normal(), then the
* sculpt_normal_symm gets updated quickly with the usual symmetry
* transforms */
float sculpt_normal[3];
float sculpt_normal_symm[3];
/* Used for area texture mode, local_mat gets calculated by
* calc_brush_local_mat() and used in tex_strength(). */
float brush_local_mat[4][4];
float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */
int tile_pass;
float last_center[3];
int radial_symmetry_pass;
float symm_rot_mat[4][4];
float symm_rot_mat_inv[4][4];
bool original;
float anchored_location[3];
float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
Dial *dial;
char saved_active_brush_name[MAX_ID_NAME];
char saved_mask_brush_tool;
int saved_smooth_size; /* smooth tool copies the size of the current tool */
bool alt_smooth;
float plane_trim_squared;
bool supports_gravity;
float true_gravity_direction[3];
float gravity_direction[3];
rcti previous_r; /* previous redraw rectangle */
rcti current_r; /* current redraw rectangle */
} StrokeCache;
/************** Access to original unmodified vertex data *************/ /************** Access to original unmodified vertex data *************/
typedef struct { typedef struct {
@@ -477,41 +377,6 @@ static bool sculpt_stroke_is_dynamic_topology(
/*** paint mesh ***/ /*** paint mesh ***/
/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */
typedef struct SculptThreadedTaskData {
Sculpt *sd;
Object *ob;
Brush *brush;
PBVHNode **nodes;
int totnode;
/* Data specific to some callbacks. */
/* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out
* what it is, and memory overhead is ridiculous anyway... */
float flippedbstrength;
float angle;
float strength;
bool smooth_mask;
bool has_bm_orco;
SculptProjectVector *spvc;
float *offset;
float *grab_delta;
float *cono;
float *area_no;
float *area_no_sp;
float *area_co;
float (*mat)[4];
float (*vertCos)[3];
/* 0=towards view, 1=flipped */
float (*area_cos)[3];
float (*area_nos)[3];
int *count;
ThreadMutex mutex;
} SculptThreadedTaskData;
static void paint_mesh_restore_co_task_cb(void *userdata, const int n) static void paint_mesh_restore_co_task_cb(void *userdata, const int n)
{ {
SculptThreadedTaskData *data = userdata; SculptThreadedTaskData *data = userdata;
@@ -601,7 +466,7 @@ static void sculpt_extend_redraw_rect_previous(Object *ob, rcti *rect)
} }
/* Get a screen-space rectangle of the modified area */ /* Get a screen-space rectangle of the modified area */
static bool sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d, bool sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
Object *ob, rcti *rect) Object *ob, rcti *rect)
{ {
PBVH *pbvh = ob->sculpt->pbvh; PBVH *pbvh = ob->sculpt->pbvh;
@@ -650,17 +515,7 @@ void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar, Object *ob)
/************************ Brush Testing *******************/ /************************ Brush Testing *******************/
typedef struct SculptBrushTest { void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
float radius_squared;
float location[3];
float dist;
int mirror_symmetry_pass;
/* View3d clipping - only set rv3d for clipping */
RegionView3D *clip_rv3d;
} SculptBrushTest;
static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
{ {
RegionView3D *rv3d = ss->cache->vc->rv3d; RegionView3D *rv3d = ss->cache->vc->rv3d;
@@ -689,7 +544,7 @@ BLI_INLINE bool sculpt_brush_test_clipping(const SculptBrushTest *test, const fl
return ED_view3d_clipping_test(rv3d, symm_co, true); return ED_view3d_clipping_test(rv3d, symm_co, true);
} }
static bool sculpt_brush_test(SculptBrushTest *test, const float co[3]) bool sculpt_brush_test(SculptBrushTest *test, const float co[3])
{ {
float distsq = len_squared_v3v3(co, test->location); float distsq = len_squared_v3v3(co, test->location);
@@ -705,7 +560,7 @@ static bool sculpt_brush_test(SculptBrushTest *test, const float co[3])
} }
} }
static bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]) bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3])
{ {
float distsq = len_squared_v3v3(co, test->location); float distsq = len_squared_v3v3(co, test->location);
@@ -721,7 +576,7 @@ static bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3])
} }
} }
static bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3]) bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3])
{ {
if (sculpt_brush_test_clipping(test, co)) { if (sculpt_brush_test_clipping(test, co)) {
return 0; return 0;
@@ -729,7 +584,7 @@ static bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3
return len_squared_v3v3(co, test->location) <= test->radius_squared; return len_squared_v3v3(co, test->location) <= test->radius_squared;
} }
static bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4]) bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4])
{ {
float side = M_SQRT1_2; float side = M_SQRT1_2;
float local_co[3]; float local_co[3];
@@ -1237,13 +1092,13 @@ static float brush_strength(
} }
/* Return a multiplier for brush strength on a particular vertex. */ /* Return a multiplier for brush strength on a particular vertex. */
static float tex_strength(SculptSession *ss, Brush *br, float tex_strength(SculptSession *ss, Brush *br,
const float brush_point[3], const float brush_point[3],
const float len, const float len,
const short vno[3], const short vno[3],
const float fno[3], const float fno[3],
const float mask, const float mask,
const int thread_id) const int thread_id)
{ {
StrokeCache *cache = ss->cache; StrokeCache *cache = ss->cache;
const Scene *scene = cache->vc->scene; const Scene *scene = cache->vc->scene;
@@ -1316,15 +1171,8 @@ static float tex_strength(SculptSession *ss, Brush *br,
return avg; return avg;
} }
typedef struct {
Sculpt *sd;
SculptSession *ss;
float radius_squared;
bool original;
} SculptSearchSphereData;
/* Test AABB against sphere */ /* Test AABB against sphere */
static bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v) bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
{ {
SculptSearchSphereData *data = data_v; SculptSearchSphereData *data = data_v;
float *center = data->ss->cache->location, nearest[3]; float *center = data->ss->cache->location, nearest[3];
@@ -1632,6 +1480,22 @@ typedef struct SculptDoBrushSmoothGridDataChunk {
size_t tmpgrid_size; size_t tmpgrid_size;
} SculptDoBrushSmoothGridDataChunk; } SculptDoBrushSmoothGridDataChunk;
typedef struct {
SculptSession *ss;
const float *ray_start, *ray_normal;
bool hit;
float dist;
bool original;
PBVHNode* node;
} SculptRaycastData;
typedef struct {
const float *ray_start, *ray_normal;
bool hit;
float dist;
float detail;
} SculptDetailRaycastData;
static void do_smooth_brush_mesh_task_cb_ex( static void do_smooth_brush_mesh_task_cb_ex(
void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
{ {
@@ -3952,7 +3816,7 @@ static const char *sculpt_tool_name(Sculpt *sd)
* Operator for applying a stroke (various attributes including mouse path) * Operator for applying a stroke (various attributes including mouse path)
* using the current brush. */ * using the current brush. */
static void sculpt_cache_free(StrokeCache *cache) void sculpt_cache_free(StrokeCache *cache)
{ {
if (cache->dial) if (cache->dial)
MEM_freeN(cache->dial); MEM_freeN(cache->dial);
@@ -4405,21 +4269,6 @@ static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob)
} }
} }
typedef struct {
SculptSession *ss;
const float *ray_start, *ray_normal;
bool hit;
float dist;
bool original;
} SculptRaycastData;
typedef struct {
const float *ray_start, *ray_normal;
bool hit;
float dist;
float detail;
} SculptDetailRaycastData;
static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin) static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
{ {
if (BKE_pbvh_node_get_tmin(node) < *tmin) { if (BKE_pbvh_node_get_tmin(node) < *tmin) {
@@ -4444,6 +4293,9 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
{ {
srd->hit = 1; srd->hit = 1;
*tmin = srd->dist; *tmin = srd->dist;
//for vwpaint testing
srd->node = node;
} }
} }
} }
@@ -4528,12 +4380,17 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
srd.dist = dist; srd.dist = dist;
BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd,
ray_start, ray_normal, srd.original); ray_start, ray_normal, srd.original);
copy_v3_v3(out, ray_normal); copy_v3_v3(out, ray_normal);
mul_v3_fl(out, srd.dist); mul_v3_fl(out, srd.dist);
add_v3_v3(out, ray_start); add_v3_v3(out, ray_start);
//used in vwpaint
if (cache && srd.hit){
copy_v3_v3(cache->true_location, out);
}
return srd.hit; return srd.hit;
} }

View File

@@ -38,12 +38,15 @@
#include "DNA_key_types.h" #include "DNA_key_types.h"
#include "BLI_bitmap.h" #include "BLI_bitmap.h"
#include "BLI_threads.h"
#include "BKE_pbvh.h" #include "BKE_pbvh.h"
struct bContext; struct bContext;
struct KeyBlock; struct KeyBlock;
struct Object; struct Object;
struct SculptUndoNode; struct SculptUndoNode;
struct SculptOrigVertData;
int sculpt_mode_poll(struct bContext *C); int sculpt_mode_poll(struct bContext *C);
int sculpt_mode_poll_view3d(struct bContext *C); int sculpt_mode_poll_view3d(struct bContext *C);
@@ -115,6 +118,194 @@ typedef struct SculptUndoNode {
char shapeName[sizeof(((KeyBlock *)0))->name]; char shapeName[sizeof(((KeyBlock *)0))->name];
} SculptUndoNode; } SculptUndoNode;
/* Factor of brush to have rake point following behind
* (could be configurable but this is reasonable default). */
#define SCULPT_RAKE_BRUSH_FACTOR 0.25f
struct SculptRakeData {
float follow_dist;
float follow_co[3];
};
/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */
typedef struct SculptThreadedTaskData {
bContext *C;
struct Sculpt *sd;
struct Object *ob;
struct Brush *brush;
struct PBVHNode **nodes;
int totnode;
struct VPaint *vp;
struct VPaintData *vpd;
struct WPaintData *wpd;
struct WeightPaintInfo *wpi;
unsigned int *lcol;
struct Mesh *me;
/* For passing generic params. */
void *custom_data;
/* Data specific to some callbacks. */
/* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out
* what it is, and memory overhead is ridiculous anyway... */
float flippedbstrength;
float angle;
float strength;
bool smooth_mask;
bool has_bm_orco;
struct SculptProjectVector *spvc;
float *offset;
float *grab_delta;
float *cono;
float *area_no;
float *area_no_sp;
float *area_co;
float(*mat)[4];
float(*vertCos)[3];
/* 0=towards view, 1=flipped */
float(*area_cos)[3];
float(*area_nos)[3];
int *count;
ThreadMutex mutex;
} SculptThreadedTaskData;
/*************** Brush testing declarations ****************/
typedef struct SculptBrushTest {
float radius_squared;
float location[3];
float dist;
int mirror_symmetry_pass;
/* View3d clipping - only set rv3d for clipping */
struct RegionView3D *clip_rv3d;
} SculptBrushTest;
typedef struct {
struct Sculpt *sd;
struct SculptSession *ss;
float radius_squared;
bool original;
} SculptSearchSphereData;
void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test);
bool sculpt_brush_test(SculptBrushTest *test, const float co[3]);
bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]);
bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3]);
bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4]);
bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v);
float tex_strength(
SculptSession *ss, struct Brush *br,
const float point[3],
const float len,
const short vno[3],
const float fno[3],
const float mask,
const int thread_id);
/* Cache stroke properties. Used because
* RNA property lookup isn't particularly fast.
*
* For descriptions of these settings, check the operator properties.
*/
typedef struct StrokeCache {
/* Invariants */
float initial_radius;
float scale[3];
int flag;
float clip_tolerance[3];
float initial_mouse[2];
/* Variants */
float radius;
float radius_squared;
float true_location[3];
float true_last_location[3];
float location[3];
float last_location[3];
bool is_last_valid;
bool pen_flip;
bool invert;
float pressure;
float mouse[2];
float bstrength;
float normal_weight; /* from brush (with optional override) */
/* The rest is temporary storage that isn't saved as a property */
bool first_time; /* Beginning of stroke may do some things special */
/* from ED_view3d_ob_project_mat_get() */
float projection_mat[4][4];
/* Clean this up! */
struct ViewContext *vc;
struct Brush *brush;
float special_rotation;
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3], orig_grab_location[3];
/* screen-space rotation defined by mouse motion */
float rake_rotation[4], rake_rotation_symmetry[4];
bool is_rake_rotation_valid;
struct SculptRakeData rake_data;
/* Symmetry index between 0 and 7 bit combo 0 is Brush only;
* 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
int symmetry;
int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/
float true_view_normal[3];
float view_normal[3];
/* sculpt_normal gets calculated by calc_sculpt_normal(), then the
* sculpt_normal_symm gets updated quickly with the usual symmetry
* transforms */
float sculpt_normal[3];
float sculpt_normal_symm[3];
/* Used for area texture mode, local_mat gets calculated by
* calc_brush_local_mat() and used in tex_strength(). */
float brush_local_mat[4][4];
float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */
int tile_pass;
float last_center[3];
int radial_symmetry_pass;
float symm_rot_mat[4][4];
float symm_rot_mat_inv[4][4];
bool original;
float anchored_location[3];
float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
struct Dial *dial;
char saved_active_brush_name[MAX_ID_NAME];
char saved_mask_brush_tool;
int saved_smooth_size; /* smooth tool copies the size of the current tool */
bool alt_smooth;
float plane_trim_squared;
bool supports_gravity;
float true_gravity_direction[3];
float gravity_direction[3];
rcti previous_r; /* previous redraw rectangle */
rcti current_r; /* current redraw rectangle */
} StrokeCache;
void sculpt_cache_free(StrokeCache *cache);
SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type); SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type);
SculptUndoNode *sculpt_undo_get_node(PBVHNode *node); SculptUndoNode *sculpt_undo_get_node(PBVHNode *node);
void sculpt_undo_push_begin(const char *name); void sculpt_undo_push_begin(const char *name);
@@ -124,6 +315,8 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]);
void sculpt_update_object_bounding_box(struct Object *ob); void sculpt_update_object_bounding_box(struct Object *ob);
bool sculpt_get_redraw_rect(struct ARegion *ar, struct RegionView3D *rv3d, Object *ob, rcti *rect);
#define SCULPT_THREADED_LIMIT 4 #define SCULPT_THREADED_LIMIT 4
#endif #endif

View File

@@ -315,7 +315,9 @@ enum {
PAINT_BLEND_MUL = 3, PAINT_BLEND_MUL = 3,
PAINT_BLEND_BLUR = 4, PAINT_BLEND_BLUR = 4,
PAINT_BLEND_LIGHTEN = 5, PAINT_BLEND_LIGHTEN = 5,
PAINT_BLEND_DARKEN = 6 PAINT_BLEND_DARKEN = 6,
PAINT_BLEND_AVERAGE = 7,
PAINT_BLEND_SMEAR = 8,
}; };
typedef enum { typedef enum {

View File

@@ -723,6 +723,9 @@ typedef enum ObjectMode {
/* any mode where the brush system is used */ /* any mode where the brush system is used */
#define OB_MODE_ALL_PAINT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT) #define OB_MODE_ALL_PAINT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)
/* any mode that uses ob->sculpt */
#define OB_MODE_ALL_SCULPT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)
#define MAX_DUPLI_RECUR 8 #define MAX_DUPLI_RECUR 8
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -1121,13 +1121,8 @@ typedef struct UvSculpt {
/* Vertex Paint */ /* Vertex Paint */
typedef struct VPaint { typedef struct VPaint {
Paint paint; Paint paint;
short flag, pad; short flag, pad;
int tot; /* allocation size of prev buffers */ int radial_symm[3]; /* For mirrored painting */
unsigned int *vpaint_prev; /* previous mesh colors */
struct MDeformVert *wpaint_prev; /* previous vertex weights */
void *paintcursor; /* wm handle */
} VPaint; } VPaint;
/* VPaint.flag */ /* VPaint.flag */

View File

@@ -94,6 +94,8 @@ EnumPropertyItem rna_enum_brush_vertex_tool_items[] = {
{PAINT_BLEND_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", "Blur the color with surrounding values"}, {PAINT_BLEND_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", "Blur the color with surrounding values"},
{PAINT_BLEND_LIGHTEN, "LIGHTEN", ICON_BRUSH_LIGHTEN, "Lighten", "Use lighten blending mode while painting"}, {PAINT_BLEND_LIGHTEN, "LIGHTEN", ICON_BRUSH_LIGHTEN, "Lighten", "Use lighten blending mode while painting"},
{PAINT_BLEND_DARKEN, "DARKEN", ICON_BRUSH_DARKEN, "Darken", "Use darken blending mode while painting"}, {PAINT_BLEND_DARKEN, "DARKEN", ICON_BRUSH_DARKEN, "Darken", "Use darken blending mode while painting"},
{PAINT_BLEND_AVERAGE, "AVERAGE", ICON_BRUSH_BLUR, "Average", "Use average blending mode while painting" },
{PAINT_BLEND_SMEAR, "SMEAR", ICON_BRUSH_BLUR, "Smear", "Use smear blending mode while painting" },
{0, NULL, 0, NULL, NULL} {0, NULL, 0, NULL, NULL}
}; };

View File

@@ -706,6 +706,15 @@ static void rna_def_vertex_paint(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_ONLYVGROUP); RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_ONLYVGROUP);
RNA_def_property_ui_text(prop, "Restrict", "Restrict painting to vertices in the group"); RNA_def_property_ui_text(prop, "Restrict", "Restrict painting to vertices in the group");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
/* Mirroring */
prop = RNA_def_property(srna, "radial_symmetry", PROP_INT, PROP_XYZ);
RNA_def_property_int_sdna(prop, NULL, "radial_symm");
RNA_def_property_int_default(prop, 1);
RNA_def_property_range(prop, 1, 64);
RNA_def_property_ui_range(prop, 1, 32, 1, 1);
RNA_def_property_ui_text(prop, "Radial Symmetry Count X Axis",
"Number of times to copy strokes across the surface");
} }
static void rna_def_image_paint(BlenderRNA *brna) static void rna_def_image_paint(BlenderRNA *brna)

View File

@@ -476,6 +476,34 @@ int BGL_typeSize(int type)
return -1; return -1;
} }
static int gl_buffer_type_from_py_format_char(char format)
{
switch (format) {
case 'b':
return GL_BYTE;
case 'h':
case 'i':
return GL_SHORT;
case 'l':
return GL_INT;
case 'f':
return GL_FLOAT;
case 'd':
return GL_DOUBLE;
}
return -1; /* UNKNOWN */
}
static bool compare_dimensions(int ndim, int *dim1, Py_ssize_t *dim2)
{
for (int i = 0; i < ndim; i++) {
if (dim1[i] != dim2[i]) {
return false;
}
}
return true;
}
/** \} */ /** \} */
@@ -634,6 +662,22 @@ PyTypeObject BGL_bufferType = {
NULL /*tp_del*/ NULL /*tp_del*/
}; };
static Buffer *BGL_MakeBuffer_FromData(PyObject *parent, int type, int ndimensions, int *dimensions, void *buf)
{
Buffer *buffer = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType);
Py_XINCREF(parent);
buffer->parent = parent;
buffer->ndimensions = ndimensions;
buffer->dimensions = MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions");
memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int));
buffer->type = type;
buffer->buf.asvoid = buf;
return buffer;
}
/** /**
* Create a buffer object * Create a buffer object
* *
@@ -645,30 +689,21 @@ Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuf
{ {
Buffer *buffer; Buffer *buffer;
void *buf = NULL; void *buf = NULL;
int i, size, length; int i, size = BGL_typeSize(type);
length = 1;
for (i = 0; i < ndimensions; i++) { for (i = 0; i < ndimensions; i++) {
length *= dimensions[i]; size *= dimensions[i];
} }
size = BGL_typeSize(type); buf = MEM_mallocN(size, "Buffer buffer");
buf = MEM_mallocN(length * size, "Buffer buffer"); buffer = BGL_MakeBuffer_FromData(NULL, type, ndimensions, dimensions, buf);
buffer = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType);
buffer->parent = NULL;
buffer->ndimensions = ndimensions;
buffer->dimensions = MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions");
memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int));
buffer->type = type;
buffer->buf.asvoid = buf;
if (initbuffer) { if (initbuffer) {
memcpy(buffer->buf.asvoid, initbuffer, length * size); memcpy(buffer->buf.asvoid, initbuffer, size);
} }
else { else {
memset(buffer->buf.asvoid, 0, length * size); memset(buffer->buf.asvoid, 0, size);
} }
return buffer; return buffer;
} }
@@ -678,7 +713,7 @@ Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuf
static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
{ {
PyObject *length_ob = NULL, *init = NULL; PyObject *length_ob = NULL, *init = NULL;
Buffer *buffer; Buffer *buffer = NULL;
int dimensions[MAX_DIMENSIONS]; int dimensions[MAX_DIMENSIONS];
int type; int type;
@@ -743,9 +778,32 @@ static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject
return NULL; return NULL;
} }
buffer = BGL_MakeBuffer(type, ndimensions, dimensions, NULL); if (init && PyObject_CheckBuffer(init)) {
if (init && ndimensions) { Py_buffer pybuffer;
if (Buffer_ass_slice(buffer, 0, dimensions[0], init)) {
if (PyObject_GetBuffer(init, &pybuffer, PyBUF_ND | PyBUF_FORMAT) == -1) {
/* PyObject_GetBuffer raise a PyExc_BufferError */
return NULL;
}
if (type != gl_buffer_type_from_py_format_char(*pybuffer.format)) {
PyErr_Format(PyExc_TypeError,
"`GL_TYPE` and `format` of object with buffer interface do not match");
}
else if (ndimensions != pybuffer.ndim ||
!compare_dimensions(ndimensions, dimensions, pybuffer.shape))
{
PyErr_Format(PyExc_TypeError, "array size does not match");
}
else {
buffer = BGL_MakeBuffer_FromData(init, type, pybuffer.ndim, dimensions, pybuffer.buf);
}
PyBuffer_Release(&pybuffer);
}
else {
buffer = BGL_MakeBuffer(type, ndimensions, dimensions, NULL);
if (init && Buffer_ass_slice(buffer, 0, dimensions[0], init)) {
Py_DECREF(buffer); Py_DECREF(buffer);
return NULL; return NULL;
} }
@@ -778,27 +836,17 @@ static PyObject *Buffer_item(Buffer *self, int i)
} }
} }
else { else {
Buffer *newbuf; int j, offset = i * BGL_typeSize(self->type);
int j, length, size;
length = 1;
for (j = 1; j < self->ndimensions; j++) { for (j = 1; j < self->ndimensions; j++) {
length *= self->dimensions[j]; offset *= self->dimensions[j];
} }
size = BGL_typeSize(self->type);
newbuf = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType); return (PyObject *)BGL_MakeBuffer_FromData(
(PyObject *)self, self->type,
Py_INCREF(self); self->ndimensions - 1,
newbuf->parent = (PyObject *)self; self->dimensions + 1,
self->buf.asbyte + offset);
newbuf->ndimensions = self->ndimensions - 1;
newbuf->type = self->type;
newbuf->buf.asvoid = self->buf.asbyte + i * length * size;
newbuf->dimensions = MEM_mallocN(newbuf->ndimensions * sizeof(int), "Buffer dimensions");
memcpy(newbuf->dimensions, self->dimensions + 1, newbuf->ndimensions * sizeof(int));
return (PyObject *)newbuf;
} }
return NULL; return NULL;