[cairo] [PATCH 3/3] DRM/gallium3D: Initial implementation of painting method

Igor Oliveira itrindade.oliveira at gmail.com
Sun May 30 12:14:45 PDT 2010


Now we are supporting solid surfaces
---
 src/drm/cairo-drm-gallium-surface.c |  357 ++++++++++++++++++++++++++++++++++-
 1 files changed, 348 insertions(+), 9 deletions(-)

diff --git a/src/drm/cairo-drm-gallium-surface.c b/src/drm/cairo-drm-gallium-surface.c
index 17ba136..e035eae 100644
--- a/src/drm/cairo-drm-gallium-surface.c
+++ b/src/drm/cairo-drm-gallium-surface.c
@@ -41,15 +41,35 @@
 #include <drivers/softpipe/sp_public.h>
 #include <winsys/sw/null/null_sw_winsys.h>
 #include <state_tracker/drm_api.h>
+
 #include <pipe/p_format.h>
 #include <pipe/p_screen.h>
 #include <pipe/p_context.h>
 #include <pipe/p_state.h>
 
 #include <util/u_inlines.h>
+#include <util/u_format.h>
+#include <util/u_tile.h>
+#include <util/u_simple_shaders.h>
+#include <util/u_draw_quad.h>
+
+#include <tgsi/tgsi_ureg.h>
+#include <tgsi/tgsi_build.h>
+#include <tgsi/tgsi_parse.h>
+#include <tgsi/tgsi_util.h>
+
+#include <cso_cache/cso_context.h>
+#include <cso_cache/cso_hash.h>
+
 
+#define MAX_CONTANTS 20
+
+typedef enum _shader_type shadertype_t;
+
+typedef struct _gallium_paint   gallium_paint_t;
 typedef struct _gallium_surface gallium_surface_t;
