ssol_draw.c (5222B)
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 #include "ssol.h" 18 #include "ssol_device_c.h" 19 #include "ssol_draw.h" 20 #include "ssol_scene_c.h" 21 22 #include <star/s3d.h> 23 24 #include <omp.h> 25 #include <star/ssf.h> 26 #include <star/ssp.h> 27 28 #define TILE_SIZE 32 /* definition in X & Y of a tile */ 29 STATIC_ASSERT(IS_POW2(TILE_SIZE), TILE_SIZE_must_be_a_power_of_2); 30 31 /******************************************************************************* 32 * Helper function 33 ******************************************************************************/ 34 static FINLINE uint16_t 35 morton2D_decode(const uint32_t u32) 36 { 37 uint32_t x = u32 & 0x55555555; 38 x = (x | (x >> 1)) & 0x33333333; 39 x = (x | (x >> 2)) & 0x0F0F0F0F; 40 x = (x | (x >> 4)) & 0x00FF00FF; 41 x = (x | (x >> 8)) & 0x0000FFFF; 42 return (uint16_t)x; 43 } 44 45 static void 46 draw_tile 47 (struct ssol_scene* scn, 48 struct s3d_scene_view* view, 49 const struct ssol_camera* cam, 50 const int ithread, 51 const size_t spp, 52 const size_t origin[2], /* Tile origin */ 53 const size_t size[2], /* Tile definition */ 54 const float pix_sz[2], /* Normalized size of a pixel in the image plane */ 55 double* pixels, 56 pixel_shader_T shader, 57 void* shader_data) 58 { 59 size_t npixels; 60 size_t mcode; /* Morton code of the tile pixel */ 61 ASSERT(scn && view && cam && spp && origin && size && pix_sz && pixels); 62 ASSERT(shader); 63 64 /* Adjust the #pixels to process them wrt a morton order */ 65 npixels = round_up_pow2(MMAX(size[0], size[1])); 66 npixels *= npixels; 67 68 FOR_EACH(mcode, 0, npixels) { 69 size_t ipix[2]; 70 double* pixel; 71 72 ipix[0] = morton2D_decode((uint32_t)(mcode>>0)); 73 if(ipix[0] >= size[0]) continue; 74 ipix[1] = morton2D_decode((uint32_t)(mcode>>1)); 75 if(ipix[1] >= size[1]) continue; 76 77 pixel = pixels + (ipix[1]*size[0] + ipix[0])*3/*#channels*/; 78 ipix[0] = ipix[0] + origin[0]; 79 ipix[1] = ipix[1] + origin[1]; 80 81 shader(scn, cam, view, ithread, ipix, pix_sz, spp, pixel, shader_data); 82 } 83 } 84 85 /******************************************************************************* 86 * Local function 87 ******************************************************************************/ 88 res_T 89 draw 90 (struct ssol_scene* scn, 91 const struct ssol_camera* cam, 92 const size_t width, 93 const size_t height, 94 const size_t spp, /* #samples per pixel */ 95 ssol_write_pixels_T writer, 96 void* writer_data, 97 pixel_shader_T pixel_shader, 98 void* pixel_shader_data) 99 { 100 struct s3d_scene_view* view = NULL; 101 struct darray_byte* tiles = NULL; 102 int64_t mcode; /* Morton code of a tile */ 103 float pix_sz[2]; 104 size_t ntiles_x, ntiles_y, ntiles; 105 size_t i; 106 ATOMIC res = RES_OK; 107 108 if(!scn || !cam || !width || !height || !spp || !writer || !pixel_shader) 109 return RES_BAD_ARG; 110 111 tiles = darray_tile_data_get(&scn->dev->tiles); 112 ASSERT(darray_tile_size_get(&scn->dev->tiles) == scn->dev->nthreads); 113 FOR_EACH(i, 0, scn->dev->nthreads) { 114 const size_t sizeof_tile = TILE_SIZE * TILE_SIZE * sizeof(double[3]); 115 res = darray_byte_resize(tiles+i, sizeof_tile); 116 if(res != RES_OK) goto error; 117 } 118 119 ntiles_x = (width + (TILE_SIZE-1)/*ceil*/)/TILE_SIZE; 120 ntiles_y = (height+ (TILE_SIZE-1)/*ceil*/)/TILE_SIZE; 121 ntiles = round_up_pow2(MMAX(ntiles_x, ntiles_y)); 122 ntiles *= ntiles; 123 124 pix_sz[0] = 1.f / (float)width; 125 pix_sz[1] = 1.f / (float)height; 126 127 res = s3d_scene_view_create(scn->scn_rt, S3D_TRACE, &view); 128 if(res != RES_OK) goto error; 129 130 #pragma omp parallel for schedule(dynamic, 1/*chunck size*/) 131 for(mcode=0; mcode<(int64_t)ntiles; ++mcode) { 132 size_t tile_org[2]; 133 size_t tile_sz[2]; 134 const int ithread = omp_get_thread_num(); 135 double* pixels; 136 res_T res_local; 137 138 if(ATOMIC_GET(&res) != RES_OK) continue; 139 140 tile_org[0] = morton2D_decode((uint32_t)(mcode>>0)); 141 if(tile_org[0] >= ntiles_x) continue; 142 tile_org[1] = morton2D_decode((uint32_t)(mcode>>1)); 143 if(tile_org[1] >= ntiles_y) continue; 144 145 tile_org[0] *= TILE_SIZE; 146 tile_org[1] *= TILE_SIZE; 147 tile_sz[0] = MMIN(TILE_SIZE, width - tile_org[0]); 148 tile_sz[1] = MMIN(TILE_SIZE, height- tile_org[1]); 149 150 pixels = (double*)darray_byte_data_get(tiles+ithread); 151 152 draw_tile(scn, view, cam, ithread, spp, tile_org, tile_sz, pix_sz, pixels, 153 pixel_shader, pixel_shader_data); 154 155 res_local = writer(writer_data, tile_org, tile_sz, SSOL_PIXEL_DOUBLE3, pixels); 156 if(res_local != RES_OK) { 157 ATOMIC_SET(&res, res_local); 158 continue; 159 } 160 } 161 162 exit: 163 if(view) S3D(scene_view_ref_put(view)); 164 return (res_T)res; 165 error: 166 goto exit; 167 } 168 169