diff options
author | Igor Oliveira <itrindade.oliveira@gmail.com> | 2010-05-30 12:50:21 -0400 |
---|---|---|
committer | Igor Oliveira <igor.oliveira@openbossa.org> | 2010-06-08 21:32:26 -0400 |
commit | 7be27feac3db6a32c1c2155c5cfccf19f38b19d5 (patch) | |
tree | 9d22ffc2157b1eaeeefe64432cd55b7e94ec9ee1 | |
parent | b3e52cfb1e3318d9ec859b186b7a68090e702f3a (diff) |
DRM/gallium3D: Initial implementation of painting method
Now we are supporting solid surfaces
-rw-r--r-- | 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 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); |