Cycles: Adding native support for UINT16 textures.
Textures in 16 bit integer format are sometimes used for displacement, bump and normal maps and can be exported by tools like Substance Painter. Without this patch, Cycles would promote those textures to single precision floating point, causing them to take up twice as much memory as needed. Reviewers: #cycles, brecht, sergey Reviewed By: #cycles, brecht, sergey Subscribers: sergey, dingto, #cycles Tags: #cycles Differential Revision: https://developer.blender.org/D3523
This commit is contained in:
@@ -1072,6 +1072,7 @@ public:
|
||||
CUarray_format_enum format;
|
||||
switch(mem.data_type) {
|
||||
case TYPE_UCHAR: format = CU_AD_FORMAT_UNSIGNED_INT8; break;
|
||||
case TYPE_UINT16: format = CU_AD_FORMAT_UNSIGNED_INT16; break;
|
||||
case TYPE_UINT: format = CU_AD_FORMAT_UNSIGNED_INT32; break;
|
||||
case TYPE_INT: format = CU_AD_FORMAT_SIGNED_INT32; break;
|
||||
case TYPE_FLOAT: format = CU_AD_FORMAT_FLOAT; break;
|
||||
|
@@ -43,6 +43,7 @@ enum MemoryType {
|
||||
enum DataType {
|
||||
TYPE_UNKNOWN,
|
||||
TYPE_UCHAR,
|
||||
TYPE_UINT16,
|
||||
TYPE_UINT,
|
||||
TYPE_INT,
|
||||
TYPE_FLOAT,
|
||||
@@ -57,6 +58,7 @@ static inline size_t datatype_size(DataType datatype)
|
||||
case TYPE_UCHAR: return sizeof(uchar);
|
||||
case TYPE_FLOAT: return sizeof(float);
|
||||
case TYPE_UINT: return sizeof(uint);
|
||||
case TYPE_UINT16: return sizeof(uint16_t);
|
||||
case TYPE_INT: return sizeof(int);
|
||||
case TYPE_HALF: return sizeof(half);
|
||||
case TYPE_UINT64: return sizeof(uint64_t);
|
||||
@@ -156,6 +158,16 @@ template<> struct device_type_traits<half> {
|
||||
static const int num_elements = 1;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<ushort4> {
|
||||
static const DataType data_type = TYPE_UINT16;
|
||||
static const int num_elements = 4;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<uint16_t> {
|
||||
static const DataType data_type = TYPE_UINT16;
|
||||
static const int num_elements = 1;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<half4> {
|
||||
static const DataType data_type = TYPE_HALF;
|
||||
static const int num_elements = 4;
|
||||
|
@@ -287,6 +287,7 @@ set(SRC_UTIL_HEADERS
|
||||
../util/util_types_uint3_impl.h
|
||||
../util/util_types_uint4.h
|
||||
../util/util_types_uint4_impl.h
|
||||
../util/util_types_ushort4.h
|
||||
../util/util_types_vector3.h
|
||||
../util/util_types_vector3_impl.h
|
||||
)
|
||||
|
@@ -35,13 +35,13 @@ template<typename T> struct TextureInterpolator {
|
||||
|
||||
static ccl_always_inline float4 read(uchar4 r)
|
||||
{
|
||||
float f = 1.0f/255.0f;
|
||||
float f = 1.0f / 255.0f;
|
||||
return make_float4(r.x*f, r.y*f, r.z*f, r.w*f);
|
||||
}
|
||||
|
||||
static ccl_always_inline float4 read(uchar r)
|
||||
{
|
||||
float f = r*(1.0f/255.0f);
|
||||
float f = r * (1.0f / 255.0f);
|
||||
return make_float4(f, f, f, 1.0f);
|
||||
}
|
||||
|
||||
@@ -63,6 +63,18 @@ template<typename T> struct TextureInterpolator {
|
||||
return make_float4(f, f, f, 1.0f);
|
||||
}
|
||||
|
||||
static ccl_always_inline float4 read(uint16_t r)
|
||||
{
|
||||
float f = r*(1.0f/65535.0f);
|
||||
return make_float4(f, f, f, 1.0f);
|
||||
}
|
||||
|
||||
static ccl_always_inline float4 read(ushort4 r)
|
||||
{
|
||||
float f = 1.0f/65535.0f;
|
||||
return make_float4(r.x*f, r.y*f, r.z*f, r.w*f);
|
||||
}
|
||||
|
||||
static ccl_always_inline float4 read(const T *data,
|
||||
int x, int y,
|
||||
int width, int height)
|
||||
@@ -481,15 +493,21 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, fl
|
||||
return TextureInterpolator<half>::interp(info, x, y);
|
||||
case IMAGE_DATA_TYPE_BYTE:
|
||||
return TextureInterpolator<uchar>::interp(info, x, y);
|
||||
case IMAGE_DATA_TYPE_USHORT:
|
||||
return TextureInterpolator<uint16_t>::interp(info, x, y);
|
||||
case IMAGE_DATA_TYPE_FLOAT:
|
||||
return TextureInterpolator<float>::interp(info, x, y);
|
||||
case IMAGE_DATA_TYPE_HALF4:
|
||||
return TextureInterpolator<half4>::interp(info, x, y);
|
||||
case IMAGE_DATA_TYPE_BYTE4:
|
||||
return TextureInterpolator<uchar4>::interp(info, x, y);
|
||||
case IMAGE_DATA_TYPE_USHORT4:
|
||||
return TextureInterpolator<ushort4>::interp(info, x, y);
|
||||
case IMAGE_DATA_TYPE_FLOAT4:
|
||||
default:
|
||||
return TextureInterpolator<float4>::interp(info, x, y);
|
||||
default:
|
||||
assert(0);
|
||||
return make_float4(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,15 +520,21 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float x,
|
||||
return TextureInterpolator<half>::interp_3d(info, x, y, z, interp);
|
||||
case IMAGE_DATA_TYPE_BYTE:
|
||||
return TextureInterpolator<uchar>::interp_3d(info, x, y, z, interp);
|
||||
case IMAGE_DATA_TYPE_USHORT:
|
||||
return TextureInterpolator<uint16_t>::interp_3d(info, x, y, z, interp);
|
||||
case IMAGE_DATA_TYPE_FLOAT:
|
||||
return TextureInterpolator<float>::interp_3d(info, x, y, z, interp);
|
||||
case IMAGE_DATA_TYPE_HALF4:
|
||||
return TextureInterpolator<half4>::interp_3d(info, x, y, z, interp);
|
||||
case IMAGE_DATA_TYPE_BYTE4:
|
||||
return TextureInterpolator<uchar4>::interp_3d(info, x, y, z, interp);
|
||||
case IMAGE_DATA_TYPE_USHORT4:
|
||||
return TextureInterpolator<ushort4>::interp_3d(info, x, y, z, interp);
|
||||
case IMAGE_DATA_TYPE_FLOAT4:
|
||||
default:
|
||||
return TextureInterpolator<float4>::interp_3d(info, x, y, z, interp);
|
||||
default:
|
||||
assert(0);
|
||||
return make_float4(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -127,11 +127,12 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, fl
|
||||
const TextureInfo& info = kernel_tex_fetch(__texture_info, id);
|
||||
CUtexObject tex = (CUtexObject)info.data;
|
||||
|
||||
/* float4, byte4 and half4 */
|
||||
/* float4, byte4, ushort4 and half4 */
|
||||
const int texture_type = kernel_tex_type(id);
|
||||
if(texture_type == IMAGE_DATA_TYPE_FLOAT4 ||
|
||||
texture_type == IMAGE_DATA_TYPE_BYTE4 ||
|
||||
texture_type == IMAGE_DATA_TYPE_HALF4)
|
||||
texture_type == IMAGE_DATA_TYPE_HALF4 ||
|
||||
texture_type == IMAGE_DATA_TYPE_USHORT4)
|
||||
{
|
||||
if(info.interpolation == INTERPOLATION_CUBIC) {
|
||||
return kernel_tex_image_interp_bicubic<float4>(info, tex, x, y);
|
||||
@@ -164,7 +165,8 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float x,
|
||||
const int texture_type = kernel_tex_type(id);
|
||||
if(texture_type == IMAGE_DATA_TYPE_FLOAT4 ||
|
||||
texture_type == IMAGE_DATA_TYPE_BYTE4 ||
|
||||
texture_type == IMAGE_DATA_TYPE_HALF4)
|
||||
texture_type == IMAGE_DATA_TYPE_HALF4 ||
|
||||
texture_type == IMAGE_DATA_TYPE_USHORT4)
|
||||
{
|
||||
if(interpolation == INTERPOLATION_CUBIC) {
|
||||
return kernel_tex_image_interp_bicubic_3d<float4>(info, tex, x, y, z);
|
||||
|
@@ -54,11 +54,23 @@ ccl_device_inline float4 svm_image_texture_read(KernelGlobals *kg, const ccl_glo
|
||||
float f = 1.0f/255.0f;
|
||||
return make_float4(r.x*f, r.y*f, r.z*f, r.w*f);
|
||||
}
|
||||
/* Ushort4 */
|
||||
else if(texture_type == IMAGE_DATA_TYPE_USHORT4) {
|
||||
ushort4 r = tex_fetch(ushort4, info, offset);
|
||||
float f = 1.0f/65535.f;
|
||||
return make_float4(r.x*f, r.y*f, r.z*f, r.w*f);
|
||||
}
|
||||
/* Float */
|
||||
else if(texture_type == IMAGE_DATA_TYPE_FLOAT) {
|
||||
float f = tex_fetch(float, info, offset);
|
||||
return make_float4(f, f, f, 1.0f);
|
||||
}
|
||||
/* UShort */
|
||||
else if(texture_type == IMAGE_DATA_TYPE_USHORT) {
|
||||
ushort r = tex_fetch(ushort, info, offset);
|
||||
float f = r * (1.0f / 65535.0f);
|
||||
return make_float4(f, f, f, 1.0f);
|
||||
}
|
||||
/* Byte */
|
||||
else {
|
||||
uchar r = tex_fetch(uchar, info, offset);
|
||||
|
@@ -39,6 +39,10 @@ static bool isfinite(half /*value*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static bool isfinite(uint16_t /*value*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ImageManager::ImageManager(const DeviceInfo& info)
|
||||
{
|
||||
@@ -164,23 +168,27 @@ bool ImageManager::get_image_metadata(const string& filename,
|
||||
metadata.height = spec.height;
|
||||
metadata.depth = spec.depth;
|
||||
|
||||
/* check the main format, and channel formats;
|
||||
* if any take up more than one byte, we'll need a float texture slot */
|
||||
if(spec.format.basesize() > 1) {
|
||||
|
||||
/* Check the main format, and channel formats. */
|
||||
size_t channel_size = spec.format.basesize();
|
||||
|
||||
if(spec.format.is_floating_point()) {
|
||||
metadata.is_float = true;
|
||||
metadata.is_linear = true;
|
||||
}
|
||||
|
||||
for(size_t channel = 0; channel < spec.channelformats.size(); channel++) {
|
||||
if(spec.channelformats[channel].basesize() > 1) {
|
||||
channel_size = max(channel_size, spec.channelformats[channel].basesize());
|
||||
if(spec.channelformats[channel].is_floating_point()) {
|
||||
metadata.is_float = true;
|
||||
metadata.is_linear = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if it's half float */
|
||||
if(spec.format == TypeDesc::HALF)
|
||||
if(spec.format == TypeDesc::HALF) {
|
||||
metadata.is_half = true;
|
||||
}
|
||||
|
||||
/* basic color space detection, not great but better than nothing
|
||||
* before we do OpenColorIO integration */
|
||||
@@ -208,6 +216,9 @@ bool ImageManager::get_image_metadata(const string& filename,
|
||||
else if(metadata.is_float) {
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
|
||||
}
|
||||
else if(spec.format == TypeDesc::USHORT) {
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4 : IMAGE_DATA_TYPE_USHORT;
|
||||
}
|
||||
else {
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
|
||||
}
|
||||
@@ -254,6 +265,10 @@ string ImageManager::name_from_type(int type)
|
||||
return "half4";
|
||||
else if(type == IMAGE_DATA_TYPE_HALF)
|
||||
return "half";
|
||||
else if(type == IMAGE_DATA_TYPE_USHORT)
|
||||
return "ushort";
|
||||
else if(type == IMAGE_DATA_TYPE_USHORT4)
|
||||
return "ushort4";
|
||||
else
|
||||
return "byte4";
|
||||
}
|
||||
@@ -583,7 +598,8 @@ bool ImageManager::file_load_image(Image *img,
|
||||
*/
|
||||
bool is_rgba = (type == IMAGE_DATA_TYPE_FLOAT4 ||
|
||||
type == IMAGE_DATA_TYPE_HALF4 ||
|
||||
type == IMAGE_DATA_TYPE_BYTE4);
|
||||
type == IMAGE_DATA_TYPE_BYTE4 ||
|
||||
type == IMAGE_DATA_TYPE_USHORT4);
|
||||
if(is_rgba) {
|
||||
if(cmyk) {
|
||||
/* CMYK */
|
||||
@@ -843,14 +859,61 @@ void ImageManager::device_load_image(Device *device,
|
||||
thread_scoped_lock device_lock(device_mutex);
|
||||
tex_img->copy_to_device();
|
||||
}
|
||||
else if(type == IMAGE_DATA_TYPE_USHORT) {
|
||||
device_vector<uint16_t> *tex_img
|
||||
= new device_vector<uint16_t>(device, img->mem_name.c_str(), MEM_TEXTURE);
|
||||
|
||||
if(!file_load_image<TypeDesc::USHORT, uint16_t>(img,
|
||||
type,
|
||||
texture_limit,
|
||||
*tex_img)) {
|
||||
/* on failure to load, we set a 1x1 pixels pink image */
|
||||
thread_scoped_lock device_lock(device_mutex);
|
||||
uint16_t *pixels = (uint16_t*)tex_img->alloc(1, 1);
|
||||
|
||||
pixels[0] = TEX_IMAGE_MISSING_R;
|
||||
}
|
||||
|
||||
img->mem = tex_img;
|
||||
img->mem->interpolation = img->interpolation;
|
||||
img->mem->extension = img->extension;
|
||||
|
||||
thread_scoped_lock device_lock(device_mutex);
|
||||
tex_img->copy_to_device();
|
||||
}
|
||||
else if(type == IMAGE_DATA_TYPE_USHORT4) {
|
||||
device_vector<ushort4> *tex_img
|
||||
= new device_vector<ushort4>(device, img->mem_name.c_str(), MEM_TEXTURE);
|
||||
|
||||
if(!file_load_image<TypeDesc::USHORT, uint16_t>(img,
|
||||
type,
|
||||
texture_limit,
|
||||
*tex_img)) {
|
||||
/* on failure to load, we set a 1x1 pixels pink image */
|
||||
thread_scoped_lock device_lock(device_mutex);
|
||||
uint16_t *pixels = (uint16_t*)tex_img->alloc(1, 1);
|
||||
|
||||
pixels[0] = TEX_IMAGE_MISSING_R;
|
||||
pixels[1] = TEX_IMAGE_MISSING_G;
|
||||
pixels[2] = TEX_IMAGE_MISSING_B;
|
||||
pixels[3] = TEX_IMAGE_MISSING_A;
|
||||
}
|
||||
|
||||
img->mem = tex_img;
|
||||
img->mem->interpolation = img->interpolation;
|
||||
img->mem->extension = img->extension;
|
||||
|
||||
thread_scoped_lock device_lock(device_mutex);
|
||||
tex_img->copy_to_device();
|
||||
}
|
||||
else if(type == IMAGE_DATA_TYPE_HALF) {
|
||||
device_vector<half> *tex_img
|
||||
= new device_vector<half>(device, img->mem_name.c_str(), MEM_TEXTURE);
|
||||
|
||||
if(!file_load_image<TypeDesc::HALF, half>(img,
|
||||
type,
|
||||
texture_limit,
|
||||
*tex_img)) {
|
||||
type,
|
||||
texture_limit,
|
||||
*tex_img)) {
|
||||
/* on failure to load, we set a 1x1 pixels pink image */
|
||||
thread_scoped_lock device_lock(device_mutex);
|
||||
half *pixels = (half*)tex_img->alloc(1, 1);
|
||||
@@ -865,7 +928,6 @@ void ImageManager::device_load_image(Device *device,
|
||||
thread_scoped_lock device_lock(device_mutex);
|
||||
tex_img->copy_to_device();
|
||||
}
|
||||
|
||||
img->need_load = false;
|
||||
}
|
||||
|
||||
|
@@ -116,6 +116,7 @@ set(SRC_HEADERS
|
||||
util_types_uint3_impl.h
|
||||
util_types_uint4.h
|
||||
util_types_uint4_impl.h
|
||||
util_types_ushort4.h
|
||||
util_types_vector3.h
|
||||
util_types_vector3_impl.h
|
||||
util_vector.h
|
||||
|
@@ -36,7 +36,16 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* CUDA has its own half data type, no need to define then */
|
||||
#ifndef __KERNEL_CUDA__
|
||||
typedef unsigned short half;
|
||||
/* Implementing this as a class rather than a typedef so that the compiler can tell it apart from unsigned shorts. */
|
||||
class half {
|
||||
public:
|
||||
half() : v(0) {}
|
||||
half(const unsigned short& i) : v(i) {}
|
||||
operator unsigned short() { return v; }
|
||||
half & operator =(const unsigned short& i) { v = i; return *this; }
|
||||
private:
|
||||
unsigned short v;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct half4 { half x, y, z, w; };
|
||||
|
@@ -53,6 +53,11 @@ inline float cast_to_float(uchar value)
|
||||
return (float)value / 255.0f;
|
||||
}
|
||||
template<>
|
||||
inline float cast_to_float(uint16_t value)
|
||||
{
|
||||
return (float)value / 65535.0f;
|
||||
}
|
||||
template<>
|
||||
inline float cast_to_float(half value)
|
||||
{
|
||||
return half_to_float(value);
|
||||
@@ -79,6 +84,17 @@ inline uchar cast_from_float(float value)
|
||||
return (uchar)((255.0f * value) + 0.5f);
|
||||
}
|
||||
template<>
|
||||
inline uint16_t cast_from_float(float value)
|
||||
{
|
||||
if(value < 0.0f) {
|
||||
return 0;
|
||||
}
|
||||
else if(value >(1.0f - 0.5f / 65535.0f)) {
|
||||
return 65535;
|
||||
}
|
||||
return (uchar)((65535.0f * value) + 0.5f);
|
||||
}
|
||||
template<>
|
||||
inline half cast_from_float(float value)
|
||||
{
|
||||
return float_to_half(value);
|
||||
|
@@ -53,6 +53,8 @@ typedef enum ImageDataType {
|
||||
IMAGE_DATA_TYPE_FLOAT = 3,
|
||||
IMAGE_DATA_TYPE_BYTE = 4,
|
||||
IMAGE_DATA_TYPE_HALF = 5,
|
||||
IMAGE_DATA_TYPE_USHORT4 = 6,
|
||||
IMAGE_DATA_TYPE_USHORT = 7,
|
||||
|
||||
IMAGE_DATA_NUM_TYPES
|
||||
} ImageDataType;
|
||||
|
@@ -116,6 +116,8 @@ CCL_NAMESPACE_END
|
||||
#include "util/util_types_uint3.h"
|
||||
#include "util/util_types_uint4.h"
|
||||
|
||||
#include "util/util_types_ushort4.h"
|
||||
|
||||
#include "util/util_types_float2.h"
|
||||
#include "util/util_types_float3.h"
|
||||
#include "util/util_types_float4.h"
|
||||
|
36
intern/cycles/util/util_types_ushort4.h
Normal file
36
intern/cycles/util/util_types_ushort4.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2011-2017 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __UTIL_TYPES_USHORT4_H__
|
||||
#define __UTIL_TYPES_USHORT4_H__
|
||||
|
||||
#ifndef __UTIL_TYPES_H__
|
||||
# error "Do not include this file directly, include util_types.h instead."
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifndef __KERNEL_GPU__
|
||||
|
||||
struct ushort4 {
|
||||
uint16_t x, y, z, w;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __UTIL_TYPES_USHORT4_H__ */
|
Reference in New Issue
Block a user