ssol_image.c (7062B)
1 /* Copyright (C) 2018-2026 |Meso|Star> (contact@meso-star.com) 2 * Copyright (C) 2016, 2018 CNRS 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17 #define _POSIX_C_SOURCE 200112L /* nextafter support */ 18 19 #include "ssol.h" 20 #include "ssol_image_c.h" 21 #include "ssol_device_c.h" 22 23 #include <rsys/mem_allocator.h> 24 #include <rsys/ref_count.h> 25 #include <rsys/rsys.h> 26 27 #include <math.h> 28 #include <string.h> 29 30 /******************************************************************************* 31 * Helper functions 32 ******************************************************************************/ 33 static INLINE double 34 map_address(const double address, const enum ssol_address_mode mode) 35 { 36 double dbl; 37 double i; 38 switch(mode) { 39 case SSOL_ADDRESS_CLAMP: dbl = CLAMP(address, 0, nextafter(1,0)); break; 40 case SSOL_ADDRESS_REPEAT: 41 dbl = modf(address, &i); 42 if(dbl < 0) dbl = 1.0+dbl; 43 break; 44 default: FATAL("Unreachable code.\n"); break; 45 } 46 return dbl; 47 } 48 49 static INLINE const char* 50 get_pixel(const struct ssol_image* img, const size_t x, const size_t y) 51 { 52 ASSERT(img && x < img->size[0] && y < img->size[1]); 53 return img->mem + y*img->pitch + x*ssol_sizeof_pixel_format(img->format); 54 } 55 56 static void 57 image_release(ref_T* ref) 58 { 59 struct ssol_device* dev; 60 struct ssol_image* image = CONTAINER_OF(ref, struct ssol_image, ref); 61 ASSERT(ref); 62 dev = image->dev; 63 ASSERT(dev && dev->allocator); 64 if(image->mem) MEM_RM(image->dev->allocator, image->mem); 65 MEM_RM(image->dev->allocator, image); 66 SSOL(device_ref_put(dev)); 67 } 68 69 /******************************************************************************* 70 * Exported ssol_image functions 71 ******************************************************************************/ 72 res_T 73 ssol_image_create 74 (struct ssol_device* dev, 75 struct ssol_image** out_image) 76 { 77 struct ssol_image* image = NULL; 78 res_T res = RES_OK; 79 80 if(!dev || !out_image) { 81 return RES_BAD_ARG; 82 } 83 84 image = MEM_CALLOC(dev->allocator, 1, sizeof(struct ssol_image)); 85 if(!image) { 86 res = RES_MEM_ERR; 87 goto error; 88 } 89 90 SSOL(device_ref_get(dev)); 91 image->dev = dev; 92 ref_init(&image->ref); 93 94 exit: 95 if(out_image) *out_image = image; 96 return res; 97 error: 98 if(image) { 99 SSOL(image_ref_put(image)); 100 image = NULL; 101 } 102 goto exit; 103 } 104 105 res_T 106 ssol_image_ref_get(struct ssol_image* image) 107 { 108 if(!image) return RES_BAD_ARG; 109 ref_get(&image->ref); 110 return RES_OK; 111 } 112 113 res_T 114 ssol_image_ref_put(struct ssol_image* image) 115 { 116 if(!image) return RES_BAD_ARG; 117 ref_put(&image->ref, image_release); 118 return RES_OK; 119 } 120 121 res_T 122 ssol_image_setup 123 (struct ssol_image* img, 124 const size_t width, 125 const size_t height, 126 const enum ssol_pixel_format fmt) 127 { 128 size_t pitch; 129 void* mem; 130 131 if(!img || width <= 0 || height <= 0 132 || (unsigned)fmt >= SSOL_PIXEL_FORMATS_COUNT__) { 133 return RES_BAD_ARG; 134 } 135 136 pitch = width * ssol_sizeof_pixel_format(fmt); 137 mem = MEM_ALLOC_ALIGNED(img->dev->allocator, pitch*height, 16); 138 if(!mem) return RES_MEM_ERR; 139 140 if(img->mem) { 141 MEM_RM(img->dev->allocator, img->mem); 142 } 143 img->mem = mem; 144 img->pitch = pitch; 145 img->size[0] = width; 146 img->size[1] = height; 147 img->format = fmt; 148 return RES_OK; 149 } 150 151 res_T 152 ssol_image_get_layout 153 (const struct ssol_image* img, struct ssol_image_layout* layout) 154 { 155 if(!img || !layout) return RES_BAD_ARG; 156 layout->row_pitch = img->pitch; 157 layout->offset = 0; 158 layout->size = img->size[0] * img->size[1]; 159 layout->width = img->size[0]; 160 layout->height = img->size[1]; 161 layout->pixel_format = img->format; 162 return RES_OK; 163 } 164 165 res_T 166 ssol_image_map(const struct ssol_image* img, char** mem) 167 { 168 if(!img || !mem) return RES_BAD_ARG; 169 *mem = img->mem; 170 return RES_OK; 171 } 172 173 res_T ssol_image_unmap(const struct ssol_image* img) 174 { 175 if(!img) return RES_BAD_ARG; 176 /* Do nothing */ 177 return RES_OK; 178 } 179 180 res_T 181 ssol_image_sample 182 (const struct ssol_image* img, 183 const enum ssol_filter_mode filter, 184 const enum ssol_address_mode address_u, 185 const enum ssol_address_mode address_v, 186 const double uv[2], 187 void* val) 188 { 189 double* z00, *z01, *z10, *z11; 190 double x0, y0, x1, y1; 191 double texsz[2]; 192 double s, t; 193 double* pix = val; 194 double integer; 195 196 if(!img || !uv || !val) return RES_BAD_ARG; 197 198 /* Only double3 pixel format is currently supported */ 199 if(img->format != SSOL_PIXEL_DOUBLE3) return RES_BAD_ARG; 200 201 x0 = map_address(uv[0], address_u) * (double)img->size[0]; 202 y0 = map_address(uv[1], address_v) * (double)img->size[1]; 203 204 switch(filter) { 205 case SSOL_FILTER_NEAREST: 206 z00 = (double*)get_pixel(img, (size_t)x0, (size_t)y0); 207 pix[0] = z00[0]; 208 pix[1] = z00[1]; 209 pix[2] = z00[2]; 210 break; 211 case SSOL_FILTER_LINEAR: 212 texsz[0] = 1.0/(double)img->size[0]; 213 texsz[1] = 1.0/(double)img->size[1]; 214 x1 = map_address(uv[0] + texsz[0], address_u) * (double)img->size[0]; 215 y1 = map_address(uv[1] + texsz[1], address_v) * (double)img->size[1]; 216 z00 = (double*)get_pixel(img, (size_t)x0, (size_t)y0); 217 z01 = (double*)get_pixel(img, (size_t)x0, (size_t)y1); 218 z10 = (double*)get_pixel(img, (size_t)x1, (size_t)y0); 219 z11 = (double*)get_pixel(img, (size_t)x1, (size_t)y1); 220 s = modf(x0, &integer); 221 t = modf(y0, &integer); 222 pix[0] = (1-s)*((1-t)*z00[0] + t*z01[0]) + s*((1-t)*z10[0] + t*z11[0]); 223 pix[1] = (1-s)*((1-t)*z00[1] + t*z01[1]) + s*((1-t)*z10[1] + t*z11[1]); 224 pix[2] = (1-s)*((1-t)*z00[2] + t*z01[2]) + s*((1-t)*z10[2] + t*z11[2]); 225 break; 226 default: FATAL("Unreachable code.\n"); break; 227 } 228 return RES_OK; 229 } 230 231 res_T 232 ssol_image_write 233 (void* image, 234 const size_t origin[2], 235 const size_t size[2], 236 const enum ssol_pixel_format fmt, 237 const void* pixels) 238 { 239 struct ssol_image* img = image; 240 const char* src_row = pixels; 241 size_t src_pitch; 242 size_t src_ix; 243 size_t dst_iy; 244 size_t Bpp; 245 246 if(UNLIKELY(!image || !origin || !size || !pixels)) 247 return RES_BAD_ARG; 248 if(UNLIKELY(fmt != img->format || !img->mem)) 249 return RES_BAD_ARG; 250 251 if(UNLIKELY((origin[0] + size[0]) > img->size[0])) 252 return RES_BAD_ARG; 253 if(UNLIKELY((origin[1] + size[1]) > img->size[1])) 254 return RES_BAD_ARG; 255 256 Bpp = ssol_sizeof_pixel_format(img->format); 257 src_pitch = size[0] * Bpp; 258 src_ix = origin[0] * Bpp; 259 260 FOR_EACH(dst_iy, origin[1], origin[1] + size[1]) { 261 const size_t dst_irow = dst_iy * img->pitch + src_ix; 262 memcpy(img->mem + dst_irow, src_row, src_pitch); 263 src_row += src_pitch; 264 } 265 return RES_OK; 266 } 267