diff options
Diffstat (limited to 'src/gallium/state_trackers/vega')
35 files changed, 3331 insertions, 2590 deletions
diff --git a/src/gallium/state_trackers/vega/.gitignore b/src/gallium/state_trackers/vega/.gitignore new file mode 100644 index 00000000000..c452229f7f4 --- /dev/null +++ b/src/gallium/state_trackers/vega/.gitignore @@ -0,0 +1 @@ +api_tmp.h diff --git a/src/gallium/state_trackers/vega/Makefile b/src/gallium/state_trackers/vega/Makefile index 0543fac0946..7342c124c28 100644 --- a/src/gallium/state_trackers/vega/Makefile +++ b/src/gallium/state_trackers/vega/Makefile @@ -38,7 +38,14 @@ C_SOURCES = \ renderer.c \ stroker.c \ mask.c \ + text.c \ shader.c \ shaders_cache.c +GENERATED_SOURCES := api_tmp.h + include ../../Makefile.template + +MAPI := $(TOP)/src/mapi +api_tmp.h: $(MAPI)/mapi/mapi_abi.py $(MAPI)/vgapi/vgapi.csv + $(PYTHON2) $< --printer vgapi --mode app $(MAPI)/vgapi/vgapi.csv > $@ diff --git a/src/gallium/state_trackers/vega/SConscript b/src/gallium/state_trackers/vega/SConscript index a62783ab18e..4900135a1c5 100644 --- a/src/gallium/state_trackers/vega/SConscript +++ b/src/gallium/state_trackers/vega/SConscript @@ -3,6 +3,8 @@ Import('*') +from sys import executable as python_cmd + env = env.Clone() env.Append(CPPPATH = [ @@ -40,10 +42,16 @@ vega_sources = [ 'mask.c', 'shader.c', 'shaders_cache.c', + 'text.c', ] -# vgapi_header must be generated first -env.Depends(vega_sources, vgapi_header) +api_tmp = env.CodeGenerate( + target = '#/src/gallium/state_trackers/vega/api_tmp.h', + script = '#src/mapi/mapi/mapi_abi.py', + source = '#src/mapi/vgapi/vgapi.csv', + command = python_cmd + ' $SCRIPT --printer vgapi --mode app $SOURCE > $TARGET' +) +env.Depends(vega_sources, api_tmp) st_vega = env.ConvenienceLibrary( target = 'st_vega', diff --git a/src/gallium/state_trackers/vega/api.c b/src/gallium/state_trackers/vega/api.c index bf1d37493af..4bf7c71d453 100644 --- a/src/gallium/state_trackers/vega/api.c +++ b/src/gallium/state_trackers/vega/api.c @@ -28,23 +28,10 @@ #include "mapi/mapi.h" +/* define vega_spec and vega_procs for use with mapi */ +#define API_TMP_DEFINE_SPEC #include "api.h" -static const char vega_spec[] = - "1" -#define MAPI_ABI_ENTRY(ret, name, params) \ - "\0" #name "\0" -#define MAPI_ALIAS_ENTRY(alias, ret, name, params) \ - #name "\0" -#include "vgapi/vgapi_tmp.h" - "\0"; - -static const mapi_proc vega_procs[] = { -#define MAPI_ABI_ENTRY(ret, name, params) \ - (mapi_proc) vega ## name, -#include "vgapi/vgapi_tmp.h" -}; - static void api_init(void) { static boolean initialized = FALSE; diff --git a/src/gallium/state_trackers/vega/api.h b/src/gallium/state_trackers/vega/api.h index 955508dae9a..459dafb4bb0 100644 --- a/src/gallium/state_trackers/vega/api.h +++ b/src/gallium/state_trackers/vega/api.h @@ -33,10 +33,7 @@ #include "VG/vgext.h" #include "vg_manager.h" -/* declare the prototypes */ -#define MAPI_ABI_ENTRY(ret, name, params) \ - ret VG_API_ENTRY vega ## name params; -#include "vgapi/vgapi_tmp.h" +#include "api_tmp.h" struct mapi_table; diff --git a/src/gallium/state_trackers/vega/api_filters.c b/src/gallium/state_trackers/vega/api_filters.c index fa1e00d1f88..724e38241b5 100644 --- a/src/gallium/state_trackers/vega/api_filters.c +++ b/src/gallium/state_trackers/vega/api_filters.c @@ -31,7 +31,6 @@ #include "api.h" #include "renderer.h" #include "shaders_cache.h" -#include "st_inlines.h" #include "pipe/p_context.h" #include "pipe/p_state.h" @@ -42,7 +41,6 @@ #include "util/u_sampler.h" #include "util/u_string.h" - #include "asm_filters.h" @@ -73,6 +71,7 @@ static INLINE struct pipe_resource *create_texture_1d(struct vg_context *ctx, templ.width0 = color_data_len; templ.height0 = 1; templ.depth0 = 1; + templ.array_size = 1; templ.bind = PIPE_BIND_SAMPLER_VIEW; tex = screen->resource_create(screen, &templ); @@ -80,9 +79,9 @@ static INLINE struct pipe_resource *create_texture_1d(struct vg_context *ctx, { /* upload color_data */ struct pipe_transfer *transfer = pipe_get_transfer(pipe, tex, - 0, 0, 0, - PIPE_TRANSFER_READ_WRITE , - 0, 0, tex->width0, tex->height0); + 0, 0, + PIPE_TRANSFER_READ_WRITE , + 0, 0, tex->width0, tex->height0); void *map = pipe->transfer_map(pipe, transfer); memcpy(map, color_data, sizeof(VGint)*color_data_len); pipe->transfer_unmap(pipe, transfer); @@ -114,153 +113,11 @@ static INLINE struct pipe_sampler_view *create_texture_1d_view(struct vg_context return view; } -static INLINE struct pipe_surface * setup_framebuffer(struct vg_image *dst) -{ - struct vg_context *ctx = vg_current_context(); - struct pipe_context *pipe = ctx->pipe; - struct pipe_framebuffer_state fb; - struct pipe_surface *dst_surf = pipe->screen->get_tex_surface( - pipe->screen, dst->sampler_view->texture, 0, 0, 0, - PIPE_BIND_RENDER_TARGET); - - /* drawing dest */ - memset(&fb, 0, sizeof(fb)); - fb.width = dst->x + dst_surf->width; - fb.height = dst->y + dst_surf->height; - fb.nr_cbufs = 1; - fb.cbufs[0] = dst_surf; - { - VGint i; - for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i) - fb.cbufs[i] = 0; - } - cso_set_framebuffer(ctx->cso_context, &fb); - - return dst_surf; -} - -static void setup_viewport(struct vg_image *dst) -{ - struct vg_context *ctx = vg_current_context(); - vg_set_viewport(ctx, VEGA_Y0_TOP); -} - -static void setup_blend() -{ - struct vg_context *ctx = vg_current_context(); - struct pipe_blend_state blend; - memset(&blend, 0, sizeof(blend)); - blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; - blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; - blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; - blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; - if (ctx->state.vg.filter_channel_mask & VG_RED) - blend.rt[0].colormask |= PIPE_MASK_R; - if (ctx->state.vg.filter_channel_mask & VG_GREEN) - blend.rt[0].colormask |= PIPE_MASK_G; - if (ctx->state.vg.filter_channel_mask & VG_BLUE) - blend.rt[0].colormask |= PIPE_MASK_B; - if (ctx->state.vg.filter_channel_mask & VG_ALPHA) - blend.rt[0].colormask |= PIPE_MASK_A; - blend.rt[0].blend_enable = 0; - cso_set_blend(ctx->cso_context, &blend); -} - -static void setup_constant_buffer(struct vg_context *ctx, const void *buffer, - VGint param_bytes) -{ - struct pipe_context *pipe = ctx->pipe; - struct pipe_resource **cbuf = &ctx->filter.buffer; - - /* We always need to get a new buffer, to keep the drivers simple and - * avoid gratuitous rendering synchronization. */ - pipe_resource_reference(cbuf, NULL); - - *cbuf = pipe_buffer_create(pipe->screen, - PIPE_BIND_CONSTANT_BUFFER, - param_bytes); - - if (*cbuf) { - st_no_flush_pipe_buffer_write(ctx, *cbuf, - 0, param_bytes, buffer); - } - - ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, *cbuf); -} - -static void setup_samplers(struct vg_context *ctx, struct filter_info *info) -{ - struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; - struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; - struct pipe_sampler_state sampler[3]; - int num_samplers = 0; - int num_textures = 0; - - samplers[0] = NULL; - samplers[1] = NULL; - samplers[2] = NULL; - samplers[3] = NULL; - sampler_views[0] = NULL; - sampler_views[1] = NULL; - sampler_views[2] = NULL; - sampler_views[3] = NULL; - - memset(&sampler[0], 0, sizeof(struct pipe_sampler_state)); - sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - sampler[0].wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - sampler[0].min_img_filter = PIPE_TEX_MIPFILTER_LINEAR; - sampler[0].mag_img_filter = PIPE_TEX_MIPFILTER_LINEAR; - sampler[0].normalized_coords = 1; - - switch(info->tiling_mode) { - case VG_TILE_FILL: - sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_BORDER; - sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_BORDER; - memcpy(sampler[0].border_color, - ctx->state.vg.tile_fill_color, - sizeof(VGfloat) * 4); - break; - case VG_TILE_PAD: - sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - break; - case VG_TILE_REPEAT: - sampler[0].wrap_s = PIPE_TEX_WRAP_REPEAT; - sampler[0].wrap_t = PIPE_TEX_WRAP_REPEAT; - break; - case VG_TILE_REFLECT: - sampler[0].wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT; - sampler[0].wrap_t = PIPE_TEX_WRAP_MIRROR_REPEAT; - break; - default: - debug_assert(!"Unknown tiling mode"); - } - - samplers[0] = &sampler[0]; - sampler_views[0] = info->src->sampler_view; - ++num_samplers; - ++num_textures; - - if (info->extra_texture_view) { - memcpy(&sampler[1], &sampler[0], sizeof(struct pipe_sampler_state)); - samplers[1] = &sampler[1]; - sampler_views[1] = info->extra_texture_view; - ++num_samplers; - ++num_textures; - } - - - cso_set_samplers(ctx->cso_context, num_samplers, (const struct pipe_sampler_state **)samplers); - cso_set_fragment_sampler_views(ctx->cso_context, num_textures, sampler_views); -} - static struct vg_shader * setup_color_matrix(struct vg_context *ctx, void *user_data) { struct vg_shader *shader = shader_create_from_text(ctx->pipe, color_matrix_asm, 200, PIPE_SHADER_FRAGMENT); - cso_set_fragment_shader_handle(ctx->cso_context, shader->driver); return shader; } @@ -275,7 +132,6 @@ static struct vg_shader * setup_convolution(struct vg_context *ctx, void *user_d shader = shader_create_from_text(ctx->pipe, buffer, 200, PIPE_SHADER_FRAGMENT); - cso_set_fragment_shader_handle(ctx->cso_context, shader->driver); return shader; } @@ -285,7 +141,6 @@ static struct vg_shader * setup_lookup(struct vg_context *ctx, void *user_data) shader_create_from_text(ctx->pipe, lookup_asm, 200, PIPE_SHADER_FRAGMENT); - cso_set_fragment_shader_handle(ctx->cso_context, shader->driver); return shader; } @@ -316,49 +171,68 @@ static struct vg_shader * setup_lookup_single(struct vg_context *ctx, void *user shader = shader_create_from_text(ctx->pipe, buffer, 200, PIPE_SHADER_FRAGMENT); - cso_set_fragment_shader_handle(ctx->cso_context, shader->driver); return shader; } static void execute_filter(struct vg_context *ctx, struct filter_info *info) { - struct pipe_surface *dst_surf; struct vg_shader *shader; + const struct pipe_sampler_state *samplers[2]; + struct pipe_sampler_view *views[2]; + struct pipe_sampler_state sampler; + uint tex_wrap; + + memset(&sampler, 0, sizeof(sampler)); + sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.normalized_coords = 1; + + switch (info->tiling_mode) { + case VG_TILE_FILL: + tex_wrap = PIPE_TEX_WRAP_CLAMP_TO_BORDER; + /* copy border color */ + memcpy(sampler.border_color, ctx->state.vg.tile_fill_color, + sizeof(sampler.border_color)); + break; + case VG_TILE_PAD: + tex_wrap = PIPE_TEX_WRAP_CLAMP_TO_EDGE;; + break; + case VG_TILE_REPEAT: + tex_wrap = PIPE_TEX_WRAP_REPEAT;; + break; + case VG_TILE_REFLECT: + tex_wrap = PIPE_TEX_WRAP_MIRROR_REPEAT; + break; + default: + debug_assert(!"Unknown tiling mode"); + tex_wrap = 0; + break; + } + + sampler.wrap_s = tex_wrap; + sampler.wrap_t = tex_wrap; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + + samplers[0] = samplers[1] = &sampler; + views[0] = info->src->sampler_view; + views[1] = info->extra_texture_view; - cso_save_framebuffer(ctx->cso_context); - cso_save_fragment_shader(ctx->cso_context); - cso_save_viewport(ctx->cso_context); - cso_save_blend(ctx->cso_context); - cso_save_samplers(ctx->cso_context); - cso_save_fragment_sampler_views(ctx->cso_context); - - dst_surf = setup_framebuffer(info->dst); - setup_viewport(info->dst); - setup_blend(); - setup_constant_buffer(ctx, info->const_buffer, info->const_buffer_len); shader = info->setup_shader(ctx, info->user_data); - setup_samplers(ctx, info); - - renderer_draw_texture(ctx->renderer, - info->src->sampler_view->texture, - info->dst->x, info->dst->y, - info->dst->x + info->dst->width, - info->dst->y + info->dst->height, - info->dst->x, info->dst->y, - info->dst->x + info->dst->width, - info->dst->y + info->dst->height); - - cso_restore_framebuffer(ctx->cso_context); - cso_restore_fragment_shader(ctx->cso_context); - cso_restore_viewport(ctx->cso_context); - cso_restore_blend(ctx->cso_context); - cso_restore_samplers(ctx->cso_context); - cso_restore_fragment_sampler_views(ctx->cso_context); - vg_shader_destroy(ctx, shader); + if (renderer_filter_begin(ctx->renderer, + info->dst->sampler_view->texture, VG_TRUE, + ctx->state.vg.filter_channel_mask, + samplers, views, (info->extra_texture_view) ? 2 : 1, + shader->driver, info->const_buffer, info->const_buffer_len)) { + renderer_filter(ctx->renderer, + info->dst->x, info->dst->y, info->dst->width, info->dst->height, + info->src->x, info->src->y, info->src->width, info->src->height); + renderer_filter_end(ctx->renderer); + } - pipe_surface_reference(&dst_surf, NULL); + vg_shader_destroy(ctx, shader); } void vegaColorMatrix(VGImage dst, VGImage src, diff --git a/src/gallium/state_trackers/vega/api_images.c b/src/gallium/state_trackers/vega/api_images.c index e9f038c5f92..ad95409cd00 100644 --- a/src/gallium/state_trackers/vega/api_images.c +++ b/src/gallium/state_trackers/vega/api_images.c @@ -303,7 +303,8 @@ void vegaDrawImage(VGImage image) } vg_validate_state(ctx); - image_draw((struct vg_image*)image); + image_draw((struct vg_image*)image, + &ctx->state.vg.image_user_to_surface_matrix); } void vegaSetPixels(VGint dx, VGint dy, @@ -399,7 +400,6 @@ void vegaReadPixels(void * data, VGint dataStride, struct st_framebuffer *stfb = ctx->draw_buffer; struct st_renderbuffer *strb = stfb->strb; - struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4]; VGfloat *df = (VGfloat*)temp; @@ -435,21 +435,21 @@ void vegaReadPixels(void * data, VGint dataStride, sy = 0; } - if (sx + width > fb->width || sy + height > fb->height) { - width = fb->width - sx; - height = fb->height - sy; + if (sx + width > stfb->width || sy + height > stfb->height) { + width = stfb->width - sx; + height = stfb->height - sy; /* nothing to read */ if (width <= 0 || height <= 0) return; } { - VGint y = (fb->height - sy) - 1, yStep = -1; + VGint y = (stfb->height - sy) - 1, yStep = -1; struct pipe_transfer *transfer; - transfer = pipe_get_transfer(pipe, strb->texture, 0, 0, 0, - PIPE_TRANSFER_READ, - 0, 0, sx + width, fb->height - sy); + transfer = pipe_get_transfer(pipe, strb->texture, 0, 0, + PIPE_TRANSFER_READ, + 0, 0, sx + width, stfb->height - sy); /* Do a row at a time to flip image data vertically */ for (i = 0; i < height; i++) { @@ -472,8 +472,8 @@ void vegaCopyPixels(VGint dx, VGint dy, VGint width, VGint height) { struct vg_context *ctx = vg_current_context(); - struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; - struct st_renderbuffer *strb = ctx->draw_buffer->strb; + struct st_framebuffer *stfb = ctx->draw_buffer; + struct st_renderbuffer *strb = stfb->strb; if (width <= 0 || height <= 0) { vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); @@ -481,8 +481,8 @@ void vegaCopyPixels(VGint dx, VGint dy, } /* do nothing if we copy from outside the fb */ - if (dx >= (VGint)fb->width || dy >= (VGint)fb->height || - sx >= (VGint)fb->width || sy >= (VGint)fb->height) + if (dx >= (VGint)stfb->width || dy >= (VGint)stfb->height || + sx >= (VGint)stfb->width || sy >= (VGint)stfb->height) return; vg_validate_state(ctx); diff --git a/src/gallium/state_trackers/vega/api_masks.c b/src/gallium/state_trackers/vega/api_masks.c index 189390ec2d3..beb15c33a59 100644 --- a/src/gallium/state_trackers/vega/api_masks.c +++ b/src/gallium/state_trackers/vega/api_masks.c @@ -28,6 +28,7 @@ #include "mask.h" #include "api.h" +#include "renderer.h" #include "vg_context.h" #include "pipe/p_context.h" @@ -36,119 +37,6 @@ #include "util/u_pack_color.h" #include "util/u_draw_quad.h" -#define DISABLE_1_1_MASKING 1 - -/** - * Draw a screen-aligned quadrilateral. - * Coords are window coords with y=0=bottom. These coords will be transformed - * by the vertex shader and viewport transform. - */ -static void -draw_clear_quad(struct vg_context *st, - float x0, float y0, float x1, float y1, float z, - const VGfloat color[4]) -{ - struct pipe_context *pipe = st->pipe; - struct pipe_resource *buf; - VGuint i; - - /* positions */ - st->clear.vertices[0][0][0] = x0; - st->clear.vertices[0][0][1] = y0; - - st->clear.vertices[1][0][0] = x1; - st->clear.vertices[1][0][1] = y0; - - st->clear.vertices[2][0][0] = x1; - st->clear.vertices[2][0][1] = y1; - - st->clear.vertices[3][0][0] = x0; - st->clear.vertices[3][0][1] = y1; - - /* same for all verts: */ - for (i = 0; i < 4; i++) { - st->clear.vertices[i][0][2] = z; - st->clear.vertices[i][0][3] = 1.0; - st->clear.vertices[i][1][0] = color[0]; - st->clear.vertices[i][1][1] = color[1]; - st->clear.vertices[i][1][2] = color[2]; - st->clear.vertices[i][1][3] = color[3]; - } - - - /* put vertex data into vbuf */ - buf = pipe_user_buffer_create(pipe->screen, - st->clear.vertices, - sizeof(st->clear.vertices), - PIPE_BIND_VERTEX_BUFFER); - - - /* draw */ - if (buf) { - cso_set_vertex_elements(st->cso_context, 2, st->velems); - - util_draw_vertex_buffer(pipe, buf, 0, - PIPE_PRIM_TRIANGLE_FAN, - 4, /* verts */ - 2); /* attribs/vert */ - - pipe_resource_reference(&buf, NULL); - } -} - -/** - * Do vgClear by drawing a quadrilateral. - */ -static void -clear_with_quad(struct vg_context *st, float x0, float y0, - float width, float height, const VGfloat clear_color[4]) -{ - VGfloat x1, y1; - - vg_validate_state(st); - - x1 = x0 + width; - y1 = y0 + height; - - /* - printf("%s %f,%f %f,%f\n", __FUNCTION__, - x0, y0, - x1, y1); - */ - - cso_save_blend(st->cso_context); - cso_save_rasterizer(st->cso_context); - cso_save_fragment_shader(st->cso_context); - cso_save_vertex_shader(st->cso_context); - - /* blend state: RGBA masking */ - { - struct pipe_blend_state blend; - memset(&blend, 0, sizeof(blend)); - blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; - blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; - blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; - blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; - blend.rt[0].colormask = PIPE_MASK_RGBA; - cso_set_blend(st->cso_context, &blend); - } - - cso_set_rasterizer(st->cso_context, &st->clear.raster); - - cso_set_fragment_shader_handle(st->cso_context, st->clear.fs); - cso_set_vertex_shader_handle(st->cso_context, vg_clear_vs(st)); - - /* draw quad matching scissor rect (XXX verify coord round-off) */ - draw_clear_quad(st, x0, y0, x1, y1, 0, clear_color); - - /* Restore pipe state */ - cso_restore_blend(st->cso_context); - cso_restore_rasterizer(st->cso_context); - cso_restore_fragment_shader(st->cso_context); - cso_restore_vertex_shader(st->cso_context); -} - - void vegaMask(VGHandle mask, VGMaskOperation operation, VGint x, VGint y, VGint width, VGint height) @@ -176,12 +64,8 @@ void vegaMask(VGHandle mask, VGMaskOperation operation, struct vg_image *image = (struct vg_image *)mask; mask_using_image(image, operation, x, y, width, height); } else if (vg_object_is_valid((void*)mask, VG_OBJECT_MASK)) { -#if DISABLE_1_1_MASKING - return; -#else struct vg_mask_layer *layer = (struct vg_mask_layer *)mask; mask_using_layer(layer, operation, x, y, width, height); -#endif } else { vg_set_error(ctx, VG_BAD_HANDLE_ERROR); } @@ -191,7 +75,7 @@ void vegaClear(VGint x, VGint y, VGint width, VGint height) { struct vg_context *ctx = vg_current_context(); - struct pipe_framebuffer_state *fb; + struct st_framebuffer *stfb = ctx->draw_buffer; if (width <= 0 || height <= 0) { vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); @@ -208,14 +92,15 @@ void vegaClear(VGint x, VGint y, ctx->state.vg.clear_color[3]); #endif - fb = &ctx->state.g3d.fb; /* check for a whole surface clear */ if (!ctx->state.vg.scissoring && - (x == 0 && y == 0 && width == fb->width && height == fb->height)) { + (x == 0 && y == 0 && width == stfb->width && height == stfb->height)) { ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_COLOR | PIPE_CLEAR_DEPTHSTENCIL, ctx->state.vg.clear_color, 1., 0); - } else { - clear_with_quad(ctx, x, y, width, height, ctx->state.vg.clear_color); + } else if (renderer_clear_begin(ctx->renderer)) { + /* XXX verify coord round-off */ + renderer_clear(ctx->renderer, x, y, width, height, ctx->state.vg.clear_color); + renderer_clear_end(ctx->renderer); } } @@ -247,10 +132,6 @@ void vegaRenderToMask(VGPath path, return; } -#if DISABLE_1_1_MASKING - return; -#endif - vg_validate_state(ctx); mask_render_to((struct path *)path, paintModes, operation); @@ -328,9 +209,8 @@ void vegaFillMaskLayer(VGMaskLayer maskLayer, return; } -#if DISABLE_1_1_MASKING - return; -#endif + vg_validate_state(ctx); + mask_layer_fill(mask, x, y, width, height, value); } @@ -355,9 +235,7 @@ void vegaCopyMask(VGMaskLayer maskLayer, return; } -#if DISABLE_1_1_MASKING - return; -#endif + vg_validate_state(ctx); mask = (struct vg_mask_layer*)maskLayer; mask_copy(mask, sx, sy, dx, dy, width, height); diff --git a/src/gallium/state_trackers/vega/api_misc.c b/src/gallium/state_trackers/vega/api_misc.c index e648549745b..9e2ab03e01a 100644 --- a/src/gallium/state_trackers/vega/api_misc.c +++ b/src/gallium/state_trackers/vega/api_misc.c @@ -63,8 +63,8 @@ const VGubyte *vegaGetString(VGStringID name) { struct vg_context *ctx = vg_current_context(); static const VGubyte *vendor = (VGubyte *)"Tungsten Graphics, Inc"; - static const VGubyte *renderer = (VGubyte *)"Vega OpenVG 1.0"; - static const VGubyte *version = (VGubyte *)"1.0"; + static const VGubyte *renderer = (VGubyte *)"Vega OpenVG 1.1"; + static const VGubyte *version = (VGubyte *)"1.1"; if (!ctx) return NULL; diff --git a/src/gallium/state_trackers/vega/api_params.c b/src/gallium/state_trackers/vega/api_params.c index a10b009e631..a73b6c3effe 100644 --- a/src/gallium/state_trackers/vega/api_params.c +++ b/src/gallium/state_trackers/vega/api_params.c @@ -30,6 +30,7 @@ #include "paint.h" #include "path.h" #include "image.h" +#include "text.h" #include "matrix.h" #include "api_consts.h" #include "api.h" @@ -174,6 +175,7 @@ void vegaSeti (VGParamType type, VGint value) error = VG_ILLEGAL_ARGUMENT_ERROR; else state->image_mode = value; + break; #ifdef OPENVG_VERSION_1_1 case VG_COLOR_TRANSFORM: state->color_transform = value; @@ -1500,7 +1502,8 @@ VGint vegaGetParameteri(VGHandle object, #ifdef OPENVG_VERSION_1_1 case VG_FONT_NUM_GLYPHS: { - return 1; + struct vg_font *font = (struct vg_font*)object; + return font_num_glyphs(font); } break; #endif diff --git a/src/gallium/state_trackers/vega/api_path.c b/src/gallium/state_trackers/vega/api_path.c index f76adddb584..fe57b7671d9 100644 --- a/src/gallium/state_trackers/vega/api_path.c +++ b/src/gallium/state_trackers/vega/api_path.c @@ -479,6 +479,7 @@ void vegaDrawPath(VGPath path, VGbitfield paintModes) if (path_is_empty((struct path*)path)) return; - path_render((struct path*)path, paintModes); + path_render((struct path*)path, paintModes, + &ctx->state.vg.path_user_to_surface_matrix); } diff --git a/src/gallium/state_trackers/vega/api_text.c b/src/gallium/state_trackers/vega/api_text.c index 2a62da0a1de..7c6b4794099 100644 --- a/src/gallium/state_trackers/vega/api_text.c +++ b/src/gallium/state_trackers/vega/api_text.c @@ -27,21 +27,15 @@ #include "VG/openvg.h" #include "vg_context.h" +#include "text.h" +#include "api.h" #include "util/u_memory.h" #ifdef OPENVG_VERSION_1_1 -struct vg_font { - struct vg_object base; - - VGint glyph_indices[200]; - VGint num_glyphs; -}; - VGFont vegaCreateFont(VGint glyphCapacityHint) { - struct vg_font *font = 0; struct vg_context *ctx = vg_current_context(); if (glyphCapacityHint < 0) { @@ -49,10 +43,7 @@ VGFont vegaCreateFont(VGint glyphCapacityHint) return VG_INVALID_HANDLE; } - font = CALLOC_STRUCT(vg_font); - vg_init_object(&font->base, ctx, VG_OBJECT_FONT); - vg_context_add_object(ctx, VG_OBJECT_FONT, font); - return (VGFont)font; + return (VGFont) font_create(glyphCapacityHint); } void vegaDestroyFont(VGFont f) @@ -64,20 +55,23 @@ void vegaDestroyFont(VGFont f) vg_set_error(ctx, VG_BAD_HANDLE_ERROR); return; } + if (!vg_object_is_valid((void *) font, VG_OBJECT_FONT)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } - vg_context_remove_object(ctx, VG_OBJECT_FONT, font); - /*free(font);*/ + font_destroy(font); } void vegaSetGlyphToPath(VGFont font, VGuint glyphIndex, VGPath path, VGboolean isHinted, - VGfloat glyphOrigin [2], - VGfloat escapement[2]) + const VGfloat glyphOrigin[2], + const VGfloat escapement[2]) { struct vg_context *ctx = vg_current_context(); - struct vg_object *pathObj; + struct path *pathObj; struct vg_font *f; if (font == VG_INVALID_HANDLE || @@ -95,25 +89,22 @@ void vegaSetGlyphToPath(VGFont font, vg_set_error(ctx, VG_BAD_HANDLE_ERROR); return; } - pathObj = (struct vg_object*)path; - if (pathObj && pathObj->type != VG_OBJECT_PATH) { - vg_set_error(ctx, VG_BAD_HANDLE_ERROR); - return; - } - f = (struct vg_font*)font; - f->glyph_indices[f->num_glyphs] = glyphIndex; - ++f->num_glyphs; + pathObj = (struct path*) path; + f = (struct vg_font*) font; + + font_set_glyph_to_path(f, glyphIndex, pathObj, + isHinted, glyphOrigin, escapement); } void vegaSetGlyphToImage(VGFont font, VGuint glyphIndex, VGImage image, - VGfloat glyphOrigin [2], - VGfloat escapement[2]) + const VGfloat glyphOrigin[2], + const VGfloat escapement[2]) { struct vg_context *ctx = vg_current_context(); - struct vg_object *img_obj; + struct vg_image *img_obj; struct vg_font *f; if (font == VG_INVALID_HANDLE || @@ -131,26 +122,11 @@ void vegaSetGlyphToImage(VGFont font, vg_set_error(ctx, VG_BAD_HANDLE_ERROR); return; } - img_obj = (struct vg_object*)image; - if (img_obj && img_obj->type != VG_OBJECT_IMAGE) { - vg_set_error(ctx, VG_BAD_HANDLE_ERROR); - return; - } + + img_obj = (struct vg_image*)image; f = (struct vg_font*)font; - f->glyph_indices[f->num_glyphs] = glyphIndex; - ++f->num_glyphs; -} -static INLINE VGboolean font_contains_glyph(struct vg_font *font, - VGuint glyph_index) -{ - VGint i; - for (i = 0; i < font->num_glyphs; ++i) { - if (font->glyph_indices[i] == glyph_index) { - return VG_TRUE; - } - } - return VG_FALSE; + font_set_glyph_to_image(f, glyphIndex, img_obj, glyphOrigin, escapement); } void vegaClearGlyph(VGFont font, @@ -158,30 +134,15 @@ void vegaClearGlyph(VGFont font, { struct vg_context *ctx = vg_current_context(); struct vg_font *f; - VGint i; if (font == VG_INVALID_HANDLE) { vg_set_error(ctx, VG_BAD_HANDLE_ERROR); return; } - if (glyphIndex <= 0) { - vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); - return; - } - f = (struct vg_font*)font; - if (!font_contains_glyph(f, glyphIndex)) { - vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); - return; - } - for (i = 0; i < f->num_glyphs; ++i) { - if (f->glyph_indices[i] == glyphIndex) { - /*FIXME*/ - f->glyph_indices[f->num_glyphs] = 0; - --f->num_glyphs; - return; - } - } + f = (struct vg_font*) font; + + font_clear_glyph(f, glyphIndex); } void vegaDrawGlyph(VGFont font, @@ -196,31 +157,24 @@ void vegaDrawGlyph(VGFont font, vg_set_error(ctx, VG_BAD_HANDLE_ERROR); return; } - if (glyphIndex <= 0) { - vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); - return; - } if (paintModes & (~(VG_STROKE_PATH|VG_FILL_PATH))) { vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); return; } f = (struct vg_font*)font; - if (!font_contains_glyph(f, glyphIndex)) { - vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); - return; - } + + font_draw_glyph(f, glyphIndex, paintModes, allowAutoHinting); } void vegaDrawGlyphs(VGFont font, VGint glyphCount, - VGuint *glyphIndices, - VGfloat *adjustments_x, - VGfloat *adjustments_y, + const VGuint *glyphIndices, + const VGfloat *adjustments_x, + const VGfloat *adjustments_y, VGbitfield paintModes, VGboolean allowAutoHinting) { struct vg_context *ctx = vg_current_context(); - VGint i; struct vg_font *f; if (font == VG_INVALID_HANDLE) { @@ -235,8 +189,8 @@ void vegaDrawGlyphs(VGFont font, vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); return; } - if (!adjustments_x || !is_aligned(adjustments_x) || - !adjustments_y || !is_aligned(adjustments_y)) { + if ((adjustments_x && !is_aligned(adjustments_x)) || + (adjustments_y && !is_aligned(adjustments_y))) { vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); return; } @@ -246,13 +200,9 @@ void vegaDrawGlyphs(VGFont font, } f = (struct vg_font*)font; - for (i = 0; i < glyphCount; ++i) { - VGuint glyph_index = glyphIndices[i]; - if (!font_contains_glyph(f, glyph_index)) { - vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); - return; - } - } + + font_draw_glyphs(f, glyphCount, glyphIndices, + adjustments_x, adjustments_y, paintModes, allowAutoHinting); } -#endif +#endif /* OPENVG_VERSION_1_1 */ diff --git a/src/gallium/state_trackers/vega/asm_fill.h b/src/gallium/state_trackers/vega/asm_fill.h index 27773467fa8..77e6a14fe99 100644 --- a/src/gallium/state_trackers/vega/asm_fill.h +++ b/src/gallium/state_trackers/vega/asm_fill.h @@ -44,9 +44,31 @@ solid_fill( struct ureg_program *ureg, struct ureg_dst *temp, struct ureg_src *constant) { - ureg_MOV(ureg, *out, constant[0]); + ureg_MOV(ureg, *out, constant[2]); } +/** + * Perform frag-coord-to-paint-coord transform. The transformation is in + * CONST[4..6]. + */ +#define PAINT_TRANSFORM \ + ureg_MOV(ureg, ureg_writemask(temp[0], TGSI_WRITEMASK_XY), in[0]); \ + ureg_MOV(ureg, \ + ureg_writemask(temp[0], TGSI_WRITEMASK_Z), \ + ureg_scalar(constant[3], TGSI_SWIZZLE_Y)); \ + ureg_DP3(ureg, temp[1], constant[4], ureg_src(temp[0])); \ + ureg_DP3(ureg, temp[2], constant[5], ureg_src(temp[0])); \ + ureg_DP3(ureg, temp[3], constant[6], ureg_src(temp[0])); \ + ureg_RCP(ureg, temp[3], ureg_src(temp[3])); \ + ureg_MUL(ureg, temp[1], ureg_src(temp[1]), ureg_src(temp[3])); \ + ureg_MUL(ureg, temp[2], ureg_src(temp[2]), ureg_src(temp[3])); \ + ureg_MOV(ureg, \ + ureg_writemask(temp[4], TGSI_WRITEMASK_X), \ + ureg_src(temp[1])); \ + ureg_MOV(ureg, \ + ureg_writemask(temp[4], TGSI_WRITEMASK_Y), \ + ureg_src(temp[2])); + static INLINE void linear_grad( struct ureg_program *ureg, struct ureg_dst *out, @@ -55,30 +77,19 @@ linear_grad( struct ureg_program *ureg, struct ureg_dst *temp, struct ureg_src *constant) { + PAINT_TRANSFORM - ureg_MOV(ureg, - ureg_writemask(temp[0], TGSI_WRITEMASK_XY), - in[0]); - ureg_MOV(ureg, - ureg_writemask(temp[0], TGSI_WRITEMASK_Z), - ureg_scalar(constant[1], TGSI_SWIZZLE_Y)); - ureg_DP3(ureg, temp[1], constant[2], ureg_src(temp[0])); - ureg_DP3(ureg, temp[2], constant[3], ureg_src(temp[0])); - ureg_DP3(ureg, temp[3], constant[4], ureg_src(temp[0])); - ureg_RCP(ureg, temp[3], ureg_src(temp[3])); - ureg_MUL(ureg, temp[1], ureg_src(temp[1]), ureg_src(temp[3])); - ureg_MUL(ureg, temp[2], ureg_src(temp[2]), ureg_src(temp[3])); - ureg_MOV(ureg, ureg_writemask(temp[4], TGSI_WRITEMASK_X), ureg_src(temp[1])); - ureg_MOV(ureg, ureg_writemask(temp[4], TGSI_WRITEMASK_Y), ureg_src(temp[2])); + /* grad = DP2((x, y), CONST[2].xy) * CONST[2].z */ ureg_MUL(ureg, temp[0], - ureg_scalar(constant[0], TGSI_SWIZZLE_Y), + ureg_scalar(constant[2], TGSI_SWIZZLE_Y), ureg_scalar(ureg_src(temp[4]), TGSI_SWIZZLE_Y)); ureg_MAD(ureg, temp[1], - ureg_scalar(constant[0], TGSI_SWIZZLE_X), + ureg_scalar(constant[2], TGSI_SWIZZLE_X), ureg_scalar(ureg_src(temp[4]), TGSI_SWIZZLE_X), ureg_src(temp[0])); ureg_MUL(ureg, temp[2], ureg_src(temp[1]), - ureg_scalar(constant[0], TGSI_SWIZZLE_Z)); + ureg_scalar(constant[2], TGSI_SWIZZLE_Z)); + ureg_TEX(ureg, *out, TGSI_TEXTURE_1D, ureg_src(temp[2]), sampler[0]); } @@ -90,52 +101,32 @@ radial_grad( struct ureg_program *ureg, struct ureg_dst *temp, struct ureg_src *constant) { - - ureg_MOV(ureg, ureg_writemask(temp[0], TGSI_WRITEMASK_XY), in[0]); - ureg_MOV(ureg, - ureg_writemask(temp[0], TGSI_WRITEMASK_Z), - ureg_scalar(constant[1], TGSI_SWIZZLE_Y)); - ureg_DP3(ureg, temp[1], constant[2], ureg_src(temp[0])); - ureg_DP3(ureg, temp[2], constant[3], ureg_src(temp[0])); - ureg_DP3(ureg, temp[3], constant[4], ureg_src(temp[0])); + PAINT_TRANSFORM + + /* + * Calculate (sqrt(B^2 + AC) - B) / A, where + * + * A is CONST[2].z, + * B is DP2((x, y), CONST[2].xy), and + * C is DP2((x, y), (x, y)). + */ + + /* B and C */ + ureg_DP2(ureg, temp[0], ureg_src(temp[4]), constant[2]); + ureg_DP2(ureg, temp[1], ureg_src(temp[4]), ureg_src(temp[4])); + + /* the square root */ + ureg_MUL(ureg, temp[2], ureg_src(temp[0]), ureg_src(temp[0])); + ureg_MAD(ureg, temp[3], ureg_src(temp[1]), + ureg_scalar(constant[2], TGSI_SWIZZLE_Z), ureg_src(temp[2])); + ureg_RSQ(ureg, temp[3], ureg_src(temp[3])); ureg_RCP(ureg, temp[3], ureg_src(temp[3])); - ureg_MUL(ureg, temp[1], ureg_src(temp[1]), ureg_src(temp[3])); - ureg_MUL(ureg, temp[2], ureg_src(temp[2]), ureg_src(temp[3])); - ureg_MOV(ureg, ureg_writemask(temp[5], TGSI_WRITEMASK_X), ureg_src(temp[1])); - ureg_MOV(ureg, ureg_writemask(temp[5], TGSI_WRITEMASK_Y), ureg_src(temp[2])); - ureg_MUL(ureg, temp[0], ureg_scalar(constant[0], TGSI_SWIZZLE_Y), - ureg_scalar(ureg_src(temp[5]), TGSI_SWIZZLE_Y)); - ureg_MAD(ureg, temp[1], - ureg_scalar(constant[0], TGSI_SWIZZLE_X), - ureg_scalar(ureg_src(temp[5]), TGSI_SWIZZLE_X), ureg_src(temp[0])); - ureg_ADD(ureg, temp[1], ureg_src(temp[1]), ureg_src(temp[1])); - ureg_MUL(ureg, temp[3], - ureg_scalar(ureg_src(temp[5]), TGSI_SWIZZLE_Y), - ureg_scalar(ureg_src(temp[5]), TGSI_SWIZZLE_Y)); - ureg_MAD(ureg, temp[4], - ureg_scalar(ureg_src(temp[5]), TGSI_SWIZZLE_X), - ureg_scalar(ureg_src(temp[5]), TGSI_SWIZZLE_X), - ureg_src(temp[3])); - ureg_MOV(ureg, temp[4], ureg_negate(ureg_src(temp[4]))); - ureg_MUL(ureg, temp[2], - ureg_scalar(constant[0], TGSI_SWIZZLE_Z), - ureg_src(temp[4])); - ureg_MUL(ureg, temp[0], - ureg_scalar(constant[1], TGSI_SWIZZLE_W), - ureg_src(temp[2])); - ureg_MUL(ureg, temp[3], ureg_src(temp[1]), ureg_src(temp[1])); - - ureg_SUB(ureg, temp[2], ureg_src(temp[3]), ureg_src(temp[0])); - ureg_RSQ(ureg, temp[2], ureg_abs(ureg_src(temp[2]))); - ureg_RCP(ureg, temp[2], ureg_src(temp[2])); - ureg_SUB(ureg, temp[1], ureg_src(temp[2]), ureg_src(temp[1])); - ureg_ADD(ureg, temp[0], - ureg_scalar(constant[0], TGSI_SWIZZLE_Z), - ureg_scalar(constant[0], TGSI_SWIZZLE_Z)); - ureg_RCP(ureg, temp[0], ureg_src(temp[0])); - ureg_MUL(ureg, temp[2], ureg_src(temp[1]), ureg_src(temp[0])); - ureg_TEX(ureg, *out, TGSI_TEXTURE_1D, ureg_src(temp[2]), sampler[0]); + ureg_SUB(ureg, temp[3], ureg_src(temp[3]), ureg_src(temp[0])); + ureg_RCP(ureg, temp[0], ureg_scalar(constant[2], TGSI_SWIZZLE_Z)); + ureg_MUL(ureg, temp[0], ureg_src(temp[0]), ureg_src(temp[3])); + + ureg_TEX(ureg, *out, TGSI_TEXTURE_1D, ureg_src(temp[0]), sampler[0]); } @@ -147,22 +138,11 @@ pattern( struct ureg_program *ureg, struct ureg_dst *temp, struct ureg_src *constant) { - ureg_MOV(ureg, - ureg_writemask(temp[0], TGSI_WRITEMASK_XY), - in[0]); - ureg_MOV(ureg, - ureg_writemask(temp[0], TGSI_WRITEMASK_Z), - ureg_scalar(constant[1], TGSI_SWIZZLE_Y)); - ureg_DP3(ureg, temp[1], constant[2], ureg_src(temp[0])); - ureg_DP3(ureg, temp[2], constant[3], ureg_src(temp[0])); - ureg_DP3(ureg, temp[3], constant[4], ureg_src(temp[0])); - ureg_RCP(ureg, temp[3], ureg_src(temp[3])); - ureg_MUL(ureg, temp[1], ureg_src(temp[1]), ureg_src(temp[3])); - ureg_MUL(ureg, temp[2], ureg_src(temp[2]), ureg_src(temp[3])); - ureg_MOV(ureg, ureg_writemask(temp[4], TGSI_WRITEMASK_X), ureg_src(temp[1])); - ureg_MOV(ureg, ureg_writemask(temp[4], TGSI_WRITEMASK_Y), ureg_src(temp[2])); + PAINT_TRANSFORM + + /* (s, t) = (x / tex_width, y / tex_height) */ ureg_RCP(ureg, temp[0], - ureg_swizzle(constant[1], + ureg_swizzle(constant[3], TGSI_SWIZZLE_Z, TGSI_SWIZZLE_W, TGSI_SWIZZLE_Z, @@ -176,22 +156,21 @@ pattern( struct ureg_program *ureg, ureg_writemask(temp[1], TGSI_WRITEMASK_Y), ureg_src(temp[1]), ureg_src(temp[0])); + ureg_TEX(ureg, *out, TGSI_TEXTURE_2D, ureg_src(temp[1]), sampler[0]); } static INLINE void -mask( struct ureg_program *ureg, - struct ureg_dst *out, - struct ureg_src *in, - struct ureg_src *sampler, - struct ureg_dst *temp, - struct ureg_src *constant) +paint_degenerate( struct ureg_program *ureg, + struct ureg_dst *out, + struct ureg_src *in, + struct ureg_src *sampler, + struct ureg_dst *temp, + struct ureg_src *constant) { - ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[0], sampler[1]); - ureg_MUL(ureg, ureg_writemask(temp[0], TGSI_WRITEMASK_W), - ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W), - ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W)); - ureg_MOV(ureg, *out, ureg_src(temp[0])); + /* CONST[3].y is 1.0f */ + ureg_MOV(ureg, temp[1], ureg_scalar(constant[3], TGSI_SWIZZLE_Y)); + ureg_TEX(ureg, *out, TGSI_TEXTURE_1D, ureg_src(temp[1]), sampler[0]); } static INLINE void @@ -202,7 +181,9 @@ image_normal( struct ureg_program *ureg, struct ureg_dst *temp, struct ureg_src *constant) { - ureg_TEX(ureg, *out, TGSI_TEXTURE_2D, in[1], sampler[3]); + /* store and pass image color in TEMP[1] */ + ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[1], sampler[3]); + ureg_MOV(ureg, *out, ureg_src(temp[1])); } @@ -214,6 +195,7 @@ image_multiply( struct ureg_program *ureg, struct ureg_dst *temp, struct ureg_src *constant) { + /* store and pass image color in TEMP[1] */ ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[1], sampler[3]); ureg_MUL(ureg, *out, ureg_src(temp[0]), ureg_src(temp[1])); } @@ -227,43 +209,279 @@ image_stencil( struct ureg_program *ureg, struct ureg_dst *temp, struct ureg_src *constant) { + /* store and pass image color in TEMP[1] */ ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[1], sampler[3]); - ureg_MUL(ureg, *out, ureg_src(temp[0]), ureg_src(temp[1])); + ureg_MOV(ureg, *out, ureg_src(temp[0])); +} + +static INLINE void +color_transform( struct ureg_program *ureg, + struct ureg_dst *out, + struct ureg_src *in, + struct ureg_src *sampler, + struct ureg_dst *temp, + struct ureg_src *constant) +{ + /* note that TEMP[1] may already be used for image color */ + + ureg_MAD(ureg, temp[2], ureg_src(temp[0]), constant[0], constant[1]); + /* clamp to [0.0f, 1.0f] */ + ureg_CLAMP(ureg, temp[2], + ureg_src(temp[2]), + ureg_scalar(constant[3], TGSI_SWIZZLE_X), + ureg_scalar(constant[3], TGSI_SWIZZLE_Y)); + ureg_MOV(ureg, *out, ureg_src(temp[2])); +} + +static INLINE void +alpha_normal( struct ureg_program *ureg, + struct ureg_dst *out, + struct ureg_src *in, + struct ureg_src *sampler, + struct ureg_dst *temp, + struct ureg_src *constant) +{ + /* save per-channel alpha in TEMP[1] */ + ureg_MOV(ureg, temp[1], ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W)); + + ureg_MOV(ureg, *out, ureg_src(temp[0])); } -#define EXTENDED_BLENDER_OVER_FUNC \ - ureg_SUB(ureg, temp[3], \ - ureg_scalar(constant[1], TGSI_SWIZZLE_Y), \ - ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W)); \ - ureg_SUB(ureg, temp[3], \ - ureg_scalar(constant[1], TGSI_SWIZZLE_Y), \ - ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W)); \ - ureg_MUL(ureg, temp[3], ureg_src(temp[0]), ureg_src(temp[3])); \ - ureg_MUL(ureg, temp[4], ureg_src(temp[1]), ureg_src(temp[4])); \ - ureg_ADD(ureg, temp[3], ureg_src(temp[3]), ureg_src(temp[4])); +static INLINE void +alpha_per_channel( struct ureg_program *ureg, + struct ureg_dst *out, + struct ureg_src *in, + struct ureg_src *sampler, + struct ureg_dst *temp, + struct ureg_src *constant) +{ + /* save per-channel alpha in TEMP[1] */ + ureg_MUL(ureg, + ureg_writemask(temp[1], TGSI_WRITEMASK_W), + ureg_src(temp[0]), + ureg_src(temp[1])); + ureg_MUL(ureg, + ureg_writemask(temp[1], TGSI_WRITEMASK_XYZ), + ureg_src(temp[1]), + ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W)); + /* update alpha */ + ureg_MOV(ureg, + ureg_writemask(temp[0], TGSI_WRITEMASK_W), + ureg_src(temp[1])); + ureg_MOV(ureg, *out, ureg_src(temp[0])); +} +/** + * Premultiply src and dst. + */ static INLINE void -blend_multiply( struct ureg_program *ureg, +blend_premultiply( struct ureg_program *ureg, + struct ureg_src src, + struct ureg_src src_channel_alpha, + struct ureg_src dst) +{ + /* premultiply src */ + ureg_MUL(ureg, + ureg_writemask(ureg_dst(src), TGSI_WRITEMASK_XYZ), + src, + src_channel_alpha); + /* premultiply dst */ + ureg_MUL(ureg, + ureg_writemask(ureg_dst(dst), TGSI_WRITEMASK_XYZ), + dst, + ureg_scalar(dst, TGSI_SWIZZLE_W)); +} + +/** + * Unpremultiply src. + */ +static INLINE void +blend_unpremultiply( struct ureg_program *ureg, + struct ureg_src src, + struct ureg_src one, + struct ureg_dst temp[1]) +{ + /* replace 0.0f by 1.0f before calculating reciprocal */ + ureg_CMP(ureg, + temp[0], + ureg_negate(ureg_scalar(src, TGSI_SWIZZLE_W)), + ureg_scalar(src, TGSI_SWIZZLE_W), + one); + ureg_RCP(ureg, temp[0], ureg_src(temp[0])); + + ureg_MUL(ureg, + ureg_writemask(ureg_dst(src), TGSI_WRITEMASK_XYZ), + src, + ureg_src(temp[0])); +} + +/** + * Emit instructions for the specified blend mode. Colors will be + * unpremultiplied. Two temporary registers are required. + * + * The output is written back to src. + */ +static INLINE void +blend_generic(struct ureg_program *ureg, + VGBlendMode mode, + struct ureg_src src, + struct ureg_src src_channel_alpha, + struct ureg_src dst, + struct ureg_src one, + struct ureg_dst temp[2]) +{ + struct ureg_dst out; + + blend_premultiply(ureg, src, src_channel_alpha, dst); + + /* blend in-place */ + out = ureg_dst(src); + + switch (mode) { + case VG_BLEND_SRC: + ureg_MOV(ureg, out, src); + break; + case VG_BLEND_SRC_OVER: + /* RGBA_out = RGBA_src + (1 - A_src) * RGBA_dst */ + ureg_SUB(ureg, temp[0], one, src_channel_alpha); + ureg_MAD(ureg, out, ureg_src(temp[0]), dst, src); + break; + case VG_BLEND_DST_OVER: + /* RGBA_out = RGBA_dst + (1 - A_dst) * RGBA_src */ + ureg_SUB(ureg, temp[0], one, ureg_scalar(dst, TGSI_SWIZZLE_W)); + ureg_MAD(ureg, out, ureg_src(temp[0]), src, dst); + break; + case VG_BLEND_SRC_IN: + ureg_MUL(ureg, out, src, ureg_scalar(dst, TGSI_SWIZZLE_W)); + break; + case VG_BLEND_DST_IN: + ureg_MUL(ureg, out, dst, src_channel_alpha); + break; + case VG_BLEND_MULTIPLY: + /* + * RGB_out = (1 - A_dst) * RGB_src + (1 - A_src) * RGB_dst + + * RGB_src * RGB_dst + */ + ureg_MAD(ureg, temp[0], + ureg_scalar(dst, TGSI_SWIZZLE_W), ureg_negate(src), src); + ureg_MAD(ureg, temp[1], + src_channel_alpha, ureg_negate(dst), dst); + ureg_MAD(ureg, temp[0], src, dst, ureg_src(temp[0])); + ureg_ADD(ureg, out, ureg_src(temp[0]), ureg_src(temp[1])); + /* alpha is src over */ + ureg_ADD(ureg, ureg_writemask(out, TGSI_WRITEMASK_W), + src, ureg_src(temp[1])); + break; + case VG_BLEND_SCREEN: + /* RGBA_out = RGBA_src + (1 - RGBA_src) * RGBA_dst */ + ureg_SUB(ureg, temp[0], one, src); + ureg_MAD(ureg, out, ureg_src(temp[0]), dst, src); + break; + case VG_BLEND_DARKEN: + case VG_BLEND_LIGHTEN: + /* src over */ + ureg_SUB(ureg, temp[0], one, src_channel_alpha); + ureg_MAD(ureg, temp[0], ureg_src(temp[0]), dst, src); + /* dst over */ + ureg_SUB(ureg, temp[1], one, ureg_scalar(dst, TGSI_SWIZZLE_W)); + ureg_MAD(ureg, temp[1], ureg_src(temp[1]), src, dst); + /* take min/max for colors */ + if (mode == VG_BLEND_DARKEN) { + ureg_MIN(ureg, ureg_writemask(out, TGSI_WRITEMASK_XYZ), + ureg_src(temp[0]), ureg_src(temp[1])); + } + else { + ureg_MAX(ureg, ureg_writemask(out, TGSI_WRITEMASK_XYZ), + ureg_src(temp[0]), ureg_src(temp[1])); + } + break; + case VG_BLEND_ADDITIVE: + /* RGBA_out = RGBA_src + RGBA_dst */ + ureg_ADD(ureg, temp[0], src, dst); + ureg_MIN(ureg, out, ureg_src(temp[0]), one); + break; + default: + assert(0); + break; + } + + blend_unpremultiply(ureg, src, one, temp); +} + +#define BLEND_GENERIC(mode) \ + do { \ + ureg_TEX(ureg, temp[2], TGSI_TEXTURE_2D, in[0], sampler[2]); \ + blend_generic(ureg, (mode), ureg_src(temp[0]), ureg_src(temp[1]), \ + ureg_src(temp[2]), \ + ureg_scalar(constant[3], TGSI_SWIZZLE_Y), temp + 3); \ + ureg_MOV(ureg, *out, ureg_src(temp[0])); \ + } while (0) + +static INLINE void +blend_src( struct ureg_program *ureg, + struct ureg_dst *out, + struct ureg_src *in, + struct ureg_src *sampler, + struct ureg_dst *temp, + struct ureg_src *constant) +{ + BLEND_GENERIC(VG_BLEND_SRC); +} + +static INLINE void +blend_src_over( struct ureg_program *ureg, struct ureg_dst *out, struct ureg_src *in, struct ureg_src *sampler, struct ureg_dst *temp, struct ureg_src *constant) { - ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[0], sampler[2]); - EXTENDED_BLENDER_OVER_FUNC - ureg_MUL(ureg, temp[4], ureg_src(temp[0]), ureg_src(temp[1])); - ureg_ADD(ureg, temp[1], ureg_src(temp[4]), ureg_src(temp[3])); + BLEND_GENERIC(VG_BLEND_SRC_OVER); +} - ureg_MUL(ureg, temp[2], ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W), - ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W)); - ureg_ADD(ureg, temp[3], ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W), - ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W)); - ureg_SUB(ureg, ureg_writemask(temp[1], TGSI_WRITEMASK_W), - ureg_src(temp[3]), ureg_src(temp[2])); +static INLINE void +blend_dst_over( struct ureg_program *ureg, + struct ureg_dst *out, + struct ureg_src *in, + struct ureg_src *sampler, + struct ureg_dst *temp, + struct ureg_src *constant) +{ + BLEND_GENERIC(VG_BLEND_DST_OVER); +} - ureg_MOV(ureg, *out, ureg_src(temp[1])); +static INLINE void +blend_src_in( struct ureg_program *ureg, + struct ureg_dst *out, + struct ureg_src *in, + struct ureg_src *sampler, + struct ureg_dst *temp, + struct ureg_src *constant) +{ + BLEND_GENERIC(VG_BLEND_SRC_IN); +} + +static INLINE void +blend_dst_in( struct ureg_program *ureg, + struct ureg_dst *out, + struct ureg_src *in, + struct ureg_src *sampler, + struct ureg_dst *temp, + struct ureg_src *constant) +{ + BLEND_GENERIC(VG_BLEND_DST_IN); +} + +static INLINE void +blend_multiply( struct ureg_program *ureg, + struct ureg_dst *out, + struct ureg_src *in, + struct ureg_src *sampler, + struct ureg_dst *temp, + struct ureg_src *constant) +{ + BLEND_GENERIC(VG_BLEND_MULTIPLY); } static INLINE void @@ -274,10 +492,7 @@ blend_screen( struct ureg_program *ureg, struct ureg_dst *temp, struct ureg_src *constant) { - ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[0], sampler[2]); - ureg_ADD(ureg, temp[3], ureg_src(temp[0]), ureg_src(temp[1])); - ureg_MUL(ureg, temp[2], ureg_src(temp[0]), ureg_src(temp[1])); - ureg_SUB(ureg, *out, ureg_src(temp[3]), ureg_src(temp[2])); + BLEND_GENERIC(VG_BLEND_SCREEN); } static INLINE void @@ -288,23 +503,7 @@ blend_darken( struct ureg_program *ureg, struct ureg_dst *temp, struct ureg_src *constant) { - ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[0], sampler[2]); - EXTENDED_BLENDER_OVER_FUNC - ureg_MUL(ureg, temp[4], ureg_src(temp[0]), - ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W)); - ureg_MUL(ureg, temp[5], ureg_src(temp[1]), - ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W)); - ureg_MIN(ureg, temp[4], ureg_src(temp[4]), ureg_src(temp[5])); - ureg_ADD(ureg, temp[1], ureg_src(temp[3]), ureg_src(temp[4])); - - ureg_MUL(ureg, temp[2], ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W), - ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W)); - ureg_ADD(ureg, temp[3], ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W), - ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W)); - ureg_SUB(ureg, ureg_writemask(temp[1], TGSI_WRITEMASK_W), - ureg_src(temp[3]), ureg_src(temp[2])); - - ureg_MOV(ureg, *out, ureg_src(temp[1])); + BLEND_GENERIC(VG_BLEND_DARKEN); } static INLINE void @@ -315,23 +514,33 @@ blend_lighten( struct ureg_program *ureg, struct ureg_dst *temp, struct ureg_src *constant) { - ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[0], sampler[2]); - EXTENDED_BLENDER_OVER_FUNC - ureg_MUL(ureg, temp[4], ureg_src(temp[0]), - ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W)); - ureg_MUL(ureg, temp[5], ureg_src(temp[1]), - ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W)); - ureg_MAX(ureg, temp[4], ureg_src(temp[4]), ureg_src(temp[5])); - ureg_ADD(ureg, temp[1], ureg_src(temp[3]), ureg_src(temp[4])); + BLEND_GENERIC(VG_BLEND_LIGHTEN); +} - ureg_MUL(ureg, temp[2], ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W), - ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W)); - ureg_ADD(ureg, temp[3], ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W), - ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W)); - ureg_SUB(ureg, ureg_writemask(temp[1], TGSI_WRITEMASK_W), - ureg_src(temp[3]), ureg_src(temp[2])); +static INLINE void +blend_additive( struct ureg_program *ureg, + struct ureg_dst *out, + struct ureg_src *in, + struct ureg_src *sampler, + struct ureg_dst *temp, + struct ureg_src *constant) +{ + BLEND_GENERIC(VG_BLEND_ADDITIVE); +} - ureg_MOV(ureg, *out, ureg_src(temp[1])); +static INLINE void +mask( struct ureg_program *ureg, + struct ureg_dst *out, + struct ureg_src *in, + struct ureg_src *sampler, + struct ureg_dst *temp, + struct ureg_src *constant) +{ + ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[0], sampler[1]); + ureg_MUL(ureg, ureg_writemask(temp[0], TGSI_WRITEMASK_W), + ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W), + ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W)); + ureg_MOV(ureg, *out, ureg_src(temp[0])); } static INLINE void @@ -369,11 +578,11 @@ color_bw( struct ureg_program *ureg, struct ureg_src *constant) { ureg_ADD(ureg, temp[1], - ureg_scalar(constant[1], TGSI_SWIZZLE_Y), - ureg_scalar(constant[1], TGSI_SWIZZLE_Y)); + ureg_scalar(constant[3], TGSI_SWIZZLE_Y), + ureg_scalar(constant[3], TGSI_SWIZZLE_Y)); ureg_RCP(ureg, temp[2], ureg_src(temp[1])); ureg_ADD(ureg, temp[1], - ureg_scalar(constant[1], TGSI_SWIZZLE_Y), + ureg_scalar(constant[3], TGSI_SWIZZLE_Y), ureg_src(temp[2])); ureg_ADD(ureg, ureg_writemask(temp[2], TGSI_WRITEMASK_X), ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_X), @@ -410,46 +619,75 @@ struct shader_asm_info { }; -static const struct shader_asm_info shaders_asm[] = { - /* fills */ +/* paint types */ +static const struct shader_asm_info shaders_paint_asm[] = { {VEGA_SOLID_FILL_SHADER, solid_fill, - VG_FALSE, 0, 1, 0, 0, 0, 0}, + VG_FALSE, 2, 1, 0, 0, 0, 0}, {VEGA_LINEAR_GRADIENT_SHADER, linear_grad, - VG_TRUE, 0, 5, 0, 1, 0, 5}, + VG_TRUE, 2, 5, 0, 1, 0, 5}, {VEGA_RADIAL_GRADIENT_SHADER, radial_grad, - VG_TRUE, 0, 5, 0, 1, 0, 6}, + VG_TRUE, 2, 5, 0, 1, 0, 5}, {VEGA_PATTERN_SHADER, pattern, - VG_TRUE, 1, 4, 0, 1, 0, 5}, + VG_TRUE, 3, 4, 0, 1, 0, 5}, + {VEGA_PAINT_DEGENERATE_SHADER, paint_degenerate, + VG_FALSE, 3, 1, 0, 1, 0, 2} +}; - /* image draw modes */ +/* image draw modes */ +static const struct shader_asm_info shaders_image_asm[] = { {VEGA_IMAGE_NORMAL_SHADER, image_normal, - VG_TRUE, 0, 0, 3, 1, 0, 0}, + VG_TRUE, 0, 0, 3, 1, 0, 2}, {VEGA_IMAGE_MULTIPLY_SHADER, image_multiply, VG_TRUE, 0, 0, 3, 1, 0, 2}, {VEGA_IMAGE_STENCIL_SHADER, image_stencil, - VG_TRUE, 0, 0, 3, 1, 0, 2}, + VG_TRUE, 0, 0, 3, 1, 0, 2} +}; +static const struct shader_asm_info shaders_color_transform_asm[] = { + {VEGA_COLOR_TRANSFORM_SHADER, color_transform, + VG_FALSE, 0, 4, 0, 0, 0, 3} +}; + +static const struct shader_asm_info shaders_alpha_asm[] = { + {VEGA_ALPHA_NORMAL_SHADER, alpha_normal, + VG_FALSE, 0, 0, 0, 0, 0, 2}, + {VEGA_ALPHA_PER_CHANNEL_SHADER, alpha_per_channel, + VG_FALSE, 0, 0, 0, 0, 0, 2} +}; + +/* extra blend modes */ +static const struct shader_asm_info shaders_blend_asm[] = { +#define BLEND_ASM_INFO(id, func) { (id), (func), VG_TRUE, 3, 1, 2, 1, 0, 5 } + BLEND_ASM_INFO(VEGA_BLEND_SRC_SHADER, blend_src), + BLEND_ASM_INFO(VEGA_BLEND_SRC_OVER_SHADER, blend_src_over), + BLEND_ASM_INFO(VEGA_BLEND_DST_OVER_SHADER, blend_dst_over), + BLEND_ASM_INFO(VEGA_BLEND_SRC_IN_SHADER, blend_src_in), + BLEND_ASM_INFO(VEGA_BLEND_DST_IN_SHADER, blend_dst_in), + BLEND_ASM_INFO(VEGA_BLEND_MULTIPLY_SHADER, blend_multiply), + BLEND_ASM_INFO(VEGA_BLEND_SCREEN_SHADER, blend_screen), + BLEND_ASM_INFO(VEGA_BLEND_DARKEN_SHADER, blend_darken), + BLEND_ASM_INFO(VEGA_BLEND_LIGHTEN_SHADER, blend_lighten), + BLEND_ASM_INFO(VEGA_BLEND_ADDITIVE_SHADER, blend_additive) +#undef BLEND_ASM_INFO +}; + +static const struct shader_asm_info shaders_mask_asm[] = { {VEGA_MASK_SHADER, mask, - VG_TRUE, 0, 0, 1, 1, 0, 2}, - - /* extra blend modes */ - {VEGA_BLEND_MULTIPLY_SHADER, blend_multiply, - VG_TRUE, 1, 1, 2, 1, 0, 5}, - {VEGA_BLEND_SCREEN_SHADER, blend_screen, - VG_TRUE, 0, 0, 2, 1, 0, 4}, - {VEGA_BLEND_DARKEN_SHADER, blend_darken, - VG_TRUE, 1, 1, 2, 1, 0, 6}, - {VEGA_BLEND_LIGHTEN_SHADER, blend_lighten, - VG_TRUE, 1, 1, 2, 1, 0, 6}, - - /* premultiply */ + VG_TRUE, 0, 0, 1, 1, 0, 2} +}; + +/* premultiply */ +static const struct shader_asm_info shaders_premultiply_asm[] = { {VEGA_PREMULTIPLY_SHADER, premultiply, VG_FALSE, 0, 0, 0, 0, 0, 1}, {VEGA_UNPREMULTIPLY_SHADER, unpremultiply, VG_FALSE, 0, 0, 0, 0, 0, 1}, +}; - /* color transform to black and white */ +/* color transform to black and white */ +static const struct shader_asm_info shaders_bw_asm[] = { {VEGA_BW_SHADER, color_bw, - VG_FALSE, 1, 1, 0, 0, 0, 3}, + VG_FALSE, 3, 1, 0, 0, 0, 3}, }; + #endif diff --git a/src/gallium/state_trackers/vega/asm_util.h b/src/gallium/state_trackers/vega/asm_util.h index 903bfc88a4d..ae1842a62cd 100644 --- a/src/gallium/state_trackers/vega/asm_util.h +++ b/src/gallium/state_trackers/vega/asm_util.h @@ -27,16 +27,6 @@ #ifndef ASM_UTIL_H #define ASM_UTIL_H - -static const char pass_through_depth_asm[] = - "FRAG\n" - "DCL IN[0], POSITION, LINEAR\n" - "DCL OUT[0].z, POSITION, CONSTANT\n" - "0: MOV OUT[0].z, IN[0].zzzz\n" - "1: END\n"; - - - /* μnew = μmask */ static const char set_mask_asm[] = "FRAG\n" @@ -92,45 +82,4 @@ static const char subtract_mask_asm[] = "3: MUL OUT[0], TEMP[2].wwww, TEMP[0].wwww\n" "4: END\n"; - -static const char vs_plain_asm[] = - "VERT\n" - "DCL IN[0]\n" - "DCL OUT[0], POSITION\n" - "DCL TEMP[0]\n" - "DCL CONST[0..1]\n" - "0: MUL TEMP[0], IN[0], CONST[0]\n" - "1: ADD TEMP[0], TEMP[0], CONST[1]\n" - "2: MOV OUT[0], TEMP[0]\n" - "3: END\n"; - -static const char vs_clear_asm[] = - "VERT\n" - "DCL IN[0]\n" - "DCL IN[1]\n" - "DCL OUT[0], POSITION\n" - "DCL OUT[1], COLOR\n" - "DCL TEMP[0]\n" - "DCL CONST[0..1]\n" - "0: MUL TEMP[0], IN[0], CONST[0]\n" - "1: ADD TEMP[0], TEMP[0], CONST[1]\n" - "2: MOV OUT[0], TEMP[0]\n" - "3: MOV OUT[1], IN[1]\n" - "4: END\n"; - - -static const char vs_texture_asm[] = - "VERT\n" - "DCL IN[0]\n" - "DCL IN[1]\n" - "DCL OUT[0], POSITION\n" - "DCL OUT[1], GENERIC\n" - "DCL TEMP[0]\n" - "DCL CONST[0..1]\n" - "0: MUL TEMP[0], IN[0], CONST[0]\n" - "1: ADD TEMP[0], TEMP[0], CONST[1]\n" - "2: MOV OUT[0], TEMP[0]\n" - "3: MOV OUT[1], IN[1]\n" - "4: END\n"; - #endif diff --git a/src/gallium/state_trackers/vega/image.c b/src/gallium/state_trackers/vega/image.c index 28bbe420a21..318ea94bdfb 100644 --- a/src/gallium/state_trackers/vega/image.c +++ b/src/gallium/state_trackers/vega/image.c @@ -42,6 +42,7 @@ #include "util/u_memory.h" #include "util/u_math.h" #include "util/u_sampler.h" +#include "util/u_surface.h" static enum pipe_format vg_format_to_pipe(VGImageFormat format) { @@ -77,33 +78,23 @@ static INLINE void vg_sync_size(VGfloat *src_loc, VGfloat *dst_loc) dst_loc[3] = src_loc[3]; } - -static void vg_copy_texture(struct vg_context *ctx, - struct pipe_resource *dst, VGint dx, VGint dy, - struct pipe_sampler_view *src, VGint sx, VGint sy, - VGint width, VGint height) +static void vg_get_copy_coords(VGfloat *src_loc, + VGfloat src_width, VGfloat src_height, + VGfloat *dst_loc, + VGfloat dst_width, VGfloat dst_height) { - VGfloat dst_loc[4], src_loc[4]; VGfloat dst_bounds[4], src_bounds[4]; VGfloat src_shift[4], dst_shift[4], shift[4]; - dst_loc[0] = dx; - dst_loc[1] = dy; - dst_loc[2] = width; - dst_loc[3] = height; dst_bounds[0] = 0.f; dst_bounds[1] = 0.f; - dst_bounds[2] = dst->width0; - dst_bounds[3] = dst->height0; + dst_bounds[2] = dst_width; + dst_bounds[3] = dst_height; - src_loc[0] = sx; - src_loc[1] = sy; - src_loc[2] = width; - src_loc[3] = height; src_bounds[0] = 0.f; src_bounds[1] = 0.f; - src_bounds[2] = src->texture->width0; - src_bounds[3] = src->texture->height0; + src_bounds[2] = src_width; + src_bounds[3] = src_height; vg_bound_rect(src_loc, src_bounds, src_shift); vg_bound_rect(dst_loc, dst_bounds, dst_shift); @@ -121,22 +112,44 @@ static void vg_copy_texture(struct vg_context *ctx, vg_shift_recty(dst_loc, dst_bounds, shift[1]); vg_sync_size(src_loc, dst_loc); +} + +static void vg_copy_texture(struct vg_context *ctx, + struct pipe_resource *dst, VGint dx, VGint dy, + struct pipe_sampler_view *src, VGint sx, VGint sy, + VGint width, VGint height) +{ + VGfloat dst_loc[4], src_loc[4]; + + dst_loc[0] = dx; + dst_loc[1] = dy; + dst_loc[2] = width; + dst_loc[3] = height; + + src_loc[0] = sx; + src_loc[1] = sy; + src_loc[2] = width; + src_loc[3] = height; + + vg_get_copy_coords(src_loc, src->texture->width0, src->texture->height0, + dst_loc, dst->width0, dst->height0); if (src_loc[2] >= 0 && src_loc[3] >= 0 && dst_loc[2] >= 0 && dst_loc[3] >= 0) { - renderer_copy_texture(ctx->renderer, - src, - src_loc[0], - src_loc[1] + src_loc[3], - src_loc[0] + src_loc[2], - src_loc[1], - dst, - dst_loc[0], - dst_loc[1] + dst_loc[3], - dst_loc[0] + dst_loc[2], - dst_loc[1]); - } + struct pipe_surface *surf, surf_tmpl; + + /* get the destination surface */ + u_surface_default_template(&surf_tmpl, dst, PIPE_BIND_RENDER_TARGET); + surf = ctx->pipe->create_surface(ctx->pipe, dst, &surf_tmpl); + if (surf && renderer_copy_begin(ctx->renderer, surf, VG_TRUE, src)) { + renderer_copy(ctx->renderer, + dst_loc[0], dst_loc[1], dst_loc[2], dst_loc[3], + src_loc[0], src_loc[1], src_loc[2], src_loc[3]); + renderer_copy_end(ctx->renderer); + } + pipe_surface_reference(&surf, NULL); + } } void vg_copy_surface(struct vg_context *ctx, @@ -145,43 +158,19 @@ void vg_copy_surface(struct vg_context *ctx, VGint width, VGint height) { VGfloat dst_loc[4], src_loc[4]; - VGfloat dst_bounds[4], src_bounds[4]; - VGfloat src_shift[4], dst_shift[4], shift[4]; dst_loc[0] = dx; dst_loc[1] = dy; dst_loc[2] = width; dst_loc[3] = height; - dst_bounds[0] = 0.f; - dst_bounds[1] = 0.f; - dst_bounds[2] = dst->width; - dst_bounds[3] = dst->height; src_loc[0] = sx; src_loc[1] = sy; src_loc[2] = width; src_loc[3] = height; - src_bounds[0] = 0.f; - src_bounds[1] = 0.f; - src_bounds[2] = src->width; - src_bounds[3] = src->height; - - vg_bound_rect(src_loc, src_bounds, src_shift); - vg_bound_rect(dst_loc, dst_bounds, dst_shift); - shift[0] = src_shift[0] - dst_shift[0]; - shift[1] = src_shift[1] - dst_shift[1]; - - if (shift[0] < 0) - vg_shift_rectx(src_loc, src_bounds, -shift[0]); - else - vg_shift_rectx(dst_loc, dst_bounds, shift[0]); - - if (shift[1] < 0) - vg_shift_recty(src_loc, src_bounds, -shift[1]); - else - vg_shift_recty(dst_loc, dst_bounds, shift[1]); - vg_sync_size(src_loc, dst_loc); + vg_get_copy_coords(src_loc, src->width, src->height, + dst_loc, dst->width, dst->height); if (src_loc[2] > 0 && src_loc[3] > 0 && dst_loc[2] > 0 && dst_loc[3] > 0) { @@ -277,6 +266,7 @@ struct vg_image * image_create(VGImageFormat format, pt.width0 = width; pt.height0 = height; pt.depth0 = 1; + pt.array_size = 1; pt.bind = PIPE_BIND_SAMPLER_VIEW; newtex = screen->resource_create(screen, &pt); @@ -284,6 +274,13 @@ struct vg_image * image_create(VGImageFormat format, debug_assert(newtex); u_sampler_view_default_template(&view_templ, newtex, newtex->format); + /* R, G, and B are treated as 1.0 for alpha-only formats in OpenVG */ + if (newtex->format == PIPE_FORMAT_A8_UNORM) { + view_templ.swizzle_r = PIPE_SWIZZLE_ONE; + view_templ.swizzle_g = PIPE_SWIZZLE_ONE; + view_templ.swizzle_b = PIPE_SWIZZLE_ONE; + } + view = pipe->create_sampler_view(pipe, newtex, &view_templ); /* want the texture to go away if the view is freed */ pipe_resource_reference(&newtex, NULL); @@ -420,7 +417,7 @@ void image_sub_data(struct vg_image *image, { /* upload color_data */ struct pipe_transfer *transfer = pipe_get_transfer( - pipe, texture, 0, 0, 0, + pipe, texture, 0, 0, PIPE_TRANSFER_WRITE, 0, 0, texture->width0, texture->height0); src += (dataStride * yoffset); for (i = 0; i < height; i++) { @@ -451,11 +448,11 @@ void image_get_sub_data(struct vg_image * image, { struct pipe_transfer *transfer = pipe_get_transfer(pipe, - image->sampler_view->texture, 0, 0, 0, - PIPE_TRANSFER_READ, - 0, 0, - image->x + image->width, - image->y + image->height); + image->sampler_view->texture, 0, 0, + PIPE_TRANSFER_READ, + 0, 0, + image->x + image->width, + image->y + image->height); /* Do a row at a time to flip image data vertically */ for (i = 0; i < height; i++) { #if 0 @@ -525,14 +522,20 @@ void image_copy(struct vg_image *dst, VGint dx, VGint dy, src->sampler_view, src->x + sx, src->y + sy, width, height); } -void image_draw(struct vg_image *img) +void image_draw(struct vg_image *img, struct matrix *matrix) { struct vg_context *ctx = vg_current_context(); + struct matrix paint_matrix; VGfloat x1, y1; VGfloat x2, y2; VGfloat x3, y3; VGfloat x4, y4; - struct matrix *matrix; + + if (!vg_get_paint_matrix(ctx, + &ctx->state.vg.fill_paint_to_user_matrix, + matrix, + &paint_matrix)) + return; x1 = 0; y1 = 0; @@ -543,15 +546,10 @@ void image_draw(struct vg_image *img) x4 = 0; y4 = img->height; - matrix = &ctx->state.vg.image_user_to_surface_matrix; - - matrix_map_point(matrix, x1, y1, &x1, &y1); - matrix_map_point(matrix, x2, y2, &x2, &y2); - matrix_map_point(matrix, x3, y3, &x3, &y3); - matrix_map_point(matrix, x4, y4, &x4, &y4); - + shader_set_surface_matrix(ctx->shader, matrix); shader_set_drawing_image(ctx->shader, VG_TRUE); shader_set_paint(ctx->shader, ctx->state.vg.fill_paint); + shader_set_paint_matrix(ctx->shader, &paint_matrix); shader_set_image(ctx->shader, img); shader_bind(ctx->shader); @@ -566,20 +564,21 @@ void image_set_pixels(VGint dx, VGint dy, { struct vg_context *ctx = vg_current_context(); struct pipe_context *pipe = ctx->pipe; - struct pipe_screen *screen = pipe->screen; - struct pipe_surface *surf; + struct pipe_surface *surf, surf_tmpl; struct st_renderbuffer *strb = ctx->draw_buffer->strb; /* make sure rendering has completed */ pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); - surf = screen->get_tex_surface(screen, image_texture(src), 0, 0, 0, - 0 /* no bind flags as surf isn't actually used??? */); + memset(&surf_tmpl, 0, sizeof(surf_tmpl)); + u_surface_default_template(&surf_tmpl, image_texture(src), + 0 /* no bind flag - not a surface*/); + surf = pipe->create_surface(pipe, image_texture(src), &surf_tmpl); vg_copy_surface(ctx, strb->surface, dx, dy, surf, sx+src->x, sy+src->y, width, height); - screen->tex_surface_destroy(surf); + pipe->surface_destroy(pipe, surf); } void image_get_pixels(struct vg_image *dst, VGint dx, VGint dy, @@ -588,8 +587,7 @@ void image_get_pixels(struct vg_image *dst, VGint dx, VGint dy, { struct vg_context *ctx = vg_current_context(); struct pipe_context *pipe = ctx->pipe; - struct pipe_screen *screen = pipe->screen; - struct pipe_surface *surf; + struct pipe_surface *surf, surf_tmpl; struct st_renderbuffer *strb = ctx->draw_buffer->strb; /* flip the y coordinates */ @@ -598,8 +596,10 @@ void image_get_pixels(struct vg_image *dst, VGint dx, VGint dy, /* make sure rendering has completed */ pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); - surf = screen->get_tex_surface(screen, image_texture(dst), 0, 0, 0, - 0 /* no bind flags as surf isn't actually used??? */); + memset(&surf_tmpl, 0, sizeof(surf_tmpl)); + u_surface_default_template(&surf_tmpl, image_texture(dst), + PIPE_BIND_RENDER_TARGET); + surf = pipe->create_surface(pipe, image_texture(dst), &surf_tmpl); vg_copy_surface(ctx, surf, dst->x + dx, dst->y + dy, strb->surface, sx, sy, width, height); diff --git a/src/gallium/state_trackers/vega/image.h b/src/gallium/state_trackers/vega/image.h index a990c9c5873..391c0485948 100644 --- a/src/gallium/state_trackers/vega/image.h +++ b/src/gallium/state_trackers/vega/image.h @@ -79,7 +79,7 @@ void image_copy(struct vg_image *dst, VGint dx, VGint dy, VGint width, VGint height, VGboolean dither); -void image_draw(struct vg_image *img); +void image_draw(struct vg_image *img, struct matrix *matrix); void image_set_pixels(VGint dx, VGint dy, struct vg_image *src, VGint sx, VGint sy, diff --git a/src/gallium/state_trackers/vega/mask.c b/src/gallium/state_trackers/vega/mask.c index ef28ebd740c..dfd0600e444 100644 --- a/src/gallium/state_trackers/vega/mask.c +++ b/src/gallium/state_trackers/vega/mask.c @@ -31,13 +31,14 @@ #include "shaders_cache.h" #include "renderer.h" #include "asm_util.h" -#include "st_inlines.h" #include "pipe/p_context.h" #include "pipe/p_screen.h" #include "util/u_inlines.h" #include "util/u_format.h" #include "util/u_memory.h" +#include "util/u_surface.h" +#include "util/u_sampler.h" struct vg_mask_layer { struct vg_object base; @@ -48,17 +49,6 @@ struct vg_mask_layer { struct pipe_sampler_view *sampler_view; }; -static INLINE struct pipe_surface * -alpha_mask_surface(struct vg_context *ctx, int usage) -{ - struct pipe_screen *screen = ctx->pipe->screen; - struct st_framebuffer *stfb = ctx->draw_buffer; - return screen->get_tex_surface(screen, - stfb->alpha_mask_view->texture, - 0, 0, 0, - usage); -} - static INLINE VGboolean intersect_rectangles(VGint dwidth, VGint dheight, VGint swidth, VGint sheight, @@ -110,15 +100,13 @@ static void read_alpha_mask(void * data, VGint dataStride, { struct vg_context *ctx = vg_current_context(); struct pipe_context *pipe = ctx->pipe; - struct pipe_screen *screen = pipe->screen; struct st_framebuffer *stfb = ctx->draw_buffer; struct st_renderbuffer *strb = stfb->alpha_mask; - struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4]; VGfloat *df = (VGfloat*)temp; - VGint y = (fb->height - sy) - 1, yStep = -1; + VGint y = (stfb->height - sy) - 1, yStep = -1; VGint i; VGubyte *dst = (VGubyte *)data; VGint xoffset = 0, yoffset = 0; @@ -135,15 +123,15 @@ static void read_alpha_mask(void * data, VGint dataStride, yoffset = -sy; height += sy; sy = 0; - y = (fb->height - sy) - 1; + y = (stfb->height - sy) - 1; yoffset *= dataStride; } { struct pipe_surface *surf; - surf = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, - PIPE_BIND_TRANSFER_READ); + surf = pipe->create_surface(pipe, strb->texture, 0, 0, 0, + PIPE_BIND_TRANSFER_READ); /* Do a row at a time to flip image data vertically */ for (i = 0; i < height; i++) { @@ -164,23 +152,23 @@ static void read_alpha_mask(void * data, VGint dataStride, void save_alpha_to_file(const char *filename) { struct vg_context *ctx = vg_current_context(); - struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; + struct st_framebuffer *stfb = ctx->draw_buffer; VGint *data; int i, j; - data = malloc(sizeof(int) * fb->width * fb->height); - read_alpha_mask(data, fb->width * sizeof(int), + data = malloc(sizeof(int) * stfb->width * stfb->height); + read_alpha_mask(data, stfb->width * sizeof(int), VG_sRGBA_8888, - 0, 0, fb->width, fb->height); + 0, 0, stfb->width, stfb->height); fprintf(stderr, "/*---------- start */\n"); fprintf(stderr, "const int image_width = %d;\n", - fb->width); + stfb->width); fprintf(stderr, "const int image_height = %d;\n", - fb->height); + stfb->height); fprintf(stderr, "const int image_data = {\n"); - for (i = 0; i < fb->height; ++i) { - for (j = 0; j < fb->width; ++j) { - int rgba = data[i * fb->height + j]; + for (i = 0; i < stfb->height; ++i) { + for (j = 0; j < stfb->width; ++j) { + int rgba = data[i * stfb->height + j]; int argb = 0; argb = (rgba >> 8); argb |= ((rgba & 0xff) << 24); @@ -193,49 +181,12 @@ void save_alpha_to_file(const char *filename) } #endif -static void setup_mask_framebuffer(struct pipe_surface *surf, - VGint surf_width, VGint surf_height) -{ - struct vg_context *ctx = vg_current_context(); - struct pipe_framebuffer_state fb; - - memset(&fb, 0, sizeof(fb)); - fb.width = surf_width; - fb.height = surf_height; - fb.nr_cbufs = 1; - fb.cbufs[0] = surf; - { - VGint i; - for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i) - fb.cbufs[i] = 0; - } - cso_set_framebuffer(ctx->cso_context, &fb); -} - - -/* setup shader constants */ -static void setup_mask_operation(VGMaskOperation operation) +/* setup mask shader */ +static void *setup_mask_operation(VGMaskOperation operation) { struct vg_context *ctx = vg_current_context(); - struct pipe_resource **cbuf = &ctx->mask.cbuf; - const VGint param_bytes = 4 * sizeof(VGfloat); - const VGfloat ones[4] = {1.f, 1.f, 1.f, 1.f}; void *shader = 0; - /* We always need to get a new buffer, to keep the drivers simple and - * avoid gratuitous rendering synchronization. - */ - pipe_resource_reference(cbuf, NULL); - - *cbuf = pipe_buffer_create(ctx->pipe->screen, - PIPE_BIND_CONSTANT_BUFFER, - param_bytes); - if (*cbuf) { - st_no_flush_pipe_buffer_write(ctx, *cbuf, - 0, param_bytes, ones); - } - - ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, *cbuf); switch (operation) { case VG_UNION_MASK: { if (!ctx->mask.union_fs) { @@ -281,94 +232,21 @@ static void setup_mask_operation(VGMaskOperation operation) assert(0); break; } - cso_set_fragment_shader_handle(ctx->cso_context, shader); -} - -static void setup_mask_samplers(struct pipe_sampler_view *umask) -{ - struct vg_context *ctx = vg_current_context(); - struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; - struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; - struct st_framebuffer *fb_buffers = ctx->draw_buffer; - struct pipe_sampler_view *uprev = NULL; - struct pipe_sampler_state sampler; - - uprev = fb_buffers->blend_texture_view; - sampler = ctx->mask.sampler; - sampler.normalized_coords = 1; - - samplers[0] = NULL; - samplers[1] = NULL; - sampler_views[0] = NULL; - sampler_views[1] = NULL; - - samplers[0] = &sampler; - samplers[1] = &ctx->mask.sampler; - - sampler_views[0] = umask; - sampler_views[1] = uprev; - - cso_set_samplers(ctx->cso_context, 2, - (const struct pipe_sampler_state **)samplers); - cso_set_fragment_sampler_views(ctx->cso_context, 2, sampler_views); -} - - -/* setup shader constants */ -static void setup_mask_fill(const VGfloat color[4]) -{ - struct vg_context *ctx = vg_current_context(); - struct pipe_resource **cbuf = &ctx->mask.cbuf; - const VGint param_bytes = 4 * sizeof(VGfloat); - - /* We always need to get a new buffer, to keep the drivers simple and - * avoid gratuitous rendering synchronization. - */ - pipe_resource_reference(cbuf, NULL); - - *cbuf = pipe_buffer_create(ctx->pipe->screen, - PIPE_BIND_CONSTANT_BUFFER, - param_bytes); - if (*cbuf) { - st_no_flush_pipe_buffer_write(ctx, *cbuf, 0, param_bytes, color); - } - - ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, *cbuf); - cso_set_fragment_shader_handle(ctx->cso_context, - shaders_cache_fill(ctx->sc, - VEGA_SOLID_FILL_SHADER)); -} - -static void setup_mask_viewport() -{ - struct vg_context *ctx = vg_current_context(); - vg_set_viewport(ctx, VEGA_Y0_TOP); -} - -static void setup_mask_blend() -{ - struct vg_context *ctx = vg_current_context(); - - struct pipe_blend_state blend; - memset(&blend, 0, sizeof(struct pipe_blend_state)); - blend.rt[0].blend_enable = 0; - blend.rt[0].colormask = PIPE_MASK_RGBA; - blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; - blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; - blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; - blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; - - cso_set_blend(ctx->cso_context, &blend); + return shader; } - -static void surface_fill(struct pipe_surface *surf, - int surf_width, int surf_height, - int x, int y, int width, int height, - const VGfloat color[4]) +static void mask_resource_fill(struct pipe_resource *dst, + int x, int y, int width, int height, + VGfloat coverage) { struct vg_context *ctx = vg_current_context(); + VGfloat fs_consts[12] = { + 0.0f, 0.0f, 0.0f, 0.0f, /* not used */ + 0.0f, 0.0f, 0.0f, 0.0f, /* not used */ + 0.0f, 0.0f, 0.0f, coverage /* color */ + }; + void *fs; if (x < 0) { width += x; @@ -379,50 +257,38 @@ static void surface_fill(struct pipe_surface *surf, y = 0; } - cso_save_framebuffer(ctx->cso_context); - cso_save_blend(ctx->cso_context); - cso_save_fragment_shader(ctx->cso_context); - cso_save_viewport(ctx->cso_context); - - setup_mask_blend(); - setup_mask_fill(color); - setup_mask_framebuffer(surf, surf_width, surf_height); - setup_mask_viewport(); + fs = shaders_cache_fill(ctx->sc, VEGA_SOLID_FILL_SHADER); - renderer_draw_quad(ctx->renderer, x, y, - x + width, y + height, 0.0f/*depth should be disabled*/); - - - /* make sure rendering has completed */ - ctx->pipe->flush(ctx->pipe, - PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, - NULL); + if (renderer_filter_begin(ctx->renderer, dst, VG_FALSE, ~0, + NULL, NULL, 0, fs, (const void *) fs_consts, sizeof(fs_consts))) { + renderer_filter(ctx->renderer, x, y, width, height, 0, 0, 0, 0); + renderer_filter_end(ctx->renderer); + } #if DEBUG_MASKS save_alpha_to_file(0); #endif - - cso_restore_blend(ctx->cso_context); - cso_restore_framebuffer(ctx->cso_context); - cso_restore_fragment_shader(ctx->cso_context); - cso_restore_viewport(ctx->cso_context); } static void mask_using_texture(struct pipe_sampler_view *sampler_view, + VGboolean is_layer, VGMaskOperation operation, VGint x, VGint y, VGint width, VGint height) { struct vg_context *ctx = vg_current_context(); + struct pipe_sampler_view *dst_view = vg_get_surface_mask(ctx); + struct pipe_resource *dst = dst_view->texture; struct pipe_resource *texture = sampler_view->texture; - struct pipe_surface *surface = - alpha_mask_surface(ctx, PIPE_BIND_RENDER_TARGET); + const struct pipe_sampler_state *samplers[2]; + struct pipe_sampler_view *views[2]; + struct pipe_sampler_state sampler; VGint offsets[4], loc[4]; + const VGfloat ones[4] = {1.f, 1.f, 1.f, 1.f}; + void *fs; - if (!surface) - return; - if (!intersect_rectangles(surface->width, surface->height, + if (!intersect_rectangles(dst->width0, dst->height0, texture->width0, texture->height0, x, y, width, height, offsets, loc)) @@ -434,38 +300,30 @@ static void mask_using_texture(struct pipe_sampler_view *sampler_view, loc[1], loc[2], loc[3]); #endif + + sampler = ctx->mask.sampler; + sampler.normalized_coords = 1; + samplers[0] = &sampler; + views[0] = sampler_view; + /* prepare our blend surface */ - vg_prepare_blend_surface_from_mask(ctx); - - cso_save_samplers(ctx->cso_context); - cso_save_fragment_sampler_views(ctx->cso_context); - cso_save_framebuffer(ctx->cso_context); - cso_save_blend(ctx->cso_context); - cso_save_fragment_shader(ctx->cso_context); - cso_save_viewport(ctx->cso_context); - - setup_mask_samplers(sampler_view); - setup_mask_blend(); - setup_mask_operation(operation); - setup_mask_framebuffer(surface, surface->width, surface->height); - setup_mask_viewport(); - - /* render the quad to propagate the rendering from stencil */ - renderer_draw_texture(ctx->renderer, texture, - offsets[0], offsets[1], - offsets[0] + offsets[2], offsets[1] + offsets[3], - loc[0], loc[1], loc[0] + loc[2], loc[1] + loc[3]); + samplers[1] = &ctx->mask.sampler; + views[1] = vg_prepare_blend_surface_from_mask(ctx); - /* make sure rendering has completed */ - ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL); - cso_restore_blend(ctx->cso_context); - cso_restore_framebuffer(ctx->cso_context); - cso_restore_fragment_shader(ctx->cso_context); - cso_restore_samplers(ctx->cso_context); - cso_restore_fragment_sampler_views(ctx->cso_context); - cso_restore_viewport(ctx->cso_context); - - pipe_surface_reference(&surface, NULL); + fs = setup_mask_operation(operation); + + if (renderer_filter_begin(ctx->renderer, dst, VG_FALSE, + ~0, samplers, views, 2, fs, (const void *) ones, sizeof(ones))) { + /* layer should be flipped when used as a texture */ + if (is_layer) { + offsets[1] += offsets[3]; + offsets[3] = -offsets[3]; + } + renderer_filter(ctx->renderer, + loc[0], loc[1], loc[2], loc[3], + offsets[0], offsets[1], offsets[2], offsets[3]); + renderer_filter_end(ctx->renderer); + } } @@ -496,8 +354,8 @@ struct vg_mask_layer * mask_layer_create(VGint width, VGint height) pt.width0 = width; pt.height0 = height; pt.depth0 = 1; + pt.array_size = 1; pt.bind = PIPE_BIND_SAMPLER_VIEW; - pt.compressed = 0; texture = screen->resource_create(screen, &pt); @@ -519,7 +377,7 @@ void mask_layer_destroy(struct vg_mask_layer *layer) struct vg_context *ctx = vg_current_context(); vg_context_remove_object(ctx, VG_OBJECT_MASK, layer); - pipe_resource_release(&layer->texture); + pipe_sampler_view_reference(&layer->sampler_view, NULL); FREE(layer); } @@ -528,22 +386,12 @@ void mask_layer_fill(struct vg_mask_layer *layer, VGint width, VGint height, VGfloat value) { - struct vg_context *ctx = vg_current_context(); VGfloat alpha_color[4] = {0, 0, 0, 0}; - struct pipe_surface *surface; alpha_color[3] = value; - surface = ctx->pipe->screen->get_tex_surface( - ctx->pipe->screen, layer->sampler_view->texture, - 0, 0, 0, - PIPE_BIND_RENDER_TARGET); - - surface_fill(surface, - layer->width, layer->height, - x, y, width, height, alpha_color); - - ctx->pipe->screen->tex_surface_release(ctx->pipe->screen, &surface); + mask_resource_fill(layer->sampler_view->texture, + x, y, width, height, value); } void mask_copy(struct vg_mask_layer *layer, @@ -551,16 +399,27 @@ void mask_copy(struct vg_mask_layer *layer, VGint dx, VGint dy, VGint width, VGint height) { - struct vg_context *ctx = vg_current_context(); - struct st_framebuffer *fb_buffers = ctx->draw_buffer; - - renderer_copy_texture(ctx->renderer, - layer->sampler_view, - sx, sy, - sx + width, sy + height, - fb_buffers->alpha_mask_view->texture, - dx, dy, - dx + width, dy + height); + struct vg_context *ctx = vg_current_context(); + struct pipe_sampler_view *src = vg_get_surface_mask(ctx); + struct pipe_surface *surf, surf_tmpl; + + /* get the destination surface */ + u_surface_default_template(&surf_tmpl, layer->sampler_view->texture, + PIPE_BIND_RENDER_TARGET); + surf = ctx->pipe->create_surface(ctx->pipe, layer->sampler_view->texture, + &surf_tmpl); + if (surf && renderer_copy_begin(ctx->renderer, surf, VG_FALSE, src)) { + /* layer should be flipped when used as a texture */ + sy += height; + height = -height; + + renderer_copy(ctx->renderer, + dx, dy, width, height, + sx, sy, width, height); + renderer_copy_end(ctx->renderer); + } + + pipe_surface_reference(&surf, NULL); } static void mask_layer_render_to(struct vg_mask_layer *layer, @@ -568,41 +427,25 @@ static void mask_layer_render_to(struct vg_mask_layer *layer, VGbitfield paint_modes) { struct vg_context *ctx = vg_current_context(); - const VGfloat fill_color[4] = {1.f, 1.f, 1.f, 1.f}; - struct pipe_screen *screen = ctx->pipe->screen; - struct pipe_surface *surface; - - surface = screen->get_tex_surface(screen, layer->sampler_view->texture, 0, 0, 0, - PIPE_BIND_RENDER_TARGET); - - cso_save_framebuffer(ctx->cso_context); - cso_save_fragment_shader(ctx->cso_context); - cso_save_viewport(ctx->cso_context); + struct pipe_context *pipe = ctx->pipe; + struct pipe_sampler_view *view = vg_get_surface_mask(ctx); + struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix; + struct pipe_surface *surf, surf_tmpl; + u_surface_default_template(&surf_tmpl, view->texture, + PIPE_BIND_RENDER_TARGET); + surf = pipe->create_surface(pipe, view->texture, &surf_tmpl); - setup_mask_blend(); - setup_mask_fill(fill_color); - setup_mask_framebuffer(surface, layer->width, layer->height); - setup_mask_viewport(); + renderer_validate_for_mask_rendering(ctx->renderer, surf, mat); if (paint_modes & VG_FILL_PATH) { - struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix; - path_fill(path, mat); + path_fill(path); } if (paint_modes & VG_STROKE_PATH){ path_stroke(path); } - - /* make sure rendering has completed */ - ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL); - - cso_restore_framebuffer(ctx->cso_context); - cso_restore_fragment_shader(ctx->cso_context); - cso_restore_viewport(ctx->cso_context); - ctx->state.dirty |= BLEND_DIRTY; - - screen->tex_surface_release(ctx->pipe->screen, &surface); + pipe_surface_reference(&surf, NULL); } void mask_render_to(struct path *path, @@ -610,19 +453,19 @@ void mask_render_to(struct path *path, VGMaskOperation operation) { struct vg_context *ctx = vg_current_context(); - struct st_framebuffer *fb_buffers = ctx->draw_buffer; + struct st_framebuffer *stfb = ctx->draw_buffer; struct vg_mask_layer *temp_layer; VGint width, height; - width = fb_buffers->alpha_mask_view->texture->width0; - height = fb_buffers->alpha_mask_view->texture->width0; + width = stfb->width; + height = stfb->height; temp_layer = mask_layer_create(width, height); + mask_layer_fill(temp_layer, 0, 0, width, height, 0.0f); mask_layer_render_to(temp_layer, path, paint_modes); - mask_using_layer(temp_layer, 0, 0, width, height, - operation); + mask_using_layer(temp_layer, operation, 0, 0, width, height); mask_layer_destroy(temp_layer); } @@ -632,7 +475,7 @@ void mask_using_layer(struct vg_mask_layer *layer, VGint x, VGint y, VGint width, VGint height) { - mask_using_texture(layer->sampler_view, operation, + mask_using_texture(layer->sampler_view, VG_TRUE, operation, x, y, width, height); } @@ -654,7 +497,7 @@ void mask_using_image(struct vg_image *image, VGint x, VGint y, VGint width, VGint height) { - mask_using_texture(image->sampler_view, operation, + mask_using_texture(image->sampler_view, VG_FALSE, operation, x, y, width, height); } @@ -662,23 +505,15 @@ void mask_fill(VGint x, VGint y, VGint width, VGint height, VGfloat value) { struct vg_context *ctx = vg_current_context(); - VGfloat alpha_color[4] = {.0f, .0f, .0f, value}; - struct pipe_surface *surf = alpha_mask_surface( - ctx, PIPE_BIND_RENDER_TARGET); + struct pipe_sampler_view *view = vg_get_surface_mask(ctx); #if DEBUG_MASKS debug_printf("mask_fill(%d, %d, %d, %d) with rgba(%f, %f, %f, %f)\n", x, y, width, height, - alpha_color[0], alpha_color[1], - alpha_color[2], alpha_color[3]); - debug_printf("XXX %f === %f \n", - alpha_color[3], value); + 0.0f, 0.0f, 0.0f, value); #endif - surface_fill(surf, surf->width, surf->height, - x, y, width, height, alpha_color); - - pipe_surface_reference(&surf, NULL); + mask_resource_fill(view->texture, x, y, width, height, value); } VGint mask_bind_samplers(struct pipe_sampler_state **samplers, @@ -687,10 +522,8 @@ VGint mask_bind_samplers(struct pipe_sampler_state **samplers, struct vg_context *ctx = vg_current_context(); if (ctx->state.vg.masking) { - struct st_framebuffer *fb_buffers = ctx->draw_buffer; - samplers[1] = &ctx->mask.sampler; - sampler_views[1] = fb_buffers->alpha_mask_view; + sampler_views[1] = vg_get_surface_mask(ctx); return 1; } else return 0; diff --git a/src/gallium/state_trackers/vega/matrix.h b/src/gallium/state_trackers/vega/matrix.h index 4c207f912a8..bed2b3193d0 100644 --- a/src/gallium/state_trackers/vega/matrix.h +++ b/src/gallium/state_trackers/vega/matrix.h @@ -129,7 +129,7 @@ static INLINE void matrix_make_affine(struct matrix *matrix) } static INLINE void matrix_mult(struct matrix *dst, - struct matrix *src) + const struct matrix *src) { VGfloat m11 = dst->m[0]*src->m[0] + dst->m[3]*src->m[1] + dst->m[6]*src->m[2]; VGfloat m12 = dst->m[0]*src->m[3] + dst->m[3]*src->m[4] + dst->m[6]*src->m[5]; diff --git a/src/gallium/state_trackers/vega/paint.c b/src/gallium/state_trackers/vega/paint.c index c0c8cddabe9..2db8cbcf7c8 100644 --- a/src/gallium/state_trackers/vega/paint.c +++ b/src/gallium/state_trackers/vega/paint.c @@ -28,7 +28,6 @@ #include "matrix.h" #include "image.h" -#include "st_inlines.h" #include "pipe/p_compiler.h" #include "util/u_inlines.h" @@ -155,14 +154,15 @@ static INLINE struct pipe_resource *create_gradient_texture(struct vg_paint *p) templ.width0 = 1024; templ.height0 = 1; templ.depth0 = 1; + templ.array_size = 1; templ.bind = PIPE_BIND_SAMPLER_VIEW; tex = screen->resource_create(screen, &templ); { /* upload color_data */ struct pipe_transfer *transfer = - st_no_flush_get_transfer(p->base.ctx, tex, 0, 0, 0, - PIPE_TRANSFER_WRITE, 0, 0, 1024, 1); + pipe_get_transfer(p->base.ctx->pipe, tex, 0, 0, + PIPE_TRANSFER_WRITE, 0, 0, 1024, 1); void *map = pipe->transfer_map(pipe, transfer); memcpy(map, p->gradient.color_data, sizeof(VGint)*1024); pipe->transfer_unmap(pipe, transfer); @@ -261,14 +261,18 @@ static INLINE void paint_color_buffer(struct vg_paint *paint, void *buffer) map[7] = 4.f; } -static INLINE void paint_linear_gradient_buffer(struct vg_paint *paint, void *buffer) +static INLINE void paint_linear_gradient_buffer(struct vg_paint *paint, + const struct matrix *inv, + void *buffer) { - struct vg_context *ctx = paint->base.ctx; VGfloat *map = (VGfloat*)buffer; + VGfloat dd; map[0] = paint->gradient.linear.coords[2] - paint->gradient.linear.coords[0]; map[1] = paint->gradient.linear.coords[3] - paint->gradient.linear.coords[1]; - map[2] = 1.f / (map[0] * map[0] + map[1] * map[1]); + dd = (map[0] * map[0] + map[1] * map[1]); + + map[2] = (dd > 0.0f) ? 1.f / dd : 0.f; map[3] = 1.f; map[4] = 0.f; @@ -277,15 +281,10 @@ static INLINE void paint_linear_gradient_buffer(struct vg_paint *paint, void *bu map[7] = 4.f; { struct matrix mat; - struct matrix inv; matrix_load_identity(&mat); + /* VEGA_LINEAR_GRADIENT_SHADER expects the first point to be at (0, 0) */ matrix_translate(&mat, -paint->gradient.linear.coords[0], -paint->gradient.linear.coords[1]); - memcpy(&inv, &ctx->state.vg.fill_paint_to_user_matrix, - sizeof(struct matrix)); - matrix_invert(&inv); - matrix_mult(&inv, &mat); - memcpy(&mat, &inv, - sizeof(struct matrix)); + matrix_mult(&mat, inv); map[8] = mat.m[0]; map[9] = mat.m[3]; map[10] = mat.m[6]; map[11] = 0.f; map[12] = mat.m[1]; map[13] = mat.m[4]; map[14] = mat.m[7]; map[15] = 0.f; @@ -298,17 +297,37 @@ static INLINE void paint_linear_gradient_buffer(struct vg_paint *paint, void *bu } -static INLINE void paint_radial_gradient_buffer(struct vg_paint *paint, void *buffer) +static INLINE void paint_radial_gradient_buffer(struct vg_paint *paint, + const struct matrix *inv, + void *buffer) { - VGfloat *radialCoords = paint->gradient.radial.vals; - struct vg_context *ctx = paint->base.ctx; - + const VGfloat *center = &paint->gradient.radial.vals[0]; + const VGfloat *focal = &paint->gradient.radial.vals[2]; + VGfloat rr = paint->gradient.radial.vals[4]; VGfloat *map = (VGfloat*)buffer; + VGfloat dd, new_focal[2]; + + rr *= rr; + + map[0] = center[0] - focal[0]; + map[1] = center[1] - focal[1]; + dd = map[0] * map[0] + map[1] * map[1]; + + /* focal point must lie inside the circle */ + if (0.998f * rr < dd) { + VGfloat scale; + + scale = (dd > 0.0f) ? sqrt(0.998f * rr / dd) : 0.0f; + map[0] *= scale; + map[1] *= scale; - map[0] = radialCoords[0] - radialCoords[2]; - map[1] = radialCoords[1] - radialCoords[3]; - map[2] = -map[0] * map[0] - map[1] * map[1] + - radialCoords[4] * radialCoords[4]; + new_focal[0] = center[0] - map[0]; + new_focal[1] = center[1] - map[1]; + dd = map[0] * map[0] + map[1] * map[1]; + focal = new_focal; + } + + map[2] = (rr > dd) ? rr - dd : 1.0f; map[3] = 1.f; map[4] = 0.f; @@ -318,15 +337,9 @@ static INLINE void paint_radial_gradient_buffer(struct vg_paint *paint, void *bu { struct matrix mat; - struct matrix inv; matrix_load_identity(&mat); - matrix_translate(&mat, -radialCoords[2], -radialCoords[3]); - memcpy(&inv, &ctx->state.vg.fill_paint_to_user_matrix, - sizeof(struct matrix)); - matrix_invert(&inv); - matrix_mult(&inv, &mat); - memcpy(&mat, &inv, - sizeof(struct matrix)); + matrix_translate(&mat, -focal[0], -focal[1]); + matrix_mult(&mat, inv); map[8] = mat.m[0]; map[9] = mat.m[3]; map[10] = mat.m[6]; map[11] = 0.f; map[12] = mat.m[1]; map[13] = mat.m[4]; map[14] = mat.m[7]; map[15] = 0.f; @@ -340,10 +353,10 @@ static INLINE void paint_radial_gradient_buffer(struct vg_paint *paint, void *bu } -static INLINE void paint_pattern_buffer(struct vg_paint *paint, void *buffer) +static INLINE void paint_pattern_buffer(struct vg_paint *paint, + const struct matrix *inv, + void *buffer) { - struct vg_context *ctx = paint->base.ctx; - VGfloat *map = (VGfloat *)buffer; memcpy(map, paint->solid.color, 4 * sizeof(VGfloat)); @@ -353,17 +366,8 @@ static INLINE void paint_pattern_buffer(struct vg_paint *paint, void *buffer) map[7] = paint->pattern.sampler_view->texture->height0; { struct matrix mat; - memcpy(&mat, &ctx->state.vg.fill_paint_to_user_matrix, - sizeof(struct matrix)); - matrix_invert(&mat); - { - struct matrix pm; - memcpy(&pm, &ctx->state.vg.path_user_to_surface_matrix, - sizeof(struct matrix)); - matrix_invert(&pm); - matrix_mult(&pm, &mat); - memcpy(&mat, &pm, sizeof(struct matrix)); - } + + memcpy(&mat, inv, sizeof(*inv)); map[8] = mat.m[0]; map[9] = mat.m[3]; map[10] = mat.m[6]; map[11] = 0.f; map[12] = mat.m[1]; map[13] = mat.m[4]; map[14] = mat.m[7]; map[15] = 0.f; @@ -672,6 +676,34 @@ void paint_resolve_type(struct vg_paint *paint) } } +VGboolean paint_is_degenerate(struct vg_paint *paint) +{ + VGboolean degen; + VGfloat *vals; + + + switch (paint->type) { + case VG_PAINT_TYPE_LINEAR_GRADIENT: + vals = paint->gradient.linear.coords; + /* two points are coincident */ + degen = (floatsEqual(vals[0], vals[2]) && + floatsEqual(vals[1], vals[3])); + break; + case VG_PAINT_TYPE_RADIAL_GRADIENT: + vals = paint->gradient.radial.vals; + /* radius <= 0 */ + degen = (vals[4] <= 0.0f); + break; + case VG_PAINT_TYPE_COLOR: + case VG_PAINT_TYPE_PATTERN: + default: + degen = VG_FALSE; + break; + } + + return degen; +} + VGint paint_constant_buffer_size(struct vg_paint *paint) { switch(paint->type) { @@ -695,6 +727,7 @@ VGint paint_constant_buffer_size(struct vg_paint *paint) } void paint_fill_constant_buffer(struct vg_paint *paint, + const struct matrix *mat, void *buffer) { switch(paint->type) { @@ -702,13 +735,13 @@ void paint_fill_constant_buffer(struct vg_paint *paint, paint_color_buffer(paint, buffer); break; case VG_PAINT_TYPE_LINEAR_GRADIENT: - paint_linear_gradient_buffer(paint, buffer); + paint_linear_gradient_buffer(paint, mat, buffer); break; case VG_PAINT_TYPE_RADIAL_GRADIENT: - paint_radial_gradient_buffer(paint, buffer); + paint_radial_gradient_buffer(paint, mat, buffer); break; case VG_PAINT_TYPE_PATTERN: - paint_pattern_buffer(paint, buffer); + paint_pattern_buffer(paint, mat, buffer); break; default: diff --git a/src/gallium/state_trackers/vega/paint.h b/src/gallium/state_trackers/vega/paint.h index 012cd3e5618..3de3bbe12ed 100644 --- a/src/gallium/state_trackers/vega/paint.h +++ b/src/gallium/state_trackers/vega/paint.h @@ -110,8 +110,12 @@ VGboolean paint_color_ramp_premultiplied(struct vg_paint *paint); VGint paint_bind_samplers(struct vg_paint *paint, struct pipe_sampler_state **samplers, struct pipe_sampler_view **sampler_views); +VGboolean paint_is_degenerate(struct vg_paint *paint); + VGint paint_constant_buffer_size(struct vg_paint *paint); + void paint_fill_constant_buffer(struct vg_paint *paint, + const struct matrix *mat, void *buffer); diff --git a/src/gallium/state_trackers/vega/path.c b/src/gallium/state_trackers/vega/path.c index 05f8b0d9979..d7253befd03 100644 --- a/src/gallium/state_trackers/vega/path.c +++ b/src/gallium/state_trackers/vega/path.c @@ -207,13 +207,29 @@ struct path * path_create(VGPathDatatype dt, VGfloat scale, VGfloat bias, return path; } +static void polygon_array_cleanup(struct polygon_array *polyarray) +{ + if (polyarray->array) { + VGint i; + + for (i = 0; i < polyarray->array->num_elements; i++) { + struct polygon *p = ((struct polygon **) polyarray->array->data)[i]; + polygon_destroy(p); + } + + array_destroy(polyarray->array); + polyarray->array = NULL; + } +} + void path_destroy(struct path *p) { vg_context_remove_object(vg_current_context(), VG_OBJECT_PATH, p); array_destroy(p->segments); array_destroy(p->control_points); - array_destroy(p->fill_polys.polygon_array.array); + + polygon_array_cleanup(&p->fill_polys.polygon_array); if (p->stroked.path) path_destroy(p->stroked.path); @@ -302,7 +318,6 @@ static void convert_path(struct path *p, } } - static void polygon_array_calculate_bounds( struct polygon_array *polyarray ) { struct array *polys = polyarray->array; @@ -312,7 +327,15 @@ static void polygon_array_calculate_bounds( struct polygon_array *polyarray ) unsigned i; assert(polys); - assert(polys->num_elements); + + if (!polys->num_elements) { + polyarray->min_x = 0.0f; + polyarray->min_y = 0.0f; + polyarray->max_x = 0.0f; + polyarray->max_y = 0.0f; + return; + } + polygon_bounding_rect((((struct polygon**)polys->data)[0]), bounds); min_x = bounds[0]; min_y = bounds[1]; @@ -353,16 +376,17 @@ static struct polygon_array * path_get_fill_polygons(struct path *p, struct matr return &p->fill_polys.polygon_array; } else { - array_destroy( p->fill_polys.polygon_array.array ); - p->fill_polys.polygon_array.array = NULL; + polygon_array_cleanup(&p->fill_polys.polygon_array); } } - array = array_create(sizeof(struct array*)); + /* an array of pointers to polygons */ + array = array_create(sizeof(struct polygon *)); sx = sy = px = py = ox = oy = 0.f; - current = polygon_create(32); + if (p->num_segments) + current = polygon_create(32); for (i = 0; i < p->num_segments; ++i) { VGubyte segment = ((VGubyte*)(p->segments->data))[i]; @@ -1519,10 +1543,11 @@ struct path * path_create_stroke(struct path *p, return stroker.base.path; } -void path_render(struct path *p, VGbitfield paintModes) +void path_render(struct path *p, VGbitfield paintModes, + struct matrix *mat) { struct vg_context *ctx = vg_current_context(); - struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix; + struct matrix paint_matrix; vg_validate_state(ctx); @@ -1534,29 +1559,45 @@ void path_render(struct path *p, VGbitfield paintModes) mat->m[3], mat->m[4], mat->m[5], mat->m[6], mat->m[7], mat->m[8]); #endif - if (paintModes & VG_FILL_PATH) { + if ((paintModes & VG_FILL_PATH) && + vg_get_paint_matrix(ctx, + &ctx->state.vg.fill_paint_to_user_matrix, + mat, + &paint_matrix)) { /* First the fill */ + shader_set_surface_matrix(ctx->shader, mat); shader_set_paint(ctx->shader, ctx->state.vg.fill_paint); + shader_set_paint_matrix(ctx->shader, &paint_matrix); shader_bind(ctx->shader); - path_fill(p, mat); + path_fill(p); } - if (paintModes & VG_STROKE_PATH){ + if ((paintModes & VG_STROKE_PATH) && + vg_get_paint_matrix(ctx, + &ctx->state.vg.stroke_paint_to_user_matrix, + mat, + &paint_matrix)) { /* 8.7.5: "line width less than or equal to 0 prevents stroking from * taking place."*/ if (ctx->state.vg.stroke.line_width.f <= 0) return; + shader_set_surface_matrix(ctx->shader, mat); shader_set_paint(ctx->shader, ctx->state.vg.stroke_paint); + shader_set_paint_matrix(ctx->shader, &paint_matrix); shader_bind(ctx->shader); path_stroke(p); } } -void path_fill(struct path *p, struct matrix *mat) +void path_fill(struct path *p) { struct vg_context *ctx = vg_current_context(); + struct matrix identity; + + matrix_load_identity(&identity); + { - struct polygon_array *polygon_array = path_get_fill_polygons(p, mat); + struct polygon_array *polygon_array = path_get_fill_polygons(p, &identity); struct array *polys = polygon_array->array; if (!polygon_array || !polys || !polys->num_elements) { @@ -1569,7 +1610,6 @@ void path_fill(struct path *p, struct matrix *mat) void path_stroke(struct path *p) { struct vg_context *ctx = vg_current_context(); - struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix; VGFillRule old_fill = ctx->state.vg.fill_rule; struct matrix identity; struct path *stroke; @@ -1579,7 +1619,7 @@ void path_stroke(struct path *p) if (stroke && !path_is_empty(stroke)) { ctx->state.vg.fill_rule = VG_NON_ZERO; - path_fill(stroke, mat); + path_fill(stroke); ctx->state.vg.fill_rule = old_fill; } diff --git a/src/gallium/state_trackers/vega/path.h b/src/gallium/state_trackers/vega/path.h index e34538b7368..d84b1f083ce 100644 --- a/src/gallium/state_trackers/vega/path.h +++ b/src/gallium/state_trackers/vega/path.h @@ -104,8 +104,8 @@ VGboolean path_interpolate(struct path *dst, VGfloat amount); void path_clear(struct path *p, VGbitfield capabilities); -void path_render(struct path *p, VGbitfield paintModes); -void path_fill(struct path *p, struct matrix *mat); +void path_render(struct path *p, VGbitfield paintModes, struct matrix *mat); +void path_fill(struct path *p); void path_stroke(struct path *p); void path_move_to(struct path *p, float x, float y); diff --git a/src/gallium/state_trackers/vega/polygon.c b/src/gallium/state_trackers/vega/polygon.c index ca8831064c9..a491de27fa6 100644 --- a/src/gallium/state_trackers/vega/polygon.c +++ b/src/gallium/state_trackers/vega/polygon.c @@ -244,24 +244,11 @@ VGboolean polygon_is_closed(struct polygon *p) return floatsEqual(start[0], end[0]) && floatsEqual(start[1], end[1]); } -static void set_blend_for_fill(struct pipe_blend_state *blend) -{ - memset(blend, 0, sizeof(struct pipe_blend_state)); - blend->rt[0].colormask = 0; /*disable colorwrites*/ - - blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; - blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; - blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; - blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; -} - -static void draw_polygon(struct vg_context *ctx, - struct polygon *poly) +static void polygon_prepare_buffer(struct vg_context *ctx, + struct polygon *poly) { int vert_size; struct pipe_context *pipe; - struct pipe_vertex_buffer vbuffer; - struct pipe_vertex_element velement; vert_size = poly->num_verts * COMPONENTS * sizeof(float); @@ -281,35 +268,15 @@ static void draw_polygon(struct vg_context *ctx, PIPE_BIND_VERTEX_BUFFER); poly->dirty = VG_FALSE; } - - - /* tell pipe about the vertex buffer */ - memset(&vbuffer, 0, sizeof(vbuffer)); - vbuffer.buffer = poly->vbuf; - vbuffer.stride = COMPONENTS * sizeof(float); /* vertex size */ - vbuffer.buffer_offset = 0; - vbuffer.max_index = poly->num_verts - 1; - pipe->set_vertex_buffers(pipe, 1, &vbuffer); - - /* tell pipe about the vertex attributes */ - 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(ctx->cso_context, 1, &velement); - - /* draw */ - util_draw_arrays(pipe, PIPE_PRIM_TRIANGLE_FAN, 0, (uint) poly->num_verts); } void polygon_fill(struct polygon *poly, struct vg_context *ctx) { - struct pipe_depth_stencil_alpha_state dsa; - struct pipe_stencil_ref sr; - struct pipe_blend_state blend; + struct pipe_vertex_element velement; + struct pipe_vertex_buffer vbuffer; VGfloat bounds[4]; VGfloat min_x, min_y, max_x, max_y; + assert(poly); polygon_bounding_rect(poly, bounds); min_x = bounds[0]; @@ -322,113 +289,42 @@ void polygon_fill(struct polygon *poly, struct vg_context *ctx) min_x, min_y, max_x, max_y); #endif - set_blend_for_fill(&blend); - - memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); - memset(&sr, 0, sizeof(struct pipe_stencil_ref)); - /* only need a fixed 0. Rely on default or move it out at least? */ - cso_set_stencil_ref(ctx->cso_context, &sr); - - cso_save_blend(ctx->cso_context); - cso_save_depth_stencil_alpha(ctx->cso_context); - - dsa.stencil[0].enabled = 1; - if (ctx->state.vg.fill_rule == VG_EVEN_ODD) { - dsa.stencil[0].writemask = 1; - dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT; - dsa.stencil[0].func = PIPE_FUNC_ALWAYS; - dsa.stencil[0].valuemask = ~0; - - cso_set_blend(ctx->cso_context, &blend); - cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); - draw_polygon(ctx, poly); - } else if (ctx->state.vg.fill_rule == VG_NON_ZERO) { - struct pipe_screen *screen = ctx->pipe->screen; - - if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) { - /* front */ - dsa.stencil[0].writemask = ~0; - dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; - dsa.stencil[0].func = PIPE_FUNC_ALWAYS; - dsa.stencil[0].valuemask = ~0; - - /* back */ - dsa.stencil[1].enabled = 1; - dsa.stencil[1].writemask = ~0; - dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; - dsa.stencil[1].func = PIPE_FUNC_ALWAYS; - dsa.stencil[1].valuemask = ~0; - - cso_set_blend(ctx->cso_context, &blend); - cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); - draw_polygon(ctx, poly); - } else { - struct pipe_rasterizer_state raster; - - memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state)); - - cso_save_rasterizer(ctx->cso_context); - dsa.stencil[0].func = PIPE_FUNC_ALWAYS; - dsa.stencil[0].valuemask = ~0; - - raster.cull_face = PIPE_FACE_BACK; - dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; - - cso_set_blend(ctx->cso_context, &blend); - cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); - cso_set_rasterizer(ctx->cso_context, &raster); - draw_polygon(ctx, poly); - - raster.cull_face = PIPE_FACE_FRONT; - dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; - cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); - cso_set_rasterizer(ctx->cso_context, &raster); - draw_polygon(ctx, poly); - - cso_restore_rasterizer(ctx->cso_context); - } - } + polygon_prepare_buffer(ctx, poly); + + /* tell renderer about the vertex attributes */ + 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; + + /* tell renderer about the vertex buffer */ + memset(&vbuffer, 0, sizeof(vbuffer)); + vbuffer.buffer = poly->vbuf; + vbuffer.stride = COMPONENTS * sizeof(float); /* vertex size */ + vbuffer.buffer_offset = 0; + vbuffer.max_index = poly->num_verts - 1; + + renderer_polygon_stencil_begin(ctx->renderer, + &velement, ctx->state.vg.fill_rule, VG_FALSE); + renderer_polygon_stencil(ctx->renderer, &vbuffer, + PIPE_PRIM_TRIANGLE_FAN, 0, (VGuint) poly->num_verts); + renderer_polygon_stencil_end(ctx->renderer); - /* restore color writes */ - cso_restore_blend(ctx->cso_context); - /* setup stencil ops */ - dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL; - dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; - dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; - dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; - dsa.stencil[0].valuemask = dsa.stencil[0].writemask; - dsa.stencil[1].enabled = 0; - memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth, - sizeof(struct pipe_depth_state)); - cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); - - /* render the quad to propagate the rendering from stencil */ - renderer_draw_quad(ctx->renderer, min_x, min_y, - max_x, max_y, 0.0f/*depth should be disabled*/); - - cso_restore_depth_stencil_alpha(ctx->cso_context); + renderer_polygon_fill_begin(ctx->renderer, VG_FALSE); + renderer_polygon_fill(ctx->renderer, min_x, min_y, max_x, max_y); + renderer_polygon_fill_end(ctx->renderer); } void polygon_array_fill(struct polygon_array *polyarray, struct vg_context *ctx) { struct array *polys = polyarray->array; - struct pipe_depth_stencil_alpha_state dsa; - struct pipe_stencil_ref sr; - struct pipe_blend_state blend; VGfloat min_x = polyarray->min_x; VGfloat min_y = polyarray->min_y; VGfloat max_x = polyarray->max_x; VGfloat max_y = polyarray->max_y; + struct pipe_vertex_element velement; + struct pipe_vertex_buffer vbuffer; VGint i; @@ -438,111 +334,35 @@ void polygon_array_fill(struct polygon_array *polyarray, struct vg_context *ctx) min_x, min_y, max_x, max_y); #endif - set_blend_for_fill(&blend); - - memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); - memset(&sr, 0, sizeof(struct pipe_stencil_ref)); - /* only need a fixed 0. Rely on default or move it out at least? */ - cso_set_stencil_ref(ctx->cso_context, &sr); - - cso_save_blend(ctx->cso_context); - cso_save_depth_stencil_alpha(ctx->cso_context); - - dsa.stencil[0].enabled = 1; - if (ctx->state.vg.fill_rule == VG_EVEN_ODD) { - dsa.stencil[0].writemask = 1; - dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT; - dsa.stencil[0].func = PIPE_FUNC_ALWAYS; - dsa.stencil[0].valuemask = ~0; - - cso_set_blend(ctx->cso_context, &blend); - cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); - for (i = 0; i < polys->num_elements; ++i) { - struct polygon *poly = (((struct polygon**)polys->data)[i]); - draw_polygon(ctx, poly); - } - } else if (ctx->state.vg.fill_rule == VG_NON_ZERO) { - struct pipe_screen *screen = ctx->pipe->screen; - - if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) { - /* front */ - dsa.stencil[0].writemask = ~0; - dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; - dsa.stencil[0].func = PIPE_FUNC_ALWAYS; - dsa.stencil[0].valuemask = ~0; - - /* back */ - dsa.stencil[1].enabled = 1; - dsa.stencil[1].writemask = ~0; - dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; - dsa.stencil[1].func = PIPE_FUNC_ALWAYS; - dsa.stencil[1].valuemask = ~0; - - cso_set_blend(ctx->cso_context, &blend); - cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); - for (i = 0; i < polys->num_elements; ++i) { - struct polygon *poly = (((struct polygon**)polys->data)[i]); - draw_polygon(ctx, poly); - } - } else { - struct pipe_rasterizer_state raster; - - memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state)); - - cso_save_rasterizer(ctx->cso_context); - dsa.stencil[0].func = PIPE_FUNC_ALWAYS; - dsa.stencil[0].valuemask = ~0; - - raster.cull_face = PIPE_FACE_BACK; - dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; - - cso_set_blend(ctx->cso_context, &blend); - cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); - cso_set_rasterizer(ctx->cso_context, &raster); - for (i = 0; i < polys->num_elements; ++i) { - struct polygon *poly = (((struct polygon**)polys->data)[i]); - draw_polygon(ctx, poly); - } - - raster.cull_face = PIPE_FACE_FRONT; - dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; - dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; - cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); - cso_set_rasterizer(ctx->cso_context, &raster); - for (i = 0; i < polys->num_elements; ++i) { - struct polygon *poly = (((struct polygon**)polys->data)[i]); - draw_polygon(ctx, poly); - } - - cso_restore_rasterizer(ctx->cso_context); - } + /* tell renderer about the vertex attributes */ + 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; + + /* tell renderer about the vertex buffer */ + memset(&vbuffer, 0, sizeof(vbuffer)); + vbuffer.stride = COMPONENTS * sizeof(float); /* vertex size */ + vbuffer.buffer_offset = 0; + + /* prepare the stencil buffer */ + renderer_polygon_stencil_begin(ctx->renderer, + &velement, ctx->state.vg.fill_rule, VG_FALSE); + for (i = 0; i < polys->num_elements; ++i) { + struct polygon *poly = (((struct polygon**)polys->data)[i]); + + polygon_prepare_buffer(ctx, poly); + vbuffer.buffer = poly->vbuf; + vbuffer.max_index = poly->num_verts - 1; + + renderer_polygon_stencil(ctx->renderer, &vbuffer, + PIPE_PRIM_TRIANGLE_FAN, 0, (VGuint) poly->num_verts); } + renderer_polygon_stencil_end(ctx->renderer); - /* restore color writes */ - cso_restore_blend(ctx->cso_context); - /* setup stencil ops */ - dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL; - dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; - dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; - dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; - dsa.stencil[0].valuemask = dsa.stencil[0].writemask; - dsa.stencil[1].enabled = 0; - memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth, - sizeof(struct pipe_depth_state)); - cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); - - /* render the quad to propagate the rendering from stencil */ - renderer_draw_quad(ctx->renderer, min_x, min_y, - max_x, max_y, 0.0f/*depth should be disabled*/); - - cso_restore_depth_stencil_alpha(ctx->cso_context); + /* fill it */ + renderer_polygon_fill_begin(ctx->renderer, VG_FALSE); + renderer_polygon_fill(ctx->renderer, min_x, min_y, max_x, max_y); + renderer_polygon_fill_end(ctx->renderer); } diff --git a/src/gallium/state_trackers/vega/renderer.c b/src/gallium/state_trackers/vega/renderer.c index c6f5f7a05b8..7871c516c41 100644 --- a/src/gallium/state_trackers/vega/renderer.c +++ b/src/gallium/state_trackers/vega/renderer.c @@ -1,6 +1,7 @@ /************************************************************************** * * Copyright 2009 VMware, Inc. All Rights Reserved. + * Copyright 2010 LunarG, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -27,6 +28,7 @@ #include "renderer.h" #include "vg_context.h" +#include "image.h" #include "pipe/p_context.h" #include "pipe/p_state.h" @@ -38,364 +40,1382 @@ #include "util/u_simple_shaders.h" #include "util/u_memory.h" #include "util/u_sampler.h" +#include "util/u_surface.h" +#include "util/u_math.h" +#include "util/u_format.h" #include "cso_cache/cso_context.h" +#include "tgsi/tgsi_ureg.h" + +typedef enum { + RENDERER_STATE_INIT, + RENDERER_STATE_COPY, + RENDERER_STATE_DRAWTEX, + RENDERER_STATE_SCISSOR, + RENDERER_STATE_CLEAR, + RENDERER_STATE_FILTER, + RENDERER_STATE_POLYGON_STENCIL, + RENDERER_STATE_POLYGON_FILL, + NUM_RENDERER_STATES +} RendererState; + +typedef enum { + RENDERER_VS_PLAIN, + RENDERER_VS_COLOR, + RENDERER_VS_TEXTURE, + NUM_RENDERER_VS +} RendererVs; + +typedef enum { + RENDERER_FS_COLOR, + RENDERER_FS_TEXTURE, + RENDERER_FS_SCISSOR, + RENDERER_FS_WHITE, + NUM_RENDERER_FS +} RendererFs; struct renderer { struct pipe_context *pipe; - struct vg_context *owner; - struct cso_context *cso; - void *fs; + VGbitfield dirty; + struct { + struct pipe_rasterizer_state rasterizer; + struct pipe_depth_stencil_alpha_state dsa; + struct pipe_framebuffer_state fb; + } g3d; + struct matrix projection; + + struct matrix mvp; + struct pipe_resource *vs_cbuf; + + struct pipe_resource *fs_cbuf; + VGfloat fs_cbuf_data[32]; + VGint fs_cbuf_len; + struct pipe_vertex_element velems[2]; VGfloat vertices[4][2][4]; + + void *cached_vs[NUM_RENDERER_VS]; + void *cached_fs[NUM_RENDERER_FS]; + + RendererState state; + + /* state data */ + union { + struct { + VGint tex_width; + VGint tex_height; + } copy; + + struct { + VGint tex_width; + VGint tex_height; + } drawtex; + + struct { + VGboolean restore_dsa; + } scissor; + + struct { + VGboolean use_sampler; + VGint tex_width, tex_height; + } filter; + + struct { + struct pipe_depth_stencil_alpha_state dsa; + VGboolean manual_two_sides; + VGboolean restore_dsa; + } polygon_stencil; + } u; }; -static void setup_shaders(struct renderer *ctx) +/** + * Return VG_TRUE if the renderer can use the resource as the asked bindings. + */ +static VGboolean renderer_can_support(struct renderer *renderer, + struct pipe_resource *res, + unsigned bindings) { - struct pipe_context *pipe = ctx->pipe; - /* fragment shader */ - ctx->fs = util_make_fragment_tex_shader(pipe, TGSI_TEXTURE_2D, - TGSI_INTERPOLATE_LINEAR); -} - -static struct pipe_resource * -setup_vertex_data(struct renderer *ctx, - float x0, float y0, float x1, float y1, float z) -{ - ctx->vertices[0][0][0] = x0; - ctx->vertices[0][0][1] = y0; - ctx->vertices[0][0][2] = z; - ctx->vertices[0][1][0] = 0.0f; /*s*/ - ctx->vertices[0][1][1] = 0.0f; /*t*/ - - ctx->vertices[1][0][0] = x1; - ctx->vertices[1][0][1] = y0; - ctx->vertices[1][0][2] = z; - ctx->vertices[1][1][0] = 1.0f; /*s*/ - ctx->vertices[1][1][1] = 0.0f; /*t*/ - - ctx->vertices[2][0][0] = x1; - ctx->vertices[2][0][1] = y1; - ctx->vertices[2][0][2] = z; - ctx->vertices[2][1][0] = 1.0f; - ctx->vertices[2][1][1] = 1.0f; - - ctx->vertices[3][0][0] = x0; - ctx->vertices[3][0][1] = y1; - ctx->vertices[3][0][2] = z; - ctx->vertices[3][1][0] = 0.0f; - ctx->vertices[3][1][1] = 1.0f; - - return pipe_user_buffer_create( ctx->pipe->screen, - ctx->vertices, - sizeof(ctx->vertices), - PIPE_BIND_VERTEX_BUFFER); -} - -static struct pipe_resource * -setup_vertex_data_tex(struct renderer *ctx, - float x0, float y0, float x1, float y1, - float s0, float t0, float s1, float t1, - float z) -{ - ctx->vertices[0][0][0] = x0; - ctx->vertices[0][0][1] = y0; - ctx->vertices[0][0][2] = z; - ctx->vertices[0][1][0] = s0; /*s*/ - ctx->vertices[0][1][1] = t0; /*t*/ - - ctx->vertices[1][0][0] = x1; - ctx->vertices[1][0][1] = y0; - ctx->vertices[1][0][2] = z; - ctx->vertices[1][1][0] = s1; /*s*/ - ctx->vertices[1][1][1] = t0; /*t*/ - - ctx->vertices[2][0][0] = x1; - ctx->vertices[2][0][1] = y1; - ctx->vertices[2][0][2] = z; - ctx->vertices[2][1][0] = s1; - ctx->vertices[2][1][1] = t1; - - ctx->vertices[3][0][0] = x0; - ctx->vertices[3][0][1] = y1; - ctx->vertices[3][0][2] = z; - ctx->vertices[3][1][0] = s0; - ctx->vertices[3][1][1] = t1; - - return pipe_user_buffer_create( ctx->pipe->screen, - ctx->vertices, - sizeof(ctx->vertices), - PIPE_BIND_VERTEX_BUFFER); -} - - -static struct pipe_resource * -setup_vertex_data_qtex(struct renderer *ctx, - float x0, float y0, float x1, float y1, - float x2, float y2, float x3, float y3, - float s0, float t0, float s1, float t1, - float z) -{ - ctx->vertices[0][0][0] = x0; - ctx->vertices[0][0][1] = y0; - ctx->vertices[0][0][2] = z; - ctx->vertices[0][1][0] = s0; /*s*/ - ctx->vertices[0][1][1] = t0; /*t*/ - - ctx->vertices[1][0][0] = x1; - ctx->vertices[1][0][1] = y1; - ctx->vertices[1][0][2] = z; - ctx->vertices[1][1][0] = s1; /*s*/ - ctx->vertices[1][1][1] = t0; /*t*/ - - ctx->vertices[2][0][0] = x2; - ctx->vertices[2][0][1] = y2; - ctx->vertices[2][0][2] = z; - ctx->vertices[2][1][0] = s1; - ctx->vertices[2][1][1] = t1; - - ctx->vertices[3][0][0] = x3; - ctx->vertices[3][0][1] = y3; - ctx->vertices[3][0][2] = z; - ctx->vertices[3][1][0] = s0; - ctx->vertices[3][1][1] = t1; - - return pipe_user_buffer_create( ctx->pipe->screen, - ctx->vertices, - sizeof(ctx->vertices), - PIPE_BIND_VERTEX_BUFFER); + struct pipe_screen *screen = renderer->pipe->screen; + + return screen->is_format_supported(screen, + res->format, res->target, 0, bindings, 0); } -struct renderer * renderer_create(struct vg_context *owner) +/** + * Set the model-view-projection matrix used by vertex shaders. + */ +static void renderer_set_mvp(struct renderer *renderer, + const struct matrix *mvp) { + struct matrix *cur = &renderer->mvp; + struct pipe_resource *cbuf; + VGfloat consts[3][4]; VGint i; - struct renderer *renderer = CALLOC_STRUCT(renderer); - if (!renderer) + /* projection only */ + if (!mvp) + mvp = &renderer->projection; + + /* re-upload only if necessary */ + if (memcmp(cur, mvp, sizeof(*mvp)) == 0) + return; + + /* 3x3 matrix to 3 constant vectors (no Z) */ + for (i = 0; i < 3; i++) { + consts[i][0] = mvp->m[i + 0]; + consts[i][1] = mvp->m[i + 3]; + consts[i][2] = 0.0f; + consts[i][3] = mvp->m[i + 6]; + } + + cbuf = renderer->vs_cbuf; + pipe_resource_reference(&cbuf, NULL); + cbuf = pipe_buffer_create(renderer->pipe->screen, + PIPE_BIND_CONSTANT_BUFFER, + sizeof(consts)); + if (cbuf) { + pipe_buffer_write(renderer->pipe, cbuf, + 0, sizeof(consts), consts); + } + renderer->pipe->set_constant_buffer(renderer->pipe, + PIPE_SHADER_VERTEX, 0, cbuf); + + memcpy(cur, mvp, sizeof(*mvp)); + renderer->vs_cbuf = cbuf; +} + +/** + * Create a simple vertex shader that passes through position and the given + * attribute. + */ +static void *create_passthrough_vs(struct pipe_context *pipe, int semantic_name) +{ + struct ureg_program *ureg; + struct ureg_src src[2], constants[3]; + struct ureg_dst dst[2], tmp; + int i; + + ureg = ureg_create(TGSI_PROCESSOR_VERTEX); + if (!ureg) return NULL; - renderer->owner = owner; - renderer->pipe = owner->pipe; - renderer->cso = owner->cso_context; + /* position is in user coordinates */ + src[0] = ureg_DECL_vs_input(ureg, 0); + dst[0] = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); + tmp = ureg_DECL_temporary(ureg); + for (i = 0; i < Elements(constants); i++) + constants[i] = ureg_DECL_constant(ureg, i); + + /* transform to clipped coordinates */ + ureg_DP4(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), src[0], constants[0]); + ureg_DP4(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), src[0], constants[1]); + ureg_MOV(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Z), src[0]); + ureg_DP4(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_W), src[0], constants[2]); + ureg_MOV(ureg, dst[0], ureg_src(tmp)); + + if (semantic_name >= 0) { + src[1] = ureg_DECL_vs_input(ureg, 1); + dst[1] = ureg_DECL_output(ureg, semantic_name, 0); + ureg_MOV(ureg, dst[1], src[1]); + } - setup_shaders(renderer); + ureg_END(ureg); - /* init vertex data that doesn't change */ - for (i = 0; i < 4; i++) { - renderer->vertices[i][0][3] = 1.0f; /* w */ - renderer->vertices[i][1][2] = 0.0f; /* r */ - renderer->vertices[i][1][3] = 1.0f; /* q */ + return ureg_create_shader_and_destroy(ureg, pipe); +} + +/** + * Set renderer vertex shader. + * + * This function modifies vertex_shader state. + */ +static void renderer_set_vs(struct renderer *r, RendererVs id) +{ + /* create as needed */ + if (!r->cached_vs[id]) { + int semantic_name = -1; + + switch (id) { + case RENDERER_VS_PLAIN: + break; + case RENDERER_VS_COLOR: + semantic_name = TGSI_SEMANTIC_COLOR; + break; + case RENDERER_VS_TEXTURE: + semantic_name = TGSI_SEMANTIC_GENERIC; + break; + default: + assert(!"Unknown renderer vs id"); + break; + } + + r->cached_vs[id] = create_passthrough_vs(r->pipe, semantic_name); } - return renderer; + cso_set_vertex_shader_handle(r->cso, r->cached_vs[id]); } -void renderer_destroy(struct renderer *ctx) +/** + * Create a simple fragment shader that sets the depth to 0.0f. + */ +static void *create_scissor_fs(struct pipe_context *pipe) +{ + struct ureg_program *ureg; + struct ureg_dst out; + struct ureg_src imm; + + ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); + out = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); + imm = ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 0.0f); + + ureg_MOV(ureg, ureg_writemask(out, TGSI_WRITEMASK_Z), imm); + ureg_END(ureg); + + return ureg_create_shader_and_destroy(ureg, pipe); +} + +/** + * Create a simple fragment shader that sets the color to white. + */ +static void *create_white_fs(struct pipe_context *pipe) +{ + struct ureg_program *ureg; + struct ureg_dst out; + struct ureg_src imm; + + ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); + out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); + imm = ureg_imm4f(ureg, 1.0f, 1.0f, 1.0f, 1.0f); + + ureg_MOV(ureg, out, imm); + ureg_END(ureg); + + return ureg_create_shader_and_destroy(ureg, pipe); +} + +/** + * Set renderer fragment shader. + * + * This function modifies fragment_shader state. + */ +static void renderer_set_fs(struct renderer *r, RendererFs id) { -#if 0 - if (ctx->fs) { - cso_delete_fragment_shader(ctx->cso, ctx->fs); - ctx->fs = NULL; + /* create as needed */ + if (!r->cached_fs[id]) { + void *fs = NULL; + + switch (id) { + case RENDERER_FS_COLOR: + fs = util_make_fragment_passthrough_shader(r->pipe); + break; + case RENDERER_FS_TEXTURE: + fs = util_make_fragment_tex_shader(r->pipe, + TGSI_TEXTURE_2D, TGSI_INTERPOLATE_LINEAR); + break; + case RENDERER_FS_SCISSOR: + fs = create_scissor_fs(r->pipe); + break; + case RENDERER_FS_WHITE: + fs = create_white_fs(r->pipe); + break; + default: + assert(!"Unknown renderer fs id"); + break; + } + + r->cached_fs[id] = fs; } -#endif - FREE(ctx); + + cso_set_fragment_shader_handle(r->cso, r->cached_fs[id]); } -void renderer_draw_quad(struct renderer *r, - VGfloat x1, VGfloat y1, - VGfloat x2, VGfloat y2, - VGfloat depth) +typedef enum { + VEGA_Y0_TOP, + VEGA_Y0_BOTTOM +} VegaOrientation; + +static void vg_set_viewport(struct renderer *r, + VegaOrientation orientation) { - struct pipe_resource *buf; + const struct pipe_framebuffer_state *fb = &r->g3d.fb; + struct pipe_viewport_state viewport; + VGfloat y_scale = (orientation == VEGA_Y0_BOTTOM) ? -2.f : 2.f; + + viewport.scale[0] = fb->width / 2.f; + viewport.scale[1] = fb->height / y_scale; + viewport.scale[2] = 1.0; + viewport.scale[3] = 1.0; + viewport.translate[0] = fb->width / 2.f; + viewport.translate[1] = fb->height / 2.f; + viewport.translate[2] = 0.0; + viewport.translate[3] = 0.0; + + cso_set_viewport(r->cso, &viewport); +} + +/** + * Set renderer target. + * + * This function modifies framebuffer and viewport states. + */ +static void renderer_set_target(struct renderer *r, + struct pipe_surface *cbuf, + struct pipe_surface *zsbuf, + VGboolean y0_top) +{ + struct pipe_framebuffer_state fb; + + memset(&fb, 0, sizeof(fb)); + fb.width = cbuf->width; + fb.height = cbuf->height; + fb.cbufs[0] = cbuf; + fb.nr_cbufs = 1; + fb.zsbuf = zsbuf; + cso_set_framebuffer(r->cso, &fb); + + vg_set_viewport(r, (y0_top) ? VEGA_Y0_TOP : VEGA_Y0_BOTTOM); +} + +/** + * Set renderer blend state. Blending is disabled. + * + * This function modifies blend state. + */ +static void renderer_set_blend(struct renderer *r, + VGbitfield channel_mask) +{ + struct pipe_blend_state blend; + + memset(&blend, 0, sizeof(blend)); + + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + + if (channel_mask & VG_RED) + blend.rt[0].colormask |= PIPE_MASK_R; + if (channel_mask & VG_GREEN) + blend.rt[0].colormask |= PIPE_MASK_G; + if (channel_mask & VG_BLUE) + blend.rt[0].colormask |= PIPE_MASK_B; + if (channel_mask & VG_ALPHA) + blend.rt[0].colormask |= PIPE_MASK_A; + + cso_set_blend(r->cso, &blend); +} + +/** + * Set renderer sampler and view states. + * + * This function modifies samplers and fragment_sampler_views states. + */ +static void renderer_set_samplers(struct renderer *r, + uint num_views, + struct pipe_sampler_view **views) +{ + struct pipe_sampler_state sampler; + unsigned tex_filter = PIPE_TEX_FILTER_NEAREST; + unsigned tex_wrap = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + uint i; + + memset(&sampler, 0, sizeof(sampler)); + + sampler.min_img_filter = tex_filter; + sampler.mag_img_filter = tex_filter; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + + sampler.wrap_s = tex_wrap; + sampler.wrap_t = tex_wrap; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + + sampler.normalized_coords = 1; + + /* set samplers */ + for (i = 0; i < num_views; i++) + cso_single_sampler(r->cso, i, &sampler); + cso_single_sampler_done(r->cso); + + /* set views */ + cso_set_fragment_sampler_views(r->cso, num_views, views); +} + +/** + * Set custom renderer fragment shader, and optionally set samplers and views + * and upload the fragment constant buffer. + * + * This function modifies fragment_shader, samplers and fragment_sampler_views + * states. + */ +static void renderer_set_custom_fs(struct renderer *renderer, + void *fs, + const struct pipe_sampler_state **samplers, + struct pipe_sampler_view **views, + VGint num_samplers, + const void *const_buffer, + VGint const_buffer_len) +{ + cso_set_fragment_shader_handle(renderer->cso, fs); + + /* set samplers and views */ + if (num_samplers) { + cso_set_samplers(renderer->cso, num_samplers, samplers); + cso_set_fragment_sampler_views(renderer->cso, num_samplers, views); + } + + /* upload fs constant buffer */ + if (const_buffer_len) { + struct pipe_resource *cbuf = renderer->fs_cbuf; + + if (!cbuf || renderer->fs_cbuf_len != const_buffer_len || + memcmp(renderer->fs_cbuf_data, const_buffer, const_buffer_len)) { + pipe_resource_reference(&cbuf, NULL); + + cbuf = pipe_buffer_create(renderer->pipe->screen, + PIPE_BIND_CONSTANT_BUFFER, const_buffer_len); + pipe_buffer_write(renderer->pipe, cbuf, 0, + const_buffer_len, const_buffer); + renderer->pipe->set_constant_buffer(renderer->pipe, + PIPE_SHADER_FRAGMENT, 0, cbuf); + + renderer->fs_cbuf = cbuf; + if (const_buffer_len <= sizeof(renderer->fs_cbuf_data)) { + memcpy(renderer->fs_cbuf_data, const_buffer, const_buffer_len); + renderer->fs_cbuf_len = const_buffer_len; + } + else { + renderer->fs_cbuf_len = 0; + } + } + } +} + +/** + * Setup renderer quad position. + */ +static void renderer_quad_pos(struct renderer *r, + VGfloat x0, VGfloat y0, + VGfloat x1, VGfloat y1, + VGboolean scissor) +{ + VGfloat z; + + /* the depth test is used for scissoring */ + z = (scissor) ? 0.0f : 1.0f; + + /* positions */ + r->vertices[0][0][0] = x0; + r->vertices[0][0][1] = y0; + r->vertices[0][0][2] = z; - buf = setup_vertex_data(r, x1, y1, x2, y2, depth); + r->vertices[1][0][0] = x1; + r->vertices[1][0][1] = y0; + r->vertices[1][0][2] = z; + r->vertices[2][0][0] = x1; + r->vertices[2][0][1] = y1; + r->vertices[2][0][2] = z; + + r->vertices[3][0][0] = x0; + r->vertices[3][0][1] = y1; + r->vertices[3][0][2] = z; +} + +/** + * Setup renderer quad texture coordinates. + */ +static void renderer_quad_texcoord(struct renderer *r, + VGfloat x0, VGfloat y0, + VGfloat x1, VGfloat y1, + VGint tex_width, VGint tex_height) +{ + VGfloat s0, t0, s1, t1, r0, q0; + VGint i; + + s0 = x0 / tex_width; + s1 = x1 / tex_width; + t0 = y0 / tex_height; + t1 = y1 / tex_height; + r0 = 0.0f; + q0 = 1.0f; + + /* texcoords */ + r->vertices[0][1][0] = s0; + r->vertices[0][1][1] = t0; + + r->vertices[1][1][0] = s1; + r->vertices[1][1][1] = t0; + + r->vertices[2][1][0] = s1; + r->vertices[2][1][1] = t1; + + r->vertices[3][1][0] = s0; + r->vertices[3][1][1] = t1; + + for (i = 0; i < 4; i++) { + r->vertices[i][1][2] = r0; + r->vertices[i][1][3] = q0; + } +} + +/** + * Draw renderer quad. + */ +static void renderer_quad_draw(struct renderer *r) +{ + struct pipe_resource *buf; + + buf = pipe_user_buffer_create(r->pipe->screen, + r->vertices, + sizeof(r->vertices), + PIPE_BIND_VERTEX_BUFFER); if (buf) { - cso_set_vertex_elements(r->cso, 2, r->owner->velems); util_draw_vertex_buffer(r->pipe, buf, 0, PIPE_PRIM_TRIANGLE_FAN, - 4, /* verts */ - 2); /* attribs/vert */ + Elements(r->vertices), /* verts */ + Elements(r->vertices[0])); /* attribs/vert */ - pipe_resource_reference( &buf, - NULL ); + pipe_resource_reference(&buf, NULL); } } -void renderer_draw_texture(struct renderer *r, - struct pipe_resource *tex, - VGfloat x1offset, VGfloat y1offset, - VGfloat x2offset, VGfloat y2offset, - VGfloat x1, VGfloat y1, - VGfloat x2, VGfloat y2) +/** + * Prepare the renderer for copying. + */ +VGboolean renderer_copy_begin(struct renderer *renderer, + struct pipe_surface *dst, + VGboolean y0_top, + struct pipe_sampler_view *src) { - struct pipe_context *pipe = r->pipe; - struct pipe_resource *buf; - VGfloat s0, t0, s1, t1; + assert(renderer->state == RENDERER_STATE_INIT); - assert(tex->width0 != 0); - assert(tex->height0 != 0); + /* sanity check */ + if (!renderer_can_support(renderer, + dst->texture, PIPE_BIND_RENDER_TARGET) || + !renderer_can_support(renderer, + src->texture, PIPE_BIND_SAMPLER_VIEW)) + return VG_FALSE; - s0 = x1offset / tex->width0; - s1 = x2offset / tex->width0; - t0 = y1offset / tex->height0; - t1 = y2offset / tex->height0; + cso_save_framebuffer(renderer->cso); + cso_save_viewport(renderer->cso); + cso_save_blend(renderer->cso); + cso_save_samplers(renderer->cso); + cso_save_fragment_sampler_views(renderer->cso); + cso_save_fragment_shader(renderer->cso); + cso_save_vertex_shader(renderer->cso); - cso_save_vertex_shader(r->cso); - /* shaders */ - cso_set_vertex_shader_handle(r->cso, vg_texture_vs(r->owner)); + renderer_set_target(renderer, dst, NULL, y0_top); - /* draw quad */ - buf = setup_vertex_data_tex(r, x1, y1, x2, y2, - s0, t0, s1, t1, 0.0f); + renderer_set_blend(renderer, ~0); + renderer_set_samplers(renderer, 1, &src); - if (buf) { - cso_set_vertex_elements(r->cso, 2, r->owner->velems); - util_draw_vertex_buffer(pipe, buf, 0, - PIPE_PRIM_TRIANGLE_FAN, - 4, /* verts */ - 2); /* attribs/vert */ - - pipe_resource_reference( &buf, - NULL ); + renderer_set_fs(renderer, RENDERER_FS_TEXTURE); + renderer_set_vs(renderer, RENDERER_VS_TEXTURE); + + renderer_set_mvp(renderer, NULL); + + /* remember the texture size */ + renderer->u.copy.tex_width = src->texture->width0; + renderer->u.copy.tex_height = src->texture->height0; + renderer->state = RENDERER_STATE_COPY; + + return VG_TRUE; +} + +/** + * Draw into the destination rectangle given by (x, y, w, h). The texture is + * sampled from within the rectangle given by (sx, sy, sw, sh). + * + * The coordinates are in surface coordinates. + */ +void renderer_copy(struct renderer *renderer, + VGint x, VGint y, VGint w, VGint h, + VGint sx, VGint sy, VGint sw, VGint sh) +{ + assert(renderer->state == RENDERER_STATE_COPY); + + /* there is no depth buffer for scissoring anyway */ + renderer_quad_pos(renderer, x, y, x + w, y + h, VG_FALSE); + renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh, + renderer->u.copy.tex_width, + renderer->u.copy.tex_height); + + renderer_quad_draw(renderer); +} + +/** + * End copying and restore the states. + */ +void renderer_copy_end(struct renderer *renderer) +{ + assert(renderer->state == RENDERER_STATE_COPY); + + cso_restore_framebuffer(renderer->cso); + cso_restore_viewport(renderer->cso); + cso_restore_blend(renderer->cso); + cso_restore_samplers(renderer->cso); + cso_restore_fragment_sampler_views(renderer->cso); + cso_restore_fragment_shader(renderer->cso); + cso_restore_vertex_shader(renderer->cso); + + renderer->state = RENDERER_STATE_INIT; +} + +/** + * Prepare the renderer for textured drawing. + */ +VGboolean renderer_drawtex_begin(struct renderer *renderer, + struct pipe_sampler_view *src) +{ + assert(renderer->state == RENDERER_STATE_INIT); + + if (!renderer_can_support(renderer, src->texture, PIPE_BIND_SAMPLER_VIEW)) + return VG_FALSE; + + cso_save_blend(renderer->cso); + cso_save_samplers(renderer->cso); + cso_save_fragment_sampler_views(renderer->cso); + cso_save_fragment_shader(renderer->cso); + cso_save_vertex_shader(renderer->cso); + + renderer_set_blend(renderer, ~0); + + renderer_set_samplers(renderer, 1, &src); + + renderer_set_fs(renderer, RENDERER_FS_TEXTURE); + renderer_set_vs(renderer, RENDERER_VS_TEXTURE); + + renderer_set_mvp(renderer, NULL); + + /* remember the texture size */ + renderer->u.drawtex.tex_width = src->texture->width0; + renderer->u.drawtex.tex_height = src->texture->height0; + renderer->state = RENDERER_STATE_DRAWTEX; + + return VG_TRUE; +} + +/** + * Draw into the destination rectangle given by (x, y, w, h). The texture is + * sampled from within the rectangle given by (sx, sy, sw, sh). + * + * The coordinates are in surface coordinates. + */ +void renderer_drawtex(struct renderer *renderer, + VGint x, VGint y, VGint w, VGint h, + VGint sx, VGint sy, VGint sw, VGint sh) +{ + assert(renderer->state == RENDERER_STATE_DRAWTEX); + + /* with scissoring */ + renderer_quad_pos(renderer, x, y, x + w, y + h, VG_TRUE); + renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh, + renderer->u.drawtex.tex_width, + renderer->u.drawtex.tex_height); + + renderer_quad_draw(renderer); +} + +/** + * End textured drawing and restore the states. + */ +void renderer_drawtex_end(struct renderer *renderer) +{ + assert(renderer->state == RENDERER_STATE_DRAWTEX); + + cso_restore_blend(renderer->cso); + cso_restore_samplers(renderer->cso); + cso_restore_fragment_sampler_views(renderer->cso); + cso_restore_fragment_shader(renderer->cso); + cso_restore_vertex_shader(renderer->cso); + + renderer->state = RENDERER_STATE_INIT; +} + +/** + * Prepare the renderer for scissor update. This will reset the depth buffer + * to 1.0f. + */ +VGboolean renderer_scissor_begin(struct renderer *renderer, + VGboolean restore_dsa) +{ + struct pipe_depth_stencil_alpha_state dsa; + + assert(renderer->state == RENDERER_STATE_INIT); + + if (restore_dsa) + cso_save_depth_stencil_alpha(renderer->cso); + cso_save_blend(renderer->cso); + cso_save_fragment_shader(renderer->cso); + + /* enable depth writes */ + memset(&dsa, 0, sizeof(dsa)); + dsa.depth.enabled = 1; + dsa.depth.writemask = 1; + dsa.depth.func = PIPE_FUNC_ALWAYS; + cso_set_depth_stencil_alpha(renderer->cso, &dsa); + + /* disable color writes */ + renderer_set_blend(renderer, 0); + renderer_set_fs(renderer, RENDERER_FS_SCISSOR); + + renderer_set_mvp(renderer, NULL); + + renderer->u.scissor.restore_dsa = restore_dsa; + renderer->state = RENDERER_STATE_SCISSOR; + + /* clear the depth buffer to 1.0f */ + renderer->pipe->clear(renderer->pipe, + PIPE_CLEAR_DEPTHSTENCIL, NULL, 1.0f, 0); + + return VG_TRUE; +} + +/** + * Add a scissor rectangle. Depth values inside the rectangle will be set to + * 0.0f. + */ +void renderer_scissor(struct renderer *renderer, + VGint x, VGint y, VGint width, VGint height) +{ + assert(renderer->state == RENDERER_STATE_SCISSOR); + + renderer_quad_pos(renderer, x, y, x + width, y + height, VG_FALSE); + renderer_quad_draw(renderer); +} + +/** + * End scissor update and restore the states. + */ +void renderer_scissor_end(struct renderer *renderer) +{ + assert(renderer->state == RENDERER_STATE_SCISSOR); + + if (renderer->u.scissor.restore_dsa) + cso_restore_depth_stencil_alpha(renderer->cso); + cso_restore_blend(renderer->cso); + cso_restore_fragment_shader(renderer->cso); + + renderer->state = RENDERER_STATE_INIT; +} + +/** + * Prepare the renderer for clearing. + */ +VGboolean renderer_clear_begin(struct renderer *renderer) +{ + assert(renderer->state == RENDERER_STATE_INIT); + + cso_save_blend(renderer->cso); + cso_save_fragment_shader(renderer->cso); + cso_save_vertex_shader(renderer->cso); + + renderer_set_blend(renderer, ~0); + renderer_set_fs(renderer, RENDERER_FS_COLOR); + renderer_set_vs(renderer, RENDERER_VS_COLOR); + + renderer_set_mvp(renderer, NULL); + + renderer->state = RENDERER_STATE_CLEAR; + + return VG_TRUE; +} + +/** + * Clear the framebuffer with the specified region and color. + * + * The coordinates are in surface coordinates. + */ +void renderer_clear(struct renderer *renderer, + VGint x, VGint y, VGint width, VGint height, + const VGfloat color[4]) +{ + VGuint i; + + assert(renderer->state == RENDERER_STATE_CLEAR); + + renderer_quad_pos(renderer, x, y, x + width, y + height, VG_TRUE); + for (i = 0; i < 4; i++) + memcpy(renderer->vertices[i][1], color, sizeof(VGfloat) * 4); + + renderer_quad_draw(renderer); +} + +/** + * End clearing and retore the states. + */ +void renderer_clear_end(struct renderer *renderer) +{ + assert(renderer->state == RENDERER_STATE_CLEAR); + + cso_restore_blend(renderer->cso); + cso_restore_fragment_shader(renderer->cso); + cso_restore_vertex_shader(renderer->cso); + + renderer->state = RENDERER_STATE_INIT; +} + +/** + * Prepare the renderer for image filtering. + */ +VGboolean renderer_filter_begin(struct renderer *renderer, + struct pipe_resource *dst, + VGboolean y0_top, + VGbitfield channel_mask, + const struct pipe_sampler_state **samplers, + struct pipe_sampler_view **views, + VGint num_samplers, + void *fs, + const void *const_buffer, + VGint const_buffer_len) +{ + struct pipe_surface *surf, surf_tmpl; + + assert(renderer->state == RENDERER_STATE_INIT); + + if (!fs) + return VG_FALSE; + if (!renderer_can_support(renderer, dst, PIPE_BIND_RENDER_TARGET)) + return VG_FALSE; + + u_surface_default_template(&surf_tmpl, dst, + PIPE_BIND_RENDER_TARGET); + surf = renderer->pipe->create_surface(renderer->pipe, dst, &surf_tmpl); + if (!surf) + return VG_FALSE; + + cso_save_framebuffer(renderer->cso); + cso_save_viewport(renderer->cso); + cso_save_blend(renderer->cso); + + /* set the image as the target */ + renderer_set_target(renderer, surf, NULL, y0_top); + pipe_surface_reference(&surf, NULL); + + renderer_set_blend(renderer, channel_mask); + + if (num_samplers) { + struct pipe_resource *tex; + + cso_save_samplers(renderer->cso); + cso_save_fragment_sampler_views(renderer->cso); + cso_save_fragment_shader(renderer->cso); + cso_save_vertex_shader(renderer->cso); + + renderer_set_custom_fs(renderer, fs, + samplers, views, num_samplers, + const_buffer, const_buffer_len); + renderer_set_vs(renderer, RENDERER_VS_TEXTURE); + + tex = views[0]->texture; + renderer->u.filter.tex_width = tex->width0; + renderer->u.filter.tex_height = tex->height0; + renderer->u.filter.use_sampler = VG_TRUE; } + else { + cso_save_fragment_shader(renderer->cso); - cso_restore_vertex_shader(r->cso); + renderer_set_custom_fs(renderer, fs, NULL, NULL, 0, + const_buffer, const_buffer_len); + + renderer->u.filter.use_sampler = VG_FALSE; + } + + renderer_set_mvp(renderer, NULL); + + renderer->state = RENDERER_STATE_FILTER; + + return VG_TRUE; } -void renderer_copy_texture(struct renderer *ctx, - struct pipe_sampler_view *src, - VGfloat sx1, VGfloat sy1, - VGfloat sx2, VGfloat sy2, - struct pipe_resource *dst, - VGfloat dx1, VGfloat dy1, - VGfloat dx2, VGfloat dy2) +/** + * Draw into a rectangle of the destination with the specified region of the + * texture(s). + * + * The coordinates are in surface coordinates. + */ +void renderer_filter(struct renderer *renderer, + VGint x, VGint y, VGint w, VGint h, + VGint sx, VGint sy, VGint sw, VGint sh) { - struct pipe_context *pipe = ctx->pipe; - struct pipe_screen *screen = pipe->screen; - struct pipe_resource *tex = src->texture; - struct pipe_resource *buf; - struct pipe_surface *dst_surf = screen->get_tex_surface( - screen, dst, 0, 0, 0, - PIPE_BIND_RENDER_TARGET); - struct pipe_framebuffer_state fb; - float s0, t0, s1, t1; + assert(renderer->state == RENDERER_STATE_FILTER); - assert(tex->width0 != 0); - assert(tex->height0 != 0); - assert(dst->width0 != 0); - assert(dst->height0 != 0); - -#if 0 - debug_printf("copy texture [%f, %f, %f, %f], [%f, %f, %f, %f]\n", - sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); -#endif - -#if 1 - s0 = sx1 / tex->width0; - s1 = sx2 / tex->width0; - t0 = sy1 / tex->height0; - t1 = sy2 / tex->height0; -#else - s0 = 0; - s1 = 1; - t0 = 0; - t1 = 1; -#endif - - assert(screen->is_format_supported(screen, dst_surf->format, PIPE_TEXTURE_2D, - 0, PIPE_BIND_RENDER_TARGET, 0)); + renderer_quad_pos(renderer, x, y, x + w, y + h, VG_FALSE); + if (renderer->u.filter.use_sampler) { + renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh, + renderer->u.filter.tex_width, + renderer->u.filter.tex_height); + } - /* save state (restored below) */ - cso_save_blend(ctx->cso); - cso_save_samplers(ctx->cso); - cso_save_fragment_sampler_views(ctx->cso); - cso_save_framebuffer(ctx->cso); - cso_save_fragment_shader(ctx->cso); - cso_save_vertex_shader(ctx->cso); + renderer_quad_draw(renderer); +} + +/** + * End image filtering and restore the states. + */ +void renderer_filter_end(struct renderer *renderer) +{ + assert(renderer->state == RENDERER_STATE_FILTER); - cso_save_viewport(ctx->cso); + if (renderer->u.filter.use_sampler) { + cso_restore_samplers(renderer->cso); + cso_restore_fragment_sampler_views(renderer->cso); + cso_restore_vertex_shader(renderer->cso); + } + cso_restore_framebuffer(renderer->cso); + cso_restore_viewport(renderer->cso); + cso_restore_blend(renderer->cso); + cso_restore_fragment_shader(renderer->cso); - /* set misc state we care about */ - { - struct pipe_blend_state blend; - memset(&blend, 0, sizeof(blend)); - blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; - blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; - blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; - blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; - blend.rt[0].colormask = PIPE_MASK_RGBA; - cso_set_blend(ctx->cso, &blend); + renderer->state = RENDERER_STATE_INIT; +} + +/** + * Prepare the renderer for polygon silhouette rendering. + */ +VGboolean renderer_polygon_stencil_begin(struct renderer *renderer, + struct pipe_vertex_element *velem, + VGFillRule rule, + VGboolean restore_dsa) +{ + struct pipe_depth_stencil_alpha_state *dsa; + VGboolean manual_two_sides; + + assert(renderer->state == RENDERER_STATE_INIT); + + cso_save_vertex_elements(renderer->cso); + cso_save_blend(renderer->cso); + cso_save_depth_stencil_alpha(renderer->cso); + + cso_set_vertex_elements(renderer->cso, 1, velem); + + /* disable color writes */ + renderer_set_blend(renderer, 0); + + manual_two_sides = VG_FALSE; + dsa = &renderer->u.polygon_stencil.dsa; + memset(dsa, 0, sizeof(*dsa)); + if (rule == VG_EVEN_ODD) { + dsa->stencil[0].enabled = 1; + dsa->stencil[0].writemask = 1; + dsa->stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; + dsa->stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa->stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT; + dsa->stencil[0].func = PIPE_FUNC_ALWAYS; + dsa->stencil[0].valuemask = ~0; } + else { + assert(rule == VG_NON_ZERO); + + /* front face */ + dsa->stencil[0].enabled = 1; + dsa->stencil[0].writemask = ~0; + dsa->stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; + dsa->stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa->stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; + dsa->stencil[0].func = PIPE_FUNC_ALWAYS; + dsa->stencil[0].valuemask = ~0; + + if (renderer->pipe->screen->get_param(renderer->pipe->screen, + PIPE_CAP_TWO_SIDED_STENCIL)) { + /* back face */ + dsa->stencil[1] = dsa->stencil[0]; + dsa->stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; + } + else { + manual_two_sides = VG_TRUE; + } + } + cso_set_depth_stencil_alpha(renderer->cso, dsa); + + if (manual_two_sides) + cso_save_rasterizer(renderer->cso); - /* sampler */ - { - struct pipe_sampler_state sampler; - memset(&sampler, 0, sizeof(sampler)); - sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; - sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; - sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; - sampler.normalized_coords = 1; - cso_single_sampler(ctx->cso, 0, &sampler); - cso_single_sampler_done(ctx->cso); + renderer->u.polygon_stencil.manual_two_sides = manual_two_sides; + renderer->u.polygon_stencil.restore_dsa = restore_dsa; + renderer->state = RENDERER_STATE_POLYGON_STENCIL; + + return VG_TRUE; +} + +/** + * Render a polygon silhouette to stencil buffer. + */ +void renderer_polygon_stencil(struct renderer *renderer, + struct pipe_vertex_buffer *vbuf, + VGuint mode, VGuint start, VGuint count) +{ + assert(renderer->state == RENDERER_STATE_POLYGON_STENCIL); + + renderer->pipe->set_vertex_buffers(renderer->pipe, 1, vbuf); + + if (!renderer->u.polygon_stencil.manual_two_sides) { + util_draw_arrays(renderer->pipe, mode, start, count); } + else { + struct pipe_rasterizer_state raster; + struct pipe_depth_stencil_alpha_state dsa; - vg_set_viewport(ctx->owner, VEGA_Y0_TOP); + raster = renderer->g3d.rasterizer; + dsa = renderer->u.polygon_stencil.dsa; - /* texture */ - cso_set_fragment_sampler_views(ctx->cso, 1, &src); + /* front */ + raster.cull_face = PIPE_FACE_BACK; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; - /* shaders */ - cso_set_vertex_shader_handle(ctx->cso, vg_texture_vs(ctx->owner)); - cso_set_fragment_shader_handle(ctx->cso, ctx->fs); + cso_set_rasterizer(renderer->cso, &raster); + cso_set_depth_stencil_alpha(renderer->cso, &dsa); + util_draw_arrays(renderer->pipe, mode, start, count); - /* drawing dest */ - memset(&fb, 0, sizeof(fb)); - fb.width = dst_surf->width; - fb.height = dst_surf->height; - fb.nr_cbufs = 1; - fb.cbufs[0] = dst_surf; - { - VGint i; - for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i) - fb.cbufs[i] = 0; + /* back */ + raster.cull_face = PIPE_FACE_FRONT; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; + + cso_set_rasterizer(renderer->cso, &raster); + cso_set_depth_stencil_alpha(renderer->cso, &dsa); + util_draw_arrays(renderer->pipe, mode, start, count); } - cso_set_framebuffer(ctx->cso, &fb); +} + +/** + * End polygon silhouette rendering. + */ +void renderer_polygon_stencil_end(struct renderer *renderer) +{ + assert(renderer->state == RENDERER_STATE_POLYGON_STENCIL); - /* draw quad */ - buf = setup_vertex_data_tex(ctx, - dx1, dy1, - dx2, dy2, - s0, t0, s1, t1, - 0.0f); + if (renderer->u.polygon_stencil.manual_two_sides) + cso_restore_rasterizer(renderer->cso); - if (buf) { - cso_set_vertex_elements(ctx->cso, 2, ctx->owner->velems); - util_draw_vertex_buffer(ctx->pipe, buf, 0, - PIPE_PRIM_TRIANGLE_FAN, - 4, /* verts */ - 2); /* attribs/vert */ + cso_restore_vertex_elements(renderer->cso); + + /* restore color writes */ + cso_restore_blend(renderer->cso); + + if (renderer->u.polygon_stencil.restore_dsa) + cso_restore_depth_stencil_alpha(renderer->cso); + + renderer->state = RENDERER_STATE_INIT; +} + +/** + * Prepare the renderer for polygon filling. + */ +VGboolean renderer_polygon_fill_begin(struct renderer *renderer, + VGboolean save_dsa) +{ + struct pipe_depth_stencil_alpha_state dsa; + + assert(renderer->state == RENDERER_STATE_INIT); + + if (save_dsa) + cso_save_depth_stencil_alpha(renderer->cso); + + /* setup stencil ops */ + memset(&dsa, 0, sizeof(dsa)); + dsa.stencil[0].enabled = 1; + dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL; + dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; + dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; + dsa.stencil[0].valuemask = ~0; + dsa.stencil[0].writemask = ~0; + dsa.depth = renderer->g3d.dsa.depth; + cso_set_depth_stencil_alpha(renderer->cso, &dsa); + + renderer->state = RENDERER_STATE_POLYGON_FILL; + + return VG_TRUE; +} + +/** + * Fill a polygon. + */ +void renderer_polygon_fill(struct renderer *renderer, + VGfloat min_x, VGfloat min_y, + VGfloat max_x, VGfloat max_y) +{ + assert(renderer->state == RENDERER_STATE_POLYGON_FILL); + + renderer_quad_pos(renderer, min_x, min_y, max_x, max_y, VG_TRUE); + renderer_quad_draw(renderer); +} + +/** + * End polygon filling. + */ +void renderer_polygon_fill_end(struct renderer *renderer) +{ + assert(renderer->state == RENDERER_STATE_POLYGON_FILL); + + cso_restore_depth_stencil_alpha(renderer->cso); - pipe_resource_reference( &buf, - NULL ); + renderer->state = RENDERER_STATE_INIT; +} + +struct renderer * renderer_create(struct vg_context *owner) +{ + struct renderer *renderer; + struct pipe_rasterizer_state *raster; + struct pipe_stencil_ref sr; + VGint i; + + renderer = CALLOC_STRUCT(renderer); + if (!renderer) + return NULL; + + renderer->pipe = owner->pipe; + renderer->cso = owner->cso_context; + + /* init vertex data that doesn't change */ + for (i = 0; i < 4; i++) + renderer->vertices[i][0][3] = 1.0f; /* w */ + + for (i = 0; i < 2; i++) { + renderer->velems[i].src_offset = i * 4 * sizeof(float); + renderer->velems[i].instance_divisor = 0; + renderer->velems[i].vertex_buffer_index = 0; + renderer->velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; + } + cso_set_vertex_elements(renderer->cso, 2, renderer->velems); + + /* GL rasterization rules */ + raster = &renderer->g3d.rasterizer; + memset(raster, 0, sizeof(*raster)); + raster->gl_rasterization_rules = 1; + cso_set_rasterizer(renderer->cso, raster); + + /* fixed at 0 */ + memset(&sr, 0, sizeof(sr)); + cso_set_stencil_ref(renderer->cso, &sr); + + renderer_set_vs(renderer, RENDERER_VS_PLAIN); + + renderer->state = RENDERER_STATE_INIT; + + return renderer; +} + +void renderer_destroy(struct renderer *ctx) +{ + int i; + + for (i = 0; i < NUM_RENDERER_VS; i++) { + if (ctx->cached_vs[i]) + cso_delete_vertex_shader(ctx->cso, ctx->cached_vs[i]); + } + for (i = 0; i < NUM_RENDERER_FS; i++) { + if (ctx->cached_fs[i]) + cso_delete_fragment_shader(ctx->cso, ctx->cached_fs[i]); + } + + pipe_resource_reference(&ctx->vs_cbuf, NULL); + pipe_resource_reference(&ctx->fs_cbuf, NULL); + + FREE(ctx); +} + +static void update_clip_state(struct renderer *renderer, + const struct vg_state *state) +{ + struct pipe_depth_stencil_alpha_state *dsa = &renderer->g3d.dsa; + + memset(dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); + + if (state->scissoring) { + struct pipe_framebuffer_state *fb = &renderer->g3d.fb; + int i; + + renderer_scissor_begin(renderer, VG_FALSE); + + for (i = 0; i < state->scissor_rects_num; ++i) { + const float x = state->scissor_rects[i * 4 + 0].f; + const float y = state->scissor_rects[i * 4 + 1].f; + const float width = state->scissor_rects[i * 4 + 2].f; + const float height = state->scissor_rects[i * 4 + 3].f; + VGint x0, y0, x1, y1, iw, ih; + + x0 = (VGint) x; + y0 = (VGint) y; + if (x0 < 0) + x0 = 0; + if (y0 < 0) + y0 = 0; + + /* note that x1 and y1 are exclusive */ + x1 = (VGint) ceilf(x + width); + y1 = (VGint) ceilf(y + height); + if (x1 > fb->width) + x1 = fb->width; + if (y1 > fb->height) + y1 = fb->height; + + iw = x1 - x0; + ih = y1 - y0; + if (iw > 0 && ih> 0 ) + renderer_scissor(renderer, x0, y0, iw, ih); + } + + renderer_scissor_end(renderer); + + dsa->depth.enabled = 1; /* glEnable(GL_DEPTH_TEST); */ + dsa->depth.writemask = 0;/*glDepthMask(FALSE);*/ + dsa->depth.func = PIPE_FUNC_GEQUAL; } +} + +static void renderer_validate_blend(struct renderer *renderer, + const struct vg_state *state, + enum pipe_format fb_format) +{ + struct pipe_blend_state blend; + + memset(&blend, 0, sizeof(blend)); + blend.rt[0].colormask = PIPE_MASK_RGBA; + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; - /* restore state we changed */ - cso_restore_blend(ctx->cso); - cso_restore_samplers(ctx->cso); - cso_restore_fragment_sampler_views(ctx->cso); - cso_restore_framebuffer(ctx->cso); - cso_restore_vertex_shader(ctx->cso); - cso_restore_fragment_shader(ctx->cso); - cso_restore_viewport(ctx->cso); + /* TODO alpha masking happens after blending? */ + + switch (state->blend_mode) { + case VG_BLEND_SRC: + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + break; + case VG_BLEND_SRC_OVER: + if (!util_format_has_alpha(fb_format)) { + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; + blend.rt[0].blend_enable = 1; + } + break; + case VG_BLEND_SRC_IN: + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_DST_ALPHA; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.rt[0].blend_enable = 1; + break; + case VG_BLEND_DST_IN: + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ZERO; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + blend.rt[0].blend_enable = 1; + break; + case VG_BLEND_DST_OVER: + case VG_BLEND_MULTIPLY: + case VG_BLEND_SCREEN: + case VG_BLEND_DARKEN: + case VG_BLEND_LIGHTEN: + case VG_BLEND_ADDITIVE: + /* need a shader */ + break; + default: + assert(!"not implemented blend mode"); + break; + } - pipe_surface_reference(&dst_surf, NULL); + cso_set_blend(renderer->cso, &blend); +} + +/** + * Propogate OpenVG state changes to the renderer. Only framebuffer, blending + * and scissoring states are relevant here. + */ +void renderer_validate(struct renderer *renderer, + VGbitfield dirty, + const struct st_framebuffer *stfb, + const struct vg_state *state) +{ + assert(renderer->state == RENDERER_STATE_INIT); + + dirty |= renderer->dirty; + renderer->dirty = 0; + + if (dirty & FRAMEBUFFER_DIRTY) { + struct pipe_framebuffer_state *fb = &renderer->g3d.fb; + struct matrix *proj = &renderer->projection; + + memset(fb, 0, sizeof(struct pipe_framebuffer_state)); + fb->width = stfb->width; + fb->height = stfb->height; + fb->nr_cbufs = 1; + fb->cbufs[0] = stfb->strb->surface; + fb->zsbuf = stfb->dsrb->surface; + + cso_set_framebuffer(renderer->cso, fb); + vg_set_viewport(renderer, VEGA_Y0_BOTTOM); + + matrix_load_identity(proj); + matrix_translate(proj, -1.0f, -1.0f); + matrix_scale(proj, 2.0f / fb->width, 2.0f / fb->height); + + /* we also got a new depth buffer */ + if (dirty & DEPTH_STENCIL_DIRTY) { + renderer->pipe->clear(renderer->pipe, + PIPE_CLEAR_DEPTHSTENCIL, NULL, 0.0, 0); + } + } + + /* must be last because it renders to the depth buffer*/ + if (dirty & DEPTH_STENCIL_DIRTY) { + update_clip_state(renderer, state); + cso_set_depth_stencil_alpha(renderer->cso, &renderer->g3d.dsa); + } + + if (dirty & BLEND_DIRTY) + renderer_validate_blend(renderer, state, stfb->strb->format); +} + +/** + * Prepare the renderer for OpenVG pipeline. + */ +void renderer_validate_for_shader(struct renderer *renderer, + const struct pipe_sampler_state **samplers, + struct pipe_sampler_view **views, + VGint num_samplers, + const struct matrix *modelview, + void *fs, + const void *const_buffer, + VGint const_buffer_len) +{ + struct matrix mvp = renderer->projection; + + /* will be used in POLYGON_STENCIL and POLYGON_FILL */ + matrix_mult(&mvp, modelview); + renderer_set_mvp(renderer, &mvp); + + renderer_set_custom_fs(renderer, fs, + samplers, views, num_samplers, + const_buffer, const_buffer_len); +} + +void renderer_validate_for_mask_rendering(struct renderer *renderer, + struct pipe_surface *dst, + const struct matrix *modelview) +{ + struct matrix mvp = renderer->projection; + + /* will be used in POLYGON_STENCIL and POLYGON_FILL */ + matrix_mult(&mvp, modelview); + renderer_set_mvp(renderer, &mvp); + + renderer_set_target(renderer, dst, renderer->g3d.fb.zsbuf, VG_FALSE); + renderer_set_blend(renderer, ~0); + renderer_set_fs(renderer, RENDERER_FS_WHITE); + + /* set internal dirty flags (hacky!) */ + renderer->dirty = FRAMEBUFFER_DIRTY | BLEND_DIRTY; } void renderer_copy_surface(struct renderer *ctx, @@ -409,13 +1429,11 @@ void renderer_copy_surface(struct renderer *ctx, { struct pipe_context *pipe = ctx->pipe; struct pipe_screen *screen = pipe->screen; - struct pipe_resource *buf; struct pipe_sampler_view view_templ; struct pipe_sampler_view *view; + struct pipe_box src_box; struct pipe_resource texTemp, *tex; - struct pipe_subresource subsrc, subdst; - struct pipe_framebuffer_state fb; - struct st_framebuffer *stfb = ctx->owner->draw_buffer; + const struct pipe_framebuffer_state *fb = &ctx->g3d.fb; const int srcW = abs(srcX1 - srcX0); const int srcH = abs(srcY1 - srcY0); const int srcLeft = MIN2(srcX0, srcX1); @@ -458,6 +1476,7 @@ void renderer_copy_surface(struct renderer *ctx, texTemp.width0 = srcW; texTemp.height0 = srcH; texTemp.depth0 = 1; + texTemp.array_size = 1; texTemp.bind = PIPE_BIND_SAMPLER_VIEW; tex = screen->resource_create(screen, &texTemp); @@ -470,100 +1489,35 @@ void renderer_copy_surface(struct renderer *ctx, if (!view) return; - subdst.face = 0; - subdst.level = 0; - subsrc.face = src->face; - subsrc.level = src->level; + u_box_2d_zslice(srcLeft, srcTop, src->u.tex.first_layer, srcW, srcH, &src_box); pipe->resource_copy_region(pipe, - tex, subdst, 0, 0, 0, /* dest */ - src->texture, subsrc, srcLeft, srcTop, src->zslice, /* src */ - srcW, srcH); /* size */ - - /* save state (restored below) */ - cso_save_blend(ctx->cso); - cso_save_samplers(ctx->cso); - cso_save_fragment_sampler_views(ctx->cso); - cso_save_framebuffer(ctx->cso); - cso_save_fragment_shader(ctx->cso); - cso_save_vertex_shader(ctx->cso); - cso_save_viewport(ctx->cso); - - /* set misc state we care about */ - { - struct pipe_blend_state blend; - memset(&blend, 0, sizeof(blend)); - blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; - blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; - blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; - blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; - blend.rt[0].colormask = PIPE_MASK_RGBA; - cso_set_blend(ctx->cso, &blend); + tex, 0, 0, 0, 0, /* dest */ + src->texture, 0, &src_box); + + assert(floatsEqual(z, 0.0f)); + + /* draw */ + if (fb->cbufs[0] == dst) { + /* transform back to surface coordinates */ + dstY0 = dst->height - dstY0; + dstY1 = dst->height - dstY1; + + if (renderer_drawtex_begin(ctx, view)) { + renderer_drawtex(ctx, + dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0, + 0, 0, view->texture->width0, view->texture->height0); + renderer_drawtex_end(ctx); + } } - - vg_set_viewport(ctx->owner, VEGA_Y0_TOP); - - /* sampler */ - { - struct pipe_sampler_state sampler; - memset(&sampler, 0, sizeof(sampler)); - sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; - sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; - sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; - sampler.normalized_coords = 1; - cso_single_sampler(ctx->cso, 0, &sampler); - cso_single_sampler_done(ctx->cso); - } - - /* texture */ - cso_set_fragment_sampler_views(ctx->cso, 1, &view); - - /* shaders */ - cso_set_fragment_shader_handle(ctx->cso, ctx->fs); - cso_set_vertex_shader_handle(ctx->cso, vg_texture_vs(ctx->owner)); - - /* drawing dest */ - if (stfb->strb->surface != dst) { - memset(&fb, 0, sizeof(fb)); - fb.width = dst->width; - fb.height = dst->height; - fb.nr_cbufs = 1; - fb.cbufs[0] = dst; - fb.zsbuf = stfb->dsrb->surface; - cso_set_framebuffer(ctx->cso, &fb); + else { + if (renderer_copy_begin(ctx, dst, VG_TRUE, view)) { + renderer_copy(ctx, + dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0, + 0, 0, view->texture->width0, view->texture->height0); + renderer_copy_end(ctx); + } } - - /* draw quad */ - buf = setup_vertex_data(ctx, - (float) dstX0, (float) dstY0, - (float) dstX1, (float) dstY1, z); - - if (buf) { - cso_set_vertex_elements(ctx->cso, 2, ctx->owner->velems); - util_draw_vertex_buffer(ctx->pipe, buf, 0, - PIPE_PRIM_TRIANGLE_FAN, - 4, /* verts */ - 2); /* attribs/vert */ - - pipe_resource_reference( &buf, - NULL ); - } - - - /* restore state we changed */ - cso_restore_blend(ctx->cso); - cso_restore_samplers(ctx->cso); - cso_restore_fragment_sampler_views(ctx->cso); - cso_restore_framebuffer(ctx->cso); - cso_restore_fragment_shader(ctx->cso); - cso_restore_vertex_shader(ctx->cso); - cso_restore_viewport(ctx->cso); - - pipe_resource_reference(&tex, NULL); - pipe_sampler_view_reference(&view, NULL); } void renderer_texture_quad(struct renderer *r, @@ -575,36 +1529,38 @@ void renderer_texture_quad(struct renderer *r, VGfloat x3, VGfloat y3, VGfloat x4, VGfloat y4) { - struct pipe_context *pipe = r->pipe; - struct pipe_resource *buf; - VGfloat s0, t0, s1, t1; + const VGfloat z = 0.0f; + assert(r->state == RENDERER_STATE_INIT); assert(tex->width0 != 0); assert(tex->height0 != 0); - s0 = x1offset / tex->width0; - s1 = x2offset / tex->width0; - t0 = y1offset / tex->height0; - t1 = y2offset / tex->height0; - cso_save_vertex_shader(r->cso); - /* shaders */ - cso_set_vertex_shader_handle(r->cso, vg_texture_vs(r->owner)); - /* draw quad */ - buf = setup_vertex_data_qtex(r, x1, y1, x2, y2, x3, y3, x4, y4, - s0, t0, s1, t1, 0.0f); + renderer_set_vs(r, RENDERER_VS_TEXTURE); - if (buf) { - cso_set_vertex_elements(r->cso, 2, r->owner->velems); - util_draw_vertex_buffer(pipe, buf, 0, - PIPE_PRIM_TRIANGLE_FAN, - 4, /* verts */ - 2); /* attribs/vert */ + /* manually set up positions */ + r->vertices[0][0][0] = x1; + r->vertices[0][0][1] = y1; + r->vertices[0][0][2] = z; - pipe_resource_reference(&buf, - NULL); - } + r->vertices[1][0][0] = x2; + r->vertices[1][0][1] = y2; + r->vertices[1][0][2] = z; + + r->vertices[2][0][0] = x3; + r->vertices[2][0][1] = y3; + r->vertices[2][0][2] = z; + + r->vertices[3][0][0] = x4; + r->vertices[3][0][1] = y4; + r->vertices[3][0][2] = z; + + /* texcoords */ + renderer_quad_texcoord(r, x1offset, y1offset, + x2offset, y2offset, tex->width0, tex->height0); + + renderer_quad_draw(r); cso_restore_vertex_shader(r->cso); } diff --git a/src/gallium/state_trackers/vega/renderer.h b/src/gallium/state_trackers/vega/renderer.h index b1a9fb58be6..fe719936580 100644 --- a/src/gallium/state_trackers/vega/renderer.h +++ b/src/gallium/state_trackers/vega/renderer.h @@ -1,6 +1,7 @@ /************************************************************************** * * Copyright 2009 VMware, Inc. All Rights Reserved. + * Copyright 2010 LunarG, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -32,23 +33,110 @@ struct renderer; struct vg_context; +struct vg_state; +struct st_framebuffer; struct pipe_resource; +struct pipe_sampler_state; struct pipe_sampler_view; struct pipe_surface; +struct pipe_vertex_element; +struct pipe_vertex_buffer; +struct matrix; struct renderer *renderer_create(struct vg_context *owner); void renderer_destroy(struct renderer *); -void renderer_draw_quad(struct renderer *, - VGfloat x1, VGfloat y1, - VGfloat x2, VGfloat y2, - VGfloat depth); -void renderer_draw_texture(struct renderer *, - struct pipe_resource *texture, - VGfloat x1offset, VGfloat y1offset, - VGfloat x2offset, VGfloat y2offset, - VGfloat x1, VGfloat y1, - VGfloat x2, VGfloat y2); +void renderer_validate(struct renderer *renderer, + VGbitfield dirty, + const struct st_framebuffer *stfb, + const struct vg_state *state); + +void renderer_validate_for_shader(struct renderer *renderer, + const struct pipe_sampler_state **samplers, + struct pipe_sampler_view **views, + VGint num_samplers, + const struct matrix *modelview, + void *fs, + const void *const_buffer, + VGint const_buffer_len); + +void renderer_validate_for_mask_rendering(struct renderer *renderer, + struct pipe_surface *dst, + const struct matrix *modelview); + +VGboolean renderer_copy_begin(struct renderer *renderer, + struct pipe_surface *dst, + VGboolean y0_top, + struct pipe_sampler_view *src); + +void renderer_copy(struct renderer *renderer, + VGint x, VGint y, VGint w, VGint h, + VGint sx, VGint sy, VGint sw, VGint sh); + +void renderer_copy_end(struct renderer *renderer); + +VGboolean renderer_drawtex_begin(struct renderer *renderer, + struct pipe_sampler_view *src); + +void renderer_drawtex(struct renderer *renderer, + VGint x, VGint y, VGint w, VGint h, + VGint sx, VGint sy, VGint sw, VGint sh); + +void renderer_drawtex_end(struct renderer *renderer); + +VGboolean renderer_scissor_begin(struct renderer *renderer, + VGboolean restore_dsa); + +void renderer_scissor(struct renderer *renderer, + VGint x, VGint y, VGint width, VGint height); + +void renderer_scissor_end(struct renderer *renderer); + +VGboolean renderer_clear_begin(struct renderer *renderer); + +void renderer_clear(struct renderer *renderer, + VGint x, VGint y, VGint width, VGint height, + const VGfloat color[4]); + +void renderer_clear_end(struct renderer *renderer); + +VGboolean renderer_filter_begin(struct renderer *renderer, + struct pipe_resource *dst, + VGboolean y0_top, + VGbitfield channel_mask, + const struct pipe_sampler_state **samplers, + struct pipe_sampler_view **views, + VGint num_samplers, + void *fs, + const void *const_buffer, + VGint const_buffer_len); + +void renderer_filter(struct renderer *renderer, + VGint x, VGint y, VGint w, VGint h, + VGint sx, VGint sy, VGint sw, VGint sh); + +void renderer_filter_end(struct renderer *renderer); + +VGboolean renderer_polygon_stencil_begin(struct renderer *renderer, + struct pipe_vertex_element *velem, + VGFillRule rule, + VGboolean restore_dsa); + +void renderer_polygon_stencil(struct renderer *renderer, + struct pipe_vertex_buffer *vbuf, + VGuint mode, VGuint start, VGuint count); + +void renderer_polygon_stencil_end(struct renderer *renderer); + +VGboolean renderer_polygon_fill_begin(struct renderer *renderer, + VGboolean save_dsa); + +void renderer_polygon_fill(struct renderer *renderer, + VGfloat min_x, VGfloat min_y, + VGfloat max_x, VGfloat max_y); + +void renderer_polygon_fill_end(struct renderer *renderer); + void renderer_texture_quad(struct renderer *, struct pipe_resource *texture, VGfloat x1offset, VGfloat y1offset, @@ -57,13 +145,7 @@ void renderer_texture_quad(struct renderer *, VGfloat x2, VGfloat y2, VGfloat x3, VGfloat y3, VGfloat x4, VGfloat y4); -void renderer_copy_texture(struct renderer *r, - struct pipe_sampler_view *src, - VGfloat sx1, VGfloat sy1, - VGfloat sx2, VGfloat sy2, - struct pipe_resource *dst, - VGfloat dx1, VGfloat dy1, - VGfloat dx2, VGfloat dy2); + void renderer_copy_surface(struct renderer *r, struct pipe_surface *src, int sx1, int sy1, diff --git a/src/gallium/state_trackers/vega/shader.c b/src/gallium/state_trackers/vega/shader.c index eab1349639c..0ed721376cf 100644 --- a/src/gallium/state_trackers/vega/shader.c +++ b/src/gallium/state_trackers/vega/shader.c @@ -31,22 +31,29 @@ #include "paint.h" #include "mask.h" #include "image.h" +#include "renderer.h" #include "pipe/p_context.h" #include "pipe/p_screen.h" #include "pipe/p_state.h" #include "util/u_inlines.h" #include "util/u_memory.h" +#include "util/u_math.h" +#include "util/u_format.h" -#define MAX_CONSTANTS 20 +#define MAX_CONSTANTS 28 struct shader { struct vg_context *context; + VGboolean color_transform; VGboolean masking; struct vg_paint *paint; struct vg_image *image; + struct matrix modelview; + struct matrix paint_matrix; + VGboolean drawing_image; VGImageMode image_mode; @@ -71,6 +78,11 @@ void shader_destroy(struct shader *shader) FREE(shader); } +void shader_set_color_transform(struct shader *shader, VGboolean set) +{ + shader->color_transform = set; +} + void shader_set_masking(struct shader *shader, VGboolean set) { shader->masking = set; @@ -91,49 +103,64 @@ struct vg_paint * shader_paint(struct shader *shader) return shader->paint; } - -static void setup_constant_buffer(struct shader *shader) +static VGint setup_constant_buffer(struct shader *shader) { - struct vg_context *ctx = shader->context; - struct pipe_context *pipe = shader->context->pipe; - struct pipe_resource **cbuf = &shader->cbuf; + const struct vg_state *state = &shader->context->state.vg; VGint param_bytes = paint_constant_buffer_size(shader->paint); - float temp_buf[MAX_CONSTANTS]; + VGint i; + + param_bytes += sizeof(VGfloat) * 8; + assert(param_bytes <= sizeof(shader->constants)); + + if (state->color_transform) { + for (i = 0; i < 8; i++) { + VGfloat val = (i < 4) ? 127.0f : 1.0f; + shader->constants[i] = + CLAMP(state->color_transform_values[i], -val, val); + } + } + else { + memset(shader->constants, 0, sizeof(VGfloat) * 8); + } - assert(param_bytes <= sizeof(temp_buf)); - paint_fill_constant_buffer(shader->paint, temp_buf); + paint_fill_constant_buffer(shader->paint, + &shader->paint_matrix, shader->constants + 8); - if (*cbuf == NULL || - memcmp(temp_buf, shader->constants, param_bytes) != 0) - { - pipe_resource_reference(cbuf, NULL); + return param_bytes; +} + +static VGboolean blend_use_shader(struct vg_context *ctx) +{ + VGboolean advanced_blending; - memcpy(shader->constants, temp_buf, param_bytes); - *cbuf = pipe_user_buffer_create(pipe->screen, - &shader->constants, - sizeof(shader->constants), - PIPE_BIND_VERTEX_BUFFER); + switch (ctx->state.vg.blend_mode) { + case VG_BLEND_SRC_OVER: + advanced_blending = + util_format_has_alpha(ctx->draw_buffer->strb->format); + break; + case VG_BLEND_DST_OVER: + case VG_BLEND_MULTIPLY: + case VG_BLEND_SCREEN: + case VG_BLEND_DARKEN: + case VG_BLEND_LIGHTEN: + case VG_BLEND_ADDITIVE: + advanced_blending = VG_TRUE; + break; + default: + advanced_blending = VG_FALSE; + break; } - ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, *cbuf); + return advanced_blending; } static VGint blend_bind_samplers(struct vg_context *ctx, struct pipe_sampler_state **samplers, struct pipe_sampler_view **sampler_views) { - VGBlendMode bmode = ctx->state.vg.blend_mode; - - if (bmode == VG_BLEND_MULTIPLY || - bmode == VG_BLEND_SCREEN || - bmode == VG_BLEND_DARKEN || - bmode == VG_BLEND_LIGHTEN) { - struct st_framebuffer *stfb = ctx->draw_buffer; - - vg_prepare_blend_surface(ctx); - + if (blend_use_shader(ctx)) { samplers[2] = &ctx->blend_sampler; - sampler_views[2] = stfb->blend_texture_view; + sampler_views[2] = vg_prepare_blend_surface(ctx); if (!samplers[0] || !sampler_views[0]) { samplers[0] = samplers[2]; @@ -149,10 +176,10 @@ static VGint blend_bind_samplers(struct vg_context *ctx, return 0; } -static void setup_samplers(struct shader *shader) +static VGint setup_samplers(struct shader *shader, + struct pipe_sampler_state **samplers, + struct pipe_sampler_view **sampler_views) { - struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; - struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; struct vg_context *ctx = shader->context; /* a little wonky: we use the num as a boolean that just says * whether any sampler/textures have been set. the actual numbering @@ -179,10 +206,7 @@ static void setup_samplers(struct shader *shader) if (shader->drawing_image && shader->image) num += image_bind_samplers(shader->image, samplers, sampler_views); - if (num) { - cso_set_samplers(ctx->cso_context, 4, (const struct pipe_sampler_state **)samplers); - cso_set_fragment_sampler_views(ctx->cso_context, 4, sampler_views); - } + return (num) ? 4 : 0; } static INLINE VGboolean is_format_bw(struct shader *shader) @@ -227,6 +251,9 @@ static void setup_shader_program(struct shader *shader) default: abort(); } + + if (paint_is_degenerate(shader->paint)) + shader_id = VEGA_PAINT_DEGENERATE_SHADER; } /* second stage image */ @@ -246,43 +273,86 @@ static void setup_shader_program(struct shader *shader) } } - if (shader->masking) - shader_id |= VEGA_MASK_SHADER; + if (shader->color_transform) + shader_id |= VEGA_COLOR_TRANSFORM_SHADER; - switch(blend_mode) { - case VG_BLEND_MULTIPLY: - shader_id |= VEGA_BLEND_MULTIPLY_SHADER; - break; - case VG_BLEND_SCREEN: - shader_id |= VEGA_BLEND_SCREEN_SHADER; - break; - case VG_BLEND_DARKEN: - shader_id |= VEGA_BLEND_DARKEN_SHADER; - break; - case VG_BLEND_LIGHTEN: - shader_id |= VEGA_BLEND_LIGHTEN_SHADER; - break; - default: - /* handled by pipe_blend_state */ - break; + if (blend_use_shader(ctx)) { + if (shader->drawing_image && shader->image_mode == VG_DRAW_IMAGE_STENCIL) + shader_id |= VEGA_ALPHA_PER_CHANNEL_SHADER; + else + shader_id |= VEGA_ALPHA_NORMAL_SHADER; + + switch(blend_mode) { + case VG_BLEND_SRC: + shader_id |= VEGA_BLEND_SRC_SHADER; + break; + case VG_BLEND_SRC_OVER: + shader_id |= VEGA_BLEND_SRC_OVER_SHADER; + break; + case VG_BLEND_DST_OVER: + shader_id |= VEGA_BLEND_DST_OVER_SHADER; + break; + case VG_BLEND_SRC_IN: + shader_id |= VEGA_BLEND_SRC_IN_SHADER; + break; + case VG_BLEND_DST_IN: + shader_id |= VEGA_BLEND_DST_IN_SHADER; + break; + case VG_BLEND_MULTIPLY: + shader_id |= VEGA_BLEND_MULTIPLY_SHADER; + break; + case VG_BLEND_SCREEN: + shader_id |= VEGA_BLEND_SCREEN_SHADER; + break; + case VG_BLEND_DARKEN: + shader_id |= VEGA_BLEND_DARKEN_SHADER; + break; + case VG_BLEND_LIGHTEN: + shader_id |= VEGA_BLEND_LIGHTEN_SHADER; + break; + case VG_BLEND_ADDITIVE: + shader_id |= VEGA_BLEND_ADDITIVE_SHADER; + break; + default: + assert(0); + break; + } + } + else { + /* update alpha of the source */ + if (shader->drawing_image && shader->image_mode == VG_DRAW_IMAGE_STENCIL) + shader_id |= VEGA_ALPHA_PER_CHANNEL_SHADER; } + if (shader->masking) + shader_id |= VEGA_MASK_SHADER; + if (black_white) shader_id |= VEGA_BW_SHADER; shader->fs = shaders_cache_fill(ctx->sc, shader_id); - cso_set_fragment_shader_handle(ctx->cso_context, shader->fs); } void shader_bind(struct shader *shader) { + struct vg_context *ctx = shader->context; + struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; + struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; + VGint num_samplers, param_bytes; + /* first resolve the real paint type */ paint_resolve_type(shader->paint); - setup_constant_buffer(shader); - setup_samplers(shader); + num_samplers = setup_samplers(shader, samplers, sampler_views); + param_bytes = setup_constant_buffer(shader); setup_shader_program(shader); + + renderer_validate_for_shader(ctx->renderer, + (const struct pipe_sampler_state **) samplers, + sampler_views, num_samplers, + &shader->modelview, + shader->fs, (const void *) shader->constants, param_bytes); } void shader_set_image_mode(struct shader *shader, VGImageMode image_mode) @@ -309,3 +379,28 @@ void shader_set_image(struct shader *shader, struct vg_image *img) { shader->image = img; } + +/** + * Set the transformation to map a vertex to the surface coordinates. + */ +void shader_set_surface_matrix(struct shader *shader, + const struct matrix *mat) +{ + shader->modelview = *mat; +} + +/** + * Set the transformation to map a pixel to the paint coordinates. + */ +void shader_set_paint_matrix(struct shader *shader, const struct matrix *mat) +{ + const struct st_framebuffer *stfb = shader->context->draw_buffer; + const VGfloat px_center_offset = 0.5f; + + memcpy(&shader->paint_matrix, mat, sizeof(*mat)); + + /* make it window-to-paint for the shaders */ + matrix_translate(&shader->paint_matrix, px_center_offset, + stfb->height - 1.0f + px_center_offset); + matrix_scale(&shader->paint_matrix, 1.0f, -1.0f); +} diff --git a/src/gallium/state_trackers/vega/shader.h b/src/gallium/state_trackers/vega/shader.h index 847eee6a310..8b97e537efe 100644 --- a/src/gallium/state_trackers/vega/shader.h +++ b/src/gallium/state_trackers/vega/shader.h @@ -33,10 +33,13 @@ struct shader; struct vg_paint; struct vg_context; struct vg_image; +struct matrix; struct shader *shader_create(struct vg_context *context); void shader_destroy(struct shader *shader); +void shader_set_color_transform(struct shader *shader, VGboolean set); + void shader_set_masking(struct shader *shader, VGboolean set); VGboolean shader_is_masking(struct shader *shader); @@ -51,6 +54,10 @@ VGboolean shader_drawing_image(struct shader *shader); void shader_set_image(struct shader *shader, struct vg_image *img); +void shader_set_surface_matrix(struct shader *shader, + const struct matrix *mat); +void shader_set_paint_matrix(struct shader *shader, const struct matrix *mat); + void shader_bind(struct shader *shader); #endif diff --git a/src/gallium/state_trackers/vega/shaders_cache.c b/src/gallium/state_trackers/vega/shaders_cache.c index e002a7ed428..023996ce2d8 100644 --- a/src/gallium/state_trackers/vega/shaders_cache.c +++ b/src/gallium/state_trackers/vega/shaders_cache.c @@ -50,14 +50,16 @@ /* Essentially we construct an ubber-shader based on the state * of the pipeline. The stages are: - * 1) Fill (mandatory, solid color/gradient/pattern/image draw) - * 2) Image composition (image mode multiply and stencil) - * 3) Mask - * 4) Extended blend (multiply/screen/darken/lighten) - * 5) Premultiply/Unpremultiply - * 6) Color transform (to black and white) + * 1) Paint generation (color/gradient/pattern) + * 2) Image composition (normal/multiply/stencil) + * 3) Color transform + * 4) Per-channel alpha generation + * 5) Extended blend (multiply/screen/darken/lighten) + * 6) Mask + * 7) Premultiply/Unpremultiply + * 8) Color transform (to black and white) */ -#define SHADER_STAGES 6 +#define SHADER_STAGES 8 struct cached_shader { void *driver_shader; @@ -86,13 +88,6 @@ static INLINE struct tgsi_token *tokens_from_assembly(const char *txt, int num_t return tokens; } -#define ALL_FILLS (VEGA_SOLID_FILL_SHADER | \ - VEGA_LINEAR_GRADIENT_SHADER | \ - VEGA_RADIAL_GRADIENT_SHADER | \ - VEGA_PATTERN_SHADER | \ - VEGA_IMAGE_NORMAL_SHADER) - - /* static const char max_shader_preamble[] = "FRAG\n" @@ -257,98 +252,126 @@ create_shader(struct pipe_context *pipe, int id, struct pipe_shader_state *shader) { - int idx = 0; + int idx = 0, sh; const struct shader_asm_info * shaders[SHADER_STAGES]; - /* the shader has to have a fill */ - debug_assert(id & ALL_FILLS); - /* first stage */ - if (id & VEGA_SOLID_FILL_SHADER) { - debug_assert(idx == 0); - shaders[idx] = &shaders_asm[0]; - debug_assert(shaders_asm[0].id == VEGA_SOLID_FILL_SHADER); - ++idx; - } - if ((id & VEGA_LINEAR_GRADIENT_SHADER)) { - debug_assert(idx == 0); - shaders[idx] = &shaders_asm[1]; - debug_assert(shaders_asm[1].id == VEGA_LINEAR_GRADIENT_SHADER); - ++idx; - } - if ((id & VEGA_RADIAL_GRADIENT_SHADER)) { - debug_assert(idx == 0); - shaders[idx] = &shaders_asm[2]; - debug_assert(shaders_asm[2].id == VEGA_RADIAL_GRADIENT_SHADER); - ++idx; - } - if ((id & VEGA_PATTERN_SHADER)) { - debug_assert(idx == 0); - debug_assert(shaders_asm[3].id == VEGA_PATTERN_SHADER); - shaders[idx] = &shaders_asm[3]; - ++idx; - } - if ((id & VEGA_IMAGE_NORMAL_SHADER)) { - debug_assert(idx == 0); - debug_assert(shaders_asm[4].id == VEGA_IMAGE_NORMAL_SHADER); - shaders[idx] = &shaders_asm[4]; - ++idx; + sh = SHADERS_GET_PAINT_SHADER(id); + switch (sh << SHADERS_PAINT_SHIFT) { + case VEGA_SOLID_FILL_SHADER: + case VEGA_LINEAR_GRADIENT_SHADER: + case VEGA_RADIAL_GRADIENT_SHADER: + case VEGA_PATTERN_SHADER: + case VEGA_PAINT_DEGENERATE_SHADER: + shaders[idx] = &shaders_paint_asm[(sh >> SHADERS_PAINT_SHIFT) - 1]; + assert(shaders[idx]->id == sh); + idx++; + break; + default: + break; } /* second stage */ - if ((id & VEGA_IMAGE_MULTIPLY_SHADER)) { - debug_assert(shaders_asm[5].id == VEGA_IMAGE_MULTIPLY_SHADER); - shaders[idx] = &shaders_asm[5]; - ++idx; - } else if ((id & VEGA_IMAGE_STENCIL_SHADER)) { - debug_assert(shaders_asm[6].id == VEGA_IMAGE_STENCIL_SHADER); - shaders[idx] = &shaders_asm[6]; - ++idx; + sh = SHADERS_GET_IMAGE_SHADER(id); + switch (sh) { + case VEGA_IMAGE_NORMAL_SHADER: + case VEGA_IMAGE_MULTIPLY_SHADER: + case VEGA_IMAGE_STENCIL_SHADER: + shaders[idx] = &shaders_image_asm[(sh >> SHADERS_IMAGE_SHIFT) - 1]; + assert(shaders[idx]->id == sh); + idx++; + break; + default: + break; } + /* sanity check */ + assert(idx == ((!sh || sh == VEGA_IMAGE_NORMAL_SHADER) ? 1 : 2)); + /* third stage */ - if ((id & VEGA_MASK_SHADER)) { - debug_assert(idx == 1); - debug_assert(shaders_asm[7].id == VEGA_MASK_SHADER); - shaders[idx] = &shaders_asm[7]; - ++idx; + sh = SHADERS_GET_COLOR_TRANSFORM_SHADER(id); + switch (sh) { + case VEGA_COLOR_TRANSFORM_SHADER: + shaders[idx] = &shaders_color_transform_asm[ + (sh >> SHADERS_COLOR_TRANSFORM_SHIFT) - 1]; + assert(shaders[idx]->id == sh); + idx++; + break; + default: + break; } /* fourth stage */ - if ((id & VEGA_BLEND_MULTIPLY_SHADER)) { - debug_assert(shaders_asm[8].id == VEGA_BLEND_MULTIPLY_SHADER); - shaders[idx] = &shaders_asm[8]; - ++idx; - } else if ((id & VEGA_BLEND_SCREEN_SHADER)) { - debug_assert(shaders_asm[9].id == VEGA_BLEND_SCREEN_SHADER); - shaders[idx] = &shaders_asm[9]; - ++idx; - } else if ((id & VEGA_BLEND_DARKEN_SHADER)) { - debug_assert(shaders_asm[10].id == VEGA_BLEND_DARKEN_SHADER); - shaders[idx] = &shaders_asm[10]; - ++idx; - } else if ((id & VEGA_BLEND_LIGHTEN_SHADER)) { - debug_assert(shaders_asm[11].id == VEGA_BLEND_LIGHTEN_SHADER); - shaders[idx] = &shaders_asm[11]; - ++idx; + sh = SHADERS_GET_ALPHA_SHADER(id); + switch (sh) { + case VEGA_ALPHA_NORMAL_SHADER: + case VEGA_ALPHA_PER_CHANNEL_SHADER: + shaders[idx] = &shaders_alpha_asm[ + (sh >> SHADERS_ALPHA_SHIFT) - 1]; + assert(shaders[idx]->id == sh); + idx++; + break; + default: + break; } /* fifth stage */ - if ((id & VEGA_PREMULTIPLY_SHADER)) { - debug_assert(shaders_asm[12].id == VEGA_PREMULTIPLY_SHADER); - shaders[idx] = &shaders_asm[12]; - ++idx; - } else if ((id & VEGA_UNPREMULTIPLY_SHADER)) { - debug_assert(shaders_asm[13].id == VEGA_UNPREMULTIPLY_SHADER); - shaders[idx] = &shaders_asm[13]; - ++idx; + sh = SHADERS_GET_BLEND_SHADER(id); + switch (sh) { + case VEGA_BLEND_SRC_SHADER: + case VEGA_BLEND_SRC_OVER_SHADER: + case VEGA_BLEND_DST_OVER_SHADER: + case VEGA_BLEND_SRC_IN_SHADER: + case VEGA_BLEND_DST_IN_SHADER: + case VEGA_BLEND_MULTIPLY_SHADER: + case VEGA_BLEND_SCREEN_SHADER: + case VEGA_BLEND_DARKEN_SHADER: + case VEGA_BLEND_LIGHTEN_SHADER: + case VEGA_BLEND_ADDITIVE_SHADER: + shaders[idx] = &shaders_blend_asm[(sh >> SHADERS_BLEND_SHIFT) - 1]; + assert(shaders[idx]->id == sh); + idx++; + break; + default: + break; } /* sixth stage */ - if ((id & VEGA_BW_SHADER)) { - debug_assert(shaders_asm[14].id == VEGA_BW_SHADER); - shaders[idx] = &shaders_asm[14]; - ++idx; + sh = SHADERS_GET_MASK_SHADER(id); + switch (sh) { + case VEGA_MASK_SHADER: + shaders[idx] = &shaders_mask_asm[(sh >> SHADERS_MASK_SHIFT) - 1]; + assert(shaders[idx]->id == sh); + idx++; + break; + default: + break; + } + + /* seventh stage */ + sh = SHADERS_GET_PREMULTIPLY_SHADER(id); + switch (sh) { + case VEGA_PREMULTIPLY_SHADER: + case VEGA_UNPREMULTIPLY_SHADER: + shaders[idx] = &shaders_premultiply_asm[ + (sh >> SHADERS_PREMULTIPLY_SHIFT) - 1]; + assert(shaders[idx]->id == sh); + idx++; + break; + default: + break; + } + + /* eighth stage */ + sh = SHADERS_GET_BW_SHADER(id); + switch (sh) { + case VEGA_BW_SHADER: + shaders[idx] = &shaders_bw_asm[(sh >> SHADERS_BW_SHIFT) - 1]; + assert(shaders[idx]->id == sh); + idx++; + break; + default: + break; } return combine_shaders(shaders, idx, pipe, shader); diff --git a/src/gallium/state_trackers/vega/shaders_cache.h b/src/gallium/state_trackers/vega/shaders_cache.h index feca58b61a9..05014f25dcc 100644 --- a/src/gallium/state_trackers/vega/shaders_cache.h +++ b/src/gallium/state_trackers/vega/shaders_cache.h @@ -33,26 +33,69 @@ struct pipe_context; struct tgsi_token; struct shaders_cache; +#define _SHADERS_PAINT_BITS 3 +#define _SHADERS_IMAGE_BITS 2 +#define _SHADERS_COLOR_TRANSFORM_BITS 1 +#define _SHADERS_ALPHA_BITS 2 +#define _SHADERS_BLEND_BITS 4 +#define _SHADERS_MASK_BITS 1 +#define _SHADERS_PREMULTIPLY_BITS 2 +#define _SHADERS_BW_BITS 1 + +#define SHADERS_PAINT_SHIFT (0) +#define SHADERS_IMAGE_SHIFT (SHADERS_PAINT_SHIFT + _SHADERS_PAINT_BITS) +#define SHADERS_COLOR_TRANSFORM_SHIFT (SHADERS_IMAGE_SHIFT + _SHADERS_IMAGE_BITS) +#define SHADERS_ALPHA_SHIFT (SHADERS_COLOR_TRANSFORM_SHIFT + _SHADERS_COLOR_TRANSFORM_BITS) +#define SHADERS_BLEND_SHIFT (SHADERS_ALPHA_SHIFT + _SHADERS_ALPHA_BITS) +#define SHADERS_MASK_SHIFT (SHADERS_BLEND_SHIFT + _SHADERS_BLEND_BITS) +#define SHADERS_PREMULTIPLY_SHIFT (SHADERS_MASK_SHIFT + _SHADERS_MASK_BITS) +#define SHADERS_BW_SHIFT (SHADERS_PREMULTIPLY_SHIFT + _SHADERS_PREMULTIPLY_BITS) + +#define _SHADERS_GET_STAGE(stage, id) \ + ((id) & (((1 << _SHADERS_ ## stage ## _BITS) - 1) << SHADERS_ ## stage ## _SHIFT)) + +#define SHADERS_GET_PAINT_SHADER(id) _SHADERS_GET_STAGE(PAINT, id) +#define SHADERS_GET_IMAGE_SHADER(id) _SHADERS_GET_STAGE(IMAGE, id) +#define SHADERS_GET_COLOR_TRANSFORM_SHADER(id) _SHADERS_GET_STAGE(COLOR_TRANSFORM, id) +#define SHADERS_GET_ALPHA_SHADER(id) _SHADERS_GET_STAGE(ALPHA, id) +#define SHADERS_GET_BLEND_SHADER(id) _SHADERS_GET_STAGE(BLEND, id) +#define SHADERS_GET_MASK_SHADER(id) _SHADERS_GET_STAGE(MASK, id) +#define SHADERS_GET_PREMULTIPLY_SHADER(id) _SHADERS_GET_STAGE(PREMULTIPLY, id) +#define SHADERS_GET_BW_SHADER(id) _SHADERS_GET_STAGE(BW, id) + enum VegaShaderType { - VEGA_SOLID_FILL_SHADER = 1 << 0, - VEGA_LINEAR_GRADIENT_SHADER = 1 << 1, - VEGA_RADIAL_GRADIENT_SHADER = 1 << 2, - VEGA_PATTERN_SHADER = 1 << 3, - VEGA_IMAGE_NORMAL_SHADER = 1 << 4, - VEGA_IMAGE_MULTIPLY_SHADER = 1 << 5, - VEGA_IMAGE_STENCIL_SHADER = 1 << 6, + VEGA_SOLID_FILL_SHADER = 1 << SHADERS_PAINT_SHIFT, + VEGA_LINEAR_GRADIENT_SHADER = 2 << SHADERS_PAINT_SHIFT, + VEGA_RADIAL_GRADIENT_SHADER = 3 << SHADERS_PAINT_SHIFT, + VEGA_PATTERN_SHADER = 4 << SHADERS_PAINT_SHIFT, + VEGA_PAINT_DEGENERATE_SHADER = 5 << SHADERS_PAINT_SHIFT, + + VEGA_IMAGE_NORMAL_SHADER = 1 << SHADERS_IMAGE_SHIFT, + VEGA_IMAGE_MULTIPLY_SHADER = 2 << SHADERS_IMAGE_SHIFT, + VEGA_IMAGE_STENCIL_SHADER = 3 << SHADERS_IMAGE_SHIFT, + + VEGA_COLOR_TRANSFORM_SHADER = 1 << SHADERS_COLOR_TRANSFORM_SHIFT, + + VEGA_ALPHA_NORMAL_SHADER = 1 << SHADERS_ALPHA_SHIFT, + VEGA_ALPHA_PER_CHANNEL_SHADER = 2 << SHADERS_ALPHA_SHIFT, - VEGA_MASK_SHADER = 1 << 7, + VEGA_BLEND_SRC_SHADER = 1 << SHADERS_BLEND_SHIFT, + VEGA_BLEND_SRC_OVER_SHADER = 2 << SHADERS_BLEND_SHIFT, + VEGA_BLEND_DST_OVER_SHADER = 3 << SHADERS_BLEND_SHIFT, + VEGA_BLEND_SRC_IN_SHADER = 4 << SHADERS_BLEND_SHIFT, + VEGA_BLEND_DST_IN_SHADER = 5 << SHADERS_BLEND_SHIFT, + VEGA_BLEND_MULTIPLY_SHADER = 6 << SHADERS_BLEND_SHIFT, + VEGA_BLEND_SCREEN_SHADER = 7 << SHADERS_BLEND_SHIFT, + VEGA_BLEND_DARKEN_SHADER = 8 << SHADERS_BLEND_SHIFT, + VEGA_BLEND_LIGHTEN_SHADER = 9 << SHADERS_BLEND_SHIFT, + VEGA_BLEND_ADDITIVE_SHADER = 10<< SHADERS_BLEND_SHIFT, - VEGA_BLEND_MULTIPLY_SHADER = 1 << 8, - VEGA_BLEND_SCREEN_SHADER = 1 << 9, - VEGA_BLEND_DARKEN_SHADER = 1 << 10, - VEGA_BLEND_LIGHTEN_SHADER = 1 << 11, + VEGA_MASK_SHADER = 1 << SHADERS_MASK_SHIFT, - VEGA_PREMULTIPLY_SHADER = 1 << 12, - VEGA_UNPREMULTIPLY_SHADER = 1 << 13, + VEGA_PREMULTIPLY_SHADER = 1 << SHADERS_PREMULTIPLY_SHIFT, + VEGA_UNPREMULTIPLY_SHADER = 2 << SHADERS_PREMULTIPLY_SHIFT, - VEGA_BW_SHADER = 1 << 14 + VEGA_BW_SHADER = 1 << SHADERS_BW_SHIFT }; struct vg_shader { diff --git a/src/gallium/state_trackers/vega/st_inlines.h b/src/gallium/state_trackers/vega/st_inlines.h deleted file mode 100644 index 7eaa67c76ae..00000000000 --- a/src/gallium/state_trackers/vega/st_inlines.h +++ /dev/null @@ -1,122 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -/** - * Functions for checking if buffers/textures are referenced when we need - * to read/write from/to them. Flush when needed. - */ - -#ifndef ST_INLINES_H -#define ST_INLINES_H - -#include "vg_context.h" - -#include "pipe/p_context.h" -#include "pipe/p_screen.h" -#include "pipe/p_defines.h" -#include "util/u_inlines.h" -#include "pipe/p_state.h" - -static INLINE struct pipe_transfer * -st_cond_flush_get_transfer(struct vg_context *st, - struct pipe_resource *pt, - unsigned int face, - unsigned int level, - unsigned int zslice, - enum pipe_transfer_usage usage, - unsigned int x, unsigned int y, - unsigned int w, unsigned int h) -{ - struct pipe_context *pipe = st->pipe; - - return pipe_get_transfer(pipe, pt, face, level, zslice, usage, - x, y, w, h); -} - -static INLINE struct pipe_transfer * -st_no_flush_get_transfer(struct vg_context *st, - struct pipe_resource *pt, - unsigned int face, - unsigned int level, - unsigned int zslice, - enum pipe_transfer_usage usage, - unsigned int x, unsigned int y, - unsigned int w, unsigned int h) -{ - struct pipe_context *pipe = st->pipe; - - return pipe_get_transfer(pipe, pt, face, level, - zslice, usage, x, y, w, h); -} - - -static INLINE void -st_cond_flush_pipe_buffer_write(struct vg_context *st, - struct pipe_resource *buf, - unsigned int offset, - unsigned int size, - const void * data) -{ - struct pipe_context *pipe = st->pipe; - - pipe_buffer_write(pipe, buf, offset, size, data); -} - -static INLINE void -st_no_flush_pipe_buffer_write(struct vg_context *st, - struct pipe_resource *buf, - unsigned int offset, - unsigned int size, - const void * data) -{ - pipe_buffer_write(st->pipe, buf, offset, size, data); -} - -static INLINE void -st_cond_flush_pipe_buffer_read(struct vg_context *st, - struct pipe_resource *buf, - unsigned int offset, - unsigned int size, - void * data) -{ - struct pipe_context *pipe = st->pipe; - - pipe_buffer_read(pipe, buf, offset, size, data); -} - -static INLINE void -st_no_flush_pipe_buffer_read(struct vg_context *st, - struct pipe_resource *buf, - unsigned int offset, - unsigned int size, - void * data) -{ - pipe_buffer_read(st->pipe, buf, offset, size, data); -} - -#endif - diff --git a/src/gallium/state_trackers/vega/text.c b/src/gallium/state_trackers/vega/text.c new file mode 100644 index 00000000000..01ff602f58a --- /dev/null +++ b/src/gallium/state_trackers/vega/text.c @@ -0,0 +1,250 @@ +/************************************************************************** + * + * Copyright 2010 LunarG, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "util/u_memory.h" +#include "cso_cache/cso_hash.h" + +#include "text.h" +#include "image.h" +#include "path.h" +#include "api.h" + +#ifdef OPENVG_VERSION_1_1 + +struct vg_font { + struct vg_object base; + struct cso_hash *glyphs; +}; + +struct vg_glyph { + struct vg_object *object; /* it could be NULL */ + VGboolean is_hinted; + VGfloat glyph_origin[2]; + VGfloat escapement[2]; +}; + +static VGboolean del_glyph(struct vg_font *font, + VGuint glyphIndex) +{ + struct vg_glyph *glyph; + + glyph = (struct vg_glyph *) + cso_hash_take(font->glyphs, (unsigned) glyphIndex); + if (glyph) + FREE(glyph); + + return (glyph != NULL); +} + +static void add_glyph(struct vg_font *font, + VGuint glyphIndex, + struct vg_object *obj, + VGboolean isHinted, + const VGfloat glyphOrigin[2], + const VGfloat escapement[2]) +{ + struct vg_glyph *glyph; + + /* remove the existing one */ + del_glyph(font, glyphIndex); + + glyph = CALLOC_STRUCT(vg_glyph); + glyph->object = obj; + glyph->is_hinted = isHinted; + memcpy(glyph->glyph_origin, glyphOrigin, sizeof(glyphOrigin)); + memcpy(glyph->escapement, escapement, sizeof(escapement)); + + cso_hash_insert(font->glyphs, (unsigned) glyphIndex, glyph); +} + +static struct vg_glyph *get_glyph(struct vg_font *font, + VGuint glyphIndex) +{ + struct cso_hash_iter iter; + + iter = cso_hash_find(font->glyphs, (unsigned) glyphIndex); + return (struct vg_glyph *) cso_hash_iter_data(iter); +} + +static void vg_render_glyph(struct vg_context *ctx, + struct vg_glyph *glyph, + VGbitfield paintModes, + VGboolean allowAutoHinting) +{ + if (glyph->object && paintModes) { + struct vg_state *state = &ctx->state.vg; + struct matrix m; + + m = state->glyph_user_to_surface_matrix; + matrix_translate(&m, + state->glyph_origin[0].f - glyph->glyph_origin[0], + state->glyph_origin[1].f - glyph->glyph_origin[1]); + + if (glyph->object->type == VG_OBJECT_PATH) { + path_render((struct path *) glyph->object, paintModes, &m); + } + else { + assert(glyph->object->type == VG_OBJECT_IMAGE); + image_draw((struct vg_image *) glyph->object, &m); + } + } +} + +static void vg_advance_glyph(struct vg_context *ctx, + struct vg_glyph *glyph, + VGfloat adjustment_x, + VGfloat adjustment_y, + VGboolean last) +{ + struct vg_value *glyph_origin = ctx->state.vg.glyph_origin; + + glyph_origin[0].f += glyph->escapement[0] + adjustment_x; + glyph_origin[1].f += glyph->escapement[1] + adjustment_y; + + if (last) { + glyph_origin[0].i = float_to_int_floor(glyph_origin[0].f); + glyph_origin[1].i = float_to_int_floor(glyph_origin[1].f); + } +} + +struct vg_font *font_create(VGint glyphCapacityHint) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_font *font; + + font = CALLOC_STRUCT(vg_font); + vg_init_object(&font->base, ctx, VG_OBJECT_FONT); + font->glyphs = cso_hash_create(); + + vg_context_add_object(ctx, VG_OBJECT_FONT, font); + + return font; +} + +void font_destroy(struct vg_font *font) +{ + struct vg_context *ctx = vg_current_context(); + struct cso_hash_iter iter; + + vg_context_remove_object(ctx, VG_OBJECT_FONT, font); + + iter = cso_hash_first_node(font->glyphs); + while (!cso_hash_iter_is_null(iter)) { + struct vg_glyph *glyph = (struct vg_glyph *) cso_hash_iter_data(iter); + FREE(glyph); + iter = cso_hash_iter_next(iter); + } + cso_hash_delete(font->glyphs); + + FREE(font); +} + +void font_set_glyph_to_path(struct vg_font *font, + VGuint glyphIndex, + struct path *path, + VGboolean isHinted, + const VGfloat glyphOrigin[2], + const VGfloat escapement[2]) +{ + add_glyph(font, glyphIndex, (struct vg_object *) path, + isHinted, glyphOrigin, escapement); +} + +void font_set_glyph_to_image(struct vg_font *font, + VGuint glyphIndex, + struct vg_image *image, + const VGfloat glyphOrigin[2], + const VGfloat escapement[2]) +{ + add_glyph(font, glyphIndex, (struct vg_object *) image, + VG_TRUE, glyphOrigin, escapement); +} + +void font_clear_glyph(struct vg_font *font, + VGuint glyphIndex) +{ + if (!del_glyph(font, glyphIndex)) { + struct vg_context *ctx = vg_current_context(); + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + } +} + +void font_draw_glyph(struct vg_font *font, + VGuint glyphIndex, + VGbitfield paintModes, + VGboolean allowAutoHinting) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_glyph *glyph; + + glyph = get_glyph(font, glyphIndex); + if (!glyph) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + vg_render_glyph(ctx, glyph, paintModes, allowAutoHinting); + vg_advance_glyph(ctx, glyph, 0.0f, 0.0f, VG_TRUE); +} + +void font_draw_glyphs(struct vg_font *font, + VGint glyphCount, + const VGuint *glyphIndices, + const VGfloat *adjustments_x, + const VGfloat *adjustments_y, + VGbitfield paintModes, + VGboolean allowAutoHinting) +{ + struct vg_context *ctx = vg_current_context(); + VGint i; + + for (i = 0; i < glyphCount; ++i) { + if (!get_glyph(font, glyphIndices[i])) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + } + + for (i = 0; i < glyphCount; ++i) { + struct vg_glyph *glyph; + VGfloat adj_x, adj_y; + + glyph = get_glyph(font, glyphIndices[i]); + + vg_render_glyph(ctx, glyph, paintModes, allowAutoHinting); + + adj_x = (adjustments_x) ? adjustments_x[i] : 0.0f; + adj_y = (adjustments_y) ? adjustments_y[i] : 0.0f; + vg_advance_glyph(ctx, glyph, adj_x, adj_y, (i == glyphCount - 1)); + } +} + +VGint font_num_glyphs(struct vg_font *font) +{ + return cso_hash_size(font->glyphs); +} + +#endif /* OPENVG_VERSION_1_1 */ diff --git a/src/gallium/state_trackers/vega/text.h b/src/gallium/state_trackers/vega/text.h new file mode 100644 index 00000000000..6b3fa7323e9 --- /dev/null +++ b/src/gallium/state_trackers/vega/text.h @@ -0,0 +1,71 @@ +/************************************************************************** + * + * Copyright 2010 LunarG, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef _TEXT_H +#define _TEXT_H + +#include "vg_context.h" +#include "cso_cache/cso_hash.h" + +struct vg_font; +struct vg_image; +struct path; + +struct vg_font *font_create(VGint glyphCapacityHint); +void font_destroy(struct vg_font *font); + +void font_set_glyph_to_path(struct vg_font *font, + VGuint glyphIndex, + struct path *path, + VGboolean isHinted, + const VGfloat glyphOrigin[2], + const VGfloat escapement[2]); + +void font_set_glyph_to_image(struct vg_font *font, + VGuint glyphIndex, + struct vg_image *image, + const VGfloat glyphOrigin[2], + const VGfloat escapement[2]); + +void font_clear_glyph(struct vg_font *font, + VGuint glyphIndex); + +void font_draw_glyph(struct vg_font *font, + VGuint glyphIndex, + VGbitfield paintModes, + VGboolean allowAutoHinting); + +void font_draw_glyphs(struct vg_font *font, + VGint glyphCount, + const VGuint *glyphIndices, + const VGfloat *adjustments_x, + const VGfloat *adjustments_y, + VGbitfield paintModes, + VGboolean allowAutoHinting); + +VGint font_num_glyphs(struct vg_font *font); + +#endif /* _TEXT_H */ diff --git a/src/gallium/state_trackers/vega/vg_context.c b/src/gallium/state_trackers/vega/vg_context.c index 99e444affdf..0844012cc3b 100644 --- a/src/gallium/state_trackers/vega/vg_context.c +++ b/src/gallium/state_trackers/vega/vg_context.c @@ -31,9 +31,9 @@ #include "shaders_cache.h" #include "shader.h" #include "asm_util.h" -#include "st_inlines.h" #include "vg_manager.h" #include "api.h" +#include "mask.h" #include "pipe/p_context.h" #include "util/u_inlines.h" @@ -44,6 +44,8 @@ #include "util/u_memory.h" #include "util/u_blit.h" #include "util/u_sampler.h" +#include "util/u_surface.h" +#include "util/u_format.h" struct vg_context *_vg_context = 0; @@ -52,19 +54,6 @@ struct vg_context * vg_current_context(void) return _vg_context; } -static void init_clear(struct vg_context *st) -{ - struct pipe_context *pipe = st->pipe; - - /* rasterizer state: bypass clipping */ - memset(&st->clear.raster, 0, sizeof(st->clear.raster)); - st->clear.raster.gl_rasterization_rules = 1; - - /* fragment shader state: color pass-through program */ - st->clear.fs = - util_make_fragment_passthrough_shader(pipe); -} - /** * A depth/stencil rb will be needed regardless of what the visual says. */ @@ -101,7 +90,6 @@ struct vg_context * vg_create_context(struct pipe_context *pipe, struct vg_context *share) { struct vg_context *ctx; - unsigned i; ctx = CALLOC_STRUCT(vg_context); @@ -118,8 +106,6 @@ struct vg_context * vg_create_context(struct pipe_context *pipe, ctx->cso_context = cso_create_context(pipe); - init_clear(ctx); - ctx->default_paint = paint_create(ctx); ctx->state.vg.stroke_paint = ctx->default_paint; ctx->state.vg.fill_paint = ctx->default_paint; @@ -141,13 +127,6 @@ struct vg_context * vg_create_context(struct pipe_context *pipe, ctx->blend_sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; ctx->blend_sampler.normalized_coords = 0; - for (i = 0; i < 2; i++) { - ctx->velems[i].src_offset = i * 4 * sizeof(float); - ctx->velems[i].instance_divisor = 0; - ctx->velems[i].vertex_buffer_index = 0; - ctx->velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; - } - vg_set_error(ctx, VG_NO_ERROR); ctx->owned_objects[VG_OBJECT_PAINT] = cso_hash_create(); @@ -168,7 +147,6 @@ struct vg_context * vg_create_context(struct pipe_context *pipe, void vg_destroy_context(struct vg_context *ctx) { struct pipe_resource **cbuf = &ctx->mask.cbuf; - struct pipe_resource **vsbuf = &ctx->vs_const_buffer; util_destroy_blit(ctx->blit); renderer_destroy(ctx->renderer); @@ -179,29 +157,6 @@ void vg_destroy_context(struct vg_context *ctx) if (*cbuf) pipe_resource_reference(cbuf, NULL); - if (*vsbuf) - pipe_resource_reference(vsbuf, NULL); - - if (ctx->clear.fs) { - cso_delete_fragment_shader(ctx->cso_context, ctx->clear.fs); - ctx->clear.fs = NULL; - } - - if (ctx->plain_vs) { - vg_shader_destroy(ctx, ctx->plain_vs); - ctx->plain_vs = NULL; - } - if (ctx->clear_vs) { - vg_shader_destroy(ctx, ctx->clear_vs); - ctx->clear_vs = NULL; - } - if (ctx->texture_vs) { - vg_shader_destroy(ctx, ctx->texture_vs); - ctx->texture_vs = NULL; - } - - if (ctx->pass_through_depth_fs) - vg_shader_destroy(ctx, ctx->pass_through_depth_fs); if (ctx->mask.union_fs) vg_shader_destroy(ctx, ctx->mask.union_fs); if (ctx->mask.intersect_fs) @@ -268,186 +223,195 @@ void vg_context_remove_object(struct vg_context *ctx, } } -static void update_clip_state(struct vg_context *ctx) +static struct pipe_resource * +create_texture(struct pipe_context *pipe, enum pipe_format format, + VGint width, VGint height) { - struct pipe_depth_stencil_alpha_state *dsa = &ctx->state.g3d.dsa; - struct vg_state *state = &ctx->state.vg; - - memset(dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); - - if (state->scissoring) { - struct pipe_blend_state *blend = &ctx->state.g3d.blend; - struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; - int i; - - dsa->depth.writemask = 1;/*glDepthMask(TRUE);*/ - dsa->depth.func = PIPE_FUNC_ALWAYS; - dsa->depth.enabled = 1; - - cso_save_blend(ctx->cso_context); - cso_save_fragment_shader(ctx->cso_context); - /* set a passthrough shader */ - if (!ctx->pass_through_depth_fs) - ctx->pass_through_depth_fs = shader_create_from_text(ctx->pipe, - pass_through_depth_asm, - 40, - PIPE_SHADER_FRAGMENT); - cso_set_fragment_shader_handle(ctx->cso_context, - ctx->pass_through_depth_fs->driver); - cso_set_depth_stencil_alpha(ctx->cso_context, dsa); - - ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL, NULL, 1.0, 0); - - /* disable color writes */ - blend->rt[0].colormask = 0; /*disable colorwrites*/ - cso_set_blend(ctx->cso_context, blend); - - /* enable scissoring */ - for (i = 0; i < state->scissor_rects_num; ++i) { - const float x = state->scissor_rects[i * 4 + 0].f; - const float y = state->scissor_rects[i * 4 + 1].f; - const float width = state->scissor_rects[i * 4 + 2].f; - const float height = state->scissor_rects[i * 4 + 3].f; - VGfloat minx, miny, maxx, maxy; - - minx = 0; - miny = 0; - maxx = fb->width; - maxy = fb->height; - - if (x > minx) - minx = x; - if (y > miny) - miny = y; - - if (x + width < maxx) - maxx = x + width; - if (y + height < maxy) - maxy = y + height; - - /* check for null space */ - if (minx >= maxx || miny >= maxy) - minx = miny = maxx = maxy = 0; - - /*glClear(GL_DEPTH_BUFFER_BIT);*/ - renderer_draw_quad(ctx->renderer, minx, miny, maxx, maxy, 0.0f); - } - - cso_restore_blend(ctx->cso_context); - cso_restore_fragment_shader(ctx->cso_context); - - dsa->depth.enabled = 1; /* glEnable(GL_DEPTH_TEST); */ - dsa->depth.writemask = 0;/*glDepthMask(FALSE);*/ - dsa->depth.func = PIPE_FUNC_GEQUAL; + struct pipe_resource templ; + + memset(&templ, 0, sizeof(templ)); + + if (format != PIPE_FORMAT_NONE) { + templ.format = format; + } + else { + templ.format = PIPE_FORMAT_B8G8R8A8_UNORM; + } + + templ.target = PIPE_TEXTURE_2D; + templ.width0 = width; + templ.height0 = height; + templ.depth0 = 1; + templ.array_size = 1; + templ.last_level = 0; + + if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) { + templ.bind = PIPE_BIND_DEPTH_STENCIL; + } else { + templ.bind = (PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_RENDER_TARGET | + PIPE_BIND_SAMPLER_VIEW); } + + return pipe->screen->resource_create(pipe->screen, &templ); } -void vg_validate_state(struct vg_context *ctx) +static struct pipe_sampler_view * +create_tex_and_view(struct pipe_context *pipe, enum pipe_format format, + VGint width, VGint height) { - vg_manager_validate_framebuffer(ctx); + struct pipe_resource *texture; + struct pipe_sampler_view view_templ; + struct pipe_sampler_view *view; - if ((ctx->state.dirty & BLEND_DIRTY)) { - struct pipe_blend_state *blend = &ctx->state.g3d.blend; - memset(blend, 0, sizeof(struct pipe_blend_state)); - blend->rt[0].blend_enable = 1; - blend->rt[0].colormask = PIPE_MASK_RGBA; - - switch (ctx->state.vg.blend_mode) { - case VG_BLEND_SRC: - blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; - blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; - blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; - blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; - blend->rt[0].blend_enable = 0; - break; - case VG_BLEND_SRC_OVER: - blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; - blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; - blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; - blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; - break; - case VG_BLEND_DST_OVER: - blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_INV_DST_ALPHA; - blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_INV_DST_ALPHA; - blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_DST_ALPHA; - blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_DST_ALPHA; - break; - case VG_BLEND_SRC_IN: - blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_DST_ALPHA; - blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_DST_ALPHA; - blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; - blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; - break; - case VG_BLEND_DST_IN: - blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ZERO; - blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO; - blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_SRC_ALPHA; - blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_SRC_ALPHA; - break; - case VG_BLEND_MULTIPLY: - case VG_BLEND_SCREEN: - case VG_BLEND_DARKEN: - case VG_BLEND_LIGHTEN: - blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; - blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; - blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; - blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; - blend->rt[0].blend_enable = 0; - break; - case VG_BLEND_ADDITIVE: - blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; - blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; - blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE; - blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; - break; - default: - assert(!"not implemented blend mode"); - } - cso_set_blend(ctx->cso_context, &ctx->state.g3d.blend); - } - if ((ctx->state.dirty & RASTERIZER_DIRTY)) { - struct pipe_rasterizer_state *raster = &ctx->state.g3d.rasterizer; - memset(raster, 0, sizeof(struct pipe_rasterizer_state)); - raster->gl_rasterization_rules = 1; - cso_set_rasterizer(ctx->cso_context, &ctx->state.g3d.rasterizer); - } - if ((ctx->state.dirty & VIEWPORT_DIRTY)) { - struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; - const VGint param_bytes = 8 * sizeof(VGfloat); - VGfloat vs_consts[8] = { - 2.f/fb->width, 2.f/fb->height, 1, 1, - -1, -1, 0, 0 - }; - struct pipe_resource **cbuf = &ctx->vs_const_buffer; + texture = create_texture(pipe, format, width, height); - vg_set_viewport(ctx, VEGA_Y0_BOTTOM); + if (!texture) + return NULL; - pipe_resource_reference(cbuf, NULL); - *cbuf = pipe_buffer_create(ctx->pipe->screen, - PIPE_BIND_CONSTANT_BUFFER, - param_bytes); - - if (*cbuf) { - st_no_flush_pipe_buffer_write(ctx, *cbuf, - 0, param_bytes, vs_consts); - } - ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_VERTEX, 0, *cbuf); + u_sampler_view_default_template(&view_templ, texture, texture->format); + view = pipe->create_sampler_view(pipe, texture, &view_templ); + /* want the texture to go away if the view is freed */ + pipe_resource_reference(&texture, NULL); + + return view; +} + +static void +vg_context_update_surface_mask_view(struct vg_context *ctx, + uint width, uint height) +{ + struct st_framebuffer *stfb = ctx->draw_buffer; + struct pipe_sampler_view *old_sampler_view = stfb->surface_mask_view; + struct pipe_context *pipe = ctx->pipe; + + if (old_sampler_view && + old_sampler_view->texture->width0 == width && + old_sampler_view->texture->height0 == height) + return; + + /* + we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to + this texture and use it as a sampler, so while this wastes some + space it makes both of those a lot simpler + */ + stfb->surface_mask_view = create_tex_and_view(pipe, + PIPE_FORMAT_B8G8R8A8_UNORM, width, height); + + if (!stfb->surface_mask_view) { + if (old_sampler_view) + pipe_sampler_view_reference(&old_sampler_view, NULL); + return; } - if ((ctx->state.dirty & VS_DIRTY)) { - cso_set_vertex_shader_handle(ctx->cso_context, - vg_plain_vs(ctx)); + + /* XXX could this call be avoided? */ + vg_validate_state(ctx); + + /* alpha mask starts with 1.f alpha */ + mask_fill(0, 0, width, height, 1.f); + + /* if we had an old surface copy it over */ + if (old_sampler_view) { + struct pipe_box src_box; + u_box_origin_2d(MIN2(old_sampler_view->texture->width0, + stfb->surface_mask_view->texture->width0), + MIN2(old_sampler_view->texture->height0, + stfb->surface_mask_view->texture->height0), + &src_box); + + pipe->resource_copy_region(pipe, + stfb->surface_mask_view->texture, + 0, 0, 0, 0, + old_sampler_view->texture, + 0, &src_box); } - /* must be last because it renders to the depth buffer*/ - if ((ctx->state.dirty & DEPTH_STENCIL_DIRTY)) { - update_clip_state(ctx); - cso_set_depth_stencil_alpha(ctx->cso_context, &ctx->state.g3d.dsa); + /* Free the old texture + */ + if (old_sampler_view) + pipe_sampler_view_reference(&old_sampler_view, NULL); +} + +static void +vg_context_update_blend_texture_view(struct vg_context *ctx, + uint width, uint height) +{ + struct pipe_context *pipe = ctx->pipe; + struct st_framebuffer *stfb = ctx->draw_buffer; + struct pipe_sampler_view *old = stfb->blend_texture_view; + + if (old && + old->texture->width0 == width && + old->texture->height0 == height) + return; + + stfb->blend_texture_view = create_tex_and_view(pipe, + PIPE_FORMAT_B8G8R8A8_UNORM, width, height); + + pipe_sampler_view_reference(&old, NULL); +} + +static boolean +vg_context_update_depth_stencil_rb(struct vg_context * ctx, + uint width, uint height) +{ + struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb; + struct pipe_context *pipe = ctx->pipe; + struct pipe_surface surf_tmpl; + + if ((dsrb->width == width && dsrb->height == height) && dsrb->texture) + return FALSE; + + /* unreference existing ones */ + pipe_surface_reference(&dsrb->surface, NULL); + pipe_resource_reference(&dsrb->texture, NULL); + dsrb->width = dsrb->height = 0; + + dsrb->texture = create_texture(pipe, dsrb->format, width, height); + if (!dsrb->texture) + return TRUE; + + memset(&surf_tmpl, 0, sizeof(surf_tmpl)); + u_surface_default_template(&surf_tmpl, dsrb->texture, + PIPE_BIND_DEPTH_STENCIL); + dsrb->surface = pipe->create_surface(pipe, + dsrb->texture, + &surf_tmpl); + if (!dsrb->surface) { + pipe_resource_reference(&dsrb->texture, NULL); + return TRUE; } + dsrb->width = width; + dsrb->height = height; + + assert(dsrb->surface->width == width); + assert(dsrb->surface->height == height); + + return TRUE; +} + +void vg_validate_state(struct vg_context *ctx) +{ + struct st_framebuffer *stfb = ctx->draw_buffer; + + vg_manager_validate_framebuffer(ctx); + + if (vg_context_update_depth_stencil_rb(ctx, stfb->width, stfb->height)) + ctx->state.dirty |= DEPTH_STENCIL_DIRTY; + + /* blend state depends on fb format */ + if (ctx->state.dirty & FRAMEBUFFER_DIRTY) + ctx->state.dirty |= BLEND_DIRTY; + + renderer_validate(ctx->renderer, ctx->state.dirty, + ctx->draw_buffer, &ctx->state.vg); + + ctx->state.dirty = 0; + shader_set_masking(ctx->shader, ctx->state.vg.masking); shader_set_image_mode(ctx->shader, ctx->state.vg.image_mode); - - ctx->state.dirty = NONE_DIRTY; + shader_set_color_transform(ctx->shader, ctx->state.vg.color_transform); } VGboolean vg_object_is_valid(void *ptr, enum vg_object_type type) @@ -470,130 +434,94 @@ void vg_set_error(struct vg_context *ctx, ctx->_error = code; } -void vg_prepare_blend_surface(struct vg_context *ctx) +static void vg_prepare_blend_texture(struct vg_context *ctx, + struct pipe_sampler_view *src) +{ + struct st_framebuffer *stfb = ctx->draw_buffer; + struct pipe_surface *surf; + struct pipe_surface surf_tmpl; + + vg_context_update_blend_texture_view(ctx, stfb->width, stfb->height); + + memset(&surf_tmpl, 0, sizeof(surf_tmpl)); + u_surface_default_template(&surf_tmpl, stfb->blend_texture_view->texture, + PIPE_BIND_RENDER_TARGET); + surf = ctx->pipe->create_surface(ctx->pipe, + stfb->blend_texture_view->texture, + &surf_tmpl); + if (surf) { + util_blit_pixels_tex(ctx->blit, + src, 0, 0, stfb->width, stfb->height, + surf, 0, 0, stfb->width, stfb->height, + 0.0, PIPE_TEX_MIPFILTER_NEAREST); + + pipe_surface_reference(&surf, NULL); + } +} + +struct pipe_sampler_view *vg_prepare_blend_surface(struct vg_context *ctx) { - struct pipe_surface *dest_surface = NULL; struct pipe_context *pipe = ctx->pipe; struct pipe_sampler_view *view; struct pipe_sampler_view view_templ; struct st_framebuffer *stfb = ctx->draw_buffer; struct st_renderbuffer *strb = stfb->strb; - /* first finish all pending rendering */ - vgFinish(); + vg_validate_state(ctx); u_sampler_view_default_template(&view_templ, strb->texture, strb->texture->format); view = pipe->create_sampler_view(pipe, strb->texture, &view_templ); - dest_surface = pipe->screen->get_tex_surface(pipe->screen, - stfb->blend_texture_view->texture, - 0, 0, 0, - PIPE_BIND_RENDER_TARGET); - /* flip it, because we want to use it as a sampler */ - util_blit_pixels_tex(ctx->blit, - view, - 0, strb->height, - strb->width, 0, - dest_surface, - 0, 0, - strb->width, strb->height, - 0.0, PIPE_TEX_MIPFILTER_NEAREST); - - if (dest_surface) - pipe_surface_reference(&dest_surface, NULL); - - /* make sure it's complete */ - vgFinish(); + vg_prepare_blend_texture(ctx, view); pipe_sampler_view_reference(&view, NULL); + + return stfb->blend_texture_view; } -void vg_prepare_blend_surface_from_mask(struct vg_context *ctx) +struct pipe_sampler_view *vg_prepare_blend_surface_from_mask(struct vg_context *ctx) { - struct pipe_surface *dest_surface = NULL; - struct pipe_context *pipe = ctx->pipe; struct st_framebuffer *stfb = ctx->draw_buffer; - struct st_renderbuffer *strb = stfb->strb; vg_validate_state(ctx); - /* first finish all pending rendering */ - vgFinish(); - - dest_surface = pipe->screen->get_tex_surface(pipe->screen, - stfb->blend_texture_view->texture, - 0, 0, 0, - PIPE_BIND_RENDER_TARGET); - - /* flip it, because we want to use it as a sampler */ - util_blit_pixels_tex(ctx->blit, - stfb->alpha_mask_view, - 0, strb->height, - strb->width, 0, - dest_surface, - 0, 0, - strb->width, strb->height, - 0.0, PIPE_TEX_MIPFILTER_NEAREST); - - /* make sure it's complete */ - vgFinish(); - - if (dest_surface) - pipe_surface_reference(&dest_surface, NULL); + vg_context_update_surface_mask_view(ctx, stfb->width, stfb->height); + vg_prepare_blend_texture(ctx, stfb->surface_mask_view); + + return stfb->blend_texture_view; } -void * vg_plain_vs(struct vg_context *ctx) +struct pipe_sampler_view *vg_get_surface_mask(struct vg_context *ctx) { - if (!ctx->plain_vs) { - ctx->plain_vs = shader_create_from_text(ctx->pipe, - vs_plain_asm, - 200, - PIPE_SHADER_VERTEX); - } + struct st_framebuffer *stfb = ctx->draw_buffer; - return ctx->plain_vs->driver; -} + vg_context_update_surface_mask_view(ctx, stfb->width, stfb->height); + return stfb->surface_mask_view; +} -void * vg_clear_vs(struct vg_context *ctx) +/** + * A transformation from window coordinates to paint coordinates. + */ +VGboolean vg_get_paint_matrix(struct vg_context *ctx, + const struct matrix *paint_to_user, + const struct matrix *user_to_surface, + struct matrix *mat) { - if (!ctx->clear_vs) { - ctx->clear_vs = shader_create_from_text(ctx->pipe, - vs_clear_asm, - 200, - PIPE_SHADER_VERTEX); - } + struct matrix tmp; - return ctx->clear_vs->driver; -} + /* get user-to-paint matrix */ + memcpy(mat, paint_to_user, sizeof(*paint_to_user)); + if (!matrix_invert(mat)) + return VG_FALSE; -void * vg_texture_vs(struct vg_context *ctx) -{ - if (!ctx->texture_vs) { - ctx->texture_vs = shader_create_from_text(ctx->pipe, - vs_texture_asm, - 200, - PIPE_SHADER_VERTEX); - } + /* get surface-to-user matrix */ + memcpy(&tmp, user_to_surface, sizeof(*user_to_surface)); + if (!matrix_invert(&tmp)) + return VG_FALSE; - return ctx->texture_vs->driver; -} + matrix_mult(mat, &tmp); -void vg_set_viewport(struct vg_context *ctx, VegaOrientation orientation) -{ - struct pipe_viewport_state viewport; - struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; - VGfloat y_scale = (orientation == VEGA_Y0_BOTTOM) ? -2.f : 2.f; - - viewport.scale[0] = fb->width / 2.f; - viewport.scale[1] = fb->height / y_scale; - viewport.scale[2] = 1.0; - viewport.scale[3] = 1.0; - viewport.translate[0] = fb->width / 2.f; - viewport.translate[1] = fb->height / 2.f; - viewport.translate[2] = 0.0; - viewport.translate[3] = 0.0; - - cso_set_viewport(ctx->cso_context, &viewport); + return VG_TRUE; } diff --git a/src/gallium/state_trackers/vega/vg_context.h b/src/gallium/state_trackers/vega/vg_context.h index 80a6c07c693..d616a20a3d9 100644 --- a/src/gallium/state_trackers/vega/vg_context.h +++ b/src/gallium/state_trackers/vega/vg_context.h @@ -56,7 +56,7 @@ struct st_framebuffer { struct st_renderbuffer *strb; struct st_renderbuffer *dsrb; - struct pipe_sampler_view *alpha_mask_view; + struct pipe_sampler_view *surface_mask_view; struct pipe_sampler_view *blend_texture_view; @@ -78,14 +78,13 @@ enum vg_object_type { VG_OBJECT_LAST }; enum dirty_state { - NONE_DIRTY = 0<<0, - BLEND_DIRTY = 1<<1, - RASTERIZER_DIRTY = 1<<2, - VIEWPORT_DIRTY = 1<<3, - VS_DIRTY = 1<<4, - DEPTH_STENCIL_DIRTY = 1<<5, - ALL_DIRTY = BLEND_DIRTY | RASTERIZER_DIRTY | - VIEWPORT_DIRTY | VS_DIRTY | DEPTH_STENCIL_DIRTY + BLEND_DIRTY = 1 << 0, + FRAMEBUFFER_DIRTY = 1 << 1, + DEPTH_STENCIL_DIRTY = 1 << 2, + + ALL_DIRTY = BLEND_DIRTY | + FRAMEBUFFER_DIRTY | + DEPTH_STENCIL_DIRTY }; struct vg_context @@ -98,13 +97,6 @@ struct vg_context struct { struct vg_state vg; - struct { - struct pipe_blend_state blend; - struct pipe_rasterizer_state rasterizer; - struct pipe_shader_state vs_state; - struct pipe_depth_stencil_alpha_state dsa; - struct pipe_framebuffer_state fb; - } g3d; VGbitfield dirty; } state; @@ -116,14 +108,6 @@ struct vg_context struct cso_hash *owned_objects[VG_OBJECT_LAST]; struct { - struct pipe_shader_state vert_shader; - struct pipe_shader_state frag_shader; - struct pipe_rasterizer_state raster; - void *fs; - float vertices[4][2][4]; /**< vertex pos + color */ - } clear; - - struct { struct pipe_resource *cbuf; struct pipe_sampler_state sampler; @@ -133,31 +117,16 @@ struct vg_context struct vg_shader *set_fs; } mask; - struct vg_shader *pass_through_depth_fs; - struct cso_context *cso_context; - struct pipe_resource *stencil_quad; - VGfloat stencil_vertices[4][2][4]; - struct renderer *renderer; struct shaders_cache *sc; struct shader *shader; struct pipe_sampler_state blend_sampler; - struct { - struct pipe_resource *buffer; - void *color_matrix_fs; - } filter; struct vg_paint *default_paint; struct blit_state *blit; - - struct vg_shader *plain_vs; - struct vg_shader *clear_vs; - struct vg_shader *texture_vs; - struct pipe_resource *vs_const_buffer; - struct pipe_vertex_element velems[2]; }; struct vg_object { @@ -189,9 +158,15 @@ void vg_validate_state(struct vg_context *ctx); void vg_set_error(struct vg_context *ctx, VGErrorCode code); -void vg_prepare_blend_surface(struct vg_context *ctx); -void vg_prepare_blend_surface_from_mask(struct vg_context *ctx); +struct pipe_sampler_view *vg_prepare_blend_surface(struct vg_context *ctx); +struct pipe_sampler_view *vg_prepare_blend_surface_from_mask(struct vg_context *ctx); +struct pipe_sampler_view *vg_get_surface_mask(struct vg_context *ctx); + +VGboolean vg_get_paint_matrix(struct vg_context *ctx, + const struct matrix *paint_to_user, + const struct matrix *user_to_surface, + struct matrix *mat); static INLINE VGboolean is_aligned_to(const void *ptr, VGbyte alignment) { @@ -292,13 +267,4 @@ static INLINE void vg_bound_rect(VGfloat coords[4], } } -void *vg_plain_vs(struct vg_context *ctx); -void *vg_clear_vs(struct vg_context *ctx); -void *vg_texture_vs(struct vg_context *ctx); -typedef enum { - VEGA_Y0_TOP, - VEGA_Y0_BOTTOM -} VegaOrientation; -void vg_set_viewport(struct vg_context *ctx, VegaOrientation orientation); - #endif diff --git a/src/gallium/state_trackers/vega/vg_manager.c b/src/gallium/state_trackers/vega/vg_manager.c index bb15ec024f2..de935768b22 100644 --- a/src/gallium/state_trackers/vega/vg_manager.c +++ b/src/gallium/state_trackers/vega/vg_manager.c @@ -33,168 +33,22 @@ #include "pipe/p_screen.h" #include "util/u_memory.h" #include "util/u_inlines.h" -#include "util/u_format.h" #include "util/u_sampler.h" +#include "util/u_box.h" +#include "util/u_surface.h" #include "vg_api.h" #include "vg_manager.h" #include "vg_context.h" #include "image.h" -#include "mask.h" #include "api.h" -static struct pipe_resource * -create_texture(struct pipe_context *pipe, enum pipe_format format, - VGint width, VGint height) -{ - struct pipe_resource templ; - - memset(&templ, 0, sizeof(templ)); - - if (format != PIPE_FORMAT_NONE) { - templ.format = format; - } - else { - templ.format = PIPE_FORMAT_B8G8R8A8_UNORM; - } - - templ.target = PIPE_TEXTURE_2D; - templ.width0 = width; - templ.height0 = height; - templ.depth0 = 1; - templ.last_level = 0; - - if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) { - templ.bind = PIPE_BIND_DEPTH_STENCIL; - } else { - templ.bind = (PIPE_BIND_DISPLAY_TARGET | - PIPE_BIND_RENDER_TARGET | - PIPE_BIND_SAMPLER_VIEW); - } - - return pipe->screen->resource_create(pipe->screen, &templ); -} - -static struct pipe_sampler_view * -create_tex_and_view(struct pipe_context *pipe, enum pipe_format format, - VGint width, VGint height) -{ - struct pipe_resource *texture; - struct pipe_sampler_view view_templ; - struct pipe_sampler_view *view; - - texture = create_texture(pipe, format, width, height); - - if (!texture) - return NULL; - - u_sampler_view_default_template(&view_templ, texture, texture->format); - view = pipe->create_sampler_view(pipe, texture, &view_templ); - /* want the texture to go away if the view is freed */ - pipe_resource_reference(&texture, NULL); - - return view; -} - -static void -setup_new_alpha_mask(struct vg_context *ctx, struct st_framebuffer *stfb) -{ - struct pipe_context *pipe = ctx->pipe; - struct pipe_sampler_view *old_sampler_view = stfb->alpha_mask_view; - - /* - we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to - this texture and use it as a sampler, so while this wastes some - space it makes both of those a lot simpler - */ - stfb->alpha_mask_view = create_tex_and_view(pipe, - PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height); - - if (!stfb->alpha_mask_view) { - if (old_sampler_view) - pipe_sampler_view_reference(&old_sampler_view, NULL); - return; - } - - /* XXX could this call be avoided? */ - vg_validate_state(ctx); - - /* alpha mask starts with 1.f alpha */ - mask_fill(0, 0, stfb->width, stfb->height, 1.f); - - /* if we had an old surface copy it over */ - if (old_sampler_view) { - struct pipe_subresource subsurf, subold_surf; - subsurf.face = 0; - subsurf.level = 0; - subold_surf.face = 0; - subold_surf.level = 0; - pipe->resource_copy_region(pipe, - stfb->alpha_mask_view->texture, - subsurf, - 0, 0, 0, - old_sampler_view->texture, - subold_surf, - 0, 0, 0, - MIN2(old_sampler_view->texture->width0, - stfb->alpha_mask_view->texture->width0), - MIN2(old_sampler_view->texture->height0, - stfb->alpha_mask_view->texture->height0)); - } - - /* Free the old texture - */ - if (old_sampler_view) - pipe_sampler_view_reference(&old_sampler_view, NULL); -} - -static boolean -vg_context_update_depth_stencil_rb(struct vg_context * ctx, - uint width, uint height) -{ - struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb; - struct pipe_context *pipe = ctx->pipe; - unsigned surface_usage; - - if ((dsrb->width == width && dsrb->height == height) && dsrb->texture) - return FALSE; - - /* unreference existing ones */ - pipe_surface_reference(&dsrb->surface, NULL); - pipe_resource_reference(&dsrb->texture, NULL); - dsrb->width = dsrb->height = 0; - - /* Probably need dedicated flags for surface usage too: - */ - surface_usage = PIPE_BIND_DEPTH_STENCIL; /* XXX: was: RENDER_TARGET */ - - dsrb->texture = create_texture(pipe, dsrb->format, width, height); - if (!dsrb->texture) - return TRUE; - - dsrb->surface = pipe->screen->get_tex_surface(pipe->screen, - dsrb->texture, - 0, 0, 0, - surface_usage); - if (!dsrb->surface) { - pipe_resource_reference(&dsrb->texture, NULL); - return TRUE; - } - - dsrb->width = width; - dsrb->height = height; - - assert(dsrb->surface->width == width); - assert(dsrb->surface->height == height); - - return TRUE; -} - static boolean vg_context_update_color_rb(struct vg_context *ctx, struct pipe_resource *pt) { struct st_renderbuffer *strb = ctx->draw_buffer->strb; - struct pipe_screen *screen = ctx->pipe->screen; + struct pipe_context *pipe = ctx->pipe; + struct pipe_surface surf_tmpl; if (strb->texture == pt) { pipe_resource_reference(&pt, NULL); @@ -207,8 +61,12 @@ vg_context_update_color_rb(struct vg_context *ctx, struct pipe_resource *pt) strb->width = strb->height = 0; strb->texture = pt; - strb->surface = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, - PIPE_BIND_RENDER_TARGET); + + memset(&surf_tmpl, 0, sizeof(surf_tmpl)); + u_surface_default_template(&surf_tmpl, strb->texture, + PIPE_BIND_RENDER_TARGET); + strb->surface = pipe->create_surface(pipe, strb->texture, &surf_tmpl); + if (!strb->surface) { pipe_resource_reference(&strb->texture, NULL); return TRUE; @@ -220,49 +78,6 @@ vg_context_update_color_rb(struct vg_context *ctx, struct pipe_resource *pt) return TRUE; } -static void -vg_context_update_draw_buffer(struct vg_context *ctx, struct pipe_resource *pt) -{ - struct st_framebuffer *stfb = ctx->draw_buffer; - boolean new_cbuf, new_zsbuf, new_size; - - new_cbuf = vg_context_update_color_rb(ctx, pt); - new_zsbuf = - vg_context_update_depth_stencil_rb(ctx, pt->width0, pt->height0); - - new_size = (stfb->width != pt->width0 || stfb->height != pt->height0); - stfb->width = pt->width0; - stfb->height = pt->height0; - - if (new_cbuf || new_zsbuf || new_size) { - struct pipe_framebuffer_state *state = &ctx->state.g3d.fb; - - memset(state, 0, sizeof(struct pipe_framebuffer_state)); - state->width = stfb->width; - state->height = stfb->height; - state->nr_cbufs = 1; - state->cbufs[0] = stfb->strb->surface; - state->zsbuf = stfb->dsrb->surface; - - cso_set_framebuffer(ctx->cso_context, state); - } - - if (new_zsbuf || new_size) { - ctx->state.dirty |= VIEWPORT_DIRTY; - ctx->state.dirty |= DEPTH_STENCIL_DIRTY;/*to reset the scissors*/ - - ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL, NULL, 0.0, 0); - - /* we need all the other state already set */ - - setup_new_alpha_mask(ctx, stfb); - - pipe_sampler_view_reference( &stfb->blend_texture_view, NULL); - stfb->blend_texture_view = create_tex_and_view(ctx->pipe, - PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height); - } -} - /** * Flush the front buffer if the current context renders to the front buffer. */ @@ -304,15 +119,16 @@ vg_manager_validate_framebuffer(struct vg_context *ctx) if (!stfb->iface->validate(stfb->iface, &stfb->strb_att, 1, &pt) || !pt) return; - /* - * unset draw_buffer_invalid first because vg_context_update_draw_buffer - * will cause the framebuffer to be validated again because of a call to - * vg_validate_state - */ p_atomic_set(&ctx->draw_buffer_invalid, FALSE); - vg_context_update_draw_buffer(ctx, pt); -} + if (vg_context_update_color_rb(ctx, pt) || + stfb->width != pt->width0 || + stfb->height != pt->height0) + ctx->state.dirty |= FRAMEBUFFER_DIRTY; + + stfb->width = pt->width0; + stfb->height = pt->height0; +} static void vg_context_notify_invalid_framebuffer(struct st_context_iface *stctxi, @@ -336,7 +152,10 @@ static void vg_context_destroy(struct st_context_iface *stctxi) { struct vg_context *ctx = (struct vg_context *) stctxi; + struct pipe_context *pipe = ctx->pipe; + vg_destroy_context(ctx); + pipe->destroy(pipe); } static struct st_context_iface * |