| /********************************************************** |
| * Copyright 2009-2011 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, sublicense, 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 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 |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| * 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. |
| * |
| ********************************************************* |
| * Authors: |
| * Zack Rusin <zackr-at-vmware-dot-com> |
| * Thomas Hellstrom <thellstrom-at-vmware-dot-com> |
| */ |
| #include "xa_context.h" |
| #include "xa_priv.h" |
| #include "cso_cache/cso_context.h" |
| #include "util/u_inlines.h" |
| #include "util/u_rect.h" |
| #include "util/u_surface.h" |
| #include "pipe/p_context.h" |
| |
| |
| XA_EXPORT struct xa_context * |
| xa_context_default(struct xa_tracker *xa) |
| { |
| return xa->default_ctx; |
| } |
| |
| XA_EXPORT struct xa_context * |
| xa_context_create(struct xa_tracker *xa) |
| { |
| struct xa_context *ctx = calloc(1, sizeof(*ctx)); |
| |
| ctx->xa = xa; |
| ctx->pipe = xa->screen->context_create(xa->screen, NULL); |
| ctx->cso = cso_create_context(ctx->pipe); |
| ctx->shaders = xa_shaders_create(ctx); |
| renderer_init_state(ctx); |
| |
| return ctx; |
| } |
| |
| XA_EXPORT void |
| xa_context_destroy(struct xa_context *r) |
| { |
| struct pipe_resource **vsbuf = &r->vs_const_buffer; |
| struct pipe_resource **fsbuf = &r->fs_const_buffer; |
| |
| if (*vsbuf) |
| pipe_resource_reference(vsbuf, NULL); |
| |
| if (*fsbuf) |
| pipe_resource_reference(fsbuf, NULL); |
| |
| if (r->shaders) { |
| xa_shaders_destroy(r->shaders); |
| r->shaders = NULL; |
| } |
| |
| xa_ctx_sampler_views_destroy(r); |
| |
| if (r->cso) { |
| cso_release_all(r->cso); |
| cso_destroy_context(r->cso); |
| r->cso = NULL; |
| } |
| |
| r->pipe->destroy(r->pipe); |
| } |
| |
| XA_EXPORT int |
| xa_surface_dma(struct xa_context *ctx, |
| struct xa_surface *srf, |
| void *data, |
| unsigned int pitch, |
| int to_surface, struct xa_box *boxes, unsigned int num_boxes) |
| { |
| struct pipe_transfer *transfer; |
| void *map; |
| int w, h, i; |
| enum pipe_transfer_usage transfer_direction; |
| struct pipe_context *pipe = ctx->pipe; |
| |
| transfer_direction = (to_surface ? PIPE_TRANSFER_WRITE : |
| PIPE_TRANSFER_READ); |
| |
| for (i = 0; i < num_boxes; ++i, ++boxes) { |
| w = boxes->x2 - boxes->x1; |
| h = boxes->y2 - boxes->y1; |
| |
| transfer = pipe_get_transfer(pipe, srf->tex, 0, 0, |
| transfer_direction, boxes->x1, boxes->y1, |
| w, h); |
| if (!transfer) |
| return -XA_ERR_NORES; |
| |
| map = pipe_transfer_map(ctx->pipe, transfer); |
| if (!map) |
| goto out_no_map; |
| |
| if (to_surface) { |
| util_copy_rect(map, srf->tex->format, transfer->stride, |
| 0, 0, w, h, data, pitch, boxes->x1, boxes->y1); |
| } else { |
| util_copy_rect(data, srf->tex->format, pitch, |
| boxes->x1, boxes->y1, w, h, map, transfer->stride, 0, |
| 0); |
| } |
| pipe->transfer_unmap(pipe, transfer); |
| pipe->transfer_destroy(pipe, transfer); |
| if (to_surface) |
| pipe->flush(pipe, &ctx->last_fence); |
| } |
| return XA_ERR_NONE; |
| out_no_map: |
| pipe->transfer_destroy(pipe, transfer); |
| return -XA_ERR_NORES; |
| } |
| |
| XA_EXPORT void * |
| xa_surface_map(struct xa_context *ctx, |
| struct xa_surface *srf, unsigned int usage) |
| { |
| void *map; |
| unsigned int transfer_direction = 0; |
| struct pipe_context *pipe = ctx->pipe; |
| |
| /* |
| * A surface may only have a single map. |
| */ |
| if (srf->transfer) |
| return NULL; |
| |
| if (usage & XA_MAP_READ) |
| transfer_direction = PIPE_TRANSFER_READ; |
| if (usage & XA_MAP_WRITE) |
| transfer_direction = PIPE_TRANSFER_WRITE; |
| |
| if (!transfer_direction) |
| return NULL; |
| |
| srf->transfer = pipe_get_transfer(pipe, srf->tex, 0, 0, |
| transfer_direction, 0, 0, |
| srf->tex->width0, srf->tex->height0); |
| if (!srf->transfer) |
| return NULL; |
| |
| map = pipe_transfer_map(pipe, srf->transfer); |
| if (!map) |
| pipe->transfer_destroy(pipe, srf->transfer); |
| |
| srf->mapping_pipe = pipe; |
| return map; |
| } |
| |
| XA_EXPORT void |
| xa_surface_unmap(struct xa_surface *srf) |
| { |
| if (srf->transfer) { |
| struct pipe_context *pipe = srf->mapping_pipe; |
| |
| pipe->transfer_unmap(pipe, srf->transfer); |
| pipe->transfer_destroy(pipe, srf->transfer); |
| srf->transfer = NULL; |
| } |
| } |
| |
| int |
| xa_ctx_srf_create(struct xa_context *ctx, struct xa_surface *dst) |
| { |
| struct pipe_screen *screen = ctx->pipe->screen; |
| struct pipe_surface srf_templ; |
| |
| if (ctx->srf) |
| return -XA_ERR_INVAL; |
| |
| if (!screen->is_format_supported(screen, dst->tex->format, |
| PIPE_TEXTURE_2D, 0, |
| PIPE_BIND_RENDER_TARGET)) |
| return -XA_ERR_INVAL; |
| |
| u_surface_default_template(&srf_templ, dst->tex, |
| PIPE_BIND_RENDER_TARGET); |
| ctx->srf = ctx->pipe->create_surface(ctx->pipe, dst->tex, &srf_templ); |
| if (!ctx->srf) |
| return -XA_ERR_NORES; |
| |
| return XA_ERR_NONE; |
| } |
| |
| void |
| xa_ctx_srf_destroy(struct xa_context *ctx) |
| { |
| pipe_surface_reference(&ctx->srf, NULL); |
| } |
| |
| XA_EXPORT int |
| xa_copy_prepare(struct xa_context *ctx, |
| struct xa_surface *dst, struct xa_surface *src) |
| { |
| if (src == dst || ctx->srf != NULL) |
| return -XA_ERR_INVAL; |
| |
| if (src->tex->format != dst->tex->format) { |
| int ret = xa_ctx_srf_create(ctx, dst); |
| if (ret != XA_ERR_NONE) |
| return ret; |
| renderer_copy_prepare(ctx, ctx->srf, src->tex, |
| src->fdesc.xa_format, |
| dst->fdesc.xa_format); |
| ctx->simple_copy = 0; |
| } else |
| ctx->simple_copy = 1; |
| |
| ctx->src = src; |
| ctx->dst = dst; |
| xa_ctx_srf_destroy(ctx); |
| |
| return 0; |
| } |
| |
| XA_EXPORT void |
| xa_copy(struct xa_context *ctx, |
| int dx, int dy, int sx, int sy, int width, int height) |
| { |
| struct pipe_box src_box; |
| |
| if (ctx->simple_copy) { |
| u_box_2d(sx, sy, width, height, &src_box); |
| ctx->pipe->resource_copy_region(ctx->pipe, |
| ctx->dst->tex, 0, dx, dy, 0, |
| ctx->src->tex, |
| 0, &src_box); |
| } else |
| renderer_copy(ctx, dx, dy, sx, sy, width, height, |
| (float) ctx->src->tex->width0, |
| (float) ctx->src->tex->height0); |
| } |
| |
| XA_EXPORT void |
| xa_copy_done(struct xa_context *ctx) |
| { |
| if (!ctx->simple_copy) { |
| renderer_draw_flush(ctx); |
| ctx->pipe->flush(ctx->pipe, &ctx->last_fence); |
| } else |
| ctx->pipe->flush(ctx->pipe, &ctx->last_fence); |
| } |
| |
| static void |
| bind_solid_blend_state(struct xa_context *ctx) |
| { |
| 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, &blend); |
| } |
| |
| XA_EXPORT int |
| xa_solid_prepare(struct xa_context *ctx, struct xa_surface *dst, |
| uint32_t fg) |
| { |
| unsigned vs_traits, fs_traits; |
| struct xa_shader shader; |
| int width, height; |
| int ret; |
| |
| ret = xa_ctx_srf_create(ctx, dst); |
| if (ret != XA_ERR_NONE) |
| return ret; |
| |
| if (ctx->srf->format == PIPE_FORMAT_L8_UNORM) |
| xa_pixel_to_float4_a8(fg, ctx->solid_color); |
| else |
| xa_pixel_to_float4(fg, ctx->solid_color); |
| ctx->has_solid_color = 1; |
| |
| ctx->dst = dst; |
| width = ctx->srf->width; |
| height = ctx->srf->height; |
| |
| #if 0 |
| debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n", |
| (fg >> 24) & 0xff, (fg >> 16) & 0xff, |
| (fg >> 8) & 0xff, (fg >> 0) & 0xff, |
| exa->solid_color[0], exa->solid_color[1], |
| exa->solid_color[2], exa->solid_color[3]); |
| #endif |
| |
| vs_traits = VS_SOLID_FILL; |
| fs_traits = FS_SOLID_FILL; |
| |
| renderer_bind_destination(ctx, ctx->srf, width, height); |
| bind_solid_blend_state(ctx); |
| cso_set_samplers(ctx->cso, PIPE_SHADER_FRAGMENT, 0, NULL); |
| cso_set_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT, 0, NULL); |
| |
| shader = xa_shaders_get(ctx->shaders, vs_traits, fs_traits); |
| cso_set_vertex_shader_handle(ctx->cso, shader.vs); |
| cso_set_fragment_shader_handle(ctx->cso, shader.fs); |
| |
| renderer_begin_solid(ctx); |
| |
| xa_ctx_srf_destroy(ctx); |
| return XA_ERR_NONE; |
| } |
| |
| XA_EXPORT void |
| xa_solid(struct xa_context *ctx, int x, int y, int width, int height) |
| { |
| renderer_solid(ctx, x, y, x + width, y + height, ctx->solid_color); |
| } |
| |
| XA_EXPORT void |
| xa_solid_done(struct xa_context *ctx) |
| { |
| renderer_draw_flush(ctx); |
| ctx->pipe->flush(ctx->pipe, &ctx->last_fence); |
| |
| ctx->comp = NULL; |
| ctx->has_solid_color = FALSE; |
| ctx->num_bound_samplers = 0; |
| } |
| |
| XA_EXPORT struct xa_fence * |
| xa_fence_get(struct xa_context *ctx) |
| { |
| struct xa_fence *fence = calloc(1, sizeof(*fence)); |
| struct pipe_screen *screen = ctx->xa->screen; |
| |
| if (!fence) |
| return NULL; |
| |
| fence->xa = ctx->xa; |
| |
| if (ctx->last_fence == NULL) |
| fence->pipe_fence = NULL; |
| else |
| screen->fence_reference(screen, &fence->pipe_fence, ctx->last_fence); |
| |
| return fence; |
| } |
| |
| XA_EXPORT int |
| xa_fence_wait(struct xa_fence *fence, uint64_t timeout) |
| { |
| if (!fence) |
| return XA_ERR_NONE; |
| |
| if (fence->pipe_fence) { |
| struct pipe_screen *screen = fence->xa->screen; |
| boolean timed_out; |
| |
| timed_out = !screen->fence_finish(screen, fence->pipe_fence, timeout); |
| if (timed_out) |
| return -XA_ERR_BUSY; |
| |
| screen->fence_reference(screen, &fence->pipe_fence, NULL); |
| } |
| return XA_ERR_NONE; |
| } |
| |
| XA_EXPORT void |
| xa_fence_destroy(struct xa_fence *fence) |
| { |
| if (!fence) |
| return; |
| |
| if (fence->pipe_fence) { |
| struct pipe_screen *screen = fence->xa->screen; |
| |
| screen->fence_reference(screen, &fence->pipe_fence, NULL); |
| } |
| |
| free(fence); |
| } |
| |
| void |
| xa_ctx_sampler_views_destroy(struct xa_context *ctx) |
| { |
| int i; |
| |
| for (i = 0; i < ctx->num_bound_samplers; ++i) |
| pipe_sampler_view_reference(&ctx->bound_sampler_views[i], NULL); |
| ctx->num_bound_samplers = 0; |
| } |