diff options
author | Igor Oliveira <itrindade.oliveira@gmail.com> | 2010-06-05 14:18:40 -0400 |
---|---|---|
committer | Igor Oliveira <igor.oliveira@openbossa.org> | 2010-06-10 09:44:37 -0400 |
commit | 119d13f6f734b28a29e53c9832086043c401abf0 (patch) | |
tree | d7e17b95074e3813ebc84797e4e859c351ba7729 | |
parent | 7be27feac3db6a32c1c2155c5cfccf19f38b19d5 (diff) |
DRM/Gallium3D: Path initial implementation
Support to all paths and line width
missing:
Some features in cairo_stroke_style_t
-rw-r--r-- | src/drm/cairo-drm-gallium-surface.c | 230 |
1 files changed, 209 insertions, 21 deletions
diff --git a/src/drm/cairo-drm-gallium-surface.c b/src/drm/cairo-drm-gallium-surface.c index 4d92a97e..0fc395ed 100644 --- a/src/drm/cairo-drm-gallium-surface.c +++ b/src/drm/cairo-drm-gallium-surface.c @@ -182,7 +182,7 @@ format_is_supported_destination (gallium_device_t *device, return device->screen->is_format_supported (device->screen, format, PIPE_TEXTURE_2D, - 0, + 0, PIPE_BIND_RENDER_TARGET, 0); } @@ -431,7 +431,6 @@ setup_shader(gallium_shader_t *shader, shadertype_t type) cso_set_fragment_shader_handle(shader->device->cso, shader->fs); } - static INLINE void unpack_color (const unsigned *src, unsigned w, unsigned h, @@ -658,31 +657,220 @@ gallium_surface_mask (void *abstract_surface, clip); } +#define MIN_POINTS 10 + +typedef struct _gallium_path { + cairo_matrix_t *ctm_inverse; + double *points; + int count; + + struct pipe_resource *buf; +} gallium_path_t; + +static cairo_status_t +_gallium_init_path (gallium_path_t *path) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + path = (gallium_path_t *) malloc(sizeof(gallium_path_t)); + if (path == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto CLEAN; + } + + path->points = (double *) malloc(sizeof(double) * MIN_POINTS * 2); + if (path->points == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto CLEAN; + } + path->count = 0; + +CLEAN: + return status; +} + +static cairo_status_t +_gallium_finish_path (gallium_path_t *path) +{ + if (path->count != 0) + free(path->points); + free(path->buf); + free(path); +} + +static cairo_status_t +_gallium_append_point (gallium_path_t *path, const cairo_point_t *point) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + if (path->count >= MIN_POINTS) { + double *new_points = (double *) malloc (sizeof(double) * (path->count + 2)); + if (new_points == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto CLEAN; + } + + memcpy(new_points, path->points, path->count * 2 * sizeof(double)); + free(path->points); + path->points = new_points; + } + + path->points[path->count] = _cairo_fixed_to_double (point->x); + path->points[path->count + 1] = _cairo_fixed_to_double (point->y); + + path->count += 2; + +CLEAN: + return status; +} + +static void +draw_path (gallium_device_t *device, + gallium_path_t *path, + const cairo_stroke_style_t *style) +{ + const int components = 2; + struct pipe_context *ctx = device->pipe; + struct pipe_vertex_buffer vbuffer; + struct pipe_vertex_element velement; + struct pipe_rasterizer_state rasterizer; + int vert_size = components * path->count * sizeof(float); + + path->buf= pipe_user_buffer_create(ctx->screen, + path->points, + vert_size, + PIPE_BIND_VERTEX_BUFFER); + + memset(&vbuffer, 0, sizeof(vbuffer)); + vbuffer.buffer = path->buf; + // We just have x and y components + vbuffer.stride = components * sizeof(float); + vbuffer.buffer_offset = 0; + vbuffer.max_index = path->count - 1; + ctx->set_vertex_buffers(ctx, 1, &vbuffer); + + memset(&velement, 0, sizeof(velement)); + velement.src_offset = 0; + velement.instance_divisor = 0; + velement.vertex_buffer_index = 0; + velement.src_format = PIPE_FORMAT_R32G32_FLOAT; + cso_set_vertex_elements(device->cso, 1, &velement); + + rasterizer.line_width = style->line_width; + + cso_save_rasterizer(device->cso); + cso_set_rasterizer(device->cso, &rasterizer); + + ctx->draw_arrays(ctx, PIPE_PRIM_TRIANGLE_FAN, + 0, path->count); + + cso_restore_rasterizer(device->cso); +} + +static cairo_status_t +_gallium_move_to_line_to (void *closure, const cairo_point_t *point) +{ + gallium_path_t *path = closure; + + if (path->ctm_inverse) + cairo_matrix_transform_point (path->ctm_inverse, point->x, point->y); + + _gallium_append_point(path, point); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_gallium_close_path (void *closure) +{ + cairo_status_t status = CAIRO_STATUS_NO_MEMORY; + gallium_path_t *path = closure; + + if (path->count != 0) { + cairo_point_t close_point_path; + close_point_path.x = path->points[0]; + close_point_path.y = path->points[1]; + _gallium_append_point(path, &close_point_path); + status = CAIRO_STATUS_SUCCESS; + } + + return status; +} + +static cairo_status_t +_gallium_curve_to (void *closure, + const cairo_point_t *p0, + const cairo_point_t *p1, + const cairo_point_t *p2) +{ + gallium_path_t *path = closure; + cairo_spline_t *spline = (cairo_spline_t *) malloc (sizeof(cairo_spline_t)); + + cairo_point_t initial_point; + + if (path->count != 0) { + initial_point.x = path->points[0]; + initial_point.y = path->points[1]; + } else { + initial_point.x = 0; + initial_point.y = 0; + } + + if (path->ctm_inverse) { + cairo_matrix_transform_point (path->ctm_inverse, initial_point.x, initial_point.y); + cairo_matrix_transform_point (path->ctm_inverse, p0->x, p0->y); + cairo_matrix_transform_point (path->ctm_inverse, p1->x, p1->y); + cairo_matrix_transform_point (path->ctm_inverse, p2->x, p2->y); + } + + _cairo_spline_init(spline, + _gallium_move_to_line_to, + path, + &initial_point, p0, p1, p2); + return _cairo_spline_decompose(spline, 0.25); +} + +static void +_gallium_path_from_cairo (gallium_path_t *gallium_path, const cairo_path_fixed_t *path) +{ + cairo_status_t status; + + status = _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + _gallium_move_to_line_to, + _gallium_move_to_line_to, + _gallium_curve_to, + 0, + gallium_path); + + assert (status == CAIRO_STATUS_SUCCESS); +} + static cairo_int_status_t gallium_surface_stroke (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_path_fixed_t *path, - const cairo_stroke_style_t *style, - const cairo_matrix_t *ctm, - const cairo_matrix_t *ctm_inverse, - double tolerance, - cairo_antialias_t antialias, - cairo_clip_t *clip) + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) { gallium_surface_t *surface = abstract_surface; + gallium_path_t *gallium_path; + gallium_device_t *device = gallium_device(surface); - if (surface->fallback == NULL) { - /* XXX insert magic */ - surface->fallback = gallium_surface_map_to_image (surface); - } + _gallium_init_path(gallium_path); + + gallium_path->ctm_inverse = ctm_inverse; - return _cairo_surface_stroke (surface->fallback, - op, source, - path, style, - ctm, ctm_inverse, - tolerance, antialias, - clip); + _gallium_path_from_cairo(gallium_path, path); + draw_path(device, gallium_path, style); + _gallium_finish_path(gallium_path); + + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t |