summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Oliveira <itrindade.oliveira@gmail.com>2010-05-30 12:50:21 -0400
committerIgor Oliveira <igor.oliveira@openbossa.org>2010-06-08 21:32:26 -0400
commit7be27feac3db6a32c1c2155c5cfccf19f38b19d5 (patch)
tree9d22ffc2157b1eaeeefe64432cd55b7e94ec9ee1
parentb3e52cfb1e3318d9ec859b186b7a68090e702f3a (diff)
DRM/gallium3D: Initial implementation of painting method
Now we are supporting solid surfaces
-rw-r--r--src/drm/cairo-drm-gallium-surface.c357
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 17ba136f..4d92a97e 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] = solid->color.alpha;
+}
+
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);