st/xorg: add yuv vertex shader
authorZack Rusin <zackr@vmware.com>
Sat, 24 Oct 2009 05:05:40 +0000 (01:05 -0400)
committerZack Rusin <zackr@vmware.com>
Mon, 26 Oct 2009 12:15:48 +0000 (08:15 -0400)
plus some general fixes

src/gallium/state_trackers/xorg/xorg_exa_tgsi.c
src/gallium/state_trackers/xorg/xorg_exa_tgsi.h
src/gallium/state_trackers/xorg/xorg_renderer.c
src/gallium/state_trackers/xorg/xorg_renderer.h
src/gallium/state_trackers/xorg/xorg_xv.c

index 950389170184b5be5a86ea75f938106dd79bc24a..7cb11dc42bd1d3b91282ce50fd27d5b13f0042a6 100644 (file)
@@ -236,6 +236,7 @@ create_vs(struct pipe_context *pipe,
    boolean is_fill = vs_traits & VS_FILL;
    boolean is_composite = vs_traits & VS_COMPOSITE;
    boolean has_mask = vs_traits & VS_MASK;
+   boolean is_yuv = vs_traits & VS_YUV;
    unsigned input_slot = 0;
 
    ureg = ureg_create(TGSI_PROCESSOR_VERTEX);
@@ -254,6 +255,20 @@ create_vs(struct pipe_context *pipe,
                              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);
+
+      src = ureg_DECL_vs_input(ureg, input_slot++);
+      dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 1);
+      ureg_MOV(ureg, dst, src);
+
+      src = ureg_DECL_vs_input(ureg, input_slot++);
+      dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 2);
+      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);
index b373d1357bbfbf17d57e359cd6d6775120481386..d3bfa304c2be19aac775ccd6339273bebc0372fb 100644 (file)
@@ -9,10 +9,12 @@ enum xorg_vs_traits {
    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)
-   /*VS_TRANSFORM      = 1 << 5*/
 };
 
 enum xorg_fs_traits {
index 51941f091cb8edf839ba60b2c474d5623a00832e..ec5268f9d6c39734883602e6eb0dea54828905e2 100644 (file)
@@ -224,6 +224,44 @@ setup_vertex_data2(struct xorg_renderer *r,
                                   sizeof(r->vertices3));
 }
 
+static struct pipe_buffer *
+setup_vertex_data_yuv(struct xorg_renderer *r,
+                      float srcX, float srcY,
+                      float dstX, float dstY,
+                      float width, float height,
+                      struct pipe_texture **tex)
+{
+   float s0, t0, s1, t1;
+   float spt0[2], spt1[2];
+
+   spt0[0] = srcX;
+   spt0[1] = srcY;
+   spt1[0] = srcX + width;
+   spt1[1] = srcY + height;
+
+   s0 = spt0[0] / tex[0]->width[0];
+   t0 = spt0[1] / tex[0]->height[0];
+   s1 = spt1[0] / tex[0]->width[0];
+   t1 = spt1[1] / tex[0]->height[0];
+
+   /* 1st vertex */
+   setup_vertex1(r->vertices2[0], dstX, dstY, s0, t0);
+   /* 2nd vertex */
+   setup_vertex1(r->vertices2[1], dstX + width, dstY,
+                 s1, t0);
+   /* 3rd vertex */
+   setup_vertex1(r->vertices2[2], dstX + width, dstY + height,
+                 s1, t1);
+   /* 4th vertex */
+   setup_vertex1(r->vertices2[3], dstX, dstY + height,
+                 s0, t1);
+
+
+   return pipe_user_buffer_create(r->pipe->screen,
+                                  r->vertices2,
+                                  sizeof(r->vertices2));
+}
+
 
 
 static void
@@ -825,6 +863,13 @@ void renderer_draw_textures(struct xorg_renderer *r,
                                textures[0], textures[1],
                                src_matrix, mask_matrix);
       break;
+   case 3:
+      buf = setup_vertex_data_yuv(r,
+                                  pos[0], pos[1],
+                                  pos[2], pos[3],
+                                  width, height,
+                                  textures);
+      break;
    default:
       debug_assert(!"Unsupported number of textures");
       break;
index 3e37c9aa9301bb3004bb7c2b9ba4a16891343858..f86ef670beefcb042c3f59201777bbc64137e746 100644 (file)
@@ -16,7 +16,7 @@ struct xorg_renderer {
    struct pipe_constant_buffer vs_const_buffer;
    struct pipe_constant_buffer fs_const_buffer;
 
-   /* we should combine these two */
+   /* we should combine these three */
    float vertices2[4][2][4];
    float vertices3[4][3][4];
 };
index 6d057b4c75f03c5681030c3852d0c329a3891a80..983310f9b5235336bb558b808153665380092696 100644 (file)
@@ -6,6 +6,9 @@
 
 #include "xorg_exa.h"
 #include "xorg_renderer.h"
+#include "xorg_exa_tgsi.h"
+
+#include "cso_cache/cso_context.h"
 
 #include "pipe/p_screen.h"
 #include "pipe/p_inlines.h"
@@ -280,43 +283,144 @@ copy_packed_data(ScrnInfoPtr pScrn,
    screen->tex_transfer_destroy(vtrans);
 }
 
+
+static void
+setup_vs_video_constants(struct xorg_renderer *r, struct exa_pixmap_priv *dst)
+{
+   int width = dst->tex->width[0];
+   int height = dst->tex->height[0];
+   const int param_bytes = 8 * sizeof(float);
+   float vs_consts[8] = {
+      2.f/width, 2.f/height, 1, 1,
+      -1, -1, 0, 0
+   };
+
+   renderer_set_constants(r, PIPE_SHADER_VERTEX,
+                          vs_consts, param_bytes);
+}
+
 static void