-typedef struct _gallium_device gallium_device_t;
+typedef struct _gallium_shader  gallium_shader_t;
+typedef struct _gallium_device  gallium_device_t;
 
 struct _gallium_device {
     cairo_drm_device_t drm;
@@ -59,8 +79,29 @@ struct _gallium_device {
 
     struct pipe_screen *screen;
     struct pipe_context *pipe;
+    struct cso_context  *cso;
+
+    struct pipe_framebuffer_state framebuffer;
+    struct pipe_viewport_state viewport;
 
     int max_size;
+
+    gallium_shader_t *shader;
+};
+
+struct _gallium_paint {
+
+    float solid_color[4];
+    //XXX: add gradient infrastructure
+};
+
+struct _gallium_shader {
+    gallium_device_t *device;
+
+    float constants[MAX_CONTANTS];
+    struct pipe_resource *cbuf;
+    struct cso_hash *fs;
+    struct cso_hash *vs;
 };
 
 struct _gallium_surface {
@@ -70,10 +111,21 @@ struct _gallium_surface {
 
     struct pipe_resource *texture;
     struct pipe_transfer *map_transfer;
+    gallium_paint_t paint;
+
+    struct pipe_resource *vbuf;
+    struct pipe_vertex_element velem[2];
+    struct pipe_blend_state blend;
+    struct pipe_rasterizer_state rasterizer;
+    struct pipe_depth_stencil_alpha_state depthstencil;
 
     cairo_surface_t *fallback;
 };
 
+enum _shader_type {
+    SOLID_FILL = 0,
+};
+
 static cairo_surface_t *
 gallium_surface_create_internal (gallium_device_t *device,
 				 enum pipe_format format,
@@ -242,6 +294,165 @@ gallium_surface_map_to_image (gallium_surface_t *surface)
 						surface->map_transfer->stride);
 }
 
+static gallium_shader_t *
+shader_create(gallium_device_t *device)
+{
+    gallium_shader_t *shader = 0;
+
+    shader = malloc (sizeof(gallium_shader_t));
+    shader->device = device;
+    shader->fs  = cso_hash_create();
+
+    return shader;
+}
+
+static void
+shader_solid_fill(struct ureg_program *ureg,
+                  struct ureg_src *constant,
+                  struct ureg_dst *out)
+{
+    ureg_MOV(ureg, *out, constant[0]);
+}
+
+static void
+setup_constant_buffer(gallium_shader_t *shader, float *constants, int size)
+{
+    struct pipe_context *ctx    = shader->device->pipe;
+    struct pipe_resource  *buffer = shader->cbuf;
+
+    pipe_resource_reference (&buffer, NULL);
+
+    memcpy (shader->constants, constants, size);
+
+    buffer = pipe_user_buffer_create (ctx->screen,
+				      &shader->constants,
+				      sizeof(shader->constants),
+				      PIPE_BIND_VERTEX_BUFFER);
+
+    ctx->set_constant_buffer (ctx, PIPE_SHADER_FRAGMENT, 0, buffer);
+}
+
+static void *
+create_fs(struct pipe_context *ctx, shadertype_t type)
+{
+    void *ret;
+    struct ureg_program *ureg;
+    struct ureg_dst out;
+    struct ureg_src constant;
+    struct ureg_src sampler;
+    struct ureg_src in;
+
+    ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+    if (!ureg)
+        return NULL;
+
+    out = ureg_DECL_output(ureg,
+                           TGSI_SEMANTIC_COLOR,
+                           0);
+
+    constant = ureg_DECL_constant(ureg, 0);
+
+    in = ureg_DECL_fs_input(ureg,
+                            TGSI_SEMANTIC_POSITION,
+                            0,
+                            TGSI_INTERPOLATE_LINEAR);
+
+    sampler = ureg_DECL_sampler(ureg, 0);
+
+    switch (type) {
+    case SOLID_FILL:
+        shader_solid_fill(ureg, &constant, &out);
+        break;
+    }
+
+    ureg_END(ureg);
+
+    ret = ureg_create_shader_and_destroy(ureg, ctx);
+
+    return ret;
+}
+
+static INLINE void *
+shader_from_cache(gallium_device_t *device,
+                  shadertype_t key,
+                  struct cso_hash *hash)
+{
+    void *shader;
+    struct cso_hash_iter iter = cso_hash_find(hash, key);
+
+    if (cso_hash_iter_is_null(iter)) {
+        shader = create_fs(device->pipe, key);
+        cso_hash_insert(hash, key, shader);
+    } else {
+        shader = (void *)cso_hash_iter_data(iter);
+    }
+
+    return shader;
+}
+
+static void
+shader_cache_destroy(gallium_shader_t *cairo_shader)
+{
+    struct cso_hash_iter iter = cso_hash_first_node(cairo_shader->fs);
+
+    while(!cso_hash_iter_is_null(iter)) {
+        void *shader = (void *)cso_hash_iter_data(iter);
+        cso_delete_fragment_shader(cairo_shader->device->cso, shader);
+        iter = cso_hash_erase(cairo_shader->fs, iter);
+    }
+
+    cso_hash_delete(cairo_shader->fs);
+}
+
+static void
+shader_destroy(gallium_shader_t *shader)
+{
+    shader_cache_destroy(shader);
+    free(shader);
+}
+
+static void
+setup_shader(gallium_shader_t *shader, shadertype_t type)
+{
+    {
+        const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
+                                       TGSI_SEMANTIC_GENERIC };
+        const uint semantic_indexes[] = {0, 0};
+
+        shader->vs = util_make_vertex_passthrough_shader(shader->device->pipe,
+                                                         2,
+                                                         semantic_names,
+                                                         semantic_indexes);
+    }
+
+    cso_set_vertex_shader_handle(shader->device->cso, shader->vs);
+
+    shader->fs = shader_from_cache(shader->device, type, shader->fs);
+    cso_set_fragment_shader_handle(shader->device->cso, shader->fs);
+}
+
+
+static INLINE void
+unpack_color (const unsigned *src,
+	      unsigned w, unsigned h,
+	      unsigned char *p,
+	      unsigned dst_stride)
+{
+    unsigned i, j;
+
+    for (i = 0; i < h; i++) {
+        unsigned char *pRow = p;
+        for (j = 0; j < w; j++, pRow += 4) {
+            const unsigned pixel = *src++;
+            pRow[0] = (pixel >>  0) & 0xff;
+            pRow[1] = (pixel >>  8) & 0xff;
+            pRow[2] = (pixel >> 16) & 0xff;
+            pRow[3] = (pixel >> 24) & 0xff;
+        }
+        p += dst_stride;
+    }
+}
+
 static cairo_status_t
 gallium_surface_acquire_source_image (void *abstract_surface,
 				      cairo_image_surface_t **image_out,
@@ -253,7 +464,9 @@ gallium_surface_acquire_source_image (void *abstract_surface,
     cairo_surface_t *image;
     cairo_status_t status;
     struct pipe_transfer *transfer;
-    void *ptr;
+    void *rgba_packed;
+    unsigned char *color_unpacked;
+    int stride;
 
     if (surface->fallback != NULL) {
 	*image_out = (cairo_image_surface_t *)
@@ -286,10 +499,29 @@ gallium_surface_acquire_source_image (void *abstract_surface,
 				  0, 0,
 				  surface->drm.width,
 				  surface->drm.height);
-    ptr = device->pipe->transfer_map (device->pipe, transfer);
+
+    rgba_packed =
+        malloc (util_format_get_nblocks(surface->texture->format,
+					surface->drm.width,
+					surface->drm.height) *
+		util_format_get_blocksize(surface->texture->format));
+
+    rgba_packed = malloc (surface->drm.width*surface->drm.height*4);
+
+    stride = util_format_get_stride(surface->texture->format, surface->drm.width);
+
+    pipe_get_tile_raw (device->pipe,
+		       transfer,
+		       0, 0,
+		       surface->drm.width,
+		       surface->drm.height,
+		       rgba_packed,
+		       stride);
+
+    unpack_color (rgba_packed, surface->drm.width, surface->drm.height, color_unpacked, stride);
     cairo_device_release (&device->drm.base);
 
-    image = cairo_image_surface_create_for_data (ptr, format,
+    image = cairo_image_surface_create_for_data (color_unpacked, format,
 						 surface->drm.width,
 						 surface->drm.height,
 						 surface->drm.stride);
@@ -298,6 +530,8 @@ gallium_surface_acquire_source_image (void *abstract_surface,
 
     *image_out = (cairo_image_surface_t *) image;
     *image_extra = transfer;
+
+    free(rgba_packed);
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -323,6 +557,23 @@ gallium_surface_flush (void *abstract_surface)
     gallium_device_t *device = gallium_device (surface);
     cairo_status_t status;
 
+
+    {
+	cso_set_framebuffer (device->cso, &device->framebuffer);
+	cso_set_blend (device->cso, &surface->blend);
+	cso_set_depth_stencil_alpha (device->cso, &surface->depthstencil);
+	cso_set_rasterizer (device->cso, &surface->rasterizer);
+	cso_set_viewport (device->cso, &device->viewport);
+
+	cso_set_vertex_elements (device->cso, 2, surface->velem);
+
+	util_draw_vertex_buffer (device->pipe,
+				 surface->vbuf, 0,
+				 PIPE_PRIM_QUADS,
+				 4,
+				 2);
+    }
+
     if (surface->fallback == NULL) {
 	device->pipe->flush (device->pipe,
 			     PIPE_FLUSH_RENDER_CACHE,
@@ -350,20 +601,42 @@ gallium_surface_flush (void *abstract_surface)
     return status;
 }
 
+static void
+_gallium_surface_paint_solid(gallium_surface_t *surface, const cairo_pattern_t *pattern)
+{
+    cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *)pattern;
+
+    surface->paint.solid_color[0] = solid->color.red;
+    surface->paint.solid_color[1] = solid->color.green;
+    surface->paint.solid_color[2] = solid->color.blue;
+    surface->paint.solid_color[3] = 1.0f;
+}
+
 static cairo_int_status_t
 gallium_surface_paint (void			*abstract_surface,
-			  cairo_operator_t	 op,
-			  const cairo_pattern_t	*source,
-			  cairo_clip_t		*clip)
+		       cairo_operator_t	         op,
+		       const cairo_pattern_t	*source,
+		       cairo_clip_t		*clip)
 {
     gallium_surface_t *surface = abstract_surface;
+    gallium_shader_t  *shader  = gallium_device(surface)->shader;
+    cairo_status_t status;
 
     if (surface->fallback == NULL) {
 	/* XXX insert magic */
 	surface->fallback = gallium_surface_map_to_image (surface);
     }
 
-    return _cairo_surface_paint (surface->fallback, op, source, clip);
+    if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
+	_gallium_surface_paint_solid(surface, source);
+	setup_constant_buffer(shader, &surface->paint.solid_color[0], 4*sizeof(float));
+	setup_shader(shader, SOLID_FILL);
+	status = CAIRO_STATUS_SUCCESS;
+    } else {
+	status = _cairo_surface_paint (surface->fallback, op, source, clip);
+    }
+
+    return status;
 }
 
 static cairo_int_status_t
@@ -586,8 +859,73 @@ gallium_surface_create_internal (gallium_device_t *device,
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     }
 
+    {
+	float vertices[4][2][4] = {
+            {
+                { 0.0f, 0.0f, 0.0f, 1.0f },
+                { 0.0f, 0.0f, 0.0f, 1.0f }
+            },
+            {
+                { 0.0f, 1.0f, 0.0f, 1.0f },
+                { 0.0f, 0.0f, 0.0f, 1.0f }
+            },
+            {
+                { 1.0f, 1.0f, 0.0f, 1.0f },
+                { 0.0f, 0.0f, 0.0f, 1.0f }
+            },
+            {
+                { 1.0f, 0.0f, 0.0f, 1.0f },
+                { 0.0f, 0.0f, 0.0f, 1.0f }
+            }
+        };
+
+        surface->vbuf = pipe_buffer_create(device->pipe->screen, PIPE_BIND_CONSTANT_BUFFER, sizeof(vertices));
+        pipe_buffer_write(device->pipe, surface->vbuf, 0, sizeof(vertices), vertices);
+	device->pipe->set_constant_buffer(device->pipe, PIPE_SHADER_VERTEX, 0, surface->vbuf);
+    }
+
+    memset(&device->framebuffer, 0, sizeof(device->framebuffer));
+    device->framebuffer.width  = width;
+    device->framebuffer.height = height;
+    device->framebuffer.nr_cbufs = 1;
+    device->framebuffer.cbufs[0] =
+	device->screen->get_tex_surface(device->screen,
+					surface->texture,
+					0, 0, 0,
+					PIPE_BIND_RENDER_TARGET);
+
+    device->viewport.scale[0] = width;
+    device->viewport.scale[1] = height;
+    device->viewport.scale[2] = 1.0f;
+    device->viewport.scale[3] = 1.0f;
+
+    device->viewport.translate[0] = 0.0f;
+    device->viewport.translate[1] = 0.0f;
+    device->viewport.translate[2] = 0.0f;
+    device->viewport.translate[3] = 0.0f;
+
+    memset(&surface->blend, 0, sizeof(surface->blend));
+    surface->blend.rt[0].colormask = PIPE_MASK_RGBA;
+
+    memset(&surface->depthstencil, 0, sizeof(surface->depthstencil));
+
+    memset(&surface->rasterizer, 0, sizeof(surface->rasterizer));
+    surface->rasterizer.gl_rasterization_rules = 1;
+
+    memset(surface->velem, 0, sizeof(surface->velem));
+    surface->velem[0].src_offset = 0 * 4 * sizeof(float);
+    surface->velem[0].instance_divisor = 0;
+    surface->velem[0].vertex_buffer_index = 0;
+    surface->velem[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+
+    surface->velem[1].src_offset = 1 * 4 * sizeof(float);
+    surface->velem[1].instance_divisor = 0;
+    surface->velem[1].vertex_buffer_index = 0;
+    surface->velem[1].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+
     surface->pipe_format = pipe_format;
-    surface->texture = NULL;
+
+    device->shader = shader_create(device);
 
     return &surface->drm.base;
 }
@@ -730,6 +1068,7 @@ gallium_device_destroy (void *abstract_device)
 {
     gallium_device_t *device = abstract_device;
 
+    shader_destroy (device->shader);
     device->pipe->destroy (device->pipe);
     device->screen->destroy (device->screen);
     device->api->destroy (device->api);
-- 
1.6.3.3



More information about the cairo mailing list