diff options
Diffstat (limited to 'src/gallium/state_trackers/xorg')
-rw-r--r-- | src/gallium/state_trackers/xorg/Makefile | 23 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/SConscript | 36 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_composite.c | 583 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_composite.h | 36 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_crtc.c | 417 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_dri2.c | 467 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_driver.c | 1243 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_exa.c | 1088 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_exa.h | 81 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_exa_tgsi.c | 690 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_exa_tgsi.h | 59 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_output.c | 294 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_renderer.c | 716 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_renderer.h | 96 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_tracker.h | 218 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_winsys.h | 50 | ||||
-rw-r--r-- | src/gallium/state_trackers/xorg/xorg_xv.c | 768 |
17 files changed, 6865 insertions, 0 deletions
diff --git a/src/gallium/state_trackers/xorg/Makefile b/src/gallium/state_trackers/xorg/Makefile new file mode 100644 index 0000000000..cb2c3aea41 --- /dev/null +++ b/src/gallium/state_trackers/xorg/Makefile @@ -0,0 +1,23 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBNAME = xorgtracker + +LIBRARY_INCLUDES = \ + -DHAVE_CONFIG_H \ + $(shell pkg-config xextproto --atleast-version=7.0.99.1 \ + && echo "-DHAVE_XEXTPROTO_71") \ + $(shell pkg-config libkms --atleast-version=1.0 \ + && echo "-DHAVE_LIBKMS") \ + $(shell pkg-config libkms --silence-errors --cflags-only-I) \ + $(shell pkg-config --cflags-only-I pixman-1 xorg-server libdrm xproto) \ + -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/auxiliary \ + -I$(TOP)/include \ + -I$(TOP)/src/mesa \ + -I$(TOP)/src/mesa/drivers/dri/common \ + -I$(TOP)/src/mesa/main + +C_SOURCES = $(wildcard ./*.c) + +include ../../Makefile.template diff --git a/src/gallium/state_trackers/xorg/SConscript b/src/gallium/state_trackers/xorg/SConscript new file mode 100644 index 0000000000..0b598dab6e --- /dev/null +++ b/src/gallium/state_trackers/xorg/SConscript @@ -0,0 +1,36 @@ +####################################################################### +# SConscript for xorg state_tracker + +Import('*') + +if 'xorg' in env['statetrackers']: + + env = env.Clone() + + env.Append(CPPPATH = [ + '#/src/mesa', + ]) + + env.ParseConfig('pkg-config --cflags --libs libdrm xorg-server') + + conf = env.Configure() + + if conf.CheckHeader('X11/extensions/dpmsconst.h'): + env.Append(CPPDEFINES = [('HAVE_XEXTPROTO_71', '1')]) + + conf.Finish() + + st_xorg = env.ConvenienceLibrary( + target = 'st_xorg', + source = [ 'xorg_composite.c', + 'xorg_crtc.c', + 'xorg_dri2.c', + 'xorg_driver.c', + 'xorg_exa.c', + 'xorg_exa_tgsi.c', + 'xorg_output.c', + 'xorg_renderer.c', + 'xorg_xv.c', + ] + ) + Export('st_xorg') diff --git a/src/gallium/state_trackers/xorg/xorg_composite.c b/src/gallium/state_trackers/xorg/xorg_composite.c new file mode 100644 index 0000000000..4ff48026e5 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_composite.c @@ -0,0 +1,583 @@ +#include "xorg_composite.h" + +#include "xorg_renderer.h" +#include "xorg_exa_tgsi.h" + +#include "cso_cache/cso_context.h" +#include "util/u_sampler.h" + + +/*XXX also in Xrender.h but the including it here breaks compilition */ +#define XFixedToDouble(f) (((double) (f)) / 65536.) + +struct xorg_composite_blend { + int op : 8; + + unsigned alpha_dst : 4; + unsigned alpha_src : 4; + + unsigned rgb_src : 8; /**< PIPE_BLENDFACTOR_x */ + unsigned rgb_dst : 8; /**< PIPE_BLENDFACTOR_x */ +}; + +#define BLEND_OP_OVER 3 +static const struct xorg_composite_blend xorg_blends[] = { + { PictOpClear, + 0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO}, + { PictOpSrc, + 0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ZERO}, + { PictOpDst, + 0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE}, + { PictOpOver, + 0, 1, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, + { PictOpOverReverse, + 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE}, + { PictOpIn, + 1, 0, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_ZERO}, + { PictOpInReverse, + 0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_SRC_ALPHA}, + { PictOpOut, + 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ZERO}, + { PictOpOutReverse, + 0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, + { PictOpAtop, + 1, 1, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, + { PictOpAtopReverse, + 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_SRC_ALPHA}, + { PictOpXor, + 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, + { PictOpAdd, + 0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE}, +}; + + +static INLINE void +pixel_to_float4(Pixel pixel, float *color) +{ + CARD32 r, g, b, a; + + a = (pixel >> 24) & 0xff; + r = (pixel >> 16) & 0xff; + g = (pixel >> 8) & 0xff; + b = (pixel >> 0) & 0xff; + color[0] = ((float)r) / 255.; + color[1] = ((float)g) / 255.; + color[2] = ((float)b) / 255.; + color[3] = ((float)a) / 255.; +} + +static boolean +blend_for_op(struct xorg_composite_blend *blend, + int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + const int num_blends = + sizeof(xorg_blends)/sizeof(struct xorg_composite_blend); + int i; + boolean supported = FALSE; + + /* our default in case something goes wrong */ + *blend = xorg_blends[BLEND_OP_OVER]; + + for (i = 0; i < num_blends; ++i) { + if (xorg_blends[i].op == op) { + *blend = xorg_blends[i]; + supported = TRUE; + } + } + + /* If there's no dst alpha channel, adjust the blend op so that we'll treat + * it as always 1. */ + if (pDstPicture && + PICT_FORMAT_A(pDstPicture->format) == 0 && blend->alpha_dst) { + if (blend->rgb_src == PIPE_BLENDFACTOR_DST_ALPHA) + blend->rgb_src = PIPE_BLENDFACTOR_ONE; + else if (blend->rgb_src == PIPE_BLENDFACTOR_INV_DST_ALPHA) + blend->rgb_src = PIPE_BLENDFACTOR_ZERO; + } + + /* If the source alpha is being used, then we should only be in a case where + * the source blend factor is 0, and the source blend value is the mask + * channels multiplied by the source picture's alpha. */ + if (pMaskPicture && pMaskPicture->componentAlpha && + PICT_FORMAT_RGB(pMaskPicture->format) && blend->alpha_src) { + if (blend->rgb_dst == PIPE_BLENDFACTOR_SRC_ALPHA) { + blend->rgb_dst = PIPE_BLENDFACTOR_SRC_COLOR; + } else if (blend->rgb_dst == PIPE_BLENDFACTOR_INV_SRC_ALPHA) { + blend->rgb_dst = PIPE_BLENDFACTOR_INV_SRC_COLOR; + } + } + + return supported; +} + +static INLINE int +render_repeat_to_gallium(int mode) +{ + switch(mode) { + case RepeatNone: + return PIPE_TEX_WRAP_CLAMP_TO_BORDER; + case RepeatNormal: + return PIPE_TEX_WRAP_REPEAT; + case RepeatReflect: + return PIPE_TEX_WRAP_MIRROR_REPEAT; + case RepeatPad: + return PIPE_TEX_WRAP_CLAMP_TO_EDGE; + default: + debug_printf("Unsupported repeat mode\n"); + } + return PIPE_TEX_WRAP_REPEAT; +} + +static INLINE boolean +render_filter_to_gallium(int xrender_filter, int *out_filter) +{ + + switch (xrender_filter) { + case PictFilterNearest: + *out_filter = PIPE_TEX_FILTER_NEAREST; + break; + case PictFilterBilinear: + *out_filter = PIPE_TEX_FILTER_LINEAR; + break; + case PictFilterFast: + *out_filter = PIPE_TEX_FILTER_NEAREST; + break; + case PictFilterGood: + *out_filter = PIPE_TEX_FILTER_LINEAR; + break; + case PictFilterBest: + *out_filter = PIPE_TEX_FILTER_LINEAR; + break; + case PictFilterConvolution: + *out_filter = PIPE_TEX_FILTER_NEAREST; + return FALSE; + default: + debug_printf("Unknown xrender filter\n"); + *out_filter = PIPE_TEX_FILTER_NEAREST; + return FALSE; + } + + return TRUE; +} + +static boolean is_filter_accelerated(PicturePtr pic) +{ + int filter; + if (pic && !render_filter_to_gallium(pic->filter, &filter)) + return FALSE; + return TRUE; +} + +boolean xorg_composite_accelerated(int op, + PicturePtr pSrcPicture, + PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct xorg_composite_blend blend; + + if (!is_filter_accelerated(pSrcPicture) || + !is_filter_accelerated(pMaskPicture)) { + XORG_FALLBACK("Unsupported Xrender filter"); + } + + if (pSrcPicture->pSourcePict) { + if (pSrcPicture->pSourcePict->type != SourcePictTypeSolidFill) + XORG_FALLBACK("Gradients not enabled (haven't been well tested)"); + } + + if (blend_for_op(&blend, op, + pSrcPicture, pMaskPicture, pDstPicture)) { + /* Check for component alpha */ + if (pMaskPicture && pMaskPicture->componentAlpha && + PICT_FORMAT_RGB(pMaskPicture->format)) { + if (blend.alpha_src && blend.rgb_src != PIPE_BLENDFACTOR_ZERO) { + XORG_FALLBACK("Component alpha not supported with source " + "alpha and source value blending. (op=%d)", + op); + } + } + + return TRUE; + } + XORG_FALLBACK("Unsupported composition operation = %d", op); +} + +static void +bind_blend_state(struct exa_context *exa, int op, + PicturePtr pSrcPicture, + PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + struct xorg_composite_blend blend_opt; + struct pipe_blend_state blend; + + blend_for_op(&blend_opt, op, pSrcPicture, pMaskPicture, pDstPicture); + + memset(&blend, 0, sizeof(struct pipe_blend_state)); + blend.rt[0].blend_enable = 1; + blend.rt[0].colormask = PIPE_MASK_RGBA; + + blend.rt[0].rgb_src_factor = blend_opt.rgb_src; + blend.rt[0].alpha_src_factor = blend_opt.rgb_src; + blend.rt[0].rgb_dst_factor = blend_opt.rgb_dst; + blend.rt[0].alpha_dst_factor = blend_opt.rgb_dst; + + cso_set_blend(exa->renderer->cso, &blend); +} + +static unsigned +picture_format_fixups(struct exa_pixmap_priv *pSrc, PicturePtr pSrcPicture, boolean mask, + PicturePtr pDstPicture) +{ + boolean set_alpha = FALSE; + boolean swizzle = FALSE; + unsigned ret = 0; + + if (pSrc->picture_format == pSrcPicture->format) { + if (pSrc->picture_format == PICT_a8) { + if (mask) + return FS_MASK_LUMINANCE; + else if (pDstPicture->format != PICT_a8) { + /* if both dst and src are luminance then + * we don't want to swizzle the alpha (X) of the + * source into W component of the dst because + * it will break our destination */ + return FS_SRC_LUMINANCE; + } + } + return 0; + } + + if (pSrc->picture_format != PICT_a8r8g8b8) { + assert(!"can not handle formats"); + return 0; + } + + /* pSrc->picture_format == PICT_a8r8g8b8 */ + switch (pSrcPicture->format) { + case PICT_x8b8g8r8: + case PICT_b8g8r8: + set_alpha = TRUE; /* fall trough */ + case PICT_a8b8g8r8: + swizzle = TRUE; + break; + case PICT_x8r8g8b8: + case PICT_r8g8b8: + set_alpha = TRUE; /* fall through */ + case PICT_a8r8g8b8: + break; +#ifdef PICT_TYPE_BGRA + case PICT_b8g8r8a8: + case PICT_b8g8r8x8: + case PICT_a2r10g10b10: + case PICT_x2r10g10b10: + case PICT_a2b10g10r10: + case PICT_x2b10g10r10: +#endif + default: + assert(!"can not handle formats"); + return 0; + } + + if (set_alpha) + ret |= mask ? FS_MASK_SET_ALPHA : FS_SRC_SET_ALPHA; + if (swizzle) + ret |= mask ? FS_MASK_SWIZZLE_RGB : FS_SRC_SWIZZLE_RGB; + + return ret; +} + +static void +bind_shaders(struct exa_context *exa, int op, + PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture, + struct exa_pixmap_priv *pSrc, struct exa_pixmap_priv *pMask) +{ + unsigned vs_traits = 0, fs_traits = 0; + struct xorg_shader shader; + + exa->has_solid_color = FALSE; + + if (pSrcPicture) { + if (pSrcPicture->repeatType == RepeatNone && pSrcPicture->transform) + fs_traits |= FS_SRC_REPEAT_NONE; + + if (pSrcPicture->pSourcePict) { + if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) { + fs_traits |= FS_SOLID_FILL; + vs_traits |= VS_SOLID_FILL; + debug_assert(pSrcPicture->format == PICT_a8r8g8b8); + pixel_to_float4(pSrcPicture->pSourcePict->solidFill.color, + exa->solid_color); + exa->has_solid_color = TRUE; + } else { + debug_assert("!gradients not supported"); + } + } else { + fs_traits |= FS_COMPOSITE; + vs_traits |= VS_COMPOSITE; + } + + fs_traits |= picture_format_fixups(pSrc, pSrcPicture, FALSE, pDstPicture); + } + + if (pMaskPicture) { + vs_traits |= VS_MASK; + fs_traits |= FS_MASK; + if (pMaskPicture->repeatType == RepeatNone && pMaskPicture->transform) + fs_traits |= FS_MASK_REPEAT_NONE; + if (pMaskPicture->componentAlpha) { + struct xorg_composite_blend blend; + blend_for_op(&blend, op, + pSrcPicture, pMaskPicture, NULL); + if (blend.alpha_src) { + fs_traits |= FS_CA_SRCALPHA; + } else + fs_traits |= FS_CA_FULL; + } + + fs_traits |= picture_format_fixups(pMask, pMaskPicture, TRUE, pDstPicture); + } + + shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits); + cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs); + cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs); +} + +static void +bind_samplers(struct exa_context *exa, int op, + PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture, + struct exa_pixmap_priv *pSrc, + struct exa_pixmap_priv *pMask, + struct exa_pixmap_priv *pDst) +{ + struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; + struct pipe_sampler_state src_sampler, mask_sampler; + struct pipe_sampler_view view_templ; + struct pipe_sampler_view *src_view; + struct pipe_context *pipe = exa->pipe; + + exa->num_bound_samplers = 0; + + memset(&src_sampler, 0, sizeof(struct pipe_sampler_state)); + memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state)); + + if (pSrcPicture && pSrc) { + if (exa->has_solid_color) { + debug_assert(!"solid color with textures"); + samplers[0] = NULL; + pipe_sampler_view_reference(&exa->bound_sampler_views[0], NULL); + } else { + unsigned src_wrap = render_repeat_to_gallium( + pSrcPicture->repeatType); + int filter; + + render_filter_to_gallium(pSrcPicture->filter, &filter); + + src_sampler.wrap_s = src_wrap; + src_sampler.wrap_t = src_wrap; + src_sampler.min_img_filter = filter; + src_sampler.mag_img_filter = filter; + src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; + src_sampler.normalized_coords = 1; + samplers[0] = &src_sampler; + exa->num_bound_samplers = 1; + u_sampler_view_default_template(&view_templ, + pSrc->tex, + pSrc->tex->format); + src_view = pipe->create_sampler_view(pipe, pSrc->tex, &view_templ); + pipe_sampler_view_reference(&exa->bound_sampler_views[0], NULL); + exa->bound_sampler_views[0] = src_view; + } + } + + if (pMaskPicture && pMask) { + unsigned mask_wrap = render_repeat_to_gallium( + pMaskPicture->repeatType); + int filter; + + render_filter_to_gallium(pMaskPicture->filter, &filter); + + mask_sampler.wrap_s = mask_wrap; + mask_sampler.wrap_t = mask_wrap; + mask_sampler.min_img_filter = filter; + mask_sampler.mag_img_filter = filter; + src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; + mask_sampler.normalized_coords = 1; + samplers[1] = &mask_sampler; + exa->num_bound_samplers = 2; + u_sampler_view_default_template(&view_templ, + pMask->tex, + pMask->tex->format); + src_view = pipe->create_sampler_view(pipe, pMask->tex, &view_templ); + pipe_sampler_view_reference(&exa->bound_sampler_views[1], NULL); + exa->bound_sampler_views[1] = src_view; + } + + cso_set_samplers(exa->renderer->cso, exa->num_bound_samplers, + (const struct pipe_sampler_state **)samplers); + cso_set_fragment_sampler_views(exa->renderer->cso, exa->num_bound_samplers, + exa->bound_sampler_views); +} + + + +static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix) +{ + if (!trans) + return FALSE; + + matrix[0] = XFixedToDouble(trans->matrix[0][0]); + matrix[3] = XFixedToDouble(trans->matrix[0][1]); + matrix[6] = XFixedToDouble(trans->matrix[0][2]); + + matrix[1] = XFixedToDouble(trans->matrix[1][0]); + matrix[4] = XFixedToDouble(trans->matrix[1][1]); + matrix[7] = XFixedToDouble(trans->matrix[1][2]); + + matrix[2] = XFixedToDouble(trans->matrix[2][0]); + matrix[5] = XFixedToDouble(trans->matrix[2][1]); + matrix[8] = XFixedToDouble(trans->matrix[2][2]); + + return TRUE; +} + +static void +setup_transforms(struct exa_context *exa, + PicturePtr pSrcPicture, PicturePtr pMaskPicture) +{ + PictTransform *src_t = NULL; + PictTransform *mask_t = NULL; + + if (pSrcPicture) + src_t = pSrcPicture->transform; + if (pMaskPicture) + mask_t = pMaskPicture->transform; + + exa->transform.has_src = + matrix_from_pict_transform(src_t, exa->transform.src); + exa->transform.has_mask = + matrix_from_pict_transform(mask_t, exa->transform.mask); +} + +boolean xorg_composite_bind_state(struct exa_context *exa, + int op, + PicturePtr pSrcPicture, + PicturePtr pMaskPicture, + PicturePtr pDstPicture, + struct exa_pixmap_priv *pSrc, + struct exa_pixmap_priv *pMask, + struct exa_pixmap_priv *pDst) +{ + struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pDst); + + renderer_bind_destination(exa->renderer, dst_surf, + pDst->width, + pDst->height); + + bind_blend_state(exa, op, pSrcPicture, pMaskPicture, pDstPicture); + bind_shaders(exa, op, pSrcPicture, pMaskPicture, pDstPicture, pSrc, pMask); + bind_samplers(exa, op, pSrcPicture, pMaskPicture, + pDstPicture, pSrc, pMask, pDst); + + setup_transforms(exa, pSrcPicture, pMaskPicture); + + if (exa->num_bound_samplers == 0 ) { /* solid fill */ + renderer_begin_solid(exa->renderer); + } else { + renderer_begin_textures(exa->renderer, + exa->num_bound_samplers); + } + + + pipe_surface_reference(&dst_surf, NULL); + return TRUE; +} + +void xorg_composite(struct exa_context *exa, + struct exa_pixmap_priv *dst, + int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int width, int height) +{ + if (exa->num_bound_samplers == 0 ) { /* solid fill */ + renderer_solid(exa->renderer, + dstX, dstY, dstX + width, dstY + height, + exa->solid_color); + } else { + int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY}; + float *src_matrix = NULL; + float *mask_matrix = NULL; + + if (exa->transform.has_src) + src_matrix = exa->transform.src; + if (exa->transform.has_mask) + mask_matrix = exa->transform.mask; + + renderer_texture(exa->renderer, + pos, width, height, + exa->bound_sampler_views, + exa->num_bound_samplers, + src_matrix, mask_matrix); + } +} + +boolean xorg_solid_bind_state(struct exa_context *exa, + struct exa_pixmap_priv *pixmap, + Pixel fg) +{ + struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pixmap); + unsigned vs_traits, fs_traits; + struct xorg_shader shader; + + pixel_to_float4(fg, exa->solid_color); + exa->has_solid_color = TRUE; + +#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(exa->renderer, dst_surf, + pixmap->width, pixmap->height); + bind_blend_state(exa, PictOpSrc, NULL, NULL, NULL); + cso_set_samplers(exa->renderer->cso, 0, NULL); + cso_set_fragment_sampler_views(exa->renderer->cso, 0, NULL); + + shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits); + cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs); + cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs); + + renderer_begin_solid(exa->renderer); + + pipe_surface_reference(&dst_surf, NULL); + return TRUE; +} + +void xorg_solid(struct exa_context *exa, + struct exa_pixmap_priv *pixmap, + int x0, int y0, int x1, int y1) +{ + renderer_solid(exa->renderer, + x0, y0, x1, y1, exa->solid_color); +} + +void +xorg_composite_done(struct exa_context *exa) +{ + renderer_draw_flush(exa->renderer); + + exa->transform.has_src = FALSE; + exa->transform.has_mask = FALSE; + exa->has_solid_color = FALSE; + exa->num_bound_samplers = 0; +} diff --git a/src/gallium/state_trackers/xorg/xorg_composite.h b/src/gallium/state_trackers/xorg/xorg_composite.h new file mode 100644 index 0000000000..ec71ebfe0d --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_composite.h @@ -0,0 +1,36 @@ +#ifndef XORG_COMPOSITE_H +#define XORG_COMPOSITE_H + +#include "xorg_exa.h" + +boolean xorg_composite_accelerated(int op, + PicturePtr pSrcPicture, + PicturePtr pMaskPicture, + PicturePtr pDstPicture); + +boolean xorg_composite_bind_state(struct exa_context *exa, + int op, + PicturePtr pSrcPicture, + PicturePtr pMaskPicture, + PicturePtr pDstPicture, + struct exa_pixmap_priv *pSrc, + struct exa_pixmap_priv *pMask, + struct exa_pixmap_priv *pDst); + +void xorg_composite(struct exa_context *exa, + struct exa_pixmap_priv *dst, + int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int width, int height); + +boolean xorg_solid_bind_state(struct exa_context *exa, + struct exa_pixmap_priv *pixmap, + Pixel fg); +void xorg_solid(struct exa_context *exa, + struct exa_pixmap_priv *pixmap, + int x0, int y0, int x1, int y1); + + +void +xorg_composite_done(struct exa_context *exa); + +#endif diff --git a/src/gallium/state_trackers/xorg/xorg_crtc.c b/src/gallium/state_trackers/xorg/xorg_crtc.c new file mode 100644 index 0000000000..f1a07bd863 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_crtc.c @@ -0,0 +1,417 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <math.h> +#include <stdint.h> + +#include "xorg-server.h" +#include <xf86.h> +#include <xf86i2c.h> +#include <xf86Crtc.h> +#include <cursorstr.h> +#include "xorg_tracker.h" +#include "xf86Modes.h" + +#ifdef HAVE_XEXTPROTO_71 +#include <X11/extensions/dpmsconst.h> +#else +#define DPMS_SERVER +#include <X11/extensions/dpms.h> +#endif + +#include "util/u_inlines.h" +#include "util/u_rect.h" + +#ifdef HAVE_LIBKMS +#include "libkms.h" +#endif + +struct crtc_private +{ + drmModeCrtcPtr drm_crtc; + + /* hwcursor */ + struct pipe_resource *cursor_tex; + struct kms_bo *cursor_bo; + + unsigned cursor_handle; +}; + +static void +crtc_dpms(xf86CrtcPtr crtc, int mode) +{ + /* ScrnInfoPtr pScrn = crtc->scrn; */ + + switch (mode) { + case DPMSModeOn: + case DPMSModeStandby: + case DPMSModeSuspend: + break; + case DPMSModeOff: + break; + } +} + +static Bool +crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, + Rotation rotation, int x, int y) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + modesettingPtr ms = modesettingPTR(crtc->scrn); + xf86OutputPtr output = NULL; + struct crtc_private *crtcp = crtc->driver_private; + drmModeCrtcPtr drm_crtc = crtcp->drm_crtc; + drmModeModeInfo drm_mode; + int i, ret, connector_id; + + for (i = 0; i < config->num_output; output = NULL, i++) { + output = config->output[i]; + + if (output->crtc == crtc) + break; + } + + if (!output) + return FALSE; + + connector_id = xorg_output_get_id(output); + + drm_mode.clock = mode->Clock; + drm_mode.hdisplay = mode->HDisplay; + drm_mode.hsync_start = mode->HSyncStart; + drm_mode.hsync_end = mode->HSyncEnd; + drm_mode.htotal = mode->HTotal; + drm_mode.vdisplay = mode->VDisplay; + drm_mode.vsync_start = mode->VSyncStart; + drm_mode.vsync_end = mode->VSyncEnd; + drm_mode.vtotal = mode->VTotal; + drm_mode.flags = mode->Flags; + drm_mode.hskew = mode->HSkew; + drm_mode.vscan = mode->VScan; + drm_mode.vrefresh = mode->VRefresh; + if (!mode->name) + xf86SetModeDefaultName(mode); + strncpy(drm_mode.name, mode->name, DRM_DISPLAY_MODE_LEN - 1); + drm_mode.name[DRM_DISPLAY_MODE_LEN - 1] = '\0'; + + ret = drmModeSetCrtc(ms->fd, drm_crtc->crtc_id, ms->fb_id, x, y, + &connector_id, 1, &drm_mode); + + if (ret) + return FALSE; + + crtc->x = x; + crtc->y = y; + crtc->mode = *mode; + crtc->rotation = rotation; + + return TRUE; +} + +static void +crtc_gamma_set(xf86CrtcPtr crtc, CARD16 * red, CARD16 * green, CARD16 * blue, + int size) +{ + /* XXX: hockup */ +} + +#if 0 /* Implement and enable to enable rotation and reflection. */ +static void * +crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) +{ + /* ScrnInfoPtr pScrn = crtc->scrn; */ + + return NULL; +} + +static PixmapPtr +crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) +{ + /* ScrnInfoPtr pScrn = crtc->scrn; */ + + return NULL; +} + +static void +crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) +{ + /* ScrnInfoPtr pScrn = crtc->scrn; */ +} + +#endif + +/* + * Cursor functions + */ + +static void +crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) +{ + /* XXX: See if this one is needed, as we only support ARGB cursors */ +} + +static void +crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y) +{ + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + + drmModeMoveCursor(ms->fd, crtcp->drm_crtc->crtc_id, x, y); +} + +static void +crtc_load_cursor_argb_ga3d(xf86CrtcPtr crtc, CARD32 * image) +{ + unsigned char *ptr; + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + struct pipe_transfer *transfer; + + if (!crtcp->cursor_tex) { + struct pipe_resource templat; + struct winsys_handle whandle; + + memset(&templat, 0, sizeof(templat)); + templat.bind |= PIPE_BIND_RENDER_TARGET; + templat.bind |= PIPE_BIND_SCANOUT; + templat.target = PIPE_TEXTURE_2D; + templat.last_level = 0; + templat.depth0 = 1; + templat.format = PIPE_FORMAT_B8G8R8A8_UNORM; + templat.width0 = 64; + templat.height0 = 64; + + memset(&whandle, 0, sizeof(whandle)); + whandle.type = DRM_API_HANDLE_TYPE_KMS; + + crtcp->cursor_tex = ms->screen->resource_create(ms->screen, + &templat); + ms->screen->resource_get_handle(ms->screen, crtcp->cursor_tex, &whandle); + + crtcp->cursor_handle = whandle.handle; + } + + transfer = pipe_get_transfer(ms->ctx, crtcp->cursor_tex, + 0, 0, 0, + PIPE_TRANSFER_WRITE, + 0, 0, 64, 64); + ptr = ms->ctx->transfer_map(ms->ctx, transfer); + util_copy_rect(ptr, crtcp->cursor_tex->format, + transfer->stride, 0, 0, + 64, 64, (void*)image, 64 * 4, 0, 0); + ms->ctx->transfer_unmap(ms->ctx, transfer); + ms->ctx->transfer_destroy(ms->ctx, transfer); +} + +#if HAVE_LIBKMS +static void +crtc_load_cursor_argb_kms(xf86CrtcPtr crtc, CARD32 * image) +{ + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + unsigned char *ptr; + + if (!crtcp->cursor_bo) { + unsigned attr[8]; + + attr[0] = KMS_BO_TYPE; +#ifdef KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8 + attr[1] = KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8; +#else + attr[1] = KMS_BO_TYPE_CURSOR; +#endif + attr[2] = KMS_WIDTH; + attr[3] = 64; + attr[4] = KMS_HEIGHT; + attr[5] = 64; + attr[6] = 0; + + if (kms_bo_create(ms->kms, attr, &crtcp->cursor_bo)) + return; + + if (kms_bo_get_prop(crtcp->cursor_bo, KMS_HANDLE, + &crtcp->cursor_handle)) + goto err_bo_destroy; + } + + kms_bo_map(crtcp->cursor_bo, (void**)&ptr); + memcpy(ptr, image, 64*64*4); + kms_bo_unmap(crtcp->cursor_bo); + + return; + +err_bo_destroy: + kms_bo_destroy(&crtcp->cursor_bo); +} +#endif + +static void +crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + modesettingPtr ms = modesettingPTR(crtc->scrn); + + /* Older X servers have cursor reference counting bugs leading to use of + * freed memory and consequently random crashes. Should be fixed as of + * xserver 1.8, but this workaround shouldn't hurt anyway. + */ + if (config->cursor) + config->cursor->refcnt++; + + if (ms->cursor) + FreeCursor(ms->cursor, None); + + ms->cursor = config->cursor; + + if (ms->screen) + crtc_load_cursor_argb_ga3d(crtc, image); +#ifdef HAVE_LIBKMS + else if (ms->kms) + crtc_load_cursor_argb_kms(crtc, image); +#endif +} + +static void +crtc_show_cursor(xf86CrtcPtr crtc) +{ + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + + if (crtcp->cursor_tex || crtcp->cursor_bo) + drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, + crtcp->cursor_handle, 64, 64); +} + +static void +crtc_hide_cursor(xf86CrtcPtr crtc) +{ + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + + drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 0, 0, 0); +} + +/** + * Called at vt leave + */ +void +xorg_crtc_cursor_destroy(xf86CrtcPtr crtc) +{ + struct crtc_private *crtcp = crtc->driver_private; + + if (crtcp->cursor_tex) + pipe_resource_reference(&crtcp->cursor_tex, NULL); +#ifdef HAVE_LIBKMS + if (crtcp->cursor_bo) + kms_bo_destroy(&crtcp->cursor_bo); +#endif +} + +/* + * Misc functions + */ + +static void +crtc_destroy(xf86CrtcPtr crtc) +{ + struct crtc_private *crtcp = crtc->driver_private; + + xorg_crtc_cursor_destroy(crtc); + + drmModeFreeCrtc(crtcp->drm_crtc); + + xfree(crtcp); + crtc->driver_private = NULL; +} + +static const xf86CrtcFuncsRec crtc_funcs = { + .dpms = crtc_dpms, + .set_mode_major = crtc_set_mode_major, + + .set_cursor_colors = crtc_set_cursor_colors, + .set_cursor_position = crtc_set_cursor_position, + .show_cursor = crtc_show_cursor, + .hide_cursor = crtc_hide_cursor, + .load_cursor_argb = crtc_load_cursor_argb, + + .shadow_create = NULL, + .shadow_allocate = NULL, + .shadow_destroy = NULL, + + .gamma_set = crtc_gamma_set, + .destroy = crtc_destroy, +}; + +void +xorg_crtc_init(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + xf86CrtcPtr crtc; + drmModeResPtr res; + drmModeCrtcPtr drm_crtc = NULL; + struct crtc_private *crtcp; + int c; + + res = drmModeGetResources(ms->fd); + if (res == 0) { + ErrorF("Failed drmModeGetResources %d\n", errno); + return; + } + + for (c = 0; c < res->count_crtcs; c++) { + drm_crtc = drmModeGetCrtc(ms->fd, res->crtcs[c]); + + if (!drm_crtc) + continue; + + crtc = xf86CrtcCreate(pScrn, &crtc_funcs); + if (crtc == NULL) + goto out; + + crtcp = xcalloc(1, sizeof(struct crtc_private)); + if (!crtcp) { + xf86CrtcDestroy(crtc); + goto out; + } + + crtcp->drm_crtc = drm_crtc; + + crtc->driver_private = crtcp; + } + + out: + drmModeFreeResources(res); +} + +/* vim: set sw=4 ts=8 sts=4: */ diff --git a/src/gallium/state_trackers/xorg/xorg_dri2.c b/src/gallium/state_trackers/xorg/xorg_dri2.c new file mode 100644 index 0000000000..4e01bd1030 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_dri2.c @@ -0,0 +1,467 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + +#include "xorg-server.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include "xorg_tracker.h" +#include "xorg_exa.h" + +#include "dri2.h" + +#include "pipe/p_state.h" +#include "util/u_inlines.h" + +#include "util/u_format.h" + +/* Make all the #if cases in the code esier to read */ +#ifndef DRI2INFOREC_VERSION +#define DRI2INFOREC_VERSION 1 +#endif + +#if DRI2INFOREC_VERSION == 2 +static Bool set_format_in_do_create_buffer; +#endif + +typedef struct { + PixmapPtr pPixmap; + struct pipe_resource *tex; + struct pipe_fence_handle *fence; +} *BufferPrivatePtr; + +static Bool +dri2_do_create_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, unsigned int format) +{ + struct pipe_resource *tex = NULL; + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_pixmap_priv *exa_priv; + BufferPrivatePtr private = buffer->driverPrivate; + PixmapPtr pPixmap; + struct winsys_handle whandle; + + if (pDraw->type == DRAWABLE_PIXMAP) + pPixmap = (PixmapPtr) pDraw; + else + pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr) pDraw); + exa_priv = exaGetPixmapDriverPrivate(pPixmap); + + + switch (buffer->attachment) { + default: + if (buffer->attachment != DRI2BufferFakeFrontLeft || + pDraw->type != DRAWABLE_PIXMAP) { + private->pPixmap = (*pScreen->CreatePixmap)(pScreen, pDraw->width, + pDraw->height, + pDraw->depth, + 0); + } + break; + case DRI2BufferFrontLeft: + break; + case DRI2BufferStencil: +#if DRI2INFOREC_VERSION >= 3 + case DRI2BufferDepthStencil: +#else + /* Works on old X servers because sanity checking is for the weak */ + case 9: +#endif + if (exa_priv->depth_stencil_tex && + !util_format_is_depth_or_stencil(exa_priv->depth_stencil_tex->format)) + exa_priv->depth_stencil_tex = NULL; + /* Fall through */ + case DRI2BufferDepth: + if (exa_priv->depth_stencil_tex) + pipe_resource_reference(&tex, exa_priv->depth_stencil_tex); + else { + struct pipe_resource template; + unsigned depthBits = (format != 0) ? format : pDraw->depth; + memset(&template, 0, sizeof(template)); + template.target = PIPE_TEXTURE_2D; + if (buffer->attachment == DRI2BufferDepth) { + switch(depthBits) { + case 16: + template.format = PIPE_FORMAT_Z16_UNORM; + break; + case 32: + template.format = PIPE_FORMAT_Z32_UNORM; + break; + default: + template.format = ms->ds_depth_bits_last ? + PIPE_FORMAT_Z24X8_UNORM : PIPE_FORMAT_X8Z24_UNORM; + break; + } + } else { + template.format = ms->ds_depth_bits_last ? + PIPE_FORMAT_Z24_UNORM_S8_USCALED : PIPE_FORMAT_S8_USCALED_Z24_UNORM; + } + template.width0 = pDraw->width; + template.height0 = pDraw->height; + template.depth0 = 1; + template.last_level = 0; + template.bind = PIPE_BIND_DEPTH_STENCIL | + PIPE_BIND_SHARED; + tex = ms->screen->resource_create(ms->screen, &template); + pipe_resource_reference(&exa_priv->depth_stencil_tex, tex); + } + break; + } + + if (!private->pPixmap) { + private->pPixmap = pPixmap; + pPixmap->refcnt++; + } + + if (!tex) { + /* First call to make sure we have a pixmap private */ + exaMoveInPixmap(private->pPixmap); + xorg_exa_set_shared_usage(private->pPixmap); + pScreen->ModifyPixmapHeader(private->pPixmap, 0, 0, 0, 0, 0, NULL); + /* Second call to make sure texture has valid contents */ + exaMoveInPixmap(private->pPixmap); + tex = xorg_exa_get_texture(private->pPixmap); + } + + if (!tex) + FatalError("NO TEXTURE IN DRI2\n"); + + memset(&whandle, 0, sizeof(whandle)); + whandle.type = DRM_API_HANDLE_TYPE_SHARED; + + ms->screen->resource_get_handle(ms->screen, tex, &whandle); + + buffer->name = whandle.handle; + buffer->pitch = whandle.stride; + buffer->cpp = 4; + buffer->driverPrivate = private; + buffer->flags = 0; /* not tiled */ +#if DRI2INFOREC_VERSION == 2 + /* ABI forwards/backwards compatibility */ + if (set_format_in_do_create_buffer) + ((DRI2Buffer2Ptr)buffer)->format = 0; +#elif DRI2INFOREC_VERSION >= 3 + buffer->format = 0; +#endif + private->tex = tex; + + return TRUE; +} + +static void +dri2_do_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + BufferPrivatePtr private = buffer->driverPrivate; + struct exa_pixmap_priv *exa_priv = exaGetPixmapDriverPrivate(private->pPixmap); + + pipe_resource_reference(&private->tex, NULL); + ms->screen->fence_reference(ms->screen, &private->fence, NULL); + pipe_resource_reference(&exa_priv->depth_stencil_tex, NULL); + (*pScreen->DestroyPixmap)(private->pPixmap); +} + +#if DRI2INFOREC_VERSION >= 2 + +static DRI2Buffer2Ptr +dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, unsigned int format) +{ + DRI2Buffer2Ptr buffer; + BufferPrivatePtr private; + + buffer = xcalloc(1, sizeof *buffer); + if (!buffer) + return NULL; + + private = xcalloc(1, sizeof *private); + if (!private) { + goto fail; + } + + buffer->attachment = attachment; + buffer->driverPrivate = private; + + /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */ + if (dri2_do_create_buffer(pDraw, (DRI2BufferPtr)buffer, format)) + return buffer; + + xfree(private); +fail: + xfree(buffer); + return NULL; +} + +static void +dri2_destroy_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer) +{ + /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */ + dri2_do_destroy_buffer(pDraw, (DRI2BufferPtr)buffer); + + xfree(buffer->driverPrivate); + xfree(buffer); +} + +#endif /* DRI2INFOREC_VERSION >= 2 */ + +#if DRI2INFOREC_VERSION <= 2 + +static DRI2BufferPtr +dri2_create_buffers(DrawablePtr pDraw, unsigned int *attachments, int count) +{ + BufferPrivatePtr privates; + DRI2BufferPtr buffers; + int i; + + buffers = xcalloc(count, sizeof *buffers); + if (!buffers) + goto fail_buffers; + + privates = xcalloc(count, sizeof *privates); + if (!privates) + goto fail_privates; + + for (i = 0; i < count; i++) { + buffers[i].attachment = attachments[i]; + buffers[i].driverPrivate = &privates[i]; + + if (!dri2_do_create_buffer(pDraw, &buffers[i], 0)) + goto fail; + } + + return buffers; + +fail: + xfree(privates); +fail_privates: + xfree(buffers); +fail_buffers: + return NULL; +} + +static void +dri2_destroy_buffers(DrawablePtr pDraw, DRI2BufferPtr buffers, int count) +{ + int i; + + for (i = 0; i < count; i++) { + dri2_do_destroy_buffer(pDraw, &buffers[i]); + } + + if (buffers) { + xfree(buffers[0].driverPrivate); + xfree(buffers); + } +} + +#endif /* DRI2INFOREC_VERSION <= 2 */ + +static void +dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion, + DRI2BufferPtr pDestBuffer, DRI2BufferPtr pSrcBuffer) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + BufferPrivatePtr dst_priv = pDestBuffer->driverPrivate; + BufferPrivatePtr src_priv = pSrcBuffer->driverPrivate; + DrawablePtr src_draw; + DrawablePtr dst_draw; + GCPtr gc; + RegionPtr copy_clip; + Bool save_accel; + CustomizerPtr cust = ms->cust; + + /* + * In driCreateBuffers we dewrap windows into the + * backing pixmaps in order to get to the texture. + * We need to use the real drawable in CopyArea + * so that cliprects and offsets are correct. + */ + src_draw = (pSrcBuffer->attachment == DRI2BufferFrontLeft) ? pDraw : + &src_priv->pPixmap->drawable; + dst_draw = (pDestBuffer->attachment == DRI2BufferFrontLeft) ? pDraw : + &dst_priv->pPixmap->drawable; + + /* + * The clients implements glXWaitX with a copy front to fake and then + * waiting on the server to signal its completion of it. While + * glXWaitGL is a client side flush and a copy from fake to front. + * This is how it is done in the DRI2 protocol, how ever depending + * which type of drawables the server does things a bit differently + * then what the protocol says as the fake and front are the same. + * + * for pixmaps glXWaitX is a server flush. + * for pixmaps glXWaitGL is a client flush. + * for windows glXWaitX is a copy from front to fake then a server flush. + * for windows glXWaitGL is a client flush then a copy from fake to front. + * + * XXX in the windows case this code always flushes but that isn't a + * must in the glXWaitGL case but we don't know if this is a glXWaitGL + * or a glFlush/glFinish call. + */ + if (dst_priv->pPixmap == src_priv->pPixmap) { + /* pixmap glXWaitX */ + if (pSrcBuffer->attachment == DRI2BufferFrontLeft && + pDestBuffer->attachment == DRI2BufferFakeFrontLeft) { + ms->ctx->flush(ms->ctx, PIPE_FLUSH_SWAPBUFFERS, NULL); + return; + } + /* pixmap glXWaitGL */ + if (pDestBuffer->attachment == DRI2BufferFrontLeft && + pSrcBuffer->attachment == DRI2BufferFakeFrontLeft) { + return; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "copying between the same pixmap\n"); + } + } + + gc = GetScratchGC(pDraw->depth, pScreen); + copy_clip = REGION_CREATE(pScreen, NULL, 0); + REGION_COPY(pScreen, copy_clip, pRegion); + (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0); + ValidateGC(dst_draw, gc); + + /* If this is a full buffer swap, throttle on the previous one */ + if (ms->swapThrottling && + dst_priv->fence && REGION_NUM_RECTS(pRegion) == 1) { + BoxPtr extents = REGION_EXTENTS(pScreen, pRegion); + + if (extents->x1 == 0 && extents->y1 == 0 && + extents->x2 == pDraw->width && extents->y2 == pDraw->height) { + ms->screen->fence_finish(ms->screen, dst_priv->fence, 0); + ms->screen->fence_reference(ms->screen, &dst_priv->fence, NULL); + } + } + + /* Try to make sure the blit will be accelerated */ + save_accel = ms->exa->accel; + ms->exa->accel = TRUE; + + /* In case it won't be though, make sure the GPU copy contents of the + * source pixmap will be used for the software fallback - presumably the + * client modified them before calling in here. + */ + exaMoveInPixmap(src_priv->pPixmap); + DamageRegionAppend(src_draw, pRegion); + DamageRegionProcessPending(src_draw); + + if (cust && cust->winsys_context_throttle) + cust->winsys_context_throttle(cust, ms->ctx, THROTTLE_SWAP); + + (*gc->ops->CopyArea)(src_draw, dst_draw, gc, + 0, 0, pDraw->width, pDraw->height, 0, 0); + ms->exa->accel = save_accel; + + FreeScratchGC(gc); + + ms->ctx->flush(ms->ctx, PIPE_FLUSH_SWAPBUFFERS, + (pDestBuffer->attachment == DRI2BufferFrontLeft + && ms->swapThrottling) ? + &dst_priv->fence : NULL); + + if (cust && cust->winsys_context_throttle) + cust->winsys_context_throttle(cust, ms->ctx, THROTTLE_RENDER); + +} + +Bool +xorg_dri2_init(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + DRI2InfoRec dri2info; +#if DRI2INFOREC_VERSION >= 2 + int major, minor; + + if (xf86LoaderCheckSymbol("DRI2Version")) { + DRI2Version(&major, &minor); + } else { + /* Assume version 1.0 */ + major = 1; + minor = 0; + } +#endif + + dri2info.version = min(DRI2INFOREC_VERSION, 3); + dri2info.fd = ms->fd; + + dri2info.driverName = pScrn->driverName; + dri2info.deviceName = "/dev/dri/card0"; /* FIXME */ + +#if DRI2INFOREC_VERSION >= 2 + dri2info.CreateBuffer = dri2_create_buffer; + dri2info.DestroyBuffer = dri2_destroy_buffer; +#endif + + /* For X servers in the 1.6.x series there where two DRI2 version. + * This allows us to build one binary that works on both servers. + */ +#if DRI2INFOREC_VERSION == 2 + if (minor == 0) { + set_format_in_do_create_buffer = FALSE; + dri2info.CreateBuffers = dri2_create_buffers; + dri2info.DestroyBuffers = dri2_destroy_buffers; + } else + set_format_in_do_create_buffer = FALSE; +#endif + + /* For version 1 set these unconditionaly. */ +#if DRI2INFOREC_VERSION == 1 + dri2info.CreateBuffers = dri2_create_buffers; + dri2info.DestroyBuffers = dri2_destroy_buffers; +#endif + dri2info.CopyRegion = dri2_copy_region; + dri2info.Wait = NULL; + + ms->d_depth_bits_last = + ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_Z24X8_UNORM, + PIPE_TEXTURE_2D, + 0, + PIPE_BIND_DEPTH_STENCIL, 0); + ms->ds_depth_bits_last = + ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED, + PIPE_TEXTURE_2D, + 0, + PIPE_BIND_DEPTH_STENCIL, 0); + + return DRI2ScreenInit(pScreen, &dri2info); +} + +void +xorg_dri2_close(ScreenPtr pScreen) +{ + DRI2CloseScreen(pScreen); +} + +/* vim: set sw=4 ts=8 sts=4: */ diff --git a/src/gallium/state_trackers/xorg/xorg_driver.c b/src/gallium/state_trackers/xorg/xorg_driver.c new file mode 100644 index 0000000000..a7e57634ae --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_driver.c @@ -0,0 +1,1243 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + + +#include "xorg-server.h" +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "mipointer.h" +#include "micmap.h" +#include <X11/extensions/randr.h> +#include "fb.h" +#include "edid.h" +#include "xf86i2c.h" +#include "xf86Crtc.h" +#include "miscstruct.h" +#include "dixstruct.h" +#include "xf86xv.h" +#ifndef XSERVER_LIBPCIACCESS +#error "libpciaccess needed" +#endif + +#include <pciaccess.h> + +#include "pipe/p_context.h" +#include "xorg_tracker.h" +#include "xorg_winsys.h" + +#ifdef HAVE_LIBKMS +#include "libkms.h" +#endif + +/* + * Functions and symbols exported to Xorg via pointers. + */ + +static Bool drv_pre_init(ScrnInfoPtr pScrn, int flags); +static Bool drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, + char **argv); +static Bool drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags); +static void drv_adjust_frame(int scrnIndex, int x, int y, int flags); +static Bool drv_enter_vt(int scrnIndex, int flags); +static void drv_leave_vt(int scrnIndex, int flags); +static void drv_free_screen(int scrnIndex, int flags); +static ModeStatus drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, + int flags); + +typedef enum +{ + OPTION_SW_CURSOR, + OPTION_2D_ACCEL, + OPTION_DEBUG_FALLBACK, + OPTION_THROTTLE_SWAP, + OPTION_THROTTLE_DIRTY, + OPTION_3D_ACCEL +} drv_option_enums; + +static const OptionInfoRec drv_options[] = { + {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_2D_ACCEL, "2DAccel", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_DEBUG_FALLBACK, "DebugFallback", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_THROTTLE_SWAP, "SwapThrottling", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_THROTTLE_DIRTY, "DirtyThrottling", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_3D_ACCEL, "3DAccel", OPTV_BOOLEAN, {0}, FALSE}, + {-1, NULL, OPTV_NONE, {0}, FALSE} +}; + + +/* + * Exported Xorg driver functions to winsys + */ + +const OptionInfoRec * +xorg_tracker_available_options(int chipid, int busid) +{ + return drv_options; +} + +void +xorg_tracker_set_functions(ScrnInfoPtr scrn) +{ + scrn->PreInit = drv_pre_init; + scrn->ScreenInit = drv_screen_init; + scrn->SwitchMode = drv_switch_mode; + scrn->AdjustFrame = drv_adjust_frame; + scrn->EnterVT = drv_enter_vt; + scrn->LeaveVT = drv_leave_vt; + scrn->FreeScreen = drv_free_screen; + scrn->ValidMode = drv_valid_mode; +} + +Bool +xorg_tracker_have_modesetting(ScrnInfoPtr pScrn, struct pci_device *device) +{ + char *BusID = xalloc(64); + sprintf(BusID, "pci:%04x:%02x:%02x.%d", + device->domain, device->bus, + device->dev, device->func); + + if (drmCheckModesettingSupported(BusID)) { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0, + "Drm modesetting not supported %s\n", BusID); + xfree(BusID); + return FALSE; + } + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0, + "Drm modesetting supported on %s\n", BusID); + + xfree(BusID); + return TRUE; +} + + +/* + * Internal function definitions + */ + +static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn); +static Bool drv_close_screen(int scrnIndex, ScreenPtr pScreen); + + +/* + * Internal functions + */ + +static Bool +drv_get_rec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate) + return TRUE; + + pScrn->driverPrivate = xnfcalloc(1, sizeof(modesettingRec)); + + return TRUE; +} + +static void +drv_free_rec(ScrnInfoPtr pScrn) +{ + if (!pScrn) + return; + + if (!pScrn->driverPrivate) + return; + + xfree(pScrn->driverPrivate); + + pScrn->driverPrivate = NULL; +} + +static void +drv_probe_ddc(ScrnInfoPtr pScrn, int index) +{ + ConfiguredMonitor = NULL; +} + +static Bool +drv_crtc_resize(ScrnInfoPtr pScrn, int width, int height) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + modesettingPtr ms = modesettingPTR(pScrn); + ScreenPtr pScreen = pScrn->pScreen; + int old_width, old_height; + PixmapPtr rootPixmap; + int i; + + if (width == pScrn->virtualX && height == pScrn->virtualY) + return TRUE; + + old_width = pScrn->virtualX; + old_height = pScrn->virtualY; + pScrn->virtualX = width; + pScrn->virtualY = height; + + /* ms->create_front_buffer will remove the old front buffer */ + + rootPixmap = pScreen->GetScreenPixmap(pScreen); + if (!pScreen->ModifyPixmapHeader(rootPixmap, width, height, -1, -1, -1, NULL)) + goto error_modify; + + pScrn->displayWidth = rootPixmap->devKind / (rootPixmap->drawable.bitsPerPixel / 8); + + if (!ms->create_front_buffer(pScrn) || !ms->bind_front_buffer(pScrn)) + goto error_create; + + /* + * create && bind will turn off all crtc(s) in the kernel so we need to + * re-enable all the crtcs again. For real HW we might want to do this + * before destroying the old framebuffer. + */ + for (i = 0; i < xf86_config->num_crtc; i++) { + xf86CrtcPtr crtc = xf86_config->crtc[i]; + + if (!crtc->enabled) + continue; + + crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, crtc->y); + } + + return TRUE; + + /* + * This is the error recovery path. + */ +error_create: + if (!pScreen->ModifyPixmapHeader(rootPixmap, old_width, old_height, -1, -1, -1, NULL)) + FatalError("failed to resize rootPixmap error path\n"); + + pScrn->displayWidth = rootPixmap->devKind / (rootPixmap->drawable.bitsPerPixel / 8); + +error_modify: + pScrn->virtualX = old_width; + pScrn->virtualY = old_height; + + if (ms->create_front_buffer(pScrn) && ms->bind_front_buffer(pScrn)) + return FALSE; + + FatalError("failed to setup old framebuffer\n"); + return FALSE; +} + +static const xf86CrtcConfigFuncsRec crtc_config_funcs = { + .resize = drv_crtc_resize +}; + +static Bool +drv_init_drm(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + + /* deal with server regeneration */ + if (ms->fd < 0) { + char *BusID; + + BusID = xalloc(64); + sprintf(BusID, "PCI:%d:%d:%d", + ((ms->PciInfo->domain << 8) | ms->PciInfo->bus), + ms->PciInfo->dev, ms->PciInfo->func + ); + + + ms->api = drm_api_create(); + ms->fd = drmOpen(ms->api ? ms->api->driver_name : NULL, BusID); + xfree(BusID); + + if (ms->fd >= 0) + return TRUE; + + if (ms->api && ms->api->destroy) + ms->api->destroy(ms->api); + + ms->api = NULL; + + return FALSE; + } + + return TRUE; +} + +static Bool +drv_close_drm(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + + if (ms->api && ms->api->destroy) + ms->api->destroy(ms->api); + ms->api = NULL; + + drmClose(ms->fd); + ms->fd = -1; + + return TRUE; +} + +static Bool +drv_init_resource_management(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + /* + ScreenPtr pScreen = pScrn->pScreen; + PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); + Bool fbAccessDisabled; + CARD8 *fbstart; + */ + + if (ms->screen || ms->kms) + return TRUE; + + if (ms->api) { + ms->screen = ms->no3D ? NULL : + ms->api->create_screen(ms->api, ms->fd); + + if (ms->screen) + return TRUE; + + if (ms->api->destroy) + ms->api->destroy(ms->api); + + ms->api = NULL; + } + +#ifdef HAVE_LIBKMS + if (!kms_create(ms->fd, &ms->kms)) + return TRUE; +#endif + + return FALSE; +} + +static Bool +drv_close_resource_management(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + + if (ms->screen) { + assert(ms->ctx == NULL); + ms->screen->destroy(ms->screen); + } + ms->screen = NULL; + +#ifdef HAVE_LIBKMS + if (ms->kms) + kms_destroy(&ms->kms); +#endif + + return TRUE; +} + +static void +drv_cleanup_fences(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + int i; + + assert(ms->screen); + + for (i = 0; i < XORG_NR_FENCES; i++) { + if (ms->fence[i]) { + ms->screen->fence_finish(ms->screen, ms->fence[i], 0); + ms->screen->fence_reference(ms->screen, &ms->fence[i], NULL); + } + } +} + +static Bool +drv_pre_init(ScrnInfoPtr pScrn, int flags) +{ + xf86CrtcConfigPtr xf86_config; + modesettingPtr ms; + rgb defaultWeight = { 0, 0, 0 }; + EntityInfoPtr pEnt; + EntPtr msEnt = NULL; + int max_width, max_height; + CustomizerPtr cust; + + if (pScrn->numEntities != 1) + return FALSE; + + pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + + if (flags & PROBE_DETECT) { + drv_probe_ddc(pScrn, pEnt->index); + return TRUE; + } + + cust = (CustomizerPtr) pScrn->driverPrivate; + pScrn->driverPrivate = NULL; + + /* Allocate driverPrivate */ + if (!drv_get_rec(pScrn)) + return FALSE; + + ms = modesettingPTR(pScrn); + ms->pEnt = pEnt; + ms->cust = cust; + + pScrn->displayWidth = 640; /* default it */ + + if (ms->pEnt->location.type != BUS_PCI) + return FALSE; + + ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index); + + /* Allocate an entity private if necessary */ + if (xf86IsEntityShared(pScrn->entityList[0])) { + FatalError("Entity"); +#if 0 + msEnt = xf86GetEntityPrivate(pScrn->entityList[0], + modesettingEntityIndex)->ptr; + ms->entityPrivate = msEnt; +#else + (void)msEnt; +#endif + } else + ms->entityPrivate = NULL; + + if (xf86IsEntityShared(pScrn->entityList[0])) { + if (xf86IsPrimInitDone(pScrn->entityList[0])) { + /* do something */ + } else { + xf86SetPrimInitDone(pScrn->entityList[0]); + } + } + + ms->fd = -1; + ms->api = NULL; + if (!drv_init_drm(pScrn)) + return FALSE; + + pScrn->monitor = pScrn->confScreen->monitor; + pScrn->progClock = TRUE; + pScrn->rgbBits = 8; + + if (!xf86SetDepthBpp + (pScrn, 0, 0, 0, + PreferConvert24to32 | SupportConvert24to32 | Support32bppFb)) + return FALSE; + + switch (pScrn->depth) { + case 15: + case 16: + case 24: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given depth (%d) is not supported by the driver\n", + pScrn->depth); + return FALSE; + } + xf86PrintDepthBpp(pScrn); + + if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) + return FALSE; + if (!xf86SetDefaultVisual(pScrn, -1)) + return FALSE; + + /* Process the options */ + xf86CollectOptions(pScrn, NULL); + if (!(ms->Options = xalloc(sizeof(drv_options)))) + return FALSE; + memcpy(ms->Options, drv_options, sizeof(drv_options)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options); + + /* Allocate an xf86CrtcConfig */ + xf86CrtcConfigInit(pScrn, &crtc_config_funcs); + xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + + max_width = 2048; /* A very low default */ + max_height = 2048; /* see screen_init */ + xf86CrtcSetSizeRange(pScrn, 320, 200, max_width, max_height); + + if (xf86ReturnOptValBool(ms->Options, OPTION_SW_CURSOR, FALSE)) { + ms->SWCursor = TRUE; + } + + xorg_crtc_init(pScrn); + xorg_output_init(pScrn); + + if (!xf86InitialConfiguration(pScrn, TRUE)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); + return FALSE; + } + + /* + * If the driver can do gamma correction, it should call xf86SetGamma() here. + */ + { + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrn, zeros)) { + return FALSE; + } + } + + if (pScrn->modes == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); + return FALSE; + } + + pScrn->currentMode = pScrn->modes; + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + + /* Load the required sub modules */ + if (!xf86LoadSubModule(pScrn, "fb")) + return FALSE; + + /* XXX: these aren't needed when we are using libkms */ + if (!xf86LoadSubModule(pScrn, "exa")) + return FALSE; + +#ifdef DRI2 + if (!xf86LoadSubModule(pScrn, "dri2")) + return FALSE; +#endif + + return TRUE; +} + +static void drv_block_handler(int i, pointer blockData, pointer pTimeout, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]); + + pScreen->BlockHandler = ms->blockHandler; + pScreen->BlockHandler(i, blockData, pTimeout, pReadmask); + pScreen->BlockHandler = drv_block_handler; + + if (ms->ctx) { + int j; + + ms->ctx->flush(ms->ctx, PIPE_FLUSH_RENDER_CACHE, + ms->dirtyThrottling ? + &ms->fence[XORG_NR_FENCES-1] : + NULL); + + if (ms->dirtyThrottling) { + if (ms->fence[0]) + ms->ctx->screen->fence_finish(ms->ctx->screen, + ms->fence[0], 0); + + /* The amount of rendering generated by a block handler can be + * quite small. Let us get a fair way ahead of hardware before + * throttling. + */ + for (j = 0; j < XORG_NR_FENCES - 1; j++) + ms->screen->fence_reference(ms->screen, + &ms->fence[j], + ms->fence[j+1]); + + ms->screen->fence_reference(ms->screen, + &ms->fence[XORG_NR_FENCES-1], + NULL); + } + } + + +#ifdef DRM_MODE_FEATURE_DIRTYFB + { + RegionPtr dirty = DamageRegion(ms->damage); + unsigned num_cliprects = REGION_NUM_RECTS(dirty); + + if (num_cliprects) { + drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip)); + BoxPtr rect = REGION_RECTS(dirty); + int i, ret; + + /* XXX no need for copy? */ + for (i = 0; i < num_cliprects; i++, rect++) { + clip[i].x1 = rect->x1; + clip[i].y1 = rect->y1; + clip[i].x2 = rect->x2; + clip[i].y2 = rect->y2; + } + + /* TODO query connector property to see if this is needed */ + ret = drmModeDirtyFB(ms->fd, ms->fb_id, clip, num_cliprects); + if (ret) { + debug_printf("%s: failed to send dirty (%i, %s)\n", + __func__, ret, strerror(-ret)); + } + + DamageEmpty(ms->damage); + } + } +#endif +} + +static Bool +drv_create_screen_resources(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + PixmapPtr rootPixmap; + Bool ret; + + ms->noEvict = TRUE; + + pScreen->CreateScreenResources = ms->createScreenResources; + ret = pScreen->CreateScreenResources(pScreen); + pScreen->CreateScreenResources = drv_create_screen_resources; + + ms->bind_front_buffer(pScrn); + + ms->noEvict = FALSE; + + drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + +#ifdef DRM_MODE_FEATURE_DIRTYFB + rootPixmap = pScreen->GetScreenPixmap(pScreen); + ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE, + pScreen, rootPixmap); + + if (ms->damage) { + DamageRegister(&rootPixmap->drawable, ms->damage); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to create screen damage record\n"); + return FALSE; + } +#else + (void)rootPixmap; +#endif + + return ret; +} + +static Bool +drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + unsigned max_width, max_height; + VisualPtr visual; + CustomizerPtr cust = ms->cust; + MessageType from_st; + MessageType from_dt; + MessageType from_3D; + Bool use3D; + + if (!drv_init_drm(pScrn)) { + FatalError("Could not init DRM"); + return FALSE; + } + + use3D = cust ? !cust->no_3d : TRUE; + from_3D = xf86GetOptValBool(ms->Options, OPTION_3D_ACCEL, + &use3D) ? + X_CONFIG : X_PROBED; + + ms->no3D = !use3D; + + if (!drv_init_resource_management(pScrn)) { + FatalError("Could not init resource management (!pipe_screen && !libkms)"); + return FALSE; + } + + if (!drv_init_front_buffer_functions(pScrn)) { + FatalError("Could not init front buffer manager"); + return FALSE; + } + + /* get max width and height */ + { + drmModeResPtr res; + res = drmModeGetResources(ms->fd); + max_width = res->max_width; + max_height = res->max_height; + drmModeFreeResources(res); + } + + if (ms->screen) { + int max; + max = ms->screen->get_param(ms->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS); + max = 1 << (max - 1); + max_width = max < max_width ? max : max_width; + max_height = max < max_height ? max : max_height; + } + + xf86CrtcSetSizeRange(pScrn, 1, 1, max_width, max_height); + + pScrn->pScreen = pScreen; + + /* HW dependent - FIXME */ + pScrn->displayWidth = pScrn->virtualX; + + miClearVisualTypes(); + + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; + + if (!miSetPixmapDepths()) + return FALSE; + + pScrn->memPhysBase = 0; + pScrn->fbOffset = 0; + + if (!fbScreenInit(pScreen, NULL, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth, pScrn->bitsPerPixel)) + return FALSE; + + if (pScrn->bitsPerPixel > 8) { + /* Fixup RGB ordering */ + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + + fbPictureInit(pScreen, NULL, 0); + + ms->blockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = drv_block_handler; + ms->createScreenResources = pScreen->CreateScreenResources; + pScreen->CreateScreenResources = drv_create_screen_resources; + + xf86SetBlackWhitePixels(pScreen); + + ms->accelerate_2d = xf86ReturnOptValBool(ms->Options, OPTION_2D_ACCEL, FALSE); + ms->debug_fallback = xf86ReturnOptValBool(ms->Options, OPTION_DEBUG_FALLBACK, ms->accelerate_2d); + + if (cust && cust->winsys_screen_init) + cust->winsys_screen_init(cust, ms->fd); + + ms->swapThrottling = cust ? cust->swap_throttling : TRUE; + from_st = xf86GetOptValBool(ms->Options, OPTION_THROTTLE_SWAP, + &ms->swapThrottling) ? + X_CONFIG : X_DEFAULT; + + ms->dirtyThrottling = cust ? cust->dirty_throttling : TRUE; + from_dt = xf86GetOptValBool(ms->Options, OPTION_THROTTLE_DIRTY, + &ms->dirtyThrottling) ? + X_CONFIG : X_DEFAULT; + + if (ms->screen) { + ms->exa = xorg_exa_init(pScrn, ms->accelerate_2d); + + xorg_xv_init(pScreen); +#ifdef DRI2 + xorg_dri2_init(pScreen); +#endif + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "# Usefull debugging info follows #\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %s backend\n", + ms->screen ? "Gallium3D" : "libkms"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D Acceleration is %s\n", + ms->screen && ms->accelerate_2d ? "enabled" : "disabled"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Fallback debugging is %s\n", + ms->debug_fallback ? "enabled" : "disabled"); +#ifdef DRI2 + xf86DrvMsg(pScrn->scrnIndex, from_3D, "3D Acceleration is %s\n", + ms->screen ? "enabled" : "disabled"); +#else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D Acceleration is disabled\n"); +#endif + xf86DrvMsg(pScrn->scrnIndex, from_st, "Swap Throttling is %s.\n", + ms->swapThrottling ? "enabled" : "disabled"); + xf86DrvMsg(pScrn->scrnIndex, from_dt, "Dirty Throttling is %s.\n", + ms->dirtyThrottling ? "enabled" : "disabled"); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n"); + + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + xf86SetSilkenMouse(pScreen); + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + /* Need to extend HWcursor support to handle mask interleave */ + if (!ms->SWCursor) + xf86_cursors_init(pScreen, 64, 64, + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 | + HARDWARE_CURSOR_ARGB); + + /* Must force it before EnterVT, so we are in control of VT and + * later memory should be bound when allocating, e.g rotate_mem */ + pScrn->vtSema = TRUE; + + pScreen->SaveScreen = xf86SaveScreen; + ms->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = drv_close_screen; + + if (!xf86CrtcScreenInit(pScreen)) + return FALSE; + + if (!miCreateDefColormap(pScreen)) + return FALSE; + + xf86DPMSInit(pScreen, xf86DPMSSet, 0); + + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + + return drv_enter_vt(scrnIndex, 1); +} + +static void +drv_adjust_frame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output = config->output[config->compat_output]; + xf86CrtcPtr crtc = output->crtc; + + if (crtc && crtc->enabled) { + crtc->funcs->set_mode_major(crtc, pScrn->currentMode, + RR_Rotate_0, x, y); + crtc->x = output->initial_x + x; + crtc->y = output->initial_y + y; + } +} + +static void +drv_free_screen(int scrnIndex, int flags) +{ + drv_free_rec(xf86Screens[scrnIndex]); +} + +static void +drv_leave_vt(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + modesettingPtr ms = modesettingPTR(pScrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + CustomizerPtr cust = ms->cust; + int o; + + if (cust && cust->winsys_leave_vt) + cust->winsys_leave_vt(cust); + + for (o = 0; o < config->num_crtc; o++) { + xf86CrtcPtr crtc = config->crtc[o]; + + xorg_crtc_cursor_destroy(crtc); + + if (crtc->rotatedPixmap || crtc->rotatedData) { + crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap, + crtc->rotatedData); + crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; + } + } + + drmModeRmFB(ms->fd, ms->fb_id); + ms->fb_id = -1; + + /* idle hardware */ + if (!ms->kms) + drv_cleanup_fences(pScrn); + + if (drmDropMaster(ms->fd)) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "drmDropMaster failed: %s\n", strerror(errno)); + + pScrn->vtSema = FALSE; +} + +/* + * This gets called when gaining control of the VT, and from ScreenInit(). + */ +static Bool +drv_enter_vt(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + modesettingPtr ms = modesettingPTR(pScrn); + CustomizerPtr cust = ms->cust; + + if (drmSetMaster(ms->fd)) { + if (errno == EINVAL) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "drmSetMaster failed: 2.6.29 or newer kernel required for " + "multi-server DRI\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "drmSetMaster failed: %s\n", strerror(errno)); + } + } + + if (!ms->create_front_buffer(pScrn)) + return FALSE; + + if (!flags && !ms->bind_front_buffer(pScrn)) + return FALSE; + + if (!xf86SetDesiredModes(pScrn)) + return FALSE; + + if (cust && cust->winsys_enter_vt) + cust->winsys_enter_vt(cust); + + return TRUE; +} + +static Bool +drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + + return xf86SetSingleMode(pScrn, mode, RR_Rotate_0); +} + +static Bool +drv_close_screen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + modesettingPtr ms = modesettingPTR(pScrn); + CustomizerPtr cust = ms->cust; + + if (ms->cursor) { + FreeCursor(ms->cursor, None); + ms->cursor = NULL; + } + + if (cust && cust->winsys_screen_close) + cust->winsys_screen_close(cust); + +#ifdef DRI2 + if (ms->screen) + xorg_dri2_close(pScreen); +#endif + + pScreen->BlockHandler = ms->blockHandler; + pScreen->CreateScreenResources = ms->createScreenResources; + +#ifdef DRM_MODE_FEATURE_DIRTYFB + if (ms->damage) { + DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage); + DamageDestroy(ms->damage); + ms->damage = NULL; + } +#endif + + drmModeRmFB(ms->fd, ms->fb_id); + ms->destroy_front_buffer(pScrn); + + if (ms->exa) + xorg_exa_close(pScrn); + ms->exa = NULL; + + /* calls drop master make sure we don't talk to 3D HW after that */ + if (pScrn->vtSema) { + drv_leave_vt(scrnIndex, 0); + } + + drv_close_resource_management(pScrn); + + drv_close_drm(pScrn); + + pScrn->vtSema = FALSE; + pScreen->CloseScreen = ms->CloseScreen; + return (*pScreen->CloseScreen) (scrnIndex, pScreen); +} + +static ModeStatus +drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) +{ + return MODE_OK; +} + + +/* + * Front buffer backing store functions. + */ + +static Bool +drv_destroy_front_buffer_ga3d(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + + if (!ms->root_texture) + return TRUE; + + if (ms->fb_id != -1) { + drmModeRmFB(ms->fd, ms->fb_id); + ms->fb_id = -1; + } + + pipe_resource_reference(&ms->root_texture, NULL); + return TRUE; +} + +static Bool +drv_create_front_buffer_ga3d(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + struct pipe_resource *tex; + struct winsys_handle whandle; + unsigned fb_id; + int ret; + + ms->noEvict = TRUE; + + tex = xorg_exa_create_root_texture(pScrn, pScrn->virtualX, pScrn->virtualY, + pScrn->depth, pScrn->bitsPerPixel); + + if (!tex) + return FALSE; + + memset(&whandle, 0, sizeof(whandle)); + whandle.type = DRM_API_HANDLE_TYPE_KMS; + + if (!ms->screen->resource_get_handle(ms->screen, tex, &whandle)) + goto err_destroy; + + ret = drmModeAddFB(ms->fd, + pScrn->virtualX, + pScrn->virtualY, + pScrn->depth, + pScrn->bitsPerPixel, + whandle.stride, + whandle.handle, + &fb_id); + if (ret) { + debug_printf("%s: failed to create framebuffer (%i, %s)\n", + __func__, ret, strerror(-ret)); + goto err_destroy; + } + + if (!drv_destroy_front_buffer_ga3d(pScrn)) + FatalError("%s: failed to take down old framebuffer\n", __func__); + + pScrn->frameX0 = 0; + pScrn->frameY0 = 0; + drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + + pipe_resource_reference(&ms->root_texture, tex); + pipe_resource_reference(&tex, NULL); + ms->fb_id = fb_id; + + return TRUE; + +err_destroy: + pipe_resource_reference(&tex, NULL); + return FALSE; +} + +static Bool +drv_bind_front_buffer_ga3d(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + ScreenPtr pScreen = pScrn->pScreen; + PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); + struct pipe_resource *check; + + xorg_exa_set_displayed_usage(rootPixmap); + xorg_exa_set_shared_usage(rootPixmap); + xorg_exa_set_texture(rootPixmap, ms->root_texture); + if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, NULL)) + FatalError("Couldn't adjust screen pixmap\n"); + + check = xorg_exa_get_texture(rootPixmap); + if (ms->root_texture != check) + FatalError("Created new root texture\n"); + + pipe_resource_reference(&check, NULL); + return TRUE; +} + +#ifdef HAVE_LIBKMS +static Bool +drv_destroy_front_buffer_kms(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + ScreenPtr pScreen = pScrn->pScreen; + PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); + + /* XXX Do something with the rootPixmap. + * This currently works fine but if we are getting crashes in + * the fb functions after VT switches maybe look more into it. + */ + (void)rootPixmap; + + if (!ms->root_bo) + return TRUE; + + if (ms->fb_id != -1) { + drmModeRmFB(ms->fd, ms->fb_id); + ms->fb_id = -1; + } + + kms_bo_unmap(ms->root_bo); + kms_bo_destroy(&ms->root_bo); + return TRUE; +} + +static Bool +drv_create_front_buffer_kms(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + unsigned handle, stride; + struct kms_bo *bo; + unsigned attr[8]; + unsigned fb_id; + int ret; + + attr[0] = KMS_BO_TYPE; +#ifdef KMS_BO_TYPE_SCANOUT_X8R8G8B8 + attr[1] = KMS_BO_TYPE_SCANOUT_X8R8G8B8; +#else + attr[1] = KMS_BO_TYPE_SCANOUT; +#endif + attr[2] = KMS_WIDTH; + attr[3] = pScrn->virtualX; + attr[4] = KMS_HEIGHT; + attr[5] = pScrn->virtualY; + attr[6] = 0; + + if (kms_bo_create(ms->kms, attr, &bo)) + return FALSE; + + if (kms_bo_get_prop(bo, KMS_PITCH, &stride)) + goto err_destroy; + + if (kms_bo_get_prop(bo, KMS_HANDLE, &handle)) + goto err_destroy; + + ret = drmModeAddFB(ms->fd, + pScrn->virtualX, + pScrn->virtualY, + pScrn->depth, + pScrn->bitsPerPixel, + stride, + handle, + &fb_id); + if (ret) { + debug_printf("%s: failed to create framebuffer (%i, %s)", + __func__, ret, strerror(-ret)); + goto err_destroy; + } + + if (!drv_destroy_front_buffer_kms(pScrn)) + FatalError("%s: could not takedown old bo", __func__); + + pScrn->frameX0 = 0; + pScrn->frameY0 = 0; + drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + ms->root_bo = bo; + ms->fb_id = fb_id; + + return TRUE; + +err_destroy: + kms_bo_destroy(&bo); + return FALSE; +} + +static Bool +drv_bind_front_buffer_kms(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + ScreenPtr pScreen = pScrn->pScreen; + PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); + unsigned stride; + void *ptr; + + if (kms_bo_get_prop(ms->root_bo, KMS_PITCH, &stride)) + return FALSE; + + if (kms_bo_map(ms->root_bo, &ptr)) + goto err_destroy; + + pScreen->ModifyPixmapHeader(rootPixmap, + pScrn->virtualX, + pScrn->virtualY, + pScreen->rootDepth, + pScrn->bitsPerPixel, + stride, + ptr); + + /* This a hack to work around EnableDisableFBAccess setting the pointer + * the real fix would be to replace pScrn->EnableDisableFBAccess hook + * and set the rootPixmap->devPrivate.ptr to something valid before that. + * + * But in its infinit visdome something uses either this some times before + * that, so our hook doesn't get called before the crash happens. + */ + pScrn->pixmapPrivate.ptr = ptr; + + return TRUE; + +err_destroy: + kms_bo_destroy(&ms->root_bo); + return FALSE; +} +#endif /* HAVE_LIBKMS */ + +static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + if (ms->screen) { + ms->destroy_front_buffer = drv_destroy_front_buffer_ga3d; + ms->create_front_buffer = drv_create_front_buffer_ga3d; + ms->bind_front_buffer = drv_bind_front_buffer_ga3d; +#ifdef HAVE_LIBKMS + } else if (ms->kms) { + ms->destroy_front_buffer = drv_destroy_front_buffer_kms; + ms->create_front_buffer = drv_create_front_buffer_kms; + ms->bind_front_buffer = drv_bind_front_buffer_kms; +#endif + } else + return FALSE; + + return TRUE; +} + +CustomizerPtr xorg_customizer(ScrnInfoPtr pScrn) +{ + return modesettingPTR(pScrn)->cust; +} + +Bool xorg_has_gallium(ScrnInfoPtr pScrn) +{ + return modesettingPTR(pScrn)->screen != NULL; +} + +/* vim: set sw=4 ts=8 sts=4: */ diff --git a/src/gallium/state_trackers/xorg/xorg_exa.c b/src/gallium/state_trackers/xorg/xorg_exa.c new file mode 100644 index 0000000000..bd84668300 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_exa.c @@ -0,0 +1,1088 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + +#include "xorg_exa.h" +#include "xorg_tracker.h" +#include "xorg_composite.h" +#include "xorg_exa_tgsi.h" + +#include <xorg-server.h> +#include <xf86.h> +#include <picturestr.h> +#include <picture.h> + +#include "pipe/p_format.h" +#include "pipe/p_context.h" +#include "pipe/p_state.h" + +#include "util/u_rect.h" +#include "util/u_math.h" +#include "util/u_debug.h" +#include "util/u_format.h" + +#define DEBUG_PRINT 0 +#define ROUND_UP_TEXTURES 1 + +/* + * Helper functions + */ +struct render_format_str { + int format; + const char *name; +}; +static const struct render_format_str formats_info[] = +{ + {PICT_a8r8g8b8, "PICT_a8r8g8b8"}, + {PICT_x8r8g8b8, "PICT_x8r8g8b8"}, + {PICT_a8b8g8r8, "PICT_a8b8g8r8"}, + {PICT_x8b8g8r8, "PICT_x8b8g8r8"}, +#ifdef PICT_TYPE_BGRA + {PICT_b8g8r8a8, "PICT_b8g8r8a8"}, + {PICT_b8g8r8x8, "PICT_b8g8r8x8"}, + {PICT_a2r10g10b10, "PICT_a2r10g10b10"}, + {PICT_x2r10g10b10, "PICT_x2r10g10b10"}, + {PICT_a2b10g10r10, "PICT_a2b10g10r10"}, + {PICT_x2b10g10r10, "PICT_x2b10g10r10"}, +#endif + {PICT_r8g8b8, "PICT_r8g8b8"}, + {PICT_b8g8r8, "PICT_b8g8r8"}, + {PICT_r5g6b5, "PICT_r5g6b5"}, + {PICT_b5g6r5, "PICT_b5g6r5"}, + {PICT_a1r5g5b5, "PICT_a1r5g5b5"}, + {PICT_x1r5g5b5, "PICT_x1r5g5b5"}, + {PICT_a1b5g5r5, "PICT_a1b5g5r5"}, + {PICT_x1b5g5r5, "PICT_x1b5g5r5"}, + {PICT_a4r4g4b4, "PICT_a4r4g4b4"}, + {PICT_x4r4g4b4, "PICT_x4r4g4b4"}, + {PICT_a4b4g4r4, "PICT_a4b4g4r4"}, + {PICT_x4b4g4r4, "PICT_x4b4g4r4"}, + {PICT_a8, "PICT_a8"}, + {PICT_r3g3b2, "PICT_r3g3b2"}, + {PICT_b2g3r3, "PICT_b2g3r3"}, + {PICT_a2r2g2b2, "PICT_a2r2g2b2"}, + {PICT_a2b2g2r2, "PICT_a2b2g2r2"}, + {PICT_c8, "PICT_c8"}, + {PICT_g8, "PICT_g8"}, + {PICT_x4a4, "PICT_x4a4"}, + {PICT_x4c4, "PICT_x4c4"}, + {PICT_x4g4, "PICT_x4g4"}, + {PICT_a4, "PICT_a4"}, + {PICT_r1g2b1, "PICT_r1g2b1"}, + {PICT_b1g2r1, "PICT_b1g2r1"}, + {PICT_a1r1g1b1, "PICT_a1r1g1b1"}, + {PICT_a1b1g1r1, "PICT_a1b1g1r1"}, + {PICT_c4, "PICT_c4"}, + {PICT_g4, "PICT_g4"}, + {PICT_a1, "PICT_a1"}, + {PICT_g1, "PICT_g1"} +}; +static const char *render_format_name(int format) +{ + int i = 0; + for (i = 0; i < sizeof(formats_info)/sizeof(formats_info[0]); ++i) { + if (formats_info[i].format == format) + return formats_info[i].name; + } + return NULL; +} + +static void +exa_get_pipe_format(int depth, enum pipe_format *format, int *bbp, int *picture_format) +{ + switch (depth) { + case 32: + *format = PIPE_FORMAT_B8G8R8A8_UNORM; + *picture_format = PICT_a8r8g8b8; + assert(*bbp == 32); + break; + case 24: + *format = PIPE_FORMAT_B8G8R8X8_UNORM; + *picture_format = PICT_x8r8g8b8; + assert(*bbp == 32); + break; + case 16: + *format = PIPE_FORMAT_B5G6R5_UNORM; + *picture_format = PICT_r5g6b5; + assert(*bbp == 16); + break; + case 15: + *format = PIPE_FORMAT_B5G5R5A1_UNORM; + *picture_format = PICT_x1r5g5b5; + assert(*bbp == 16); + break; + case 8: + *format = PIPE_FORMAT_L8_UNORM; + *picture_format = PICT_a8; + assert(*bbp == 8); + break; + case 4: + case 1: + *format = PIPE_FORMAT_B8G8R8A8_UNORM; /* bad bad bad */ + break; + default: + assert(0); + break; + } +} + + +/* + * Static exported EXA functions + */ + +static void +ExaWaitMarker(ScreenPtr pScreen, int marker) +{ + /* Nothing to do, handled in the PrepareAccess hook */ +} + +static int +ExaMarkSync(ScreenPtr pScreen) +{ + return 1; +} + + +/*********************************************************************** + * Screen upload/download + */ + +static Bool +ExaDownloadFromScreen(PixmapPtr pPix, int x, int y, int w, int h, char *dst, + int dst_pitch) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPix); + struct pipe_transfer *transfer; + + if (!priv || !priv->tex) + return FALSE; + + transfer = pipe_get_transfer(exa->pipe, priv->tex, 0, 0, 0, + PIPE_TRANSFER_READ, x, y, w, h); + if (!transfer) + return FALSE; + +#if DEBUG_PRINT + debug_printf("------ ExaDownloadFromScreen(%d, %d, %d, %d, %d)\n", + x, y, w, h, dst_pitch); +#endif + + util_copy_rect((unsigned char*)dst, priv->tex->format, dst_pitch, 0, 0, + w, h, exa->pipe->transfer_map(exa->pipe, transfer), + transfer->stride, 0, 0); + + exa->pipe->transfer_unmap(exa->pipe, transfer); + exa->pipe->transfer_destroy(exa->pipe, transfer); + + return TRUE; +} + +static Bool +ExaUploadToScreen(PixmapPtr pPix, int x, int y, int w, int h, char *src, + int src_pitch) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPix); + struct pipe_transfer *transfer; + + if (!priv || !priv->tex) + return FALSE; + + transfer = pipe_get_transfer(exa->pipe, priv->tex, 0, 0, 0, + PIPE_TRANSFER_WRITE, x, y, w, h); + if (!transfer) + return FALSE; + +#if DEBUG_PRINT + debug_printf("++++++ ExaUploadToScreen(%d, %d, %d, %d, %d)\n", + x, y, w, h, src_pitch); +#endif + + util_copy_rect(exa->pipe->transfer_map(exa->pipe, transfer), + priv->tex->format, transfer->stride, 0, 0, w, h, + (unsigned char*)src, src_pitch, 0, 0); + + exa->pipe->transfer_unmap(exa->pipe, transfer); + exa->pipe->transfer_destroy(exa->pipe, transfer); + + return TRUE; +} + +static Bool +ExaPrepareAccess(PixmapPtr pPix, int index) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv; + + priv = exaGetPixmapDriverPrivate(pPix); + + if (!priv) + return FALSE; + + if (!priv->tex) + return FALSE; + + if (priv->map_count == 0) + { + assert(pPix->drawable.width <= priv->tex->width0); + assert(pPix->drawable.height <= priv->tex->height0); + + priv->map_transfer = + pipe_get_transfer(exa->pipe, priv->tex, 0, 0, 0, +#ifdef EXA_MIXED_PIXMAPS + PIPE_TRANSFER_MAP_DIRECTLY | +#endif + PIPE_TRANSFER_READ_WRITE, + 0, 0, + pPix->drawable.width, + pPix->drawable.height ); + if (!priv->map_transfer) +#ifdef EXA_MIXED_PIXMAPS + return FALSE; +#else + FatalError("failed to create transfer\n"); +#endif + + pPix->devPrivate.ptr = + exa->pipe->transfer_map(exa->pipe, priv->map_transfer); + pPix->devKind = priv->map_transfer->stride; + } + + priv->map_count++; + + return TRUE; +} + +static void +ExaFinishAccess(PixmapPtr pPix, int index) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv; + priv = exaGetPixmapDriverPrivate(pPix); + + if (!priv) + return; + + if (!priv->map_transfer) + return; + + if (--priv->map_count == 0) { + assert(priv->map_transfer); + exa->pipe->transfer_unmap(exa->pipe, priv->map_transfer); + exa->pipe->transfer_destroy(exa->pipe, priv->map_transfer); + priv->map_transfer = NULL; + pPix->devPrivate.ptr = NULL; + } +} + +/*********************************************************************** + * Solid Fills + */ + +static Bool +ExaPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planeMask, Pixel fg) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); + struct exa_context *exa = ms->exa; + +#if DEBUG_PRINT + debug_printf("ExaPrepareSolid(0x%x)\n", fg); +#endif + if (!exa->accel) + return FALSE; + + if (!exa->pipe) + XORG_FALLBACK("accle not enabled"); + + if (!priv || !priv->tex) + XORG_FALLBACK("%s", !priv ? "!priv" : "!priv->tex"); + + if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planeMask)) + XORG_FALLBACK("planeMask is not solid"); + + if (alu != GXcopy) + XORG_FALLBACK("not GXcopy"); + + if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format, + priv->tex->target, 0, + PIPE_BIND_RENDER_TARGET, 0)) { + XORG_FALLBACK("format %s", util_format_name(priv->tex->format)); + } + + return xorg_solid_bind_state(exa, priv, fg); +} + +static void +ExaSolid(PixmapPtr pPixmap, int x0, int y0, int x1, int y1) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); + +#if DEBUG_PRINT + debug_printf("\tExaSolid(%d, %d, %d, %d)\n", x0, y0, x1, y1); +#endif + + if (x0 == 0 && y0 == 0 && + x1 == pPixmap->drawable.width && y1 == pPixmap->drawable.height) { + exa->pipe->clear(exa->pipe, PIPE_CLEAR_COLOR, exa->solid_color, 0.0, 0); + return; + } + + xorg_solid(exa, priv, x0, y0, x1, y1) ; +} + + +static void +ExaDoneSolid(PixmapPtr pPixmap) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); + struct exa_context *exa = ms->exa; + + if (!priv) + return; + + xorg_composite_done(exa); +} + +/*********************************************************************** + * Copy Blits + */ + +static Bool +ExaPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, + int ydir, int alu, Pixel planeMask) +{ + ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap); + struct exa_pixmap_priv *src_priv = exaGetPixmapDriverPrivate(pSrcPixmap); + +#if DEBUG_PRINT + debug_printf("ExaPrepareCopy\n"); +#endif + + if (!exa->accel) + return FALSE; + + if (!exa->pipe) + XORG_FALLBACK("accle not enabled"); + + if (!priv || !priv->tex) + XORG_FALLBACK("pDst %s", !priv ? "!priv" : "!priv->tex"); + + if (!src_priv || !src_priv->tex) + XORG_FALLBACK("pSrc %s", !src_priv ? "!priv" : "!priv->tex"); + + if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planeMask)) + XORG_FALLBACK("planeMask is not solid"); + + if (alu != GXcopy) + XORG_FALLBACK("alu not GXcopy"); + + if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format, + priv->tex->target, 0, + PIPE_BIND_RENDER_TARGET, 0)) + XORG_FALLBACK("pDst format %s", util_format_name(priv->tex->format)); + + if (!exa->scrn->is_format_supported(exa->scrn, src_priv->tex->format, + src_priv->tex->target, 0, + PIPE_BIND_SAMPLER_VIEW, 0)) + XORG_FALLBACK("pSrc format %s", util_format_name(src_priv->tex->format)); + + exa->copy.src = src_priv; + exa->copy.dst = priv; + + /* XXX this used to use resource_copy_region for same-surface copies, + * but they were redefined to not allow overlaps (some of the util code + * always assumed this anyway). + * Drivers should implement accelerated resource_copy_region or it will + * be slow - disable for now. + */ + if (0 && exa->copy.src != exa->copy.dst) { + exa->copy.use_surface_copy = TRUE; + } + else { + exa->copy.use_surface_copy = FALSE; + + if (exa->copy.dst == exa->copy.src) + exa->copy.src_texture = renderer_clone_texture( exa->renderer, + exa->copy.src->tex ); + else + pipe_resource_reference(&exa->copy.src_texture, + exa->copy.src->tex); + + exa->copy.dst_surface = + exa->scrn->get_tex_surface(exa->scrn, + exa->copy.dst->tex, + 0, 0, 0, + PIPE_BIND_RENDER_TARGET); + + + renderer_copy_prepare(exa->renderer, + exa->copy.dst_surface, + exa->copy.src_texture ); + } + + + return TRUE; +} + +static void +ExaCopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY, + int width, int height) +{ + ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap); + +#if DEBUG_PRINT + debug_printf("\tExaCopy(srcx=%d, srcy=%d, dstX=%d, dstY=%d, w=%d, h=%d)\n", + srcX, srcY, dstX, dstY, width, height); +#endif + + debug_assert(priv == exa->copy.dst); + (void) priv; + + if (exa->copy.use_surface_copy) { + struct pipe_subresource subdst, subsrc; + subdst.face = 0; + subdst.level = 0; + subsrc.face = 0; + subsrc.level = 0; + exa->pipe->resource_copy_region( exa->pipe, + exa->copy.dst->tex, + subdst, + dstX, dstY, 0, + exa->copy.src->tex, + subsrc, + srcX, srcY, 0, + width, height ); + } + else { + renderer_copy_pixmap(exa->renderer, + dstX, dstY, + srcX, srcY, + width, height, + exa->copy.src_texture->width0, + exa->copy.src_texture->height0); + } +} + +static void +ExaDoneCopy(PixmapPtr pPixmap) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); + struct exa_context *exa = ms->exa; + + if (!priv) + return; + + renderer_draw_flush(exa->renderer); + + exa->copy.src = NULL; + exa->copy.dst = NULL; + pipe_surface_reference(&exa->copy.dst_surface, NULL); + pipe_resource_reference(&exa->copy.src_texture, NULL); +} + + + +static Bool +picture_check_formats(struct exa_pixmap_priv *pSrc, PicturePtr pSrcPicture) +{ + if (pSrc->picture_format == pSrcPicture->format) + return TRUE; + + if (pSrc->picture_format != PICT_a8r8g8b8) + return FALSE; + + /* pSrc->picture_format == PICT_a8r8g8b8 */ + switch (pSrcPicture->format) { + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + case PICT_a8b8g8r8: + case PICT_x8b8g8r8: + /* just treat these two as x8... */ + case PICT_r8g8b8: + case PICT_b8g8r8: + return TRUE; +#ifdef PICT_TYPE_BGRA + case PICT_b8g8r8a8: + case PICT_b8g8r8x8: + return FALSE; /* does not support swizzleing the alpha channel yet */ + case PICT_a2r10g10b10: + case PICT_x2r10g10b10: + case PICT_a2b10g10r10: + case PICT_x2b10g10r10: + return FALSE; +#endif + default: + return FALSE; + } + return FALSE; +} + +/*********************************************************************** + * Composite entrypoints + */ + +static Bool +ExaCheckComposite(int op, + PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + ScrnInfoPtr pScrn = xf86Screens[pDstPicture->pDrawable->pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + +#if DEBUG_PRINT + debug_printf("ExaCheckComposite(%d, %p, %p, %p) = %d\n", + op, pSrcPicture, pMaskPicture, pDstPicture, accelerated); +#endif + + if (!exa->accel) + return FALSE; + + return xorg_composite_accelerated(op, + pSrcPicture, + pMaskPicture, + pDstPicture); +} + + +static Bool +ExaPrepareComposite(int op, PicturePtr pSrcPicture, + PicturePtr pMaskPicture, PicturePtr pDstPicture, + PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) +{ + ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv; + + if (!exa->accel) + return FALSE; + +#if DEBUG_PRINT + debug_printf("ExaPrepareComposite(%d, src=0x%p, mask=0x%p, dst=0x%p)\n", + op, pSrcPicture, pMaskPicture, pDstPicture); + debug_printf("\tFormats: src(%s), mask(%s), dst(%s)\n", + pSrcPicture ? render_format_name(pSrcPicture->format) : "none", + pMaskPicture ? render_format_name(pMaskPicture->format) : "none", + pDstPicture ? render_format_name(pDstPicture->format) : "none"); +#endif + if (!exa->pipe) + XORG_FALLBACK("accle not enabled"); + + priv = exaGetPixmapDriverPrivate(pDst); + if (!priv || !priv->tex) + XORG_FALLBACK("pDst %s", !priv ? "!priv" : "!priv->tex"); + + if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format, + priv->tex->target, 0, + PIPE_BIND_RENDER_TARGET, 0)) + XORG_FALLBACK("pDst format: %s", util_format_name(priv->tex->format)); + + if (priv->picture_format != pDstPicture->format) + XORG_FALLBACK("pDst pic_format: %s != %s", + render_format_name(priv->picture_format), + render_format_name(pDstPicture->format)); + + if (pSrc) { + priv = exaGetPixmapDriverPrivate(pSrc); + if (!priv || !priv->tex) + XORG_FALLBACK("pSrc %s", !priv ? "!priv" : "!priv->tex"); + + if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format, + priv->tex->target, 0, + PIPE_BIND_SAMPLER_VIEW, 0)) + XORG_FALLBACK("pSrc format: %s", util_format_name(priv->tex->format)); + + if (!picture_check_formats(priv, pSrcPicture)) + XORG_FALLBACK("pSrc pic_format: %s != %s", + render_format_name(priv->picture_format), + render_format_name(pSrcPicture->format)); + + } + + if (pMask) { + priv = exaGetPixmapDriverPrivate(pMask); + if (!priv || !priv->tex) + XORG_FALLBACK("pMask %s", !priv ? "!priv" : "!priv->tex"); + + if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format, + priv->tex->target, 0, + PIPE_BIND_SAMPLER_VIEW, 0)) + XORG_FALLBACK("pMask format: %s", util_format_name(priv->tex->format)); + + if (!picture_check_formats(priv, pMaskPicture)) + XORG_FALLBACK("pMask pic_format: %s != %s", + render_format_name(priv->picture_format), + render_format_name(pMaskPicture->format)); + } + + return xorg_composite_bind_state(exa, op, pSrcPicture, pMaskPicture, + pDstPicture, + pSrc ? exaGetPixmapDriverPrivate(pSrc) : NULL, + pMask ? exaGetPixmapDriverPrivate(pMask) : NULL, + exaGetPixmapDriverPrivate(pDst)); +} + +static void +ExaComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int width, int height) +{ + ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDst); + +#if DEBUG_PRINT + debug_printf("\tExaComposite(src[%d,%d], mask=[%d, %d], dst=[%d, %d], dim=[%d, %d])\n", + srcX, srcY, maskX, maskY, dstX, dstY, width, height); + debug_printf("\t Num bound samplers = %d\n", + exa->num_bound_samplers); +#endif + + xorg_composite(exa, priv, srcX, srcY, maskX, maskY, + dstX, dstY, width, height); +} + + + +static void +ExaDoneComposite(PixmapPtr pPixmap) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + + xorg_composite_done(exa); +} + + +/*********************************************************************** + * Pixmaps + */ + +static void * +ExaCreatePixmap(ScreenPtr pScreen, int size, int align) +{ + struct exa_pixmap_priv *priv; + + priv = xcalloc(1, sizeof(struct exa_pixmap_priv)); + if (!priv) + return NULL; + + return priv; +} + +static void +ExaDestroyPixmap(ScreenPtr pScreen, void *dPriv) +{ + struct exa_pixmap_priv *priv = (struct exa_pixmap_priv *)dPriv; + + if (!priv) + return; + + pipe_resource_reference(&priv->tex, NULL); + + xfree(priv); +} + +static Bool +ExaPixmapIsOffscreen(PixmapPtr pPixmap) +{ + struct exa_pixmap_priv *priv; + + priv = exaGetPixmapDriverPrivate(pPixmap); + + if (!priv) + return FALSE; + + if (priv->tex) + return TRUE; + + return FALSE; +} + +int +xorg_exa_set_displayed_usage(PixmapPtr pPixmap) +{ + struct exa_pixmap_priv *priv; + priv = exaGetPixmapDriverPrivate(pPixmap); + + if (!priv) { + FatalError("NO PIXMAP PRIVATE\n"); + return 0; + } + + priv->flags |= PIPE_BIND_SCANOUT; + + return 0; +} + +int +xorg_exa_set_shared_usage(PixmapPtr pPixmap) +{ + struct exa_pixmap_priv *priv; + priv = exaGetPixmapDriverPrivate(pPixmap); + + if (!priv) { + FatalError("NO PIXMAP PRIVATE\n"); + return 0; + } + + priv->flags |= PIPE_BIND_SHARED; + + return 0; +} + + + +static Bool +size_match( int width, int tex_width ) +{ +#if ROUND_UP_TEXTURES + if (width > tex_width) + return FALSE; + + if (width * 2 < tex_width) + return FALSE; + + return TRUE; +#else + return width == tex_width; +#endif +} + +static Bool +ExaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, + int depth, int bitsPerPixel, int devKind, + pointer pPixData) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + + if (!priv || pPixData) + return FALSE; + + if (0) { + debug_printf("%s pixmap %p sz %dx%dx%d devKind %d\n", + __FUNCTION__, pPixmap, width, height, bitsPerPixel, devKind); + + if (priv->tex) + debug_printf(" ==> old texture %dx%d\n", + priv->tex->width0, + priv->tex->height0); + } + + + if (depth <= 0) + depth = pPixmap->drawable.depth; + + if (bitsPerPixel <= 0) + bitsPerPixel = pPixmap->drawable.bitsPerPixel; + + if (width <= 0) + width = pPixmap->drawable.width; + + if (height <= 0) + height = pPixmap->drawable.height; + + if (width <= 0 || height <= 0 || depth <= 0) + return FALSE; + + miModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, NULL); + + priv->width = width; + priv->height = height; + + /* Deal with screen resize */ + if ((exa->accel || priv->flags) && + (!priv->tex || + !size_match(width, priv->tex->width0) || + !size_match(height, priv->tex->height0) || + priv->tex_flags != priv->flags)) { + struct pipe_resource *texture = NULL; + struct pipe_resource template; + + memset(&template, 0, sizeof(template)); + template.target = PIPE_TEXTURE_2D; + exa_get_pipe_format(depth, &template.format, &bitsPerPixel, &priv->picture_format); + if (ROUND_UP_TEXTURES && priv->flags == 0) { + template.width0 = util_next_power_of_two(width); + template.height0 = util_next_power_of_two(height); + } + else { + template.width0 = width; + template.height0 = height; + } + + template.depth0 = 1; + template.last_level = 0; + template.bind = PIPE_BIND_RENDER_TARGET | priv->flags; + priv->tex_flags = priv->flags; + texture = exa->scrn->resource_create(exa->scrn, &template); + + if (priv->tex) { + struct pipe_subresource subdst, subsrc; + struct pipe_surface *src_surf; + + subdst.face = 0; + subdst.level = 0; + subsrc.face = 0; + subsrc.level = 0; + exa->pipe->resource_copy_region(exa->pipe, texture, + subdst, 0, 0, 0, + priv->tex, + subsrc, 0, 0, 0, + min(width, texture->width0), + min(height, texture->height0)); + } + + pipe_resource_reference(&priv->tex, texture); + /* the texture we create has one reference */ + pipe_resource_reference(&texture, NULL); + } + + return TRUE; +} + +struct pipe_resource * +xorg_exa_get_texture(PixmapPtr pPixmap) +{ + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); + struct pipe_resource *tex = NULL; + pipe_resource_reference(&tex, priv->tex); + return tex; +} + +Bool +xorg_exa_set_texture(PixmapPtr pPixmap, struct pipe_resource *tex) +{ + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); + + int mask = PIPE_BIND_SHARED | PIPE_BIND_SCANOUT; + + if (!priv) + return FALSE; + + if (pPixmap->drawable.width != tex->width0 || + pPixmap->drawable.height != tex->height0) + return FALSE; + + pipe_resource_reference(&priv->tex, tex); + priv->tex_flags = tex->bind & mask; + + return TRUE; +} + +struct pipe_resource * +xorg_exa_create_root_texture(ScrnInfoPtr pScrn, + int width, int height, + int depth, int bitsPerPixel) +{ + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct pipe_resource template; + int dummy; + + memset(&template, 0, sizeof(template)); + template.target = PIPE_TEXTURE_2D; + exa_get_pipe_format(depth, &template.format, &bitsPerPixel, &dummy); + template.width0 = width; + template.height0 = height; + template.depth0 = 1; + template.last_level = 0; + template.bind |= PIPE_BIND_RENDER_TARGET; + template.bind |= PIPE_BIND_SCANOUT; + template.bind |= PIPE_BIND_SHARED; + + return exa->scrn->resource_create(exa->scrn, &template); +} + +void +xorg_exa_close(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + + pipe_sampler_view_reference(&exa->bound_sampler_views[0], NULL); + pipe_sampler_view_reference(&exa->bound_sampler_views[1], NULL); + + renderer_destroy(exa->renderer); + + xorg_exa_finish(exa); + + if (exa->pipe) + exa->pipe->destroy(exa->pipe); + exa->pipe = NULL; + /* Since this was shared be proper with the pointer */ + ms->ctx = NULL; + + exaDriverFini(pScrn->pScreen); + xfree(exa); + ms->exa = NULL; +} + +void * +xorg_exa_init(ScrnInfoPtr pScrn, Bool accel) +{ + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa; + ExaDriverPtr pExa; + CustomizerPtr cust = ms->cust; + + exa = xcalloc(1, sizeof(struct exa_context)); + if (!exa) + return NULL; + + pExa = exaDriverAlloc(); + if (!pExa) { + goto out_err; + } + + memset(pExa, 0, sizeof(*pExa)); + + pExa->exa_major = 2; + pExa->exa_minor = 2; + pExa->memoryBase = 0; + pExa->memorySize = 0; + pExa->offScreenBase = 0; + pExa->pixmapOffsetAlign = 0; + pExa->pixmapPitchAlign = 1; + pExa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_HANDLES_PIXMAPS; +#ifdef EXA_SUPPORTS_PREPARE_AUX + pExa->flags |= EXA_SUPPORTS_PREPARE_AUX; +#endif +#ifdef EXA_MIXED_PIXMAPS + pExa->flags |= EXA_MIXED_PIXMAPS; +#endif + pExa->maxX = 8191; /* FIXME */ + pExa->maxY = 8191; /* FIXME */ + + pExa->WaitMarker = ExaWaitMarker; + pExa->MarkSync = ExaMarkSync; + pExa->PrepareSolid = ExaPrepareSolid; + pExa->Solid = ExaSolid; + pExa->DoneSolid = ExaDoneSolid; + pExa->PrepareCopy = ExaPrepareCopy; + pExa->Copy = ExaCopy; + pExa->DoneCopy = ExaDoneCopy; + pExa->CheckComposite = ExaCheckComposite; + pExa->PrepareComposite = ExaPrepareComposite; + pExa->Composite = ExaComposite; + pExa->DoneComposite = ExaDoneComposite; + pExa->PixmapIsOffscreen = ExaPixmapIsOffscreen; + pExa->DownloadFromScreen = ExaDownloadFromScreen; + pExa->UploadToScreen = ExaUploadToScreen; + pExa->PrepareAccess = ExaPrepareAccess; + pExa->FinishAccess = ExaFinishAccess; + pExa->CreatePixmap = ExaCreatePixmap; + pExa->DestroyPixmap = ExaDestroyPixmap; + pExa->ModifyPixmapHeader = ExaModifyPixmapHeader; + + if (!exaDriverInit(pScrn->pScreen, pExa)) { + goto out_err; + } + + exa->scrn = ms->screen; + exa->pipe = exa->scrn->context_create(exa->scrn, NULL); + if (exa->pipe == NULL) + goto out_err; + + /* Share context with DRI */ + ms->ctx = exa->pipe; + if (cust && cust->winsys_context_throttle) + cust->winsys_context_throttle(cust, ms->ctx, THROTTLE_RENDER); + + exa->renderer = renderer_create(exa->pipe); + exa->accel = accel; + + return (void *)exa; + +out_err: + xorg_exa_close(pScrn); + + return NULL; +} + +struct pipe_surface * +xorg_gpu_surface(struct pipe_screen *scrn, struct exa_pixmap_priv *priv) +{ + return scrn->get_tex_surface(scrn, priv->tex, 0, 0, 0, + PIPE_BIND_RENDER_TARGET); + +} + +void xorg_exa_flush(struct exa_context *exa, uint pipeFlushFlags, + struct pipe_fence_handle **fence) +{ + exa->pipe->flush(exa->pipe, pipeFlushFlags, fence); +} + +void xorg_exa_finish(struct exa_context *exa) +{ + struct pipe_fence_handle *fence = NULL; + + xorg_exa_flush(exa, PIPE_FLUSH_RENDER_CACHE, &fence); + + exa->pipe->screen->fence_finish(exa->pipe->screen, fence, 0); + exa->pipe->screen->fence_reference(exa->pipe->screen, &fence, NULL); +} + diff --git a/src/gallium/state_trackers/xorg/xorg_exa.h b/src/gallium/state_trackers/xorg/xorg_exa.h new file mode 100644 index 0000000000..86a1afc06e --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_exa.h @@ -0,0 +1,81 @@ +#ifndef XORG_EXA_H +#define XORG_EXA_H + +#include "xorg_tracker.h" + +#include <pipe/p_state.h> + +struct cso_context; +struct xorg_shaders; + +/* src + mask + dst */ +#define MAX_EXA_SAMPLERS 3 + +struct exa_context +{ + ExaDriverPtr pExa; + struct pipe_context *pipe; + struct pipe_screen *scrn; + struct xorg_renderer *renderer; + + struct pipe_sampler_view *bound_sampler_views[MAX_EXA_SAMPLERS]; + int num_bound_samplers; + + float solid_color[4]; + boolean has_solid_color; + + boolean accel; + + /* float[9] projective matrix bound to pictures */ + struct { + float src[9]; + float mask[9]; + boolean has_src; + boolean has_mask; + } transform; + + struct { + boolean use_surface_copy; + + struct exa_pixmap_priv *src; + struct exa_pixmap_priv *dst; + + struct pipe_surface *dst_surface; + + struct pipe_resource *src_texture; + } copy; +}; + +struct exa_pixmap_priv +{ + int width, height; + + int flags; + int tex_flags; + + int picture_format; + + struct pipe_resource *tex; + struct pipe_resource *depth_stencil_tex; + + struct pipe_transfer *map_transfer; + unsigned map_count; +}; + +#define XORG_FALLBACK(s, arg...) \ +do { \ + if (ms->debug_fallback) { \ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, \ + "%s fallback " s "\n", __FUNCTION__, ##arg); \ + } \ + return FALSE; \ +} while(0) + +struct pipe_surface * +xorg_gpu_surface(struct pipe_screen *scrn, struct exa_pixmap_priv *priv); + +void xorg_exa_flush(struct exa_context *exa, uint pipeFlushFlags, + struct pipe_fence_handle **fence); +void xorg_exa_finish(struct exa_context *exa); + +#endif diff --git a/src/gallium/state_trackers/xorg/xorg_exa_tgsi.c b/src/gallium/state_trackers/xorg/xorg_exa_tgsi.c new file mode 100644 index 0000000000..3e5e6bd6a6 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_exa_tgsi.c @@ -0,0 +1,690 @@ +#include "xorg_exa_tgsi.h" + +/*### stupidity defined in X11/extensions/XI.h */ +#undef Absolute + +#include "pipe/p_format.h" +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "pipe/p_shader_tokens.h" + +#include "util/u_memory.h" + +#include "tgsi/tgsi_ureg.h" + +#include "cso_cache/cso_context.h" +#include "cso_cache/cso_hash.h" + +/* Vertex shader: + * IN[0] = vertex pos + * IN[1] = src tex coord | solid fill color + * IN[2] = mask tex coord + * IN[3] = dst tex coord + * CONST[0] = (2/dst_width, 2/dst_height, 1, 1) + * CONST[1] = (-1, -1, 0, 0) + * + * OUT[0] = vertex pos + * OUT[1] = src tex coord | solid fill color + * OUT[2] = mask tex coord + * OUT[3] = dst tex coord + */ + +/* Fragment shader: + * SAMP[0] = src + * SAMP[1] = mask + * SAMP[2] = dst + * IN[0] = pos src | solid fill color + * IN[1] = pos mask + * IN[2] = pos dst + * CONST[0] = (0, 0, 0, 1) + * + * OUT[0] = color + */ + +static void +print_fs_traits(int fs_traits) +{ + const char *strings[] = { + "FS_COMPOSITE", /* = 1 << 0, */ + "FS_MASK", /* = 1 << 1, */ + "FS_SOLID_FILL", /* = 1 << 2, */ + "FS_LINGRAD_FILL", /* = 1 << 3, */ + "FS_RADGRAD_FILL", /* = 1 << 4, */ + "FS_CA_FULL", /* = 1 << 5, */ /* src.rgba * mask.rgba */ + "FS_CA_SRCALPHA", /* = 1 << 6, */ /* src.aaaa * mask.rgba */ + "FS_YUV", /* = 1 << 7, */ + "FS_SRC_REPEAT_NONE", /* = 1 << 8, */ + "FS_MASK_REPEAT_NONE",/* = 1 << 9, */ + "FS_SRC_SWIZZLE_RGB", /* = 1 << 10, */ + "FS_MASK_SWIZZLE_RGB",/* = 1 << 11, */ + "FS_SRC_SET_ALPHA", /* = 1 << 12, */ + "FS_MASK_SET_ALPHA", /* = 1 << 13, */ + "FS_SRC_LUMINANCE", /* = 1 << 14, */ + "FS_MASK_LUMINANCE", /* = 1 << 15, */ + }; + int i, k; + debug_printf("%s: ", __func__); + + for (i = 0, k = 1; k < (1 << 16); i++, k <<= 1) { + if (fs_traits & k) + debug_printf("%s, ", strings[i]); + } + + debug_printf("\n"); +} + +struct xorg_shaders { + struct xorg_renderer *r; + + struct cso_hash *vs_hash; + struct cso_hash *fs_hash; +}; + +static INLINE void +src_in_mask(struct ureg_program *ureg, + struct ureg_dst dst, + struct ureg_src src, + struct ureg_src mask, + unsigned component_alpha, + unsigned mask_luminance) +{ + if (component_alpha == FS_CA_FULL) { + ureg_MUL(ureg, dst, src, mask); + } else if (component_alpha == FS_CA_SRCALPHA) { + ureg_MUL(ureg, dst, + ureg_scalar(src, TGSI_SWIZZLE_W), mask); + } + else { + if (mask_luminance) + ureg_MUL(ureg, dst, src, + ureg_scalar(mask, TGSI_SWIZZLE_X)); + else + ureg_MUL(ureg, dst, src, + ureg_scalar(mask, TGSI_SWIZZLE_W)); + } +} + +static struct ureg_src +vs_normalize_coords(struct ureg_program *ureg, struct ureg_src coords, + struct ureg_src const0, struct ureg_src const1) +{ + struct ureg_dst tmp = ureg_DECL_temporary(ureg); + struct ureg_src ret; + ureg_MAD(ureg, tmp, coords, const0, const1); + ret = ureg_src(tmp); + ureg_release_temporary(ureg, tmp); + return ret; +} + +static void +linear_gradient(struct ureg_program *ureg, + struct ureg_dst out, + struct ureg_src pos, + struct ureg_src sampler, + struct ureg_src coords, + struct ureg_src const0124, + struct ureg_src matrow0, + struct ureg_src matrow1, + struct ureg_src matrow2) +{ + struct ureg_dst temp0 = ureg_DECL_temporary(ureg); + struct ureg_dst temp1 = ureg_DECL_temporary(ureg); + struct ureg_dst temp2 = ureg_DECL_temporary(ureg); + struct ureg_dst temp3 = ureg_DECL_temporary(ureg); + struct ureg_dst temp4 = ureg_DECL_temporary(ureg); + struct ureg_dst temp5 = ureg_DECL_temporary(ureg); + + ureg_MOV(ureg, + ureg_writemask(temp0, TGSI_WRITEMASK_XY), pos); + ureg_MOV(ureg, + ureg_writemask(temp0, TGSI_WRITEMASK_Z), + ureg_scalar(const0124, TGSI_SWIZZLE_Y)); + + ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0)); + ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0)); + ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0)); + ureg_RCP(ureg, temp3, ureg_src(temp3)); + ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3)); + ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3)); + + ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_X), + ureg_src(temp1)); + ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_Y), + ureg_src(temp2)); + + ureg_MUL(ureg, temp0, + ureg_scalar(coords, TGSI_SWIZZLE_Y), + ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_Y)); + ureg_MAD(ureg, temp1, + ureg_scalar(coords, TGSI_SWIZZLE_X), + ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_X), + ureg_src(temp0)); + + ureg_MUL(ureg, temp2, + ureg_src(temp1), + ureg_scalar(coords, TGSI_SWIZZLE_Z)); + + ureg_TEX(ureg, out, + TGSI_TEXTURE_1D, ureg_src(temp2), sampler); + + ureg_release_temporary(ureg, temp0); + ureg_release_temporary(ureg, temp1); + ureg_release_temporary(ureg, temp2); + ureg_release_temporary(ureg, temp3); + ureg_release_temporary(ureg, temp4); + ureg_release_temporary(ureg, temp5); +} + + +static void +radial_gradient(struct ureg_program *ureg, + struct ureg_dst out, + struct ureg_src pos, + struct ureg_src sampler, + struct ureg_src coords, + struct ureg_src const0124, + struct ureg_src matrow0, + struct ureg_src matrow1, + struct ureg_src matrow2) +{ + struct ureg_dst temp0 = ureg_DECL_temporary(ureg); + struct ureg_dst temp1 = ureg_DECL_temporary(ureg); + struct ureg_dst temp2 = ureg_DECL_temporary(ureg); + struct ureg_dst temp3 = ureg_DECL_temporary(ureg); + struct ureg_dst temp4 = ureg_DECL_temporary(ureg); + struct ureg_dst temp5 = ureg_DECL_temporary(ureg); + + ureg_MOV(ureg, + ureg_writemask(temp0, TGSI_WRITEMASK_XY), + pos); + ureg_MOV(ureg, + ureg_writemask(temp0, TGSI_WRITEMASK_Z), + ureg_scalar(const0124, TGSI_SWIZZLE_Y)); + + ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0)); + ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0)); + ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0)); + ureg_RCP(ureg, temp3, ureg_src(temp3)); + ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3)); + ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3)); + + ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_X), + ureg_src(temp1)); + ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_Y), + ureg_src(temp2)); + + ureg_MUL(ureg, temp0, ureg_scalar(coords, TGSI_SWIZZLE_Y), + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y)); + ureg_MAD(ureg, temp1, + ureg_scalar(coords, TGSI_SWIZZLE_X), + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X), + ureg_src(temp0)); + ureg_ADD(ureg, temp1, + ureg_src(temp1), ureg_src(temp1)); + ureg_MUL(ureg, temp3, + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y), + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y)); + ureg_MAD(ureg, temp4, + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X), + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X), + ureg_src(temp3)); + ureg_MOV(ureg, temp4, ureg_negate(ureg_src(temp4))); + ureg_MUL(ureg, temp2, + ureg_scalar(coords, TGSI_SWIZZLE_Z), + ureg_src(temp4)); + ureg_MUL(ureg, temp0, + ureg_scalar(const0124, TGSI_SWIZZLE_W), + ureg_src(temp2)); + ureg_MUL(ureg, temp3, + ureg_src(temp1), ureg_src(temp1)); + ureg_SUB(ureg, temp2, + ureg_src(temp3), ureg_src(temp0)); + ureg_RSQ(ureg, temp2, ureg_abs(ureg_src(temp2))); + ureg_RCP(ureg, temp2, ureg_src(temp2)); + ureg_SUB(ureg, temp1, + ureg_src(temp2), ureg_src(temp1)); + ureg_ADD(ureg, temp0, + ureg_scalar(coords, TGSI_SWIZZLE_Z), + ureg_scalar(coords, TGSI_SWIZZLE_Z)); + ureg_RCP(ureg, temp0, ureg_src(temp0)); + ureg_MUL(ureg, temp2, + ureg_src(temp1), ureg_src(temp0)); + ureg_TEX(ureg, out, TGSI_TEXTURE_1D, + ureg_src(temp2), sampler); + + ureg_release_temporary(ureg, temp0); + ureg_release_temporary(ureg, temp1); + ureg_release_temporary(ureg, temp2); + ureg_release_temporary(ureg, temp3); + ureg_release_temporary(ureg, temp4); + ureg_release_temporary(ureg, temp5); +} + +static void * +create_vs(struct pipe_context *pipe, + unsigned vs_traits) +{ + struct ureg_program *ureg; + struct ureg_src src; + struct ureg_dst dst; + struct ureg_src const0, const1; + boolean is_fill = (vs_traits & VS_FILL) != 0; + boolean is_composite = (vs_traits & VS_COMPOSITE) != 0; + boolean has_mask = (vs_traits & VS_MASK) != 0; + boolean is_yuv = (vs_traits & VS_YUV) != 0; + unsigned input_slot = 0; + + ureg = ureg_create(TGSI_PROCESSOR_VERTEX); + if (ureg == NULL) + return 0; + + const0 = ureg_DECL_constant(ureg, 0); + const1 = ureg_DECL_constant(ureg, 1); + + /* it has to be either a fill or a composite op */ + debug_assert((is_fill ^ is_composite) ^ is_yuv); + + src = ureg_DECL_vs_input(ureg, input_slot++); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); + src = vs_normalize_coords(ureg, src, + const0, const1); + ureg_MOV(ureg, dst, src); + + if (is_yuv) { + src = ureg_DECL_vs_input(ureg, input_slot++); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 0); + ureg_MOV(ureg, dst, src); + } + + if (is_composite) { + src = ureg_DECL_vs_input(ureg, input_slot++); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 0); + ureg_MOV(ureg, dst, src); + } + + if (is_fill) { + src = ureg_DECL_vs_input(ureg, input_slot++); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); + ureg_MOV(ureg, dst, src); + } + + if (has_mask) { + src = ureg_DECL_vs_input(ureg, input_slot++); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 1); + ureg_MOV(ureg, dst, src); + } + + ureg_END(ureg); + + return ureg_create_shader_and_destroy(ureg, pipe); +} + +static void * +create_yuv_shader(struct pipe_context *pipe, struct ureg_program *ureg) +{ + struct ureg_src y_sampler, u_sampler, v_sampler; + struct ureg_src pos; + struct ureg_src matrow0, matrow1, matrow2; + struct ureg_dst y, u, v, rgb; + struct ureg_dst out = ureg_DECL_output(ureg, + TGSI_SEMANTIC_COLOR, + 0); + + pos = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_GENERIC, + 0, + TGSI_INTERPOLATE_PERSPECTIVE); + + rgb = ureg_DECL_temporary(ureg); + y = ureg_DECL_temporary(ureg); + u = ureg_DECL_temporary(ureg); + v = ureg_DECL_temporary(ureg); + + y_sampler = ureg_DECL_sampler(ureg, 0); + u_sampler = ureg_DECL_sampler(ureg, 1); + v_sampler = ureg_DECL_sampler(ureg, 2); + + matrow0 = ureg_DECL_constant(ureg, 0); + matrow1 = ureg_DECL_constant(ureg, 1); + matrow2 = ureg_DECL_constant(ureg, 2); + + ureg_TEX(ureg, y, + TGSI_TEXTURE_2D, pos, y_sampler); + ureg_TEX(ureg, u, + TGSI_TEXTURE_2D, pos, u_sampler); + ureg_TEX(ureg, v, + TGSI_TEXTURE_2D, pos, v_sampler); + + ureg_SUB(ureg, u, ureg_src(u), + ureg_scalar(matrow0, TGSI_SWIZZLE_W)); + ureg_SUB(ureg, v, ureg_src(v), + ureg_scalar(matrow0, TGSI_SWIZZLE_W)); + + ureg_MUL(ureg, rgb, + ureg_scalar(ureg_src(y), TGSI_SWIZZLE_X), + matrow0); + ureg_MAD(ureg, rgb, + ureg_scalar(ureg_src(u), TGSI_SWIZZLE_X), + matrow1, + ureg_src(rgb)); + ureg_MAD(ureg, rgb, + ureg_scalar(ureg_src(v), TGSI_SWIZZLE_X), + matrow2, + ureg_src(rgb)); + + /* rgb.a = 1; */ + ureg_MOV(ureg, ureg_writemask(rgb, TGSI_WRITEMASK_W), + ureg_scalar(matrow0, TGSI_SWIZZLE_X)); + + ureg_MOV(ureg, out, ureg_src(rgb)); + + ureg_release_temporary(ureg, rgb); + ureg_release_temporary(ureg, y); + ureg_release_temporary(ureg, u); + ureg_release_temporary(ureg, v); + + ureg_END(ureg); + + return ureg_create_shader_and_destroy(ureg, pipe); +} + + +static INLINE void +xrender_tex(struct ureg_program *ureg, + struct ureg_dst dst, + struct ureg_src coords, + struct ureg_src sampler, + struct ureg_src imm0, + boolean repeat_none, + boolean swizzle, + boolean set_alpha) +{ + if (repeat_none) { + struct ureg_dst tmp0 = ureg_DECL_temporary(ureg); + struct ureg_dst tmp1 = ureg_DECL_temporary(ureg); + ureg_SGT(ureg, tmp1, ureg_swizzle(coords, + TGSI_SWIZZLE_X, + TGSI_SWIZZLE_Y, + TGSI_SWIZZLE_X, + TGSI_SWIZZLE_Y), + ureg_scalar(imm0, TGSI_SWIZZLE_X)); + ureg_SLT(ureg, tmp0, ureg_swizzle(coords, + TGSI_SWIZZLE_X, + TGSI_SWIZZLE_Y, + TGSI_SWIZZLE_X, + TGSI_SWIZZLE_Y), + ureg_scalar(imm0, TGSI_SWIZZLE_W)); + ureg_MIN(ureg, tmp0, ureg_src(tmp0), ureg_src(tmp1)); + ureg_MIN(ureg, tmp0, ureg_scalar(ureg_src(tmp0), TGSI_SWIZZLE_X), + ureg_scalar(ureg_src(tmp0), TGSI_SWIZZLE_Y)); + ureg_TEX(ureg, tmp1, TGSI_TEXTURE_2D, coords, sampler); + if (swizzle) + ureg_MOV(ureg, tmp1, ureg_swizzle(ureg_src(tmp1), + TGSI_SWIZZLE_Z, + TGSI_SWIZZLE_Y, + TGSI_SWIZZLE_X, + TGSI_SWIZZLE_W)); + if (set_alpha) + ureg_MOV(ureg, + ureg_writemask(tmp1, TGSI_WRITEMASK_W), + ureg_scalar(imm0, TGSI_SWIZZLE_W)); + ureg_MUL(ureg, dst, ureg_src(tmp1), ureg_src(tmp0)); + ureg_release_temporary(ureg, tmp0); + ureg_release_temporary(ureg, tmp1); + } else { + if (swizzle) { + struct ureg_dst tmp = ureg_DECL_temporary(ureg); + ureg_TEX(ureg, tmp, TGSI_TEXTURE_2D, coords, sampler); + ureg_MOV(ureg, dst, ureg_swizzle(ureg_src(tmp), + TGSI_SWIZZLE_Z, + TGSI_SWIZZLE_Y, + TGSI_SWIZZLE_X, + TGSI_SWIZZLE_W)); + ureg_release_temporary(ureg, tmp); + } else { + ureg_TEX(ureg, dst, TGSI_TEXTURE_2D, coords, sampler); + } + if (set_alpha) + ureg_MOV(ureg, + ureg_writemask(dst, TGSI_WRITEMASK_W), + ureg_scalar(imm0, TGSI_SWIZZLE_W)); + } +} + +static void * +create_fs(struct pipe_context *pipe, + unsigned fs_traits) +{ + struct ureg_program *ureg; + struct ureg_src /*dst_sampler,*/ src_sampler, mask_sampler; + struct ureg_src /*dst_pos,*/ src_input, mask_pos; + struct ureg_dst src, mask; + struct ureg_dst out; + struct ureg_src imm0 = { 0 }; + unsigned has_mask = (fs_traits & FS_MASK) != 0; + unsigned is_fill = (fs_traits & FS_FILL) != 0; + unsigned is_composite = (fs_traits & FS_COMPOSITE) != 0; + unsigned is_solid = (fs_traits & FS_SOLID_FILL) != 0; + unsigned is_lingrad = (fs_traits & FS_LINGRAD_FILL) != 0; + unsigned is_radgrad = (fs_traits & FS_RADGRAD_FILL) != 0; + unsigned comp_alpha_mask = fs_traits & FS_COMPONENT_ALPHA; + unsigned is_yuv = (fs_traits & FS_YUV) != 0; + unsigned src_repeat_none = (fs_traits & FS_SRC_REPEAT_NONE) != 0; + unsigned mask_repeat_none = (fs_traits & FS_MASK_REPEAT_NONE) != 0; + unsigned src_swizzle = (fs_traits & FS_SRC_SWIZZLE_RGB) != 0; + unsigned mask_swizzle = (fs_traits & FS_MASK_SWIZZLE_RGB) != 0; + unsigned src_set_alpha = (fs_traits & FS_SRC_SET_ALPHA) != 0; + unsigned mask_set_alpha = (fs_traits & FS_MASK_SET_ALPHA) != 0; + unsigned src_luminance = (fs_traits & FS_SRC_LUMINANCE) != 0; + unsigned mask_luminance = (fs_traits & FS_MASK_LUMINANCE) != 0; + +#if 0 + print_fs_traits(fs_traits); +#else + (void)print_fs_traits; +#endif + + ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (ureg == NULL) + return 0; + + /* it has to be either a fill, a composite op or a yuv conversion */ + debug_assert((is_fill ^ is_composite) ^ is_yuv); + (void) is_yuv; + + out = ureg_DECL_output(ureg, + TGSI_SEMANTIC_COLOR, + 0); + + if (src_repeat_none || mask_repeat_none || + src_set_alpha || mask_set_alpha || + src_luminance) { + imm0 = ureg_imm4f(ureg, 0, 0, 0, 1); + } + if (is_composite) { + src_sampler = ureg_DECL_sampler(ureg, 0); + src_input = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_GENERIC, + 0, + TGSI_INTERPOLATE_PERSPECTIVE); + } else if (is_fill) { + if (is_solid) + src_input = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_COLOR, + 0, + TGSI_INTERPOLATE_PERSPECTIVE); + else + src_input = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_POSITION, + 0, + TGSI_INTERPOLATE_PERSPECTIVE); + } else { + debug_assert(is_yuv); + return create_yuv_shader(pipe, ureg); + } + + if (has_mask) { + mask_sampler = ureg_DECL_sampler(ureg, 1); + mask_pos = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_GENERIC, + 1, + TGSI_INTERPOLATE_PERSPECTIVE); + } + +#if 0 /* unused right now */ + dst_sampler = ureg_DECL_sampler(ureg, 2); + dst_pos = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_POSITION, + 2, + TGSI_INTERPOLATE_PERSPECTIVE); +#endif + + + if (is_composite) { + if (has_mask || src_luminance) + src = ureg_DECL_temporary(ureg); + else + src = out; + xrender_tex(ureg, src, src_input, src_sampler, imm0, + src_repeat_none, src_swizzle, src_set_alpha); + } else if (is_fill) { + if (is_solid) { + if (has_mask || src_luminance) + src = ureg_dst(src_input); + else + ureg_MOV(ureg, out, src_input); + } else if (is_lingrad || is_radgrad) { + struct ureg_src coords, const0124, + matrow0, matrow1, matrow2; + + if (has_mask || src_luminance) + src = ureg_DECL_temporary(ureg); + else + src = out; + + coords = ureg_DECL_constant(ureg, 0); + const0124 = ureg_DECL_constant(ureg, 1); + matrow0 = ureg_DECL_constant(ureg, 2); + matrow1 = ureg_DECL_constant(ureg, 3); + matrow2 = ureg_DECL_constant(ureg, 4); + + if (is_lingrad) { + linear_gradient(ureg, src, + src_input, src_sampler, + coords, const0124, + matrow0, matrow1, matrow2); + } else if (is_radgrad) { + radial_gradient(ureg, src, + src_input, src_sampler, + coords, const0124, + matrow0, matrow1, matrow2); + } + } else + debug_assert(!"Unknown fill type!"); + } + if (src_luminance) { + ureg_MOV(ureg, src, + ureg_scalar(ureg_src(src), TGSI_SWIZZLE_X)); + ureg_MOV(ureg, ureg_writemask(src, TGSI_WRITEMASK_XYZ), + ureg_scalar(imm0, TGSI_SWIZZLE_X)); + if (!has_mask) + ureg_MOV(ureg, out, ureg_src(src)); + } + + if (has_mask) { + mask = ureg_DECL_temporary(ureg); + xrender_tex(ureg, mask, mask_pos, mask_sampler, imm0, + mask_repeat_none, mask_swizzle, mask_set_alpha); + /* src IN mask */ + src_in_mask(ureg, out, ureg_src(src), ureg_src(mask), + comp_alpha_mask, mask_luminance); + ureg_release_temporary(ureg, mask); + } + + ureg_END(ureg); + + return ureg_create_shader_and_destroy(ureg, pipe); +} + +struct xorg_shaders * xorg_shaders_create(struct xorg_renderer *r) +{ + struct xorg_shaders *sc = CALLOC_STRUCT(xorg_shaders); + + sc->r = r; + sc->vs_hash = cso_hash_create(); + sc->fs_hash = cso_hash_create(); + + return sc; +} + +static void +cache_destroy(struct cso_context *cso, + struct cso_hash *hash, + unsigned processor) +{ + struct cso_hash_iter iter = cso_hash_first_node(hash); + while (!cso_hash_iter_is_null(iter)) { + void *shader = (void *)cso_hash_iter_data(iter); + if (processor == PIPE_SHADER_FRAGMENT) { + cso_delete_fragment_shader(cso, shader); + } else if (processor == PIPE_SHADER_VERTEX) { + cso_delete_vertex_shader(cso, shader); + } + iter = cso_hash_erase(hash, iter); + } + cso_hash_delete(hash); +} + +void xorg_shaders_destroy(struct xorg_shaders *sc) +{ + cache_destroy(sc->r->cso, sc->vs_hash, + PIPE_SHADER_VERTEX); + cache_destroy(sc->r->cso, sc->fs_hash, + PIPE_SHADER_FRAGMENT); + + free(sc); +} + +static INLINE void * +shader_from_cache(struct pipe_context *pipe, + unsigned type, + struct cso_hash *hash, + unsigned key) +{ + void *shader = 0; + + struct cso_hash_iter iter = cso_hash_find(hash, key); + + if (cso_hash_iter_is_null(iter)) { + if (type == PIPE_SHADER_VERTEX) + shader = create_vs(pipe, key); + else + shader = create_fs(pipe, key); + cso_hash_insert(hash, key, shader); + } else + shader = (void *)cso_hash_iter_data(iter); + + return shader; +} + +struct xorg_shader xorg_shaders_get(struct xorg_shaders *sc, + unsigned vs_traits, + unsigned fs_traits) +{ + struct xorg_shader shader = { NULL, NULL }; + void *vs, *fs; + + vs = shader_from_cache(sc->r->pipe, PIPE_SHADER_VERTEX, + sc->vs_hash, vs_traits); + fs = shader_from_cache(sc->r->pipe, PIPE_SHADER_FRAGMENT, + sc->fs_hash, fs_traits); + + debug_assert(vs && fs); + if (!vs || !fs) + return shader; + + shader.vs = vs; + shader.fs = fs; + + return shader; +} diff --git a/src/gallium/state_trackers/xorg/xorg_exa_tgsi.h b/src/gallium/state_trackers/xorg/xorg_exa_tgsi.h new file mode 100644 index 0000000000..6f2a361d03 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_exa_tgsi.h @@ -0,0 +1,59 @@ +#ifndef XORG_EXA_TGSI_H +#define XORG_EXA_TGSI_H + +#include "xorg_renderer.h" + +enum xorg_vs_traits { + VS_COMPOSITE = 1 << 0, + VS_MASK = 1 << 1, + VS_SOLID_FILL = 1 << 2, + VS_LINGRAD_FILL = 1 << 3, + VS_RADGRAD_FILL = 1 << 4, + VS_YUV = 1 << 5, + + + VS_FILL = (VS_SOLID_FILL | + VS_LINGRAD_FILL | + VS_RADGRAD_FILL) +}; + +enum xorg_fs_traits { + FS_COMPOSITE = 1 << 0, + FS_MASK = 1 << 1, + FS_SOLID_FILL = 1 << 2, + FS_LINGRAD_FILL = 1 << 3, + FS_RADGRAD_FILL = 1 << 4, + FS_CA_FULL = 1 << 5, /* src.rgba * mask.rgba */ + FS_CA_SRCALPHA = 1 << 6, /* src.aaaa * mask.rgba */ + FS_YUV = 1 << 7, + FS_SRC_REPEAT_NONE = 1 << 8, + FS_MASK_REPEAT_NONE = 1 << 9, + FS_SRC_SWIZZLE_RGB = 1 << 10, + FS_MASK_SWIZZLE_RGB = 1 << 11, + FS_SRC_SET_ALPHA = 1 << 12, + FS_MASK_SET_ALPHA = 1 << 13, + FS_SRC_LUMINANCE = 1 << 14, + FS_MASK_LUMINANCE = 1 << 15, + + FS_FILL = (FS_SOLID_FILL | + FS_LINGRAD_FILL | + FS_RADGRAD_FILL), + FS_COMPONENT_ALPHA = (FS_CA_FULL | + FS_CA_SRCALPHA) +}; + +struct xorg_shader { + void *fs; + void *vs; +}; + +struct xorg_shaders; + +struct xorg_shaders *xorg_shaders_create(struct xorg_renderer *renderer); +void xorg_shaders_destroy(struct xorg_shaders *shaders); + +struct xorg_shader xorg_shaders_get(struct xorg_shaders *shaders, + unsigned vs_traits, + unsigned fs_traits); + +#endif diff --git a/src/gallium/state_trackers/xorg/xorg_output.c b/src/gallium/state_trackers/xorg/xorg_output.c new file mode 100644 index 0000000000..056098f76b --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_output.c @@ -0,0 +1,294 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + +#include "xorg-server.h" +#include <xf86.h> +#include <xf86i2c.h> +#include <xf86Crtc.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> + +#ifdef HAVE_XEXTPROTO_71 +#include <X11/extensions/dpmsconst.h> +#else +#define DPMS_SERVER +#include <X11/extensions/dpms.h> +#endif + +#include "xorg_tracker.h" + +struct output_private +{ + drmModeConnectorPtr drm_connector; + + int c; +}; + +static char *output_enum_list[] = { + "Unknown", + "VGA", + "DVI", + "DVI", + "DVI", + "Composite", + "SVIDEO", + "LVDS", + "CTV", + "DIN", + "DP", + "HDMI", + "HDMI", +}; + +static void +output_create_resources(xf86OutputPtr output) +{ +#ifdef RANDR_12_INTERFACE +#endif /* RANDR_12_INTERFACE */ +} + +static void +output_dpms(xf86OutputPtr output, int mode) +{ +} + +static xf86OutputStatus +output_detect(xf86OutputPtr output) +{ + modesettingPtr ms = modesettingPTR(output->scrn); + struct output_private *priv = output->driver_private; + drmModeConnectorPtr drm_connector; + xf86OutputStatus status; + + drm_connector = drmModeGetConnector(ms->fd, priv->drm_connector->connector_id); + if (drm_connector) { + drmModeFreeConnector(priv->drm_connector); + priv->drm_connector = drm_connector; + } else { + drm_connector = priv->drm_connector; + } + + switch (drm_connector->connection) { + case DRM_MODE_CONNECTED: + status = XF86OutputStatusConnected; + break; + case DRM_MODE_DISCONNECTED: + status = XF86OutputStatusDisconnected; + break; + default: + status = XF86OutputStatusUnknown; + } + + return status; +} + +static DisplayModePtr +output_get_modes(xf86OutputPtr output) +{ + struct output_private *priv = output->driver_private; + drmModeConnectorPtr drm_connector = priv->drm_connector; + drmModeModeInfoPtr drm_mode = NULL; + DisplayModePtr modes = NULL, mode = NULL; + int i; + + for (i = 0; i < drm_connector->count_modes; i++) { + drm_mode = &drm_connector->modes[i]; + if (drm_mode) { + mode = xcalloc(1, sizeof(DisplayModeRec)); + if (!mode) + continue; + mode->Clock = drm_mode->clock; + mode->HDisplay = drm_mode->hdisplay; + mode->HSyncStart = drm_mode->hsync_start; + mode->HSyncEnd = drm_mode->hsync_end; + mode->HTotal = drm_mode->htotal; + mode->VDisplay = drm_mode->vdisplay; + mode->VSyncStart = drm_mode->vsync_start; + mode->VSyncEnd = drm_mode->vsync_end; + mode->VTotal = drm_mode->vtotal; + mode->Flags = drm_mode->flags; + mode->HSkew = drm_mode->hskew; + mode->VScan = drm_mode->vscan; + mode->VRefresh = xf86ModeVRefresh(mode); + mode->Private = (void *)drm_mode; + mode->type = 0; + if (drm_mode->type & DRM_MODE_TYPE_PREFERRED) + mode->type |= M_T_PREFERRED; + if (drm_mode->type & DRM_MODE_TYPE_DRIVER) + mode->type |= M_T_DRIVER; + xf86SetModeDefaultName(mode); + modes = xf86ModesAdd(modes, mode); + xf86PrintModeline(0, mode); + } + } + + return modes; +} + +static int +output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) +{ + return MODE_OK; +} + +#ifdef RANDR_12_INTERFACE +static Bool +output_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value) +{ + return TRUE; +} +#endif /* RANDR_12_INTERFACE */ + +#ifdef RANDR_13_INTERFACE +static Bool +output_get_property(xf86OutputPtr output, Atom property) +{ + return TRUE; +} +#endif /* RANDR_13_INTERFACE */ + +static void +output_destroy(xf86OutputPtr output) +{ + struct output_private *priv = output->driver_private; + drmModeFreeConnector(priv->drm_connector); + xfree(priv); + output->driver_private = NULL; +} + +static const xf86OutputFuncsRec output_funcs = { + .create_resources = output_create_resources, +#ifdef RANDR_12_INTERFACE + .set_property = output_set_property, +#endif +#ifdef RANDR_13_INTERFACE + .get_property = output_get_property, +#endif + .dpms = output_dpms, + .detect = output_detect, + + .get_modes = output_get_modes, + .mode_valid = output_mode_valid, + .destroy = output_destroy, +}; + +void +xorg_output_init(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + xf86OutputPtr output; + drmModeResPtr res; + drmModeConnectorPtr drm_connector = NULL; + drmModeEncoderPtr drm_encoder = NULL; + struct output_private *priv; + char name[32]; + int c, v, p; + + res = drmModeGetResources(ms->fd); + if (res == 0) { + DRV_ERROR("Failed drmModeGetResources\n"); + return; + } + + for (c = 0; c < res->count_connectors; c++) { + drm_connector = drmModeGetConnector(ms->fd, res->connectors[c]); + if (!drm_connector) + goto out; + +#if 0 + for (p = 0; p < drm_connector->count_props; p++) { + drmModePropertyPtr prop; + + prop = drmModeGetProperty(ms->fd, drm_connector->props[p]); + + name = NULL; + if (prop) { + ErrorF("VALUES %d\n", prop->count_values); + + for (v = 0; v < prop->count_values; v++) + ErrorF("%s %lld\n", prop->name, prop->values[v]); + } + } +#else + (void)p; + (void)v; +#endif + + snprintf(name, 32, "%s%d", + output_enum_list[drm_connector->connector_type], + drm_connector->connector_type_id); + + + priv = xcalloc(sizeof(*priv), 1); + if (!priv) { + continue; + } + + output = xf86OutputCreate(pScrn, &output_funcs, name); + if (!output) { + xfree(priv); + continue; + } + + drm_encoder = drmModeGetEncoder(ms->fd, drm_connector->encoders[0]); + if (drm_encoder) { + output->possible_crtcs = drm_encoder->possible_crtcs; + output->possible_clones = drm_encoder->possible_clones; + } else { + output->possible_crtcs = 0; + output->possible_clones = 0; + } + priv->c = c; + priv->drm_connector = drm_connector; + output->driver_private = priv; + output->subpixel_order = SubPixelHorizontalRGB; + output->interlaceAllowed = FALSE; + output->doubleScanAllowed = FALSE; + } + + out: + drmModeFreeResources(res); +} + +unsigned +xorg_output_get_id(xf86OutputPtr output) +{ + struct output_private *priv = output->driver_private; + return priv->drm_connector->connector_id; +} + +/* vim: set sw=4 ts=8 sts=4: */ diff --git a/src/gallium/state_trackers/xorg/xorg_renderer.c b/src/gallium/state_trackers/xorg/xorg_renderer.c new file mode 100644 index 0000000000..92f1cc5065 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_renderer.c @@ -0,0 +1,716 @@ +#include "xorg_exa.h" +#include "xorg_renderer.h" + +#include "xorg_exa_tgsi.h" + +#include "cso_cache/cso_context.h" +#include "util/u_draw_quad.h" +#include "util/u_math.h" +#include "util/u_memory.h" +#include "util/u_sampler.h" + +#include "util/u_inlines.h" + +#include <math.h> + +#define floatsEqual(x, y) (fabs(x - y) <= 0.00001f * MIN2(fabs(x), fabs(y))) +#define floatIsZero(x) (floatsEqual((x) + 1, 1)) + +#define NUM_COMPONENTS 4 + +static INLINE boolean is_affine(float *matrix) +{ + return floatIsZero(matrix[2]) && floatIsZero(matrix[5]) + && floatsEqual(matrix[8], 1); +} +static INLINE void map_point(float *mat, float x, float y, + float *out_x, float *out_y) +{ + if (!mat) { + *out_x = x; + *out_y = y; + return; + } + + *out_x = mat[0]*x + mat[3]*y + mat[6]; + *out_y = mat[1]*x + mat[4]*y + mat[7]; + if (!is_affine(mat)) { + float w = 1/(mat[2]*x + mat[5]*y + mat[8]); + *out_x *= w; + *out_y *= w; + } +} + +static INLINE struct pipe_resource * +renderer_buffer_create(struct xorg_renderer *r) +{ + struct pipe_resource *buf = + pipe_user_buffer_create(r->pipe->screen, + r->buffer, + sizeof(float)* + r->buffer_size, +/* XXX was: PIPE_BUFFER_USAGE_PIXEL/PIPE_BUFFER_USAGE_GPU_WRITE even though this is a vertex buffer??? */ + PIPE_BIND_VERTEX_BUFFER); + r->buffer_size = 0; + + return buf; +} + +static INLINE void +renderer_draw(struct xorg_renderer *r) +{ + struct pipe_context *pipe = r->pipe; + struct pipe_resource *buf = 0; + int num_verts = r->buffer_size/(r->attrs_per_vertex * NUM_COMPONENTS); + + if (!r->buffer_size) + return; + + buf = renderer_buffer_create(r); + + + if (buf) { + cso_set_vertex_elements(r->cso, r->attrs_per_vertex, r->velems); + + util_draw_vertex_buffer(pipe, buf, 0, + PIPE_PRIM_QUADS, + num_verts, /* verts */ + r->attrs_per_vertex); /* attribs/vert */ + + pipe_resource_reference(&buf, NULL); + } +} + +static INLINE void +renderer_draw_conditional(struct xorg_renderer *r, + int next_batch) +{ + if (r->buffer_size + next_batch >= BUF_SIZE || + (next_batch == 0 && r->buffer_size)) { + renderer_draw(r); + } +} + +static void +renderer_init_state(struct xorg_renderer *r) +{ + struct pipe_depth_stencil_alpha_state dsa; + struct pipe_rasterizer_state raster; + unsigned i; + + /* set common initial clip state */ + memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); + cso_set_depth_stencil_alpha(r->cso, &dsa); + + + /* XXX: move to renderer_init_state? */ + memset(&raster, 0, sizeof(struct pipe_rasterizer_state)); + raster.gl_rasterization_rules = 1; + cso_set_rasterizer(r->cso, &raster); + + /* vertex elements state */ + memset(&r->velems[0], 0, sizeof(r->velems[0]) * 3); + for (i = 0; i < 3; i++) { + r->velems[i].src_offset = i * 4 * sizeof(float); + r->velems[i].instance_divisor = 0; + r->velems[i].vertex_buffer_index = 0; + r->velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; + } +} + + +static INLINE void +add_vertex_color(struct xorg_renderer *r, + float x, float y, + float color[4]) +{ + float *vertex = r->buffer + r->buffer_size; + + vertex[0] = x; + vertex[1] = y; + vertex[2] = 0.f; /*z*/ + vertex[3] = 1.f; /*w*/ + + vertex[4] = color[0]; /*r*/ + vertex[5] = color[1]; /*g*/ + vertex[6] = color[2]; /*b*/ + vertex[7] = color[3]; /*a*/ + + r->buffer_size += 8; +} + +static INLINE void +add_vertex_1tex(struct xorg_renderer *r, + float x, float y, float s, float t) +{ + float *vertex = r->buffer + r->buffer_size; + + vertex[0] = x; + vertex[1] = y; + vertex[2] = 0.f; /*z*/ + vertex[3] = 1.f; /*w*/ + + vertex[4] = s; /*s*/ + vertex[5] = t; /*t*/ + vertex[6] = 0.f; /*r*/ + vertex[7] = 1.f; /*q*/ + + r->buffer_size += 8; +} + +static void +add_vertex_data1(struct xorg_renderer *r, + float srcX, float srcY, float dstX, float dstY, + float width, float height, + struct pipe_resource *src, float *src_matrix) +{ + float s0, t0, s1, t1, s2, t2, s3, t3; + float pt0[2], pt1[2], pt2[2], pt3[2]; + + pt0[0] = srcX; + pt0[1] = srcY; + pt1[0] = (srcX + width); + pt1[1] = srcY; + pt2[0] = (srcX + width); + pt2[1] = (srcY + height); + pt3[0] = srcX; + pt3[1] = (srcY + height); + + if (src_matrix) { + map_point(src_matrix, pt0[0], pt0[1], &pt0[0], &pt0[1]); + map_point(src_matrix, pt1[0], pt1[1], &pt1[0], &pt1[1]); + map_point(src_matrix, pt2[0], pt2[1], &pt2[0], &pt2[1]); + map_point(src_matrix, pt3[0], pt3[1], &pt3[0], &pt3[1]); + } + + s0 = pt0[0] / src->width0; + s1 = pt1[0] / src->width0; + s2 = pt2[0] / src->width0; + s3 = pt3[0] / src->width0; + t0 = pt0[1] / src->height0; + t1 = pt1[1] / src->height0; + t2 = pt2[1] / src->height0; + t3 = pt3[1] / src->height0; + + /* 1st vertex */ + add_vertex_1tex(r, dstX, dstY, s0, t0); + /* 2nd vertex */ + add_vertex_1tex(r, dstX + width, dstY, s1, t1); + /* 3rd vertex */ + add_vertex_1tex(r, dstX + width, dstY + height, s2, t2); + /* 4th vertex */ + add_vertex_1tex(r, dstX, dstY + height, s3, t3); +} + + +static INLINE void +add_vertex_2tex(struct xorg_renderer *r, + float x, float y, + float s0, float t0, float s1, float t1) +{ + float *vertex = r->buffer + r->buffer_size; + + vertex[0] = x; + vertex[1] = y; + vertex[2] = 0.f; /*z*/ + vertex[3] = 1.f; /*w*/ + + vertex[4] = s0; /*s*/ + vertex[5] = t0; /*t*/ + vertex[6] = 0.f; /*r*/ + vertex[7] = 1.f; /*q*/ + + vertex[8] = s1; /*s*/ + vertex[9] = t1; /*t*/ + vertex[10] = 0.f; /*r*/ + vertex[11] = 1.f; /*q*/ + + r->buffer_size += 12; +} + +static void +add_vertex_data2(struct xorg_renderer *r, + float srcX, float srcY, float maskX, float maskY, + float dstX, float dstY, float width, float height, + struct pipe_resource *src, + struct pipe_resource *mask, + float *src_matrix, float *mask_matrix) +{ + float src_s0, src_t0, src_s1, src_t1; + float mask_s0, mask_t0, mask_s1, mask_t1; + float spt0[2], spt1[2]; + float mpt0[2], mpt1[2]; + + spt0[0] = srcX; + spt0[1] = srcY; + spt1[0] = srcX + width; + spt1[1] = srcY + height; + + mpt0[0] = maskX; + mpt0[1] = maskY; + mpt1[0] = maskX + width; + mpt1[1] = maskY + height; + + if (src_matrix) { + map_point(src_matrix, spt0[0], spt0[1], &spt0[0], &spt0[1]); + map_point(src_matrix, spt1[0], spt1[1], &spt1[0], &spt1[1]); + } + + if (mask_matrix) { + map_point(mask_matrix, mpt0[0], mpt0[1], &mpt0[0], &mpt0[1]); + map_point(mask_matrix, mpt1[0], mpt1[1], &mpt1[0], &mpt1[1]); + } + + src_s0 = spt0[0] / src->width0; + src_t0 = spt0[1] / src->height0; + src_s1 = spt1[0] / src->width0; + src_t1 = spt1[1] / src->height0; + + mask_s0 = mpt0[0] / mask->width0; + mask_t0 = mpt0[1] / mask->height0; + mask_s1 = mpt1[0] / mask->width0; + mask_t1 = mpt1[1] / mask->height0; + + /* 1st vertex */ + add_vertex_2tex(r, dstX, dstY, + src_s0, src_t0, mask_s0, mask_t0); + /* 2nd vertex */ + add_vertex_2tex(r, dstX + width, dstY, + src_s1, src_t0, mask_s1, mask_t0); + /* 3rd vertex */ + add_vertex_2tex(r, dstX + width, dstY + height, + src_s1, src_t1, mask_s1, mask_t1); + /* 4th vertex */ + add_vertex_2tex(r, dstX, dstY + height, + src_s0, src_t1, mask_s0, mask_t1); +} + +static struct pipe_resource * +setup_vertex_data_yuv(struct xorg_renderer *r, + float srcX, float srcY, float srcW, float srcH, + float dstX, float dstY, float dstW, float dstH, + struct pipe_resource **tex) +{ + float s0, t0, s1, t1; + float spt0[2], spt1[2]; + + spt0[0] = srcX; + spt0[1] = srcY; + spt1[0] = srcX + srcW; + spt1[1] = srcY + srcH; + + s0 = spt0[0] / tex[0]->width0; + t0 = spt0[1] / tex[0]->height0; + s1 = spt1[0] / tex[0]->width0; + t1 = spt1[1] / tex[0]->height0; + + /* 1st vertex */ + add_vertex_1tex(r, dstX, dstY, s0, t0); + /* 2nd vertex */ + add_vertex_1tex(r, dstX + dstW, dstY, + s1, t0); + /* 3rd vertex */ + add_vertex_1tex(r, dstX + dstW, dstY + dstH, + s1, t1); + /* 4th vertex */ + add_vertex_1tex(r, dstX, dstY + dstH, + s0, t1); + + return renderer_buffer_create(r); +} + + + +/* Set up framebuffer, viewport and vertex shader constant buffer + * state for a particular destinaton surface. In all our rendering, + * these concepts are linked. + */ +void renderer_bind_destination(struct xorg_renderer *r, + struct pipe_surface *surface, + int width, + int height ) +{ + + struct pipe_framebuffer_state fb; + struct pipe_viewport_state viewport; + + /* Framebuffer uses actual surface width/height + */ + memset(&fb, 0, sizeof fb); + fb.width = surface->width; + fb.height = surface->height; + fb.nr_cbufs = 1; + fb.cbufs[0] = surface; + fb.zsbuf = 0; + + /* Viewport just touches the bit we're interested in: + */ + viewport.scale[0] = width / 2.f; + viewport.scale[1] = height / 2.f; + viewport.scale[2] = 1.0; + viewport.scale[3] = 1.0; + viewport.translate[0] = width / 2.f; + viewport.translate[1] = height / 2.f; + viewport.translate[2] = 0.0; + viewport.translate[3] = 0.0; + + /* Constant buffer set up to match viewport dimensions: + */ + if (r->fb_width != width || + r->fb_height != height) + { + float vs_consts[8] = { + 2.f/width, 2.f/height, 1, 1, + -1, -1, 0, 0 + }; + + r->fb_width = width; + r->fb_height = height; + + renderer_set_constants(r, PIPE_SHADER_VERTEX, + vs_consts, sizeof vs_consts); + } + + cso_set_framebuffer(r->cso, &fb); + cso_set_viewport(r->cso, &viewport); +} + + +struct xorg_renderer * renderer_create(struct pipe_context *pipe) +{ + struct xorg_renderer *renderer = CALLOC_STRUCT(xorg_renderer); + + renderer->pipe = pipe; + renderer->cso = cso_create_context(pipe); + renderer->shaders = xorg_shaders_create(renderer); + + renderer_init_state(renderer); + + return renderer; +} + +void renderer_destroy(struct xorg_renderer *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) { + xorg_shaders_destroy(r->shaders); + r->shaders = NULL; + } + + if (r->cso) { + cso_release_all(r->cso); + cso_destroy_context(r->cso); + r->cso = NULL; + } +} + + + + + +void renderer_set_constants(struct xorg_renderer *r, + int shader_type, + const float *params, + int param_bytes) +{ + struct pipe_resource **cbuf = + (shader_type == PIPE_SHADER_VERTEX) ? &r->vs_const_buffer : + &r->fs_const_buffer; + + pipe_resource_reference(cbuf, NULL); + *cbuf = pipe_buffer_create(r->pipe->screen, + PIPE_BIND_CONSTANT_BUFFER, + param_bytes); + + if (*cbuf) { + pipe_buffer_write(r->pipe, *cbuf, + 0, param_bytes, params); + } + r->pipe->set_constant_buffer(r->pipe, shader_type, 0, *cbuf); +} + + +void renderer_copy_prepare(struct xorg_renderer *r, + struct pipe_surface *dst_surface, + struct pipe_resource *src_texture) +{ + struct pipe_context *pipe = r->pipe; + struct pipe_screen *screen = pipe->screen; + struct xorg_shader shader; + + assert(screen->is_format_supported(screen, dst_surface->format, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET, + 0)); + (void) screen; + + + /* 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(r->cso, &blend); + } + + /* 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(r->cso, 0, &sampler); + cso_single_sampler_done(r->cso); + } + + renderer_bind_destination(r, dst_surface, + dst_surface->width, + dst_surface->height); + + /* texture/sampler view */ + { + struct pipe_sampler_view templ; + struct pipe_sampler_view *src_view; + u_sampler_view_default_template(&templ, + src_texture, + src_texture->format); + src_view = pipe->create_sampler_view(pipe, src_texture, &templ); + cso_set_fragment_sampler_views(r->cso, 1, &src_view); + pipe_sampler_view_reference(&src_view, NULL); + } + + /* shaders */ + shader = xorg_shaders_get(r->shaders, + VS_COMPOSITE, + FS_COMPOSITE); + cso_set_vertex_shader_handle(r->cso, shader.vs); + cso_set_fragment_shader_handle(r->cso, shader.fs); + + r->buffer_size = 0; + r->attrs_per_vertex = 2; +} + +struct pipe_resource * +renderer_clone_texture(struct xorg_renderer *r, + struct pipe_resource *src) +{ + enum pipe_format format; + struct pipe_context *pipe = r->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_resource *pt; + struct pipe_resource templ; + + if (pipe->is_resource_referenced(pipe, src, 0, 0) & + PIPE_REFERENCED_FOR_WRITE) + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + + /* the coming in texture should already have that invariance */ + debug_assert(screen->is_format_supported(screen, src->format, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW, 0)); + + format = src->format; + + memset(&templ, 0, sizeof(templ)); + templ.target = PIPE_TEXTURE_2D; + templ.format = format; + templ.last_level = 0; + templ.width0 = src->width0; + templ.height0 = src->height0; + templ.depth0 = 1; + templ.bind = PIPE_BIND_SAMPLER_VIEW; + + pt = screen->resource_create(screen, &templ); + + debug_assert(!pt || pipe_is_referenced(&pt->reference)); + + if (!pt) + return NULL; + + { + /* copy source framebuffer surface into texture */ + struct pipe_subresource subsrc, subdst; + subsrc.face = 0; + subsrc.level = 0; + subdst.face = 0; + subdst.level = 0; + pipe->resource_copy_region(pipe, + pt, /* dest */ + subdst, + 0, 0, 0, /* destx/y/z */ + src, + subsrc, + 0, 0, 0, + src->width0, src->height0); + } + + return pt; +} + + +void renderer_copy_pixmap(struct xorg_renderer *r, + int dx, int dy, + int sx, int sy, + int width, int height, + float src_width, + float src_height) +{ + float s0, t0, s1, t1; + float x0, y0, x1, y1; + + + /* XXX: could put the texcoord scaling calculation into the vertex + * shader. + */ + s0 = sx / src_width; + s1 = (sx + width) / src_width; + t0 = sy / src_height; + t1 = (sy + height) / src_height; + + x0 = dx; + x1 = dx + width; + y0 = dy; + y1 = dy + height; + + /* draw quad */ + renderer_draw_conditional(r, 4*8); + add_vertex_1tex(r, x0, y0, s0, t0); + add_vertex_1tex(r, x1, y0, s1, t0); + add_vertex_1tex(r, x1, y1, s1, t1); + add_vertex_1tex(r, x0, y1, s0, t1); +} + + + + +void renderer_draw_yuv(struct xorg_renderer *r, + float src_x, float src_y, float src_w, float src_h, + int dst_x, int dst_y, int dst_w, int dst_h, + struct pipe_resource **textures) +{ + struct pipe_context *pipe = r->pipe; + struct pipe_resource *buf = 0; + + buf = setup_vertex_data_yuv(r, + src_x, src_y, src_w, src_h, + dst_x, dst_y, dst_w, dst_h, + textures); + + if (buf) { + const int num_attribs = 2; /*pos + tex coord*/ + + cso_set_vertex_elements(r->cso, num_attribs, r->velems); + + util_draw_vertex_buffer(pipe, buf, 0, + PIPE_PRIM_QUADS, + 4, /* verts */ + num_attribs); /* attribs/vert */ + + pipe_resource_reference(&buf, NULL); + } +} + +void renderer_begin_solid(struct xorg_renderer *r) +{ + r->buffer_size = 0; + r->attrs_per_vertex = 2; +} + +void renderer_solid(struct xorg_renderer *r, + int x0, int y0, + int x1, int y1, + float *color) +{ + /* + debug_printf("solid rect[(%d, %d), (%d, %d)], rgba[%f, %f, %f, %f]\n", + x0, y0, x1, y1, color[0], color[1], color[2], color[3]);*/ + + renderer_draw_conditional(r, 4 * 8); + + /* 1st vertex */ + add_vertex_color(r, x0, y0, color); + /* 2nd vertex */ + add_vertex_color(r, x1, y0, color); + /* 3rd vertex */ + add_vertex_color(r, x1, y1, color); + /* 4th vertex */ + add_vertex_color(r, x0, y1, color); +} + +void renderer_draw_flush(struct xorg_renderer *r) +{ + renderer_draw_conditional(r, 0); +} + +void renderer_begin_textures(struct xorg_renderer *r, + int num_textures) +{ + r->attrs_per_vertex = 1 + num_textures; + r->buffer_size = 0; +} + +void renderer_texture(struct xorg_renderer *r, + int *pos, + int width, int height, + struct pipe_sampler_view **sampler_view, + int num_textures, + float *src_matrix, + float *mask_matrix) +{ + +#if 0 + if (src_matrix) { + debug_printf("src_matrix = \n"); + debug_printf("%f, %f, %f\n", src_matrix[0], src_matrix[1], src_matrix[2]); + debug_printf("%f, %f, %f\n", src_matrix[3], src_matrix[4], src_matrix[5]); + debug_printf("%f, %f, %f\n", src_matrix[6], src_matrix[7], src_matrix[8]); + } + if (mask_matrix) { + debug_printf("mask_matrix = \n"); + debug_printf("%f, %f, %f\n", mask_matrix[0], mask_matrix[1], mask_matrix[2]); + debug_printf("%f, %f, %f\n", mask_matrix[3], mask_matrix[4], mask_matrix[5]); + debug_printf("%f, %f, %f\n", mask_matrix[6], mask_matrix[7], mask_matrix[8]); + } +#endif + + switch(r->attrs_per_vertex) { + case 2: + renderer_draw_conditional(r, 4 * 8); + add_vertex_data1(r, + pos[0], pos[1], /* src */ + pos[4], pos[5], /* dst */ + width, height, + sampler_view[0]->texture, src_matrix); + break; + case 3: + renderer_draw_conditional(r, 4 * 12); + add_vertex_data2(r, + pos[0], pos[1], /* src */ + pos[2], pos[3], /* mask */ + pos[4], pos[5], /* dst */ + width, height, + sampler_view[0]->texture, sampler_view[1]->texture, + src_matrix, mask_matrix); + break; + default: + debug_assert(!"Unsupported number of textures"); + break; + } +} diff --git a/src/gallium/state_trackers/xorg/xorg_renderer.h b/src/gallium/state_trackers/xorg/xorg_renderer.h new file mode 100644 index 0000000000..fb09fabe15 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_renderer.h @@ -0,0 +1,96 @@ +#ifndef XORG_RENDERER_H +#define XORG_RENDERER_H + +#include "pipe/p_context.h" +#include "pipe/p_state.h" + +struct xorg_shaders; +struct exa_pixmap_priv; + +/* max number of vertices * + * max number of attributes per vertex * + * max number of components per attribute + * + * currently the max is 100 quads + */ +#define BUF_SIZE (100 * 4 * 3 * 4) + +struct xorg_renderer { + struct pipe_context *pipe; + + struct cso_context *cso; + struct xorg_shaders *shaders; + + int fb_width; + int fb_height; + struct pipe_resource *vs_const_buffer; + struct pipe_resource *fs_const_buffer; + + float buffer[BUF_SIZE]; + int buffer_size; + struct pipe_vertex_element velems[3]; + + /* number of attributes per vertex for the current + * draw operation */ + int attrs_per_vertex; +}; + +struct xorg_renderer *renderer_create(struct pipe_context *pipe); +void renderer_destroy(struct xorg_renderer *renderer); + +void renderer_bind_destination(struct xorg_renderer *r, + struct pipe_surface *surface, + int width, + int height ); + +void renderer_bind_framebuffer(struct xorg_renderer *r, + struct exa_pixmap_priv *priv); +void renderer_bind_viewport(struct xorg_renderer *r, + struct exa_pixmap_priv *dst); +void renderer_set_constants(struct xorg_renderer *r, + int shader_type, + const float *buffer, + int size); + + +void renderer_draw_yuv(struct xorg_renderer *r, + float src_x, float src_y, float src_w, float src_h, + int dst_x, int dst_y, int dst_w, int dst_h, + struct pipe_resource **textures); + +void renderer_begin_solid(struct xorg_renderer *r); +void renderer_solid(struct xorg_renderer *r, + int x0, int y0, + int x1, int y1, + float *color); + +void renderer_begin_textures(struct xorg_renderer *r, + int num_textures); + +void renderer_texture(struct xorg_renderer *r, + int *pos, + int width, int height, + struct pipe_sampler_view **textures, + int num_textures, + float *src_matrix, + float *mask_matrix); + +void renderer_draw_flush(struct xorg_renderer *r); + +struct pipe_resource * +renderer_clone_texture(struct xorg_renderer *r, + struct pipe_resource *src); + +void renderer_copy_prepare(struct xorg_renderer *r, + struct pipe_surface *dst_surface, + struct pipe_resource *src_texture); + +void renderer_copy_pixmap(struct xorg_renderer *r, + int dx, int dy, + int sx, int sy, + int width, int height, + float src_width, + float src_height); + + +#endif diff --git a/src/gallium/state_trackers/xorg/xorg_tracker.h b/src/gallium/state_trackers/xorg/xorg_tracker.h new file mode 100644 index 0000000000..df56ad1b15 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_tracker.h @@ -0,0 +1,218 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + +#ifndef _XORG_TRACKER_H_ +#define _XORG_TRACKER_H_ + +#include <stddef.h> +#include <stdint.h> +#include <errno.h> +#include <drm.h> +#include <xf86drm.h> +#include <xf86drmMode.h> +#include <xorg-server.h> +#include <xf86.h> +#include "xf86Crtc.h" +#include <exa.h> + +#ifdef DRM_MODE_FEATURE_DIRTYFB +#include <damage.h> +#endif + +#include "pipe/p_screen.h" +#include "util/u_inlines.h" +#include "util/u_debug.h" +#include "state_tracker/drm_api.h" + +#define DRV_ERROR(msg) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, msg); + +struct kms_bo; +struct kms_driver; +struct exa_context; + +typedef struct +{ + int lastInstance; + int refCount; + ScrnInfoPtr pScrn_1; + ScrnInfoPtr pScrn_2; +} EntRec, *EntPtr; + +#define XORG_NR_FENCES 3 + +enum xorg_throttling_reason { + THROTTLE_RENDER, + THROTTLE_SWAP +}; + +typedef struct _CustomizerRec +{ + Bool dirty_throttling; + Bool swap_throttling; + Bool no_3d; + Bool (*winsys_screen_init)(struct _CustomizerRec *cust, int fd); + Bool (*winsys_screen_close)(struct _CustomizerRec *cust); + Bool (*winsys_enter_vt)(struct _CustomizerRec *cust); + Bool (*winsys_leave_vt)(struct _CustomizerRec *cust); + void (*winsys_context_throttle)(struct _CustomizerRec *cust, + struct pipe_context *pipe, + enum xorg_throttling_reason reason); +} CustomizerRec, *CustomizerPtr; + +typedef struct _modesettingRec +{ + /* drm */ + int fd; + unsigned fb_id; + + /* X */ + EntPtr entityPrivate; + + int Chipset; + EntityInfoPtr pEnt; + struct pci_device *PciInfo; + + Bool noAccel; + Bool SWCursor; + CursorPtr cursor; + Bool swapThrottling; + Bool dirtyThrottling; + CloseScreenProcPtr CloseScreen; + Bool no3D; + + /* Broken-out options. */ + OptionInfoPtr Options; + + void (*blockHandler)(int, pointer, pointer, pointer); + struct pipe_fence_handle *fence[XORG_NR_FENCES]; + + CreateScreenResourcesProcPtr createScreenResources; + + /* for frontbuffer backing store */ + Bool (*destroy_front_buffer)(ScrnInfoPtr pScrn); + Bool (*create_front_buffer)(ScrnInfoPtr pScrn); + Bool (*bind_front_buffer)(ScrnInfoPtr pScrn); + + /* kms */ + struct kms_driver *kms; + struct kms_bo *root_bo; + + /* gallium */ + struct drm_api *api; + struct pipe_screen *screen; + struct pipe_context *ctx; + boolean d_depth_bits_last; + boolean ds_depth_bits_last; + struct pipe_resource *root_texture; + + /* exa */ + struct exa_context *exa; + Bool noEvict; + Bool accelerate_2d; + Bool debug_fallback; + + CustomizerPtr cust; + +#ifdef DRM_MODE_FEATURE_DIRTYFB + DamagePtr damage; +#endif +} modesettingRec, *modesettingPtr; + +#define modesettingPTR(p) ((modesettingPtr)((p)->driverPrivate)) + +CustomizerPtr xorg_customizer(ScrnInfoPtr pScrn); + +Bool xorg_has_gallium(ScrnInfoPtr pScrn); + +/*********************************************************************** + * xorg_exa.c + */ +struct pipe_resource * +xorg_exa_get_texture(PixmapPtr pPixmap); + +int +xorg_exa_set_displayed_usage(PixmapPtr pPixmap); + +int +xorg_exa_set_shared_usage(PixmapPtr pPixmap); + +Bool +xorg_exa_set_texture(PixmapPtr pPixmap, struct pipe_resource *tex); + +struct pipe_resource * +xorg_exa_create_root_texture(ScrnInfoPtr pScrn, + int width, int height, + int depth, int bpp); + +void * +xorg_exa_init(ScrnInfoPtr pScrn, Bool accel); + +void +xorg_exa_close(ScrnInfoPtr pScrn); + + +/*********************************************************************** + * xorg_dri2.c + */ +Bool +xorg_dri2_init(ScreenPtr pScreen); + +void +xorg_dri2_close(ScreenPtr pScreen); + + +/*********************************************************************** + * xorg_crtc.c + */ +void +xorg_crtc_init(ScrnInfoPtr pScrn); + +void +xorg_crtc_cursor_destroy(xf86CrtcPtr crtc); + + +/*********************************************************************** + * xorg_output.c + */ +void +xorg_output_init(ScrnInfoPtr pScrn); + +unsigned +xorg_output_get_id(xf86OutputPtr output); + + +/*********************************************************************** + * xorg_xv.c + */ +void +xorg_xv_init(ScreenPtr pScreen); + + +#endif /* _XORG_TRACKER_H_ */ diff --git a/src/gallium/state_trackers/xorg/xorg_winsys.h b/src/gallium/state_trackers/xorg/xorg_winsys.h new file mode 100644 index 0000000000..865733bca2 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_winsys.h @@ -0,0 +1,50 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + +/* + * File with all the junk needed to personalize the a xorg driver. + */ + +#ifndef _XORG_WINSYS_H_ +#define _XORG_WINSYS_H_ + +#include "xorg-server.h" +#include "xf86.h" +#include "pciaccess.h" + +#ifndef XSERVER_LIBPCIACCESS +#error "libpciaccess needed" +#endif + +void xorg_tracker_set_functions(ScrnInfoPtr scrn); +const OptionInfoRec * xorg_tracker_available_options(int chipid, int busid); +Bool xorg_tracker_have_modesetting(ScrnInfoPtr pScrn, struct pci_device *device); + +#endif diff --git a/src/gallium/state_trackers/xorg/xorg_xv.c b/src/gallium/state_trackers/xorg/xorg_xv.c new file mode 100644 index 0000000000..f98bd93901 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_xv.c @@ -0,0 +1,768 @@ +#include "xorg_tracker.h" + +#include <xf86xv.h> +#include <X11/extensions/Xv.h> +#include <fourcc.h> + +#include "xorg_exa.h" +#include "xorg_renderer.h" +#include "xorg_exa_tgsi.h" + +#include "cso_cache/cso_context.h" +#include "util/u_sampler.h" + +#include "pipe/p_screen.h" + +/*XXX get these from pipe's texture limits */ +#define IMAGE_MAX_WIDTH 2048 +#define IMAGE_MAX_HEIGHT 2048 + +#define RES_720P_X 1280 +#define RES_720P_Y 720 + + +/* The ITU-R BT.601 conversion matrix for SDTV. */ +/* original, matrix, but we transpose it to + * make the shader easier +static const float bt_601[] = { + 1.0, 0.0, 1.4075, , + 1.0, -0.3455, -0.7169, 0, + 1.0, 1.7790, 0., 0, +};*/ +static const float bt_601[] = { + 1.0, 1.0, 1.0, 0.5, + 0.0, -0.3455, 1.7790, 0, + 1.4075, -0.7169, 0., 0, +}; + +/* The ITU-R BT.709 conversion matrix for HDTV. */ +/* original, but we transpose to make the conversion + * in the shader easier +static const float bt_709[] = { + 1.0, 0.0, 1.581, 0, + 1.0, -0.1881, -0.47, 0, + 1.0, 1.8629, 0., 0, +};*/ +static const float bt_709[] = { + 1.0, 1.0, 1.0, 0.5, + 0.0, -0.1881, 1.8629, 0, + 1.581,-0.47 , 0.0, 0, +}; + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +static Atom xvBrightness, xvContrast; + +#define NUM_TEXTURED_ATTRIBUTES 2 +static XF86AttributeRec TexturedAttributes[NUM_TEXTURED_ATTRIBUTES] = { + {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"}, + {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"} +}; + +#define NUM_FORMATS 3 +static XF86VideoFormatRec Formats[NUM_FORMATS] = { + {15, TrueColor}, {16, TrueColor}, {24, TrueColor} +}; + +static XF86VideoEncodingRec DummyEncoding[1] = { + { + 0, + "XV_IMAGE", + IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, + {1, 1} + } +}; + +#define NUM_IMAGES 3 +static XF86ImageRec Images[NUM_IMAGES] = { + XVIMAGE_UYVY, + XVIMAGE_YUY2, + XVIMAGE_YV12, +}; + +struct xorg_xv_port_priv { + struct xorg_renderer *r; + + RegionRec clip; + + int brightness; + int contrast; + + int current_set; + /* juggle two sets of seperate Y, U and V + * textures */ + struct pipe_resource *yuv[2][3]; + struct pipe_sampler_view *yuv_views[2][3]; +}; + + +static void +stop_video(ScrnInfoPtr pScrn, pointer data, Bool shutdown) +{ + struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; + + REGION_EMPTY(pScrn->pScreen, &priv->clip); +} + +static int +set_port_attribute(ScrnInfoPtr pScrn, + Atom attribute, INT32 value, pointer data) +{ + struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; + + if (attribute == xvBrightness) { + if ((value < -128) || (value > 127)) + return BadValue; + priv->brightness = value; + } else if (attribute == xvContrast) { + if ((value < 0) || (value > 255)) + return BadValue; + priv->contrast = value; + } else + return BadMatch; + + return Success; +} + +static int +get_port_attribute(ScrnInfoPtr pScrn, + Atom attribute, INT32 * value, pointer data) +{ + struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; + + if (attribute == xvBrightness) + *value = priv->brightness; + else if (attribute == xvContrast) + *value = priv->contrast; + else + return BadMatch; + + return Success; +} + +static void +query_best_size(ScrnInfoPtr pScrn, + Bool motion, + short vid_w, short vid_h, + short drw_w, short drw_h, + unsigned int *p_w, unsigned int *p_h, pointer data) +{ + if (vid_w > (drw_w << 1)) + drw_w = vid_w >> 1; + if (vid_h > (drw_h << 1)) + drw_h = vid_h >> 1; + + *p_w = drw_w; + *p_h = drw_h; +} + +static INLINE struct pipe_resource * +create_component_texture(struct pipe_context *pipe, + int width, int height) +{ + struct pipe_screen *screen = pipe->screen; + struct pipe_resource *tex = 0; + struct pipe_resource templ; + + memset(&templ, 0, sizeof(templ)); + templ.target = PIPE_TEXTURE_2D; + templ.format = PIPE_FORMAT_L8_UNORM; + templ.last_level = 0; + templ.width0 = width; + templ.height0 = height; + templ.depth0 = 1; + templ.bind = PIPE_BIND_SAMPLER_VIEW; + + tex = screen->resource_create(screen, &templ); + + return tex; +} + +static int +check_yuv_textures(struct xorg_xv_port_priv *priv, int width, int height) +{ + struct pipe_resource **dst = priv->yuv[priv->current_set]; + struct pipe_sampler_view **dst_view = priv->yuv_views[priv->current_set]; + struct pipe_sampler_view view_templ; + struct pipe_context *pipe = priv->r->pipe; + + if (!dst[0] || + dst[0]->width0 != width || + dst[0]->height0 != height) { + pipe_resource_reference(&dst[0], NULL); + pipe_sampler_view_reference(&dst_view[0], NULL); + } + if (!dst[1] || + dst[1]->width0 != width || + dst[1]->height0 != height) { + pipe_resource_reference(&dst[1], NULL); + pipe_sampler_view_reference(&dst_view[1], NULL); + } + if (!dst[2] || + dst[2]->width0 != width || + dst[2]->height0 != height) { + pipe_resource_reference(&dst[2], NULL); + pipe_sampler_view_reference(&dst_view[2], NULL); + } + + if (!dst[0]) { + dst[0] = create_component_texture(priv->r->pipe, width, height); + if (dst[0]) { + u_sampler_view_default_template(&view_templ, + dst[0], + dst[0]->format); + dst_view[0] = pipe->create_sampler_view(pipe, dst[0], &view_templ); + } + } + + if (!dst[1]) { + dst[1] = create_component_texture(priv->r->pipe, width, height); + if (dst[1]) { + u_sampler_view_default_template(&view_templ, + dst[1], + dst[1]->format); + dst_view[1] = pipe->create_sampler_view(pipe, dst[1], &view_templ); + } + } + + if (!dst[2]) { + dst[2] = create_component_texture(priv->r->pipe, width, height); + if (dst[2]) { + u_sampler_view_default_template(&view_templ, + dst[2], + dst[2]->format); + dst_view[2] = pipe->create_sampler_view(pipe, dst[2], &view_templ); + } + } + + if (!dst[0] || !dst[1] || !dst[2] || !dst_view[0] || !dst_view[1] || !dst_view[2] ) + return BadAlloc; + + return Success; +} + +static int +query_image_attributes(ScrnInfoPtr pScrn, + int id, + unsigned short *w, unsigned short *h, + int *pitches, int *offsets) +{ + int size, tmp; + + if (*w > IMAGE_MAX_WIDTH) + *w = IMAGE_MAX_WIDTH; + if (*h > IMAGE_MAX_HEIGHT) + *h = IMAGE_MAX_HEIGHT; + + *w = (*w + 1) & ~1; + if (offsets) + offsets[0] = 0; + + switch (id) { + case FOURCC_YV12: + *h = (*h + 1) & ~1; + size = (*w + 3) & ~3; + if (pitches) { + pitches[0] = size; + } + size *= *h; + if (offsets) { + offsets[1] = size; + } + tmp = ((*w >> 1) + 3) & ~3; + if (pitches) { + pitches[1] = pitches[2] = tmp; + } + tmp *= (*h >> 1); + size += tmp; + if (offsets) { + offsets[2] = size; + } + size += tmp; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + size = *w << 1; + if (pitches) + pitches[0] = size; + size *= *h; + break; + } + + return size; +} + +static void +copy_packed_data(ScrnInfoPtr pScrn, + struct xorg_xv_port_priv *port, + int id, + unsigned char *buf, + int left, + int top, + unsigned short w, unsigned short h) +{ + int i, j; + struct pipe_resource **dst = port->yuv[port->current_set]; + struct pipe_transfer *ytrans, *utrans, *vtrans; + struct pipe_context *pipe = port->r->pipe; + char *ymap, *vmap, *umap; + unsigned char y1, y2, u, v; + int yidx, uidx, vidx; + int y_array_size = w * h; + + ytrans = pipe_get_transfer(pipe, dst[0], + 0, 0, 0, + PIPE_TRANSFER_WRITE, + left, top, w, h); + utrans = pipe_get_transfer(pipe, dst[1], + 0, 0, 0, + PIPE_TRANSFER_WRITE, + left, top, w, h); + vtrans = pipe_get_transfer(pipe, dst[2], + 0, 0, 0, + PIPE_TRANSFER_WRITE, + left, top, w, h); + + ymap = (char*)pipe->transfer_map(pipe, ytrans); + umap = (char*)pipe->transfer_map(pipe, utrans); + vmap = (char*)pipe->transfer_map(pipe, vtrans); + + yidx = uidx = vidx = 0; + + switch (id) { + case FOURCC_YV12: { + int pitches[3], offsets[3]; + unsigned char *y, *u, *v; + query_image_attributes(pScrn, FOURCC_YV12, + &w, &h, pitches, offsets); + + y = buf + offsets[0]; + v = buf + offsets[1]; + u = buf + offsets[2]; + for (i = 0; i < h; ++i) { + for (j = 0; j < w; ++j) { + int yoffset = (w*i+j); + int ii = (i|1), jj = (j|1); + int vuoffset = (w/2)*(ii/2) + (jj/2); + ymap[yidx++] = y[yoffset]; + umap[uidx++] = u[vuoffset]; + vmap[vidx++] = v[vuoffset]; + } + } + } + break; + case FOURCC_UYVY: + for (i = 0; i < y_array_size; i +=2 ) { + /* extracting two pixels */ + u = buf[0]; + y1 = buf[1]; + v = buf[2]; + y2 = buf[3]; + buf += 4; + + ymap[yidx++] = y1; + ymap[yidx++] = y2; + umap[uidx++] = u; + umap[uidx++] = u; + vmap[vidx++] = v; + vmap[vidx++] = v; + } + break; + case FOURCC_YUY2: + for (i = 0; i < y_array_size; i +=2 ) { + /* extracting two pixels */ + y1 = buf[0]; + u = buf[1]; + y2 = buf[2]; + v = buf[3]; + + buf += 4; + + ymap[yidx++] = y1; + ymap[yidx++] = y2; + umap[uidx++] = u; + umap[uidx++] = u; + vmap[vidx++] = v; + vmap[vidx++] = v; + } + break; + default: + debug_assert(!"Unsupported yuv format!"); + break; + } + + pipe->transfer_unmap(pipe, ytrans); + pipe->transfer_unmap(pipe, utrans); + pipe->transfer_unmap(pipe, vtrans); + pipe->transfer_destroy(pipe, ytrans); + pipe->transfer_destroy(pipe, utrans); + pipe->transfer_destroy(pipe, vtrans); +} + + +static void +setup_fs_video_constants(struct xorg_renderer *r, boolean hdtv) +{ + const int param_bytes = 12 * sizeof(float); + const float *video_constants = (hdtv) ? bt_709 : bt_601; + + renderer_set_constants(r, PIPE_SHADER_FRAGMENT, + video_constants, param_bytes); +} + +static void +draw_yuv(struct xorg_xv_port_priv *port, + float src_x, float src_y, float src_w, float src_h, + int dst_x, int dst_y, int dst_w, int dst_h) +{ + struct pipe_resource **textures = port->yuv[port->current_set]; + + /*debug_printf(" draw_yuv([%d, %d, %d ,%d], [%d, %d, %d, %d])\n", + src_x, src_y, src_w, src_h, + dst_x, dst_y, dst_w, dst_h);*/ + renderer_draw_yuv(port->r, + src_x, src_y, src_w, src_h, + dst_x, dst_y, dst_w, dst_h, + textures); +} + +static void +bind_blend_state(struct xorg_xv_port_priv *port) +{ + 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; + + /* porter&duff 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; + + cso_set_blend(port->r->cso, &blend); +} + + +static void +bind_shaders(struct xorg_xv_port_priv *port) +{ + unsigned vs_traits = 0, fs_traits = 0; + struct xorg_shader shader; + + vs_traits |= VS_YUV; + fs_traits |= FS_YUV; + + shader = xorg_shaders_get(port->r->shaders, vs_traits, fs_traits); + cso_set_vertex_shader_handle(port->r->cso, shader.vs); + cso_set_fragment_shader_handle(port->r->cso, shader.fs); +} + +static INLINE void +conditional_flush(struct pipe_context *pipe, struct pipe_resource **tex, + int num) +{ + int i; + for (i = 0; i < num; ++i) { + if (tex[i] && pipe->is_resource_referenced(pipe, tex[i], 0, 0) & + PIPE_REFERENCED_FOR_WRITE) { + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + return; + } + } +} + +static void +bind_samplers(struct xorg_xv_port_priv *port) +{ + struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; + struct pipe_sampler_state sampler; + struct pipe_resource **dst = port->yuv[port->current_set]; + struct pipe_sampler_view **dst_views = port->yuv_views[port->current_set]; + + memset(&sampler, 0, sizeof(struct pipe_sampler_state)); + + conditional_flush(port->r->pipe, dst, 3); + + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; + sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; + sampler.normalized_coords = 1; + + samplers[0] = &sampler; + samplers[1] = &sampler; + samplers[2] = &sampler; + + + cso_set_samplers(port->r->cso, 3, + (const struct pipe_sampler_state **)samplers); + cso_set_fragment_sampler_views(port->r->cso, 3, dst_views); +} + +static int +display_video(ScrnInfoPtr pScrn, struct xorg_xv_port_priv *pPriv, int id, + RegionPtr dstRegion, + int src_x, int src_y, int src_w, int src_h, + int dstX, int dstY, int dst_w, int dst_h, + PixmapPtr pPixmap) +{ + modesettingPtr ms = modesettingPTR(pScrn); + BoxPtr pbox; + int nbox; + int dxo, dyo; + Bool hdtv; + int x, y, w, h; + struct exa_pixmap_priv *dst; + struct pipe_surface *dst_surf = NULL; + + exaMoveInPixmap(pPixmap); + dst = exaGetPixmapDriverPrivate(pPixmap); + + /*debug_printf("display_video([%d, %d, %d, %d], [%d, %d, %d, %d])\n", + src_x, src_y, src_w, src_h, dstX, dstY, dst_w, dst_h);*/ + + if (dst && !dst->tex) { + xorg_exa_set_shared_usage(pPixmap); + pScrn->pScreen->ModifyPixmapHeader(pPixmap, 0, 0, 0, 0, 0, NULL); + } + + if (!dst || !dst->tex) + XORG_FALLBACK("Xv destination %s", !dst ? "!dst" : "!dst->tex"); + + dst_surf = xorg_gpu_surface(pPriv->r->pipe->screen, dst); + hdtv = ((src_w >= RES_720P_X) && (src_h >= RES_720P_Y)); + + REGION_TRANSLATE(pScrn->pScreen, dstRegion, -pPixmap->screen_x, + -pPixmap->screen_y); + + dxo = dstRegion->extents.x1; + dyo = dstRegion->extents.y1; + + pbox = REGION_RECTS(dstRegion); + nbox = REGION_NUM_RECTS(dstRegion); + + renderer_bind_destination(pPriv->r, dst_surf, + dst_surf->width, dst_surf->height); + + bind_blend_state(pPriv); + bind_shaders(pPriv); + bind_samplers(pPriv); + setup_fs_video_constants(pPriv->r, hdtv); + + DamageDamageRegion(&pPixmap->drawable, dstRegion); + + while (nbox--) { + int box_x1 = pbox->x1; + int box_y1 = pbox->y1; + int box_x2 = pbox->x2; + int box_y2 = pbox->y2; + float diff_x = (float)src_w / (float)dst_w; + float diff_y = (float)src_h / (float)dst_h; + float offset_x = box_x1 - dstX + pPixmap->screen_x; + float offset_y = box_y1 - dstY + pPixmap->screen_y; + float offset_w; + float offset_h; + + x = box_x1; + y = box_y1; + w = box_x2 - box_x1; + h = box_y2 - box_y1; + + offset_w = dst_w - w; + offset_h = dst_h - h; + + draw_yuv(pPriv, + (float) src_x + offset_x*diff_x, (float) src_y + offset_y*diff_y, + (float) src_w - offset_w*diff_x, (float) src_h - offset_h*diff_y, + x, y, w, h); + + pbox++; + } + DamageRegionProcessPending(&pPixmap->drawable); + + pipe_surface_reference(&dst_surf, NULL); + + return TRUE; +} + +static int +put_image(ScrnInfoPtr pScrn, + short src_x, short src_y, + short drw_x, short drw_y, + short src_w, short src_h, + short drw_w, short drw_h, + int id, unsigned char *buf, + short width, short height, + Bool sync, RegionPtr clipBoxes, pointer data, + DrawablePtr pDraw) +{ + struct xorg_xv_port_priv *pPriv = (struct xorg_xv_port_priv *) data; + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + PixmapPtr pPixmap; + INT32 x1, x2, y1, y2; + BoxRec dstBox; + int ret; + + /* Clip */ + x1 = src_x; + x2 = src_x + src_w; + y1 = src_y; + y2 = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, + width, height)) + return Success; + + ret = check_yuv_textures(pPriv, width, height); + + if (ret) + return ret; + + copy_packed_data(pScrn, pPriv, id, buf, + src_x, src_y, width, height); + + if (pDraw->type == DRAWABLE_WINDOW) { + pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw); + } else { + pPixmap = (PixmapPtr)pDraw; + } + + display_video(pScrn, pPriv, id, clipBoxes, + src_x, src_y, src_w, src_h, + drw_x, drw_y, + drw_w, drw_h, pPixmap); + + pPriv->current_set = (pPriv->current_set + 1) & 1; + return Success; +} + +static struct xorg_xv_port_priv * +port_priv_create(struct xorg_renderer *r) +{ + struct xorg_xv_port_priv *priv = NULL; + + priv = calloc(1, sizeof(struct xorg_xv_port_priv)); + + if (!priv) + return NULL; + + priv->r = r; + + REGION_NULL(pScreen, &priv->clip); + + debug_assert(priv && priv->r); + + return priv; +} + +static XF86VideoAdaptorPtr +xorg_setup_textured_adapter(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + XF86VideoAdaptorPtr adapt; + XF86AttributePtr attrs; + DevUnion *dev_unions; + int nports = 16, i; + int nattributes; + + nattributes = NUM_TEXTURED_ATTRIBUTES; + + debug_assert(ms->exa); + debug_assert(ms->exa->renderer); + + adapt = calloc(1, sizeof(XF86VideoAdaptorRec)); + dev_unions = calloc(nports, sizeof(DevUnion)); + attrs = calloc(nattributes, sizeof(XF86AttributeRec)); + if (adapt == NULL || dev_unions == NULL || attrs == NULL) { + free(adapt); + free(dev_unions); + free(attrs); + return NULL; + } + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = 0; + adapt->name = "Gallium3D Textured Video"; + adapt->nEncodings = 1; + adapt->pEncodings = DummyEncoding; + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = Formats; + adapt->nPorts = 0; + adapt->pPortPrivates = dev_unions; + adapt->nAttributes = nattributes; + adapt->pAttributes = attrs; + memcpy(attrs, TexturedAttributes, nattributes * sizeof(XF86AttributeRec)); + adapt->nImages = NUM_IMAGES; + adapt->pImages = Images; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = stop_video; + adapt->SetPortAttribute = set_port_attribute; + adapt->GetPortAttribute = get_port_attribute; + adapt->QueryBestSize = query_best_size; + adapt->PutImage = put_image; + adapt->QueryImageAttributes = query_image_attributes; + + for (i = 0; i < nports; i++) { + struct xorg_xv_port_priv *priv = + port_priv_create(ms->exa->renderer); + + adapt->pPortPrivates[i].ptr = (pointer) (priv); + adapt->nPorts++; + } + + return adapt; +} + +void +xorg_xv_init(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + /*modesettingPtr ms = modesettingPTR(pScrn);*/ + XF86VideoAdaptorPtr *adaptors, *new_adaptors = NULL; + XF86VideoAdaptorPtr textured_adapter; + int num_adaptors; + + num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); + new_adaptors = malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *)); + if (new_adaptors == NULL) + return; + + memcpy(new_adaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr)); + adaptors = new_adaptors; + + /* Add the adaptors supported by our hardware. First, set up the atoms + * that will be used by both output adaptors. + */ + xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); + xvContrast = MAKE_ATOM("XV_CONTRAST"); + + textured_adapter = xorg_setup_textured_adapter(pScreen); + + debug_assert(textured_adapter); + + if (textured_adapter) { + adaptors[num_adaptors++] = textured_adapter; + } + + if (num_adaptors) { + xf86XVScreenInit(pScreen, adaptors, num_adaptors); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling Xv because no adaptors could be initialized.\n"); + } + + free(adaptors); +} |