Cycles: Add support for uchar4 attributes.
authorThomas Dinges <blender@dingto.org>
Fri, 13 Jun 2014 21:40:39 +0000 (23:40 +0200)
committerThomas Dinges <blender@dingto.org>
Fri, 13 Jun 2014 21:40:54 +0000 (23:40 +0200)
* Added support for uchar4 attributes to Cycles' attribute system.
* This is used for Vertex Colors now, which saves some memory (4 unsigned characters, instead of 4 floats).
* GPU Texture Limit on sm_20 and sm_21 decreased from 95 to 94, because we need a new texture for the uchar4 attributes. This is no problem for sm_30 or newer.

Part of my GSoC 2014.

12 files changed:
intern/cycles/blender/blender_curves.cpp
intern/cycles/blender/blender_mesh.cpp
intern/cycles/kernel/geom/geom_triangle.h
intern/cycles/kernel/kernel_textures.h
intern/cycles/kernel/kernel_types.h
intern/cycles/kernel/svm/svm_image.h
intern/cycles/render/attribute.cpp
intern/cycles/render/attribute.h
intern/cycles/render/image.h
intern/cycles/render/mesh.cpp
intern/cycles/render/scene.h
intern/cycles/util/util_color.h

index 22de7b64273466955d62f2fdec62e0250ad52528..7b1a8ec0b1598551f7e0e6e5a86297e95380796c 100644 (file)
@@ -42,7 +42,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData);
 void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, float3 RotCam);
 void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution);
 void ExportCurveTriangleUV(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata);
-void ExportCurveTriangleVcol(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, float3 *fdata);
+void ExportCurveTriangleVcol(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata);
 
 ParticleCurveData::ParticleCurveData()
 {
@@ -726,9 +726,9 @@ void ExportCurveTriangleUV(Mesh *mesh, ParticleCurveData *CData, int vert_offset
        }
 }
 
-void ExportCurveTriangleVcol(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, float3 *fdata)
+void ExportCurveTriangleVcol(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata)
 {
-       if(fdata == NULL)
+       if(cdata == NULL)
                return;
 
        int vertexindex = vert_offset;
@@ -740,17 +740,17 @@ void ExportCurveTriangleVcol(Mesh *mesh, ParticleCurveData *CData, int vert_offs
 
                        for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
                                for(int section = 0; section < resol; section++) {
-                                       fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
+                                       cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
                                        vertexindex++;
-                                       fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
+                                       cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
                                        vertexindex++;
-                                       fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
+                                       cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
                                        vertexindex++;
-                                       fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
+                                       cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
                                        vertexindex++;
-                                       fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
+                                       cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
                                        vertexindex++;
-                                       fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
+                                       cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
                                        vertexindex++;
                                }
                        }
@@ -923,13 +923,12 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
                        ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, !preview, vcol_num);
 
                        if(primitive == CURVE_TRIANGLES) {
-
                                Attribute *attr_vcol = mesh->attributes.add(
-                                       ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER);
+                                       ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
 
-                               float3 *fdata = attr_vcol->data_float3();
+                               uchar4 *cdata = attr_vcol->data_uchar4();
 
-                               ExportCurveTriangleVcol(mesh, &CData, tri_num * 3, used_res, fdata);
+                               ExportCurveTriangleVcol(mesh, &CData, tri_num * 3, used_res, cdata);
                        }
                        else {
                                Attribute *attr_vcol = mesh->curve_attributes.add(
index 27ea552c6a7f1e3667c84701a523ea961c874218..07375484a737f921a29e3b0394f8807c1a00acbb 100644 (file)
@@ -347,25 +347,25 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
                                continue;
 
                        Attribute *attr = mesh->attributes.add(
-                               ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER);
+                               ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
 
                        BL::MeshColorLayer::data_iterator c;
-                       float3 *fdata = attr->data_float3();
+                       uchar4 *cdata = attr->data_uchar4();
                        size_t i = 0;
 
                        for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
-                               fdata[0] = color_srgb_to_scene_linear(get_float3(c->color1()));
-                               fdata[1] = color_srgb_to_scene_linear(get_float3(c->color2()));
-                               fdata[2] = color_srgb_to_scene_linear(get_float3(c->color3()));
+                               cdata[0] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color1())));
+                               cdata[1] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color2())));
+                               cdata[2] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color3())));
 
                                if(nverts[i] == 4) {
-                                       fdata[3] = fdata[0];
-                                       fdata[4] = fdata[2];
-                                       fdata[5] = color_srgb_to_scene_linear(get_float3(c->color4()));
-                                       fdata += 6;
+                                       cdata[3] = cdata[0];
+                                       cdata[4] = cdata[2];
+                                       cdata[5] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4())));
+                                       cdata += 6;
                                }
                                else
-                                       fdata += 3;
+                                       cdata += 3;
                        }
                }
        }
index 4ee5d5aa6d5c59eeeec5c2844ed2eea4a144e274..f2f35c2efd01efb46e6fcdfd875489cc10e108a4 100644 (file)
@@ -259,11 +259,20 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData
 
                return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
        }
