api_filters.c revision 75143ef05576ee9f25ee176bc28c3c4d03705bf5
19682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/**************************************************************************
29682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall *
39682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * Copyright 2009 VMware, Inc.  All Rights Reserved.
49682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall *
59682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * Permission is hereby granted, free of charge, to any person obtaining a
69682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * copy of this software and associated documentation files (the
79682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * "Software"), to deal in the Software without restriction, including
89682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * without limitation the rights to use, copy, modify, merge, publish,
99682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * distribute, sub license, and/or sell copies of the Software, and to
109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * permit persons to whom the Software is furnished to do so, subject to
119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * the following conditions:
129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall *
139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * The above copyright notice and this permission notice (including the
149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * next paragraph) shall be included in all copies or substantial portions
159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * of the Software.
169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall *
179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall *
259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall **************************************************************************/
269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "VG/openvg.h"
289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "vg_context.h"
309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "image.h"
319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "api.h"
329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "renderer.h"
339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "shaders_cache.h"
349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "st_inlines.h"
359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "pipe/p_context.h"
379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "pipe/p_state.h"
389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "util/u_inlines.h"
399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "pipe/p_screen.h"
409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "pipe/p_shader_tokens.h"
419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "util/u_format.h"
439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "util/u_memory.h"
449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "util/u_sampler.h"
459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "asm_filters.h"
489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstruct filter_info {
519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   struct vg_image *dst;
529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   struct vg_image *src;
539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   struct vg_shader * (*setup_shader)(struct vg_context *, void *);
549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   void *user_data;
559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   const void *const_buffer;
569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   VGint const_buffer_len;
579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   VGTilingMode tiling_mode;
589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   struct pipe_sampler_view *extra_texture_view;
599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall};
609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic INLINE struct pipe_resource *create_texture_1d(struct vg_context *ctx,
629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                                                     const VGuint *color_data,
639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                                                     const VGint color_data_len)
649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   struct pipe_context *pipe = ctx->pipe;
669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   struct pipe_screen *screen = pipe->screen;
679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   struct pipe_resource *tex = 0;
689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   struct pipe_resource templ;
699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   memset(&templ, 0, sizeof(templ));
719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   templ.target = PIPE_TEXTURE_1D;
729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   templ.last_level = 0;
749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   templ.width0 = color_data_len;
759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   templ.height0 = 1;
769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   templ.depth0 = 1;
779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   templ.bind = PIPE_BIND_SAMPLER_VIEW;
789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   tex = screen->resource_create(screen, &templ);
809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   { /* upload color_data */
829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      struct pipe_transfer *transfer =
839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall         pipe_get_transfer(pipe, tex,
849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				0, 0, 0,
859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				PIPE_TRANSFER_READ_WRITE ,
869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				0, 0, tex->width0, tex->height0);
879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      void *map = pipe->transfer_map(pipe, transfer);
889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      memcpy(map, color_data, sizeof(VGint)*color_data_len);
899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      pipe->transfer_unmap(pipe, transfer);
909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      pipe->transfer_destroy(pipe, transfer);
919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   }
92
93   return tex;
94}
95
96static INLINE struct pipe_sampler_view *create_texture_1d_view(struct vg_context *ctx,
97                                                               const VGuint *color_data,
98                                                               const VGint color_data_len)
99{
100   struct pipe_context *pipe = ctx->pipe;
101   struct pipe_resource *texture;
102   struct pipe_sampler_view view_templ;
103   struct pipe_sampler_view *view;
104
105   texture = create_texture_1d(ctx, color_data, color_data_len);
106
107   if (!texture)
108      return NULL;
109
110   u_sampler_view_default_template(&view_templ, texture, texture->format);
111   view = pipe->create_sampler_view(pipe, texture, &view_templ);
112   /* want the texture to go away if the view is freed */
113   pipe_resource_reference(&texture, NULL);
114
115   return view;
116}
117
118static INLINE struct pipe_surface * setup_framebuffer(struct vg_image *dst)
119{
120   struct vg_context *ctx = vg_current_context();
121   struct pipe_context *pipe = ctx->pipe;
122   struct pipe_framebuffer_state fb;
123   struct pipe_surface *dst_surf = pipe->screen->get_tex_surface(
124      pipe->screen, dst->sampler_view->texture, 0, 0, 0,
125      PIPE_BIND_RENDER_TARGET);
126
127   /* drawing dest */
128   memset(&fb, 0, sizeof(fb));
129   fb.width  = dst->x + dst_surf->width;
130   fb.height = dst->y + dst_surf->height;
131   fb.nr_cbufs = 1;
132   fb.cbufs[0] = dst_surf;
133   {
134      VGint i;
135      for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
136         fb.cbufs[i] = 0;
137   }
138   cso_set_framebuffer(ctx->cso_context, &fb);
139
140   return dst_surf;
141}
142
143static void setup_viewport(struct vg_image *dst)
144{
145   struct vg_context *ctx = vg_current_context();
146   vg_set_viewport(ctx, VEGA_Y0_TOP);
147}
148
149static void setup_blend()
150{
151   struct vg_context *ctx = vg_current_context();
152   struct pipe_blend_state blend;
153   memset(&blend, 0, sizeof(blend));
154   blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
155   blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
156   blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
157   blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
158   if (ctx->state.vg.filter_channel_mask & VG_RED)
159      blend.rt[0].colormask |= PIPE_MASK_R;
160   if (ctx->state.vg.filter_channel_mask & VG_GREEN)
161      blend.rt[0].colormask |= PIPE_MASK_G;
162   if (ctx->state.vg.filter_channel_mask & VG_BLUE)
163      blend.rt[0].colormask |= PIPE_MASK_B;
164   if (ctx->state.vg.filter_channel_mask & VG_ALPHA)
165      blend.rt[0].colormask |= PIPE_MASK_A;
166   blend.rt[0].blend_enable = 0;
167   cso_set_blend(ctx->cso_context, &blend);
168}
169
170static void setup_constant_buffer(struct vg_context *ctx, const void *buffer,
171                                  VGint param_bytes)
172{
173   struct pipe_context *pipe = ctx->pipe;
174   struct pipe_resource **cbuf = &ctx->filter.buffer;
175
176   /* We always need to get a new buffer, to keep the drivers simple and
177    * avoid gratuitous rendering synchronization. */
178   pipe_resource_reference(cbuf, NULL);
179
180   *cbuf = pipe_buffer_create(pipe->screen,
181                              PIPE_BIND_CONSTANT_BUFFER,
182                              param_bytes);
183
184   if (*cbuf) {
185      st_no_flush_pipe_buffer_write(ctx, *cbuf,
186                                    0, param_bytes, buffer);
187   }
188
189   ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, *cbuf);
190}
191
192static void setup_samplers(struct vg_context *ctx, struct filter_info *info)
193{
194   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
195   struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
196   struct pipe_sampler_state sampler[3];
197   int num_samplers = 0;
198   int num_textures = 0;
199
200   samplers[0] = NULL;
201   samplers[1] = NULL;
202   samplers[2] = NULL;
203   samplers[3] = NULL;
204   sampler_views[0] = NULL;
205   sampler_views[1] = NULL;
206   sampler_views[2] = NULL;
207   sampler_views[3] = NULL;
208
209   memset(&sampler[0], 0, sizeof(struct pipe_sampler_state));
210   sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
211   sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
212   sampler[0].wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
213   sampler[0].min_img_filter = PIPE_TEX_MIPFILTER_LINEAR;
214   sampler[0].mag_img_filter = PIPE_TEX_MIPFILTER_LINEAR;
215   sampler[0].normalized_coords = 1;
216
217   switch(info->tiling_mode) {
218   case VG_TILE_FILL:
219      sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
220      sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
221      memcpy(sampler[0].border_color,
222             ctx->state.vg.tile_fill_color,
223             sizeof(VGfloat) * 4);
224      break;
225   case VG_TILE_PAD:
226      sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
227      sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
228      break;
229   case VG_TILE_REPEAT:
230      sampler[0].wrap_s = PIPE_TEX_WRAP_REPEAT;
231      sampler[0].wrap_t = PIPE_TEX_WRAP_REPEAT;
232      break;
233   case VG_TILE_REFLECT:
234      sampler[0].wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT;
235      sampler[0].wrap_t = PIPE_TEX_WRAP_MIRROR_REPEAT;
236      break;
237   default:
238      debug_assert(!"Unknown tiling mode");
239   }
240
241   samplers[0] = &sampler[0];
242   sampler_views[0] = info->src->sampler_view;
243   ++num_samplers;
244   ++num_textures;
245
246   if (info->extra_texture_view) {
247      memcpy(&sampler[1], &sampler[0], sizeof(struct pipe_sampler_state));
248      samplers[1] = &sampler[1];
249      sampler_views[1] = info->extra_texture_view;
250      ++num_samplers;
251      ++num_textures;
252   }
253
254
255   cso_set_samplers(ctx->cso_context, num_samplers, (const struct pipe_sampler_state **)samplers);
256   cso_set_fragment_sampler_views(ctx->cso_context, num_textures, sampler_views);
257}
258
259static struct vg_shader * setup_color_matrix(struct vg_context *ctx, void *user_data)
260{
261   struct vg_shader *shader =
262      shader_create_from_text(ctx->pipe, color_matrix_asm, 200,
263         PIPE_SHADER_FRAGMENT);
264   cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
265   return shader;
266}
267
268static struct vg_shader * setup_convolution(struct vg_context *ctx, void *user_data)
269{
270   char buffer[1024];
271   VGint num_consts = (VGint)(long)(user_data);
272   struct vg_shader *shader;
273
274   snprintf(buffer, 1023, convolution_asm, num_consts, num_consts / 2 + 1);
275
276   shader = shader_create_from_text(ctx->pipe, buffer, 200,
277                                    PIPE_SHADER_FRAGMENT);
278
279   cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
280   return shader;
281}
282
283static struct vg_shader * setup_lookup(struct vg_context *ctx, void *user_data)
284{
285   struct vg_shader *shader =
286      shader_create_from_text(ctx->pipe, lookup_asm,
287                              200, PIPE_SHADER_FRAGMENT);
288
289   cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
290   return shader;
291}
292
293
294static struct vg_shader * setup_lookup_single(struct vg_context *ctx, void *user_data)
295{
296   char buffer[1024];
297   VGImageChannel channel = (VGImageChannel)(user_data);
298   struct vg_shader *shader;
299
300   switch(channel) {
301   case VG_RED:
302      snprintf(buffer, 1023, lookup_single_asm, "xxxx");
303      break;
304   case VG_GREEN:
305      snprintf(buffer, 1023, lookup_single_asm, "yyyy");
306      break;
307   case VG_BLUE:
308      snprintf(buffer, 1023, lookup_single_asm, "zzzz");
309      break;
310   case VG_ALPHA:
311      snprintf(buffer, 1023, lookup_single_asm, "wwww");
312      break;
313   default:
314      debug_assert(!"Unknown color channel");
315   }
316
317   shader = shader_create_from_text(ctx->pipe, buffer, 200,
318                                    PIPE_SHADER_FRAGMENT);
319
320   cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
321   return shader;
322}
323
324static void execute_filter(struct vg_context *ctx,
325                           struct filter_info *info)
326{
327   struct pipe_surface *dst_surf;
328   struct vg_shader *shader;
329
330   cso_save_framebuffer(ctx->cso_context);
331   cso_save_fragment_shader(ctx->cso_context);
332   cso_save_viewport(ctx->cso_context);
333   cso_save_blend(ctx->cso_context);
334   cso_save_samplers(ctx->cso_context);
335   cso_save_fragment_sampler_views(ctx->cso_context);
336
337   dst_surf = setup_framebuffer(info->dst);
338   setup_viewport(info->dst);
339   setup_blend();
340   setup_constant_buffer(ctx, info->const_buffer, info->const_buffer_len);
341   shader = info->setup_shader(ctx, info->user_data);
342   setup_samplers(ctx, info);
343
344   renderer_draw_texture(ctx->renderer,
345                         info->src->sampler_view->texture,
346                         info->dst->x, info->dst->y,
347                         info->dst->x + info->dst->width,
348                         info->dst->y + info->dst->height,
349                         info->dst->x, info->dst->y,
350                         info->dst->x + info->dst->width,
351                         info->dst->y + info->dst->height);
352
353   cso_restore_framebuffer(ctx->cso_context);
354   cso_restore_fragment_shader(ctx->cso_context);
355   cso_restore_viewport(ctx->cso_context);
356   cso_restore_blend(ctx->cso_context);
357   cso_restore_samplers(ctx->cso_context);
358   cso_restore_fragment_sampler_views(ctx->cso_context);
359
360   vg_shader_destroy(ctx, shader);
361
362   pipe_surface_reference(&dst_surf, NULL);
363}
364
365void vegaColorMatrix(VGImage dst, VGImage src,
366                     const VGfloat * matrix)
367{
368   struct vg_context *ctx = vg_current_context();
369   struct vg_image *d, *s;
370   struct filter_info info;
371
372   if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
373      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
374      return;
375   }
376   if (!matrix || !is_aligned(matrix)) {
377      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
378      return;
379   }
380
381   d = (struct vg_image*)dst;
382   s = (struct vg_image*)src;
383
384   if (vg_image_overlaps(d, s)) {
385      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
386      return;
387   }
388
389   info.dst = d;
390   info.src = s;
391   info.setup_shader = &setup_color_matrix;
392   info.user_data = NULL;
393   info.const_buffer = matrix;
394   info.const_buffer_len = 20 * sizeof(VGfloat);
395   info.tiling_mode = VG_TILE_PAD;
396   info.extra_texture_view = NULL;
397   execute_filter(ctx, &info);
398}
399
400static VGfloat texture_offset(VGfloat width, VGint kernelSize, VGint current, VGint shift)
401{
402   VGfloat diff = current - shift;
403
404   return diff / width;
405}
406
407void vegaConvolve(VGImage dst, VGImage src,
408                  VGint kernelWidth, VGint kernelHeight,
409                  VGint shiftX, VGint shiftY,
410                  const VGshort * kernel,
411                  VGfloat scale,
412                  VGfloat bias,
413                  VGTilingMode tilingMode)
414{
415   struct vg_context *ctx = vg_current_context();
416   VGfloat *buffer;
417   VGint buffer_len;
418   VGint i, j;
419   VGint idx = 0;
420   struct vg_image *d, *s;
421   VGint kernel_size = kernelWidth * kernelHeight;
422   struct filter_info info;
423   const VGint max_kernel_size = vgGeti(VG_MAX_KERNEL_SIZE);
424
425   if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
426      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
427      return;
428   }
429
430   if (kernelWidth <= 0 || kernelHeight <= 0 ||
431      kernelWidth > max_kernel_size || kernelHeight > max_kernel_size) {
432      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
433      return;
434   }
435
436   if (!kernel || !is_aligned_to(kernel, 2)) {
437      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
438      return;
439   }
440
441   if (tilingMode < VG_TILE_FILL ||
442       tilingMode > VG_TILE_REFLECT) {
443      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
444      return;
445   }
446
447   d = (struct vg_image*)dst;
448   s = (struct vg_image*)src;
449
450   if (vg_image_overlaps(d, s)) {
451      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
452      return;
453   }
454
455   vg_validate_state(ctx);
456
457   buffer_len = 8 + 2 * 4 * kernel_size;
458   buffer = (VGfloat*)malloc(buffer_len * sizeof(VGfloat));
459
460   buffer[0] = 0.f;
461   buffer[1] = 1.f;
462   buffer[2] = 2.f; /*unused*/
463   buffer[3] = 4.f; /*unused*/
464
465   buffer[4] = kernelWidth * kernelHeight;
466   buffer[5] = scale;
467   buffer[6] = bias;
468   buffer[7] = 0.f;
469
470   idx = 8;
471   for (j = 0; j < kernelHeight; ++j) {
472      for (i = 0; i < kernelWidth; ++i) {
473         VGint index = j * kernelWidth + i;
474         VGfloat x, y;
475
476         x = texture_offset(s->width, kernelWidth, i, shiftX);
477         y = texture_offset(s->height, kernelHeight, j, shiftY);
478
479         buffer[idx + index*4 + 0] = x;
480         buffer[idx + index*4 + 1] = y;
481         buffer[idx + index*4 + 2] = 0.f;
482         buffer[idx + index*4 + 3] = 0.f;
483      }
484   }
485   idx += kernel_size * 4;
486
487   for (j = 0; j < kernelHeight; ++j) {
488      for (i = 0; i < kernelWidth; ++i) {
489         /* transpose the kernel */
490         VGint index = j * kernelWidth + i;
491         VGint kindex = (kernelWidth - i - 1) * kernelHeight + (kernelHeight - j - 1);
492         buffer[idx + index*4 + 0] = kernel[kindex];
493         buffer[idx + index*4 + 1] = kernel[kindex];
494         buffer[idx + index*4 + 2] = kernel[kindex];
495         buffer[idx + index*4 + 3] = kernel[kindex];
496      }
497   }
498
499   info.dst = d;
500   info.src = s;
501   info.setup_shader = &setup_convolution;
502   info.user_data = (void*)(long)(buffer_len/4);
503   info.const_buffer = buffer;
504   info.const_buffer_len = buffer_len * sizeof(VGfloat);
505   info.tiling_mode = tilingMode;
506   info.extra_texture_view = NULL;
507   execute_filter(ctx, &info);
508
509   free(buffer);
510}
511
512void vegaSeparableConvolve(VGImage dst, VGImage src,
513                           VGint kernelWidth,
514                           VGint kernelHeight,
515                           VGint shiftX, VGint shiftY,
516                           const VGshort * kernelX,
517                           const VGshort * kernelY,
518                           VGfloat scale,
519                           VGfloat bias,
520                           VGTilingMode tilingMode)
521{
522   struct vg_context *ctx = vg_current_context();
523   VGshort *kernel;
524   VGint i, j, idx = 0;
525   const VGint max_kernel_size = vgGeti(VG_MAX_SEPARABLE_KERNEL_SIZE);
526
527   if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
528      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
529      return;
530   }
531
532   if (kernelWidth <= 0 || kernelHeight <= 0 ||
533       kernelWidth > max_kernel_size || kernelHeight > max_kernel_size) {
534      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
535      return;
536   }
537
538   if (!kernelX || !kernelY ||
539       !is_aligned_to(kernelX, 2) || !is_aligned_to(kernelY, 2)) {
540      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
541      return;
542   }
543   if (tilingMode < VG_TILE_FILL ||
544       tilingMode > VG_TILE_REFLECT) {
545      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
546      return;
547   }
548   kernel = malloc(sizeof(VGshort)*kernelWidth*kernelHeight);
549   for (i = 0; i < kernelWidth; ++i) {
550      for (j = 0; j < kernelHeight; ++j) {
551         kernel[idx] = kernelX[i] * kernelY[j];
552         ++idx;
553      }
554   }
555   vgConvolve(dst, src, kernelWidth, kernelHeight, shiftX, shiftY,
556              kernel, scale, bias, tilingMode);
557   free(kernel);
558}
559
560static INLINE VGfloat compute_gaussian_componenet(VGfloat x, VGfloat y,
561                                                  VGfloat stdDeviationX,
562                                                  VGfloat stdDeviationY)
563{
564   VGfloat mult = 1 / ( 2 * M_PI * stdDeviationX * stdDeviationY);
565   VGfloat e = exp( - ( pow(x, 2)/(2*pow(stdDeviationX, 2)) +
566                        pow(y, 2)/(2*pow(stdDeviationY, 2)) ) );
567   return mult * e;
568}
569
570static INLINE VGint compute_kernel_size(VGfloat deviation)
571{
572   VGint size = ceil(2.146 * deviation);
573   if (size > 11)
574      return 11;
575   return size;
576}
577
578static void compute_gaussian_kernel(VGfloat *kernel,
579                                    VGint width, VGint height,
580                                    VGfloat stdDeviationX,
581                                    VGfloat stdDeviationY)
582{
583   VGint i, j;
584   VGfloat scale = 0.0f;
585
586   for (j = 0; j < height; ++j) {
587      for (i = 0; i < width; ++i) {
588         VGint idx =  (height - j -1) * width + (width - i -1);
589         kernel[idx] = compute_gaussian_componenet(i-(ceil(width/2))-1,
590                                                   j-ceil(height/2)-1,
591                                                   stdDeviationX, stdDeviationY);
592         scale += kernel[idx];
593      }
594   }
595
596   for (j = 0; j < height; ++j) {
597      for (i = 0; i < width; ++i) {
598         VGint idx = j * width + i;
599         kernel[idx] /= scale;
600      }
601   }
602}
603
604void vegaGaussianBlur(VGImage dst, VGImage src,
605                      VGfloat stdDeviationX,
606                      VGfloat stdDeviationY,
607                      VGTilingMode tilingMode)
608{
609   struct vg_context *ctx = vg_current_context();
610   struct vg_image *d, *s;
611   VGfloat *buffer, *kernel;
612   VGint kernel_width, kernel_height, kernel_size;
613   VGint buffer_len;
614   VGint idx, i, j;
615   struct filter_info info;
616
617   if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
618      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
619      return;
620   }
621   if (stdDeviationX <= 0 || stdDeviationY <= 0) {
622      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
623      return;
624   }
625
626   if (tilingMode < VG_TILE_FILL ||
627       tilingMode > VG_TILE_REFLECT) {
628      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
629      return;
630   }
631
632   d = (struct vg_image*)dst;
633   s = (struct vg_image*)src;
634
635   if (vg_image_overlaps(d, s)) {
636      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
637      return;
638   }
639
640   kernel_width = compute_kernel_size(stdDeviationX);
641   kernel_height = compute_kernel_size(stdDeviationY);
642   kernel_size = kernel_width * kernel_height;
643   kernel = malloc(sizeof(VGfloat)*kernel_size);
644   compute_gaussian_kernel(kernel, kernel_width, kernel_height,
645                           stdDeviationX, stdDeviationY);
646
647   buffer_len = 8 + 2 * 4 * kernel_size;
648   buffer = (VGfloat*)malloc(buffer_len * sizeof(VGfloat));
649
650   buffer[0] = 0.f;
651   buffer[1] = 1.f;
652   buffer[2] = 2.f; /*unused*/
653   buffer[3] = 4.f; /*unused*/
654
655   buffer[4] = kernel_width * kernel_height;
656   buffer[5] = 1.f;/*scale*/
657   buffer[6] = 0.f;/*bias*/
658   buffer[7] = 0.f;
659
660   idx = 8;
661   for (j = 0; j < kernel_height; ++j) {
662      for (i = 0; i < kernel_width; ++i) {
663         VGint index = j * kernel_width + i;
664         VGfloat x, y;
665
666         x = texture_offset(s->width, kernel_width, i, kernel_width/2);
667         y = texture_offset(s->height, kernel_height, j, kernel_height/2);
668
669         buffer[idx + index*4 + 0] = x;
670         buffer[idx + index*4 + 1] = y;
671         buffer[idx + index*4 + 2] = 0.f;
672         buffer[idx + index*4 + 3] = 0.f;
673      }
674   }
675   idx += kernel_size * 4;
676
677   for (j = 0; j < kernel_height; ++j) {
678      for (i = 0; i < kernel_width; ++i) {
679         /* transpose the kernel */
680         VGint index = j * kernel_width + i;
681         VGint kindex = (kernel_width - i - 1) * kernel_height + (kernel_height - j - 1);
682         buffer[idx + index*4 + 0] = kernel[kindex];
683         buffer[idx + index*4 + 1] = kernel[kindex];
684         buffer[idx + index*4 + 2] = kernel[kindex];
685         buffer[idx + index*4 + 3] = kernel[kindex];
686      }
687   }
688
689   info.dst = d;
690   info.src = s;
691   info.setup_shader = &setup_convolution;
692   info.user_data = (void*)(long)(buffer_len/4);
693   info.const_buffer = buffer;
694   info.const_buffer_len = buffer_len * sizeof(VGfloat);
695   info.tiling_mode = tilingMode;
696   info.extra_texture_view = NULL;
697   execute_filter(ctx, &info);
698
699   free(buffer);
700   free(kernel);
701}
702
703void vegaLookup(VGImage dst, VGImage src,
704                const VGubyte * redLUT,
705                const VGubyte * greenLUT,
706                const VGubyte * blueLUT,
707                const VGubyte * alphaLUT,
708                VGboolean outputLinear,
709                VGboolean outputPremultiplied)
710{
711   struct vg_context *ctx = vg_current_context();
712   struct vg_image *d, *s;
713   VGuint color_data[256];
714   VGint i;
715   struct pipe_sampler_view *lut_texture_view;
716   VGfloat buffer[4];
717   struct filter_info info;
718
719   if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
720      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
721      return;
722   }
723
724   if (!redLUT || !greenLUT || !blueLUT || !alphaLUT) {
725      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
726      return;
727   }
728
729   d = (struct vg_image*)dst;
730   s = (struct vg_image*)src;
731
732   if (vg_image_overlaps(d, s)) {
733      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
734      return;
735   }
736
737   for (i = 0; i < 256; ++i) {
738      color_data[i] = blueLUT[i] << 24 | greenLUT[i] << 16 |
739                      redLUT[i]  <<  8 | alphaLUT[i];
740   }
741   lut_texture_view = create_texture_1d_view(ctx, color_data, 255);
742
743   buffer[0] = 0.f;
744   buffer[1] = 0.f;
745   buffer[2] = 1.f;
746   buffer[3] = 1.f;
747
748   info.dst = d;
749   info.src = s;
750   info.setup_shader = &setup_lookup;
751   info.user_data = NULL;
752   info.const_buffer = buffer;
753   info.const_buffer_len = 4 * sizeof(VGfloat);
754   info.tiling_mode = VG_TILE_PAD;
755   info.extra_texture_view = lut_texture_view;
756
757   execute_filter(ctx, &info);
758
759   pipe_sampler_view_reference(&lut_texture_view, NULL);
760}
761
762void vegaLookupSingle(VGImage dst, VGImage src,
763                      const VGuint * lookupTable,
764                      VGImageChannel sourceChannel,
765                      VGboolean outputLinear,
766                      VGboolean outputPremultiplied)
767{
768   struct vg_context *ctx = vg_current_context();
769   struct vg_image *d, *s;
770   struct pipe_sampler_view *lut_texture_view;
771   VGfloat buffer[4];
772   struct filter_info info;
773   VGuint color_data[256];
774   VGint i;
775
776   if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
777      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
778      return;
779   }
780
781   if (!lookupTable || !is_aligned(lookupTable)) {
782      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
783      return;
784   }
785
786   if (sourceChannel != VG_RED && sourceChannel != VG_GREEN &&
787       sourceChannel != VG_BLUE && sourceChannel != VG_ALPHA) {
788      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
789      return;
790   }
791
792   d = (struct vg_image*)dst;
793   s = (struct vg_image*)src;
794
795   if (vg_image_overlaps(d, s)) {
796      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
797      return;
798   }
799
800   for (i = 0; i < 256; ++i) {
801      VGuint rgba = lookupTable[i];
802      VGubyte blue, green, red, alpha;
803      red   = (rgba & 0xff000000)>>24;
804      green = (rgba & 0x00ff0000)>>16;
805      blue  = (rgba & 0x0000ff00)>> 8;
806      alpha = (rgba & 0x000000ff)>> 0;
807      color_data[i] = blue << 24 | green << 16 |
808                      red  <<  8 | alpha;
809   }
810   lut_texture_view = create_texture_1d_view(ctx, color_data, 256);
811
812   buffer[0] = 0.f;
813   buffer[1] = 0.f;
814   buffer[2] = 1.f;
815   buffer[3] = 1.f;
816
817   info.dst = d;
818   info.src = s;
819   info.setup_shader = &setup_lookup_single;
820   info.user_data = (void*)sourceChannel;
821   info.const_buffer = buffer;
822   info.const_buffer_len = 4 * sizeof(VGfloat);
823   info.tiling_mode = VG_TILE_PAD;
824   info.extra_texture_view = lut_texture_view;
825
826   execute_filter(ctx, &info);
827
828   pipe_sampler_view_reference(&lut_texture_view, NULL);
829}
830