1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 **************************************************************************/
27 // File: vogl_threaded_resampler.cpp
28 #include "vogl_core.h"
29 #include "vogl_threaded_resampler.h"
30 #include "vogl_resample_filters.h"
31 #include "vogl_threading.h"
35 threaded_resampler::threaded_resampler(task_pool &tp)
44 threaded_resampler::~threaded_resampler()
49 void threaded_resampler::free_contrib_lists()
53 vogl_free(m_pX_contribs->p);
54 m_pX_contribs->p = NULL;
56 vogl_free(m_pX_contribs);
62 vogl_free(m_pY_contribs->p);
63 m_pY_contribs->p = NULL;
65 vogl_free(m_pY_contribs);
70 void threaded_resampler::resample_x_task(uint64_t data, void *pData_ptr)
72 VOGL_NOTE_UNUSED(pData_ptr);
73 const uint thread_index = (uint)data;
75 for (uint src_y = 0; src_y < m_pParams->m_src_height; src_y++)
77 if (m_pTask_pool->get_num_threads())
79 if ((src_y % (m_pTask_pool->get_num_threads() + 1)) != thread_index)
83 const Resampler::Contrib_List *pContribs = m_pX_contribs;
84 const Resampler::Contrib_List *pContribs_end = m_pX_contribs + m_pParams->m_dst_width;
86 switch (m_pParams->m_fmt)
90 const float *pSrc = reinterpret_cast<const float *>(static_cast<const uint8 *>(m_pParams->m_pSrc_pixels) + m_pParams->m_src_pitch * src_y);
91 vec4F *pDst = m_tmp_img.get_ptr() + m_pParams->m_dst_width * src_y;
95 const Resampler::Contrib *p = pContribs->p;
96 const Resampler::Contrib *p_end = pContribs->p + pContribs->n;
102 const uint src_pixel = p->pixel;
103 const float src_weight = p->weight;
105 s[0] += pSrc[src_pixel] * src_weight;
112 } while (pContribs != pContribs_end);
118 const vec4F *pSrc = reinterpret_cast<const vec4F *>(static_cast<const uint8 *>(m_pParams->m_pSrc_pixels) + m_pParams->m_src_pitch * src_y);
119 vec4F *pDst = m_tmp_img.get_ptr() + m_pParams->m_dst_width * src_y;
123 const Resampler::Contrib *p = pContribs->p;
124 const Resampler::Contrib *p_end = pContribs->p + pContribs->n;
130 const float src_weight = p->weight;
132 const vec4F &src_pixel = pSrc[p->pixel];
134 s[0] += src_pixel[0] * src_weight;
135 s[1] += src_pixel[1] * src_weight;
136 s[2] += src_pixel[2] * src_weight;
143 } while (pContribs != pContribs_end);
149 const vec4F *pSrc = reinterpret_cast<const vec4F *>(static_cast<const uint8 *>(m_pParams->m_pSrc_pixels) + m_pParams->m_src_pitch * src_y);
150 vec4F *pDst = m_tmp_img.get_ptr() + m_pParams->m_dst_width * src_y;
154 Resampler::Contrib *p = pContribs->p;
155 Resampler::Contrib *p_end = pContribs->p + pContribs->n;
161 const float src_weight = p->weight;
163 const vec4F &src_pixel = pSrc[p->pixel];
165 s[0] += src_pixel[0] * src_weight;
166 s[1] += src_pixel[1] * src_weight;
167 s[2] += src_pixel[2] * src_weight;
168 s[3] += src_pixel[3] * src_weight;
175 } while (pContribs != pContribs_end);
185 void threaded_resampler::resample_y_task(uint64_t data, void *pData_ptr)
187 VOGL_NOTE_UNUSED(pData_ptr);
189 const uint thread_index = (uint)data;
191 vogl::vector<vec4F> tmp(m_pParams->m_dst_width);
193 for (uint dst_y = 0; dst_y < m_pParams->m_dst_height; dst_y++)
195 if (m_pTask_pool->get_num_threads())
197 if ((dst_y % (m_pTask_pool->get_num_threads() + 1)) != thread_index)
201 const Resampler::Contrib_List &contribs = m_pY_contribs[dst_y];
207 pSrc = m_tmp_img.get_ptr() + m_pParams->m_dst_width * contribs.p[0].pixel;
211 for (uint src_y_iter = 0; src_y_iter < contribs.n; src_y_iter++)
213 const vec4F *p = m_tmp_img.get_ptr() + m_pParams->m_dst_width * contribs.p[src_y_iter].pixel;
214 const float weight = contribs.p[src_y_iter].weight;
218 for (uint i = 0; i < m_pParams->m_dst_width; i++)
219 tmp[i] = p[i] * weight;
223 for (uint i = 0; i < m_pParams->m_dst_width; i++)
224 tmp[i] += p[i] * weight;
228 pSrc = tmp.get_ptr();
231 const vec4F *pSrc_end = pSrc + m_pParams->m_dst_width;
233 const float l = m_pParams->m_sample_low;
234 const float h = m_pParams->m_sample_high;
236 switch (m_pParams->m_fmt)
240 float *pDst = reinterpret_cast<float *>(static_cast<uint8 *>(m_pParams->m_pDst_pixels) + m_pParams->m_dst_pitch * dst_y);
244 *pDst++ = math::clamp((*pSrc)[0], l, h);
248 } while (pSrc != pSrc_end);
254 vec4F *pDst = reinterpret_cast<vec4F *>(static_cast<uint8 *>(m_pParams->m_pDst_pixels) + m_pParams->m_dst_pitch * dst_y);
258 (*pDst)[0] = math::clamp((*pSrc)[0], l, h);
259 (*pDst)[1] = math::clamp((*pSrc)[1], l, h);
260 (*pDst)[2] = math::clamp((*pSrc)[2], l, h);
266 } while (pSrc != pSrc_end);
272 vec4F *pDst = reinterpret_cast<vec4F *>(static_cast<uint8 *>(m_pParams->m_pDst_pixels) + m_pParams->m_dst_pitch * dst_y);
276 (*pDst)[0] = math::clamp((*pSrc)[0], l, h);
277 (*pDst)[1] = math::clamp((*pSrc)[1], l, h);
278 (*pDst)[2] = math::clamp((*pSrc)[2], l, h);
279 (*pDst)[3] = math::clamp((*pSrc)[3], l, h);
284 } while (pSrc != pSrc_end);
294 bool threaded_resampler::resample(const params &p)
296 free_contrib_lists();
300 VOGL_ASSERT(m_pParams->m_src_width && m_pParams->m_src_height);
301 VOGL_ASSERT(m_pParams->m_dst_width && m_pParams->m_dst_height);
306 m_bytes_per_pixel = 4;
310 m_bytes_per_pixel = 16;
317 int filter_index = find_resample_filter(p.m_Pfilter_name);
318 if (filter_index < 0)
321 const resample_filter &filter = g_resample_filters[filter_index];
323 m_pX_contribs = Resampler::make_clist(m_pParams->m_src_width, m_pParams->m_dst_width, m_pParams->m_boundary_op, filter.func, filter.support, p.m_filter_x_scale, p.m_x_ofs);
327 m_pY_contribs = Resampler::make_clist(m_pParams->m_src_height, m_pParams->m_dst_height, m_pParams->m_boundary_op, filter.func, filter.support, p.m_filter_y_scale, p.m_y_ofs);
331 if (!m_tmp_img.try_resize(m_pParams->m_dst_width * m_pParams->m_src_height))
334 for (uint i = 0; i <= m_pTask_pool->get_num_threads(); i++)
335 m_pTask_pool->queue_object_task(this, &threaded_resampler::resample_x_task, i, NULL);
336 m_pTask_pool->join();
338 for (uint i = 0; i <= m_pTask_pool->get_num_threads(); i++)
339 m_pTask_pool->queue_object_task(this, &threaded_resampler::resample_y_task, i, NULL);
340 m_pTask_pool->join();
343 free_contrib_lists();