-       else if(elem == ATTR_ELEMENT_CORNER) {
+       else if(elem == ATTR_ELEMENT_CORNER || elem == ATTR_ELEMENT_CORNER_BYTE) {
                int tri = offset + sd->prim*3;
-               float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0));
-               float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1));
-               float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2));
+               float3 f0, f1, f2;
+
+               if(elem == ATTR_ELEMENT_CORNER) {
+                       f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0));
+                       f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1));
+                       f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2));
+               }
+               else {
+                       f0 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, tri + 0));
+                       f1 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, tri + 1));
+                       f2 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, tri + 2));
+               }
 
 #ifdef __RAY_DIFFERENTIALS__
                if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
index dfef8ed9c663d98c4807be9e610031221fe34e00..55960701318e80f4290e8656f0e425dfe4c9080c 100644 (file)
@@ -49,6 +49,7 @@ KERNEL_TEX(float4, texture_float4, __curve_keys)
 KERNEL_TEX(uint4, texture_uint4, __attributes_map)
 KERNEL_TEX(float, texture_float, __attributes_float)
 KERNEL_TEX(float4, texture_float4, __attributes_float3)
+KERNEL_TEX(uchar4, texture_uchar4, __attributes_uchar4)
 
 /* lights */
 KERNEL_TEX(float4, texture_float4, __light_distribution)
index 7edbf5ab172287ecb0d6cba6df2ab987dcef9dfa..f5c73b72c49dbdb99adc4439b26519ec3110faad 100644 (file)
@@ -478,6 +478,7 @@ typedef enum AttributeElement {
        ATTR_ELEMENT_VERTEX,
        ATTR_ELEMENT_VERTEX_MOTION,
        ATTR_ELEMENT_CORNER,
+       ATTR_ELEMENT_CORNER_BYTE,
        ATTR_ELEMENT_CURVE,
        ATTR_ELEMENT_CURVE_KEY,
        ATTR_ELEMENT_CURVE_KEY_MOTION,
index b34c101f5e75fea9506d89cbbb178679240105fb..a7abeda18e55d336fd8262348217c3bcf0a11f50 100644 (file)
@@ -252,9 +252,9 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
                case 96: r = kernel_tex_image_interp(__tex_image_096, 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_098, x, y); break;
-               case 99: r = kernel_tex_image_interp(__tex_image_099, x, y); break;
 
 #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 300)
+               case 99: r = kernel_tex_image_interp(__tex_image_099, x, y); break;
                case 100: r = kernel_tex_image_interp(__tex_image_100, x, y); break;
                case 101: r = kernel_tex_image_interp(__tex_image_101, x, y); break;
                case 102: r = kernel_tex_image_interp(__tex_image_102, x, y); break;
index 72781bb0f9be16a5a63ce6d66f66768a8e9db6f0..8abf869a77568dae0144ff2f247dcf3c55c9a4e9 100644 (file)
@@ -69,6 +69,15 @@ void Attribute::add(const float& f)
                buffer.push_back(data[i]);
 }
 
