solstice-solver

Solver library of the solstice app
git clone git://git.meso-star.com/solstice-solver.git
Log | Files | Refs | README | LICENSE

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