aboutsummaryrefslogtreecommitdiff
path: root/modules/gles/gl_blender.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gles/gl_blender.cpp')
-rw-r--r--modules/gles/gl_blender.cpp852
1 files changed, 852 insertions, 0 deletions
diff --git a/modules/gles/gl_blender.cpp b/modules/gles/gl_blender.cpp
new file mode 100644
index 0000000..7f83a47
--- /dev/null
+++ b/modules/gles/gl_blender.cpp
@@ -0,0 +1,852 @@
+/*
+ * gl_blender.cpp - gl blender implementation
+ *
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "xcam_utils.h"
+#include "image_file_handle.h"
+#include "gl_utils.h"
+#include "gl_video_buffer.h"
+#include "gl_blender_shaders_priv.h"
+#include "gl_blender.h"
+#include <map>
+
+#define OVERLAP_POOL_SIZE 6
+#define LAP_POOL_SIZE 4
+
+#define GAUSS_RADIUS 2
+#define GAUSS_DIAMETER ((GAUSS_RADIUS)*2+1)
+
+const float gauss_coeffs[GAUSS_DIAMETER] = {0.152f, 0.222f, 0.252f, 0.222f, 0.152f};
+
+#define DUMP_BUFFER 0
+
+#define CHECK_RET(ret, format, ...) \
+ if ((ret) < XCAM_RETURN_NO_ERROR) { \
+ XCAM_LOG_ERROR (format, ## __VA_ARGS__); \
+ }
+
+namespace XCam {
+
+using namespace XCamGLShaders;
+
+#if DUMP_BUFFER
+#define dump_buf dump_buf_perfix_path
+
+static void
+dump_level_buf (const SmartPtr<VideoBuffer> &buf, const char *name, uint32_t level, uint32_t idx)
+{
+ XCAM_ASSERT (name);
+
+ char file_name[256];
+ snprintf (file_name, 256, "%s-L%d-Idx%d", name, level, idx);
+ dump_buf_perfix_path (buf, file_name);
+}
+#else
+static void
+dump_level_buf (const SmartPtr<VideoBuffer> &buf, ...) {
+ XCAM_UNUSED (buf);
+}
+
+static void
+dump_buf (const SmartPtr<VideoBuffer> &buf, ...) {
+ XCAM_UNUSED (buf);
+}
+#endif
+
+DECLARE_WORK_CALLBACK (CbGaussScalePyr, GLBlender, gauss_scale_done);
+DECLARE_WORK_CALLBACK (CbLapTransPyr, GLBlender, lap_trans_done);
+DECLARE_WORK_CALLBACK (CbBlendPyr, GLBlender, blend_done);
+DECLARE_WORK_CALLBACK (CbReconstructPyr, GLBlender, reconstruct_done);
+
+namespace GLBlenderPriv {
+
+typedef std::map<void*, SmartPtr<GLBlendPyrShader::Args>> MapBlendArgs;
+typedef std::map<void*, SmartPtr<GLReconstructPyrShader::Args>> MapReconstructArgs;
+
+struct PyramidResource {
+ SmartPtr<BufferPool> overlap_pool;
+ SmartPtr<GLGaussScalePyrShader> gauss_scale[GLBlender::BufIdxCount];
+ SmartPtr<GLLapTransPyrShader> lap_trans[GLBlender::BufIdxCount];
+ SmartPtr<GLReconstructPyrShader> reconstruct;
+ SmartPtr<GLBuffer> coef_mask;
+ MapReconstructArgs reconstruct_args;
+};
+
+class BlenderPrivConfig {
+public:
+ PyramidResource pyr_layer[XCAM_GL_PYRAMID_MAX_LEVEL];
+ uint32_t pyr_levels;
+
+ SmartPtr<GLBlendPyrShader> top_level_blend;
+ SmartPtr<BufferPool> first_lap_pool;
+ SmartPtr<GLBuffer> first_mask;
+
+ Mutex map_args_mutex;
+ MapBlendArgs blend_args;
+
+private:
+ GLBlender *_blender;
+ SmartPtr<GLComputeProgram> _sync_prog;
+
+public:
+ BlenderPrivConfig (GLBlender *blender, uint32_t level)
+ : pyr_levels (level - 1)
+ , _blender (blender)
+ {
+ XCAM_ASSERT (level >= 2 && level <= XCAM_GL_PYRAMID_MAX_LEVEL);
+ }
+
+ XCamReturn init_first_masks (uint32_t width, uint32_t height);
+ XCamReturn scale_down_masks (uint32_t level, uint32_t width, uint32_t height);
+
+ XCamReturn start_gauss_scale (
+ const SmartPtr<ImageHandler::Parameters> &param,
+ const SmartPtr<VideoBuffer> &in_buf,
+ uint32_t level, GLBlender::BufIdx idx);
+
+ XCamReturn start_lap_trans (
+ const SmartPtr<ImageHandler::Parameters> &param,
+ const SmartPtr<GLGaussScalePyrShader::Args> &gauss_scale_args,
+ uint32_t level, GLBlender::BufIdx idx);
+
+ XCamReturn start_blend (
+ const SmartPtr<ImageHandler::Parameters> &param,
+ const SmartPtr<VideoBuffer> &buf, GLBlender::BufIdx idx);
+
+ XCamReturn start_reconstruct_by_lap (
+ const SmartPtr<ImageHandler::Parameters> &param,
+ const SmartPtr<VideoBuffer> &lap,
+ uint32_t level, GLBlender::BufIdx idx);
+ XCamReturn start_reconstruct_by_gauss (
+ const SmartPtr<ImageHandler::Parameters> &param,
+ const SmartPtr<VideoBuffer> &prev_blend_buf, uint32_t level);
+ XCamReturn start_reconstruct (const SmartPtr<GLReconstructPyrShader::Args> &args, uint32_t level);
+ XCamReturn stop ();
+
+ const SmartPtr<GLComputeProgram> &get_sync_prog ();
+};
+
+XCamReturn
+BlenderPrivConfig::stop ()
+{
+ for (uint32_t i = 0; i < pyr_levels; ++i) {
+ pyr_layer[i].gauss_scale[GLBlender::Idx0].release ();
+ pyr_layer[i].gauss_scale[GLBlender::Idx1].release ();
+ pyr_layer[i].lap_trans[GLBlender::Idx0].release ();
+ pyr_layer[i].lap_trans[GLBlender::Idx1].release ();
+ pyr_layer[i].reconstruct.release ();
+
+ if (pyr_layer[i].overlap_pool.ptr ()) {
+ pyr_layer[i].overlap_pool->stop ();
+ }
+ }
+
+ top_level_blend.release ();
+ if (first_lap_pool.ptr ()) {
+ first_lap_pool->stop ();
+ }
+
+ return XCAM_RETURN_NO_ERROR;
+}
+
+const SmartPtr<GLComputeProgram> &
+BlenderPrivConfig::get_sync_prog ()
+{
+ if (_sync_prog.ptr ())
+ return _sync_prog;
+
+ _sync_prog = GLComputeProgram::create_compute_program ("sync_program");
+ XCAM_FAIL_RETURN (ERROR, _sync_prog.ptr (), _sync_prog, "create sync program failed");
+
+ return _sync_prog;
+}
+
+XCamReturn
+BlenderPrivConfig::init_first_masks (uint32_t width, uint32_t height)
+{
+ XCAM_ASSERT (!first_mask.ptr ());
+ XCAM_ASSERT (width && (width % GL_BLENDER_ALIGN_X == 0));
+ XCAM_FAIL_RETURN (
+ ERROR, height == 1, XCAM_RETURN_ERROR_PARAM,
+ "blender(%s) mask buffer only supports one-dimensional array", XCAM_STR (_blender->get_name ()));
+
+ uint32_t buf_size = width * sizeof (uint8_t);
+ SmartPtr<GLBuffer> buf = GLBuffer::create_buffer (GL_SHADER_STORAGE_BUFFER, NULL, buf_size);
+ XCAM_ASSERT (buf.ptr ());
+
+ GLBufferDesc desc;
+ desc.width = width;
+ desc.height = 1;
+ desc.size = buf_size;
+ buf->set_buffer_desc (desc);
+
+ std::vector<float> gauss_table;
+ uint32_t quater = width / 4;
+ XCAM_ASSERT (quater > 1);
+
+ get_gauss_table (quater, (quater + 1) / 4.0f, gauss_table, false);
+ for (uint32_t i = 0; i < gauss_table.size (); ++i) {
+ float value = ((i < quater) ? (128.0f * (2.0f - gauss_table[i])) : (128.0f * gauss_table[i]));
+ value = XCAM_CLAMP (value, 0.0f, 255.0f);
+ gauss_table[i] = value;
+ }
+
+ uint8_t *mask_ptr = (uint8_t *) buf->map_range (0, buf_size, GL_MAP_WRITE_BIT);
+ XCAM_FAIL_RETURN (ERROR, mask_ptr, XCAM_RETURN_ERROR_PARAM, "map range failed");
+
+ uint32_t gauss_start_pos = (width - gauss_table.size ()) / 2;
+ uint32_t idx = 0;
+ for (idx = 0; idx < gauss_start_pos; ++idx) {
+ mask_ptr[idx] = 255;
+ }
+ for (uint32_t i = 0; i < gauss_table.size (); ++idx, ++i) {
+ mask_ptr[idx] = (uint8_t) gauss_table[i];
+ }
+ for (; idx < width; ++idx) {
+ mask_ptr[idx] = 0;
+ }
+ buf->unmap ();
+
+ first_mask = buf;
+
+ return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderPrivConfig::scale_down_masks (uint32_t level, uint32_t width, uint32_t height)
+{
+ XCAM_ASSERT (width && (width % GL_BLENDER_ALIGN_X == 0));
+ XCAM_FAIL_RETURN (
+ ERROR, height == 1, XCAM_RETURN_ERROR_PARAM,
+ "blender(%s) mask buffer only supports one-dimensional array", XCAM_STR (_blender->get_name ()));
+
+ uint32_t buf_size = width * sizeof (uint8_t);
+ SmartPtr<GLBuffer> buf = GLBuffer::create_buffer (GL_SHADER_STORAGE_BUFFER, NULL, buf_size);
+ XCAM_ASSERT (buf.ptr ());
+
+ GLBufferDesc desc;
+ desc.width = width;
+ desc.height = 1;
+ desc.size = buf_size;
+ buf->set_buffer_desc (desc);
+
+ SmartPtr<GLBuffer> prev_mask;
+ if (level == 0) {
+ prev_mask = first_mask;
+ } else {
+ prev_mask = pyr_layer[level - 1].coef_mask;
+ }
+ XCAM_ASSERT (prev_mask.ptr ());
+
+ const GLBufferDesc prev_desc = prev_mask->get_buffer_desc ();
+ uint8_t *prev_ptr = (uint8_t *) prev_mask->map_range (0, prev_desc.size, GL_MAP_READ_BIT);
+ XCAM_FAIL_RETURN (ERROR, prev_ptr, XCAM_RETURN_ERROR_PARAM, "map range failed");
+
+ uint8_t *cur_ptr = (uint8_t *) buf->map_range (0, desc.size, GL_MAP_WRITE_BIT);
+ XCAM_FAIL_RETURN (ERROR, cur_ptr, XCAM_RETURN_ERROR_PARAM, "map range failed");
+
+ for (uint32_t i = 0; i < desc.width; ++i) {
+ int prev_start = i * 2 - 2;
+ float sum = 0.0f;
+
+ for (int j = 0; j < GAUSS_DIAMETER; ++j) {
+ int prev_idx = XCAM_CLAMP (prev_start + j, 0, (int)prev_desc.width);
+ sum += prev_ptr[prev_idx] * gauss_coeffs[j];
+ }
+
+ cur_ptr[i] = XCAM_CLAMP (sum, 0.0f, 255.0f);
+ }
+
+ buf->unmap ();
+ prev_mask->unmap ();
+
+ pyr_layer[level].coef_mask = buf;
+
+ return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderPrivConfig::start_gauss_scale (
+ const SmartPtr<ImageHandler::Parameters> &param,
+ const SmartPtr<VideoBuffer> &in_buf,
+ uint32_t level, GLBlender::BufIdx idx)
+{
+ XCAM_ASSERT (in_buf.ptr ());
+ XCAM_ASSERT (level < pyr_levels);
+ XCAM_ASSERT (idx < GLBlender::BufIdxCount);
+ XCAM_ASSERT (pyr_layer[level].gauss_scale[idx].ptr ());
+ XCAM_ASSERT (pyr_layer[level].overlap_pool.ptr ());
+
+ SmartPtr<VideoBuffer> out_buf = pyr_layer[level].overlap_pool->get_buffer ();
+ XCAM_FAIL_RETURN (
+ ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM,
+ "blender(%s) start_gauss_scale failed, output buffer is empty, level:%d, idx:%d",
+ XCAM_STR (_blender->get_name ()), level, (int)idx);
+
+ SmartPtr<GLGaussScalePyrShader::Args> args = new GLGaussScalePyrShader::Args (param, level, idx);
+ XCAM_ASSERT (args.ptr ());
+ args->in_glbuf = get_glbuffer (in_buf);
+ args->out_glbuf = get_glbuffer (out_buf);
+ args->out_video_buf = out_buf;
+
+ if (level == 0) {
+ const Rect area = _blender->get_input_merge_area (idx);
+ XCAM_FAIL_RETURN (
+ ERROR,
+ area.pos_y == 0 && area.width && area.height &&
+ area.pos_x % GL_BLENDER_ALIGN_X == 0 &&
+ area.width % GL_BLENDER_ALIGN_X == 0 &&
+ area.height % GL_BLENDER_ALIGN_Y == 0,
+ XCAM_RETURN_ERROR_PARAM,
+ "blender(%s) invalid input merge area, pos_x:%d, pos_y:%d, width:%d, height:%d, level:%d, idx:%d",
+ XCAM_STR (_blender->get_name ()), area.pos_x, area.pos_y, area.width, area.height, level, (int)idx);
+
+ args->merge_area = area;
+ } else {
+ const VideoBufferInfo &info = in_buf->get_video_info ();
+ XCAM_FAIL_RETURN (
+ ERROR,
+ info.width && info.height &&
+ info.width % GL_BLENDER_ALIGN_X == 0 &&
+ info.height % GL_BLENDER_ALIGN_Y == 0,
+ XCAM_RETURN_ERROR_PARAM,
+ "blender(%s) invalid buffer info, width:%d, height:%d, level:%d, idx:%d",
+ XCAM_STR (_blender->get_name ()), info.width, info.height, level, (int)idx);
+
+ args->merge_area = Rect (0, 0, info.width, info.height);
+ }
+
+ return pyr_layer[level].gauss_scale[idx]->work (args);
+}
+
+XCamReturn
+BlenderPrivConfig::start_lap_trans (
+ const SmartPtr<ImageHandler::Parameters> &param,
+ const SmartPtr<GLGaussScalePyrShader::Args> &gauss_scale_args,
+ uint32_t level, GLBlender::BufIdx idx)
+{
+ XCAM_ASSERT (level < pyr_levels);
+ XCAM_ASSERT (pyr_layer[level].lap_trans[idx].ptr ());
+ XCAM_ASSERT (idx < GLBlender::BufIdxCount);
+
+ SmartPtr<VideoBuffer> out_buf;
+ if (level == 0) {
+ XCAM_ASSERT (first_lap_pool.ptr ());
+ out_buf = first_lap_pool->get_buffer ();
+ } else {
+ XCAM_ASSERT (pyr_layer[level - 1].overlap_pool.ptr ());
+ out_buf = pyr_layer[level - 1].overlap_pool->get_buffer ();
+ }
+ XCAM_FAIL_RETURN (
+ ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM,
+ "blender(%s) start_lap_trans failed, output buffer is empty, level:%d, idx:%d",
+ XCAM_STR (_blender->get_name ()), level, (int)idx);
+
+ SmartPtr<GLLapTransPyrShader::Args> args = new GLLapTransPyrShader::Args (param, level, idx);
+ XCAM_ASSERT (args.ptr ());
+ args->in_glbuf = gauss_scale_args->in_glbuf;
+ args->gaussscale_glbuf = gauss_scale_args->out_glbuf;
+ args->out_glbuf = get_glbuffer (out_buf);
+ args->merge_area = gauss_scale_args->merge_area;
+ args->out_video_buf = out_buf;
+
+ return pyr_layer[level].lap_trans[idx]->work (args);
+}
+
+XCamReturn
+BlenderPrivConfig::start_blend (
+ const SmartPtr<ImageHandler::Parameters> &param,
+ const SmartPtr<VideoBuffer> &buf, GLBlender::BufIdx idx)
+{
+ XCAM_ASSERT (idx < GLBlender::BufIdxCount);
+ XCAM_ASSERT (top_level_blend.ptr ());
+
+ uint32_t top_level = pyr_levels - 1;
+ XCAM_ASSERT (pyr_layer[top_level].overlap_pool.ptr ());
+ XCAM_ASSERT (pyr_layer[top_level].coef_mask.ptr ());
+
+ SmartPtr<GLBlendPyrShader::Args> args;
+ {
+ SmartLock locker (map_args_mutex);
+ MapBlendArgs::iterator i = blend_args.find (param.ptr ());
+ if (i == blend_args.end ()) {
+ args = new GLBlendPyrShader::Args (param);
+ XCAM_ASSERT (args.ptr ());
+ blend_args.insert (std::make_pair((void*)param.ptr (), args));
+ XCAM_LOG_DEBUG ("blender(%s) init blend args, idx:%d", XCAM_STR (_blender->get_name ()), (int)idx);
+ } else {
+ args = (*i).second;
+ }
+
+ if (idx == GLBlender::Idx0) {
+ args->in0_glbuf = get_glbuffer (buf);
+ } else {
+ args->in1_glbuf = get_glbuffer (buf);
+ }
+
+ if (!args->in0_glbuf.ptr () || !args->in1_glbuf.ptr ())
+ return XCAM_RETURN_BYPASS;
+
+ blend_args.erase (i);
+ }
+
+ args->mask_glbuf = pyr_layer[top_level].coef_mask;
+
+ SmartPtr<VideoBuffer> out_buf = pyr_layer[top_level].overlap_pool->get_buffer ();
+ XCAM_FAIL_RETURN (
+ ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM,
+ "blender(%s) start_blend failed, output buffer is empty, idx:%d",
+ XCAM_STR (_blender->get_name ()), (int)idx);
+ args->out_glbuf = get_glbuffer (out_buf);
+ args->out_video_buf = out_buf;
+
+ return top_level_blend->work (args);
+}
+
+XCamReturn
+BlenderPrivConfig::start_reconstruct (
+ const SmartPtr<GLReconstructPyrShader::Args> &args, uint32_t level)
+{
+ XCAM_ASSERT (args.ptr ());
+ XCAM_ASSERT (level < pyr_levels);
+ XCAM_ASSERT (pyr_layer[level].reconstruct.ptr ());
+ XCAM_ASSERT (args->lap0_glbuf.ptr () && args->lap1_glbuf.ptr () && args->prev_blend_glbuf.ptr ());
+
+ SmartPtr<VideoBuffer> out_buf;
+ if (level == 0) {
+ const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+ XCAM_ASSERT (param.ptr () && param->out_buf.ptr ());
+ out_buf = param->out_buf;
+
+ XCAM_ASSERT (first_mask.ptr ());
+ args->mask_glbuf = first_mask;
+
+ const Rect area = _blender->get_merge_window ();
+ XCAM_FAIL_RETURN (
+ ERROR,
+ area.pos_y == 0 && area.width && area.height &&
+ area.pos_x % GL_BLENDER_ALIGN_X == 0 &&
+ area.width % GL_BLENDER_ALIGN_X == 0 &&
+ area.height % GL_BLENDER_ALIGN_Y == 0,
+ XCAM_RETURN_ERROR_PARAM,
+ "blender(%s) invalid output merge area, pos_x:%d, pos_y:%d, width:%d, height:%d, level:%d",
+ XCAM_STR (_blender->get_name ()), area.pos_x, area.pos_y, area.width, area.height, level);
+
+ args->merge_area = area;
+ } else {
+ out_buf = pyr_layer[level - 1].overlap_pool->get_buffer ();
+ XCAM_FAIL_RETURN (
+ ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM,
+ "blender(%s) start_reconstruct failed, out buffer is empty, level:%d",
+ XCAM_STR (_blender->get_name ()), level);
+
+ XCAM_ASSERT (pyr_layer[level - 1].coef_mask.ptr ());
+ args->mask_glbuf = pyr_layer[level - 1].coef_mask;
+
+ const VideoBufferInfo &info = out_buf->get_video_info ();
+ XCAM_FAIL_RETURN (
+ ERROR,
+ info.width && info.height &&
+ info.width % GL_BLENDER_ALIGN_X == 0 &&
+ info.height % GL_BLENDER_ALIGN_Y == 0,
+ XCAM_RETURN_ERROR_PARAM,
+ "blender(%s) invalid buffer info, width:%d, height:%d, level:%d",
+ XCAM_STR (_blender->get_name ()), info.width, info.height, level);
+
+ args->merge_area = Rect (0, 0, info.width, info.height);
+ }
+ args->out_glbuf = get_glbuffer (out_buf);
+ args->out_video_buf = out_buf;
+
+ return pyr_layer[level].reconstruct->work (args);
+}
+
+XCamReturn
+BlenderPrivConfig::start_reconstruct_by_gauss (
+ const SmartPtr<ImageHandler::Parameters> &param,
+ const SmartPtr<VideoBuffer> &prev_blend_buf, uint32_t level)
+{
+ XCAM_ASSERT (prev_blend_buf.ptr ());
+ XCAM_ASSERT (level < pyr_levels);
+
+ SmartPtr<GLReconstructPyrShader::Args> args;
+ {
+ SmartLock locker (map_args_mutex);
+ MapReconstructArgs::iterator i = pyr_layer[level].reconstruct_args.find (param.ptr ());
+ if (i == pyr_layer[level].reconstruct_args.end ()) {
+ args = new GLReconstructPyrShader::Args (param, level);
+ XCAM_ASSERT (args.ptr ());
+ pyr_layer[level].reconstruct_args.insert (std::make_pair((void*)param.ptr (), args));
+ XCAM_LOG_DEBUG ("blender(%s) init reconstruct_args, level:%d", XCAM_STR (_blender->get_name ()), level);
+ } else {
+ args = (*i).second;
+ }
+
+ args->prev_blend_glbuf = get_glbuffer (prev_blend_buf);
+
+ if (!args->lap0_glbuf.ptr () || !args->lap1_glbuf.ptr ())
+ return XCAM_RETURN_BYPASS;
+
+ pyr_layer[level].reconstruct_args.erase (i);
+ }
+
+ return start_reconstruct (args, level);
+}
+
+XCamReturn
+BlenderPrivConfig::start_reconstruct_by_lap (
+ const SmartPtr<ImageHandler::Parameters> &param,
+ const SmartPtr<VideoBuffer> &lap,
+ uint32_t level, GLBlender::BufIdx idx)
+{
+ XCAM_ASSERT (lap.ptr ());
+ XCAM_ASSERT (level < pyr_levels);
+ XCAM_ASSERT (idx < GLBlender::BufIdxCount);
+
+ SmartPtr<GLReconstructPyrShader::Args> args;
+ {
+ SmartLock locker (map_args_mutex);
+ MapReconstructArgs::iterator i = pyr_layer[level].reconstruct_args.find (param.ptr ());
+ if (i == pyr_layer[level].reconstruct_args.end ()) {
+ args = new GLReconstructPyrShader::Args (param, level);
+ XCAM_ASSERT (args.ptr ());
+ pyr_layer[level].reconstruct_args.insert (std::make_pair((void*)param.ptr (), args));
+ XCAM_LOG_DEBUG ("blender(%s) init reconstruct_args, level:%d", XCAM_STR (_blender->get_name ()), level);
+ } else {
+ args = (*i).second;
+ }
+
+ if (idx == GLBlender::Idx0)
+ args->lap0_glbuf = get_glbuffer (lap);
+ else
+ args->lap1_glbuf = get_glbuffer (lap);
+
+ if (!args->lap0_glbuf.ptr () || !args->lap1_glbuf.ptr () || !args->prev_blend_glbuf.ptr ())
+ return XCAM_RETURN_BYPASS;
+
+ pyr_layer[level].reconstruct_args.erase (i);
+ }
+
+ return start_reconstruct (args, level);
+}
+
+}
+
+GLBlender::GLBlender (const char *name)
+ : GLImageHandler (name)
+ , Blender (GL_BLENDER_ALIGN_X, GL_BLENDER_ALIGN_Y)
+{
+ SmartPtr<GLBlenderPriv::BlenderPrivConfig> config =
+ new GLBlenderPriv::BlenderPrivConfig (this, XCAM_GL_PYRAMID_DEFAULT_LEVEL);
+ XCAM_ASSERT (config.ptr ());
+ _priv_config = config;
+}
+
+GLBlender::~GLBlender ()
+{
+}
+
+XCamReturn
+GLBlender::finish ()
+{
+ const SmartPtr<GLComputeProgram> prog = _priv_config->get_sync_prog ();
+ XCAM_ASSERT (prog.ptr ());
+ prog->finish ();
+
+ return GLImageHandler::finish ();
+}
+
+XCamReturn
+GLBlender::terminate ()
+{
+ _priv_config->stop ();
+ return GLImageHandler::terminate ();
+}
+
+XCamReturn
+GLBlender::blend (
+ const SmartPtr<VideoBuffer> &in0,
+ const SmartPtr<VideoBuffer> &in1,
+ SmartPtr<VideoBuffer> &out_buf)
+{
+ XCAM_ASSERT (in0.ptr () && in1.ptr ());
+
+ SmartPtr<BlenderParam> param = new BlenderParam (in0, in1, out_buf);
+ XCAM_ASSERT (param.ptr ());
+
+ XCamReturn ret = execute_buffer (param, true);
+
+ finish ();
+ if (xcam_ret_is_ok (ret) && !out_buf.ptr ()) {
+ out_buf = param->out_buf;
+ }
+
+ return ret;
+}
+
+XCamReturn
+GLBlender::start_work (const SmartPtr<ImageHandler::Parameters> &base)
+{
+ XCAM_ASSERT (base.ptr ());
+ SmartPtr<BlenderParam> param = base.dynamic_cast_ptr<BlenderParam> ();
+ XCAM_ASSERT (param.ptr ());
+ XCAM_ASSERT (param->in_buf.ptr () && param->in1_buf.ptr () && param->out_buf.ptr ());
+
+ dump_level_buf (param->in_buf, "input", 0, 0);
+ dump_level_buf (param->in1_buf, "input", 0, 1);
+
+ // start gauss scale level:0 idx:0
+ XCamReturn ret = _priv_config->start_gauss_scale (param, param->in_buf, 0, GLBlender::Idx0);
+ XCAM_FAIL_RETURN (
+ ERROR, xcam_ret_is_ok (ret), ret,
+ "blender(%s) start gauss scale failed, level:0 idx:0", XCAM_STR (get_name ()));
+
+ // start gauss scale level:0 idx:1
+ ret = _priv_config->start_gauss_scale (param, param->in1_buf, 0, GLBlender::Idx1);
+ XCAM_FAIL_RETURN (
+ ERROR, xcam_ret_is_ok (ret), ret,
+ "blender(%s) start gauss scale failed, level:0 idx:1", XCAM_STR (get_name ()));
+
+ return ret;
+};
+
+XCamReturn
+GLBlender::configure_resource (const SmartPtr<Parameters> &param)
+{
+ XCAM_ASSERT (param.ptr () && param->in_buf.ptr ());
+ XCAM_ASSERT (_priv_config->pyr_levels <= XCAM_GL_PYRAMID_MAX_LEVEL);
+
+ const VideoBufferInfo &in0_info = param->in_buf->get_video_info ();
+ XCAM_FAIL_RETURN (
+ ERROR, in0_info.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM,
+ "blender(%s) only support NV12 format, but input format is %s",
+ XCAM_STR(get_name ()), xcam_fourcc_to_string (in0_info.format));
+
+ Rect in0_area, in1_area, out_area;
+ in0_area = get_input_merge_area (Idx0);
+ in1_area = get_input_merge_area (Idx1);
+ out_area = get_merge_window ();
+ XCAM_FAIL_RETURN (
+ ERROR,
+ in0_area.width && in0_area.height &&
+ in0_area.width == in1_area.width && in0_area.height == in1_area.height &&
+ in0_area.width == out_area.width && in0_area.height == out_area.height,
+ XCAM_RETURN_ERROR_PARAM,
+ "blender(%s) invalid input/output overlap area, input0:%dx%d, input1:%dx%d, output:%dx%d",
+ XCAM_STR(get_name ()), in0_area.width, in0_area.height,
+ in1_area.width, in1_area.height, out_area.width, out_area.height);
+
+ VideoBufferInfo out_info;
+ uint32_t out_width, out_height;
+ get_output_size (out_width, out_height);
+ XCAM_FAIL_RETURN (
+ ERROR, out_width && out_height, XCAM_RETURN_ERROR_PARAM,
+ "blender(%s) invalid output size, output size:%dx%d",
+ XCAM_STR(get_name ()), out_width, out_height);
+
+ out_info.init (
+ in0_info.format, out_width, out_height,
+ XCAM_ALIGN_UP (out_width, GL_BLENDER_ALIGN_X), XCAM_ALIGN_UP (out_height, GL_BLENDER_ALIGN_Y));
+ set_out_video_info (out_info);
+
+ VideoBufferInfo overlap_info;
+ Rect merge_size = get_merge_window ();
+ XCAM_FAIL_RETURN (
+ ERROR,
+ merge_size.width && merge_size.height &&
+ merge_size.width % GL_BLENDER_ALIGN_X == 0 &&
+ merge_size.height % GL_BLENDER_ALIGN_Y == 0,
+ XCAM_RETURN_ERROR_PARAM,
+ "blender(%s) invalid merge size, width:%d, height:%d",
+ XCAM_STR (get_name ()), merge_size.width, merge_size.height);
+
+ overlap_info.init (in0_info.format, merge_size.width, merge_size.height);
+ SmartPtr<BufferPool> first_lap_pool = new GLVideoBufferPool (overlap_info);
+ XCAM_ASSERT (first_lap_pool.ptr ());
+ XCAM_FAIL_RETURN (
+ ERROR, first_lap_pool->reserve (LAP_POOL_SIZE), XCAM_RETURN_ERROR_MEM,
+ "blender(%s) reserve lap buffer pool failed, overlap size:%dx%d",
+ XCAM_STR(get_name ()), overlap_info.width, overlap_info.height);
+ _priv_config->first_lap_pool = first_lap_pool;
+
+ SmartPtr<Worker::Callback> gauss_scale_cb = new CbGaussScalePyr (this);
+ SmartPtr<Worker::Callback> lap_trans_cb = new CbLapTransPyr (this);
+ SmartPtr<Worker::Callback> reconstruct_cb = new CbReconstructPyr (this);
+ XCAM_ASSERT (gauss_scale_cb.ptr () && lap_trans_cb.ptr () && reconstruct_cb.ptr ());
+
+ XCamReturn ret = _priv_config->init_first_masks (merge_size.width, 1);
+ XCAM_FAIL_RETURN (
+ ERROR, xcam_ret_is_ok (ret), ret,
+ "blender(%s) init first masks failed", XCAM_STR (get_name ()));
+
+ for (uint32_t i = 0; i < _priv_config->pyr_levels; ++i) {
+ merge_size.width = XCAM_ALIGN_UP ((merge_size.width + 1) / 2, GL_BLENDER_ALIGN_X);
+ merge_size.height = XCAM_ALIGN_UP ((merge_size.height + 1) / 2, GL_BLENDER_ALIGN_Y);
+ overlap_info.init (in0_info.format, merge_size.width, merge_size.height);
+
+ SmartPtr<BufferPool> pool = new GLVideoBufferPool (overlap_info);
+ XCAM_ASSERT (pool.ptr ());
+ XCAM_FAIL_RETURN (
+ ERROR, pool->reserve (OVERLAP_POOL_SIZE), XCAM_RETURN_ERROR_MEM,
+ "blender(%s) reserve buffer pool failed, overlap size:%dx%d",
+ XCAM_STR(get_name ()), overlap_info.width, overlap_info.height);
+ _priv_config->pyr_layer[i].overlap_pool = pool;
+
+ ret = _priv_config->scale_down_masks (i, merge_size.width, 1);
+ XCAM_FAIL_RETURN (
+ ERROR, xcam_ret_is_ok (ret), ret,
+ "blender(%s) scale down masks failed, level:%d", XCAM_STR (get_name ()), i);
+
+ _priv_config->pyr_layer[i].gauss_scale[GLBlender::Idx0] = create_gauss_scale_pyr_shader (gauss_scale_cb);
+ XCAM_ASSERT (_priv_config->pyr_layer[i].gauss_scale[GLBlender::Idx0].ptr ());
+ _priv_config->pyr_layer[i].gauss_scale[GLBlender::Idx1] = create_gauss_scale_pyr_shader (gauss_scale_cb);
+ XCAM_ASSERT (_priv_config->pyr_layer[i].gauss_scale[GLBlender::Idx1].ptr ());
+ _priv_config->pyr_layer[i].lap_trans[GLBlender::Idx0] = create_lap_trans_pyr_shader (lap_trans_cb);
+ XCAM_ASSERT (_priv_config->pyr_layer[i].lap_trans[GLBlender::Idx0].ptr ());
+ _priv_config->pyr_layer[i].lap_trans[GLBlender::Idx1] = create_lap_trans_pyr_shader (lap_trans_cb);
+ XCAM_ASSERT (_priv_config->pyr_layer[i].lap_trans[GLBlender::Idx1].ptr ());
+ _priv_config->pyr_layer[i].reconstruct = create_reconstruct_pyr_shader (reconstruct_cb);
+ XCAM_ASSERT (_priv_config->pyr_layer[i].reconstruct.ptr ());
+ }
+
+ SmartPtr<Worker::Callback> blend_cb = new CbBlendPyr (this);
+ XCAM_ASSERT (blend_cb.ptr ());
+ _priv_config->top_level_blend = create_blend_pyr_shader (blend_cb);
+ XCAM_ASSERT (_priv_config->top_level_blend.ptr ());
+
+ return XCAM_RETURN_NO_ERROR;
+}
+
+void
+GLBlender::gauss_scale_done (
+ const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+ XCAM_UNUSED (worker);
+ XCAM_UNUSED (error);
+ XCAM_ASSERT (base.ptr ());
+
+ SmartPtr<GLGaussScalePyrShader::Args> args = base.dynamic_cast_ptr<GLGaussScalePyrShader::Args> ();
+ XCAM_ASSERT (args.ptr ());
+ uint32_t level = args->level;
+ XCAM_ASSERT (level < _priv_config->pyr_levels);
+ uint32_t next_level = level + 1;
+ BufIdx idx = args->idx;
+
+ const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+ XCAM_ASSERT (param.ptr ());
+
+ dump_level_buf (args->out_video_buf, "gauss-scale", level, idx);
+
+ XCamReturn ret = _priv_config->start_lap_trans (param, args, level, idx);
+ CHECK_RET (ret, "execute laplace transformation failed, level:%d idx:%d", level, idx);
+
+ if (next_level == _priv_config->pyr_levels) { // top level
+ ret = _priv_config->start_blend (param, args->out_video_buf, idx);
+ CHECK_RET (ret, "execute blend failed, level:%d idx:%d", next_level, idx);
+ } else {
+ ret = _priv_config->start_gauss_scale (param, args->out_video_buf, next_level, idx);
+ CHECK_RET (ret, "execute gauss scale failed, level:%d idx:%d", next_level, idx);
+ }
+}
+
+void
+GLBlender::lap_trans_done (
+ const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+ XCAM_UNUSED (worker);
+ XCAM_UNUSED (error);
+ XCAM_ASSERT (base.ptr ());
+
+ SmartPtr<GLLapTransPyrShader::Args> args = base.dynamic_cast_ptr<GLLapTransPyrShader::Args> ();
+ XCAM_ASSERT (args.ptr ());
+ uint32_t level = args->level;
+ XCAM_ASSERT (level < _priv_config->pyr_levels);
+ BufIdx idx = args->idx;
+
+ const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+ XCAM_ASSERT (param.ptr ());
+
+ dump_level_buf (args->out_video_buf, "lap", level, idx);
+
+ XCamReturn ret = _priv_config->start_reconstruct_by_lap (param, args->out_video_buf, level, idx);
+ CHECK_RET (ret, "execute reconstruct by lap failed, level:%d idx:%d", level, idx);
+}
+
+void
+GLBlender::blend_done (
+ const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+ XCAM_UNUSED (worker);
+ XCAM_UNUSED (error);
+ XCAM_ASSERT (base.ptr ());
+
+ SmartPtr<GLBlendPyrShader::Args> args = base.dynamic_cast_ptr<GLBlendPyrShader::Args> ();
+ XCAM_ASSERT (args.ptr ());
+ const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+ XCAM_ASSERT (param.ptr ());
+
+ dump_buf (args->out_video_buf, "blend-top");
+
+ XCamReturn ret = _priv_config->start_reconstruct_by_gauss (param, args->out_video_buf, _priv_config->pyr_levels - 1);
+ CHECK_RET (ret, "execute reconstruct by gauss failed, level:%d", _priv_config->pyr_levels - 1);
+}
+
+void
+GLBlender::reconstruct_done (
+ const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+ XCAM_UNUSED (worker);
+ XCAM_ASSERT (base.ptr ());
+
+ SmartPtr<GLReconstructPyrShader::Args> args = base.dynamic_cast_ptr<GLReconstructPyrShader::Args> ();
+ XCAM_ASSERT (args.ptr ());
+ uint32_t level = args->level;
+ XCAM_ASSERT (level < _priv_config->pyr_levels);
+
+ const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+ XCAM_ASSERT (param.ptr ());
+
+ dump_level_buf (args->out_video_buf, "reconstruct", level, 0);
+
+ if (level == 0) {
+ execute_done (param, error);
+ return;
+ }
+
+ XCamReturn ret = _priv_config->start_reconstruct_by_gauss (param, args->out_video_buf, level - 1);
+ CHECK_RET (ret, "execute reconstruct by gauss failed, level:%d", level - 1);
+}
+
+SmartPtr<GLImageHandler>
+create_gl_blender ()
+{
+ SmartPtr<GLBlender> blender = new GLBlender();
+ XCAM_ASSERT (blender.ptr ());
+ return blender;
+}
+
+SmartPtr<Blender>
+Blender::create_gl_blender ()
+{
+ SmartPtr<GLImageHandler> handler = XCam::create_gl_blender ();
+ return handler.dynamic_cast_ptr<Blender> ();
+}
+
+}