+void Attribute::add(const uchar4& f)
+{
+       char *data = (char*)&f;
+       size_t size = sizeof(f);
+
+       for(size_t i = 0; i < size; i++)
+               buffer.push_back(data[i]);
+}
+
 void Attribute::add(const float3& f)
 {
        char *data = (char*)&f;
@@ -136,6 +145,7 @@ size_t Attribute::element_size(int numverts, int numtris, int numsteps, int numc
                        size = numtris;
                        break;
                case ATTR_ELEMENT_CORNER:
+               case ATTR_ELEMENT_CORNER_BYTE:
                        size = numtris*3;
                        break;
                case ATTR_ELEMENT_CURVE:
index 9fc32db844454720cc5c0efbfd27c93ac994c62e..f5227ebde52ece9b45826b362da0a4a77306f7fe 100644 (file)
@@ -68,6 +68,7 @@ public:
        float3 *data_float3() { return (float3*)data(); }
        float4 *data_float4() { return (float4*)data(); }
        float *data_float() { return (float*)data(); }
+       uchar4 *data_uchar4() { return (uchar4*)data(); }
        Transform *data_transform() { return (Transform*)data(); }
        VoxelAttribute *data_voxel()  { return ( VoxelAttribute*)data(); }
 
@@ -80,6 +81,7 @@ public:
 
        void add(const float& f);
        void add(const float3& f);
+       void add(const uchar4& f);
        void add(const Transform& f);
        void add(const VoxelAttribute& f);
        void add(const char *data);
index 8abf2a33d7447932075ae13173c8f99daaceea67..3eacfa7beedbc5ddd303fea1e940c691eb1658a4 100644 (file)
@@ -29,7 +29,7 @@
 CCL_NAMESPACE_BEGIN
 
 /* generic */
-#define TEX_NUM_IMAGES                 95
+#define TEX_NUM_IMAGES                 94
 #define TEX_IMAGE_BYTE_START   TEX_NUM_FLOAT_IMAGES
 
 /* extended gpu */
index b6826f0066bf83b3e25628530df50939c053babd..808db4fe5b27a1b79e9db2b1ea13b7a5d5c99d3f 100644 (file)
@@ -745,7 +745,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
        device->tex_alloc("__attributes_map", dscene->attributes_map);
 }
 
-static void update_attribute_element_offset(Mesh *mesh, vector<float>& attr_float, vector<float4>& attr_float3,
+static void update_attribute_element_offset(Mesh *mesh, vector<float>& attr_float, vector<float4>& attr_float3, vector<uchar4>& attr_uchar4,
        Attribute *mattr, TypeDesc& type, int& offset, AttributeElement& element)
 {
        if(mattr) {
@@ -766,6 +766,15 @@ static void update_attribute_element_offset(Mesh *mesh, vector<float>& attr_floa
                        VoxelAttribute *voxel_data = mattr->data_voxel();
                        offset = voxel_data->slot;
                }
+               if(mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
+                       uchar4 *data = mattr->data_uchar4();
+                       offset = attr_uchar4.size();
+
+                       attr_uchar4.resize(attr_uchar4.size() + size);
+
+                       for(size_t k = 0; k < size; k++)
+                               attr_uchar4[offset+k] = data[k];
+               }
                else if(mattr->type == TypeDesc::TypeFloat) {
                        float *data = mattr->data_float();
                        offset = attr_float.size();
@@ -802,7 +811,7 @@ static void update_attribute_element_offset(Mesh *mesh, vector<float>& attr_floa
                        offset -= mesh->vert_offset;
                else if(element == ATTR_ELEMENT_FACE)
                        offset -= mesh->tri_offset;
-               else if(element == ATTR_ELEMENT_CORNER)
+               else if(element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE)
                        offset -= 3*mesh->tri_offset;
                else if(element == ATTR_ELEMENT_CURVE)
                        offset -= mesh->curve_offset;
@@ -843,6 +852,7 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
         * maps next */
        vector<float> attr_float;
        vector<float4> attr_float3;
+       vector<uchar4> attr_uchar4;
 
        for(size_t i = 0; i < scene->meshes.size(); i++) {
                Mesh *mesh = scene->meshes[i];
@@ -863,10 +873,10 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
                                        memcpy(triangle_mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size());
                        }
 
-                       update_attribute_element_offset(mesh, attr_float, attr_float3, triangle_mattr,
+                       update_attribute_element_offset(mesh, attr_float, attr_float3, attr_uchar4, triangle_mattr,
                                req.triangle_type, req.triangle_offset, req.triangle_element);
 
-                       update_attribute_element_offset(mesh, attr_float, attr_float3, curve_mattr,
+                       update_attribute_element_offset(mesh, attr_float, attr_float3, attr_uchar4, curve_mattr,
                                req.curve_type, req.curve_offset, req.curve_element);
        
                        if(progress.get_cancel()) return;
@@ -892,6 +902,10 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
                dscene->attributes_float3.copy(&attr_float3[0], attr_float3.size());
                device->tex_alloc("__attributes_float3", dscene->attributes_float3);
        }
+       if(attr_uchar4.size()) {
+               dscene->attributes_uchar4.copy(&attr_uchar4[0], attr_uchar4.size());
+               device->tex_alloc("__attributes_uchar4", dscene->attributes_uchar4);
+       }
 }
 
 void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
index 777d26ac79ea29f7e82c1014872d42bc94e733dc..e5c7444c92da18a1e3047ec81ff825b798a13499 100644 (file)
@@ -85,6 +85,7 @@ public:
        device_vector<uint4> attributes_map;
        device_vector<float> attributes_float;
        device_vector<float4> attributes_float3;
+       device_vector<uchar4> attributes_uchar4;
 
        /* lights */
        device_vector<float4> light_distribution;
index d566e1bf359e220f0efd078e5930fe21b68eb783..d362c8abe25ec56c523dc8209a3bda8db13b54ec 100644 (file)
 
 CCL_NAMESPACE_BEGIN
 
+ccl_device uchar float_to_byte(float val)
+{
+       return ((val <= 0.0f) ? 0 : (((val) > (1.0f - 0.5f / 255.0f)) ? 255 : ((255.0f * (val)) + 0.5f)));
+}
+
+ccl_device uchar4 color_float_to_byte(float3 c)
+{
+       uchar r, g, b;
+
+       r = float_to_byte(c.x);
+       g = float_to_byte(c.y);
+       b = float_to_byte(c.z);
+
+       return make_uchar4(r, g, b, 0);
+}
+
+ccl_device_inline float3 color_byte_to_float(uchar4 c)
+{
+       return make_float3(c.x*(1.0f/255.0f), c.y*(1.0f/255.0f), c.z*(1.0f/255.0f));
+}
+
 ccl_device float color_srgb_to_scene_linear(float c)
 {
        if(c < 0.04045f)