-setup_video_constants(struct xorg_renderer *r, boolean hdtv)
+setup_fs_video_constants(struct xorg_renderer *r, boolean hdtv)
 {
-   struct pipe_context *pipe = r->pipe;
    const int param_bytes = 12 * sizeof(float);
-   struct pipe_constant_buffer *cbuf = &r->fs_const_buffer;
+   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, int src_x, int src_y,
+         int dst_x, int dst_y,
+         int w, int h)
+{
+   int pos[4] = {src_x, src_y,
+                 dst_x, dst_y};
+   struct pipe_texture **textures = port->yuv[port->current_set];
+
+   renderer_draw_textures(port->r,
+                          pos, w, h,
+                          textures,
+                          3, /*bound samplers/textures */
+                          NULL, NULL /* no transformations */);
+}
+
+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.blend_enable = 1;
+   blend.colormask |= PIPE_MASK_RGBA;
+
+   /* porter&duff src */
+   blend.rgb_src_factor   = PIPE_BLENDFACTOR_ONE;
+   blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+   blend.rgb_dst_factor   = PIPE_BLENDFACTOR_ZERO;
+   blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
 
-   pipe_buffer_reference(&cbuf->buffer, NULL);
-   cbuf->buffer = pipe_buffer_create(pipe->screen, 16,
-                                     PIPE_BUFFER_USAGE_CONSTANT,
-                                     param_bytes);
+   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;
 
-   if (cbuf->buffer) {
-      const float *video_constants = (hdtv) ? bt_709 : bt_601;
+   vs_traits |= VS_YUV;
+   fs_traits |= FS_YUV;
 
-      pipe_buffer_write(pipe->screen, cbuf->buffer,
-                        0, param_bytes, video_constants);
+   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_texture **tex,
+                  int num)
+{
+   int i;
+   for (i = 0; i < num; ++i) {
+      if (tex[i] && pipe->is_texture_referenced(pipe, tex[i], 0, 0) &
+          PIPE_REFERENCED_FOR_WRITE) {
+         pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
+         return;
+      }
    }
-   pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, cbuf);
+}
+
+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_texture **dst = port->yuv[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_sampler_textures(port->r->cso, 3,
+                            dst);
 }
 
 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,
               short width, short height,
-              int x1, int y1, int x2, int y2,
-              short src_w, short src_h, short drw_w, short drw_h,
               PixmapPtr pPixmap)
 {
+   modesettingPtr ms = modesettingPTR(pScrn);
    BoxPtr pbox;
    int nbox;
    int dxo, dyo;
    Bool hdtv;
-   float tc0[2], tc1[2], tc2[2];
+   int x, y, w, h;
+   struct exa_pixmap_priv *dst = exaGetPixmapDriverPrivate(pPixmap);
+
+   if (!dst || !dst->tex)
+      XORG_FALLBACK("Xv destination %s", !dst ? "!dst" : "!dst->tex");
 
    hdtv = ((src_w >= RES_720P_X) && (src_h >= RES_720P_Y));
-   setup_video_constants(pPriv->r, hdtv);
 
    REGION_TRANSLATE(pScrn->pScreen, dstRegion, -pPixmap->screen_x,
                     -pPixmap->screen_y);
@@ -327,32 +431,32 @@ display_video(ScrnInfoPtr pScrn, struct xorg_xv_port_priv *pPriv, int id,
    pbox = REGION_RECTS(dstRegion);
    nbox = REGION_NUM_RECTS(dstRegion);
 
+   renderer_bind_framebuffer(pPriv->r, dst);
+   renderer_bind_viewport(pPriv->r, dst);
+   bind_blend_state(pPriv);
+   renderer_bind_rasterizer(pPriv->r);
+   bind_shaders(pPriv);
+   bind_samplers(pPriv);
+   setup_vs_video_constants(pPriv->r, dst);
+   setup_fs_video_constants(pPriv->r, hdtv);
+
    while (nbox--) {
       int box_x1 = pbox->x1;
       int box_y1 = pbox->y1;
       int box_x2 = pbox->x2;
       int box_y2 = pbox->y2;
 
-      tc0[0] = (double) (box_x1 - dxo) / (double) drw_w; /* u0 */
-      tc0[1] = (double) (box_y1 - dyo) / (double) drw_h; /* v0 */
-      tc1[0] = (double) (box_x2 - dxo) / (double) drw_w; /* u1 */
-      tc1[1] = tc0[1];
-      tc2[0] = tc0[0];
-      tc2[1] = (double) (box_y2 - dyo) / (double) drw_h; /* v1 */
-
-#if 0
       x = box_x1;
       y = box_y1;
       w = box_x2 - box_x1;
       h = box_y2 - box_y1;
 
+      draw_yuv(pPriv, x, y, x, y, w, h);
+
       pbox++;
-      draw_yuv(pScrn, x, y, w, h, &src, 1, FALSE,
-               0, tc0, tc1, tc2, 1,
-               pPriv->conversionData);
-#endif
    }
    DamageDamageRegion(&pPixmap->drawable, dstRegion);
+
    return TRUE;
 }
 
@@ -412,9 +516,10 @@ put_image(ScrnInfoPtr pScrn,
       pPixmap = (PixmapPtr)pDraw;
    }
 
-   display_video(pScrn, pPriv, id, clipBoxes, width, height,
-                 x1, y1, x2, y2,
-                 src_w, src_h, drw_w, drw_h, pPixmap);
+   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;