Merge remote branch 'origin/master' into pipe-video
[mesa.git] / src / gallium / auxiliary / vl / vl_compositor.c
index e6d787b4d74db9120b4f427a50f8d35695502962..d7b29497ace9a56dcfe626f05f3a8bd54435996e 100644 (file)
  **************************************************************************/
 
 #include "vl_compositor.h"
+#include "util/u_draw.h"
 #include <assert.h>
 #include <pipe/p_context.h>
-#include <pipe/p_inlines.h>
-#include <tgsi/tgsi_ureg.h>
+#include <util/u_inlines.h>
 #include <util/u_memory.h>
+#include <util/u_keymap.h>
+#include <util/u_draw.h>
+#include <util/u_sampler.h>
+#include <tgsi/tgsi_ureg.h>
 #include "vl_csc.h"
 
 struct vertex_shader_consts
@@ -96,7 +100,7 @@ create_vert_shader(struct vl_compositor *c)
 }
 
 static bool
-create_frag_shader(struct vl_compositor *c)
+create_frag_shader_ycbcr_2_rgb(struct vl_compositor *c)
 {
    struct ureg_program *shader;
    struct ureg_src tc;
@@ -128,8 +132,37 @@ create_frag_shader(struct vl_compositor *c)
    ureg_release_temporary(shader, texel);
    ureg_END(shader);
 
-   c->fragment_shader = ureg_create_shader_and_destroy(shader, c->pipe);
-   if (!c->fragment_shader)
+   c->fragment_shader.ycbcr_2_rgb = ureg_create_shader_and_destroy(shader, c->pipe);
+   if (!c->fragment_shader.ycbcr_2_rgb)
+      return false;
+
+   return true;
+}
+
+static bool
+create_frag_shader_rgb_2_rgb(struct vl_compositor *c)
+{
+   struct ureg_program *shader;
+   struct ureg_src tc;
+   struct ureg_src sampler;
+   struct ureg_dst fragment;
+
+   shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+   if (!shader)
+      return false;
+
+   tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
+   sampler = ureg_DECL_sampler(shader, 0);
+   fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
+
+   /*
+    * fragment = tex(tc, sampler)
+    */
+   ureg_TEX(shader, fragment, TGSI_TEXTURE_2D, tc, sampler);
+   ureg_END(shader);
+
+   c->fragment_shader.rgb_2_rgb = ureg_create_shader_and_destroy(shader, c->pipe);
+   if (!c->fragment_shader.rgb_2_rgb)
       return false;
 
    return true;
@@ -145,6 +178,7 @@ init_pipe_state(struct vl_compositor *c)
    c->fb_state.nr_cbufs = 1;
    c->fb_state.zsbuf = NULL;
 
+   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;
@@ -154,7 +188,6 @@ init_pipe_state(struct vl_compositor *c)
    sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
    sampler.compare_func = PIPE_FUNC_ALWAYS;
    sampler.normalized_coords = 1;
-   /*sampler.prefilter = ;*/
    /*sampler.lod_bias = ;*/
    /*sampler.min_lod = ;*/
    /*sampler.max_lod = ;*/
@@ -177,8 +210,18 @@ init_shaders(struct vl_compositor *c)
 {
    assert(c);
 
-   create_vert_shader(c);
-   create_frag_shader(c);
+   if (!create_vert_shader(c)) {
+      debug_printf("Unable to create vertex shader.\n");
+      return false;
+   }
+   if (!create_frag_shader_ycbcr_2_rgb(c)) {
+      debug_printf("Unable to create YCbCr-to-RGB fragment shader.\n");
+      return false;
+   }
+   if (!create_frag_shader_rgb_2_rgb(c)) {
+      debug_printf("Unable to create RGB-to-RGB fragment shader.\n");
+      return false;
+   }
 
    return true;
 }
@@ -188,13 +231,15 @@ static void cleanup_shaders(struct vl_compositor *c)
    assert(c);
 
    c->pipe->delete_vs_state(c->pipe, c->vertex_shader);
-   c->pipe->delete_fs_state(c->pipe, c->fragment_shader);
+   c->pipe->delete_fs_state(c->pipe, c->fragment_shader.ycbcr_2_rgb);
+   c->pipe->delete_fs_state(c->pipe, c->fragment_shader.rgb_2_rgb);
 }
 
 static bool
 init_buffers(struct vl_compositor *c)
 {
    struct fragment_shader_consts fsc;
+   struct pipe_vertex_element vertex_elems[2];
 
    assert(c);
 
@@ -204,32 +249,33 @@ init_buffers(struct vl_compositor *c)
    c->vertex_buf.stride = sizeof(struct vertex4f);
    c->vertex_buf.max_index = (VL_COMPOSITOR_MAX_LAYERS + 2) * 6 - 1;
    c->vertex_buf.buffer_offset = 0;
+   /* XXX: Create with DYNAMIC or STREAM */
    c->vertex_buf.buffer = pipe_buffer_create
    (
       c->pipe->screen,
-      1,
-      PIPE_BUFFER_USAGE_VERTEX,
+      PIPE_BIND_VERTEX_BUFFER,
       sizeof(struct vertex4f) * (VL_COMPOSITOR_MAX_LAYERS + 2) * 6
    );
 
-   c->vertex_elems[0].src_offset = 0;
-   c->vertex_elems[0].vertex_buffer_index = 0;
-   c->vertex_elems[0].nr_components = 2;
-   c->vertex_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT;
-   c->vertex_elems[1].src_offset = sizeof(struct vertex2f);
-   c->vertex_elems[1].vertex_buffer_index = 0;
-   c->vertex_elems[1].nr_components = 2;
-   c->vertex_elems[1].src_format = PIPE_FORMAT_R32G32_FLOAT;
+   vertex_elems[0].src_offset = 0;
+   vertex_elems[0].instance_divisor = 0;
+   vertex_elems[0].vertex_buffer_index = 0;
+   vertex_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT;
+   vertex_elems[1].src_offset = sizeof(struct vertex2f);
+   vertex_elems[1].instance_divisor = 0;
+   vertex_elems[1].vertex_buffer_index = 0;
+   vertex_elems[1].src_format = PIPE_FORMAT_R32G32_FLOAT;
+   c->vertex_elems_state = c->pipe->create_vertex_elements_state(c->pipe, 2, vertex_elems);
 
    /*
     * Create our fragment shader's constant buffer
     * Const buffer contains the color conversion matrix and bias vectors
     */
-   c->fs_const_buf.buffer = pipe_buffer_create
+   /* XXX: Create with IMMUTABLE/STATIC... although it does change every once in a long while... */
+   c->fs_const_buf = pipe_buffer_create
    (
       c->pipe->screen,
-      1,
-      PIPE_BUFFER_USAGE_CONSTANT,
+      PIPE_BIND_CONSTANT_BUFFER,
       sizeof(struct fragment_shader_consts)
    );
 
@@ -245,8 +291,24 @@ cleanup_buffers(struct vl_compositor *c)
 {
    assert(c);
 
-   pipe_buffer_reference(&c->vertex_buf.buffer, NULL);
-   pipe_buffer_reference(&c->fs_const_buf.buffer, NULL);
+   c->pipe->delete_vertex_elements_state(c->pipe, c->vertex_elems_state);
+   pipe_resource_reference(&c->vertex_buf.buffer, NULL);
+   pipe_resource_reference(&c->fs_const_buf, NULL);
+}
+
+static void
+texview_map_delete(const struct keymap *map,
+                   const void *key, void *data,
+                   void *user)
+{
+   struct pipe_sampler_view *sv = (struct pipe_sampler_view*)data;
+
+   assert(map);
+   assert(key);
+   assert(data);
+   assert(user);
+
+   pipe_sampler_view_reference(&sv, NULL);
 }
 
 bool vl_compositor_init(struct vl_compositor *compositor, struct pipe_context *pipe)
@@ -259,13 +321,22 @@ bool vl_compositor_init(struct vl_compositor *compositor, struct pipe_context *p
 
    compositor->pipe = pipe;
 
-   if (!init_pipe_state(compositor))
+   compositor->texview_map = util_new_keymap(sizeof(struct pipe_surface*), -1,
+                                             texview_map_delete);
+   if (!compositor->texview_map)
+      return false;
+
+   if (!init_pipe_state(compositor)) {
+      util_delete_keymap(compositor->texview_map, compositor->pipe);
       return false;
+   }
    if (!init_shaders(compositor)) {
+      util_delete_keymap(compositor->texview_map, compositor->pipe);
       cleanup_pipe_state(compositor);
       return false;
    }
    if (!init_buffers(compositor)) {
+      util_delete_keymap(compositor->texview_map, compositor->pipe);
       cleanup_shaders(compositor);
       cleanup_pipe_state(compositor);
       return false;
@@ -286,20 +357,21 @@ void vl_compositor_cleanup(struct vl_compositor *compositor)
 {
    assert(compositor);
 
+   util_delete_keymap(compositor->texview_map, compositor->pipe);
    cleanup_buffers(compositor);
    cleanup_shaders(compositor);
    cleanup_pipe_state(compositor);
 }
 
 void vl_compositor_set_background(struct vl_compositor *compositor,
-                                 struct pipe_texture *bg, struct pipe_video_rect *bg_src_rect)
+                                 struct pipe_surface *bg, struct pipe_video_rect *bg_src_rect)
 {
    assert(compositor);
    assert((bg && bg_src_rect) || (!bg && !bg_src_rect));
 
    if (compositor->bg != bg ||
        !u_video_rects_equal(&compositor->bg_src_rect, bg_src_rect)) {
-      pipe_texture_reference(&compositor->bg, bg);
+      pipe_surface_reference(&compositor->bg, bg);
       /*if (!u_video_rects_equal(&compositor->bg_src_rect, bg_src_rect))*/
          compositor->bg_src_rect = *bg_src_rect;
       compositor->dirty_bg = true;
@@ -307,7 +379,7 @@ void vl_compositor_set_background(struct vl_compositor *compositor,
 }
 
 void vl_compositor_set_layers(struct vl_compositor *compositor,
-                              struct pipe_texture *layers[],
+                              struct pipe_surface *layers[],
                               struct pipe_video_rect *src_rects[],
                               struct pipe_video_rect *dst_rects[],
                               unsigned num_layers)
@@ -326,17 +398,20 @@ void vl_compositor_set_layers(struct vl_compositor *compositor,
           !u_video_rects_equal(&compositor->layer_src_rects[i], src_rects[i]) ||
           !u_video_rects_equal(&compositor->layer_dst_rects[i], dst_rects[i]))
       {
-         pipe_texture_reference(&compositor->layers[i], layers[i]);
+         pipe_surface_reference(&compositor->layers[i], layers[i]);
          /*if (!u_video_rects_equal(&compositor->layer_src_rects[i], src_rects[i]))*/
             compositor->layer_src_rects[i] = *src_rects[i];
          /*if (!u_video_rects_equal(&compositor->layer_dst_rects[i], dst_rects[i]))*/
             compositor->layer_dst_rects[i] = *dst_rects[i];
          compositor->dirty_layers |= 1 << i;
       }
+
+      if (layers[i])
+         compositor->dirty_layers |= 1 << i;
    }
 
    for (; i < VL_COMPOSITOR_MAX_LAYERS; ++i)
-      pipe_texture_reference(&compositor->layers[i], NULL);
+      pipe_surface_reference(&compositor->layers[i], NULL);
 }
 
 static void gen_rect_verts(unsigned pos,
@@ -384,12 +459,14 @@ static void gen_rect_verts(unsigned pos,
 }
 
 static unsigned gen_data(struct vl_compositor *c,
-                         struct pipe_texture *src_surface,
+                         struct pipe_surface *src_surface,
                          struct pipe_video_rect *src_rect,
                          struct pipe_video_rect *dst_rect,
-                         struct pipe_texture **textures)
+                         struct pipe_surface **textures,
+                         void **frag_shaders)
 {
    void *vb;
+   struct pipe_transfer *buf_transfer;
    unsigned num_rects = 0;
    unsigned i;
 
@@ -399,24 +476,29 @@ static unsigned gen_data(struct vl_compositor *c,
    assert(dst_rect);
    assert(textures);
 
-   vb = pipe_buffer_map(c->pipe->screen, c->vertex_buf.buffer,
-                        PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_DISCARD);
+   vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
+                        PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
+                        &buf_transfer);
 
    if (!vb)
       return 0;
 
    if (c->dirty_bg) {
-      struct vertex2f bg_inv_size = {1.0f / c->bg->width0, 1.0f / c->bg->height0};
+      struct vertex2f bg_inv_size = {1.0f / c->bg->width, 1.0f / c->bg->height};
       gen_rect_verts(num_rects, &c->bg_src_rect, &bg_inv_size, NULL, NULL, vb);
       textures[num_rects] = c->bg;
+      /* XXX: Hack */
+      frag_shaders[num_rects] = c->fragment_shader.rgb_2_rgb;
       ++num_rects;
       c->dirty_bg = false;
    }
 
    {
-      struct vertex2f src_inv_size = { 1.0f / src_surface->width0, 1.0f / src_surface->height0};
+      struct vertex2f src_inv_size = { 1.0f / src_surface->width, 1.0f / src_surface->height};
       gen_rect_verts(num_rects, src_rect, &src_inv_size, dst_rect, &c->fb_inv_size, vb);
       textures[num_rects] = src_surface;
+      /* XXX: Hack, sort of */
+      frag_shaders[num_rects] = c->fragment_shader.ycbcr_2_rgb;
       ++num_rects;
    }
 
@@ -424,27 +506,30 @@ static unsigned gen_data(struct vl_compositor *c,
       assert(i < VL_COMPOSITOR_MAX_LAYERS);
 
       if (c->dirty_layers & (1 << i)) {
-         struct vertex2f layer_inv_size = {1.0f / c->layers[i]->width0, 1.0f / c->layers[i]->height0};
+         struct vertex2f layer_inv_size = {1.0f / c->layers[i]->width, 1.0f / c->layers[i]->height};
          gen_rect_verts(num_rects, &c->layer_src_rects[i], &layer_inv_size,
                         &c->layer_dst_rects[i], &c->fb_inv_size, vb);
          textures[num_rects] = c->layers[i];
+         /* XXX: Hack */
+         frag_shaders[num_rects] = c->fragment_shader.rgb_2_rgb;
          ++num_rects;
          c->dirty_layers &= ~(1 << i);
       }
    }
 
-   pipe_buffer_unmap(c->pipe->screen, c->vertex_buf.buffer);
+   pipe_buffer_unmap(c->pipe, buf_transfer);
 
    return num_rects;
 }
 
 static void draw_layers(struct vl_compositor *c,
-                        struct pipe_texture *src_surface,
+                        struct pipe_surface *src_surface,
                         struct pipe_video_rect *src_rect,
                         struct pipe_video_rect *dst_rect)
 {
    unsigned num_rects;
-   struct pipe_texture *textures[VL_COMPOSITOR_MAX_LAYERS + 2];
+   struct pipe_surface *src_surfaces[VL_COMPOSITOR_MAX_LAYERS + 2];
+   void *frag_shaders[VL_COMPOSITOR_MAX_LAYERS + 2];
    unsigned i;
 
    assert(c);
@@ -452,23 +537,45 @@ static void draw_layers(struct vl_compositor *c,
    assert(src_rect);
    assert(dst_rect);
 
-   num_rects = gen_data(c, src_surface, src_rect, dst_rect, textures);
+   num_rects = gen_data(c, src_surface, src_rect, dst_rect, src_surfaces, frag_shaders);
 
    for (i = 0; i < num_rects; ++i) {
-      c->pipe->set_fragment_sampler_textures(c->pipe, 1, &textures[i]);
-      c->pipe->draw_arrays(c->pipe, PIPE_PRIM_TRIANGLES, i * 6, 6);
+      boolean delete_view = FALSE;
+      struct pipe_sampler_view *surface_view = (struct pipe_sampler_view*)util_keymap_lookup(c->texview_map,
+                                                                                             &src_surfaces[i]);
+      if (!surface_view) {
+         struct pipe_sampler_view templat;
+         u_sampler_view_default_template(&templat, src_surfaces[i]->texture,
+                                         src_surfaces[i]->texture->format);
+         surface_view = c->pipe->create_sampler_view(c->pipe, src_surfaces[i]->texture,
+                                                     &templat);
+         if (!surface_view)
+            return;
+
+         delete_view = !util_keymap_insert(c->texview_map, &src_surfaces[i],
+                                           surface_view, c->pipe);
+      }
+
+      c->pipe->bind_fs_state(c->pipe, frag_shaders[i]);
+      c->pipe->set_fragment_sampler_views(c->pipe, 1, &surface_view);
+
+      util_draw_arrays(c->pipe, PIPE_PRIM_TRIANGLES, i * 6, 6);
+
+      if (delete_view) {
+         pipe_sampler_view_reference(&surface_view, NULL);
+      }
    }
 }
 
 void vl_compositor_render(struct vl_compositor          *compositor,
-                          struct pipe_texture           *src_surface,
+                          struct pipe_surface           *src_surface,
                           enum pipe_mpeg12_picture_type picture_type,
                           /*unsigned                    num_past_surfaces,
-                          struct pipe_texture           *past_surfaces,
+                          struct pipe_surface           *past_surfaces,
                           unsigned                      num_future_surfaces,
-                          struct pipe_texture           *future_surfaces,*/
+                          struct pipe_surface           *future_surfaces,*/
                           struct pipe_video_rect        *src_area,
-                          struct pipe_texture           *dst_surface,
+                          struct pipe_surface           *dst_surface,
                           struct pipe_video_rect        *dst_area,
                           struct pipe_fence_handle      **fence)
 {
@@ -479,21 +586,16 @@ void vl_compositor_render(struct vl_compositor          *compositor,
    assert(dst_area);
    assert(picture_type == PIPE_MPEG12_PICTURE_TYPE_FRAME);
 
-   if (compositor->fb_state.width != dst_surface->width0) {
-      compositor->fb_inv_size.x = 1.0f / dst_surface->width0;
-      compositor->fb_state.width = dst_surface->width0;
+   if (compositor->fb_state.width != dst_surface->width) {
+      compositor->fb_inv_size.x = 1.0f / dst_surface->width;
+      compositor->fb_state.width = dst_surface->width;
    }
-   if (compositor->fb_state.height != dst_surface->height0) {
-      compositor->fb_inv_size.y = 1.0f / dst_surface->height0;
-      compositor->fb_state.height = dst_surface->height0;
+   if (compositor->fb_state.height != dst_surface->height) {
+      compositor->fb_inv_size.y = 1.0f / dst_surface->height;
+      compositor->fb_state.height = dst_surface->height;
    }
 
-   compositor->fb_state.cbufs[0] = compositor->pipe->screen->get_tex_surface
-   (
-      compositor->pipe->screen,
-      dst_surface,
-      0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ_WRITE
-   );
+   compositor->fb_state.cbufs[0] = dst_surface;
 
    compositor->viewport.scale[0] = compositor->fb_state.width;
    compositor->viewport.scale[1] = compositor->fb_state.height;
@@ -508,30 +610,30 @@ void vl_compositor_render(struct vl_compositor          *compositor,
    compositor->pipe->set_viewport_state(compositor->pipe, &compositor->viewport);
    compositor->pipe->bind_fragment_sampler_states(compositor->pipe, 1, &compositor->sampler);
    compositor->pipe->bind_vs_state(compositor->pipe, compositor->vertex_shader);
-   compositor->pipe->bind_fs_state(compositor->pipe, compositor->fragment_shader);
    compositor->pipe->set_vertex_buffers(compositor->pipe, 1, &compositor->vertex_buf);
-   compositor->pipe->set_vertex_elements(compositor->pipe, 2, compositor->vertex_elems);
-   compositor->pipe->set_constant_buffer(compositor->pipe, PIPE_SHADER_FRAGMENT, 0, &compositor->fs_const_buf);
+   compositor->pipe->bind_vertex_elements_state(compositor->pipe, compositor->vertex_elems_state);
+   compositor->pipe->set_constant_buffer(compositor->pipe, PIPE_SHADER_FRAGMENT, 0, compositor->fs_const_buf);
 
    draw_layers(compositor, src_surface, src_area, dst_area);
 
    assert(!compositor->dirty_bg && !compositor->dirty_layers);
    compositor->pipe->flush(compositor->pipe, PIPE_FLUSH_RENDER_CACHE, fence);
-
-   pipe_surface_reference(&compositor->fb_state.cbufs[0], NULL);
 }
 
 void vl_compositor_set_csc_matrix(struct vl_compositor *compositor, const float *mat)
 {
+   struct pipe_transfer *buf_transfer;
+
    assert(compositor);
 
    memcpy
    (
-      pipe_buffer_map(compositor->pipe->screen, compositor->fs_const_buf.buffer,
-                      PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_DISCARD),
-      mat,
-      sizeof(struct fragment_shader_consts)
+      pipe_buffer_map(compositor->pipe, compositor->fs_const_buf,
+                      PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
+                      &buf_transfer),
+               mat,
+               sizeof(struct fragment_shader_consts)
    );
 
-   pipe_buffer_unmap(compositor->pipe->screen, compositor->fs_const_buf.buffer);
+   pipe_buffer_unmap(compositor->pipe, buf_transfer);
 }