Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 3769 → Rev 3770

/drivers/video/Gallium/auxiliary/vl/vl_compositor.c
0,0 → 1,1096
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* 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.
*
**************************************************************************/
 
#include <assert.h>
 
#include "pipe/p_compiler.h"
#include "pipe/p_context.h"
 
#include "util/u_memory.h"
#include "util/u_draw.h"
#include "util/u_surface.h"
 
#include "tgsi/tgsi_ureg.h"
 
#include "vl_csc.h"
#include "vl_types.h"
#include "vl_compositor.h"
 
#define MIN_DIRTY (0)
#define MAX_DIRTY (1 << 15)
 
enum VS_OUTPUT
{
VS_O_VPOS = 0,
VS_O_COLOR = 0,
VS_O_VTEX = 0,
VS_O_VTOP,
VS_O_VBOTTOM,
};
 
static void *
create_vert_shader(struct vl_compositor *c)
{
struct ureg_program *shader;
struct ureg_src vpos, vtex, color;
struct ureg_dst tmp;
struct ureg_dst o_vpos, o_vtex, o_color;
struct ureg_dst o_vtop, o_vbottom;
 
shader = ureg_create(TGSI_PROCESSOR_VERTEX);
if (!shader)
return false;
 
vpos = ureg_DECL_vs_input(shader, 0);
vtex = ureg_DECL_vs_input(shader, 1);
color = ureg_DECL_vs_input(shader, 2);
tmp = ureg_DECL_temporary(shader);
o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
o_color = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, VS_O_COLOR);
o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX);
o_vtop = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTOP);
o_vbottom = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VBOTTOM);
 
/*
* o_vpos = vpos
* o_vtex = vtex
* o_color = color
*/
ureg_MOV(shader, o_vpos, vpos);
ureg_MOV(shader, o_vtex, vtex);
ureg_MOV(shader, o_color, color);
 
/*
* tmp.x = vtex.w / 2
* tmp.y = vtex.w / 4
*
* o_vtop.x = vtex.x
* o_vtop.y = vtex.y * tmp.x + 0.25f
* o_vtop.z = vtex.y * tmp.y + 0.25f
* o_vtop.w = 1 / tmp.x
*
* o_vbottom.x = vtex.x
* o_vbottom.y = vtex.y * tmp.x - 0.25f
* o_vbottom.z = vtex.y * tmp.y - 0.25f
* o_vbottom.w = 1 / tmp.y
*/
ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_X),
ureg_scalar(vtex, TGSI_SWIZZLE_W), ureg_imm1f(shader, 0.5f));
ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y),
ureg_scalar(vtex, TGSI_SWIZZLE_W), ureg_imm1f(shader, 0.25f));
 
ureg_MOV(shader, ureg_writemask(o_vtop, TGSI_WRITEMASK_X), vtex);
ureg_MAD(shader, ureg_writemask(o_vtop, TGSI_WRITEMASK_Y), ureg_scalar(vtex, TGSI_SWIZZLE_Y),
ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_imm1f(shader, 0.25f));
ureg_MAD(shader, ureg_writemask(o_vtop, TGSI_WRITEMASK_Z), ureg_scalar(vtex, TGSI_SWIZZLE_Y),
ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y), ureg_imm1f(shader, 0.25f));
ureg_RCP(shader, ureg_writemask(o_vtop, TGSI_WRITEMASK_W),
ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X));
 
ureg_MOV(shader, ureg_writemask(o_vbottom, TGSI_WRITEMASK_X), vtex);
ureg_MAD(shader, ureg_writemask(o_vbottom, TGSI_WRITEMASK_Y), ureg_scalar(vtex, TGSI_SWIZZLE_Y),
ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_imm1f(shader, -0.25f));
ureg_MAD(shader, ureg_writemask(o_vbottom, TGSI_WRITEMASK_Z), ureg_scalar(vtex, TGSI_SWIZZLE_Y),
ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y), ureg_imm1f(shader, -0.25f));
ureg_RCP(shader, ureg_writemask(o_vbottom, TGSI_WRITEMASK_W),
ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y));
 
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, c->pipe);
}
 
static void *
create_frag_shader_video_buffer(struct vl_compositor *c)
{
struct ureg_program *shader;
struct ureg_src tc;
struct ureg_src csc[3];
struct ureg_src sampler[3];
struct ureg_dst texel;
struct ureg_dst fragment;
unsigned i;
 
shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
if (!shader)
return false;
 
tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX, TGSI_INTERPOLATE_LINEAR);
for (i = 0; i < 3; ++i) {
csc[i] = ureg_DECL_constant(shader, i);
sampler[i] = ureg_DECL_sampler(shader, i);
}
texel = ureg_DECL_temporary(shader);
fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
 
/*
* texel.xyz = tex(tc, sampler[i])
* fragment = csc * texel
*/
for (i = 0; i < 3; ++i)
ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_X << i), TGSI_TEXTURE_2D_ARRAY, tc, sampler[i]);
 
ureg_MOV(shader, ureg_writemask(texel, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
 
for (i = 0; i < 3; ++i)
ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel));
 
ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
 
ureg_release_temporary(shader, texel);
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, c->pipe);
}
 
static void *
create_frag_shader_weave(struct vl_compositor *c)
{
struct ureg_program *shader;
struct ureg_src i_tc[2];
struct ureg_src csc[3];
struct ureg_src sampler[3];
struct ureg_dst t_tc[2];
struct ureg_dst t_texel[2];
struct ureg_dst o_fragment;
unsigned i, j;
 
shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
if (!shader)
return false;
 
i_tc[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTOP, TGSI_INTERPOLATE_LINEAR);
i_tc[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VBOTTOM, TGSI_INTERPOLATE_LINEAR);
 
for (i = 0; i < 3; ++i) {
csc[i] = ureg_DECL_constant(shader, i);
sampler[i] = ureg_DECL_sampler(shader, i);
}
 
for (i = 0; i < 2; ++i) {
t_tc[i] = ureg_DECL_temporary(shader);
t_texel[i] = ureg_DECL_temporary(shader);
}
o_fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
 
/* calculate the texture offsets
* t_tc.x = i_tc.x
* t_tc.y = (round(i_tc.y - 0.5) + 0.5) / height * 2
*/
for (i = 0; i < 2; ++i) {
ureg_MOV(shader, ureg_writemask(t_tc[i], TGSI_WRITEMASK_X), i_tc[i]);
ureg_SUB(shader, ureg_writemask(t_tc[i], TGSI_WRITEMASK_YZ),
i_tc[i], ureg_imm1f(shader, 0.5f));
ureg_ROUND(shader, ureg_writemask(t_tc[i], TGSI_WRITEMASK_YZ), ureg_src(t_tc[i]));
ureg_MOV(shader, ureg_writemask(t_tc[i], TGSI_WRITEMASK_W),
ureg_imm1f(shader, i ? 1.0f : 0.0f));
ureg_ADD(shader, ureg_writemask(t_tc[i], TGSI_WRITEMASK_YZ),
ureg_src(t_tc[i]), ureg_imm1f(shader, 0.5f));
ureg_MUL(shader, ureg_writemask(t_tc[i], TGSI_WRITEMASK_Y),
ureg_src(t_tc[i]), ureg_scalar(i_tc[0], TGSI_SWIZZLE_W));
ureg_MUL(shader, ureg_writemask(t_tc[i], TGSI_WRITEMASK_Z),
ureg_src(t_tc[i]), ureg_scalar(i_tc[1], TGSI_SWIZZLE_W));
}
 
/* fetch the texels
* texel[0..1].x = tex(t_tc[0..1][0])
* texel[0..1].y = tex(t_tc[0..1][1])
* texel[0..1].z = tex(t_tc[0..1][2])
*/
for (i = 0; i < 2; ++i)
for (j = 0; j < 3; ++j) {
struct ureg_src src = ureg_swizzle(ureg_src(t_tc[i]),
TGSI_SWIZZLE_X, j ? TGSI_SWIZZLE_Z : TGSI_SWIZZLE_Y, TGSI_SWIZZLE_W, TGSI_SWIZZLE_W);
 
ureg_TEX(shader, ureg_writemask(t_texel[i], TGSI_WRITEMASK_X << j),
TGSI_TEXTURE_2D_ARRAY, src, sampler[j]);
}
 
/* calculate linear interpolation factor
* factor = |round(i_tc.y) - i_tc.y| * 2
*/
ureg_ROUND(shader, ureg_writemask(t_tc[0], TGSI_WRITEMASK_YZ), i_tc[0]);
ureg_ADD(shader, ureg_writemask(t_tc[0], TGSI_WRITEMASK_YZ),
ureg_src(t_tc[0]), ureg_negate(i_tc[0]));
ureg_MUL(shader, ureg_writemask(t_tc[0], TGSI_WRITEMASK_YZ),
ureg_abs(ureg_src(t_tc[0])), ureg_imm1f(shader, 2.0f));
ureg_LRP(shader, t_texel[0], ureg_swizzle(ureg_src(t_tc[0]),
TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z),
ureg_src(t_texel[0]), ureg_src(t_texel[1]));
 
/* and finally do colour space transformation
* fragment = csc * texel
*/
ureg_MOV(shader, ureg_writemask(t_texel[0], TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
for (i = 0; i < 3; ++i)
ureg_DP4(shader, ureg_writemask(o_fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(t_texel[0]));
 
ureg_MOV(shader, ureg_writemask(o_fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
 
for (i = 0; i < 2; ++i) {
ureg_release_temporary(shader, t_texel[i]);
ureg_release_temporary(shader, t_tc[i]);
}
 
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, c->pipe);
}
 
static void *
create_frag_shader_palette(struct vl_compositor *c, bool include_cc)
{
struct ureg_program *shader;
struct ureg_src csc[3];
struct ureg_src tc;
struct ureg_src sampler;
struct ureg_src palette;
struct ureg_dst texel;
struct ureg_dst fragment;
unsigned i;
 
shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
if (!shader)
return false;
 
for (i = 0; include_cc && i < 3; ++i)
csc[i] = ureg_DECL_constant(shader, i);
 
tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX, TGSI_INTERPOLATE_LINEAR);
sampler = ureg_DECL_sampler(shader, 0);
palette = ureg_DECL_sampler(shader, 1);
 
texel = ureg_DECL_temporary(shader);
fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
 
/*
* texel = tex(tc, sampler)
* fragment.xyz = tex(texel, palette) * csc
* fragment.a = texel.a
*/
ureg_TEX(shader, texel, TGSI_TEXTURE_2D, tc, sampler);
ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_src(texel));
 
if (include_cc) {
ureg_TEX(shader, texel, TGSI_TEXTURE_1D, ureg_src(texel), palette);
for (i = 0; i < 3; ++i)
ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel));
} else {
ureg_TEX(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ),
TGSI_TEXTURE_1D, ureg_src(texel), palette);
}
 
ureg_release_temporary(shader, texel);
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, c->pipe);
}
 
static void *
create_frag_shader_rgba(struct vl_compositor *c)
{
struct ureg_program *shader;
struct ureg_src tc, color, sampler;
struct ureg_dst texel, fragment;
 
shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
if (!shader)
return false;
 
tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX, TGSI_INTERPOLATE_LINEAR);
color = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_COLOR, VS_O_COLOR, TGSI_INTERPOLATE_LINEAR);
sampler = ureg_DECL_sampler(shader, 0);
texel = ureg_DECL_temporary(shader);
fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
 
/*
* fragment = tex(tc, sampler)
*/
ureg_TEX(shader, texel, TGSI_TEXTURE_2D, tc, sampler);
ureg_MUL(shader, fragment, ureg_src(texel), color);
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, c->pipe);
}
 
static bool
init_shaders(struct vl_compositor *c)
{
assert(c);
 
c->vs = create_vert_shader(c);
if (!c->vs) {
debug_printf("Unable to create vertex shader.\n");
return false;
}
 
c->fs_video_buffer = create_frag_shader_video_buffer(c);
if (!c->fs_video_buffer) {
debug_printf("Unable to create YCbCr-to-RGB fragment shader.\n");
return false;
}
 
c->fs_weave = create_frag_shader_weave(c);
if (!c->fs_weave) {
debug_printf("Unable to create YCbCr-to-RGB weave fragment shader.\n");
return false;
}
 
c->fs_palette.yuv = create_frag_shader_palette(c, true);
if (!c->fs_palette.yuv) {
debug_printf("Unable to create YUV-Palette-to-RGB fragment shader.\n");
return false;
}
 
c->fs_palette.rgb = create_frag_shader_palette(c, false);
if (!c->fs_palette.rgb) {
debug_printf("Unable to create RGB-Palette-to-RGB fragment shader.\n");
return false;
}
 
c->fs_rgba = create_frag_shader_rgba(c);
if (!c->fs_rgba) {
debug_printf("Unable to create RGB-to-RGB fragment shader.\n");
return false;
}
 
return true;
}
 
static void cleanup_shaders(struct vl_compositor *c)
{
assert(c);
 
c->pipe->delete_vs_state(c->pipe, c->vs);
c->pipe->delete_fs_state(c->pipe, c->fs_video_buffer);
c->pipe->delete_fs_state(c->pipe, c->fs_weave);
c->pipe->delete_fs_state(c->pipe, c->fs_palette.yuv);
c->pipe->delete_fs_state(c->pipe, c->fs_palette.rgb);
c->pipe->delete_fs_state(c->pipe, c->fs_rgba);
}
 
static bool
init_pipe_state(struct vl_compositor *c)
{
struct pipe_rasterizer_state rast;
struct pipe_sampler_state sampler;
struct pipe_blend_state blend;
struct pipe_depth_stencil_alpha_state dsa;
unsigned i;
 
assert(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_REPEAT;
sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
sampler.compare_func = PIPE_FUNC_ALWAYS;
sampler.normalized_coords = 1;
 
c->sampler_linear = c->pipe->create_sampler_state(c->pipe, &sampler);
 
sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
c->sampler_nearest = c->pipe->create_sampler_state(c->pipe, &sampler);
 
memset(&blend, 0, sizeof blend);
blend.independent_blend_enable = 0;
blend.rt[0].blend_enable = 0;
blend.logicop_enable = 0;
blend.logicop_func = PIPE_LOGICOP_CLEAR;
blend.rt[0].colormask = PIPE_MASK_RGBA;
blend.dither = 0;
c->blend_clear = c->pipe->create_blend_state(c->pipe, &blend);
 
blend.rt[0].blend_enable = 1;
blend.rt[0].rgb_func = PIPE_BLEND_ADD;
blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
blend.rt[0].alpha_func = PIPE_BLEND_ADD;
blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
c->blend_add = c->pipe->create_blend_state(c->pipe, &blend);
 
memset(&rast, 0, sizeof rast);
rast.flatshade = 0;
rast.front_ccw = 1;
rast.cull_face = PIPE_FACE_NONE;
rast.fill_back = PIPE_POLYGON_MODE_FILL;
rast.fill_front = PIPE_POLYGON_MODE_FILL;
rast.scissor = 1;
rast.line_width = 1;
rast.point_size_per_vertex = 1;
rast.offset_units = 1;
rast.offset_scale = 1;
rast.half_pixel_center = 1;
rast.bottom_edge_rule = 1;
rast.depth_clip = 1;
 
c->rast = c->pipe->create_rasterizer_state(c->pipe, &rast);
 
memset(&dsa, 0, sizeof dsa);
dsa.depth.enabled = 0;
dsa.depth.writemask = 0;
dsa.depth.func = PIPE_FUNC_ALWAYS;
for (i = 0; i < 2; ++i) {
dsa.stencil[i].enabled = 0;
dsa.stencil[i].func = PIPE_FUNC_ALWAYS;
dsa.stencil[i].fail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[i].zpass_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[i].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[i].valuemask = 0;
dsa.stencil[i].writemask = 0;
}
dsa.alpha.enabled = 0;
dsa.alpha.func = PIPE_FUNC_ALWAYS;
dsa.alpha.ref_value = 0;
c->dsa = c->pipe->create_depth_stencil_alpha_state(c->pipe, &dsa);
c->pipe->bind_depth_stencil_alpha_state(c->pipe, c->dsa);
 
return true;
}
 
static void cleanup_pipe_state(struct vl_compositor *c)
{
assert(c);
 
/* Asserted in softpipe_delete_fs_state() for some reason */
c->pipe->bind_vs_state(c->pipe, NULL);
c->pipe->bind_fs_state(c->pipe, NULL);
 
c->pipe->delete_depth_stencil_alpha_state(c->pipe, c->dsa);
c->pipe->delete_sampler_state(c->pipe, c->sampler_linear);
c->pipe->delete_sampler_state(c->pipe, c->sampler_nearest);
c->pipe->delete_blend_state(c->pipe, c->blend_clear);
c->pipe->delete_blend_state(c->pipe, c->blend_add);
c->pipe->delete_rasterizer_state(c->pipe, c->rast);
}
 
static bool
create_vertex_buffer(struct vl_compositor *c)
{
assert(c);
 
pipe_resource_reference(&c->vertex_buf.buffer, NULL);
c->vertex_buf.buffer = pipe_buffer_create
(
c->pipe->screen,
PIPE_BIND_VERTEX_BUFFER,
PIPE_USAGE_STREAM,
c->vertex_buf.stride * VL_COMPOSITOR_MAX_LAYERS * 4
);
 
return c->vertex_buf.buffer != NULL;
}
 
static bool
init_buffers(struct vl_compositor *c)
{
struct pipe_vertex_element vertex_elems[3];
 
assert(c);
 
/*
* Create our vertex buffer and vertex buffer elements
*/
c->vertex_buf.stride = sizeof(struct vertex2f) + sizeof(struct vertex4f) * 2;
c->vertex_buf.buffer_offset = 0;
create_vertex_buffer(c);
 
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_R32G32B32A32_FLOAT;
vertex_elems[2].src_offset = sizeof(struct vertex2f) + sizeof(struct vertex4f);
vertex_elems[2].instance_divisor = 0;
vertex_elems[2].vertex_buffer_index = 0;
vertex_elems[2].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
c->vertex_elems_state = c->pipe->create_vertex_elements_state(c->pipe, 3, vertex_elems);
 
return true;
}
 
static void
cleanup_buffers(struct vl_compositor *c)
{
assert(c);
 
c->pipe->delete_vertex_elements_state(c->pipe, c->vertex_elems_state);
pipe_resource_reference(&c->vertex_buf.buffer, NULL);
}
 
static INLINE struct u_rect
default_rect(struct vl_compositor_layer *layer)
{
struct pipe_resource *res = layer->sampler_views[0]->texture;
struct u_rect rect = { 0, res->width0, 0, res->height0 * res->array_size };
return rect;
}
 
static INLINE struct vertex2f
calc_topleft(struct vertex2f size, struct u_rect rect)
{
struct vertex2f res = { rect.x0 / size.x, rect.y0 / size.y };
return res;
}
 
static INLINE struct vertex2f
calc_bottomright(struct vertex2f size, struct u_rect rect)
{
struct vertex2f res = { rect.x1 / size.x, rect.y1 / size.y };
return res;
}
 
static INLINE void
calc_src_and_dst(struct vl_compositor_layer *layer, unsigned width, unsigned height,
struct u_rect src, struct u_rect dst)
{
struct vertex2f size = { width, height };
 
layer->src.tl = calc_topleft(size, src);
layer->src.br = calc_bottomright(size, src);
layer->dst.tl = calc_topleft(size, dst);
layer->dst.br = calc_bottomright(size, dst);
layer->zw.x = 0.0f;
layer->zw.y = size.y;
}
 
static void
gen_rect_verts(struct vertex2f *vb, struct vl_compositor_layer *layer)
{
assert(vb && layer);
 
vb[ 0].x = layer->dst.tl.x;
vb[ 0].y = layer->dst.tl.y;
vb[ 1].x = layer->src.tl.x;
vb[ 1].y = layer->src.tl.y;
vb[ 2] = layer->zw;
vb[ 3].x = layer->colors[0].x;
vb[ 3].y = layer->colors[0].y;
vb[ 4].x = layer->colors[0].z;
vb[ 4].y = layer->colors[0].w;
 
vb[ 5].x = layer->dst.br.x;
vb[ 5].y = layer->dst.tl.y;
vb[ 6].x = layer->src.br.x;
vb[ 6].y = layer->src.tl.y;
vb[ 7] = layer->zw;
vb[ 8].x = layer->colors[1].x;
vb[ 8].y = layer->colors[1].y;
vb[ 9].x = layer->colors[1].z;
vb[ 9].y = layer->colors[1].w;
 
vb[10].x = layer->dst.br.x;
vb[10].y = layer->dst.br.y;
vb[11].x = layer->src.br.x;
vb[11].y = layer->src.br.y;
vb[12] = layer->zw;
vb[13].x = layer->colors[2].x;
vb[13].y = layer->colors[2].y;
vb[14].x = layer->colors[2].z;
vb[14].y = layer->colors[2].w;
 
vb[15].x = layer->dst.tl.x;
vb[15].y = layer->dst.br.y;
vb[16].x = layer->src.tl.x;
vb[16].y = layer->src.br.y;
vb[17] = layer->zw;
vb[18].x = layer->colors[3].x;
vb[18].y = layer->colors[3].y;
vb[19].x = layer->colors[3].z;
vb[19].y = layer->colors[3].w;
}
 
static INLINE struct u_rect
calc_drawn_area(struct vl_compositor_state *s, struct vl_compositor_layer *layer)
{
struct u_rect result;
 
// scale
result.x0 = layer->dst.tl.x * layer->viewport.scale[0] + layer->viewport.translate[0];
result.y0 = layer->dst.tl.y * layer->viewport.scale[1] + layer->viewport.translate[1];
result.x1 = layer->dst.br.x * layer->viewport.scale[0] + layer->viewport.translate[0];
result.y1 = layer->dst.br.y * layer->viewport.scale[1] + layer->viewport.translate[1];
 
// and clip
result.x0 = MAX2(result.x0, s->scissor.minx);
result.y0 = MAX2(result.y0, s->scissor.miny);
result.x1 = MIN2(result.x1, s->scissor.maxx);
result.y1 = MIN2(result.y1, s->scissor.maxy);
return result;
}
 
static void
gen_vertex_data(struct vl_compositor *c, struct vl_compositor_state *s, struct u_rect *dirty)
{
struct vertex2f *vb;
struct pipe_transfer *buf_transfer;
unsigned i;
 
assert(c);
 
vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE | PIPE_TRANSFER_DONTBLOCK,
&buf_transfer);
 
if (!vb) {
// If buffer is still locked from last draw create a new one
create_vertex_buffer(c);
vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE,
&buf_transfer);
}
 
for (i = 0; i < VL_COMPOSITOR_MAX_LAYERS; i++) {
if (s->used_layers & (1 << i)) {
struct vl_compositor_layer *layer = &s->layers[i];
gen_rect_verts(vb, layer);
vb += 20;
 
if (!layer->viewport_valid) {
layer->viewport.scale[0] = c->fb_state.width;
layer->viewport.scale[1] = c->fb_state.height;
layer->viewport.translate[0] = 0;
layer->viewport.translate[1] = 0;
}
 
if (dirty && layer->clearing) {
struct u_rect drawn = calc_drawn_area(s, layer);
if (
dirty->x0 >= drawn.x0 &&
dirty->y0 >= drawn.y0 &&
dirty->x1 <= drawn.x1 &&
dirty->y1 <= drawn.y1) {
 
// We clear the dirty area anyway, no need for clear_render_target
dirty->x0 = dirty->y0 = MAX_DIRTY;
dirty->x1 = dirty->y1 = MIN_DIRTY;
}
}
}
}
 
pipe_buffer_unmap(c->pipe, buf_transfer);
}
 
static void
draw_layers(struct vl_compositor *c, struct vl_compositor_state *s, struct u_rect *dirty)
{
unsigned vb_index, i;
 
assert(c);
 
for (i = 0, vb_index = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i) {
if (s->used_layers & (1 << i)) {
struct vl_compositor_layer *layer = &s->layers[i];
struct pipe_sampler_view **samplers = &layer->sampler_views[0];
unsigned num_sampler_views = !samplers[1] ? 1 : !samplers[2] ? 2 : 3;
void *blend = layer->blend ? layer->blend : i ? c->blend_add : c->blend_clear;
 
c->pipe->bind_blend_state(c->pipe, blend);
c->pipe->set_viewport_states(c->pipe, 0, 1, &layer->viewport);
c->pipe->bind_fs_state(c->pipe, layer->fs);
c->pipe->bind_fragment_sampler_states(c->pipe, num_sampler_views, layer->samplers);
c->pipe->set_fragment_sampler_views(c->pipe, num_sampler_views, samplers);
util_draw_arrays(c->pipe, PIPE_PRIM_QUADS, vb_index * 4, 4);
vb_index++;
 
if (dirty) {
// Remember the currently drawn area as dirty for the next draw command
struct u_rect drawn = calc_drawn_area(s, layer);
dirty->x0 = MIN2(drawn.x0, dirty->x0);
dirty->y0 = MIN2(drawn.y0, dirty->y0);
dirty->x1 = MAX2(drawn.x1, dirty->x1);
dirty->y1 = MAX2(drawn.y1, dirty->y1);
}
}
}
}
 
void
vl_compositor_reset_dirty_area(struct u_rect *dirty)
{
assert(dirty);
 
dirty->x0 = dirty->y0 = MIN_DIRTY;
dirty->x1 = dirty->y1 = MAX_DIRTY;
}
 
void
vl_compositor_set_clear_color(struct vl_compositor_state *s, union pipe_color_union *color)
{
assert(s);
assert(color);
 
s->clear_color = *color;
}
 
void
vl_compositor_get_clear_color(struct vl_compositor_state *s, union pipe_color_union *color)
{
assert(s);
assert(color);
 
*color = s->clear_color;
}
 
void
vl_compositor_clear_layers(struct vl_compositor_state *s)
{
unsigned i, j;
 
assert(s);
 
s->used_layers = 0;
for ( i = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i) {
struct vertex4f v_one = { 1.0f, 1.0f, 1.0f, 1.0f };
s->layers[i].clearing = i ? false : true;
s->layers[i].blend = NULL;
s->layers[i].fs = NULL;
s->layers[i].viewport.scale[2] = 1;
s->layers[i].viewport.scale[3] = 1;
s->layers[i].viewport.translate[2] = 0;
s->layers[i].viewport.translate[3] = 0;
 
for ( j = 0; j < 3; j++)
pipe_sampler_view_reference(&s->layers[i].sampler_views[j], NULL);
for ( j = 0; j < 4; ++j)
s->layers[i].colors[j] = v_one;
}
}
 
void
vl_compositor_cleanup(struct vl_compositor *c)
{
assert(c);
 
cleanup_buffers(c);
cleanup_shaders(c);
cleanup_pipe_state(c);
}
 
void
vl_compositor_set_csc_matrix(struct vl_compositor_state *s, vl_csc_matrix const *matrix)
{
struct pipe_transfer *buf_transfer;
 
assert(s);
 
memcpy
(
pipe_buffer_map(s->pipe, s->csc_matrix,
PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE,
&buf_transfer),
matrix,
sizeof(vl_csc_matrix)
);
 
pipe_buffer_unmap(s->pipe, buf_transfer);
}
 
void
vl_compositor_set_dst_clip(struct vl_compositor_state *s, struct u_rect *dst_clip)
{
assert(s);
 
s->scissor_valid = dst_clip != NULL;
if (dst_clip) {
s->scissor.minx = dst_clip->x0;
s->scissor.miny = dst_clip->y0;
s->scissor.maxx = dst_clip->x1;
s->scissor.maxy = dst_clip->y1;
}
}
 
void
vl_compositor_set_layer_blend(struct vl_compositor_state *s,
unsigned layer, void *blend,
bool is_clearing)
{
assert(s && blend);
 
assert(layer < VL_COMPOSITOR_MAX_LAYERS);
 
s->layers[layer].clearing = is_clearing;
s->layers[layer].blend = blend;
}
 
void
vl_compositor_set_layer_dst_area(struct vl_compositor_state *s,
unsigned layer, struct u_rect *dst_area)
{
assert(s);
 
assert(layer < VL_COMPOSITOR_MAX_LAYERS);
 
s->layers[layer].viewport_valid = dst_area != NULL;
if (dst_area) {
s->layers[layer].viewport.scale[0] = dst_area->x1 - dst_area->x0;
s->layers[layer].viewport.scale[1] = dst_area->y1 - dst_area->y0;
s->layers[layer].viewport.translate[0] = dst_area->x0;
s->layers[layer].viewport.translate[1] = dst_area->y0;
}
}
 
void
vl_compositor_set_buffer_layer(struct vl_compositor_state *s,
struct vl_compositor *c,
unsigned layer,
struct pipe_video_buffer *buffer,
struct u_rect *src_rect,
struct u_rect *dst_rect,
enum vl_compositor_deinterlace deinterlace)
{
struct pipe_sampler_view **sampler_views;
unsigned i;
 
assert(s && c && buffer);
 
assert(layer < VL_COMPOSITOR_MAX_LAYERS);
 
s->used_layers |= 1 << layer;
sampler_views = buffer->get_sampler_view_components(buffer);
for (i = 0; i < 3; ++i) {
s->layers[layer].samplers[i] = c->sampler_linear;
pipe_sampler_view_reference(&s->layers[layer].sampler_views[i], sampler_views[i]);
}
 
calc_src_and_dst(&s->layers[layer], buffer->width, buffer->height,
src_rect ? *src_rect : default_rect(&s->layers[layer]),
dst_rect ? *dst_rect : default_rect(&s->layers[layer]));
 
if (buffer->interlaced) {
float half_a_line = 0.5f / s->layers[layer].zw.y;
switch(deinterlace) {
case VL_COMPOSITOR_WEAVE:
s->layers[layer].fs = c->fs_weave;
break;
 
case VL_COMPOSITOR_BOB_TOP:
s->layers[layer].zw.x = 0.0f;
s->layers[layer].src.tl.y += half_a_line;
s->layers[layer].src.br.y += half_a_line;
s->layers[layer].fs = c->fs_video_buffer;
break;
 
case VL_COMPOSITOR_BOB_BOTTOM:
s->layers[layer].zw.x = 1.0f;
s->layers[layer].src.tl.y -= half_a_line;
s->layers[layer].src.br.y -= half_a_line;
s->layers[layer].fs = c->fs_video_buffer;
break;
}
 
} else
s->layers[layer].fs = c->fs_video_buffer;
}
 
void
vl_compositor_set_palette_layer(struct vl_compositor_state *s,
struct vl_compositor *c,
unsigned layer,
struct pipe_sampler_view *indexes,
struct pipe_sampler_view *palette,
struct u_rect *src_rect,
struct u_rect *dst_rect,
bool include_color_conversion)
{
assert(s && c && indexes && palette);
 
assert(layer < VL_COMPOSITOR_MAX_LAYERS);
 
s->used_layers |= 1 << layer;
 
s->layers[layer].fs = include_color_conversion ?
c->fs_palette.yuv : c->fs_palette.rgb;
 
s->layers[layer].samplers[0] = c->sampler_linear;
s->layers[layer].samplers[1] = c->sampler_nearest;
s->layers[layer].samplers[2] = NULL;
pipe_sampler_view_reference(&s->layers[layer].sampler_views[0], indexes);
pipe_sampler_view_reference(&s->layers[layer].sampler_views[1], palette);
pipe_sampler_view_reference(&s->layers[layer].sampler_views[2], NULL);
calc_src_and_dst(&s->layers[layer], indexes->texture->width0, indexes->texture->height0,
src_rect ? *src_rect : default_rect(&s->layers[layer]),
dst_rect ? *dst_rect : default_rect(&s->layers[layer]));
}
 
void
vl_compositor_set_rgba_layer(struct vl_compositor_state *s,
struct vl_compositor *c,
unsigned layer,
struct pipe_sampler_view *rgba,
struct u_rect *src_rect,
struct u_rect *dst_rect,
struct vertex4f *colors)
{
unsigned i;
 
assert(s && c && rgba);
 
assert(layer < VL_COMPOSITOR_MAX_LAYERS);
 
s->used_layers |= 1 << layer;
s->layers[layer].fs = c->fs_rgba;
s->layers[layer].samplers[0] = c->sampler_linear;
s->layers[layer].samplers[1] = NULL;
s->layers[layer].samplers[2] = NULL;
pipe_sampler_view_reference(&s->layers[layer].sampler_views[0], rgba);
pipe_sampler_view_reference(&s->layers[layer].sampler_views[1], NULL);
pipe_sampler_view_reference(&s->layers[layer].sampler_views[2], NULL);
calc_src_and_dst(&s->layers[layer], rgba->texture->width0, rgba->texture->height0,
src_rect ? *src_rect : default_rect(&s->layers[layer]),
dst_rect ? *dst_rect : default_rect(&s->layers[layer]));
 
if (colors)
for (i = 0; i < 4; ++i)
s->layers[layer].colors[i] = colors[i];
}
 
void
vl_compositor_render(struct vl_compositor_state *s,
struct vl_compositor *c,
struct pipe_surface *dst_surface,
struct u_rect *dirty_area,
bool clear_dirty)
{
assert(c);
assert(dst_surface);
 
c->fb_state.width = dst_surface->width;
c->fb_state.height = dst_surface->height;
c->fb_state.cbufs[0] = dst_surface;
if (!s->scissor_valid) {
s->scissor.minx = 0;
s->scissor.miny = 0;
s->scissor.maxx = dst_surface->width;
s->scissor.maxy = dst_surface->height;
}
 
gen_vertex_data(c, s, dirty_area);
 
if (clear_dirty && dirty_area &&
(dirty_area->x0 < dirty_area->x1 || dirty_area->y0 < dirty_area->y1)) {
 
c->pipe->clear_render_target(c->pipe, dst_surface, &s->clear_color,
0, 0, dst_surface->width, dst_surface->height);
dirty_area->x0 = dirty_area->y0 = MAX_DIRTY;
dirty_area->x1 = dirty_area->y1 = MIN_DIRTY;
}
 
c->pipe->set_scissor_states(c->pipe, 0, 1, &s->scissor);
c->pipe->set_framebuffer_state(c->pipe, &c->fb_state);
c->pipe->bind_vs_state(c->pipe, c->vs);
c->pipe->set_vertex_buffers(c->pipe, 0, 1, &c->vertex_buf);
c->pipe->bind_vertex_elements_state(c->pipe, c->vertex_elems_state);
pipe_set_constant_buffer(c->pipe, PIPE_SHADER_FRAGMENT, 0, s->csc_matrix);
c->pipe->bind_rasterizer_state(c->pipe, c->rast);
 
draw_layers(c, s, dirty_area);
}
 
bool
vl_compositor_init(struct vl_compositor *c, struct pipe_context *pipe)
{
assert(c);
 
memset(c, 0, sizeof(*c));
 
c->pipe = pipe;
 
if (!init_pipe_state(c))
return false;
 
if (!init_shaders(c)) {
cleanup_pipe_state(c);
return false;
}
 
if (!init_buffers(c)) {
cleanup_shaders(c);
cleanup_pipe_state(c);
return false;
}
 
return true;
}
 
bool
vl_compositor_init_state(struct vl_compositor_state *s, struct pipe_context *pipe)
{
vl_csc_matrix csc_matrix;
 
assert(s);
 
memset(s, 0, sizeof(*s));
 
s->pipe = pipe;
 
s->clear_color.f[0] = s->clear_color.f[1] = 0.0f;
s->clear_color.f[2] = s->clear_color.f[3] = 0.0f;
 
/*
* Create our fragment shader's constant buffer
* Const buffer contains the color conversion matrix and bias vectors
*/
/* XXX: Create with IMMUTABLE/STATIC... although it does change every once in a long while... */
s->csc_matrix = pipe_buffer_create
(
pipe->screen,
PIPE_BIND_CONSTANT_BUFFER,
PIPE_USAGE_STATIC,
sizeof(csc_matrix)
);
 
vl_compositor_clear_layers(s);
 
vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_IDENTITY, NULL, true, &csc_matrix);
vl_compositor_set_csc_matrix(s, (const vl_csc_matrix *)&csc_matrix);
 
return true;
}
 
void
vl_compositor_cleanup_state(struct vl_compositor_state *s)
{
assert(s);
 
vl_compositor_clear_layers(s);
pipe_resource_reference(&s->csc_matrix, NULL);
}
/drivers/video/Gallium/auxiliary/vl/vl_compositor.h
0,0 → 1,242
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* 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.
*
**************************************************************************/
 
#ifndef vl_compositor_h
#define vl_compositor_h
 
#include "pipe/p_state.h"
#include "pipe/p_video_decoder.h"
#include "pipe/p_video_state.h"
 
#include "util/u_rect.h"
 
#include "vl_types.h"
#include "vl_csc.h"
 
struct pipe_context;
 
/**
* composing and displaying of image data
*/
 
#define VL_COMPOSITOR_MAX_LAYERS 16
 
/* deinterlace allgorithem */
enum vl_compositor_deinterlace
{
VL_COMPOSITOR_WEAVE,
VL_COMPOSITOR_BOB_TOP,
VL_COMPOSITOR_BOB_BOTTOM
};
 
struct vl_compositor_layer
{
bool clearing;
 
bool viewport_valid;
struct pipe_viewport_state viewport;
 
void *fs;
void *samplers[3];
void *blend;
 
struct pipe_sampler_view *sampler_views[3];
struct {
struct vertex2f tl, br;
} src, dst;
struct vertex2f zw;
struct vertex4f colors[4];
};
 
struct vl_compositor_state
{
struct pipe_context *pipe;
 
bool scissor_valid;
struct pipe_scissor_state scissor;
struct pipe_resource *csc_matrix;
 
union pipe_color_union clear_color;
 
unsigned used_layers:VL_COMPOSITOR_MAX_LAYERS;
struct vl_compositor_layer layers[VL_COMPOSITOR_MAX_LAYERS];
};
 
struct vl_compositor
{
struct pipe_context *pipe;
 
struct pipe_framebuffer_state fb_state;
struct pipe_vertex_buffer vertex_buf;
 
void *sampler_linear;
void *sampler_nearest;
void *blend_clear, *blend_add;
void *rast;
void *dsa;
void *vertex_elems_state;
 
void *vs;
void *fs_video_buffer;
void *fs_weave;
void *fs_rgba;
 
struct {
void *rgb;
void *yuv;
} fs_palette;
};
 
/**
* initialize this compositor
*/
bool
vl_compositor_init(struct vl_compositor *compositor, struct pipe_context *pipe);
 
/**
* init state bag
*/
bool
vl_compositor_init_state(struct vl_compositor_state *state, struct pipe_context *pipe);
 
/**
* set yuv -> rgba conversion matrix
*/
void
vl_compositor_set_csc_matrix(struct vl_compositor_state *settings, const vl_csc_matrix *matrix);
 
/**
* reset dirty area, so it's cleared with the clear colour
*/
void
vl_compositor_reset_dirty_area(struct u_rect *dirty);
 
/**
* set the clear color
*/
void
vl_compositor_set_clear_color(struct vl_compositor_state *settings, union pipe_color_union *color);
 
/**
* get the clear color
*/
void
vl_compositor_get_clear_color(struct vl_compositor_state *settings, union pipe_color_union *color);
 
/**
* set the destination clipping
*/
void
vl_compositor_set_dst_clip(struct vl_compositor_state *settings, struct u_rect *dst_clip);
 
/**
* set overlay samplers
*/
/*@{*/
 
/**
* reset all currently set layers
*/
void
vl_compositor_clear_layers(struct vl_compositor_state *state);
 
/**
* set the blender used to render a layer
*/
void
vl_compositor_set_layer_blend(struct vl_compositor_state *state,
unsigned layer, void *blend, bool is_clearing);
 
/**
* set the layer destination area
*/
void
vl_compositor_set_layer_dst_area(struct vl_compositor_state *settings,
unsigned layer, struct u_rect *dst_area);
 
/**
* set a video buffer as a layer to render
*/
void
vl_compositor_set_buffer_layer(struct vl_compositor_state *state,
struct vl_compositor *compositor,
unsigned layer,
struct pipe_video_buffer *buffer,
struct u_rect *src_rect,
struct u_rect *dst_rect,
enum vl_compositor_deinterlace deinterlace);
 
/**
* set a paletted sampler as a layer to render
*/
void
vl_compositor_set_palette_layer(struct vl_compositor_state *state,
struct vl_compositor *compositor,
unsigned layer,
struct pipe_sampler_view *indexes,
struct pipe_sampler_view *palette,
struct u_rect *src_rect,
struct u_rect *dst_rect,
bool include_color_conversion);
 
/**
* set a rgba sampler as a layer to render
*/
void
vl_compositor_set_rgba_layer(struct vl_compositor_state *state,
struct vl_compositor *compositor,
unsigned layer,
struct pipe_sampler_view *rgba,
struct u_rect *src_rect,
struct u_rect *dst_rect,
struct vertex4f *colors);
 
/*@}*/
 
/**
* render the layers to the frontbuffer
*/
void
vl_compositor_render(struct vl_compositor_state *state,
struct vl_compositor *compositor,
struct pipe_surface *dst_surface,
struct u_rect *dirty_area,
bool clear_dirty);
 
/**
* destroy this compositor
*/
void
vl_compositor_cleanup(struct vl_compositor *compositor);
 
/**
* destroy this state bag
*/
void
vl_compositor_cleanup_state(struct vl_compositor_state *state);
 
#endif /* vl_compositor_h */
/drivers/video/Gallium/auxiliary/vl/vl_csc.c
0,0 → 1,230
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* 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.
*
**************************************************************************/
 
#include "util/u_math.h"
#include "util/u_debug.h"
 
#include "vl_csc.h"
 
/*
* Color space conversion formulas
*
* To convert YCbCr to RGB,
* vec4 ycbcr, rgb
* mat44 csc
* rgb = csc * ycbcr
*
* To calculate the color space conversion matrix csc with ProcAmp adjustments,
* mat44 csc, cstd, procamp, bias
* csc = cstd * (procamp * bias)
*
* Where cstd is a matrix corresponding to one of the color standards (BT.601, BT.709, etc)
* adjusted for the kind of YCbCr -> RGB mapping wanted (1:1, full),
* bias is a matrix corresponding to the kind of YCbCr -> RGB mapping wanted (1:1, full)
*
* To calculate procamp,
* mat44 procamp, hue, saturation, brightness, contrast
* procamp = brightness * (saturation * (contrast * hue))
* Alternatively,
* procamp = saturation * (brightness * (contrast * hue))
*
* contrast
* [ c, 0, 0, 0]
* [ 0, c, 0, 0]
* [ 0, 0, c, 0]
* [ 0, 0, 0, 1]
*
* brightness
* [ 1, 0, 0, b]
* [ 0, 1, 0, 0]
* [ 0, 0, 1, 0]
* [ 0, 0, 0, 1]
*
* saturation
* [ 1, 0, 0, 0]
* [ 0, s, 0, 0]
* [ 0, 0, s, 0]
* [ 0, 0, 0, 1]
*
* hue
* [ 1, 0, 0, 0]
* [ 0, cos(h), sin(h), 0]
* [ 0, -sin(h), cos(h), 0]
* [ 0, 0, 0, 1]
*
* procamp
* [ c, 0, 0, b]
* [ 0, c*s*cos(h), c*s*sin(h), 0]
* [ 0, -c*s*sin(h), c*s*cos(h), 0]
* [ 0, 0, 0, 1]
*
* bias
* [ 1, 0, 0, ybias]
* [ 0, 1, 0, cbbias]
* [ 0, 0, 1, crbias]
* [ 0, 0, 0, 1]
*
* csc
* [ c*cstd[ 0], c*cstd[ 1]*s*cos(h) - c*cstd[ 2]*s*sin(h), c*cstd[ 2]*s*cos(h) + c*cstd[ 1]*s*sin(h), cstd[ 3] + cstd[ 0]*(b + c*ybias) + cstd[ 1]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[ 2]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
* [ c*cstd[ 4], c*cstd[ 5]*s*cos(h) - c*cstd[ 6]*s*sin(h), c*cstd[ 6]*s*cos(h) + c*cstd[ 5]*s*sin(h), cstd[ 7] + cstd[ 4]*(b + c*ybias) + cstd[ 5]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[ 6]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
* [ c*cstd[ 8], c*cstd[ 9]*s*cos(h) - c*cstd[10]*s*sin(h), c*cstd[10]*s*cos(h) + c*cstd[ 9]*s*sin(h), cstd[11] + cstd[ 8]*(b + c*ybias) + cstd[ 9]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[10]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
* [ c*cstd[12], c*cstd[13]*s*cos(h) - c*cstd[14]*s*sin(h), c*cstd[14]*s*cos(h) + c*cstd[13]*s*sin(h), cstd[15] + cstd[12]*(b + c*ybias) + cstd[13]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[14]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
*/
 
/*
* Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
* Y is in [16,235], Cb and Cr are in [16,240]
* R, G, and B are in [16,235]
*/
static const vl_csc_matrix bt_601 =
{
{ 1.0f, 0.0f, 1.371f, 0.0f, },
{ 1.0f, -0.336f, -0.698f, 0.0f, },
{ 1.0f, 1.732f, 0.0f, 0.0f, }
};
 
/*
* Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
* Y is in [16,235], Cb and Cr are in [16,240]
* R, G, and B are in [0,255]
*/
static const vl_csc_matrix bt_601_full =
{
{ 1.164f, 0.0f, 1.596f, 0.0f, },
{ 1.164f, -0.391f, -0.813f, 0.0f, },
{ 1.164f, 2.018f, 0.0f, 0.0f, }
};
 
/*
* Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
* Y is in [16,235], Cb and Cr are in [16,240]
* R, G, and B are in [16,235]
*/
static const vl_csc_matrix bt_709 =
{
{ 1.0f, 0.0f, 1.540f, 0.0f, },
{ 1.0f, -0.183f, -0.459f, 0.0f, },
{ 1.0f, 1.816f, 0.0f, 0.0f, }
};
 
/*
* Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
* Y is in [16,235], Cb and Cr are in [16,240]
* R, G, and B are in [0,255]
*/
static const vl_csc_matrix bt_709_full =
{
{ 1.164f, 0.0f, 1.793f, 0.0f, },
{ 1.164f, -0.213f, -0.534f, 0.0f, },
{ 1.164f, 2.115f, 0.0f, 0.0f, }
};
 
static const vl_csc_matrix smpte240m =
{
{ 1.0f, 0.0f, 1.582f, 0.0f, },
{ 1.0f, -0.228f, -0.478f, 0.0f, },
{ 1.0f, 1.833f, 0.0f, 0.0f, }
};
 
static const vl_csc_matrix smpte240m_full =
{
{ 1.164f, 0.0f, 1.794f, 0.0f, },
{ 1.164f, -0.258f, -0.543f, 0.0f, },
{ 1.164f, 2.079f, 0.0f, 0.0f, }
};
 
static const vl_csc_matrix identity =
{
{ 1.0f, 0.0f, 0.0f, 0.0f, },
{ 0.0f, 1.0f, 0.0f, 0.0f, },
{ 0.0f, 0.0f, 1.0f, 0.0f, }
};
 
const struct vl_procamp vl_default_procamp = {
0.0f, /* brightness */
1.0f, /* contrast */
1.0f, /* saturation */
0.0f /* hue */
};
 
void vl_csc_get_matrix(enum VL_CSC_COLOR_STANDARD cs,
struct vl_procamp *procamp,
bool full_range,
vl_csc_matrix *matrix)
{
float ybias = full_range ? -16.0f/255.0f : 0.0f;
float cbbias = -128.0f/255.0f;
float crbias = -128.0f/255.0f;
 
const struct vl_procamp *p = procamp ? procamp : &vl_default_procamp;
float c = p->contrast;
float s = p->saturation;
float b = p->brightness;
float h = p->hue;
 
const vl_csc_matrix *cstd;
 
assert(matrix);
 
switch (cs) {
case VL_CSC_COLOR_STANDARD_BT_601:
cstd = full_range ? &bt_601_full : &bt_601;
break;
case VL_CSC_COLOR_STANDARD_BT_709:
cstd = full_range ? &bt_709_full : &bt_709;
break;
case VL_CSC_COLOR_STANDARD_SMPTE_240M:
cstd = full_range ? &smpte240m_full : &smpte240m;
break;
case VL_CSC_COLOR_STANDARD_IDENTITY:
default:
assert(cs == VL_CSC_COLOR_STANDARD_IDENTITY);
memcpy(matrix, identity, sizeof(vl_csc_matrix));
return;
}
 
(*matrix)[0][0] = c * (*cstd)[0][0];
(*matrix)[0][1] = c * (*cstd)[0][1] * s * cosf(h) - c * (*cstd)[0][2] * s * sinf(h);
(*matrix)[0][2] = c * (*cstd)[0][2] * s * cosf(h) + c * (*cstd)[0][1] * s * sinf(h);
(*matrix)[0][3] = (*cstd)[0][3] + (*cstd)[0][0] * (b + c * ybias) +
(*cstd)[0][1] * (c * cbbias * s * cosf(h) + c * crbias * s * sinf(h)) +
(*cstd)[0][2] * (c * crbias * s * cosf(h) - c * cbbias * s * sinf(h));
 
(*matrix)[1][0] = c * (*cstd)[1][0];
(*matrix)[1][1] = c * (*cstd)[1][1] * s * cosf(h) - c * (*cstd)[1][2] * s * sinf(h);
(*matrix)[1][2] = c * (*cstd)[1][2] * s * cosf(h) + c * (*cstd)[1][1] * s * sinf(h);
(*matrix)[1][3] = (*cstd)[1][3] + (*cstd)[1][0] * (b + c * ybias) +
(*cstd)[1][1] * (c * cbbias * s * cosf(h) + c * crbias * s * sinf(h)) +
(*cstd)[1][2] * (c * crbias * s * cosf(h) - c * cbbias * s * sinf(h));
 
(*matrix)[2][0] = c * (*cstd)[2][0];
(*matrix)[2][1] = c * (*cstd)[2][1] * s * cosf(h) - c * (*cstd)[2][2] * s * sinf(h);
(*matrix)[2][2] = c * (*cstd)[2][2] * s * cosf(h) + c * (*cstd)[2][1] * s * sinf(h);
(*matrix)[2][3] = (*cstd)[2][3] + (*cstd)[2][0] * (b + c * ybias) +
(*cstd)[2][1] * (c * cbbias * s * cosf(h) + c * crbias * s * sinf(h)) +
(*cstd)[2][2] * (c * crbias * s * cosf(h) - c * cbbias * s * sinf(h));
}
/drivers/video/Gallium/auxiliary/vl/vl_csc.h
0,0 → 1,58
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* 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.
*
**************************************************************************/
 
#ifndef vl_csc_h
#define vl_csc_h
 
#include "pipe/p_compiler.h"
 
typedef float vl_csc_matrix[3][4];
 
struct vl_procamp
{
float brightness;
float contrast;
float saturation;
float hue;
};
 
enum VL_CSC_COLOR_STANDARD
{
VL_CSC_COLOR_STANDARD_IDENTITY,
VL_CSC_COLOR_STANDARD_BT_601,
VL_CSC_COLOR_STANDARD_BT_709,
VL_CSC_COLOR_STANDARD_SMPTE_240M
};
 
extern const struct vl_procamp vl_default_procamp;
 
void vl_csc_get_matrix(enum VL_CSC_COLOR_STANDARD cs,
struct vl_procamp *procamp,
bool full_range,
vl_csc_matrix *matrix);
 
#endif /* vl_csc_h */
/drivers/video/Gallium/auxiliary/vl/vl_decoder.c
0,0 → 1,80
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* 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.
*
**************************************************************************/
 
#include "pipe/p_video_decoder.h"
 
#include "util/u_video.h"
 
#include "vl_decoder.h"
#include "vl_mpeg12_decoder.h"
 
bool
vl_profile_supported(struct pipe_screen *screen, enum pipe_video_profile profile)
{
assert(screen);
switch (u_reduce_video_profile(profile)) {
case PIPE_VIDEO_CODEC_MPEG12:
return true;
default:
return false;
}
}
 
struct pipe_video_decoder *
vl_create_decoder(struct pipe_context *pipe,
enum pipe_video_profile profile,
enum pipe_video_entrypoint entrypoint,
enum pipe_video_chroma_format chroma_format,
unsigned width, unsigned height, unsigned max_references,
bool expect_chunked_decode)
{
unsigned buffer_width, buffer_height;
bool pot_buffers;
 
assert(pipe);
assert(width > 0 && height > 0);
pot_buffers = !pipe->screen->get_video_param
(
pipe->screen,
profile,
PIPE_VIDEO_CAP_NPOT_TEXTURES
);
 
buffer_width = pot_buffers ? util_next_power_of_two(width) : align(width, VL_MACROBLOCK_WIDTH);
buffer_height = pot_buffers ? util_next_power_of_two(height) : align(height, VL_MACROBLOCK_HEIGHT);
 
switch (u_reduce_video_profile(profile)) {
case PIPE_VIDEO_CODEC_MPEG12:
return vl_create_mpeg12_decoder(pipe, profile, entrypoint, chroma_format,
buffer_width, buffer_height, max_references,
expect_chunked_decode);
default:
return NULL;
}
return NULL;
}
/drivers/video/Gallium/auxiliary/vl/vl_decoder.h
0,0 → 1,51
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* Copyright 2011 Christian König.
* 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.
*
**************************************************************************/
 
#ifndef vl_decoder_h
#define vl_decoder_h
 
#include "pipe/p_video_decoder.h"
 
/**
* check if a given profile is supported with shader based decoding
*/
bool
vl_profile_supported(struct pipe_screen *screen, enum pipe_video_profile profile);
 
/**
* standard implementation of pipe->create_video_decoder
*/
struct pipe_video_decoder *
vl_create_decoder(struct pipe_context *pipe,
enum pipe_video_profile profile,
enum pipe_video_entrypoint entrypoint,
enum pipe_video_chroma_format chroma_format,
unsigned width, unsigned height, unsigned max_references,
bool expect_chunked_decode);
 
#endif /* vl_decoder_h */
/drivers/video/Gallium/auxiliary/vl/vl_defines.h
0,0 → 1,42
/**************************************************************************
*
* Copyright 2011 Christian König
* 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.
*
**************************************************************************/
 
#ifndef vl_defines_h
#define vl_defines_h
 
/* constants usually used with all known codecs */
#define VL_MACROBLOCK_WIDTH 16
#define VL_MACROBLOCK_HEIGHT 16
 
#define VL_BLOCK_WIDTH 8
#define VL_BLOCK_HEIGHT 8
 
#define VL_NUM_COMPONENTS 3
#define VL_MAX_SURFACES (VL_NUM_COMPONENTS * 2)
#define VL_MAX_REF_FRAMES 2
 
#endif
/drivers/video/Gallium/auxiliary/vl/vl_idct.c
0,0 → 1,856
/**************************************************************************
*
* Copyright 2010 Christian König
* 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.
*
**************************************************************************/
 
#include <assert.h>
 
#include "pipe/p_context.h"
#include "pipe/p_screen.h"
 
#include "util/u_draw.h"
#include "util/u_sampler.h"
#include "util/u_memory.h"
 
#include "tgsi/tgsi_ureg.h"
 
#include "vl_defines.h"
#include "vl_types.h"
#include "vl_vertex_buffers.h"
#include "vl_idct.h"
 
enum VS_OUTPUT
{
VS_O_VPOS = 0,
VS_O_L_ADDR0 = 0,
VS_O_L_ADDR1,
VS_O_R_ADDR0,
VS_O_R_ADDR1
};
 
/**
* The DCT matrix stored as hex representation of floats. Equal to the following equation:
* for (i = 0; i < 8; ++i)
* for (j = 0; j < 8; ++j)
* if (i == 0) const_matrix[i][j] = 1.0f / sqrtf(8.0f);
* else const_matrix[i][j] = sqrtf(2.0f / 8.0f) * cosf((2 * j + 1) * i * M_PI / (2.0f * 8.0f));
*/
static const uint32_t const_matrix[8][8] = {
{ 0x3eb504f3, 0x3eb504f3, 0x3eb504f3, 0x3eb504f3, 0x3eb504f3, 0x3eb504f3, 0x3eb504f3, 0x3eb504f3 },
{ 0x3efb14be, 0x3ed4db31, 0x3e8e39da, 0x3dc7c5c4, 0xbdc7c5c2, 0xbe8e39d9, 0xbed4db32, 0xbefb14bf },
{ 0x3eec835f, 0x3e43ef15, 0xbe43ef14, 0xbeec835e, 0xbeec835f, 0xbe43ef1a, 0x3e43ef1b, 0x3eec835f },
{ 0x3ed4db31, 0xbdc7c5c2, 0xbefb14bf, 0xbe8e39dd, 0x3e8e39d7, 0x3efb14bf, 0x3dc7c5d0, 0xbed4db34 },
{ 0x3eb504f3, 0xbeb504f3, 0xbeb504f4, 0x3eb504f1, 0x3eb504f3, 0xbeb504f0, 0xbeb504ef, 0x3eb504f4 },
{ 0x3e8e39da, 0xbefb14bf, 0x3dc7c5c8, 0x3ed4db32, 0xbed4db34, 0xbdc7c5bb, 0x3efb14bf, 0xbe8e39d7 },
{ 0x3e43ef15, 0xbeec835f, 0x3eec835f, 0xbe43ef07, 0xbe43ef23, 0x3eec8361, 0xbeec835c, 0x3e43ef25 },
{ 0x3dc7c5c4, 0xbe8e39dd, 0x3ed4db32, 0xbefb14c0, 0x3efb14be, 0xbed4db31, 0x3e8e39ce, 0xbdc7c596 },
};
 
static void
calc_addr(struct ureg_program *shader, struct ureg_dst addr[2],
struct ureg_src tc, struct ureg_src start, bool right_side,
bool transposed, float size)
{
unsigned wm_start = (right_side == transposed) ? TGSI_WRITEMASK_X : TGSI_WRITEMASK_Y;
unsigned sw_start = right_side ? TGSI_SWIZZLE_Y : TGSI_SWIZZLE_X;
 
unsigned wm_tc = (right_side == transposed) ? TGSI_WRITEMASK_Y : TGSI_WRITEMASK_X;
unsigned sw_tc = right_side ? TGSI_SWIZZLE_X : TGSI_SWIZZLE_Y;
 
/*
* addr[0..1].(start) = right_side ? start.x : tc.x
* addr[0..1].(tc) = right_side ? tc.y : start.y
* addr[0..1].z = tc.z
* addr[1].(start) += 1.0f / scale
*/
ureg_MOV(shader, ureg_writemask(addr[0], wm_start), ureg_scalar(start, sw_start));
ureg_MOV(shader, ureg_writemask(addr[0], wm_tc), ureg_scalar(tc, sw_tc));
 
ureg_ADD(shader, ureg_writemask(addr[1], wm_start), ureg_scalar(start, sw_start), ureg_imm1f(shader, 1.0f / size));
ureg_MOV(shader, ureg_writemask(addr[1], wm_tc), ureg_scalar(tc, sw_tc));
}
 
static void
increment_addr(struct ureg_program *shader, struct ureg_dst daddr[2],
struct ureg_src saddr[2], bool right_side, bool transposed,
int pos, float size)
{
unsigned wm_start = (right_side == transposed) ? TGSI_WRITEMASK_X : TGSI_WRITEMASK_Y;
unsigned wm_tc = (right_side == transposed) ? TGSI_WRITEMASK_Y : TGSI_WRITEMASK_X;
 
/*
* daddr[0..1].(start) = saddr[0..1].(start)
* daddr[0..1].(tc) = saddr[0..1].(tc)
*/
 
ureg_MOV(shader, ureg_writemask(daddr[0], wm_start), saddr[0]);
ureg_ADD(shader, ureg_writemask(daddr[0], wm_tc), saddr[0], ureg_imm1f(shader, pos / size));
ureg_MOV(shader, ureg_writemask(daddr[1], wm_start), saddr[1]);
ureg_ADD(shader, ureg_writemask(daddr[1], wm_tc), saddr[1], ureg_imm1f(shader, pos / size));
}
 
static void
fetch_four(struct ureg_program *shader, struct ureg_dst m[2], struct ureg_src addr[2],
struct ureg_src sampler, bool resource3d)
{
ureg_TEX(shader, m[0], resource3d ? TGSI_TEXTURE_3D : TGSI_TEXTURE_2D, addr[0], sampler);
ureg_TEX(shader, m[1], resource3d ? TGSI_TEXTURE_3D : TGSI_TEXTURE_2D, addr[1], sampler);
}
 
static void
matrix_mul(struct ureg_program *shader, struct ureg_dst dst, struct ureg_dst l[2], struct ureg_dst r[2])
{
struct ureg_dst tmp;
 
tmp = ureg_DECL_temporary(shader);
 
/*
* tmp.xy = dot4(m[0][0..1], m[1][0..1])
* dst = tmp.x + tmp.y
*/
ureg_DP4(shader, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_src(l[0]), ureg_src(r[0]));
ureg_DP4(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(l[1]), ureg_src(r[1]));
ureg_ADD(shader, dst,
ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X),
ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y));
 
ureg_release_temporary(shader, tmp);
}
 
static void *
create_mismatch_vert_shader(struct vl_idct *idct)
{
struct ureg_program *shader;
struct ureg_src vpos;
struct ureg_src scale;
struct ureg_dst t_tex;
struct ureg_dst o_vpos, o_addr[2];
 
shader = ureg_create(TGSI_PROCESSOR_VERTEX);
if (!shader)
return NULL;
 
vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
 
t_tex = ureg_DECL_temporary(shader);
 
o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
 
o_addr[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR0);
o_addr[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR1);
 
/*
* scale = (VL_BLOCK_WIDTH, VL_BLOCK_HEIGHT) / (dst.width, dst.height)
*
* t_vpos = vpos + 7 / VL_BLOCK_WIDTH
* o_vpos.xy = t_vpos * scale
*
* o_addr = calc_addr(...)
*
*/
 
scale = ureg_imm2f(shader,
(float)VL_BLOCK_WIDTH / idct->buffer_width,
(float)VL_BLOCK_HEIGHT / idct->buffer_height);
 
ureg_MAD(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_XY), vpos, scale, scale);
ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_ZW), ureg_imm1f(shader, 1.0f));
 
ureg_MUL(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_XY), vpos, scale);
calc_addr(shader, o_addr, ureg_src(t_tex), ureg_src(t_tex), false, false, idct->buffer_width / 4);
 
ureg_release_temporary(shader, t_tex);
 
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, idct->pipe);
}
 
static void *
create_mismatch_frag_shader(struct vl_idct *idct)
{
struct ureg_program *shader;
 
struct ureg_src addr[2];
 
struct ureg_dst m[8][2];
struct ureg_dst fragment;
 
unsigned i;
 
shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
if (!shader)
return NULL;
 
addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR0, TGSI_INTERPOLATE_LINEAR);
addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR1, TGSI_INTERPOLATE_LINEAR);
 
fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
 
for (i = 0; i < 8; ++i) {
m[i][0] = ureg_DECL_temporary(shader);
m[i][1] = ureg_DECL_temporary(shader);
}
 
for (i = 0; i < 8; ++i) {
increment_addr(shader, m[i], addr, false, false, i, idct->buffer_height);
}
 
for (i = 0; i < 8; ++i) {
struct ureg_src s_addr[2];
s_addr[0] = ureg_src(m[i][0]);
s_addr[1] = ureg_src(m[i][1]);
fetch_four(shader, m[i], s_addr, ureg_DECL_sampler(shader, 0), false);
}
 
for (i = 1; i < 8; ++i) {
ureg_ADD(shader, m[0][0], ureg_src(m[0][0]), ureg_src(m[i][0]));
ureg_ADD(shader, m[0][1], ureg_src(m[0][1]), ureg_src(m[i][1]));
}
 
ureg_ADD(shader, m[0][0], ureg_src(m[0][0]), ureg_src(m[0][1]));
ureg_DP4(shader, m[0][0], ureg_abs(ureg_src(m[0][0])), ureg_imm1f(shader, 1 << 14));
 
ureg_MUL(shader, ureg_writemask(m[0][0], TGSI_WRITEMASK_W), ureg_abs(ureg_src(m[7][1])), ureg_imm1f(shader, 1 << 14));
ureg_FRC(shader, m[0][0], ureg_src(m[0][0]));
ureg_SGT(shader, m[0][0], ureg_imm1f(shader, 0.5f), ureg_abs(ureg_src(m[0][0])));
 
ureg_CMP(shader, ureg_writemask(m[0][0], TGSI_WRITEMASK_W), ureg_negate(ureg_src(m[0][0])),
ureg_imm1f(shader, 1.0f / (1 << 15)), ureg_imm1f(shader, -1.0f / (1 << 15)));
ureg_MUL(shader, ureg_writemask(m[0][0], TGSI_WRITEMASK_W), ureg_src(m[0][0]),
ureg_scalar(ureg_src(m[0][0]), TGSI_SWIZZLE_X));
 
ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ), ureg_src(m[7][1]));
ureg_ADD(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_src(m[0][0]), ureg_src(m[7][1]));
 
for (i = 0; i < 8; ++i) {
ureg_release_temporary(shader, m[i][0]);
ureg_release_temporary(shader, m[i][1]);
}
 
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, idct->pipe);
}
 
static void *
create_stage1_vert_shader(struct vl_idct *idct)
{
struct ureg_program *shader;
struct ureg_src vrect, vpos;
struct ureg_src scale;
struct ureg_dst t_tex, t_start;
struct ureg_dst o_vpos, o_l_addr[2], o_r_addr[2];
 
shader = ureg_create(TGSI_PROCESSOR_VERTEX);
if (!shader)
return NULL;
 
vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
 
t_tex = ureg_DECL_temporary(shader);
t_start = ureg_DECL_temporary(shader);
 
o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
 
o_l_addr[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR0);
o_l_addr[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR1);
 
o_r_addr[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR0);
o_r_addr[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR1);
 
/*
* scale = (VL_BLOCK_WIDTH, VL_BLOCK_HEIGHT) / (dst.width, dst.height)
*
* t_vpos = vpos + vrect
* o_vpos.xy = t_vpos * scale
* o_vpos.zw = vpos
*
* o_l_addr = calc_addr(...)
* o_r_addr = calc_addr(...)
*
*/
 
scale = ureg_imm2f(shader,
(float)VL_BLOCK_WIDTH / idct->buffer_width,
(float)VL_BLOCK_HEIGHT / idct->buffer_height);
 
ureg_ADD(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_XY), vpos, vrect);
ureg_MUL(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_XY), ureg_src(t_tex), scale);
 
ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_XY), ureg_src(t_tex));
ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_ZW), ureg_imm1f(shader, 1.0f));
 
ureg_MUL(shader, ureg_writemask(t_start, TGSI_WRITEMASK_XY), vpos, scale);
 
calc_addr(shader, o_l_addr, ureg_src(t_tex), ureg_src(t_start), false, false, idct->buffer_width / 4);
calc_addr(shader, o_r_addr, vrect, ureg_imm1f(shader, 0.0f), true, true, VL_BLOCK_WIDTH / 4);
 
ureg_release_temporary(shader, t_tex);
ureg_release_temporary(shader, t_start);
 
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, idct->pipe);
}
 
static void *
create_stage1_frag_shader(struct vl_idct *idct)
{
struct ureg_program *shader;
 
struct ureg_src l_addr[2], r_addr[2];
 
struct ureg_dst l[4][2], r[2];
struct ureg_dst *fragment;
 
int i, j;
 
shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
if (!shader)
return NULL;
 
fragment = MALLOC(idct->nr_of_render_targets * sizeof(struct ureg_dst));
 
l_addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR0, TGSI_INTERPOLATE_LINEAR);
l_addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR1, TGSI_INTERPOLATE_LINEAR);
 
r_addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR0, TGSI_INTERPOLATE_LINEAR);
r_addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR1, TGSI_INTERPOLATE_LINEAR);
 
for (i = 0; i < idct->nr_of_render_targets; ++i)
fragment[i] = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, i);
 
for (i = 0; i < 4; ++i) {
l[i][0] = ureg_DECL_temporary(shader);
l[i][1] = ureg_DECL_temporary(shader);
}
 
r[0] = ureg_DECL_temporary(shader);
r[1] = ureg_DECL_temporary(shader);
 
for (i = 0; i < 4; ++i) {
increment_addr(shader, l[i], l_addr, false, false, i - 2, idct->buffer_height);
}
 
for (i = 0; i < 4; ++i) {
struct ureg_src s_addr[2];
s_addr[0] = ureg_src(l[i][0]);
s_addr[1] = ureg_src(l[i][1]);
fetch_four(shader, l[i], s_addr, ureg_DECL_sampler(shader, 0), false);
}
 
for (i = 0; i < idct->nr_of_render_targets; ++i) {
struct ureg_src s_addr[2];
 
increment_addr(shader, r, r_addr, true, true, i - (signed)idct->nr_of_render_targets / 2, VL_BLOCK_HEIGHT);
 
s_addr[0] = ureg_src(r[0]);
s_addr[1] = ureg_src(r[1]);
fetch_four(shader, r, s_addr, ureg_DECL_sampler(shader, 1), false);
 
for (j = 0; j < 4; ++j) {
matrix_mul(shader, ureg_writemask(fragment[i], TGSI_WRITEMASK_X << j), l[j], r);
}
}
 
for (i = 0; i < 4; ++i) {
ureg_release_temporary(shader, l[i][0]);
ureg_release_temporary(shader, l[i][1]);
}
ureg_release_temporary(shader, r[0]);
ureg_release_temporary(shader, r[1]);
 
ureg_END(shader);
 
FREE(fragment);
 
return ureg_create_shader_and_destroy(shader, idct->pipe);
}
 
void
vl_idct_stage2_vert_shader(struct vl_idct *idct, struct ureg_program *shader,
unsigned first_output, struct ureg_dst tex)
{
struct ureg_src vrect, vpos;
struct ureg_src scale;
struct ureg_dst t_start;
struct ureg_dst o_l_addr[2], o_r_addr[2];
 
vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
 
t_start = ureg_DECL_temporary(shader);
 
--first_output;
 
o_l_addr[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, first_output + VS_O_L_ADDR0);
o_l_addr[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, first_output + VS_O_L_ADDR1);
 
o_r_addr[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, first_output + VS_O_R_ADDR0);
o_r_addr[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, first_output + VS_O_R_ADDR1);
 
scale = ureg_imm2f(shader,
(float)VL_BLOCK_WIDTH / idct->buffer_width,
(float)VL_BLOCK_HEIGHT / idct->buffer_height);
 
ureg_MUL(shader, ureg_writemask(tex, TGSI_WRITEMASK_Z),
ureg_scalar(vrect, TGSI_SWIZZLE_X),
ureg_imm1f(shader, VL_BLOCK_WIDTH / idct->nr_of_render_targets));
ureg_MUL(shader, ureg_writemask(t_start, TGSI_WRITEMASK_XY), vpos, scale);
 
calc_addr(shader, o_l_addr, vrect, ureg_imm1f(shader, 0.0f), false, false, VL_BLOCK_WIDTH / 4);
calc_addr(shader, o_r_addr, ureg_src(tex), ureg_src(t_start), true, false, idct->buffer_height / 4);
 
ureg_MOV(shader, ureg_writemask(o_r_addr[0], TGSI_WRITEMASK_Z), ureg_src(tex));
ureg_MOV(shader, ureg_writemask(o_r_addr[1], TGSI_WRITEMASK_Z), ureg_src(tex));
}
 
void
vl_idct_stage2_frag_shader(struct vl_idct *idct, struct ureg_program *shader,
unsigned first_input, struct ureg_dst fragment)
{
struct ureg_src l_addr[2], r_addr[2];
 
struct ureg_dst l[2], r[2];
 
--first_input;
 
l_addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, first_input + VS_O_L_ADDR0, TGSI_INTERPOLATE_LINEAR);
l_addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, first_input + VS_O_L_ADDR1, TGSI_INTERPOLATE_LINEAR);
 
r_addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, first_input + VS_O_R_ADDR0, TGSI_INTERPOLATE_LINEAR);
r_addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, first_input + VS_O_R_ADDR1, TGSI_INTERPOLATE_LINEAR);
 
l[0] = ureg_DECL_temporary(shader);
l[1] = ureg_DECL_temporary(shader);
r[0] = ureg_DECL_temporary(shader);
r[1] = ureg_DECL_temporary(shader);
 
fetch_four(shader, l, l_addr, ureg_DECL_sampler(shader, 1), false);
fetch_four(shader, r, r_addr, ureg_DECL_sampler(shader, 0), true);
 
matrix_mul(shader, fragment, l, r);
 
ureg_release_temporary(shader, l[0]);
ureg_release_temporary(shader, l[1]);
ureg_release_temporary(shader, r[0]);
ureg_release_temporary(shader, r[1]);
}
 
static bool
init_shaders(struct vl_idct *idct)
{
idct->vs_mismatch = create_mismatch_vert_shader(idct);
if (!idct->vs_mismatch)
goto error_vs_mismatch;
 
idct->fs_mismatch = create_mismatch_frag_shader(idct);
if (!idct->fs_mismatch)
goto error_fs_mismatch;
 
idct->vs = create_stage1_vert_shader(idct);
if (!idct->vs)
goto error_vs;
 
idct->fs = create_stage1_frag_shader(idct);
if (!idct->fs)
goto error_fs;
 
return true;
 
error_fs:
idct->pipe->delete_vs_state(idct->pipe, idct->vs);
 
error_vs:
idct->pipe->delete_vs_state(idct->pipe, idct->vs_mismatch);
 
error_fs_mismatch:
idct->pipe->delete_vs_state(idct->pipe, idct->fs);
 
error_vs_mismatch:
return false;
}
 
static void
cleanup_shaders(struct vl_idct *idct)
{
idct->pipe->delete_vs_state(idct->pipe, idct->vs_mismatch);
idct->pipe->delete_fs_state(idct->pipe, idct->fs_mismatch);
idct->pipe->delete_vs_state(idct->pipe, idct->vs);
idct->pipe->delete_fs_state(idct->pipe, idct->fs);
}
 
static bool
init_state(struct vl_idct *idct)
{
struct pipe_blend_state blend;
struct pipe_rasterizer_state rs_state;
struct pipe_sampler_state sampler;
unsigned i;
 
assert(idct);
 
memset(&rs_state, 0, sizeof(rs_state));
rs_state.point_size = 1;
rs_state.half_pixel_center = true;
rs_state.bottom_edge_rule = true;
rs_state.depth_clip = 1;
idct->rs_state = idct->pipe->create_rasterizer_state(idct->pipe, &rs_state);
if (!idct->rs_state)
goto error_rs_state;
 
memset(&blend, 0, sizeof blend);
 
blend.independent_blend_enable = 0;
blend.rt[0].blend_enable = 0;
blend.rt[0].rgb_func = PIPE_BLEND_ADD;
blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].alpha_func = PIPE_BLEND_ADD;
blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
blend.logicop_enable = 0;
blend.logicop_func = PIPE_LOGICOP_CLEAR;
/* Needed to allow color writes to FB, even if blending disabled */
blend.rt[0].colormask = PIPE_MASK_RGBA;
blend.dither = 0;
idct->blend = idct->pipe->create_blend_state(idct->pipe, &blend);
if (!idct->blend)
goto error_blend;
 
for (i = 0; i < 2; ++i) {
memset(&sampler, 0, sizeof(sampler));
sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
sampler.wrap_t = PIPE_TEX_WRAP_REPEAT;
sampler.wrap_r = PIPE_TEX_WRAP_REPEAT;
sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
sampler.compare_func = PIPE_FUNC_ALWAYS;
sampler.normalized_coords = 1;
idct->samplers[i] = idct->pipe->create_sampler_state(idct->pipe, &sampler);
if (!idct->samplers[i])
goto error_samplers;
}
 
return true;
 
error_samplers:
for (i = 0; i < 2; ++i)
if (idct->samplers[i])
idct->pipe->delete_sampler_state(idct->pipe, idct->samplers[i]);
 
idct->pipe->delete_rasterizer_state(idct->pipe, idct->rs_state);
 
error_blend:
idct->pipe->delete_blend_state(idct->pipe, idct->blend);
 
error_rs_state:
return false;
}
 
static void
cleanup_state(struct vl_idct *idct)
{
unsigned i;
 
for (i = 0; i < 2; ++i)
idct->pipe->delete_sampler_state(idct->pipe, idct->samplers[i]);
 
idct->pipe->delete_rasterizer_state(idct->pipe, idct->rs_state);
idct->pipe->delete_blend_state(idct->pipe, idct->blend);
}
 
static bool
init_source(struct vl_idct *idct, struct vl_idct_buffer *buffer)
{
struct pipe_resource *tex;
struct pipe_surface surf_templ;
 
assert(idct && buffer);
 
tex = buffer->sampler_views.individual.source->texture;
 
buffer->fb_state_mismatch.width = tex->width0;
buffer->fb_state_mismatch.height = tex->height0;
buffer->fb_state_mismatch.nr_cbufs = 1;
 
memset(&surf_templ, 0, sizeof(surf_templ));
surf_templ.format = tex->format;
surf_templ.u.tex.first_layer = 0;
surf_templ.u.tex.last_layer = 0;
buffer->fb_state_mismatch.cbufs[0] = idct->pipe->create_surface(idct->pipe, tex, &surf_templ);
 
buffer->viewport_mismatch.scale[0] = tex->width0;
buffer->viewport_mismatch.scale[1] = tex->height0;
buffer->viewport_mismatch.scale[2] = 1;
buffer->viewport_mismatch.scale[3] = 1;
 
return true;
}
 
static void
cleanup_source(struct vl_idct_buffer *buffer)
{
assert(buffer);
 
pipe_surface_reference(&buffer->fb_state_mismatch.cbufs[0], NULL);
 
pipe_sampler_view_reference(&buffer->sampler_views.individual.source, NULL);
}
 
static bool
init_intermediate(struct vl_idct *idct, struct vl_idct_buffer *buffer)
{
struct pipe_resource *tex;
struct pipe_surface surf_templ;
unsigned i;
 
assert(idct && buffer);
 
tex = buffer->sampler_views.individual.intermediate->texture;
 
buffer->fb_state.width = tex->width0;
buffer->fb_state.height = tex->height0;
buffer->fb_state.nr_cbufs = idct->nr_of_render_targets;
for(i = 0; i < idct->nr_of_render_targets; ++i) {
memset(&surf_templ, 0, sizeof(surf_templ));
surf_templ.format = tex->format;
surf_templ.u.tex.first_layer = i;
surf_templ.u.tex.last_layer = i;
buffer->fb_state.cbufs[i] = idct->pipe->create_surface(
idct->pipe, tex, &surf_templ);
 
if (!buffer->fb_state.cbufs[i])
goto error_surfaces;
}
 
buffer->viewport.scale[0] = tex->width0;
buffer->viewport.scale[1] = tex->height0;
buffer->viewport.scale[2] = 1;
buffer->viewport.scale[3] = 1;
 
return true;
 
error_surfaces:
for(i = 0; i < idct->nr_of_render_targets; ++i)
pipe_surface_reference(&buffer->fb_state.cbufs[i], NULL);
 
return false;
}
 
static void
cleanup_intermediate(struct vl_idct_buffer *buffer)
{
unsigned i;
 
assert(buffer);
 
for(i = 0; i < PIPE_MAX_COLOR_BUFS; ++i)
pipe_surface_reference(&buffer->fb_state.cbufs[i], NULL);
 
pipe_sampler_view_reference(&buffer->sampler_views.individual.intermediate, NULL);
}
 
struct pipe_sampler_view *
vl_idct_upload_matrix(struct pipe_context *pipe, float scale)
{
struct pipe_resource tex_templ, *matrix;
struct pipe_sampler_view sv_templ, *sv;
struct pipe_transfer *buf_transfer;
unsigned i, j, pitch;
float *f;
 
struct pipe_box rect =
{
0, 0, 0,
VL_BLOCK_WIDTH / 4,
VL_BLOCK_HEIGHT,
1
};
 
assert(pipe);
 
memset(&tex_templ, 0, sizeof(tex_templ));
tex_templ.target = PIPE_TEXTURE_2D;
tex_templ.format = PIPE_FORMAT_R32G32B32A32_FLOAT;
tex_templ.last_level = 0;
tex_templ.width0 = 2;
tex_templ.height0 = 8;
tex_templ.depth0 = 1;
tex_templ.array_size = 1;
tex_templ.usage = PIPE_USAGE_IMMUTABLE;
tex_templ.bind = PIPE_BIND_SAMPLER_VIEW;
tex_templ.flags = 0;
 
matrix = pipe->screen->resource_create(pipe->screen, &tex_templ);
if (!matrix)
goto error_matrix;
 
f = pipe->transfer_map(pipe, matrix, 0,
PIPE_TRANSFER_WRITE |
PIPE_TRANSFER_DISCARD_RANGE,
&rect, &buf_transfer);
if (!f)
goto error_map;
 
pitch = buf_transfer->stride / sizeof(float);
 
for(i = 0; i < VL_BLOCK_HEIGHT; ++i)
for(j = 0; j < VL_BLOCK_WIDTH; ++j)
// transpose and scale
f[i * pitch + j] = ((const float (*)[8])const_matrix)[j][i] * scale;
 
pipe->transfer_unmap(pipe, buf_transfer);
 
memset(&sv_templ, 0, sizeof(sv_templ));
u_sampler_view_default_template(&sv_templ, matrix, matrix->format);
sv = pipe->create_sampler_view(pipe, matrix, &sv_templ);
pipe_resource_reference(&matrix, NULL);
if (!sv)
goto error_map;
 
return sv;
 
error_map:
pipe_resource_reference(&matrix, NULL);
 
error_matrix:
return NULL;
}
 
bool vl_idct_init(struct vl_idct *idct, struct pipe_context *pipe,
unsigned buffer_width, unsigned buffer_height,
unsigned nr_of_render_targets,
struct pipe_sampler_view *matrix,
struct pipe_sampler_view *transpose)
{
assert(idct && pipe);
assert(matrix && transpose);
 
idct->pipe = pipe;
idct->buffer_width = buffer_width;
idct->buffer_height = buffer_height;
idct->nr_of_render_targets = nr_of_render_targets;
 
pipe_sampler_view_reference(&idct->matrix, matrix);
pipe_sampler_view_reference(&idct->transpose, transpose);
 
if(!init_shaders(idct))
return false;
 
if(!init_state(idct)) {
cleanup_shaders(idct);
return false;
}
 
return true;
}
 
void
vl_idct_cleanup(struct vl_idct *idct)
{
cleanup_shaders(idct);
cleanup_state(idct);
 
pipe_sampler_view_reference(&idct->matrix, NULL);
pipe_sampler_view_reference(&idct->transpose, NULL);
}
 
bool
vl_idct_init_buffer(struct vl_idct *idct, struct vl_idct_buffer *buffer,
struct pipe_sampler_view *source,
struct pipe_sampler_view *intermediate)
{
assert(buffer && idct);
assert(source && intermediate);
 
memset(buffer, 0, sizeof(struct vl_idct_buffer));
 
pipe_sampler_view_reference(&buffer->sampler_views.individual.matrix, idct->matrix);
pipe_sampler_view_reference(&buffer->sampler_views.individual.source, source);
pipe_sampler_view_reference(&buffer->sampler_views.individual.transpose, idct->transpose);
pipe_sampler_view_reference(&buffer->sampler_views.individual.intermediate, intermediate);
 
if (!init_source(idct, buffer))
return false;
 
if (!init_intermediate(idct, buffer))
return false;
 
return true;
}
 
void
vl_idct_cleanup_buffer(struct vl_idct_buffer *buffer)
{
assert(buffer);
 
cleanup_source(buffer);
cleanup_intermediate(buffer);
 
pipe_sampler_view_reference(&buffer->sampler_views.individual.matrix, NULL);
pipe_sampler_view_reference(&buffer->sampler_views.individual.transpose, NULL);
}
 
void
vl_idct_flush(struct vl_idct *idct, struct vl_idct_buffer *buffer, unsigned num_instances)
{
assert(buffer);
 
idct->pipe->bind_rasterizer_state(idct->pipe, idct->rs_state);
idct->pipe->bind_blend_state(idct->pipe, idct->blend);
idct->pipe->bind_fragment_sampler_states(idct->pipe, 2, idct->samplers);
idct->pipe->set_fragment_sampler_views(idct->pipe, 2, buffer->sampler_views.stage[0]);
 
/* mismatch control */
idct->pipe->set_framebuffer_state(idct->pipe, &buffer->fb_state_mismatch);
idct->pipe->set_viewport_states(idct->pipe, 0, 1, &buffer->viewport_mismatch);
idct->pipe->bind_vs_state(idct->pipe, idct->vs_mismatch);
idct->pipe->bind_fs_state(idct->pipe, idct->fs_mismatch);
util_draw_arrays_instanced(idct->pipe, PIPE_PRIM_POINTS, 0, 1, 0, num_instances);
 
/* first stage */
idct->pipe->set_framebuffer_state(idct->pipe, &buffer->fb_state);
idct->pipe->set_viewport_states(idct->pipe, 0, 1, &buffer->viewport);
idct->pipe->bind_vs_state(idct->pipe, idct->vs);
idct->pipe->bind_fs_state(idct->pipe, idct->fs);
util_draw_arrays_instanced(idct->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances);
}
 
void
vl_idct_prepare_stage2(struct vl_idct *idct, struct vl_idct_buffer *buffer)
{
assert(buffer);
 
/* second stage */
idct->pipe->bind_rasterizer_state(idct->pipe, idct->rs_state);
idct->pipe->bind_fragment_sampler_states(idct->pipe, 2, idct->samplers);
idct->pipe->set_fragment_sampler_views(idct->pipe, 2, buffer->sampler_views.stage[1]);
}
 
/drivers/video/Gallium/auxiliary/vl/vl_idct.h
0,0 → 1,119
/**************************************************************************
*
* Copyright 2010 Christian König
* 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.
*
**************************************************************************/
 
#ifndef vl_idct_h
#define vl_idct_h
 
#include "pipe/p_state.h"
 
#include "tgsi/tgsi_ureg.h"
 
/* shader based inverse distinct cosinus transformation
* expect usage of vl_vertex_buffers as a todo list
*/
struct vl_idct
{
struct pipe_context *pipe;
 
unsigned buffer_width;
unsigned buffer_height;
unsigned nr_of_render_targets;
 
void *rs_state;
void *blend;
 
void *samplers[2];
 
void *vs_mismatch, *fs_mismatch;
void *vs, *fs;
 
struct pipe_sampler_view *matrix;
struct pipe_sampler_view *transpose;
};
 
/* a set of buffers to work with */
struct vl_idct_buffer
{
struct pipe_viewport_state viewport_mismatch;
struct pipe_viewport_state viewport;
 
struct pipe_framebuffer_state fb_state_mismatch;
struct pipe_framebuffer_state fb_state;
 
union
{
struct pipe_sampler_view *all[4];
struct pipe_sampler_view *stage[2][2];
struct {
struct pipe_sampler_view *source, *matrix;
struct pipe_sampler_view *intermediate, *transpose;
} individual;
} sampler_views;
};
 
/* upload the idct matrix, which can be shared by all idct instances of a pipe */
struct pipe_sampler_view *
vl_idct_upload_matrix(struct pipe_context *pipe, float scale);
 
void
vl_idct_stage2_vert_shader(struct vl_idct *idct, struct ureg_program *shader,
unsigned first_output, struct ureg_dst tex);
 
void
vl_idct_stage2_frag_shader(struct vl_idct *idct, struct ureg_program *shader,
unsigned first_input, struct ureg_dst fragment);
 
/* init an idct instance */
bool
vl_idct_init(struct vl_idct *idct, struct pipe_context *pipe,
unsigned buffer_width, unsigned buffer_height,
unsigned nr_of_render_targets,
struct pipe_sampler_view *matrix,
struct pipe_sampler_view *transpose);
 
/* destroy an idct instance */
void
vl_idct_cleanup(struct vl_idct *idct);
 
/* init a buffer assosiated with agiven idct instance */
bool
vl_idct_init_buffer(struct vl_idct *idct, struct vl_idct_buffer *buffer,
struct pipe_sampler_view *source,
struct pipe_sampler_view *intermediate);
 
/* cleanup a buffer of an idct instance */
void
vl_idct_cleanup_buffer(struct vl_idct_buffer *buffer);
 
/* flush the buffer and start rendering, vertex buffers needs to be setup before calling this */
void
vl_idct_flush(struct vl_idct *idct, struct vl_idct_buffer *buffer, unsigned num_verts);
 
void
vl_idct_prepare_stage2(struct vl_idct *idct, struct vl_idct_buffer *buffer);
 
#endif
/drivers/video/Gallium/auxiliary/vl/vl_matrix_filter.c
0,0 → 1,319
/**************************************************************************
*
* Copyright 2012 Christian König.
* 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.
*
**************************************************************************/
 
#include <stdio.h>
 
#include "pipe/p_context.h"
 
#include "tgsi/tgsi_ureg.h"
 
#include "util/u_draw.h"
#include "util/u_memory.h"
#include "util/u_math.h"
 
#include "vl_types.h"
#include "vl_vertex_buffers.h"
#include "vl_matrix_filter.h"
 
enum VS_OUTPUT
{
VS_O_VPOS = 0,
VS_O_VTEX = 0
};
 
static void *
create_vert_shader(struct vl_matrix_filter *filter)
{
struct ureg_program *shader;
struct ureg_src i_vpos;
struct ureg_dst o_vpos, o_vtex;
 
shader = ureg_create(TGSI_PROCESSOR_VERTEX);
if (!shader)
return NULL;
 
i_vpos = ureg_DECL_vs_input(shader, 0);
o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX);
 
ureg_MOV(shader, o_vpos, i_vpos);
ureg_MOV(shader, o_vtex, i_vpos);
 
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, filter->pipe);
}
 
static inline bool
is_vec_zero(struct vertex2f v)
{
return v.x == 0.0f && v.y == 0.0f;
}
 
static void *
create_frag_shader(struct vl_matrix_filter *filter, unsigned num_offsets,
struct vertex2f *offsets, const float *matrix_values)
{
struct ureg_program *shader;
struct ureg_src i_vtex;
struct ureg_src sampler;
struct ureg_dst *t_array = MALLOC(sizeof(struct ureg_dst) * num_offsets);
struct ureg_dst t_sum;
struct ureg_dst o_fragment;
bool first;
int i;
 
shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
if (!shader) {
FREE(t_array);
return NULL;
}
 
i_vtex = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX, TGSI_INTERPOLATE_LINEAR);
sampler = ureg_DECL_sampler(shader, 0);
 
for (i = 0; i < num_offsets; ++i)
if (matrix_values[i] != 0.0f)
t_array[i] = ureg_DECL_temporary(shader);
 
o_fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
 
/*
* t_array[0..*] = vtex + offset[0..*]
* t_array[0..*] = tex(t_array[0..*], sampler)
* o_fragment = sum(t_array[0..*] * matrix_values[0..*])
*/
 
for (i = 0; i < num_offsets; ++i) {
if (matrix_values[i] != 0.0f && !is_vec_zero(offsets[i])) {
ureg_ADD(shader, ureg_writemask(t_array[i], TGSI_WRITEMASK_XY),
i_vtex, ureg_imm2f(shader, offsets[i].x, offsets[i].y));
ureg_MOV(shader, ureg_writemask(t_array[i], TGSI_WRITEMASK_ZW),
ureg_imm1f(shader, 0.0f));
}
}
 
for (i = 0; i < num_offsets; ++i) {
if (matrix_values[i] != 0.0f) {
struct ureg_src src = is_vec_zero(offsets[i]) ? i_vtex : ureg_src(t_array[i]);
ureg_TEX(shader, t_array[i], TGSI_TEXTURE_2D, src, sampler);
}
}
 
for (i = 0, first = true; i < num_offsets; ++i) {
if (matrix_values[i] != 0.0f) {
if (first) {
t_sum = t_array[i];
ureg_MUL(shader, t_sum, ureg_src(t_array[i]),
ureg_imm1f(shader, matrix_values[i]));
first = false;
} else
ureg_MAD(shader, t_sum, ureg_src(t_array[i]),
ureg_imm1f(shader, matrix_values[i]), ureg_src(t_sum));
}
}
if (first)
ureg_MOV(shader, o_fragment, ureg_imm1f(shader, 0.0f));
else
ureg_MOV(shader, o_fragment, ureg_src(t_sum));
 
ureg_END(shader);
 
FREE(t_array);
return ureg_create_shader_and_destroy(shader, filter->pipe);
}
 
bool
vl_matrix_filter_init(struct vl_matrix_filter *filter, struct pipe_context *pipe,
unsigned video_width, unsigned video_height,
unsigned matrix_width, unsigned matrix_height,
const float *matrix_values)
{
struct pipe_rasterizer_state rs_state;
struct pipe_blend_state blend;
struct pipe_sampler_state sampler;
struct pipe_vertex_element ve;
struct vertex2f *offsets, v, sizes;
unsigned i, num_offsets = matrix_width * matrix_height;
 
assert(filter && pipe);
assert(video_width && video_height);
assert(matrix_width && matrix_height);
 
memset(filter, 0, sizeof(*filter));
filter->pipe = pipe;
 
memset(&rs_state, 0, sizeof(rs_state));
rs_state.half_pixel_center = true;
rs_state.bottom_edge_rule = true;
rs_state.depth_clip = 1;
filter->rs_state = pipe->create_rasterizer_state(pipe, &rs_state);
if (!filter->rs_state)
goto error_rs_state;
 
memset(&blend, 0, sizeof blend);
blend.rt[0].rgb_func = PIPE_BLEND_ADD;
blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].alpha_func = PIPE_BLEND_ADD;
blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
blend.logicop_func = PIPE_LOGICOP_CLEAR;
blend.rt[0].colormask = PIPE_MASK_RGBA;
filter->blend = pipe->create_blend_state(pipe, &blend);
if (!filter->blend)
goto error_blend;
 
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_img_filter = PIPE_TEX_FILTER_NEAREST;
sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
sampler.compare_func = PIPE_FUNC_ALWAYS;
sampler.normalized_coords = 1;
filter->sampler = pipe->create_sampler_state(pipe, &sampler);
if (!filter->sampler)
goto error_sampler;
 
filter->quad = vl_vb_upload_quads(pipe);
if(!filter->quad.buffer)
goto error_quad;
 
memset(&ve, 0, sizeof(ve));
ve.src_offset = 0;
ve.instance_divisor = 0;
ve.vertex_buffer_index = 0;
ve.src_format = PIPE_FORMAT_R32G32_FLOAT;
filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve);
if (!filter->ves)
goto error_ves;
 
offsets = MALLOC(sizeof(struct vertex2f) * num_offsets);
if (!offsets)
goto error_offsets;
 
sizes.x = (float)(matrix_width - 1) / 2.0f;
sizes.y = (float)(matrix_height - 1) / 2.0f;
 
for (v.x = -sizes.x, i = 0; v.x <= sizes.x; v.x += 1.0f)
for (v.y = -sizes.y; v.y <= sizes.y; v.y += 1.0f)
offsets[i++] = v;
 
for (i = 0; i < num_offsets; ++i) {
offsets[i].x /= video_width;
offsets[i].y /= video_height;
}
 
filter->vs = create_vert_shader(filter);
if (!filter->vs)
goto error_vs;
 
filter->fs = create_frag_shader(filter, num_offsets, offsets, matrix_values);
if (!filter->fs)
goto error_fs;
 
FREE(offsets);
return true;
 
error_fs:
pipe->delete_vs_state(pipe, filter->vs);
 
error_vs:
FREE(offsets);
 
error_offsets:
pipe->delete_vertex_elements_state(pipe, filter->ves);
 
error_ves:
pipe_resource_reference(&filter->quad.buffer, NULL);
 
error_quad:
pipe->delete_sampler_state(pipe, filter->sampler);
 
error_sampler:
pipe->delete_blend_state(pipe, filter->blend);
 
error_blend:
pipe->delete_rasterizer_state(pipe, filter->rs_state);
 
error_rs_state:
return false;
}
 
void
vl_matrix_filter_cleanup(struct vl_matrix_filter *filter)
{
assert(filter);
 
filter->pipe->delete_sampler_state(filter->pipe, filter->sampler);
filter->pipe->delete_blend_state(filter->pipe, filter->blend);
filter->pipe->delete_rasterizer_state(filter->pipe, filter->rs_state);
filter->pipe->delete_vertex_elements_state(filter->pipe, filter->ves);
pipe_resource_reference(&filter->quad.buffer, NULL);
 
filter->pipe->delete_vs_state(filter->pipe, filter->vs);
filter->pipe->delete_fs_state(filter->pipe, filter->fs);
}
 
void
vl_matrix_filter_render(struct vl_matrix_filter *filter,
struct pipe_sampler_view *src,
struct pipe_surface *dst)
{
struct pipe_viewport_state viewport;
struct pipe_framebuffer_state fb_state;
 
assert(filter && src && dst);
 
memset(&viewport, 0, sizeof(viewport));
viewport.scale[0] = dst->width;
viewport.scale[1] = dst->height;
viewport.scale[2] = 1;
viewport.scale[3] = 1;
 
memset(&fb_state, 0, sizeof(fb_state));
fb_state.width = dst->width;
fb_state.height = dst->height;
fb_state.nr_cbufs = 1;
fb_state.cbufs[0] = dst;
 
filter->pipe->bind_rasterizer_state(filter->pipe, filter->rs_state);
filter->pipe->bind_blend_state(filter->pipe, filter->blend);
filter->pipe->bind_fragment_sampler_states(filter->pipe, 1, &filter->sampler);
filter->pipe->set_fragment_sampler_views(filter->pipe, 1, &src);
filter->pipe->bind_vs_state(filter->pipe, filter->vs);
filter->pipe->bind_fs_state(filter->pipe, filter->fs);
filter->pipe->set_framebuffer_state(filter->pipe, &fb_state);
filter->pipe->set_viewport_states(filter->pipe, 0, 1, &viewport);
filter->pipe->set_vertex_buffers(filter->pipe, 0, 1, &filter->quad);
filter->pipe->bind_vertex_elements_state(filter->pipe, filter->ves);
 
util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
}
/drivers/video/Gallium/auxiliary/vl/vl_matrix_filter.h
0,0 → 1,64
/**************************************************************************
*
* Copyright 2012 Christian König.
* 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.
*
**************************************************************************/
 
/* implementation of all matrix based filters like
gaussian, mean, laplacian, emboss, sharpness etc.. */
 
#ifndef vl_matrix_filter_h
#define vl_matrix_filter_h
 
#include "pipe/p_state.h"
 
struct vl_matrix_filter
{
struct pipe_context *pipe;
struct pipe_vertex_buffer quad;
 
void *rs_state;
void *blend;
void *sampler;
void *ves;
void *vs, *fs;
};
 
bool
vl_matrix_filter_init(struct vl_matrix_filter *filter, struct pipe_context *pipe,
unsigned video_width, unsigned video_height,
unsigned matrix_width, unsigned matrix_height,
const float *matrix_values);
 
void
vl_matrix_filter_cleanup(struct vl_matrix_filter *filter);
 
 
void
vl_matrix_filter_render(struct vl_matrix_filter *filter,
struct pipe_sampler_view *src,
struct pipe_surface *dst);
 
 
#endif /* vl_matrix_filter_h */
/drivers/video/Gallium/auxiliary/vl/vl_mc.c
0,0 → 1,648
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* 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.
*
**************************************************************************/
 
#include <assert.h>
 
#include "pipe/p_context.h"
 
#include "util/u_sampler.h"
#include "util/u_draw.h"
 
#include "tgsi/tgsi_ureg.h"
 
#include "vl_defines.h"
#include "vl_vertex_buffers.h"
#include "vl_mc.h"
#include "vl_idct.h"
 
enum VS_OUTPUT
{
VS_O_VPOS = 0,
VS_O_VTOP = 0,
VS_O_VBOTTOM,
 
VS_O_FLAGS = VS_O_VTOP,
VS_O_VTEX = VS_O_VBOTTOM
};
 
static struct ureg_dst
calc_position(struct vl_mc *r, struct ureg_program *shader, struct ureg_src block_scale)
{
struct ureg_src vrect, vpos;
struct ureg_dst t_vpos;
struct ureg_dst o_vpos;
 
vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
 
t_vpos = ureg_DECL_temporary(shader);
 
o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
 
/*
* block_scale = (VL_MACROBLOCK_WIDTH, VL_MACROBLOCK_HEIGHT) / (dst.width, dst.height)
*
* t_vpos = (vpos + vrect) * block_scale
* o_vpos.xy = t_vpos
* o_vpos.zw = vpos
*/
ureg_ADD(shader, ureg_writemask(t_vpos, TGSI_WRITEMASK_XY), vpos, vrect);
ureg_MUL(shader, ureg_writemask(t_vpos, TGSI_WRITEMASK_XY), ureg_src(t_vpos), block_scale);
ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_XY), ureg_src(t_vpos));
ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_ZW), ureg_imm1f(shader, 1.0f));
 
return t_vpos;
}
 
static struct ureg_dst
calc_line(struct ureg_program *shader)
{
struct ureg_dst tmp;
struct ureg_src pos;
 
tmp = ureg_DECL_temporary(shader);
 
pos = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS, TGSI_INTERPOLATE_LINEAR);
 
/*
* tmp.y = fraction(pos.y / 2) >= 0.5 ? 1 : 0
*/
ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), pos, ureg_imm1f(shader, 0.5f));
ureg_FRC(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp));
ureg_SGE(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp), ureg_imm1f(shader, 0.5f));
 
return tmp;
}
 
static void *
create_ref_vert_shader(struct vl_mc *r)
{
struct ureg_program *shader;
struct ureg_src mv_scale;
struct ureg_src vmv[2];
struct ureg_dst t_vpos;
struct ureg_dst o_vmv[2];
unsigned i;
 
shader = ureg_create(TGSI_PROCESSOR_VERTEX);
if (!shader)
return NULL;
 
vmv[0] = ureg_DECL_vs_input(shader, VS_I_MV_TOP);
vmv[1] = ureg_DECL_vs_input(shader, VS_I_MV_BOTTOM);
 
t_vpos = calc_position(r, shader, ureg_imm2f(shader,
(float)VL_MACROBLOCK_WIDTH / r->buffer_width,
(float)VL_MACROBLOCK_HEIGHT / r->buffer_height)
);
 
o_vmv[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTOP);
o_vmv[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VBOTTOM);
 
/*
* mv_scale.xy = 0.5 / (dst.width, dst.height);
* mv_scale.z = 1.0f / 4.0f
* mv_scale.w = 1.0f / 255.0f
*
* // Apply motion vectors
* o_vmv[0..1].xy = vmv[0..1] * mv_scale + t_vpos
* o_vmv[0..1].zw = vmv[0..1] * mv_scale
*
*/
 
mv_scale = ureg_imm4f(shader,
0.5f / r->buffer_width,
0.5f / r->buffer_height,
1.0f / 4.0f,
1.0f / PIPE_VIDEO_MV_WEIGHT_MAX);
 
for (i = 0; i < 2; ++i) {
ureg_MAD(shader, ureg_writemask(o_vmv[i], TGSI_WRITEMASK_XY), mv_scale, vmv[i], ureg_src(t_vpos));
ureg_MUL(shader, ureg_writemask(o_vmv[i], TGSI_WRITEMASK_ZW), mv_scale, vmv[i]);
}
 
ureg_release_temporary(shader, t_vpos);
 
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, r->pipe);
}
 
static void *
create_ref_frag_shader(struct vl_mc *r)
{
const float y_scale =
r->buffer_height / 2 *
r->macroblock_size / VL_MACROBLOCK_HEIGHT;
 
struct ureg_program *shader;
struct ureg_src tc[2], sampler;
struct ureg_dst ref, field;
struct ureg_dst fragment;
unsigned label;
 
shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
if (!shader)
return NULL;
 
tc[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTOP, TGSI_INTERPOLATE_LINEAR);
tc[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VBOTTOM, TGSI_INTERPOLATE_LINEAR);
 
sampler = ureg_DECL_sampler(shader, 0);
ref = ureg_DECL_temporary(shader);
 
fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
 
field = calc_line(shader);
 
/*
* ref = field.z ? tc[1] : tc[0]
*
* // Adjust tc acording to top/bottom field selection
* if (|ref.z|) {
* ref.y *= y_scale
* ref.y = floor(ref.y)
* ref.y += ref.z
* ref.y /= y_scale
* }
* fragment.xyz = tex(ref, sampler[0])
*/
ureg_CMP(shader, ureg_writemask(ref, TGSI_WRITEMASK_XYZ),
ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y)),
tc[1], tc[0]);
ureg_CMP(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W),
ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y)),
tc[1], tc[0]);
 
ureg_IF(shader, ureg_scalar(ureg_src(ref), TGSI_SWIZZLE_Z), &label);
 
ureg_MUL(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y),
ureg_src(ref), ureg_imm1f(shader, y_scale));
ureg_FLR(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y), ureg_src(ref));
ureg_ADD(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y),
ureg_src(ref), ureg_scalar(ureg_src(ref), TGSI_SWIZZLE_Z));
ureg_MUL(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y),
ureg_src(ref), ureg_imm1f(shader, 1.0f / y_scale));
 
ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
ureg_ENDIF(shader);
 
ureg_TEX(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ), TGSI_TEXTURE_2D, ureg_src(ref), sampler);
 
ureg_release_temporary(shader, ref);
 
ureg_release_temporary(shader, field);
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, r->pipe);
}
 
static void *
create_ycbcr_vert_shader(struct vl_mc *r, vl_mc_ycbcr_vert_shader vs_callback, void *callback_priv)
{
struct ureg_program *shader;
 
struct ureg_src vrect, vpos;
struct ureg_dst t_vpos, t_vtex;
struct ureg_dst o_vpos, o_flags;
 
struct vertex2f scale = {
(float)VL_BLOCK_WIDTH / r->buffer_width * VL_MACROBLOCK_WIDTH / r->macroblock_size,
(float)VL_BLOCK_HEIGHT / r->buffer_height * VL_MACROBLOCK_HEIGHT / r->macroblock_size
};
 
unsigned label;
 
shader = ureg_create(TGSI_PROCESSOR_VERTEX);
if (!shader)
return NULL;
 
vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
 
t_vpos = calc_position(r, shader, ureg_imm2f(shader, scale.x, scale.y));
t_vtex = ureg_DECL_temporary(shader);
 
o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
o_flags = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_FLAGS);
 
/*
* o_vtex.xy = t_vpos
* o_flags.z = intra * 0.5
*
* if(interlaced) {
* t_vtex.xy = vrect.y ? { 0, scale.y } : { -scale.y : 0 }
* t_vtex.z = vpos.y % 2
* t_vtex.y = t_vtex.z ? t_vtex.x : t_vtex.y
* o_vpos.y = t_vtex.y + t_vpos.y
*
* o_flags.w = t_vtex.z ? 0 : 1
* }
*
*/
 
vs_callback(callback_priv, r, shader, VS_O_VTEX, t_vpos);
 
ureg_MUL(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_Z),
ureg_scalar(vpos, TGSI_SWIZZLE_Z), ureg_imm1f(shader, 0.5f));
ureg_MOV(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_W), ureg_imm1f(shader, -1.0f));
 
if (r->macroblock_size == VL_MACROBLOCK_HEIGHT) { //TODO
ureg_IF(shader, ureg_scalar(vpos, TGSI_SWIZZLE_W), &label);
 
ureg_CMP(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_XY),
ureg_negate(ureg_scalar(vrect, TGSI_SWIZZLE_Y)),
ureg_imm2f(shader, 0.0f, scale.y),
ureg_imm2f(shader, -scale.y, 0.0f));
ureg_MUL(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Z),
ureg_scalar(vpos, TGSI_SWIZZLE_Y), ureg_imm1f(shader, 0.5f));
 
ureg_FRC(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Z), ureg_src(t_vtex));
 
ureg_CMP(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Y),
ureg_negate(ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Z)),
ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_X),
ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Y));
ureg_ADD(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_Y),
ureg_src(t_vpos), ureg_src(t_vtex));
 
ureg_CMP(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_W),
ureg_negate(ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Z)),
ureg_imm1f(shader, 0.0f), ureg_imm1f(shader, 1.0f));
 
ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
ureg_ENDIF(shader);
}
 
ureg_release_temporary(shader, t_vtex);
ureg_release_temporary(shader, t_vpos);
 
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, r->pipe);
}
 
static void *
create_ycbcr_frag_shader(struct vl_mc *r, float scale, bool invert,
vl_mc_ycbcr_frag_shader fs_callback, void *callback_priv)
{
struct ureg_program *shader;
struct ureg_src flags;
struct ureg_dst tmp;
struct ureg_dst fragment;
unsigned label;
 
shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
if (!shader)
return NULL;
 
flags = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_FLAGS, TGSI_INTERPOLATE_LINEAR);
 
fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
 
tmp = calc_line(shader);
 
/*
* if (field == tc.w)
* kill();
* else {
* fragment.xyz = tex(tc, sampler) * scale + tc.z
* fragment.w = 1.0f
* }
*/
 
ureg_SEQ(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y),
ureg_scalar(flags, TGSI_SWIZZLE_W), ureg_src(tmp));
 
ureg_IF(shader, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y), &label);
 
ureg_KILP(shader);
 
ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
ureg_ELSE(shader, &label);
 
fs_callback(callback_priv, r, shader, VS_O_VTEX, tmp);
 
if (scale != 1.0f)
ureg_MAD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ),
ureg_src(tmp), ureg_imm1f(shader, scale),
ureg_scalar(flags, TGSI_SWIZZLE_Z));
else
ureg_ADD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ),
ureg_src(tmp), ureg_scalar(flags, TGSI_SWIZZLE_Z));
ureg_MUL(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ), ureg_src(tmp), ureg_imm1f(shader, invert ? -1.0f : 1.0f));
ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
 
ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
ureg_ENDIF(shader);
 
ureg_release_temporary(shader, tmp);
 
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, r->pipe);
}
 
static bool
init_pipe_state(struct vl_mc *r)
{
struct pipe_sampler_state sampler;
struct pipe_blend_state blend;
struct pipe_rasterizer_state rs_state;
unsigned i;
 
assert(r);
 
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_BORDER;
sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
sampler.compare_func = PIPE_FUNC_ALWAYS;
sampler.normalized_coords = 1;
r->sampler_ref = r->pipe->create_sampler_state(r->pipe, &sampler);
if (!r->sampler_ref)
goto error_sampler_ref;
 
for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) {
memset(&blend, 0, sizeof blend);
blend.independent_blend_enable = 0;
blend.rt[0].blend_enable = 1;
blend.rt[0].rgb_func = PIPE_BLEND_ADD;
blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
blend.rt[0].alpha_func = PIPE_BLEND_ADD;
blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
blend.logicop_enable = 0;
blend.logicop_func = PIPE_LOGICOP_CLEAR;
blend.rt[0].colormask = i;
blend.dither = 0;
r->blend_clear[i] = r->pipe->create_blend_state(r->pipe, &blend);
if (!r->blend_clear[i])
goto error_blend;
 
blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
r->blend_add[i] = r->pipe->create_blend_state(r->pipe, &blend);
if (!r->blend_add[i])
goto error_blend;
 
blend.rt[0].rgb_func = PIPE_BLEND_REVERSE_SUBTRACT;
blend.rt[0].alpha_dst_factor = PIPE_BLEND_REVERSE_SUBTRACT;
r->blend_sub[i] = r->pipe->create_blend_state(r->pipe, &blend);
if (!r->blend_sub[i])
goto error_blend;
}
 
memset(&rs_state, 0, sizeof(rs_state));
/*rs_state.sprite_coord_enable */
rs_state.sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT;
rs_state.point_quad_rasterization = true;
rs_state.point_size = VL_BLOCK_WIDTH;
rs_state.half_pixel_center = true;
rs_state.bottom_edge_rule = true;
rs_state.depth_clip = 1;
r->rs_state = r->pipe->create_rasterizer_state(r->pipe, &rs_state);
if (!r->rs_state)
goto error_rs_state;
 
return true;
 
error_rs_state:
error_blend:
for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) {
if (r->blend_sub[i])
r->pipe->delete_blend_state(r->pipe, r->blend_sub[i]);
 
if (r->blend_add[i])
r->pipe->delete_blend_state(r->pipe, r->blend_add[i]);
 
if (r->blend_clear[i])
r->pipe->delete_blend_state(r->pipe, r->blend_clear[i]);
}
 
r->pipe->delete_sampler_state(r->pipe, r->sampler_ref);
 
error_sampler_ref:
return false;
}
 
static void
cleanup_pipe_state(struct vl_mc *r)
{
unsigned i;
 
assert(r);
 
r->pipe->delete_sampler_state(r->pipe, r->sampler_ref);
for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) {
r->pipe->delete_blend_state(r->pipe, r->blend_clear[i]);
r->pipe->delete_blend_state(r->pipe, r->blend_add[i]);
r->pipe->delete_blend_state(r->pipe, r->blend_sub[i]);
}
r->pipe->delete_rasterizer_state(r->pipe, r->rs_state);
}
 
bool
vl_mc_init(struct vl_mc *renderer, struct pipe_context *pipe,
unsigned buffer_width, unsigned buffer_height,
unsigned macroblock_size, float scale,
vl_mc_ycbcr_vert_shader vs_callback,
vl_mc_ycbcr_frag_shader fs_callback,
void *callback_priv)
{
assert(renderer);
assert(pipe);
 
memset(renderer, 0, sizeof(struct vl_mc));
 
renderer->pipe = pipe;
renderer->buffer_width = buffer_width;
renderer->buffer_height = buffer_height;
renderer->macroblock_size = macroblock_size;
 
if (!init_pipe_state(renderer))
goto error_pipe_state;
 
renderer->vs_ref = create_ref_vert_shader(renderer);
if (!renderer->vs_ref)
goto error_vs_ref;
 
renderer->vs_ycbcr = create_ycbcr_vert_shader(renderer, vs_callback, callback_priv);
if (!renderer->vs_ycbcr)
goto error_vs_ycbcr;
 
renderer->fs_ref = create_ref_frag_shader(renderer);
if (!renderer->fs_ref)
goto error_fs_ref;
 
renderer->fs_ycbcr = create_ycbcr_frag_shader(renderer, scale, false, fs_callback, callback_priv);
if (!renderer->fs_ycbcr)
goto error_fs_ycbcr;
 
renderer->fs_ycbcr_sub = create_ycbcr_frag_shader(renderer, scale, true, fs_callback, callback_priv);
if (!renderer->fs_ycbcr_sub)
goto error_fs_ycbcr_sub;
 
return true;
error_fs_ycbcr_sub:
renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr);
 
error_fs_ycbcr:
renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ref);
 
error_fs_ref:
renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ycbcr);
 
error_vs_ycbcr:
renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ref);
 
error_vs_ref:
cleanup_pipe_state(renderer);
 
error_pipe_state:
return false;
}
 
void
vl_mc_cleanup(struct vl_mc *renderer)
{
assert(renderer);
 
cleanup_pipe_state(renderer);
 
renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ref);
renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ycbcr);
renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ref);
renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr);
renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr_sub);
}
 
bool
vl_mc_init_buffer(struct vl_mc *renderer, struct vl_mc_buffer *buffer)
{
assert(renderer && buffer);
 
buffer->viewport.scale[2] = 1;
buffer->viewport.scale[3] = 1;
buffer->viewport.translate[0] = 0;
buffer->viewport.translate[1] = 0;
buffer->viewport.translate[2] = 0;
buffer->viewport.translate[3] = 0;
 
buffer->fb_state.nr_cbufs = 1;
buffer->fb_state.zsbuf = NULL;
 
return true;
}
 
void
vl_mc_cleanup_buffer(struct vl_mc_buffer *buffer)
{
assert(buffer);
}
 
void
vl_mc_set_surface(struct vl_mc_buffer *buffer, struct pipe_surface *surface)
{
assert(buffer && surface);
 
buffer->surface_cleared = false;
 
buffer->viewport.scale[0] = surface->width;
buffer->viewport.scale[1] = surface->height;
 
buffer->fb_state.width = surface->width;
buffer->fb_state.height = surface->height;
buffer->fb_state.cbufs[0] = surface;
}
 
static void
prepare_pipe_4_rendering(struct vl_mc *renderer, struct vl_mc_buffer *buffer, unsigned mask)
{
assert(buffer);
 
renderer->pipe->bind_rasterizer_state(renderer->pipe, renderer->rs_state);
 
if (buffer->surface_cleared)
renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_add[mask]);
else
renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_clear[mask]);
 
renderer->pipe->set_framebuffer_state(renderer->pipe, &buffer->fb_state);
renderer->pipe->set_viewport_states(renderer->pipe, 0, 1, &buffer->viewport);
}
 
void
vl_mc_render_ref(struct vl_mc *renderer, struct vl_mc_buffer *buffer, struct pipe_sampler_view *ref)
{
assert(buffer && ref);
 
prepare_pipe_4_rendering(renderer, buffer, PIPE_MASK_R | PIPE_MASK_G | PIPE_MASK_B);
 
renderer->pipe->bind_vs_state(renderer->pipe, renderer->vs_ref);
renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ref);
 
renderer->pipe->set_fragment_sampler_views(renderer->pipe, 1, &ref);
renderer->pipe->bind_fragment_sampler_states(renderer->pipe, 1, &renderer->sampler_ref);
 
util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0,
renderer->buffer_width / VL_MACROBLOCK_WIDTH *
renderer->buffer_height / VL_MACROBLOCK_HEIGHT);
 
buffer->surface_cleared = true;
}
 
void
vl_mc_render_ycbcr(struct vl_mc *renderer, struct vl_mc_buffer *buffer, unsigned component, unsigned num_instances)
{
unsigned mask = 1 << component;
 
assert(buffer);
 
if (num_instances == 0)
return;
 
prepare_pipe_4_rendering(renderer, buffer, mask);
 
renderer->pipe->bind_vs_state(renderer->pipe, renderer->vs_ycbcr);
renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ycbcr);
 
util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances);
if (buffer->surface_cleared) {
renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_sub[mask]);
renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ycbcr_sub);
util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances);
}
}
/drivers/video/Gallium/auxiliary/vl/vl_mc.h
0,0 → 1,97
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* 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.
*
**************************************************************************/
 
#ifndef vl_mc_h
#define vl_mc_h
 
#include "pipe/p_state.h"
#include "pipe/p_video_state.h"
 
#include "tgsi/tgsi_ureg.h"
 
#include "vl_defines.h"
#include "vl_types.h"
 
#define VL_MC_NUM_BLENDERS (1 << VL_NUM_COMPONENTS)
 
struct pipe_context;
 
struct vl_mc
{
struct pipe_context *pipe;
unsigned buffer_width;
unsigned buffer_height;
unsigned macroblock_size;
 
void *rs_state;
 
void *blend_clear[VL_MC_NUM_BLENDERS];
void *blend_add[VL_MC_NUM_BLENDERS];
void *blend_sub[VL_MC_NUM_BLENDERS];
void *vs_ref, *vs_ycbcr;
void *fs_ref, *fs_ycbcr, *fs_ycbcr_sub;
void *sampler_ref;
};
 
struct vl_mc_buffer
{
bool surface_cleared;
 
struct pipe_viewport_state viewport;
struct pipe_framebuffer_state fb_state;
};
 
typedef void (*vl_mc_ycbcr_vert_shader)(void *priv, struct vl_mc *mc,
struct ureg_program *shader,
unsigned first_output,
struct ureg_dst tex);
 
typedef void (*vl_mc_ycbcr_frag_shader)(void *priv, struct vl_mc *mc,
struct ureg_program *shader,
unsigned first_input,
struct ureg_dst dst);
 
bool vl_mc_init(struct vl_mc *renderer, struct pipe_context *pipe,
unsigned picture_width, unsigned picture_height,
unsigned macroblock_size, float scale,
vl_mc_ycbcr_vert_shader vs_callback,
vl_mc_ycbcr_frag_shader fs_callback,
void *callback_priv);
 
void vl_mc_cleanup(struct vl_mc *renderer);
 
bool vl_mc_init_buffer(struct vl_mc *renderer, struct vl_mc_buffer *buffer);
 
void vl_mc_cleanup_buffer(struct vl_mc_buffer *buffer);
 
void vl_mc_set_surface(struct vl_mc_buffer *buffer, struct pipe_surface *surface);
 
void vl_mc_render_ref(struct vl_mc *renderer, struct vl_mc_buffer *buffer, struct pipe_sampler_view *ref);
 
void vl_mc_render_ycbcr(struct vl_mc *renderer, struct vl_mc_buffer *buffer, unsigned component, unsigned num_instances);
 
#endif /* vl_mc_h */
/drivers/video/Gallium/auxiliary/vl/vl_median_filter.c
0,0 → 1,398
/**************************************************************************
*
* Copyright 2012 Christian König.
* 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.
*
**************************************************************************/
 
#include "pipe/p_context.h"
 
#include "tgsi/tgsi_ureg.h"
 
#include "util/u_draw.h"
#include "util/u_memory.h"
#include "util/u_math.h"
 
#include "vl_types.h"
#include "vl_vertex_buffers.h"
#include "vl_median_filter.h"
 
enum VS_OUTPUT
{
VS_O_VPOS = 0,
VS_O_VTEX = 0
};
 
static void *
create_vert_shader(struct vl_median_filter *filter)
{
struct ureg_program *shader;
struct ureg_src i_vpos;
struct ureg_dst o_vpos, o_vtex;
 
shader = ureg_create(TGSI_PROCESSOR_VERTEX);
if (!shader)
return NULL;
 
i_vpos = ureg_DECL_vs_input(shader, 0);
o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX);
 
ureg_MOV(shader, o_vpos, i_vpos);
ureg_MOV(shader, o_vtex, i_vpos);
 
ureg_END(shader);
 
return ureg_create_shader_and_destroy(shader, filter->pipe);
}
 
static inline bool
is_vec_zero(struct vertex2f v)
{
return v.x == 0.0f && v.y == 0.0f;
}
 
static void *
create_frag_shader(struct vl_median_filter *filter,
struct vertex2f *offsets,
unsigned num_offsets)
{
struct pipe_screen *screen = filter->pipe->screen;
struct ureg_program *shader;
struct ureg_src i_vtex;
struct ureg_src sampler;
struct ureg_dst *t_array = MALLOC(sizeof(struct ureg_dst) * num_offsets);
struct ureg_dst o_fragment;
const unsigned median = num_offsets >> 1;
int i, j;
 
assert(num_offsets & 1); /* we need an odd number of offsets */
if (!(num_offsets & 1)) { /* yeah, we REALLY need an odd number of offsets!!! */
FREE(t_array);
return NULL;
}
 
if (num_offsets > screen->get_shader_param(
screen, TGSI_PROCESSOR_FRAGMENT, PIPE_SHADER_CAP_MAX_TEMPS)) {
 
FREE(t_array);
return NULL;
}
 
shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
if (!shader) {
FREE(t_array);
return NULL;
}
 
i_vtex = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX, TGSI_INTERPOLATE_LINEAR);
sampler = ureg_DECL_sampler(shader, 0);
 
for (i = 0; i < num_offsets; ++i)
t_array[i] = ureg_DECL_temporary(shader);
o_fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
 
/*
* t_array[0..*] = vtex + offset[0..*]
* t_array[0..*] = tex(t_array[0..*], sampler)
* result = partial_bubblesort(t_array)[mid]
*/
 
for (i = 0; i < num_offsets; ++i) {
if (!is_vec_zero(offsets[i])) {
ureg_ADD(shader, ureg_writemask(t_array[i], TGSI_WRITEMASK_XY),
i_vtex, ureg_imm2f(shader, offsets[i].x, offsets[i].y));
ureg_MOV(shader, ureg_writemask(t_array[i], TGSI_WRITEMASK_ZW),
ureg_imm1f(shader, 0.0f));
}
}
 
for (i = 0; i < num_offsets; ++i) {
struct ureg_src src = is_vec_zero(offsets[i]) ? i_vtex : ureg_src(t_array[i]);
ureg_TEX(shader, t_array[i], TGSI_TEXTURE_2D, src, sampler);
}
 
// TODO: Couldn't this be improved even more?
for (i = 0; i <= median; ++i) {
for (j = 1; j < (num_offsets - i - 1); ++j) {
struct ureg_dst tmp = ureg_DECL_temporary(shader);
ureg_MOV(shader, tmp, ureg_src(t_array[j]));
ureg_MAX(shader, t_array[j], ureg_src(t_array[j]), ureg_src(t_array[j - 1]));
ureg_MIN(shader, t_array[j - 1], ureg_src(tmp), ureg_src(t_array[j - 1]));
ureg_release_temporary(shader, tmp);
}
if (i == median)
ureg_MAX(shader, t_array[j], ureg_src(t_array[j]), ureg_src(t_array[j - 1]));
else
ureg_MIN(shader, t_array[j - 1], ureg_src(t_array[j]), ureg_src(t_array[j - 1]));
}
ureg_MOV(shader, o_fragment, ureg_src(t_array[median]));
 
ureg_END(shader);
 
FREE(t_array);
return ureg_create_shader_and_destroy(shader, filter->pipe);
}
 
static void
generate_offsets(enum vl_median_filter_shape shape, unsigned size,
struct vertex2f **offsets, unsigned *num_offsets)
{
int i = 0, half_size;
struct vertex2f v;
 
assert(offsets && num_offsets);
 
/* size needs to be odd */
size = align(size + 1, 2) - 1;
half_size = size >> 1;
 
switch(shape) {
case VL_MEDIAN_FILTER_BOX:
*num_offsets = size*size;
break;
 
case VL_MEDIAN_FILTER_CROSS:
case VL_MEDIAN_FILTER_X:
*num_offsets = size + size - 1;
break;
 
case VL_MEDIAN_FILTER_HORIZONTAL:
case VL_MEDIAN_FILTER_VERTICAL:
*num_offsets = size;
break;
 
default:
*num_offsets = 0;
return;
}
 
*offsets = MALLOC(sizeof(struct vertex2f) * *num_offsets);
if (!*offsets)
return;
 
switch(shape) {
case VL_MEDIAN_FILTER_BOX:
for (v.x = -half_size; v.x <= half_size; ++v.x)
for (v.y = -half_size; v.y <= half_size; ++v.y)
(*offsets)[i++] = v;
break;
 
case VL_MEDIAN_FILTER_CROSS:
v.y = 0.0f;
for (v.x = -half_size; v.x <= half_size; ++v.x)
(*offsets)[i++] = v;
 
v.x = 0.0f;
for (v.y = -half_size; v.y <= half_size; ++v.y)
if (v.y != 0.0f)
(*offsets)[i++] = v;
break;
 
case VL_MEDIAN_FILTER_X:
for (v.x = v.y = -half_size; v.x <= half_size; ++v.x, ++v.y)
(*offsets)[i++] = v;
 
for (v.x = -half_size, v.y = half_size; v.x <= half_size; ++v.x, --v.y)
if (v.y != 0.0f)
(*offsets)[i++] = v;
break;
 
case VL_MEDIAN_FILTER_HORIZONTAL:
v.y = 0.0f;
for (v.x = -half_size; v.x <= half_size; ++v.x)
(*offsets)[i++] = v;
break;
 
case VL_MEDIAN_FILTER_VERTICAL:
v.x = 0.0f;
for (v.y = -half_size; v.y <= half_size; ++v.y)
(*offsets)[i++] = v;
break;
}
 
assert(i == *num_offsets);
}
 
bool
vl_median_filter_init(struct vl_median_filter *filter, struct pipe_context *pipe,
unsigned width, unsigned height, unsigned size,
enum vl_median_filter_shape shape)
{
struct pipe_rasterizer_state rs_state;
struct pipe_blend_state blend;
struct pipe_sampler_state sampler;
struct vertex2f *offsets = NULL;
struct pipe_vertex_element ve;
unsigned i, num_offsets = 0;
 
assert(filter && pipe);
assert(width && height);
assert(size > 1 && size < 20);
 
memset(filter, 0, sizeof(*filter));
filter->pipe = pipe;
 
memset(&rs_state, 0, sizeof(rs_state));
rs_state.half_pixel_center = true;
rs_state.bottom_edge_rule = true;
rs_state.depth_clip = 1;
filter->rs_state = pipe->create_rasterizer_state(pipe, &rs_state);
if (!filter->rs_state)
goto error_rs_state;
 
memset(&blend, 0, sizeof blend);
blend.rt[0].rgb_func = PIPE_BLEND_ADD;
blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].alpha_func = PIPE_BLEND_ADD;
blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
blend.logicop_func = PIPE_LOGICOP_CLEAR;
blend.rt[0].colormask = PIPE_MASK_RGBA;
filter->blend = pipe->create_blend_state(pipe, &blend);
if (!filter->blend)
goto error_blend;
 
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_img_filter = PIPE_TEX_FILTER_NEAREST;
sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
sampler.compare_func = PIPE_FUNC_ALWAYS;
sampler.normalized_coords = 1;
filter->sampler = pipe->create_sampler_state(pipe, &sampler);
if (!filter->sampler)
goto error_sampler;
 
filter->quad = vl_vb_upload_quads(pipe);
if(!filter->quad.buffer)
goto error_quad;
 
memset(&ve, 0, sizeof(ve));
ve.src_offset = 0;
ve.instance_divisor = 0;
ve.vertex_buffer_index = 0;
ve.src_format = PIPE_FORMAT_R32G32_FLOAT;
filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve);
if (!filter->ves)
goto error_ves;
 
generate_offsets(shape, size, &offsets, &num_offsets);
if (!offsets)
goto error_offsets;
 
for (i = 0; i < num_offsets; ++i) {
offsets[i].x /= width;
offsets[i].y /= height;
}
 
filter->vs = create_vert_shader(filter);
if (!filter->vs)
goto error_vs;
 
filter->fs = create_frag_shader(filter, offsets, num_offsets);
if (!filter->fs)
goto error_fs;
 
FREE(offsets);
return true;
 
error_fs:
pipe->delete_vs_state(pipe, filter->vs);
 
error_vs:
FREE(offsets);
 
error_offsets:
pipe->delete_vertex_elements_state(pipe, filter->ves);
 
error_ves:
pipe_resource_reference(&filter->quad.buffer, NULL);
 
error_quad:
pipe->delete_sampler_state(pipe, filter->sampler);
 
error_sampler:
pipe->delete_blend_state(pipe, filter->blend);
 
error_blend:
pipe->delete_rasterizer_state(pipe, filter->rs_state);
 
error_rs_state:
return false;
}
 
void
vl_median_filter_cleanup(struct vl_median_filter *filter)
{
assert(filter);
 
filter->pipe->delete_sampler_state(filter->pipe, filter->sampler);
filter->pipe->delete_blend_state(filter->pipe, filter->blend);
filter->pipe->delete_rasterizer_state(filter->pipe, filter->rs_state);
filter->pipe->delete_vertex_elements_state(filter->pipe, filter->ves);
pipe_resource_reference(&filter->quad.buffer, NULL);
 
filter->pipe->delete_vs_state(filter->pipe, filter->vs);
filter->pipe->delete_fs_state(filter->pipe, filter->fs);
}
 
void
vl_median_filter_render(struct vl_median_filter *filter,
struct pipe_sampler_view *src,
struct pipe_surface *dst)
{
struct pipe_viewport_state viewport;
struct pipe_framebuffer_state fb_state;
 
assert(filter && src && dst);
 
memset(&viewport, 0, sizeof(viewport));
viewport.scale[0] = dst->width;
viewport.scale[1] = dst->height;
viewport.scale[2] = 1;
viewport.scale[3] = 1;
 
memset(&fb_state, 0, sizeof(fb_state));
fb_state.width = dst->width;
fb_state.height = dst->height;
fb_state.nr_cbufs = 1;
fb_state.cbufs[0] = dst;
 
filter->pipe->bind_rasterizer_state(filter->pipe, filter->rs_state);
filter->pipe->bind_blend_state(filter->pipe, filter->blend);
filter->pipe->bind_fragment_sampler_states(filter->pipe, 1, &filter->sampler);
filter->pipe->set_fragment_sampler_views(filter->pipe, 1, &src);
filter->pipe->bind_vs_state(filter->pipe, filter->vs);
filter->pipe->bind_fs_state(filter->pipe, filter->fs);
filter->pipe->set_framebuffer_state(filter->pipe, &fb_state);
filter->pipe->set_viewport_states(filter->pipe, 0, 1, &viewport);
filter->pipe->set_vertex_buffers(filter->pipe, 0, 1, &filter->quad);
filter->pipe->bind_vertex_elements_state(filter->pipe, filter->ves);
 
util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
}
/drivers/video/Gallium/auxiliary/vl/vl_median_filter.h
0,0 → 1,70
/**************************************************************************
*
* Copyright 2012 Christian König.
* 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.
*
**************************************************************************/
 
/* implementation of a median filter for noise reduction */
 
#ifndef vl_median_filter_h
#define vl_median_filter_h
 
#include "pipe/p_state.h"
 
enum vl_median_filter_shape
{
VL_MEDIAN_FILTER_BOX,
VL_MEDIAN_FILTER_CROSS,
VL_MEDIAN_FILTER_X,
VL_MEDIAN_FILTER_HORIZONTAL,
VL_MEDIAN_FILTER_VERTICAL
};
 
struct vl_median_filter
{
struct pipe_context *pipe;
struct pipe_vertex_buffer quad;
 
void *rs_state;
void *blend;
void *sampler;
void *ves;
void *vs, *fs;
};
 
bool
vl_median_filter_init(struct vl_median_filter *filter, struct pipe_context *pipe,
unsigned width, unsigned height, unsigned size,
enum vl_median_filter_shape shape);
 
void
vl_median_filter_cleanup(struct vl_median_filter *filter);
 
 
void
vl_median_filter_render(struct vl_median_filter *filter,
struct pipe_sampler_view *src,
struct pipe_surface *dst);
 
#endif /* vl_median_filter_h */
/drivers/video/Gallium/auxiliary/vl/vl_mpeg12_bitstream.c
0,0 → 1,1014
/**************************************************************************
*
* Copyright 2011 Maarten Lankhorst
* Copyright 2011 Christian König
* 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.
*
**************************************************************************/
 
#include "pipe/p_video_decoder.h"
#include "util/u_memory.h"
 
#include "vl_vlc.h"
#include "vl_mpeg12_bitstream.h"
 
enum {
dct_End_of_Block = 0xFF,
dct_Escape = 0xFE,
dct_DC = 0xFD,
dct_AC = 0xFC
};
 
struct dct_coeff
{
uint8_t length;
uint8_t run;
int16_t level;
};
 
struct dct_coeff_compressed
{
uint32_t bitcode;
struct dct_coeff coeff;
};
 
/* coding table as found in the spec annex B.5 table B-1 */
static const struct vl_vlc_compressed macroblock_address_increment[] = {
{ 0x8000, { 1, 1 } },
{ 0x6000, { 3, 2 } },
{ 0x4000, { 3, 3 } },
{ 0x3000, { 4, 4 } },
{ 0x2000, { 4, 5 } },
{ 0x1800, { 5, 6 } },
{ 0x1000, { 5, 7 } },
{ 0x0e00, { 7, 8 } },
{ 0x0c00, { 7, 9 } },
{ 0x0b00, { 8, 10 } },
{ 0x0a00, { 8, 11 } },
{ 0x0900, { 8, 12 } },
{ 0x0800, { 8, 13 } },
{ 0x0700, { 8, 14 } },
{ 0x0600, { 8, 15 } },
{ 0x05c0, { 10, 16 } },
{ 0x0580, { 10, 17 } },
{ 0x0540, { 10, 18 } },
{ 0x0500, { 10, 19 } },
{ 0x04c0, { 10, 20 } },
{ 0x0480, { 10, 21 } },
{ 0x0460, { 11, 22 } },
{ 0x0440, { 11, 23 } },
{ 0x0420, { 11, 24 } },
{ 0x0400, { 11, 25 } },
{ 0x03e0, { 11, 26 } },
{ 0x03c0, { 11, 27 } },
{ 0x03a0, { 11, 28 } },
{ 0x0380, { 11, 29 } },
{ 0x0360, { 11, 30 } },
{ 0x0340, { 11, 31 } },
{ 0x0320, { 11, 32 } },
{ 0x0300, { 11, 33 } }
};
 
#define Q PIPE_MPEG12_MB_TYPE_QUANT
#define F PIPE_MPEG12_MB_TYPE_MOTION_FORWARD
#define B PIPE_MPEG12_MB_TYPE_MOTION_BACKWARD
#define P PIPE_MPEG12_MB_TYPE_PATTERN
#define I PIPE_MPEG12_MB_TYPE_INTRA
 
/* coding table as found in the spec annex B.5 table B-2 */
static const struct vl_vlc_compressed macroblock_type_i[] = {
{ 0x8000, { 1, I } },
{ 0x4000, { 2, Q|I } }
};
 
/* coding table as found in the spec annex B.5 table B-3 */
static const struct vl_vlc_compressed macroblock_type_p[] = {
{ 0x8000, { 1, F|P } },
{ 0x4000, { 2, P } },
{ 0x2000, { 3, F } },
{ 0x1800, { 5, I } },
{ 0x1000, { 5, Q|F|P } },
{ 0x0800, { 5, Q|P } },
{ 0x0400, { 6, Q|I } }
};
 
/* coding table as found in the spec annex B.5 table B-4 */
static const struct vl_vlc_compressed macroblock_type_b[] = {
{ 0x8000, { 2, F|B } },
{ 0xC000, { 2, F|B|P } },
{ 0x4000, { 3, B } },
{ 0x6000, { 3, B|P } },
{ 0x2000, { 4, F } },
{ 0x3000, { 4, F|P } },
{ 0x1800, { 5, I } },
{ 0x1000, { 5, Q|F|B|P } },
{ 0x0C00, { 6, Q|F|P } },
{ 0x0800, { 6, Q|B|P } },
{ 0x0400, { 6, Q|I } }
};
 
#undef Q
#undef F
#undef B
#undef P
#undef I
 
/* coding table as found in the spec annex B.5 table B-9 */
static const struct vl_vlc_compressed coded_block_pattern[] = {
{ 0xE000, { 3, 60 } },
{ 0xD000, { 4, 4 } },
{ 0xC000, { 4, 8 } },
{ 0xB000, { 4, 16 } },
{ 0xA000, { 4, 32 } },
{ 0x9800, { 5, 12 } },
{ 0x9000, { 5, 48 } },
{ 0x8800, { 5, 20 } },
{ 0x8000, { 5, 40 } },
{ 0x7800, { 5, 28 } },
{ 0x7000, { 5, 44 } },
{ 0x6800, { 5, 52 } },
{ 0x6000, { 5, 56 } },
{ 0x5800, { 5, 1 } },
{ 0x5000, { 5, 61 } },
{ 0x4800, { 5, 2 } },
{ 0x4000, { 5, 62 } },
{ 0x3C00, { 6, 24 } },
{ 0x3800, { 6, 36 } },
{ 0x3400, { 6, 3 } },
{ 0x3000, { 6, 63 } },
{ 0x2E00, { 7, 5 } },
{ 0x2C00, { 7, 9 } },
{ 0x2A00, { 7, 17 } },
{ 0x2800, { 7, 33 } },
{ 0x2600, { 7, 6 } },
{ 0x2400, { 7, 10 } },
{ 0x2200, { 7, 18 } },
{ 0x2000, { 7, 34 } },
{ 0x1F00, { 8, 7 } },
{ 0x1E00, { 8, 11 } },
{ 0x1D00, { 8, 19 } },
{ 0x1C00, { 8, 35 } },
{ 0x1B00, { 8, 13 } },
{ 0x1A00, { 8, 49 } },
{ 0x1900, { 8, 21 } },
{ 0x1800, { 8, 41 } },
{ 0x1700, { 8, 14 } },
{ 0x1600, { 8, 50 } },
{ 0x1500, { 8, 22 } },
{ 0x1400, { 8, 42 } },
{ 0x1300, { 8, 15 } },
{ 0x1200, { 8, 51 } },
{ 0x1100, { 8, 23 } },
{ 0x1000, { 8, 43 } },
{ 0x0F00, { 8, 25 } },
{ 0x0E00, { 8, 37 } },
{ 0x0D00, { 8, 26 } },
{ 0x0C00, { 8, 38 } },
{ 0x0B00, { 8, 29 } },
{ 0x0A00, { 8, 45 } },
{ 0x0900, { 8, 53 } },
{ 0x0800, { 8, 57 } },
{ 0x0700, { 8, 30 } },
{ 0x0600, { 8, 46 } },
{ 0x0500, { 8, 54 } },
{ 0x0400, { 8, 58 } },
{ 0x0380, { 9, 31 } },
{ 0x0300, { 9, 47 } },
{ 0x0280, { 9, 55 } },
{ 0x0200, { 9, 59 } },
{ 0x0180, { 9, 27 } },
{ 0x0100, { 9, 39 } },
{ 0x0080, { 9, 0 } }
};
 
/* coding table as found in the spec annex B.5 table B-10 */
static const struct vl_vlc_compressed motion_code[] = {
{ 0x0320, { 11, -16 } },
{ 0x0360, { 11, -15 } },
{ 0x03a0, { 11, -14 } },
{ 0x03e0, { 11, -13 } },
{ 0x0420, { 11, -12 } },
{ 0x0460, { 11, -11 } },
{ 0x04c0, { 10, -10 } },
{ 0x0540, { 10, -9 } },
{ 0x05c0, { 10, -8 } },
{ 0x0700, { 8, -7 } },
{ 0x0900, { 8, -6 } },
{ 0x0b00, { 8, -5 } },
{ 0x0e00, { 7, -4 } },
{ 0x1800, { 5, -3 } },
{ 0x3000, { 4, -2 } },
{ 0x6000, { 3, -1 } },
{ 0x8000, { 1, 0 } },
{ 0x4000, { 3, 1 } },
{ 0x2000, { 4, 2 } },
{ 0x1000, { 5, 3 } },
{ 0x0c00, { 7, 4 } },
{ 0x0a00, { 8, 5 } },
{ 0x0800, { 8, 6 } },
{ 0x0600, { 8, 7 } },
{ 0x0580, { 10, 8 } },
{ 0x0500, { 10, 9 } },
{ 0x0480, { 10, 10 } },
{ 0x0440, { 11, 11 } },
{ 0x0400, { 11, 12 } },
{ 0x03c0, { 11, 13 } },
{ 0x0380, { 11, 14 } },
{ 0x0340, { 11, 15 } },
{ 0x0300, { 11, 16 } }
};
 
/* coding table as found in the spec annex B.5 table B-11 */
static const struct vl_vlc_compressed dmvector[] = {
{ 0x0000, { 1, 0 } },
{ 0x8000, { 2, 1 } },
{ 0xc000, { 2, -1 } }
};
 
/* coding table as found in the spec annex B.5 table B-12 */
static const struct vl_vlc_compressed dct_dc_size_luminance[] = {
{ 0x8000, { 3, 0 } },
{ 0x0000, { 2, 1 } },
{ 0x4000, { 2, 2 } },
{ 0xA000, { 3, 3 } },
{ 0xC000, { 3, 4 } },
{ 0xE000, { 4, 5 } },
{ 0xF000, { 5, 6 } },
{ 0xF800, { 6, 7 } },
{ 0xFC00, { 7, 8 } },
{ 0xFE00, { 8, 9 } },
{ 0xFF00, { 9, 10 } },
{ 0xFF80, { 9, 11 } }
};
 
/* coding table as found in the spec annex B.5 table B-13 */
static const struct vl_vlc_compressed dct_dc_size_chrominance[] = {
{ 0x0000, { 2, 0 } },
{ 0x4000, { 2, 1 } },
{ 0x8000, { 2, 2 } },
{ 0xC000, { 3, 3 } },
{ 0xE000, { 4, 4 } },
{ 0xF000, { 5, 5 } },
{ 0xF800, { 6, 6 } },
{ 0xFC00, { 7, 7 } },
{ 0xFE00, { 8, 8 } },
{ 0xFF00, { 9, 9 } },
{ 0xFF80, { 10, 10 } },
{ 0xFFC0, { 10, 11 } }
};
 
/* coding table as found in the spec annex B.5 table B-14 */
static const struct dct_coeff_compressed dct_coeff_tbl_zero[] = {
{ 0x8000, { 2, dct_End_of_Block, 0 } },
{ 0x8000, { 1, dct_DC, 1 } },
{ 0xC000, { 2, dct_AC, 1 } },
{ 0x6000, { 3, 1, 1 } },
{ 0x4000, { 4, 0, 2 } },
{ 0x5000, { 4, 2, 1 } },
{ 0x2800, { 5, 0, 3 } },
{ 0x3800, { 5, 3, 1 } },
{ 0x3000, { 5, 4, 1 } },
{ 0x1800, { 6, 1, 2 } },
{ 0x1C00, { 6, 5, 1 } },
{ 0x1400, { 6, 6, 1 } },
{ 0x1000, { 6, 7, 1 } },
{ 0x0C00, { 7, 0, 4 } },
{ 0x0800, { 7, 2, 2 } },
{ 0x0E00, { 7, 8, 1 } },
{ 0x0A00, { 7, 9, 1 } },
{ 0x0400, { 6, dct_Escape, 0 } },
{ 0x2600, { 8, 0, 5 } },
{ 0x2100, { 8, 0, 6 } },
{ 0x2500, { 8, 1, 3 } },
{ 0x2400, { 8, 3, 2 } },
{ 0x2700, { 8, 10, 1 } },
{ 0x2300, { 8, 11, 1 } },
{ 0x2200, { 8, 12, 1 } },
{ 0x2000, { 8, 13, 1 } },
{ 0x0280, { 10, 0, 7 } },
{ 0x0300, { 10, 1, 4 } },
{ 0x02C0, { 10, 2, 3 } },
{ 0x03C0, { 10, 4, 2 } },
{ 0x0240, { 10, 5, 2 } },
{ 0x0380, { 10, 14, 1 } },
{ 0x0340, { 10, 15, 1 } },
{ 0x0200, { 10, 16, 1 } },
{ 0x01D0, { 12, 0, 8 } },
{ 0x0180, { 12, 0, 9 } },
{ 0x0130, { 12, 0, 10 } },
{ 0x0100, { 12, 0, 11 } },
{ 0x01B0, { 12, 1, 5 } },
{ 0x0140, { 12, 2, 4 } },
{ 0x01C0, { 12, 3, 3 } },
{ 0x0120, { 12, 4, 3 } },
{ 0x01E0, { 12, 6, 2 } },
{ 0x0150, { 12, 7, 2 } },
{ 0x0110, { 12, 8, 2 } },
{ 0x01F0, { 12, 17, 1 } },
{ 0x01A0, { 12, 18, 1 } },
{ 0x0190, { 12, 19, 1 } },
{ 0x0170, { 12, 20, 1 } },
{ 0x0160, { 12, 21, 1 } },
{ 0x00D0, { 13, 0, 12 } },
{ 0x00C8, { 13, 0, 13 } },
{ 0x00C0, { 13, 0, 14 } },
{ 0x00B8, { 13, 0, 15 } },
{ 0x00B0, { 13, 1, 6 } },
{ 0x00A8, { 13, 1, 7 } },
{ 0x00A0, { 13, 2, 5 } },
{ 0x0098, { 13, 3, 4 } },
{ 0x0090, { 13, 5, 3 } },
{ 0x0088, { 13, 9, 2 } },
{ 0x0080, { 13, 10, 2 } },
{ 0x00F8, { 13, 22, 1 } },
{ 0x00F0, { 13, 23, 1 } },
{ 0x00E8, { 13, 24, 1 } },
{ 0x00E0, { 13, 25, 1 } },
{ 0x00D8, { 13, 26, 1 } },
{ 0x007C, { 14, 0, 16 } },
{ 0x0078, { 14, 0, 17 } },
{ 0x0074, { 14, 0, 18 } },
{ 0x0070, { 14, 0, 19 } },
{ 0x006C, { 14, 0, 20 } },
{ 0x0068, { 14, 0, 21 } },
{ 0x0064, { 14, 0, 22 } },
{ 0x0060, { 14, 0, 23 } },
{ 0x005C, { 14, 0, 24 } },
{ 0x0058, { 14, 0, 25 } },
{ 0x0054, { 14, 0, 26 } },
{ 0x0050, { 14, 0, 27 } },
{ 0x004C, { 14, 0, 28 } },
{ 0x0048, { 14, 0, 29 } },
{ 0x0044, { 14, 0, 30 } },
{ 0x0040, { 14, 0, 31 } },
{ 0x0030, { 15, 0, 32 } },
{ 0x002E, { 15, 0, 33 } },
{ 0x002C, { 15, 0, 34 } },
{ 0x002A, { 15, 0, 35 } },
{ 0x0028, { 15, 0, 36 } },
{ 0x0026, { 15, 0, 37 } },
{ 0x0024, { 15, 0, 38 } },
{ 0x0022, { 15, 0, 39 } },
{ 0x0020, { 15, 0, 40 } },
{ 0x003E, { 15, 1, 8 } },
{ 0x003C, { 15, 1, 9 } },
{ 0x003A, { 15, 1, 10 } },
{ 0x0038, { 15, 1, 11 } },
{ 0x0036, { 15, 1, 12 } },
{ 0x0034, { 15, 1, 13 } },
{ 0x0032, { 15, 1, 14 } },
{ 0x0013, { 16, 1, 15 } },
{ 0x0012, { 16, 1, 16 } },
{ 0x0011, { 16, 1, 17 } },
{ 0x0010, { 16, 1, 18 } },
{ 0x0014, { 16, 6, 3 } },
{ 0x001A, { 16, 11, 2 } },
{ 0x0019, { 16, 12, 2 } },
{ 0x0018, { 16, 13, 2 } },
{ 0x0017, { 16, 14, 2 } },
{ 0x0016, { 16, 15, 2 } },
{ 0x0015, { 16, 16, 2 } },
{ 0x001F, { 16, 27, 1 } },
{ 0x001E, { 16, 28, 1 } },
{ 0x001D, { 16, 29, 1 } },
{ 0x001C, { 16, 30, 1 } },
{ 0x001B, { 16, 31, 1 } }
};
 
/* coding table as found in the spec annex B.5 table B-15 */
static const struct dct_coeff_compressed dct_coeff_tbl_one[] = {
{ 0x6000, { 4, dct_End_of_Block, 0 } },
{ 0x8000, { 2, 0, 1 } },
{ 0x4000, { 3, 1, 1 } },
{ 0xC000, { 3, 0, 2 } },
{ 0x2800, { 5, 2, 1 } },
{ 0x7000, { 4, 0, 3 } },
{ 0x3800, { 5, 3, 1 } },
{ 0x1800, { 6, 4, 1 } },
{ 0x3000, { 5, 1, 2 } },
{ 0x1C00, { 6, 5, 1 } },
{ 0x0C00, { 7, 6, 1 } },
{ 0x0800, { 7, 7, 1 } },
{ 0xE000, { 5, 0, 4 } },
{ 0x0E00, { 7, 2, 2 } },
{ 0x0A00, { 7, 8, 1 } },
{ 0xF000, { 7, 9, 1 } },
{ 0x0400, { 6, dct_Escape, 0 } },
{ 0xE800, { 5, 0, 5 } },
{ 0x1400, { 6, 0, 6 } },
{ 0xF200, { 7, 1, 3 } },
{ 0x2600, { 8, 3, 2 } },
{ 0xF400, { 7, 10, 1 } },
{ 0x2100, { 8, 11, 1 } },
{ 0x2500, { 8, 12, 1 } },
{ 0x2400, { 8, 13, 1 } },
{ 0x1000, { 6, 0, 7 } },
{ 0x2700, { 8, 1, 4 } },
{ 0xFC00, { 8, 2, 3 } },
{ 0xFD00, { 8, 4, 2 } },
{ 0x0200, { 9, 5, 2 } },
{ 0x0280, { 9, 14, 1 } },
{ 0x0380, { 9, 15, 1 } },
{ 0x0340, { 10, 16, 1 } },
{ 0xF600, { 7, 0, 8 } },
{ 0xF800, { 7, 0, 9 } },
{ 0x2300, { 8, 0, 10 } },
{ 0x2200, { 8, 0, 11 } },
{ 0x2000, { 8, 1, 5 } },
{ 0x0300, { 10, 2, 4 } },
{ 0x01C0, { 12, 3, 3 } },
{ 0x0120, { 12, 4, 3 } },
{ 0x01E0, { 12, 6, 2 } },
{ 0x0150, { 12, 7, 2 } },
{ 0x0110, { 12, 8, 2 } },
{ 0x01F0, { 12, 17, 1 } },
{ 0x01A0, { 12, 18, 1 } },
{ 0x0190, { 12, 19, 1 } },
{ 0x0170, { 12, 20, 1 } },
{ 0x0160, { 12, 21, 1 } },
{ 0xFA00, { 8, 0, 12 } },
{ 0xFB00, { 8, 0, 13 } },
{ 0xFE00, { 8, 0, 14 } },
{ 0xFF00, { 8, 0, 15 } },
{ 0x00B0, { 13, 1, 6 } },
{ 0x00A8, { 13, 1, 7 } },
{ 0x00A0, { 13, 2, 5 } },
{ 0x0098, { 13, 3, 4 } },
{ 0x0090, { 13, 5, 3 } },
{ 0x0088, { 13, 9, 2 } },
{ 0x0080, { 13, 10, 2 } },
{ 0x00F8, { 13, 22, 1 } },
{ 0x00F0, { 13, 23, 1 } },
{ 0x00E8, { 13, 24, 1 } },
{ 0x00E0, { 13, 25, 1 } },
{ 0x00D8, { 13, 26, 1 } },
{ 0x007C, { 14, 0, 16 } },
{ 0x0078, { 14, 0, 17 } },
{ 0x0074, { 14, 0, 18 } },
{ 0x0070, { 14, 0, 19 } },
{ 0x006C, { 14, 0, 20 } },
{ 0x0068, { 14, 0, 21 } },
{ 0x0064, { 14, 0, 22 } },
{ 0x0060, { 14, 0, 23 } },
{ 0x005C, { 14, 0, 24 } },
{ 0x0058, { 14, 0, 25 } },
{ 0x0054, { 14, 0, 26 } },
{ 0x0050, { 14, 0, 27 } },
{ 0x004C, { 14, 0, 28 } },
{ 0x0048, { 14, 0, 29 } },
{ 0x0044, { 14, 0, 30 } },
{ 0x0040, { 14, 0, 31 } },
{ 0x0030, { 15, 0, 32 } },
{ 0x002E, { 15, 0, 33 } },
{ 0x002C, { 15, 0, 34 } },
{ 0x002A, { 15, 0, 35 } },
{ 0x0028, { 15, 0, 36 } },
{ 0x0026, { 15, 0, 37 } },
{ 0x0024, { 15, 0, 38 } },
{ 0x0022, { 15, 0, 39 } },
{ 0x0020, { 15, 0, 40 } },
{ 0x003E, { 15, 1, 8 } },
{ 0x003C, { 15, 1, 9 } },
{ 0x003A, { 15, 1, 10 } },
{ 0x0038, { 15, 1, 11 } },
{ 0x0036, { 15, 1, 12 } },
{ 0x0034, { 15, 1, 13 } },
{ 0x0032, { 15, 1, 14 } },
{ 0x0013, { 16, 1, 15 } },
{ 0x0012, { 16, 1, 16 } },
{ 0x0011, { 16, 1, 17 } },
{ 0x0010, { 16, 1, 18 } },
{ 0x0014, { 16, 6, 3 } },
{ 0x001A, { 16, 11, 2 } },
{ 0x0019, { 16, 12, 2 } },
{ 0x0018, { 16, 13, 2 } },
{ 0x0017, { 16, 14, 2 } },
{ 0x0016, { 16, 15, 2 } },
{ 0x0015, { 16, 16, 2 } },
{ 0x001F, { 16, 27, 1 } },
{ 0x001E, { 16, 28, 1 } },
{ 0x001D, { 16, 29, 1 } },
{ 0x001C, { 16, 30, 1 } },
{ 0x001B, { 16, 31, 1 } }
};
 
/* q_scale_type */
static const unsigned quant_scale[2][32] = {
{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 22, 24,
28, 32, 36, 40, 44, 48, 52, 56, 64, 72, 80, 88, 96, 104, 112 }
};
 
static struct vl_vlc_entry tbl_B1[1 << 11];
static struct vl_vlc_entry tbl_B2[1 << 2];
static struct vl_vlc_entry tbl_B3[1 << 6];
static struct vl_vlc_entry tbl_B4[1 << 6];
static struct vl_vlc_entry tbl_B9[1 << 9];
static struct vl_vlc_entry tbl_B10[1 << 11];
static struct vl_vlc_entry tbl_B11[1 << 2];
static struct vl_vlc_entry tbl_B12[1 << 10];
static struct vl_vlc_entry tbl_B13[1 << 10];
static struct dct_coeff tbl_B14_DC[1 << 17];
static struct dct_coeff tbl_B14_AC[1 << 17];
static struct dct_coeff tbl_B15[1 << 17];
 
static INLINE void
init_dct_coeff_table(struct dct_coeff *dst, const struct dct_coeff_compressed *src,
unsigned size, bool is_DC)
{
unsigned i;
 
for (i=0;i<(1<<17);++i) {
dst[i].length = 0;
dst[i].level = 0;
dst[i].run = dct_End_of_Block;
}
 
for(; size > 0; --size, ++src) {
struct dct_coeff coeff = src->coeff;
bool has_sign = true;
 
switch (coeff.run) {
case dct_End_of_Block:
if (is_DC)
continue;
 
has_sign = false;
break;
 
case dct_Escape:
has_sign = false;
break;
 
case dct_DC:
if (!is_DC)
continue;
 
coeff.length += 1;
coeff.run = 1;
break;
 
case dct_AC:
if (is_DC)
continue;
 
coeff.length += 1;
coeff.run = 1;
break;
 
default:
coeff.length += 1;
coeff.run += 1;
break;
}
 
for(i=0; i<(1 << (17 - coeff.length)); ++i)
dst[src->bitcode << 1 | i] = coeff;
 
if (has_sign) {
coeff.level = -coeff.level;
for(; i<(1 << (18 - coeff.length)); ++i)
dst[src->bitcode << 1 | i] = coeff;
}
}
}
 
static INLINE void
init_tables()
{
vl_vlc_init_table(tbl_B1, Elements(tbl_B1), macroblock_address_increment, Elements(macroblock_address_increment));
vl_vlc_init_table(tbl_B2, Elements(tbl_B2), macroblock_type_i, Elements(macroblock_type_i));
vl_vlc_init_table(tbl_B3, Elements(tbl_B3), macroblock_type_p, Elements(macroblock_type_p));
vl_vlc_init_table(tbl_B4, Elements(tbl_B4), macroblock_type_b, Elements(macroblock_type_b));
vl_vlc_init_table(tbl_B9, Elements(tbl_B9), coded_block_pattern, Elements(coded_block_pattern));
vl_vlc_init_table(tbl_B10, Elements(tbl_B10), motion_code, Elements(motion_code));
vl_vlc_init_table(tbl_B11, Elements(tbl_B11), dmvector, Elements(dmvector));
vl_vlc_init_table(tbl_B12, Elements(tbl_B12), dct_dc_size_luminance, Elements(dct_dc_size_luminance));
vl_vlc_init_table(tbl_B13, Elements(tbl_B13), dct_dc_size_chrominance, Elements(dct_dc_size_chrominance));
init_dct_coeff_table(tbl_B14_DC, dct_coeff_tbl_zero, Elements(dct_coeff_tbl_zero), true);
init_dct_coeff_table(tbl_B14_AC, dct_coeff_tbl_zero, Elements(dct_coeff_tbl_zero), false);
init_dct_coeff_table(tbl_B15, dct_coeff_tbl_one, Elements(dct_coeff_tbl_one), false);
}
 
static INLINE int
DIV2DOWN(int todiv)
{
return (todiv&~1)/2;
}
 
static INLINE int
DIV2UP(int todiv)
{
return (todiv+1)/2;
}
 
static INLINE void
motion_vector(struct vl_mpg12_bs *bs, int r, int s, int dmv, short delta[2], short dmvector[2])
{
int t;
for (t = 0; t < 2; ++t) {
int motion_code;
int r_size = bs->desc->f_code[s][t];
 
vl_vlc_fillbits(&bs->vlc);
motion_code = vl_vlc_get_vlclbf(&bs->vlc, tbl_B10, 11);
 
assert(r_size >= 0);
if (r_size && motion_code) {
int residual = vl_vlc_get_uimsbf(&bs->vlc, r_size) + 1;
delta[t] = ((abs(motion_code) - 1) << r_size) + residual;
if (motion_code < 0)
delta[t] = -delta[t];
} else
delta[t] = motion_code;
if (dmv)
dmvector[t] = vl_vlc_get_vlclbf(&bs->vlc, tbl_B11, 2);
}
}
 
static INLINE int
wrap(short f, int shift)
{
if (f < (-16 << shift))
return f + (32 << shift);
else if (f >= 16 << shift)
return f - (32 << shift);
else
return f;
}
 
static INLINE void
motion_vector_frame(struct vl_mpg12_bs *bs, int s, struct pipe_mpeg12_macroblock *mb)
{
int dmv = mb->macroblock_modes.bits.frame_motion_type == PIPE_MPEG12_MO_TYPE_DUAL_PRIME;
short dmvector[2], delta[2];
 
if (mb->macroblock_modes.bits.frame_motion_type == PIPE_MPEG12_MO_TYPE_FIELD) {
mb->motion_vertical_field_select |= vl_vlc_get_uimsbf(&bs->vlc, 1) << s;
motion_vector(bs, 0, s, dmv, delta, dmvector);
mb->PMV[0][s][0] = wrap(mb->PMV[0][s][0] + delta[0], bs->desc->f_code[s][0]);
mb->PMV[0][s][1] = wrap(DIV2DOWN(mb->PMV[0][s][1]) + delta[1], bs->desc->f_code[s][1]) * 2;
 
mb->motion_vertical_field_select |= vl_vlc_get_uimsbf(&bs->vlc, 1) << (s + 2);
motion_vector(bs, 1, s, dmv, delta, dmvector);
mb->PMV[1][s][0] = wrap(mb->PMV[1][s][0] + delta[0], bs->desc->f_code[s][0]);
mb->PMV[1][s][1] = wrap(DIV2DOWN(mb->PMV[1][s][1]) + delta[1], bs->desc->f_code[s][1]) * 2;
 
} else {
motion_vector(bs, 0, s, dmv, delta, dmvector);
mb->PMV[0][s][0] = wrap(mb->PMV[0][s][0] + delta[0], bs->desc->f_code[s][0]);
mb->PMV[0][s][1] = wrap(mb->PMV[0][s][1] + delta[1], bs->desc->f_code[s][1]);
}
}
 
static INLINE void
motion_vector_field(struct vl_mpg12_bs *bs, int s, struct pipe_mpeg12_macroblock *mb)
{
int dmv = mb->macroblock_modes.bits.field_motion_type == PIPE_MPEG12_MO_TYPE_DUAL_PRIME;
short dmvector[2], delta[2];
 
if (mb->macroblock_modes.bits.field_motion_type == PIPE_MPEG12_MO_TYPE_16x8) {
mb->motion_vertical_field_select |= vl_vlc_get_uimsbf(&bs->vlc, 1) << s;
motion_vector(bs, 0, s, dmv, delta, dmvector);
 
mb->motion_vertical_field_select |= vl_vlc_get_uimsbf(&bs->vlc, 1) << (s + 2);
motion_vector(bs, 1, s, dmv, delta, dmvector);
} else {
if (!dmv)
mb->motion_vertical_field_select |= vl_vlc_get_uimsbf(&bs->vlc, 1) << s;
motion_vector(bs, 0, s, dmv, delta, dmvector);
}
}
 
static INLINE void
reset_predictor(struct vl_mpg12_bs *bs) {
bs->pred_dc[0] = bs->pred_dc[1] = bs->pred_dc[2] = 0;
}
 
static INLINE void
decode_dct(struct vl_mpg12_bs *bs, struct pipe_mpeg12_macroblock *mb, int scale)
{
static const unsigned blk2cc[] = { 0, 0, 0, 0, 1, 2 };
static const struct vl_vlc_entry *blk2dcsize[] = {
tbl_B12, tbl_B12, tbl_B12, tbl_B12, tbl_B13, tbl_B13
};
 
bool intra = mb->macroblock_type & PIPE_MPEG12_MB_TYPE_INTRA;
const struct dct_coeff *table = intra ? bs->intra_dct_tbl : tbl_B14_AC;
const struct dct_coeff *entry;
int i, cbp, blk = 0;
short *dst = mb->blocks;
 
vl_vlc_fillbits(&bs->vlc);
mb->coded_block_pattern = cbp = intra ? 0x3F : vl_vlc_get_vlclbf(&bs->vlc, tbl_B9, 9);
 
goto entry;
 
while(1) {
vl_vlc_eatbits(&bs->vlc, entry->length);
if (entry->run == dct_End_of_Block) {
 
next_d:
dst += 64;
cbp <<= 1;
cbp &= 0x3F;
blk++;
 
entry:
if (!cbp)
break;
 
while(!(cbp & 0x20)) {
cbp <<= 1;
blk++;
}
 
vl_vlc_fillbits(&bs->vlc);
 
if (intra) {
unsigned cc = blk2cc[blk];
unsigned size = vl_vlc_get_vlclbf(&bs->vlc, blk2dcsize[blk], 10);
 
if (size) {
int dct_diff = vl_vlc_get_uimsbf(&bs->vlc, size);
int half_range = 1 << (size - 1);
if (dct_diff < half_range)
dct_diff = (dct_diff + 1) - (2 * half_range);
bs->pred_dc[cc] += dct_diff;
}
 
dst[0] = bs->pred_dc[cc];
i = 0;
 
if (bs->desc->picture_coding_type == PIPE_MPEG12_PICTURE_CODING_TYPE_D)
goto next_d;
} else {
entry = tbl_B14_DC + vl_vlc_peekbits(&bs->vlc, 17);
i = -1;
continue;
}
 
} else if (entry->run == dct_Escape &&
bs->decoder->profile == PIPE_VIDEO_PROFILE_MPEG1) {
i += vl_vlc_get_uimsbf(&bs->vlc, 6) + 1;
if (i > 64)
break;
 
dst[i] = vl_vlc_get_simsbf(&bs->vlc, 8);
if (dst[i] == -128)
dst[i] = vl_vlc_get_uimsbf(&bs->vlc, 8) - 256;
else if (dst[i] == 0)
dst[i] = vl_vlc_get_uimsbf(&bs->vlc, 8);
 
dst[i] *= scale;
} else if (entry->run == dct_Escape) {
i += vl_vlc_get_uimsbf(&bs->vlc, 6) + 1;
if (i > 64)
break;
 
dst[i] = vl_vlc_get_simsbf(&bs->vlc, 12) * scale;
 
} else {
i += entry->run;
if (i > 64)
break;
 
dst[i] = entry->level * scale;
}
 
vl_vlc_fillbits(&bs->vlc);
entry = table + vl_vlc_peekbits(&bs->vlc, 17);
}
 
if (bs->desc->picture_coding_type == PIPE_MPEG12_PICTURE_CODING_TYPE_D)
vl_vlc_eatbits(&bs->vlc, 1);
}
 
static INLINE void
decode_slice(struct vl_mpg12_bs *bs, struct pipe_video_buffer *target)
{
struct pipe_mpeg12_macroblock mb;
short dct_blocks[64*6];
unsigned dct_scale;
signed x = -1;
 
memset(&mb, 0, sizeof(mb));
mb.base.codec = PIPE_VIDEO_CODEC_MPEG12;
mb.y = vl_vlc_get_uimsbf(&bs->vlc, 8) - 1;
mb.blocks = dct_blocks;
 
reset_predictor(bs);
vl_vlc_fillbits(&bs->vlc);
dct_scale = quant_scale[bs->desc->q_scale_type][vl_vlc_get_uimsbf(&bs->vlc, 5)];
 
if (vl_vlc_get_uimsbf(&bs->vlc, 1))
while (vl_vlc_get_uimsbf(&bs->vlc, 9) & 1)
vl_vlc_fillbits(&bs->vlc);
 
vl_vlc_fillbits(&bs->vlc);
assert(vl_vlc_peekbits(&bs->vlc, 23));
do {
int inc = 0;
 
while (1) {
/* MPEG-1 macroblock stuffing, can appear an arbitrary number of times. */
while (vl_vlc_peekbits(&bs->vlc, 11) == 15) {
vl_vlc_eatbits(&bs->vlc, 11);
vl_vlc_fillbits(&bs->vlc);
}
 
if (vl_vlc_peekbits(&bs->vlc, 11) == 8) {
vl_vlc_eatbits(&bs->vlc, 11);
vl_vlc_fillbits(&bs->vlc);
inc += 33;
} else {
inc += vl_vlc_get_vlclbf(&bs->vlc, tbl_B1, 11);
break;
}
}
 
if (x != -1) {
if (!inc)
return;
mb.num_skipped_macroblocks = inc - 1;
bs->decoder->decode_macroblock(bs->decoder, target, &bs->desc->base, &mb.base, 1);
}
mb.x = x += inc;
if (bs->decoder->profile == PIPE_VIDEO_PROFILE_MPEG1) {
int width = align(bs->decoder->width, 16) / 16;
mb.y += mb.x / width;
mb.x = x %= width;
}
 
switch (bs->desc->picture_coding_type) {
case PIPE_MPEG12_PICTURE_CODING_TYPE_I:
mb.macroblock_type = vl_vlc_get_vlclbf(&bs->vlc, tbl_B2, 2);
break;
 
case PIPE_MPEG12_PICTURE_CODING_TYPE_P:
mb.macroblock_type = vl_vlc_get_vlclbf(&bs->vlc, tbl_B3, 6);
break;
 
case PIPE_MPEG12_PICTURE_CODING_TYPE_B:
mb.macroblock_type = vl_vlc_get_vlclbf(&bs->vlc, tbl_B4, 6);
break;
 
case PIPE_MPEG12_PICTURE_CODING_TYPE_D:
vl_vlc_eatbits(&bs->vlc, 1);
mb.macroblock_type = PIPE_MPEG12_MB_TYPE_INTRA;
break;
}
 
mb.macroblock_modes.value = 0;
if (mb.macroblock_type & (PIPE_MPEG12_MB_TYPE_MOTION_FORWARD | PIPE_MPEG12_MB_TYPE_MOTION_BACKWARD)) {
if (bs->desc->picture_structure == PIPE_MPEG12_PICTURE_STRUCTURE_FRAME) {
if (bs->desc->frame_pred_frame_dct == 0)
mb.macroblock_modes.bits.frame_motion_type = vl_vlc_get_uimsbf(&bs->vlc, 2);
else
mb.macroblock_modes.bits.frame_motion_type = 2;
} else
mb.macroblock_modes.bits.field_motion_type = vl_vlc_get_uimsbf(&bs->vlc, 2);
 
} else if ((mb.macroblock_type & PIPE_MPEG12_MB_TYPE_INTRA) && bs->desc->concealment_motion_vectors) {
if (bs->desc->picture_structure == PIPE_MPEG12_PICTURE_STRUCTURE_FRAME)
mb.macroblock_modes.bits.frame_motion_type = 2;
else
mb.macroblock_modes.bits.field_motion_type = 1;
}
 
if (bs->desc->picture_structure == PIPE_MPEG12_PICTURE_STRUCTURE_FRAME &&
bs->desc->frame_pred_frame_dct == 0 &&
mb.macroblock_type & (PIPE_MPEG12_MB_TYPE_INTRA | PIPE_MPEG12_MB_TYPE_PATTERN))
mb.macroblock_modes.bits.dct_type = vl_vlc_get_uimsbf(&bs->vlc, 1);
 
if (mb.macroblock_type & PIPE_MPEG12_MB_TYPE_QUANT)
dct_scale = quant_scale[bs->desc->q_scale_type][vl_vlc_get_uimsbf(&bs->vlc, 5)];
 
if (inc > 1 && bs->desc->picture_coding_type == PIPE_MPEG12_PICTURE_CODING_TYPE_P)
memset(mb.PMV, 0, sizeof(mb.PMV));
 
mb.motion_vertical_field_select = 0;
if ((mb.macroblock_type & PIPE_MPEG12_MB_TYPE_MOTION_FORWARD) ||
(mb.macroblock_type & PIPE_MPEG12_MB_TYPE_INTRA && bs->desc->concealment_motion_vectors)) {
if (bs->desc->picture_structure == PIPE_MPEG12_PICTURE_STRUCTURE_FRAME)
motion_vector_frame(bs, 0, &mb);
else
motion_vector_field(bs, 0, &mb);
}
 
if (mb.macroblock_type & PIPE_MPEG12_MB_TYPE_MOTION_BACKWARD) {
if (bs->desc->picture_structure == PIPE_MPEG12_PICTURE_STRUCTURE_FRAME)
motion_vector_frame(bs, 1, &mb);
else
motion_vector_field(bs, 1, &mb);
}
 
if (mb.macroblock_type & PIPE_MPEG12_MB_TYPE_INTRA && bs->desc->concealment_motion_vectors) {
unsigned extra = vl_vlc_get_uimsbf(&bs->vlc, 1);
mb.PMV[1][0][0] = mb.PMV[0][0][0];
mb.PMV[1][0][1] = mb.PMV[0][0][1];
assert(extra);
} else if (mb.macroblock_type & PIPE_MPEG12_MB_TYPE_INTRA ||
!(mb.macroblock_type & (PIPE_MPEG12_MB_TYPE_MOTION_FORWARD |
PIPE_MPEG12_MB_TYPE_MOTION_BACKWARD))) {
memset(mb.PMV, 0, sizeof(mb.PMV));
}
 
if ((mb.macroblock_type & PIPE_MPEG12_MB_TYPE_MOTION_FORWARD &&
mb.macroblock_modes.bits.frame_motion_type == 2) ||
(mb.macroblock_modes.bits.frame_motion_type == 3)) {
mb.PMV[1][0][0] = mb.PMV[0][0][0];
mb.PMV[1][0][1] = mb.PMV[0][0][1];
}
 
if (mb.macroblock_type & PIPE_MPEG12_MB_TYPE_MOTION_BACKWARD &&
mb.macroblock_modes.bits.frame_motion_type == 2) {
mb.PMV[1][1][0] = mb.PMV[0][1][0];
mb.PMV[1][1][1] = mb.PMV[0][1][1];
}
 
if (inc > 1 || !(mb.macroblock_type & PIPE_MPEG12_MB_TYPE_INTRA))
reset_predictor(bs);
 
if (mb.macroblock_type & (PIPE_MPEG12_MB_TYPE_INTRA | PIPE_MPEG12_MB_TYPE_PATTERN)) {
memset(dct_blocks, 0, sizeof(dct_blocks));
decode_dct(bs, &mb, dct_scale);
} else
mb.coded_block_pattern = 0;
 
vl_vlc_fillbits(&bs->vlc);
} while (vl_vlc_bits_left(&bs->vlc) && vl_vlc_peekbits(&bs->vlc, 23));
 
mb.num_skipped_macroblocks = 0;
bs->decoder->decode_macroblock(bs->decoder, target, &bs->desc->base, &mb.base, 1);
}
 
void
vl_mpg12_bs_init(struct vl_mpg12_bs *bs, struct pipe_video_decoder *decoder)
{
static bool tables_initialized = false;
 
assert(bs);
 
memset(bs, 0, sizeof(struct vl_mpg12_bs));
 
bs->decoder = decoder;
 
if (!tables_initialized) {
init_tables();
tables_initialized = true;
}
}
 
void
vl_mpg12_bs_decode(struct vl_mpg12_bs *bs,
struct pipe_video_buffer *target,
struct pipe_mpeg12_picture_desc *picture,
unsigned num_buffers,
const void * const *buffers,
const unsigned *sizes)
{
assert(bs);
 
bs->desc = picture;
bs->intra_dct_tbl = picture->intra_vlc_format ? tbl_B15 : tbl_B14_AC;
 
vl_vlc_init(&bs->vlc, num_buffers, buffers, sizes);
while (vl_vlc_bits_left(&bs->vlc) > 32) {
uint32_t code = vl_vlc_peekbits(&bs->vlc, 32);
 
if (code >= 0x101 && code <= 0x1AF) {
vl_vlc_eatbits(&bs->vlc, 24);
decode_slice(bs, target);
 
/* align to a byte again */
vl_vlc_eatbits(&bs->vlc, vl_vlc_valid_bits(&bs->vlc) & 7);
 
} else {
vl_vlc_eatbits(&bs->vlc, 8);
}
 
vl_vlc_fillbits(&bs->vlc);
}
}
/drivers/video/Gallium/auxiliary/vl/vl_mpeg12_bitstream.h
0,0 → 1,56
/**************************************************************************
*
* Copyright 2011 Christian König.
* 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.
*
**************************************************************************/
 
#ifndef vl_mpeg12_bitstream_h
#define vl_mpeg12_bitstream_h
 
#include "vl_defines.h"
#include "vl_vlc.h"
 
struct vl_mpg12_bs
{
struct pipe_video_decoder *decoder;
 
struct pipe_mpeg12_picture_desc *desc;
struct dct_coeff *intra_dct_tbl;
 
struct vl_vlc vlc;
short pred_dc[3];
};
 
void
vl_mpg12_bs_init(struct vl_mpg12_bs *bs, struct pipe_video_decoder *decoder);
 
void
vl_mpg12_bs_decode(struct vl_mpg12_bs *bs,
struct pipe_video_buffer *target,
struct pipe_mpeg12_picture_desc *picture,
unsigned num_buffers,
const void * const *buffers,
const unsigned *sizes);
 
#endif /* vl_mpeg12_bitstream_h */
/drivers/video/Gallium/auxiliary/vl/vl_mpeg12_decoder.c
0,0 → 1,1157
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* 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.
*
**************************************************************************/
 
#include <math.h>
#include <assert.h>
 
#include "util/u_memory.h"
#include "util/u_rect.h"
#include "util/u_sampler.h"
#include "util/u_video.h"
 
#include "vl_mpeg12_decoder.h"
#include "vl_defines.h"
 
#define SCALE_FACTOR_SNORM (32768.0f / 256.0f)
#define SCALE_FACTOR_SSCALED (1.0f / 256.0f)
 
struct format_config {
enum pipe_format zscan_source_format;
enum pipe_format idct_source_format;
enum pipe_format mc_source_format;
 
float idct_scale;
float mc_scale;
};
 
static const struct format_config bitstream_format_config[] = {
// { PIPE_FORMAT_R16_SSCALED, PIPE_FORMAT_R16G16B16A16_SSCALED, PIPE_FORMAT_R16G16B16A16_FLOAT, 1.0f, SCALE_FACTOR_SSCALED },
// { PIPE_FORMAT_R16_SSCALED, PIPE_FORMAT_R16G16B16A16_SSCALED, PIPE_FORMAT_R16G16B16A16_SSCALED, 1.0f, SCALE_FACTOR_SSCALED },
{ PIPE_FORMAT_R16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, PIPE_FORMAT_R16G16B16A16_FLOAT, 1.0f, SCALE_FACTOR_SNORM },
{ PIPE_FORMAT_R16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, 1.0f, SCALE_FACTOR_SNORM }
};
 
static const unsigned num_bitstream_format_configs =
sizeof(bitstream_format_config) / sizeof(struct format_config);
 
static const struct format_config idct_format_config[] = {
// { PIPE_FORMAT_R16_SSCALED, PIPE_FORMAT_R16G16B16A16_SSCALED, PIPE_FORMAT_R16G16B16A16_FLOAT, 1.0f, SCALE_FACTOR_SSCALED },
// { PIPE_FORMAT_R16_SSCALED, PIPE_FORMAT_R16G16B16A16_SSCALED, PIPE_FORMAT_R16G16B16A16_SSCALED, 1.0f, SCALE_FACTOR_SSCALED },
{ PIPE_FORMAT_R16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, PIPE_FORMAT_R16G16B16A16_FLOAT, 1.0f, SCALE_FACTOR_SNORM },
{ PIPE_FORMAT_R16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, 1.0f, SCALE_FACTOR_SNORM }
};
 
static const unsigned num_idct_format_configs =
sizeof(idct_format_config) / sizeof(struct format_config);
 
static const struct format_config mc_format_config[] = {
//{ PIPE_FORMAT_R16_SSCALED, PIPE_FORMAT_NONE, PIPE_FORMAT_R16_SSCALED, 0.0f, SCALE_FACTOR_SSCALED },
{ PIPE_FORMAT_R16_SNORM, PIPE_FORMAT_NONE, PIPE_FORMAT_R16_SNORM, 0.0f, SCALE_FACTOR_SNORM }
};
 
static const unsigned num_mc_format_configs =
sizeof(mc_format_config) / sizeof(struct format_config);
 
static const unsigned const_empty_block_mask_420[3][2][2] = {
{ { 0x20, 0x10 }, { 0x08, 0x04 } },
{ { 0x02, 0x02 }, { 0x02, 0x02 } },
{ { 0x01, 0x01 }, { 0x01, 0x01 } }
};
 
static bool
init_zscan_buffer(struct vl_mpeg12_decoder *dec, struct vl_mpeg12_buffer *buffer)
{
struct pipe_resource *res, res_tmpl;
struct pipe_sampler_view sv_tmpl;
struct pipe_surface **destination;
 
unsigned i;
 
assert(dec && buffer);
 
memset(&res_tmpl, 0, sizeof(res_tmpl));
res_tmpl.target = PIPE_TEXTURE_2D;
res_tmpl.format = dec->zscan_source_format;
res_tmpl.width0 = dec->blocks_per_line * VL_BLOCK_WIDTH * VL_BLOCK_HEIGHT;
res_tmpl.height0 = align(dec->num_blocks, dec->blocks_per_line) / dec->blocks_per_line;
res_tmpl.depth0 = 1;
res_tmpl.array_size = 1;
res_tmpl.usage = PIPE_USAGE_STREAM;
res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
 
res = dec->base.context->screen->resource_create(dec->base.context->screen, &res_tmpl);
if (!res)
goto error_source;
 
 
memset(&sv_tmpl, 0, sizeof(sv_tmpl));
u_sampler_view_default_template(&sv_tmpl, res, res->format);
sv_tmpl.swizzle_r = sv_tmpl.swizzle_g = sv_tmpl.swizzle_b = sv_tmpl.swizzle_a = PIPE_SWIZZLE_RED;
buffer->zscan_source = dec->base.context->create_sampler_view(dec->base.context, res, &sv_tmpl);
pipe_resource_reference(&res, NULL);
if (!buffer->zscan_source)
goto error_sampler;
 
if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT)
destination = dec->idct_source->get_surfaces(dec->idct_source);
else
destination = dec->mc_source->get_surfaces(dec->mc_source);
 
if (!destination)
goto error_surface;
 
for (i = 0; i < VL_NUM_COMPONENTS; ++i)
if (!vl_zscan_init_buffer(i == 0 ? &dec->zscan_y : &dec->zscan_c,
&buffer->zscan[i], buffer->zscan_source, destination[i]))
goto error_plane;
 
return true;
 
error_plane:
for (; i > 0; --i)
vl_zscan_cleanup_buffer(&buffer->zscan[i - 1]);
 
error_surface:
error_sampler:
pipe_sampler_view_reference(&buffer->zscan_source, NULL);
 
error_source:
return false;
}
 
static void
cleanup_zscan_buffer(struct vl_mpeg12_buffer *buffer)
{
unsigned i;
 
assert(buffer);
 
for (i = 0; i < VL_NUM_COMPONENTS; ++i)
vl_zscan_cleanup_buffer(&buffer->zscan[i]);
 
pipe_sampler_view_reference(&buffer->zscan_source, NULL);
}
 
static bool
init_idct_buffer(struct vl_mpeg12_decoder *dec, struct vl_mpeg12_buffer *buffer)
{
struct pipe_sampler_view **idct_source_sv, **mc_source_sv;
 
unsigned i;
 
assert(dec && buffer);
 
idct_source_sv = dec->idct_source->get_sampler_view_planes(dec->idct_source);
if (!idct_source_sv)
goto error_source_sv;
 
mc_source_sv = dec->mc_source->get_sampler_view_planes(dec->mc_source);
if (!mc_source_sv)
goto error_mc_source_sv;
 
for (i = 0; i < 3; ++i)
if (!vl_idct_init_buffer(i == 0 ? &dec->idct_y : &dec->idct_c,
&buffer->idct[i], idct_source_sv[i],
mc_source_sv[i]))
goto error_plane;
 
return true;
 
error_plane:
for (; i > 0; --i)
vl_idct_cleanup_buffer(&buffer->idct[i - 1]);
 
error_mc_source_sv:
error_source_sv:
return false;
}
 
static void
cleanup_idct_buffer(struct vl_mpeg12_buffer *buf)
{
unsigned i;
assert(buf);
 
for (i = 0; i < 3; ++i)
vl_idct_cleanup_buffer(&buf->idct[0]);
}
 
static bool
init_mc_buffer(struct vl_mpeg12_decoder *dec, struct vl_mpeg12_buffer *buf)
{
assert(dec && buf);
 
if(!vl_mc_init_buffer(&dec->mc_y, &buf->mc[0]))
goto error_mc_y;
 
if(!vl_mc_init_buffer(&dec->mc_c, &buf->mc[1]))
goto error_mc_cb;
 
if(!vl_mc_init_buffer(&dec->mc_c, &buf->mc[2]))
goto error_mc_cr;
 
return true;
 
error_mc_cr:
vl_mc_cleanup_buffer(&buf->mc[1]);
 
error_mc_cb:
vl_mc_cleanup_buffer(&buf->mc[0]);
 
error_mc_y:
return false;
}
 
static void
cleanup_mc_buffer(struct vl_mpeg12_buffer *buf)
{
unsigned i;
 
assert(buf);
 
for (i = 0; i < VL_NUM_COMPONENTS; ++i)
vl_mc_cleanup_buffer(&buf->mc[i]);
}
 
static INLINE void
MacroBlockTypeToPipeWeights(const struct pipe_mpeg12_macroblock *mb, unsigned weights[2])
{
assert(mb);
 
switch (mb->macroblock_type & (PIPE_MPEG12_MB_TYPE_MOTION_FORWARD | PIPE_MPEG12_MB_TYPE_MOTION_BACKWARD)) {
case PIPE_MPEG12_MB_TYPE_MOTION_FORWARD:
weights[0] = PIPE_VIDEO_MV_WEIGHT_MAX;
weights[1] = PIPE_VIDEO_MV_WEIGHT_MIN;
break;
 
case (PIPE_MPEG12_MB_TYPE_MOTION_FORWARD | PIPE_MPEG12_MB_TYPE_MOTION_BACKWARD):
weights[0] = PIPE_VIDEO_MV_WEIGHT_HALF;
weights[1] = PIPE_VIDEO_MV_WEIGHT_HALF;
break;
 
case PIPE_MPEG12_MB_TYPE_MOTION_BACKWARD:
weights[0] = PIPE_VIDEO_MV_WEIGHT_MIN;
weights[1] = PIPE_VIDEO_MV_WEIGHT_MAX;
break;
 
default:
if (mb->macroblock_type & PIPE_MPEG12_MB_TYPE_INTRA) {
weights[0] = PIPE_VIDEO_MV_WEIGHT_MIN;
weights[1] = PIPE_VIDEO_MV_WEIGHT_MIN;
} else {
/* no motion vector, but also not intra mb ->
just copy the old frame content */
weights[0] = PIPE_VIDEO_MV_WEIGHT_MAX;
weights[1] = PIPE_VIDEO_MV_WEIGHT_MIN;
}
break;
}
}
 
static INLINE struct vl_motionvector
MotionVectorToPipe(const struct pipe_mpeg12_macroblock *mb, unsigned vector,
unsigned field_select_mask, unsigned weight)
{
struct vl_motionvector mv;
 
assert(mb);
 
if (mb->macroblock_type & (PIPE_MPEG12_MB_TYPE_MOTION_FORWARD | PIPE_MPEG12_MB_TYPE_MOTION_BACKWARD)) {
switch (mb->macroblock_modes.bits.frame_motion_type) {
case PIPE_MPEG12_MO_TYPE_FRAME:
mv.top.x = mb->PMV[0][vector][0];
mv.top.y = mb->PMV[0][vector][1];
mv.top.field_select = PIPE_VIDEO_FRAME;
mv.top.weight = weight;
 
mv.bottom.x = mb->PMV[0][vector][0];
mv.bottom.y = mb->PMV[0][vector][1];
mv.bottom.weight = weight;
mv.bottom.field_select = PIPE_VIDEO_FRAME;
break;
 
case PIPE_MPEG12_MO_TYPE_FIELD:
mv.top.x = mb->PMV[0][vector][0];
mv.top.y = mb->PMV[0][vector][1];
mv.top.field_select = (mb->motion_vertical_field_select & field_select_mask) ?
PIPE_VIDEO_BOTTOM_FIELD : PIPE_VIDEO_TOP_FIELD;
mv.top.weight = weight;
 
mv.bottom.x = mb->PMV[1][vector][0];
mv.bottom.y = mb->PMV[1][vector][1];
mv.bottom.field_select = (mb->motion_vertical_field_select & (field_select_mask << 2)) ?
PIPE_VIDEO_BOTTOM_FIELD : PIPE_VIDEO_TOP_FIELD;
mv.bottom.weight = weight;
break;
 
default: // TODO: Support DUALPRIME and 16x8
break;
}
} else {
mv.top.x = mv.top.y = 0;
mv.top.field_select = PIPE_VIDEO_FRAME;
mv.top.weight = weight;
 
mv.bottom.x = mv.bottom.y = 0;
mv.bottom.field_select = PIPE_VIDEO_FRAME;
mv.bottom.weight = weight;
}
return mv;
}
 
static INLINE void
UploadYcbcrBlocks(struct vl_mpeg12_decoder *dec,
struct vl_mpeg12_buffer *buf,
const struct pipe_mpeg12_macroblock *mb)
{
unsigned intra;
unsigned tb, x, y, num_blocks = 0;
 
assert(dec && buf);
assert(mb);
 
if (!mb->coded_block_pattern)
return;
 
intra = mb->macroblock_type & PIPE_MPEG12_MB_TYPE_INTRA ? 1 : 0;
 
for (y = 0; y < 2; ++y) {
for (x = 0; x < 2; ++x) {
if (mb->coded_block_pattern & const_empty_block_mask_420[0][y][x]) {
 
struct vl_ycbcr_block *stream = buf->ycbcr_stream[0];
stream->x = mb->x * 2 + x;
stream->y = mb->y * 2 + y;
stream->intra = intra;
stream->coding = mb->macroblock_modes.bits.dct_type;
stream->block_num = buf->block_num++;
 
buf->num_ycbcr_blocks[0]++;
buf->ycbcr_stream[0]++;
 
num_blocks++;
}
}
}
 
/* TODO: Implement 422, 444 */
//assert(ctx->base.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420);
 
for (tb = 1; tb < 3; ++tb) {
if (mb->coded_block_pattern & const_empty_block_mask_420[tb][0][0]) {
 
struct vl_ycbcr_block *stream = buf->ycbcr_stream[tb];
stream->x = mb->x;
stream->y = mb->y;
stream->intra = intra;
stream->coding = 0;
stream->block_num = buf->block_num++;
 
buf->num_ycbcr_blocks[tb]++;
buf->ycbcr_stream[tb]++;
 
num_blocks++;
}
}
 
memcpy(buf->texels, mb->blocks, 64 * sizeof(short) * num_blocks);
buf->texels += 64 * num_blocks;
}
 
static void
vl_mpeg12_destroy_buffer(void *buffer)
{
struct vl_mpeg12_buffer *buf = buffer;
 
assert(buf);
 
cleanup_zscan_buffer(buf);
cleanup_idct_buffer(buf);
cleanup_mc_buffer(buf);
vl_vb_cleanup(&buf->vertex_stream);
 
FREE(buf);
}
 
static void
vl_mpeg12_destroy(struct pipe_video_decoder *decoder)
{
struct vl_mpeg12_decoder *dec = (struct vl_mpeg12_decoder*)decoder;
unsigned i;
 
assert(decoder);
 
/* Asserted in softpipe_delete_fs_state() for some reason */
dec->base.context->bind_vs_state(dec->base.context, NULL);
dec->base.context->bind_fs_state(dec->base.context, NULL);
 
dec->base.context->delete_depth_stencil_alpha_state(dec->base.context, dec->dsa);
dec->base.context->delete_sampler_state(dec->base.context, dec->sampler_ycbcr);
 
vl_mc_cleanup(&dec->mc_y);
vl_mc_cleanup(&dec->mc_c);
dec->mc_source->destroy(dec->mc_source);
 
if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) {
vl_idct_cleanup(&dec->idct_y);
vl_idct_cleanup(&dec->idct_c);
dec->idct_source->destroy(dec->idct_source);
}
 
vl_zscan_cleanup(&dec->zscan_y);
vl_zscan_cleanup(&dec->zscan_c);
 
dec->base.context->delete_vertex_elements_state(dec->base.context, dec->ves_ycbcr);
dec->base.context->delete_vertex_elements_state(dec->base.context, dec->ves_mv);
 
pipe_resource_reference(&dec->quads.buffer, NULL);
pipe_resource_reference(&dec->pos.buffer, NULL);
 
pipe_sampler_view_reference(&dec->zscan_linear, NULL);
pipe_sampler_view_reference(&dec->zscan_normal, NULL);
pipe_sampler_view_reference(&dec->zscan_alternate, NULL);
 
for (i = 0; i < 4; ++i)
if (dec->dec_buffers[i])
vl_mpeg12_destroy_buffer(dec->dec_buffers[i]);
 
FREE(dec);
}
 
static struct vl_mpeg12_buffer *
vl_mpeg12_get_decode_buffer(struct vl_mpeg12_decoder *dec, struct pipe_video_buffer *target)
{
struct vl_mpeg12_buffer *buffer;
 
assert(dec);
 
buffer = vl_video_buffer_get_associated_data(target, &dec->base);
if (buffer)
return buffer;
 
buffer = dec->dec_buffers[dec->current_buffer];
if (buffer)
return buffer;
 
buffer = CALLOC_STRUCT(vl_mpeg12_buffer);
if (buffer == NULL)
return NULL;
 
if (!vl_vb_init(&buffer->vertex_stream, dec->base.context,
dec->base.width / VL_MACROBLOCK_WIDTH,
dec->base.height / VL_MACROBLOCK_HEIGHT))
goto error_vertex_buffer;
 
if (!init_mc_buffer(dec, buffer))
goto error_mc;
 
if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT)
if (!init_idct_buffer(dec, buffer))
goto error_idct;
 
if (!init_zscan_buffer(dec, buffer))
goto error_zscan;
 
if (dec->base.entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM)
vl_mpg12_bs_init(&buffer->bs, &dec->base);
 
if (dec->expect_chunked_decode)
vl_video_buffer_set_associated_data(target, &dec->base,
buffer, vl_mpeg12_destroy_buffer);
else
dec->dec_buffers[dec->current_buffer] = buffer;
 
return buffer;
 
error_zscan:
cleanup_idct_buffer(buffer);
 
error_idct:
cleanup_mc_buffer(buffer);
 
error_mc:
vl_vb_cleanup(&buffer->vertex_stream);
 
error_vertex_buffer:
FREE(buffer);
return NULL;
}
 
static void
vl_mpeg12_begin_frame(struct pipe_video_decoder *decoder,
struct pipe_video_buffer *target,
struct pipe_picture_desc *picture)
{
struct vl_mpeg12_decoder *dec = (struct vl_mpeg12_decoder *)decoder;
struct pipe_mpeg12_picture_desc *desc = (struct pipe_mpeg12_picture_desc *)picture;
struct vl_mpeg12_buffer *buf;
 
struct pipe_resource *tex;
struct pipe_box rect = { 0, 0, 0, 1, 1, 1 };
 
uint8_t intra_matrix[64];
uint8_t non_intra_matrix[64];
 
unsigned i;
 
assert(dec && target && picture);
 
buf = vl_mpeg12_get_decode_buffer(dec, target);
assert(buf);
 
if (dec->base.entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) {
memcpy(intra_matrix, desc->intra_matrix, sizeof(intra_matrix));
memcpy(non_intra_matrix, desc->non_intra_matrix, sizeof(non_intra_matrix));
intra_matrix[0] = 1 << (7 - desc->intra_dc_precision);
} else {
memset(intra_matrix, 0x10, sizeof(intra_matrix));
memset(non_intra_matrix, 0x10, sizeof(non_intra_matrix));
}
 
for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
struct vl_zscan *zscan = i == 0 ? &dec->zscan_y : &dec->zscan_c;
vl_zscan_upload_quant(zscan, &buf->zscan[i], intra_matrix, true);
vl_zscan_upload_quant(zscan, &buf->zscan[i], non_intra_matrix, false);
}
 
vl_vb_map(&buf->vertex_stream, dec->base.context);
 
tex = buf->zscan_source->texture;
rect.width = tex->width0;
rect.height = tex->height0;
 
buf->texels =
dec->base.context->transfer_map(dec->base.context, tex, 0,
PIPE_TRANSFER_WRITE |
PIPE_TRANSFER_DISCARD_RANGE,
&rect, &buf->tex_transfer);
 
buf->block_num = 0;
 
for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
buf->ycbcr_stream[i] = vl_vb_get_ycbcr_stream(&buf->vertex_stream, i);
buf->num_ycbcr_blocks[i] = 0;
}
 
for (i = 0; i < VL_MAX_REF_FRAMES; ++i)
buf->mv_stream[i] = vl_vb_get_mv_stream(&buf->vertex_stream, i);
 
if (dec->base.entrypoint >= PIPE_VIDEO_ENTRYPOINT_IDCT) {
for (i = 0; i < VL_NUM_COMPONENTS; ++i)
vl_zscan_set_layout(&buf->zscan[i], dec->zscan_linear);
}
}
 
static void
vl_mpeg12_decode_macroblock(struct pipe_video_decoder *decoder,
struct pipe_video_buffer *target,
struct pipe_picture_desc *picture,
const struct pipe_macroblock *macroblocks,
unsigned num_macroblocks)
{
struct vl_mpeg12_decoder *dec = (struct vl_mpeg12_decoder *)decoder;
const struct pipe_mpeg12_macroblock *mb = (const struct pipe_mpeg12_macroblock *)macroblocks;
struct pipe_mpeg12_picture_desc *desc = (struct pipe_mpeg12_picture_desc *)picture;
struct vl_mpeg12_buffer *buf;
 
unsigned i, j, mv_weights[2];
 
assert(dec && target && picture);
assert(macroblocks && macroblocks->codec == PIPE_VIDEO_CODEC_MPEG12);
 
buf = vl_mpeg12_get_decode_buffer(dec, target);
assert(buf);
 
for (; num_macroblocks > 0; --num_macroblocks) {
unsigned mb_addr = mb->y * dec->width_in_macroblocks + mb->x;
 
if (mb->macroblock_type & (PIPE_MPEG12_MB_TYPE_PATTERN | PIPE_MPEG12_MB_TYPE_INTRA))
UploadYcbcrBlocks(dec, buf, mb);
 
MacroBlockTypeToPipeWeights(mb, mv_weights);
 
for (i = 0; i < 2; ++i) {
if (!desc->ref[i]) continue;
 
buf->mv_stream[i][mb_addr] = MotionVectorToPipe
(
mb, i,
i ? PIPE_MPEG12_FS_FIRST_BACKWARD : PIPE_MPEG12_FS_FIRST_FORWARD,
mv_weights[i]
);
}
 
/* see section 7.6.6 of the spec */
if (mb->num_skipped_macroblocks > 0) {
struct vl_motionvector skipped_mv[2];
 
if (desc->ref[0] && !desc->ref[1]) {
skipped_mv[0].top.x = skipped_mv[0].top.y = 0;
skipped_mv[0].top.weight = PIPE_VIDEO_MV_WEIGHT_MAX;
} else {
skipped_mv[0] = buf->mv_stream[0][mb_addr];
skipped_mv[1] = buf->mv_stream[1][mb_addr];
}
skipped_mv[0].top.field_select = PIPE_VIDEO_FRAME;
skipped_mv[1].top.field_select = PIPE_VIDEO_FRAME;
 
skipped_mv[0].bottom = skipped_mv[0].top;
skipped_mv[1].bottom = skipped_mv[1].top;
 
++mb_addr;
for (i = 0; i < mb->num_skipped_macroblocks; ++i, ++mb_addr) {
for (j = 0; j < 2; ++j) {
if (!desc->ref[j]) continue;
buf->mv_stream[j][mb_addr] = skipped_mv[j];
 
}
}
}
 
++mb;
}
}
 
static void
vl_mpeg12_decode_bitstream(struct pipe_video_decoder *decoder,
struct pipe_video_buffer *target,
struct pipe_picture_desc *picture,
unsigned num_buffers,
const void * const *buffers,
const unsigned *sizes)
{
struct vl_mpeg12_decoder *dec = (struct vl_mpeg12_decoder *)decoder;
struct pipe_mpeg12_picture_desc *desc = (struct pipe_mpeg12_picture_desc *)picture;
struct vl_mpeg12_buffer *buf;
unsigned i;
 
assert(dec && target && picture);
 
buf = vl_mpeg12_get_decode_buffer(dec, target);
assert(buf);
 
for (i = 0; i < VL_NUM_COMPONENTS; ++i)
vl_zscan_set_layout(&buf->zscan[i], desc->alternate_scan ?
dec->zscan_alternate : dec->zscan_normal);
 
vl_mpg12_bs_decode(&buf->bs, target, desc, num_buffers, buffers, sizes);
}
 
static void
vl_mpeg12_end_frame(struct pipe_video_decoder *decoder,
struct pipe_video_buffer *target,
struct pipe_picture_desc *picture)
{
struct vl_mpeg12_decoder *dec = (struct vl_mpeg12_decoder *)decoder;
struct pipe_mpeg12_picture_desc *desc = (struct pipe_mpeg12_picture_desc *)picture;
struct pipe_sampler_view **ref_frames[2];
struct pipe_sampler_view **mc_source_sv;
struct pipe_surface **target_surfaces;
struct pipe_vertex_buffer vb[3];
struct vl_mpeg12_buffer *buf;
 
const unsigned *plane_order;
unsigned i, j, component;
unsigned nr_components;
 
assert(dec && target && picture);
assert(!target->interlaced);
 
buf = vl_mpeg12_get_decode_buffer(dec, target);
 
vl_vb_unmap(&buf->vertex_stream, dec->base.context);
 
dec->base.context->transfer_unmap(dec->base.context, buf->tex_transfer);
 
vb[0] = dec->quads;
vb[1] = dec->pos;
 
target_surfaces = target->get_surfaces(target);
 
for (i = 0; i < VL_MAX_REF_FRAMES; ++i) {
if (desc->ref[i])
ref_frames[i] = desc->ref[i]->get_sampler_view_planes(desc->ref[i]);
else
ref_frames[i] = NULL;
}
 
dec->base.context->bind_vertex_elements_state(dec->base.context, dec->ves_mv);
for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
if (!target_surfaces[i]) continue;
 
vl_mc_set_surface(&buf->mc[i], target_surfaces[i]);
 
for (j = 0; j < VL_MAX_REF_FRAMES; ++j) {
if (!ref_frames[j] || !ref_frames[j][i]) continue;
 
vb[2] = vl_vb_get_mv(&buf->vertex_stream, j);;
dec->base.context->set_vertex_buffers(dec->base.context, 0, 3, vb);
 
vl_mc_render_ref(i ? &dec->mc_c : &dec->mc_y, &buf->mc[i], ref_frames[j][i]);
}
}
 
dec->base.context->bind_vertex_elements_state(dec->base.context, dec->ves_ycbcr);
for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
if (!buf->num_ycbcr_blocks[i]) continue;
 
vb[1] = vl_vb_get_ycbcr(&buf->vertex_stream, i);
dec->base.context->set_vertex_buffers(dec->base.context, 0, 2, vb);
 
vl_zscan_render(i ? &dec->zscan_c : & dec->zscan_y, &buf->zscan[i] , buf->num_ycbcr_blocks[i]);
 
if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT)
vl_idct_flush(i ? &dec->idct_c : &dec->idct_y, &buf->idct[i], buf->num_ycbcr_blocks[i]);
}
 
plane_order = vl_video_buffer_plane_order(target->buffer_format);
mc_source_sv = dec->mc_source->get_sampler_view_planes(dec->mc_source);
for (i = 0, component = 0; component < VL_NUM_COMPONENTS; ++i) {
if (!target_surfaces[i]) continue;
 
nr_components = util_format_get_nr_components(target_surfaces[i]->texture->format);
for (j = 0; j < nr_components; ++j, ++component) {
unsigned plane = plane_order[component];
if (!buf->num_ycbcr_blocks[plane]) continue;
 
vb[1] = vl_vb_get_ycbcr(&buf->vertex_stream, plane);
dec->base.context->set_vertex_buffers(dec->base.context, 0, 2, vb);
 
if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT)
vl_idct_prepare_stage2(i ? &dec->idct_c : &dec->idct_y, &buf->idct[plane]);
else {
dec->base.context->set_fragment_sampler_views(dec->base.context, 1, &mc_source_sv[plane]);
dec->base.context->bind_fragment_sampler_states(dec->base.context, 1, &dec->sampler_ycbcr);
}
vl_mc_render_ycbcr(i ? &dec->mc_c : &dec->mc_y, &buf->mc[i], j, buf->num_ycbcr_blocks[plane]);
}
}
++dec->current_buffer;
dec->current_buffer %= 4;
}
 
static void
vl_mpeg12_flush(struct pipe_video_decoder *decoder)
{
assert(decoder);
 
//Noop, for shaders it is much faster to flush everything in end_frame
}
 
static bool
init_pipe_state(struct vl_mpeg12_decoder *dec)
{
struct pipe_depth_stencil_alpha_state dsa;
struct pipe_sampler_state sampler;
unsigned i;
 
assert(dec);
 
memset(&dsa, 0, sizeof dsa);
dsa.depth.enabled = 0;
dsa.depth.writemask = 0;
dsa.depth.func = PIPE_FUNC_ALWAYS;
for (i = 0; i < 2; ++i) {
dsa.stencil[i].enabled = 0;
dsa.stencil[i].func = PIPE_FUNC_ALWAYS;
dsa.stencil[i].fail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[i].zpass_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[i].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[i].valuemask = 0;
dsa.stencil[i].writemask = 0;
}
dsa.alpha.enabled = 0;
dsa.alpha.func = PIPE_FUNC_ALWAYS;
dsa.alpha.ref_value = 0;
dec->dsa = dec->base.context->create_depth_stencil_alpha_state(dec->base.context, &dsa);
dec->base.context->bind_depth_stencil_alpha_state(dec->base.context, dec->dsa);
 
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_BORDER;
sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
sampler.compare_func = PIPE_FUNC_ALWAYS;
sampler.normalized_coords = 1;
dec->sampler_ycbcr = dec->base.context->create_sampler_state(dec->base.context, &sampler);
if (!dec->sampler_ycbcr)
return false;
 
return true;
}
 
static const struct format_config*
find_format_config(struct vl_mpeg12_decoder *dec, const struct format_config configs[], unsigned num_configs)
{
struct pipe_screen *screen;
unsigned i;
 
assert(dec);
 
screen = dec->base.context->screen;
 
for (i = 0; i < num_configs; ++i) {
if (!screen->is_format_supported(screen, configs[i].zscan_source_format, PIPE_TEXTURE_2D,
1, PIPE_BIND_SAMPLER_VIEW))
continue;
 
if (configs[i].idct_source_format != PIPE_FORMAT_NONE) {
if (!screen->is_format_supported(screen, configs[i].idct_source_format, PIPE_TEXTURE_2D,
1, PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET))
continue;
 
if (!screen->is_format_supported(screen, configs[i].mc_source_format, PIPE_TEXTURE_3D,
1, PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET))
continue;
} else {
if (!screen->is_format_supported(screen, configs[i].mc_source_format, PIPE_TEXTURE_2D,
1, PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET))
continue;
}
return &configs[i];
}
 
return NULL;
}
 
static bool
init_zscan(struct vl_mpeg12_decoder *dec, const struct format_config* format_config)
{
unsigned num_channels;
 
assert(dec);
 
dec->zscan_source_format = format_config->zscan_source_format;
dec->zscan_linear = vl_zscan_layout(dec->base.context, vl_zscan_linear, dec->blocks_per_line);
dec->zscan_normal = vl_zscan_layout(dec->base.context, vl_zscan_normal, dec->blocks_per_line);
dec->zscan_alternate = vl_zscan_layout(dec->base.context, vl_zscan_alternate, dec->blocks_per_line);
 
num_channels = dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT ? 4 : 1;
 
if (!vl_zscan_init(&dec->zscan_y, dec->base.context, dec->base.width, dec->base.height,
dec->blocks_per_line, dec->num_blocks, num_channels))
return false;
 
if (!vl_zscan_init(&dec->zscan_c, dec->base.context, dec->chroma_width, dec->chroma_height,
dec->blocks_per_line, dec->num_blocks, num_channels))
return false;
 
return true;
}
 
static bool
init_idct(struct vl_mpeg12_decoder *dec, const struct format_config* format_config)
{
unsigned nr_of_idct_render_targets, max_inst;
enum pipe_format formats[3];
struct pipe_video_buffer templat;
 
struct pipe_sampler_view *matrix = NULL;
 
nr_of_idct_render_targets = dec->base.context->screen->get_param
(
dec->base.context->screen, PIPE_CAP_MAX_RENDER_TARGETS
);
max_inst = dec->base.context->screen->get_shader_param
(
dec->base.context->screen, PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_MAX_INSTRUCTIONS
);
 
// Just assume we need 32 inst per render target, not 100% true, but should work in most cases
if (nr_of_idct_render_targets >= 4 && max_inst >= 32*4)
// more than 4 render targets usually doesn't makes any seens
nr_of_idct_render_targets = 4;
else
nr_of_idct_render_targets = 1;
 
formats[0] = formats[1] = formats[2] = format_config->idct_source_format;
memset(&templat, 0, sizeof(templat));
templat.width = dec->base.width / 4;
templat.height = dec->base.height;
templat.chroma_format = dec->base.chroma_format;
dec->idct_source = vl_video_buffer_create_ex
(
dec->base.context, &templat,
formats, 1, 1, PIPE_USAGE_STATIC
);
 
if (!dec->idct_source)
goto error_idct_source;
 
formats[0] = formats[1] = formats[2] = format_config->mc_source_format;
memset(&templat, 0, sizeof(templat));
templat.width = dec->base.width / nr_of_idct_render_targets;
templat.height = dec->base.height / 4;
templat.chroma_format = dec->base.chroma_format;
dec->mc_source = vl_video_buffer_create_ex
(
dec->base.context, &templat,
formats, nr_of_idct_render_targets, 1, PIPE_USAGE_STATIC
);
 
if (!dec->mc_source)
goto error_mc_source;
 
if (!(matrix = vl_idct_upload_matrix(dec->base.context, format_config->idct_scale)))
goto error_matrix;
 
if (!vl_idct_init(&dec->idct_y, dec->base.context, dec->base.width, dec->base.height,
nr_of_idct_render_targets, matrix, matrix))
goto error_y;
 
if(!vl_idct_init(&dec->idct_c, dec->base.context, dec->chroma_width, dec->chroma_height,
nr_of_idct_render_targets, matrix, matrix))
goto error_c;
 
pipe_sampler_view_reference(&matrix, NULL);
 
return true;
 
error_c:
vl_idct_cleanup(&dec->idct_y);
 
error_y:
pipe_sampler_view_reference(&matrix, NULL);
 
error_matrix:
dec->mc_source->destroy(dec->mc_source);
 
error_mc_source:
dec->idct_source->destroy(dec->idct_source);
 
error_idct_source:
return false;
}
 
static bool
init_mc_source_widthout_idct(struct vl_mpeg12_decoder *dec, const struct format_config* format_config)
{
enum pipe_format formats[3];
struct pipe_video_buffer templat;
 
formats[0] = formats[1] = formats[2] = format_config->mc_source_format;
memset(&templat, 0, sizeof(templat));
templat.width = dec->base.width;
templat.height = dec->base.height;
templat.chroma_format = dec->base.chroma_format;
dec->mc_source = vl_video_buffer_create_ex
(
dec->base.context, &templat,
formats, 1, 1, PIPE_USAGE_STATIC
);
return dec->mc_source != NULL;
}
 
static void
mc_vert_shader_callback(void *priv, struct vl_mc *mc,
struct ureg_program *shader,
unsigned first_output,
struct ureg_dst tex)
{
struct vl_mpeg12_decoder *dec = priv;
struct ureg_dst o_vtex;
 
assert(priv && mc);
assert(shader);
 
if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) {
struct vl_idct *idct = mc == &dec->mc_y ? &dec->idct_y : &dec->idct_c;
vl_idct_stage2_vert_shader(idct, shader, first_output, tex);
} else {
o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, first_output);
ureg_MOV(shader, ureg_writemask(o_vtex, TGSI_WRITEMASK_XY), ureg_src(tex));
}
}
 
static void
mc_frag_shader_callback(void *priv, struct vl_mc *mc,
struct ureg_program *shader,
unsigned first_input,
struct ureg_dst dst)
{
struct vl_mpeg12_decoder *dec = priv;
struct ureg_src src, sampler;
 
assert(priv && mc);
assert(shader);
 
if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) {
struct vl_idct *idct = mc == &dec->mc_y ? &dec->idct_y : &dec->idct_c;
vl_idct_stage2_frag_shader(idct, shader, first_input, dst);
} else {
src = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, first_input, TGSI_INTERPOLATE_LINEAR);
sampler = ureg_DECL_sampler(shader, 0);
ureg_TEX(shader, dst, TGSI_TEXTURE_2D, src, sampler);
}
}
 
struct pipe_video_decoder *
vl_create_mpeg12_decoder(struct pipe_context *context,
enum pipe_video_profile profile,
enum pipe_video_entrypoint entrypoint,
enum pipe_video_chroma_format chroma_format,
unsigned width, unsigned height, unsigned max_references,
bool expect_chunked_decode)
{
const unsigned block_size_pixels = VL_BLOCK_WIDTH * VL_BLOCK_HEIGHT;
const struct format_config *format_config;
struct vl_mpeg12_decoder *dec;
 
assert(u_reduce_video_profile(profile) == PIPE_VIDEO_CODEC_MPEG12);
 
dec = CALLOC_STRUCT(vl_mpeg12_decoder);
 
if (!dec)
return NULL;
 
dec->base.context = context;
dec->base.profile = profile;
dec->base.entrypoint = entrypoint;
dec->base.chroma_format = chroma_format;
dec->base.width = width;
dec->base.height = height;
dec->base.max_references = max_references;
 
dec->base.destroy = vl_mpeg12_destroy;
dec->base.begin_frame = vl_mpeg12_begin_frame;
dec->base.decode_macroblock = vl_mpeg12_decode_macroblock;
dec->base.decode_bitstream = vl_mpeg12_decode_bitstream;
dec->base.end_frame = vl_mpeg12_end_frame;
dec->base.flush = vl_mpeg12_flush;
 
dec->blocks_per_line = MAX2(util_next_power_of_two(dec->base.width) / block_size_pixels, 4);
dec->num_blocks = (dec->base.width * dec->base.height) / block_size_pixels;
dec->width_in_macroblocks = align(dec->base.width, VL_MACROBLOCK_WIDTH) / VL_MACROBLOCK_WIDTH;
dec->expect_chunked_decode = expect_chunked_decode;
 
/* TODO: Implement 422, 444 */
assert(dec->base.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420);
 
if (dec->base.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
dec->chroma_width = dec->base.width / 2;
dec->chroma_height = dec->base.height / 2;
dec->num_blocks = dec->num_blocks * 2;
} else if (dec->base.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) {
dec->chroma_width = dec->base.width;
dec->chroma_height = dec->base.height / 2;
dec->num_blocks = dec->num_blocks * 2 + dec->num_blocks;
} else {
dec->chroma_width = dec->base.width;
dec->chroma_height = dec->base.height;
dec->num_blocks = dec->num_blocks * 3;
}
 
dec->quads = vl_vb_upload_quads(dec->base.context);
dec->pos = vl_vb_upload_pos(
dec->base.context,
dec->base.width / VL_MACROBLOCK_WIDTH,
dec->base.height / VL_MACROBLOCK_HEIGHT
);
 
dec->ves_ycbcr = vl_vb_get_ves_ycbcr(dec->base.context);
dec->ves_mv = vl_vb_get_ves_mv(dec->base.context);
 
switch (entrypoint) {
case PIPE_VIDEO_ENTRYPOINT_BITSTREAM:
format_config = find_format_config(dec, bitstream_format_config, num_bitstream_format_configs);
break;
 
case PIPE_VIDEO_ENTRYPOINT_IDCT:
format_config = find_format_config(dec, idct_format_config, num_idct_format_configs);
break;
 
case PIPE_VIDEO_ENTRYPOINT_MC:
format_config = find_format_config(dec, mc_format_config, num_mc_format_configs);
break;
 
default:
assert(0);
FREE(dec);
return NULL;
}
 
if (!format_config) {
FREE(dec);
return NULL;
}
 
if (!init_zscan(dec, format_config))
goto error_zscan;
 
if (entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) {
if (!init_idct(dec, format_config))
goto error_sources;
} else {
if (!init_mc_source_widthout_idct(dec, format_config))
goto error_sources;
}
 
if (!vl_mc_init(&dec->mc_y, dec->base.context, dec->base.width, dec->base.height,
VL_MACROBLOCK_HEIGHT, format_config->mc_scale,
mc_vert_shader_callback, mc_frag_shader_callback, dec))
goto error_mc_y;
 
// TODO
if (!vl_mc_init(&dec->mc_c, dec->base.context, dec->base.width, dec->base.height,
VL_BLOCK_HEIGHT, format_config->mc_scale,
mc_vert_shader_callback, mc_frag_shader_callback, dec))
goto error_mc_c;
 
if (!init_pipe_state(dec))
goto error_pipe_state;
 
return &dec->base;
 
error_pipe_state:
vl_mc_cleanup(&dec->mc_c);
 
error_mc_c:
vl_mc_cleanup(&dec->mc_y);
 
error_mc_y:
if (entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) {
vl_idct_cleanup(&dec->idct_y);
vl_idct_cleanup(&dec->idct_c);
dec->idct_source->destroy(dec->idct_source);
}
dec->mc_source->destroy(dec->mc_source);
 
error_sources:
vl_zscan_cleanup(&dec->zscan_y);
vl_zscan_cleanup(&dec->zscan_c);
 
error_zscan:
FREE(dec);
return NULL;
}
/drivers/video/Gallium/auxiliary/vl/vl_mpeg12_decoder.h
0,0 → 1,114
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* 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.
*
**************************************************************************/
 
#ifndef vl_mpeg12_decoder_h
#define vl_mpeg12_decoder_h
 
#include "pipe/p_video_decoder.h"
 
#include "vl_mpeg12_bitstream.h"
#include "vl_zscan.h"
#include "vl_idct.h"
#include "vl_mc.h"
 
#include "vl_vertex_buffers.h"
#include "vl_video_buffer.h"
 
struct pipe_screen;
struct pipe_context;
 
struct vl_mpeg12_decoder
{
struct pipe_video_decoder base;
 
unsigned chroma_width, chroma_height;
 
unsigned blocks_per_line;
unsigned num_blocks;
unsigned width_in_macroblocks;
bool expect_chunked_decode;
 
enum pipe_format zscan_source_format;
 
struct pipe_vertex_buffer quads;
struct pipe_vertex_buffer pos;
 
void *ves_ycbcr;
void *ves_mv;
 
void *sampler_ycbcr;
 
struct pipe_sampler_view *zscan_linear;
struct pipe_sampler_view *zscan_normal;
struct pipe_sampler_view *zscan_alternate;
 
struct pipe_video_buffer *idct_source;
struct pipe_video_buffer *mc_source;
 
struct vl_zscan zscan_y, zscan_c;
struct vl_idct idct_y, idct_c;
struct vl_mc mc_y, mc_c;
 
void *dsa;
 
unsigned current_buffer;
struct vl_mpeg12_buffer *dec_buffers[4];
};
 
struct vl_mpeg12_buffer
{
struct vl_vertex_buffer vertex_stream;
 
unsigned block_num;
unsigned num_ycbcr_blocks[3];
 
struct pipe_sampler_view *zscan_source;
 
struct vl_mpg12_bs bs;
struct vl_zscan_buffer zscan[VL_NUM_COMPONENTS];
struct vl_idct_buffer idct[VL_NUM_COMPONENTS];
struct vl_mc_buffer mc[VL_NUM_COMPONENTS];
 
struct pipe_transfer *tex_transfer;
short *texels;
 
struct vl_ycbcr_block *ycbcr_stream[VL_NUM_COMPONENTS];
struct vl_motionvector *mv_stream[VL_MAX_REF_FRAMES];
};
 
/**
* creates a shader based mpeg12 decoder
*/
struct pipe_video_decoder *
vl_create_mpeg12_decoder(struct pipe_context *pipe,
enum pipe_video_profile profile,
enum pipe_video_entrypoint entrypoint,
enum pipe_video_chroma_format chroma_format,
unsigned width, unsigned height, unsigned max_references,
bool expect_chunked_decode);
 
#endif /* vl_mpeg12_decoder_h */
/drivers/video/Gallium/auxiliary/vl/vl_types.h
0,0 → 1,51
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* 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.
*
**************************************************************************/
 
#ifndef vl_types_h
#define vl_types_h
 
struct vertex2f
{
float x, y;
};
 
struct vertex2s
{
short x, y;
};
 
struct vertex4f
{
float x, y, z, w;
};
 
struct vertex4s
{
short x, y, z, w;
};
 
#endif /* vl_types_h */
/drivers/video/Gallium/auxiliary/vl/vl_vertex_buffers.c
0,0 → 1,378
/**************************************************************************
*
* Copyright 2010 Christian König
* 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.
*
**************************************************************************/
 
#include <assert.h>
#include "util/u_format.h"
#include "vl_vertex_buffers.h"
#include "vl_types.h"
 
/* vertices for a quad covering a block */
static const struct vertex2f block_quad[4] = {
{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}
};
 
struct pipe_vertex_buffer
vl_vb_upload_quads(struct pipe_context *pipe)
{
struct pipe_vertex_buffer quad;
struct pipe_transfer *buf_transfer;
struct vertex2f *v;
 
unsigned i;
 
assert(pipe);
 
/* create buffer */
quad.stride = sizeof(struct vertex2f);
quad.buffer_offset = 0;
quad.buffer = pipe_buffer_create
(
pipe->screen,
PIPE_BIND_VERTEX_BUFFER,
PIPE_USAGE_STATIC,
sizeof(struct vertex2f) * 4
);
quad.user_buffer = NULL;
 
if(!quad.buffer)
return quad;
 
/* and fill it */
v = pipe_buffer_map
(
pipe,
quad.buffer,
PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE,
&buf_transfer
);
 
for (i = 0; i < 4; ++i, ++v) {
v->x = block_quad[i].x;
v->y = block_quad[i].y;
}
 
pipe_buffer_unmap(pipe, buf_transfer);
 
return quad;
}
 
struct pipe_vertex_buffer
vl_vb_upload_pos(struct pipe_context *pipe, unsigned width, unsigned height)
{
struct pipe_vertex_buffer pos;
struct pipe_transfer *buf_transfer;
struct vertex2s *v;
 
unsigned x, y;
 
assert(pipe);
 
/* create buffer */
pos.stride = sizeof(struct vertex2s);
pos.buffer_offset = 0;
pos.buffer = pipe_buffer_create
(
pipe->screen,
PIPE_BIND_VERTEX_BUFFER,
PIPE_USAGE_STATIC,
sizeof(struct vertex2s) * width * height
);
pos.user_buffer = NULL;
 
if(!pos.buffer)
return pos;
 
/* and fill it */
v = pipe_buffer_map
(
pipe,
pos.buffer,
PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE,
&buf_transfer
);
 
for ( y = 0; y < height; ++y) {
for ( x = 0; x < width; ++x, ++v) {
v->x = x;
v->y = y;
}
}
 
pipe_buffer_unmap(pipe, buf_transfer);
 
return pos;
}
 
static struct pipe_vertex_element
vl_vb_get_quad_vertex_element(void)
{
struct pipe_vertex_element element;
 
/* setup rectangle element */
element.src_offset = 0;
element.instance_divisor = 0;
element.vertex_buffer_index = 0;
element.src_format = PIPE_FORMAT_R32G32_FLOAT;
 
return element;
}
 
static void
vl_vb_element_helper(struct pipe_vertex_element* elements, unsigned num_elements,
unsigned vertex_buffer_index)
{
unsigned i, offset = 0;
 
assert(elements && num_elements);
 
for ( i = 0; i < num_elements; ++i ) {
elements[i].src_offset = offset;
elements[i].instance_divisor = 1;
elements[i].vertex_buffer_index = vertex_buffer_index;
offset += util_format_get_blocksize(elements[i].src_format);
}
}
 
void *
vl_vb_get_ves_ycbcr(struct pipe_context *pipe)
{
struct pipe_vertex_element vertex_elems[NUM_VS_INPUTS];
 
assert(pipe);
 
memset(&vertex_elems, 0, sizeof(vertex_elems));
vertex_elems[VS_I_RECT] = vl_vb_get_quad_vertex_element();
 
/* Position element */
vertex_elems[VS_I_VPOS].src_format = PIPE_FORMAT_R8G8B8A8_USCALED;
 
/* block num element */
vertex_elems[VS_I_BLOCK_NUM].src_format = PIPE_FORMAT_R32_FLOAT;
 
vl_vb_element_helper(&vertex_elems[VS_I_VPOS], 2, 1);
 
return pipe->create_vertex_elements_state(pipe, 3, vertex_elems);
}
 
void *
vl_vb_get_ves_mv(struct pipe_context *pipe)
{
struct pipe_vertex_element vertex_elems[NUM_VS_INPUTS];
 
assert(pipe);
 
memset(&vertex_elems, 0, sizeof(vertex_elems));
vertex_elems[VS_I_RECT] = vl_vb_get_quad_vertex_element();
 
/* Position element */
vertex_elems[VS_I_VPOS].src_format = PIPE_FORMAT_R16G16_SSCALED;
 
vl_vb_element_helper(&vertex_elems[VS_I_VPOS], 1, 1);
 
/* motion vector TOP element */
vertex_elems[VS_I_MV_TOP].src_format = PIPE_FORMAT_R16G16B16A16_SSCALED;
 
/* motion vector BOTTOM element */
vertex_elems[VS_I_MV_BOTTOM].src_format = PIPE_FORMAT_R16G16B16A16_SSCALED;
 
vl_vb_element_helper(&vertex_elems[VS_I_MV_TOP], 2, 2);
 
return pipe->create_vertex_elements_state(pipe, NUM_VS_INPUTS, vertex_elems);
}
 
bool
vl_vb_init(struct vl_vertex_buffer *buffer, struct pipe_context *pipe,
unsigned width, unsigned height)
{
unsigned i, size;
 
assert(buffer);
 
buffer->width = width;
buffer->height = height;
 
size = width * height;
 
for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
buffer->ycbcr[i].resource = pipe_buffer_create
(
pipe->screen,
PIPE_BIND_VERTEX_BUFFER,
PIPE_USAGE_STREAM,
sizeof(struct vl_ycbcr_block) * size * 4
);
if (!buffer->ycbcr[i].resource)
goto error_ycbcr;
}
 
for (i = 0; i < VL_MAX_REF_FRAMES; ++i) {
buffer->mv[i].resource = pipe_buffer_create
(
pipe->screen,
PIPE_BIND_VERTEX_BUFFER,
PIPE_USAGE_STREAM,
sizeof(struct vl_motionvector) * size
);
if (!buffer->mv[i].resource)
goto error_mv;
}
 
vl_vb_map(buffer, pipe);
return true;
 
error_mv:
for (i = 0; i < VL_NUM_COMPONENTS; ++i)
pipe_resource_reference(&buffer->mv[i].resource, NULL);
 
error_ycbcr:
for (i = 0; i < VL_NUM_COMPONENTS; ++i)
pipe_resource_reference(&buffer->ycbcr[i].resource, NULL);
return false;
}
 
unsigned
vl_vb_attributes_per_plock(struct vl_vertex_buffer *buffer)
{
return 1;
}
 
struct pipe_vertex_buffer
vl_vb_get_ycbcr(struct vl_vertex_buffer *buffer, int component)
{
struct pipe_vertex_buffer buf;
 
assert(buffer);
 
buf.stride = sizeof(struct vl_ycbcr_block);
buf.buffer_offset = 0;
buf.buffer = buffer->ycbcr[component].resource;
buf.user_buffer = NULL;
 
return buf;
}
 
struct pipe_vertex_buffer
vl_vb_get_mv(struct vl_vertex_buffer *buffer, int motionvector)
{
struct pipe_vertex_buffer buf;
 
assert(buffer);
 
buf.stride = sizeof(struct vl_motionvector);
buf.buffer_offset = 0;
buf.buffer = buffer->mv[motionvector].resource;
buf.user_buffer = NULL;
 
return buf;
}
 
void
vl_vb_map(struct vl_vertex_buffer *buffer, struct pipe_context *pipe)
{
unsigned i;
 
assert(buffer && pipe);
 
for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
buffer->ycbcr[i].vertex_stream = pipe_buffer_map
(
pipe,
buffer->ycbcr[i].resource,
PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE,
&buffer->ycbcr[i].transfer
);
}
 
for (i = 0; i < VL_MAX_REF_FRAMES; ++i) {
buffer->mv[i].vertex_stream = pipe_buffer_map
(
pipe,
buffer->mv[i].resource,
PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE,
&buffer->mv[i].transfer
);
}
 
}
 
struct vl_ycbcr_block *
vl_vb_get_ycbcr_stream(struct vl_vertex_buffer *buffer, int component)
{
assert(buffer);
assert(component < VL_NUM_COMPONENTS);
 
return buffer->ycbcr[component].vertex_stream;
}
 
unsigned
vl_vb_get_mv_stream_stride(struct vl_vertex_buffer *buffer)
{
assert(buffer);
 
return buffer->width;
}
 
struct vl_motionvector *
vl_vb_get_mv_stream(struct vl_vertex_buffer *buffer, int ref_frame)
{
assert(buffer);
assert(ref_frame < VL_MAX_REF_FRAMES);
 
return buffer->mv[ref_frame].vertex_stream;
}
 
void
vl_vb_unmap(struct vl_vertex_buffer *buffer, struct pipe_context *pipe)
{
unsigned i;
 
assert(buffer && pipe);
 
for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
pipe_buffer_unmap(pipe, buffer->ycbcr[i].transfer);
}
 
for (i = 0; i < VL_MAX_REF_FRAMES; ++i) {
pipe_buffer_unmap(pipe, buffer->mv[i].transfer);
}
}
 
void
vl_vb_cleanup(struct vl_vertex_buffer *buffer)
{
unsigned i;
 
assert(buffer);
 
for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
pipe_resource_reference(&buffer->ycbcr[i].resource, NULL);
}
 
for (i = 0; i < VL_MAX_REF_FRAMES; ++i) {
pipe_resource_reference(&buffer->mv[i].resource, NULL);
}
}
/drivers/video/Gallium/auxiliary/vl/vl_vertex_buffers.h
0,0 → 1,138
/**************************************************************************
*
* Copyright 2010 Christian König
* 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.
*
**************************************************************************/
#ifndef vl_vertex_buffers_h
#define vl_vertex_buffers_h
 
#include "pipe/p_state.h"
#include "pipe/p_video_state.h"
 
#include "vl_defines.h"
#include "vl_types.h"
 
/* vertex buffers act as a todo list
* uploading all the usefull informations to video ram
* so a vertex shader can work with them
*/
 
/* inputs to the vertex shaders */
enum VS_INPUT
{
VS_I_RECT = 0,
VS_I_VPOS = 1,
 
VS_I_BLOCK_NUM = 2,
 
VS_I_MV_TOP = 2,
VS_I_MV_BOTTOM = 3,
 
NUM_VS_INPUTS = 4
};
 
enum vl_mv_weight
{
PIPE_VIDEO_MV_WEIGHT_MIN = 0,
PIPE_VIDEO_MV_WEIGHT_HALF = 128,
PIPE_VIDEO_MV_WEIGHT_MAX = 256
};
 
enum vl_field_select
{
PIPE_VIDEO_FRAME = 0,
PIPE_VIDEO_TOP_FIELD = 1,
PIPE_VIDEO_BOTTOM_FIELD = 3,
 
/* TODO
PIPE_VIDEO_DUALPRIME
PIPE_VIDEO_16x8
*/
};
 
struct vl_motionvector
{
struct {
int16_t x, y;
int16_t field_select; /**< enum pipe_video_field_select */
int16_t weight; /**< enum pipe_video_mv_weight */
} top, bottom;
};
 
struct vl_ycbcr_block
{
uint8_t x, y;
uint8_t intra;
uint8_t coding;
float block_num;
};
 
struct vl_vertex_buffer
{
unsigned width, height;
 
struct {
struct pipe_resource *resource;
struct pipe_transfer *transfer;
struct vl_ycbcr_block *vertex_stream;
} ycbcr[VL_NUM_COMPONENTS];
 
struct {
struct pipe_resource *resource;
struct pipe_transfer *transfer;
struct vl_motionvector *vertex_stream;
} mv[VL_MAX_REF_FRAMES];
};
 
struct pipe_vertex_buffer vl_vb_upload_quads(struct pipe_context *pipe);
 
struct pipe_vertex_buffer vl_vb_upload_pos(struct pipe_context *pipe, unsigned width, unsigned height);
 
void *vl_vb_get_ves_ycbcr(struct pipe_context *pipe);
 
void *vl_vb_get_ves_mv(struct pipe_context *pipe);
 
bool vl_vb_init(struct vl_vertex_buffer *buffer,
struct pipe_context *pipe,
unsigned width, unsigned height);
 
unsigned vl_vb_attributes_per_plock(struct vl_vertex_buffer *buffer);
 
void vl_vb_map(struct vl_vertex_buffer *buffer, struct pipe_context *pipe);
 
struct pipe_vertex_buffer vl_vb_get_ycbcr(struct vl_vertex_buffer *buffer, int component);
 
struct vl_ycbcr_block *vl_vb_get_ycbcr_stream(struct vl_vertex_buffer *buffer, int component);
 
struct pipe_vertex_buffer vl_vb_get_mv(struct vl_vertex_buffer *buffer, int ref_frame);
 
unsigned vl_vb_get_mv_stream_stride(struct vl_vertex_buffer *buffer);
 
struct vl_motionvector *vl_vb_get_mv_stream(struct vl_vertex_buffer *buffer, int ref_frame);
 
void vl_vb_unmap(struct vl_vertex_buffer *buffer, struct pipe_context *pipe);
 
void vl_vb_cleanup(struct vl_vertex_buffer *buffer);
 
#endif /* vl_vertex_buffers_h */
/drivers/video/Gallium/auxiliary/vl/vl_video_buffer.c
0,0 → 1,509
/**************************************************************************
*
* Copyright 2011 Christian König.
* 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.
*
**************************************************************************/
 
#include <assert.h>
 
#include "pipe/p_screen.h"
#include "pipe/p_context.h"
#include "pipe/p_state.h"
 
#include "util/u_format.h"
#include "util/u_inlines.h"
#include "util/u_sampler.h"
#include "util/u_memory.h"
 
#include "vl_video_buffer.h"
 
const enum pipe_format const_resource_formats_YV12[3] = {
PIPE_FORMAT_R8_UNORM,
PIPE_FORMAT_R8_UNORM,
PIPE_FORMAT_R8_UNORM
};
 
const enum pipe_format const_resource_formats_NV12[3] = {
PIPE_FORMAT_R8_UNORM,
PIPE_FORMAT_R8G8_UNORM,
PIPE_FORMAT_NONE
};
 
const enum pipe_format const_resource_formats_YUVA[3] = {
PIPE_FORMAT_R8G8B8A8_UNORM,
PIPE_FORMAT_NONE,
PIPE_FORMAT_NONE
};
 
const enum pipe_format const_resource_formats_VUYA[3] = {
PIPE_FORMAT_B8G8R8A8_UNORM,
PIPE_FORMAT_NONE,
PIPE_FORMAT_NONE
};
 
const enum pipe_format const_resource_formats_YUYV[3] = {
PIPE_FORMAT_R8G8_R8B8_UNORM,
PIPE_FORMAT_NONE,
PIPE_FORMAT_NONE
};
 
const enum pipe_format const_resource_formats_UYVY[3] = {
PIPE_FORMAT_G8R8_B8R8_UNORM,
PIPE_FORMAT_NONE,
PIPE_FORMAT_NONE
};
 
const unsigned const_resource_plane_order_YUV[3] = {
0,
1,
2
};
 
const unsigned const_resource_plane_order_YVU[3] = {
0,
2,
1
};
 
const enum pipe_format *
vl_video_buffer_formats(struct pipe_screen *screen, enum pipe_format format)
{
switch(format) {
case PIPE_FORMAT_YV12:
return const_resource_formats_YV12;
 
case PIPE_FORMAT_NV12:
return const_resource_formats_NV12;
 
case PIPE_FORMAT_R8G8B8A8_UNORM:
return const_resource_formats_YUVA;
 
case PIPE_FORMAT_B8G8R8A8_UNORM:
return const_resource_formats_VUYA;
 
case PIPE_FORMAT_YUYV:
return const_resource_formats_YUYV;
 
case PIPE_FORMAT_UYVY:
return const_resource_formats_UYVY;
 
default:
return NULL;
}
}
 
const unsigned *
vl_video_buffer_plane_order(enum pipe_format format)
{
switch(format) {
case PIPE_FORMAT_YV12:
return const_resource_plane_order_YVU;
 
case PIPE_FORMAT_NV12:
case PIPE_FORMAT_R8G8B8A8_UNORM:
case PIPE_FORMAT_B8G8R8A8_UNORM:
case PIPE_FORMAT_YUYV:
case PIPE_FORMAT_UYVY:
return const_resource_plane_order_YUV;
 
default:
return NULL;
}
}
 
static enum pipe_format
vl_video_buffer_surface_format(enum pipe_format format)
{
const struct util_format_description *desc = util_format_description(format);
 
/* a subsampled formats can't work as surface use RGBA instead */
if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED)
return PIPE_FORMAT_R8G8B8A8_UNORM;
 
return format;
}
 
boolean
vl_video_buffer_is_format_supported(struct pipe_screen *screen,
enum pipe_format format,
enum pipe_video_profile profile)
{
const enum pipe_format *resource_formats;
unsigned i;
 
resource_formats = vl_video_buffer_formats(screen, format);
if (!resource_formats)
return false;
 
for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
enum pipe_format format = resource_formats[i];
 
if (format == PIPE_FORMAT_NONE)
continue;
 
/* we at least need to sample from it */
if (!screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW))
return false;
 
format = vl_video_buffer_surface_format(format);
if (!screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET))
return false;
}
 
return true;
}
 
unsigned
vl_video_buffer_max_size(struct pipe_screen *screen)
{
uint32_t max_2d_texture_level;
 
max_2d_texture_level = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
 
return 1 << (max_2d_texture_level-1);
}
 
void
vl_video_buffer_set_associated_data(struct pipe_video_buffer *vbuf,
struct pipe_video_decoder *vdec,
void *associated_data,
void (*destroy_associated_data)(void *))
{
vbuf->decoder = vdec;
 
if (vbuf->associated_data == associated_data)
return;
 
if (vbuf->associated_data)
vbuf->destroy_associated_data(vbuf->associated_data);
 
vbuf->associated_data = associated_data;
vbuf->destroy_associated_data = destroy_associated_data;
}
 
void *
vl_video_buffer_get_associated_data(struct pipe_video_buffer *vbuf,
struct pipe_video_decoder *vdec)
{
if (vbuf->decoder == vdec)
return vbuf->associated_data;
else
return NULL;
}
 
void
vl_video_buffer_template(struct pipe_resource *templ,
const struct pipe_video_buffer *tmpl,
enum pipe_format resource_format,
unsigned depth, unsigned array_size,
unsigned usage, unsigned plane)
{
memset(templ, 0, sizeof(*templ));
if (depth > 1)
templ->target = PIPE_TEXTURE_3D;
else if (array_size > 1)
templ->target = PIPE_TEXTURE_2D_ARRAY;
else
templ->target = PIPE_TEXTURE_2D;
templ->format = resource_format;
templ->width0 = tmpl->width;
templ->height0 = tmpl->height;
templ->depth0 = depth;
templ->array_size = array_size;
templ->bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
templ->usage = usage;
 
if (plane > 0) {
if (tmpl->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
templ->width0 /= 2;
templ->height0 /= 2;
} else if (tmpl->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) {
templ->height0 /= 2;
}
}
}
 
static void
vl_video_buffer_destroy(struct pipe_video_buffer *buffer)
{
struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
unsigned i;
 
assert(buf);
 
for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
pipe_resource_reference(&buf->resources[i], NULL);
}
 
for (i = 0; i < VL_NUM_COMPONENTS * 2; ++i)
pipe_surface_reference(&buf->surfaces[i], NULL);
 
vl_video_buffer_set_associated_data(buffer, NULL, NULL, NULL);
 
FREE(buffer);
}
 
static struct pipe_sampler_view **
vl_video_buffer_sampler_view_planes(struct pipe_video_buffer *buffer)
{
struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
struct pipe_sampler_view sv_templ;
struct pipe_context *pipe;
unsigned i;
 
assert(buf);
 
pipe = buf->base.context;
 
for (i = 0; i < buf->num_planes; ++i ) {
if (!buf->sampler_view_planes[i]) {
memset(&sv_templ, 0, sizeof(sv_templ));
u_sampler_view_default_template(&sv_templ, buf->resources[i], buf->resources[i]->format);
 
if (util_format_get_nr_components(buf->resources[i]->format) == 1)
sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = sv_templ.swizzle_a = PIPE_SWIZZLE_RED;
 
buf->sampler_view_planes[i] = pipe->create_sampler_view(pipe, buf->resources[i], &sv_templ);
if (!buf->sampler_view_planes[i])
goto error;
}
}
 
return buf->sampler_view_planes;
 
error:
for (i = 0; i < buf->num_planes; ++i )
pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
 
return NULL;
}
 
static struct pipe_sampler_view **
vl_video_buffer_sampler_view_components(struct pipe_video_buffer *buffer)
{
struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
struct pipe_sampler_view sv_templ;
struct pipe_context *pipe;
const enum pipe_format *sampler_format;
const unsigned *plane_order;
unsigned i, j, component;
 
assert(buf);
 
pipe = buf->base.context;
 
sampler_format = vl_video_buffer_formats(pipe->screen, buf->base.buffer_format);
plane_order = vl_video_buffer_plane_order(buf->base.buffer_format);
 
for (component = 0, i = 0; i < buf->num_planes; ++i ) {
struct pipe_resource *res = buf->resources[plane_order[i]];
const struct util_format_description *desc = util_format_description(res->format);
unsigned nr_components = util_format_get_nr_components(res->format);
if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED)
nr_components = 3;
 
for (j = 0; j < nr_components && component < VL_NUM_COMPONENTS; ++j, ++component) {
if (buf->sampler_view_components[component])
continue;
 
memset(&sv_templ, 0, sizeof(sv_templ));
u_sampler_view_default_template(&sv_templ, res, sampler_format[plane_order[i]]);
sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = PIPE_SWIZZLE_RED + j;
sv_templ.swizzle_a = PIPE_SWIZZLE_ONE;
buf->sampler_view_components[component] = pipe->create_sampler_view(pipe, res, &sv_templ);
if (!buf->sampler_view_components[component])
goto error;
}
}
assert(component == VL_NUM_COMPONENTS);
 
return buf->sampler_view_components;
 
error:
for (i = 0; i < VL_NUM_COMPONENTS; ++i )
pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
 
return NULL;
}
 
static struct pipe_surface **
vl_video_buffer_surfaces(struct pipe_video_buffer *buffer)
{
struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
struct pipe_surface surf_templ;
struct pipe_context *pipe;
unsigned i, j, array_size, surf;
 
assert(buf);
 
pipe = buf->base.context;
 
array_size = buffer->interlaced ? 2 : 1;
for (i = 0, surf = 0; i < VL_NUM_COMPONENTS; ++i) {
for (j = 0; j < array_size; ++j, ++surf) {
assert(surf < (VL_NUM_COMPONENTS * 2));
 
if (!buf->resources[i]) {
pipe_surface_reference(&buf->surfaces[surf], NULL);
continue;
}
 
if (!buf->surfaces[surf]) {
memset(&surf_templ, 0, sizeof(surf_templ));
surf_templ.format = vl_video_buffer_surface_format(buf->resources[i]->format);
surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = j;
buf->surfaces[surf] = pipe->create_surface(pipe, buf->resources[i], &surf_templ);
if (!buf->surfaces[surf])
goto error;
}
}
}
 
return buf->surfaces;
 
error:
for (i = 0; i < (VL_NUM_COMPONENTS * 2); ++i )
pipe_surface_reference(&buf->surfaces[i], NULL);
 
return NULL;
}
 
struct pipe_video_buffer *
vl_video_buffer_create(struct pipe_context *pipe,
const struct pipe_video_buffer *tmpl)
{
const enum pipe_format *resource_formats;
struct pipe_video_buffer templat, *result;
bool pot_buffers;
 
assert(pipe);
assert(tmpl->width > 0 && tmpl->height > 0);
 
pot_buffers = !pipe->screen->get_video_param
(
pipe->screen,
PIPE_VIDEO_PROFILE_UNKNOWN,
PIPE_VIDEO_CAP_NPOT_TEXTURES
);
 
resource_formats = vl_video_buffer_formats(pipe->screen, tmpl->buffer_format);
if (!resource_formats)
return NULL;
 
templat = *tmpl;
templat.width = pot_buffers ? util_next_power_of_two(tmpl->width)
: align(tmpl->width, VL_MACROBLOCK_WIDTH);
templat.height = pot_buffers ? util_next_power_of_two(tmpl->height)
: align(tmpl->height, VL_MACROBLOCK_HEIGHT);
 
if (tmpl->interlaced)
templat.height /= 2;
 
result = vl_video_buffer_create_ex
(
pipe, &templat, resource_formats,
1, tmpl->interlaced ? 2 : 1, PIPE_USAGE_STATIC
);
 
 
if (result && tmpl->interlaced)
result->height *= 2;
 
return result;
}
 
struct pipe_video_buffer *
vl_video_buffer_create_ex(struct pipe_context *pipe,
const struct pipe_video_buffer *tmpl,
const enum pipe_format resource_formats[VL_NUM_COMPONENTS],
unsigned depth, unsigned array_size, unsigned usage)
{
struct pipe_resource res_tmpl;
struct pipe_resource *resources[VL_NUM_COMPONENTS];
unsigned i;
 
assert(pipe);
 
memset(resources, 0, sizeof resources);
 
vl_video_buffer_template(&res_tmpl, tmpl, resource_formats[0], depth, array_size, usage, 0);
resources[0] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
if (!resources[0])
goto error;
 
if (resource_formats[1] == PIPE_FORMAT_NONE) {
assert(resource_formats[2] == PIPE_FORMAT_NONE);
return vl_video_buffer_create_ex2(pipe, tmpl, resources);
}
 
vl_video_buffer_template(&res_tmpl, tmpl, resource_formats[1], depth, array_size, usage, 1);
resources[1] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
if (!resources[1])
goto error;
 
if (resource_formats[2] == PIPE_FORMAT_NONE)
return vl_video_buffer_create_ex2(pipe, tmpl, resources);
 
vl_video_buffer_template(&res_tmpl, tmpl, resource_formats[2], depth, array_size, usage, 2);
resources[2] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
if (!resources[2])
goto error;
 
return vl_video_buffer_create_ex2(pipe, tmpl, resources);
 
error:
for (i = 0; i < VL_NUM_COMPONENTS; ++i)
pipe_resource_reference(&resources[i], NULL);
 
return NULL;
}
 
struct pipe_video_buffer *
vl_video_buffer_create_ex2(struct pipe_context *pipe,
const struct pipe_video_buffer *tmpl,
struct pipe_resource *resources[VL_NUM_COMPONENTS])
{
struct vl_video_buffer *buffer;
unsigned i;
 
buffer = CALLOC_STRUCT(vl_video_buffer);
 
buffer->base = *tmpl;
buffer->base.context = pipe;
buffer->base.destroy = vl_video_buffer_destroy;
buffer->base.get_sampler_view_planes = vl_video_buffer_sampler_view_planes;
buffer->base.get_sampler_view_components = vl_video_buffer_sampler_view_components;
buffer->base.get_surfaces = vl_video_buffer_surfaces;
buffer->num_planes = 0;
 
for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
buffer->resources[i] = resources[i];
if (resources[i])
buffer->num_planes++;
}
 
return &buffer->base;
}
/drivers/video/Gallium/auxiliary/vl/vl_video_buffer.h
0,0 → 1,128
/**************************************************************************
*
* Copyright 2011 Christian König.
* 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.
*
**************************************************************************/
 
#ifndef vl_video_buffer_h
#define vl_video_buffer_h
 
#include "pipe/p_context.h"
#include "pipe/p_video_decoder.h"
 
#include "vl_defines.h"
 
/**
* implementation of a planar ycbcr buffer
*/
 
/* planar buffer for vl data upload and manipulation */
struct vl_video_buffer
{
struct pipe_video_buffer base;
unsigned num_planes;
struct pipe_resource *resources[VL_NUM_COMPONENTS];
struct pipe_sampler_view *sampler_view_planes[VL_NUM_COMPONENTS];
struct pipe_sampler_view *sampler_view_components[VL_NUM_COMPONENTS];
struct pipe_surface *surfaces[VL_MAX_SURFACES];
};
 
/**
* get subformats for each plane
*/
const enum pipe_format *
vl_video_buffer_formats(struct pipe_screen *screen, enum pipe_format format);
 
/**
* get YUV plane order
*/
const unsigned *
vl_video_buffer_plane_order(enum pipe_format format);
 
/**
* get maximum size of video buffers
*/
unsigned
vl_video_buffer_max_size(struct pipe_screen *screen);
 
/**
* check if video buffer format is supported for a codec/profile
* can be used as default implementation of screen->is_video_format_supported
*/
boolean
vl_video_buffer_is_format_supported(struct pipe_screen *screen,
enum pipe_format format,
enum pipe_video_profile profile);
 
/*
* set the associated data for the given video buffer
*/
void
vl_video_buffer_set_associated_data(struct pipe_video_buffer *vbuf,
struct pipe_video_decoder *vdec,
void *associated_data,
void (*destroy_associated_data)(void *));
 
/*
* get the associated data for the given video buffer
*/
void *
vl_video_buffer_get_associated_data(struct pipe_video_buffer *vbuf,
struct pipe_video_decoder *vdec);
 
/**
* fill a resource template for the given plane
*/
void
vl_video_buffer_template(struct pipe_resource *templ,
const struct pipe_video_buffer *templat,
enum pipe_format resource_format,
unsigned depth, unsigned array_size,
unsigned usage, unsigned plane);
 
/**
* creates a video buffer, can be used as a standard implementation for pipe->create_video_buffer
*/
struct pipe_video_buffer *
vl_video_buffer_create(struct pipe_context *pipe,
const struct pipe_video_buffer *templat);
 
/**
* extended create function, gets depth, array_size, usage and formats for each plane seperately
*/
struct pipe_video_buffer *
vl_video_buffer_create_ex(struct pipe_context *pipe,
const struct pipe_video_buffer *templat,
const enum pipe_format resource_formats[VL_NUM_COMPONENTS],
unsigned depth, unsigned array_size, unsigned usage);
 
/**
* even more extended create function, provide the pipe_resource for each plane
*/
struct pipe_video_buffer *
vl_video_buffer_create_ex2(struct pipe_context *pipe,
const struct pipe_video_buffer *templat,
struct pipe_resource *resources[VL_NUM_COMPONENTS]);
 
#endif /* vl_video_buffer_h */
/drivers/video/Gallium/auxiliary/vl/vl_vlc.h
0,0 → 1,277
/**************************************************************************
*
* Copyright 2011 Christian König.
* 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.
*
**************************************************************************/
 
/*
* Functions for fast bitwise access to multiple probably unaligned input buffers
*/
 
#ifndef vl_vlc_h
#define vl_vlc_h
 
#include "pipe/p_compiler.h"
 
#include "util/u_math.h"
#include "util/u_pointer.h"
#include "util/u_debug.h"
 
struct vl_vlc
{
uint64_t buffer;
signed invalid_bits;
const uint8_t *data;
const uint8_t *end;
 
unsigned num_inputs;
const void *const *inputs;
const unsigned *sizes;
unsigned bytes_left;
};
 
struct vl_vlc_entry
{
int8_t length;
int8_t value;
};
 
struct vl_vlc_compressed
{
uint16_t bitcode;
struct vl_vlc_entry entry;
};
 
/**
* initalize and decompress a lookup table
*/
static INLINE void
vl_vlc_init_table(struct vl_vlc_entry *dst, unsigned dst_size, const struct vl_vlc_compressed *src, unsigned src_size)
{
unsigned i, bits = util_logbase2(dst_size);
 
assert(dst && dst_size);
assert(src && src_size);
 
for (i=0;i<dst_size;++i) {
dst[i].length = 0;
dst[i].value = 0;
}
 
for(; src_size > 0; --src_size, ++src) {
for(i=0; i<(1 << (bits - src->entry.length)); ++i)
dst[src->bitcode >> (16 - bits) | i] = src->entry;
}
}
 
/**
* switch over to next input buffer
*/
static INLINE void
vl_vlc_next_input(struct vl_vlc *vlc)
{
const uint8_t* data = vlc->inputs[0];
unsigned len = vlc->sizes[0];
 
assert(vlc);
assert(vlc->num_inputs);
 
vlc->bytes_left -= len;
 
/* align the data pointer */
while (len && pointer_to_uintptr(data) & 3) {
vlc->buffer |= (uint64_t)*data << (24 + vlc->invalid_bits);
++data;
--len;
vlc->invalid_bits -= 8;
}
vlc->data = data;
vlc->end = data + len;
 
--vlc->num_inputs;
++vlc->inputs;
++vlc->sizes;
}
 
/**
* fill the bit buffer, so that at least 32 bits are valid
*/
static INLINE void
vl_vlc_fillbits(struct vl_vlc *vlc)
{
assert(vlc);
 
/* as long as the buffer needs to be filled */
while (vlc->invalid_bits > 0) {
unsigned bytes_left = vlc->end - vlc->data;
 
/* if this input is depleted */
if (bytes_left == 0) {
 
if (vlc->num_inputs)
/* go on to next input */
vl_vlc_next_input(vlc);
else
/* or give up since we don't have anymore inputs */
return;
 
} else if (bytes_left >= 4) {
 
/* enough bytes in buffer, read in a whole dword */
uint64_t value = *(const uint32_t*)vlc->data;
 
#ifndef PIPE_ARCH_BIG_ENDIAN
value = util_bswap32(value);
#endif
 
vlc->buffer |= value << vlc->invalid_bits;
vlc->data += 4;
vlc->invalid_bits -= 32;
 
/* buffer is now definitely filled up avoid the loop test */
break;
 
} else while (vlc->data < vlc->end) {
 
/* not enough bytes left in buffer, read single bytes */
vlc->buffer |= (uint64_t)*vlc->data << (24 + vlc->invalid_bits);
++vlc->data;
vlc->invalid_bits -= 8;
}
}
}
 
/**
* initialize vlc structure and start reading from first input buffer
*/
static INLINE void
vl_vlc_init(struct vl_vlc *vlc, unsigned num_inputs,
const void *const *inputs, const unsigned *sizes)
{
unsigned i;
 
assert(vlc);
assert(num_inputs);
 
vlc->buffer = 0;
vlc->invalid_bits = 32;
vlc->num_inputs = num_inputs;
vlc->inputs = inputs;
vlc->sizes = sizes;
vlc->bytes_left = 0;
 
for (i = 0; i < num_inputs; ++i)
vlc->bytes_left += sizes[i];
 
vl_vlc_next_input(vlc);
vl_vlc_fillbits(vlc);
vl_vlc_fillbits(vlc);
}
 
/**
* number of bits still valid in bit buffer
*/
static INLINE unsigned
vl_vlc_valid_bits(struct vl_vlc *vlc)
{
return 32 - vlc->invalid_bits;
}
 
/**
* number of bits left over all inbut buffers
*/
static INLINE unsigned
vl_vlc_bits_left(struct vl_vlc *vlc)
{
signed bytes_left = vlc->end - vlc->data;
bytes_left += vlc->bytes_left;
return bytes_left * 8 + vl_vlc_valid_bits(vlc);
}
 
/**
* get num_bits from bit buffer without removing them
*/
static INLINE unsigned
vl_vlc_peekbits(struct vl_vlc *vlc, unsigned num_bits)
{
assert(vl_vlc_valid_bits(vlc) >= num_bits || vlc->data >= vlc->end);
return vlc->buffer >> (64 - num_bits);
}
 
/**
* remove num_bits from bit buffer
*/
static INLINE void
vl_vlc_eatbits(struct vl_vlc *vlc, unsigned num_bits)
{
assert(vl_vlc_valid_bits(vlc) >= num_bits);
 
vlc->buffer <<= num_bits;
vlc->invalid_bits += num_bits;
}
 
/**
* get num_bits from bit buffer with removing them
*/
static INLINE unsigned
vl_vlc_get_uimsbf(struct vl_vlc *vlc, unsigned num_bits)
{
unsigned value;
 
assert(vl_vlc_valid_bits(vlc) >= num_bits);
 
value = vlc->buffer >> (64 - num_bits);
vl_vlc_eatbits(vlc, num_bits);
 
return value;
}
 
/**
* treat num_bits as signed value and remove them from bit buffer
*/
static INLINE signed
vl_vlc_get_simsbf(struct vl_vlc *vlc, unsigned num_bits)
{
signed value;
 
assert(vl_vlc_valid_bits(vlc) >= num_bits);
 
value = ((int64_t)vlc->buffer) >> (64 - num_bits);
vl_vlc_eatbits(vlc, num_bits);
 
return value;
}
 
/**
* lookup a value and length in a decompressed table
*/
static INLINE int8_t
vl_vlc_get_vlclbf(struct vl_vlc *vlc, const struct vl_vlc_entry *tbl, unsigned num_bits)
{
tbl += vl_vlc_peekbits(vlc, num_bits);
vl_vlc_eatbits(vlc, tbl->length);
return tbl->value;
}
 
#endif /* vl_vlc_h */
/drivers/video/Gallium/auxiliary/vl/vl_winsys.h
0,0 → 1,69
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* 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.
*
**************************************************************************/
 
/*
* vl targets use either a dri or sw based winsys backend, so their
* Makefiles directly refer to either vl_winsys_dri.c or vl_winsys_xsp.c.
* Both files implement the interface described in this header.
*/
 
#ifndef vl_winsys_h
#define vl_winsys_h
 
#include <X11/Xlib.h>
#include "pipe/p_defines.h"
#include "pipe/p_format.h"
 
struct pipe_screen;
struct pipe_surface;
 
struct vl_screen
{
struct pipe_screen *pscreen;
};
 
struct vl_screen*
vl_screen_create(Display *display, int screen);
 
void vl_screen_destroy(struct vl_screen *vscreen);
 
struct pipe_resource*
vl_screen_texture_from_drawable(struct vl_screen *vscreen, Drawable drawable);
 
struct u_rect *
vl_screen_get_dirty_area(struct vl_screen *vscreen);
 
uint64_t
vl_screen_get_timestamp(struct vl_screen *vscreen, Drawable drawable);
 
void
vl_screen_set_next_timestamp(struct vl_screen *vscreen, uint64_t stamp);
 
void*
vl_screen_get_private(struct vl_screen *vscreen);
 
#endif
/drivers/video/Gallium/auxiliary/vl/vl_winsys_dri.c
0,0 → 1,398
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* 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.
*
**************************************************************************/
 
/* directly referenced from target Makefile, because of X dependencies */
 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
#include <X11/Xlib-xcb.h>
#include <xcb/dri2.h>
#include <xf86drm.h>
 
#include "pipe/p_screen.h"
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "state_tracker/drm_driver.h"
 
#include "util/u_memory.h"
#include "util/u_hash.h"
#include "util/u_hash_table.h"
#include "util/u_inlines.h"
 
#include "vl/vl_compositor.h"
#include "vl/vl_winsys.h"
 
struct vl_dri_screen
{
struct vl_screen base;
xcb_connection_t *conn;
xcb_drawable_t drawable;
 
unsigned width, height;
 
bool current_buffer;
uint32_t buffer_names[2];
struct u_rect dirty_areas[2];
 
bool flushed;
xcb_dri2_swap_buffers_cookie_t swap_cookie;
xcb_dri2_wait_sbc_cookie_t wait_cookie;
xcb_dri2_get_buffers_cookie_t buffers_cookie;
 
int64_t last_ust, ns_frame, last_msc, next_msc;
};
 
static const unsigned int attachments[1] = { XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT };
 
static void
vl_dri2_handle_stamps(struct vl_dri_screen* scrn,
uint32_t ust_hi, uint32_t ust_lo,
uint32_t msc_hi, uint32_t msc_lo)
{
int64_t ust = ((((uint64_t)ust_hi) << 32) | ust_lo) * 1000;
int64_t msc = (((uint64_t)msc_hi) << 32) | msc_lo;
 
if (scrn->last_ust && scrn->last_msc && (ust > scrn->last_ust) && (msc > scrn->last_msc))
scrn->ns_frame = (ust - scrn->last_ust) / (msc - scrn->last_msc);
 
scrn->last_ust = ust;
scrn->last_msc = msc;
}
 
static xcb_dri2_get_buffers_reply_t*
vl_dri2_get_flush_reply(struct vl_dri_screen *scrn)
{
xcb_dri2_wait_sbc_reply_t *wait_sbc_reply;
 
assert(scrn);
 
if (!scrn->flushed)
return NULL;
 
scrn->flushed = false;
 
free(xcb_dri2_swap_buffers_reply(scrn->conn, scrn->swap_cookie, NULL));
 
wait_sbc_reply = xcb_dri2_wait_sbc_reply(scrn->conn, scrn->wait_cookie, NULL);
if (!wait_sbc_reply)
return NULL;
vl_dri2_handle_stamps(scrn, wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo,
wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo);
free(wait_sbc_reply);
 
return xcb_dri2_get_buffers_reply(scrn->conn, scrn->buffers_cookie, NULL);
}
 
static void
vl_dri2_flush_frontbuffer(struct pipe_screen *screen,
struct pipe_resource *resource,
unsigned level, unsigned layer,
void *context_private)
{
struct vl_dri_screen *scrn = (struct vl_dri_screen*)context_private;
uint32_t msc_hi, msc_lo;
 
assert(screen);
assert(resource);
assert(context_private);
 
free(vl_dri2_get_flush_reply(scrn));
 
msc_hi = scrn->next_msc >> 32;
msc_lo = scrn->next_msc & 0xFFFFFFFF;
 
scrn->swap_cookie = xcb_dri2_swap_buffers_unchecked(scrn->conn, scrn->drawable, msc_hi, msc_lo, 0, 0, 0, 0);
scrn->wait_cookie = xcb_dri2_wait_sbc_unchecked(scrn->conn, scrn->drawable, 0, 0);
scrn->buffers_cookie = xcb_dri2_get_buffers_unchecked(scrn->conn, scrn->drawable, 1, 1, attachments);
 
scrn->flushed = true;
scrn->current_buffer = !scrn->current_buffer;
}
 
static void
vl_dri2_destroy_drawable(struct vl_dri_screen *scrn)
{
xcb_void_cookie_t destroy_cookie;
if (scrn->drawable) {
free(vl_dri2_get_flush_reply(scrn));
destroy_cookie = xcb_dri2_destroy_drawable_checked(scrn->conn, scrn->drawable);
/* ignore any error here, since the drawable can be destroyed long ago */
free(xcb_request_check(scrn->conn, destroy_cookie));
}
}
 
static void
vl_dri2_set_drawable(struct vl_dri_screen *scrn, Drawable drawable)
{
assert(scrn);
assert(drawable);
 
if (scrn->drawable == drawable)
return;
 
vl_dri2_destroy_drawable(scrn);
 
xcb_dri2_create_drawable(scrn->conn, drawable);
scrn->current_buffer = false;
vl_compositor_reset_dirty_area(&scrn->dirty_areas[0]);
vl_compositor_reset_dirty_area(&scrn->dirty_areas[1]);
scrn->drawable = drawable;
}
 
struct pipe_resource*
vl_screen_texture_from_drawable(struct vl_screen *vscreen, Drawable drawable)
{
struct vl_dri_screen *scrn = (struct vl_dri_screen*)vscreen;
 
struct winsys_handle dri2_handle;
struct pipe_resource template, *tex;
 
xcb_dri2_get_buffers_reply_t *reply;
xcb_dri2_dri2_buffer_t *buffers, *back_left;
 
unsigned i;
 
assert(scrn);
 
vl_dri2_set_drawable(scrn, drawable);
reply = vl_dri2_get_flush_reply(scrn);
if (!reply) {
xcb_dri2_get_buffers_cookie_t cookie;
cookie = xcb_dri2_get_buffers_unchecked(scrn->conn, drawable, 1, 1, attachments);
reply = xcb_dri2_get_buffers_reply(scrn->conn, cookie, NULL);
}
if (!reply)
return NULL;
 
buffers = xcb_dri2_get_buffers_buffers(reply);
if (!buffers) {
free(reply);
return NULL;
}
 
for (i = 0; i < reply->count; ++i) {
if (buffers[i].attachment == XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT) {
back_left = &buffers[i];
break;
}
}
 
if (i == reply->count) {
free(reply);
return NULL;
}
 
if (reply->width != scrn->width || reply->height != scrn->height) {
vl_compositor_reset_dirty_area(&scrn->dirty_areas[0]);
vl_compositor_reset_dirty_area(&scrn->dirty_areas[1]);
scrn->width = reply->width;
scrn->height = reply->height;
 
} else if (back_left->name != scrn->buffer_names[scrn->current_buffer]) {
vl_compositor_reset_dirty_area(&scrn->dirty_areas[scrn->current_buffer]);
scrn->buffer_names[scrn->current_buffer] = back_left->name;
}
 
memset(&dri2_handle, 0, sizeof(dri2_handle));
dri2_handle.type = DRM_API_HANDLE_TYPE_SHARED;
dri2_handle.handle = back_left->name;
dri2_handle.stride = back_left->pitch;
 
memset(&template, 0, sizeof(template));
template.target = PIPE_TEXTURE_2D;
template.format = PIPE_FORMAT_B8G8R8X8_UNORM;
template.last_level = 0;
template.width0 = reply->width;
template.height0 = reply->height;
template.depth0 = 1;
template.array_size = 1;
template.usage = PIPE_USAGE_STATIC;
template.bind = PIPE_BIND_RENDER_TARGET;
template.flags = 0;
 
tex = scrn->base.pscreen->resource_from_handle(scrn->base.pscreen, &template, &dri2_handle);
free(reply);
 
return tex;
}
 
struct u_rect *
vl_screen_get_dirty_area(struct vl_screen *vscreen)
{
struct vl_dri_screen *scrn = (struct vl_dri_screen*)vscreen;
assert(scrn);
return &scrn->dirty_areas[scrn->current_buffer];
}
 
uint64_t
vl_screen_get_timestamp(struct vl_screen *vscreen, Drawable drawable)
{
struct vl_dri_screen *scrn = (struct vl_dri_screen*)vscreen;
xcb_dri2_get_msc_cookie_t cookie;
xcb_dri2_get_msc_reply_t *reply;
 
assert(scrn);
 
vl_dri2_set_drawable(scrn, drawable);
if (!scrn->last_ust) {
cookie = xcb_dri2_get_msc_unchecked(scrn->conn, drawable);
reply = xcb_dri2_get_msc_reply(scrn->conn, cookie, NULL);
 
if (reply) {
vl_dri2_handle_stamps(scrn, reply->ust_hi, reply->ust_lo,
reply->msc_hi, reply->msc_lo);
free(reply);
}
}
return scrn->last_ust;
}
 
void
vl_screen_set_next_timestamp(struct vl_screen *vscreen, uint64_t stamp)
{
struct vl_dri_screen *scrn = (struct vl_dri_screen*)vscreen;
assert(scrn);
if (stamp && scrn->last_ust && scrn->ns_frame && scrn->last_msc)
scrn->next_msc = ((int64_t)stamp - scrn->last_ust + scrn->ns_frame/2) / scrn->ns_frame + scrn->last_msc;
else
scrn->next_msc = 0;
}
 
void*
vl_screen_get_private(struct vl_screen *vscreen)
{
return vscreen;
}
 
struct vl_screen*
vl_screen_create(Display *display, int screen)
{
struct vl_dri_screen *scrn;
const xcb_query_extension_reply_t *extension;
xcb_dri2_query_version_cookie_t dri2_query_cookie;
xcb_dri2_query_version_reply_t *dri2_query = NULL;
xcb_dri2_connect_cookie_t connect_cookie;
xcb_dri2_connect_reply_t *connect = NULL;
xcb_dri2_authenticate_cookie_t authenticate_cookie;
xcb_dri2_authenticate_reply_t *authenticate = NULL;
xcb_screen_iterator_t s;
xcb_generic_error_t *error = NULL;
char *device_name;
int fd, device_name_length;
 
drm_magic_t magic;
 
assert(display);
 
scrn = CALLOC_STRUCT(vl_dri_screen);
if (!scrn)
return NULL;
 
scrn->conn = XGetXCBConnection(display);
if (!scrn->conn)
goto free_screen;
 
xcb_prefetch_extension_data(scrn->conn, &xcb_dri2_id);
 
extension = xcb_get_extension_data(scrn->conn, &xcb_dri2_id);
if (!(extension && extension->present))
goto free_screen;
 
dri2_query_cookie = xcb_dri2_query_version (scrn->conn, XCB_DRI2_MAJOR_VERSION, XCB_DRI2_MINOR_VERSION);
dri2_query = xcb_dri2_query_version_reply (scrn->conn, dri2_query_cookie, &error);
if (dri2_query == NULL || error != NULL || dri2_query->minor_version < 2)
goto free_screen;
 
s = xcb_setup_roots_iterator(xcb_get_setup(scrn->conn));
while (screen--)
xcb_screen_next(&s);
connect_cookie = xcb_dri2_connect_unchecked(scrn->conn, s.data->root, XCB_DRI2_DRIVER_TYPE_DRI);
connect = xcb_dri2_connect_reply(scrn->conn, connect_cookie, NULL);
if (connect == NULL || connect->driver_name_length + connect->device_name_length == 0)
goto free_screen;
 
device_name_length = xcb_dri2_connect_device_name_length(connect);
device_name = CALLOC(1, device_name_length + 1);
memcpy(device_name, xcb_dri2_connect_device_name(connect), device_name_length);
fd = open(device_name, O_RDWR);
free(device_name);
 
if (fd < 0)
goto free_screen;
 
if (drmGetMagic(fd, &magic))
goto free_screen;
 
authenticate_cookie = xcb_dri2_authenticate_unchecked(scrn->conn, s.data->root, magic);
authenticate = xcb_dri2_authenticate_reply(scrn->conn, authenticate_cookie, NULL);
 
if (authenticate == NULL || !authenticate->authenticated)
goto free_screen;
 
scrn->base.pscreen = driver_descriptor.create_screen(fd);
if (!scrn->base.pscreen)
goto free_screen;
 
scrn->base.pscreen->flush_frontbuffer = vl_dri2_flush_frontbuffer;
vl_compositor_reset_dirty_area(&scrn->dirty_areas[0]);
vl_compositor_reset_dirty_area(&scrn->dirty_areas[1]);
 
free(dri2_query);
free(connect);
free(authenticate);
 
return &scrn->base;
 
free_screen:
FREE(scrn);
 
free(dri2_query);
free(connect);
free(authenticate);
free(error);
 
return NULL;
}
 
void vl_screen_destroy(struct vl_screen *vscreen)
{
struct vl_dri_screen *scrn = (struct vl_dri_screen*)vscreen;
 
assert(vscreen);
 
if (scrn->flushed) {
free(xcb_dri2_swap_buffers_reply(scrn->conn, scrn->swap_cookie, NULL));
free(xcb_dri2_wait_sbc_reply(scrn->conn, scrn->wait_cookie, NULL));
free(xcb_dri2_get_buffers_reply(scrn->conn, scrn->buffers_cookie, NULL));
}
 
vl_dri2_destroy_drawable(scrn);
scrn->base.pscreen->destroy(scrn->base.pscreen);
FREE(scrn);
}
/drivers/video/Gallium/auxiliary/vl/vl_winsys_xsp.c
0,0 → 1,170
/**************************************************************************
*
* Copyright 2009 Younes Manton.
* 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.
*
**************************************************************************/
 
/* directly referenced from target Makefile, because of X dependencies */
 
#include <sys/time.h>
 
#include "pipe/p_state.h"
 
#include "util/u_memory.h"
#include "util/u_format.h"
#include "util/u_inlines.h"
 
#include "state_tracker/xlib_sw_winsys.h"
#include "softpipe/sp_public.h"
 
#include "vl/vl_compositor.h"
#include "vl/vl_winsys.h"
 
struct vl_xsp_screen
{
struct vl_screen base;
Display *display;
int screen;
Visual visual;
struct xlib_drawable xdraw;
struct pipe_resource *tex;
struct u_rect dirty_area;
};
 
struct pipe_resource*
vl_screen_texture_from_drawable(struct vl_screen *vscreen, Drawable drawable)
{
struct vl_xsp_screen *xsp_screen = (struct vl_xsp_screen*)vscreen;
Window root;
int x, y;
unsigned int width, height;
unsigned int border_width;
unsigned int depth;
struct pipe_resource templat;
 
assert(vscreen);
assert(drawable != None);
 
if (XGetGeometry(xsp_screen->display, drawable, &root, &x, &y, &width, &height, &border_width, &depth) == BadDrawable)
return NULL;
 
xsp_screen->xdraw.drawable = drawable;
 
if (xsp_screen->tex) {
if (xsp_screen->tex->width0 == width && xsp_screen->tex->height0 == height)
return xsp_screen->tex;
pipe_resource_reference(&xsp_screen->tex, NULL);
vl_compositor_reset_dirty_area(&xsp_screen->dirty_area);
}
 
memset(&templat, 0, sizeof(struct pipe_resource));
templat.target = PIPE_TEXTURE_2D;
/* XXX: Need to figure out drawable's format */
templat.format = PIPE_FORMAT_B8G8R8X8_UNORM;
templat.last_level = 0;
templat.width0 = width;
templat.height0 = height;
templat.depth0 = 1;
templat.usage = PIPE_USAGE_DEFAULT;
templat.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_DISPLAY_TARGET;
templat.flags = 0;
 
xsp_screen->xdraw.depth = 24/*util_format_get_blocksizebits(templat.format) /
util_format_get_blockwidth(templat.format)*/;
 
pipe_resource_reference(&xsp_screen->tex, vscreen->pscreen->resource_create(vscreen->pscreen, &templat));
return xsp_screen->tex;
}
 
struct u_rect *
vl_screen_get_dirty_area(struct vl_screen *vscreen)
{
struct vl_xsp_screen *xsp_screen = (struct vl_xsp_screen*)vscreen;
return &xsp_screen->dirty_area;
}
 
uint64_t
vl_screen_get_timestamp(struct vl_screen *vscreen, Drawable drawable)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t)tv.tv_sec * 1000000000LL + (uint64_t)tv.tv_usec * 1000LL;
}
 
void
vl_screen_set_next_timestamp(struct vl_screen *vscreen, uint64_t stamp)
{
/* not supported on softpipe and so only a dummy */
}
 
void*
vl_screen_get_private(struct vl_screen *vscreen)
{
struct vl_xsp_screen *xsp_screen = (struct vl_xsp_screen*)vscreen;
return &xsp_screen->xdraw;
}
 
struct vl_screen*
vl_screen_create(Display *display, int screen)
{
struct vl_xsp_screen *xsp_screen;
struct sw_winsys *winsys;
 
assert(display);
 
xsp_screen = CALLOC_STRUCT(vl_xsp_screen);
if (!xsp_screen)
return NULL;
 
winsys = xlib_create_sw_winsys(display);
if (!winsys) {
FREE(xsp_screen);
return NULL;
}
 
xsp_screen->base.pscreen = softpipe_create_screen(winsys);
if (!xsp_screen->base.pscreen) {
winsys->destroy(winsys);
FREE(xsp_screen);
return NULL;
}
 
xsp_screen->display = display;
xsp_screen->screen = screen;
xsp_screen->xdraw.visual = XDefaultVisual(display, screen);
vl_compositor_reset_dirty_area(&xsp_screen->dirty_area);
 
return &xsp_screen->base;
}
 
void vl_screen_destroy(struct vl_screen *vscreen)
{
struct vl_xsp_screen *xsp_screen = (struct vl_xsp_screen*)vscreen;
 
assert(vscreen);
 
pipe_resource_reference(&xsp_screen->tex, NULL);
vscreen->pscreen->destroy(vscreen->pscreen);
FREE(vscreen);
}
/drivers/video/Gallium/auxiliary/vl/vl_zscan.c
0,0 → 1,584
/**************************************************************************
*
* Copyright 2011 Christian König
* 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.
*
**************************************************************************/
 
#include <assert.h>
 
#include "pipe/p_screen.h"
#include "pipe/p_context.h"
 
#include "util/u_draw.h"
#include "util/u_sampler.h"
#include "util/u_inlines.h"
#include "util/u_memory.h"
 
#include "tgsi/tgsi_ureg.h"
 
#include "vl_defines.h"
#include "vl_types.h"
 
#include "vl_zscan.h"
#include "vl_vertex_buffers.h"
 
enum VS_OUTPUT
{
VS_O_VPOS = 0,
VS_O_VTEX = 0
};
 
const int vl_zscan_linear[] =
{
/* Linear scan pattern */
0, 1, 2, 3, 4, 5, 6, 7,
8, 9,10,11,12,13,14,15,
16,17,18,19,20,21,22,23,
24,25,26,27,28,29,30,31,
32,33,34,35,36,37,38,39,
40,41,42,43,44,45,46,47,
48,49,50,51,52,53,54,55,
56,57,58,59,60,61,62,63
};
 
const int vl_zscan_normal[] =
{
/* Zig-Zag scan pattern */
0, 1, 8,16, 9, 2, 3,10,
17,24,32,25,18,11, 4, 5,
12,19,26,33,40,48,41,34,
27,20,13, 6, 7,14,21,28,
35,42,49,56,57,50,43,36,
29,22,15,23,30,37,44,51,
58,59,52,45,38,31,39,46,
53,60,61,54,47,55,62,63
};
 
const int vl_zscan_alternate[] =
{
/* Alternate scan pattern */
0, 8,16,24, 1, 9, 2,10,
17,25,32,40,48,56,57,49,
41,33,26,18, 3,11, 4,12,
19,27,34,42,50,58,35,43,
51,59,20,28, 5,13, 6,14,
21,29,36,44,52,60,37,45,
53,61,22,30, 7,15,23,31,
38,46,54,62,39,47,55,63
};
 
static void *
create_vert_shader(struct vl_zscan *zscan)
{
struct ureg_program *shader;
 
struct ureg_src scale;
struct ureg_src vrect, vpos, block_num;
 
struct ureg_dst tmp;
struct ureg_dst o_vpos;
struct ureg_dst *o_vtex;
 
signed i;
 
shader = ureg_create(TGSI_PROCESSOR_VERTEX);
if (!shader)
return NULL;
 
o_vtex = MALLOC(zscan->num_channels * sizeof(struct ureg_dst));
 
scale = ureg_imm2f(shader,
(float)VL_BLOCK_WIDTH / zscan->buffer_width,
(float)VL_BLOCK_HEIGHT / zscan->buffer_height);
 
vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
block_num = ureg_DECL_vs_input(shader, VS_I_BLOCK_NUM);
 
tmp = ureg_DECL_temporary(shader);
 
o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
 
for (i = 0; i < zscan->num_channels; ++i)
o_vtex[i] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX + i);
 
/*
* o_vpos.xy = (vpos + vrect) * scale
* o_vpos.zw = 1.0f
*
* tmp.xy = InstanceID / blocks_per_line
* tmp.x = frac(tmp.x)
* tmp.y = floor(tmp.y)
*
* o_vtex.x = vrect.x / blocks_per_line + tmp.x
* o_vtex.y = vrect.y
* o_vtex.z = tmp.z * blocks_per_line / blocks_total
*/
ureg_ADD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XY), vpos, vrect);
ureg_MUL(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_XY), ureg_src(tmp), scale);
ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_ZW), ureg_imm1f(shader, 1.0f));
 
ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XW), ureg_scalar(block_num, TGSI_SWIZZLE_X),
ureg_imm1f(shader, 1.0f / zscan->blocks_per_line));
 
ureg_FRC(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X));
ureg_FLR(shader, ureg_writemask(tmp, TGSI_WRITEMASK_W), ureg_src(tmp));
 
for (i = 0; i < zscan->num_channels; ++i) {
ureg_ADD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y),
ureg_imm1f(shader, 1.0f / (zscan->blocks_per_line * VL_BLOCK_WIDTH)
* (i - (signed)zscan->num_channels / 2)));
 
ureg_MAD(shader, ureg_writemask(o_vtex[i], TGSI_WRITEMASK_X), vrect,
ureg_imm1f(shader, 1.0f / zscan->blocks_per_line), ureg_src(tmp));
ureg_MOV(shader, ureg_writemask(o_vtex[i], TGSI_WRITEMASK_Y), vrect);
ureg_MOV(shader, ureg_writemask(o_vtex[i], TGSI_WRITEMASK_Z), vpos);
ureg_MUL(shader, ureg_writemask(o_vtex[i], TGSI_WRITEMASK_W), ureg_src(tmp),
ureg_imm1f(shader, (float)zscan->blocks_per_line / zscan->blocks_total));
}
 
ureg_release_temporary(shader, tmp);
ureg_END(shader);
 
FREE(o_vtex);
 
return ureg_create_shader_and_destroy(shader, zscan->pipe);
}
 
static void *
create_frag_shader(struct vl_zscan *zscan)
{
struct ureg_program *shader;
struct ureg_src *vtex;
 
struct ureg_src samp_src, samp_scan, samp_quant;
 
struct ureg_dst *tmp;
struct ureg_dst quant, fragment;
 
unsigned i;
 
shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
if (!shader)
return NULL;
 
vtex = MALLOC(zscan->num_channels * sizeof(struct ureg_src));
tmp = MALLOC(zscan->num_channels * sizeof(struct ureg_dst));
 
for (i = 0; i < zscan->num_channels; ++i)
vtex[i] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX + i, TGSI_INTERPOLATE_LINEAR);
 
samp_src = ureg_DECL_sampler(shader, 0);
samp_scan = ureg_DECL_sampler(shader, 1);
samp_quant = ureg_DECL_sampler(shader, 2);
 
for (i = 0; i < zscan->num_channels; ++i)
tmp[i] = ureg_DECL_temporary(shader);
quant = ureg_DECL_temporary(shader);
 
fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
 
/*
* tmp.x = tex(vtex, 1)
* tmp.y = vtex.z
* fragment = tex(tmp, 0) * quant
*/
for (i = 0; i < zscan->num_channels; ++i)
ureg_TEX(shader, ureg_writemask(tmp[i], TGSI_WRITEMASK_X), TGSI_TEXTURE_2D, vtex[i], samp_scan);
 
for (i = 0; i < zscan->num_channels; ++i)
ureg_MOV(shader, ureg_writemask(tmp[i], TGSI_WRITEMASK_Y), ureg_scalar(vtex[i], TGSI_SWIZZLE_W));
 
for (i = 0; i < zscan->num_channels; ++i) {
ureg_TEX(shader, ureg_writemask(tmp[0], TGSI_WRITEMASK_X << i), TGSI_TEXTURE_2D, ureg_src(tmp[i]), samp_src);
ureg_TEX(shader, ureg_writemask(quant, TGSI_WRITEMASK_X << i), TGSI_TEXTURE_3D, vtex[i], samp_quant);
}
 
ureg_MUL(shader, quant, ureg_src(quant), ureg_imm1f(shader, 16.0f));
ureg_MUL(shader, fragment, ureg_src(tmp[0]), ureg_src(quant));
 
for (i = 0; i < zscan->num_channels; ++i)
ureg_release_temporary(shader, tmp[i]);
ureg_END(shader);
 
FREE(vtex);
FREE(tmp);
 
return ureg_create_shader_and_destroy(shader, zscan->pipe);
}
 
static bool
init_shaders(struct vl_zscan *zscan)
{
assert(zscan);
 
zscan->vs = create_vert_shader(zscan);
if (!zscan->vs)
goto error_vs;
 
zscan->fs = create_frag_shader(zscan);
if (!zscan->fs)
goto error_fs;
 
return true;
 
error_fs:
zscan->pipe->delete_vs_state(zscan->pipe, zscan->vs);
 
error_vs:
return false;
}
 
static void
cleanup_shaders(struct vl_zscan *zscan)
{
assert(zscan);
 
zscan->pipe->delete_vs_state(zscan->pipe, zscan->vs);
zscan->pipe->delete_fs_state(zscan->pipe, zscan->fs);
}
 
static bool
init_state(struct vl_zscan *zscan)
{
struct pipe_blend_state blend;
struct pipe_rasterizer_state rs_state;
struct pipe_sampler_state sampler;
unsigned i;
 
assert(zscan);
 
memset(&rs_state, 0, sizeof(rs_state));
rs_state.half_pixel_center = true;
rs_state.bottom_edge_rule = true;
rs_state.depth_clip = 1;
zscan->rs_state = zscan->pipe->create_rasterizer_state(zscan->pipe, &rs_state);
if (!zscan->rs_state)
goto error_rs_state;
 
memset(&blend, 0, sizeof blend);
 
blend.independent_blend_enable = 0;
blend.rt[0].blend_enable = 0;
blend.rt[0].rgb_func = PIPE_BLEND_ADD;
blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].alpha_func = PIPE_BLEND_ADD;
blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
blend.logicop_enable = 0;
blend.logicop_func = PIPE_LOGICOP_CLEAR;
/* Needed to allow color writes to FB, even if blending disabled */
blend.rt[0].colormask = PIPE_MASK_RGBA;
blend.dither = 0;
zscan->blend = zscan->pipe->create_blend_state(zscan->pipe, &blend);
if (!zscan->blend)
goto error_blend;
 
for (i = 0; i < 3; ++i) {
memset(&sampler, 0, sizeof(sampler));
sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
sampler.wrap_t = PIPE_TEX_WRAP_REPEAT;
sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
sampler.compare_func = PIPE_FUNC_ALWAYS;
sampler.normalized_coords = 1;
zscan->samplers[i] = zscan->pipe->create_sampler_state(zscan->pipe, &sampler);
if (!zscan->samplers[i])
goto error_samplers;
}
 
return true;
 
error_samplers:
for (i = 0; i < 2; ++i)
if (zscan->samplers[i])
zscan->pipe->delete_sampler_state(zscan->pipe, zscan->samplers[i]);
 
zscan->pipe->delete_rasterizer_state(zscan->pipe, zscan->rs_state);
 
error_blend:
zscan->pipe->delete_blend_state(zscan->pipe, zscan->blend);
 
error_rs_state:
return false;
}
 
static void
cleanup_state(struct vl_zscan *zscan)
{
unsigned i;
 
assert(zscan);
 
for (i = 0; i < 3; ++i)
zscan->pipe->delete_sampler_state(zscan->pipe, zscan->samplers[i]);
 
zscan->pipe->delete_rasterizer_state(zscan->pipe, zscan->rs_state);
zscan->pipe->delete_blend_state(zscan->pipe, zscan->blend);
}
 
struct pipe_sampler_view *
vl_zscan_layout(struct pipe_context *pipe, const int layout[64], unsigned blocks_per_line)
{
const unsigned total_size = blocks_per_line * VL_BLOCK_WIDTH * VL_BLOCK_HEIGHT;
 
int patched_layout[64];
 
struct pipe_resource res_tmpl, *res;
struct pipe_sampler_view sv_tmpl, *sv;
struct pipe_transfer *buf_transfer;
unsigned x, y, i, pitch;
float *f;
 
struct pipe_box rect =
{
0, 0, 0,
VL_BLOCK_WIDTH * blocks_per_line,
VL_BLOCK_HEIGHT,
1
};
 
assert(pipe && layout && blocks_per_line);
 
for (i = 0; i < 64; ++i)
patched_layout[layout[i]] = i;
 
memset(&res_tmpl, 0, sizeof(res_tmpl));
res_tmpl.target = PIPE_TEXTURE_2D;
res_tmpl.format = PIPE_FORMAT_R32_FLOAT;
res_tmpl.width0 = VL_BLOCK_WIDTH * blocks_per_line;
res_tmpl.height0 = VL_BLOCK_HEIGHT;
res_tmpl.depth0 = 1;
res_tmpl.array_size = 1;
res_tmpl.usage = PIPE_USAGE_IMMUTABLE;
res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
 
res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
if (!res)
goto error_resource;
 
f = pipe->transfer_map(pipe, res,
0, PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE,
&rect, &buf_transfer);
if (!f)
goto error_map;
 
pitch = buf_transfer->stride / sizeof(float);
 
for (i = 0; i < blocks_per_line; ++i)
for (y = 0; y < VL_BLOCK_HEIGHT; ++y)
for (x = 0; x < VL_BLOCK_WIDTH; ++x) {
float addr = patched_layout[x + y * VL_BLOCK_WIDTH] +
i * VL_BLOCK_WIDTH * VL_BLOCK_HEIGHT;
 
addr /= total_size;
 
f[i * VL_BLOCK_WIDTH + y * pitch + x] = addr;
}
 
pipe->transfer_unmap(pipe, buf_transfer);
 
memset(&sv_tmpl, 0, sizeof(sv_tmpl));
u_sampler_view_default_template(&sv_tmpl, res, res->format);
sv = pipe->create_sampler_view(pipe, res, &sv_tmpl);
pipe_resource_reference(&res, NULL);
if (!sv)
goto error_map;
 
return sv;
 
error_map:
pipe_resource_reference(&res, NULL);
 
error_resource:
return NULL;
}
 
bool
vl_zscan_init(struct vl_zscan *zscan, struct pipe_context *pipe,
unsigned buffer_width, unsigned buffer_height,
unsigned blocks_per_line, unsigned blocks_total,
unsigned num_channels)
{
assert(zscan && pipe);
 
zscan->pipe = pipe;
zscan->buffer_width = buffer_width;
zscan->buffer_height = buffer_height;
zscan->num_channels = num_channels;
zscan->blocks_per_line = blocks_per_line;
zscan->blocks_total = blocks_total;
 
if(!init_shaders(zscan))
return false;
 
if(!init_state(zscan)) {
cleanup_shaders(zscan);
return false;
}
 
return true;
}
 
void
vl_zscan_cleanup(struct vl_zscan *zscan)
{
assert(zscan);
 
cleanup_shaders(zscan);
cleanup_state(zscan);
}
 
bool
vl_zscan_init_buffer(struct vl_zscan *zscan, struct vl_zscan_buffer *buffer,
struct pipe_sampler_view *src, struct pipe_surface *dst)
{
struct pipe_resource res_tmpl, *res;
struct pipe_sampler_view sv_tmpl;
 
assert(zscan && buffer);
 
memset(buffer, 0, sizeof(struct vl_zscan_buffer));
 
pipe_sampler_view_reference(&buffer->src, src);
 
buffer->viewport.scale[0] = dst->width;
buffer->viewport.scale[1] = dst->height;
buffer->viewport.scale[2] = 1;
buffer->viewport.scale[3] = 1;
buffer->viewport.translate[0] = 0;
buffer->viewport.translate[1] = 0;
buffer->viewport.translate[2] = 0;
buffer->viewport.translate[3] = 0;
 
buffer->fb_state.width = dst->width;
buffer->fb_state.height = dst->height;
buffer->fb_state.nr_cbufs = 1;
pipe_surface_reference(&buffer->fb_state.cbufs[0], dst);
 
memset(&res_tmpl, 0, sizeof(res_tmpl));
res_tmpl.target = PIPE_TEXTURE_3D;
res_tmpl.format = PIPE_FORMAT_R8_UNORM;
res_tmpl.width0 = VL_BLOCK_WIDTH * zscan->blocks_per_line;
res_tmpl.height0 = VL_BLOCK_HEIGHT;
res_tmpl.depth0 = 2;
res_tmpl.array_size = 1;
res_tmpl.usage = PIPE_USAGE_IMMUTABLE;
res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
 
res = zscan->pipe->screen->resource_create(zscan->pipe->screen, &res_tmpl);
if (!res)
return false;
 
memset(&sv_tmpl, 0, sizeof(sv_tmpl));
u_sampler_view_default_template(&sv_tmpl, res, res->format);
sv_tmpl.swizzle_r = sv_tmpl.swizzle_g = sv_tmpl.swizzle_b = sv_tmpl.swizzle_a = TGSI_SWIZZLE_X;
buffer->quant = zscan->pipe->create_sampler_view(zscan->pipe, res, &sv_tmpl);
pipe_resource_reference(&res, NULL);
if (!buffer->quant)
return false;
 
return true;
}
 
void
vl_zscan_cleanup_buffer(struct vl_zscan_buffer *buffer)
{
assert(buffer);
 
pipe_sampler_view_reference(&buffer->src, NULL);
pipe_sampler_view_reference(&buffer->layout, NULL);
pipe_sampler_view_reference(&buffer->quant, NULL);
pipe_surface_reference(&buffer->fb_state.cbufs[0], NULL);
}
 
void
vl_zscan_set_layout(struct vl_zscan_buffer *buffer, struct pipe_sampler_view *layout)
{
assert(buffer);
assert(layout);
 
pipe_sampler_view_reference(&buffer->layout, layout);
}
 
void
vl_zscan_upload_quant(struct vl_zscan *zscan, struct vl_zscan_buffer *buffer,
const uint8_t matrix[64], bool intra)
{
struct pipe_context *pipe;
struct pipe_transfer *buf_transfer;
unsigned x, y, i, pitch;
uint8_t *data;
 
struct pipe_box rect =
{
0, 0, intra ? 1 : 0,
VL_BLOCK_WIDTH,
VL_BLOCK_HEIGHT,
1
};
 
assert(buffer);
assert(matrix);
 
pipe = zscan->pipe;
 
rect.width *= zscan->blocks_per_line;
 
data = pipe->transfer_map(pipe, buffer->quant->texture,
0, PIPE_TRANSFER_WRITE |
PIPE_TRANSFER_DISCARD_RANGE,
&rect, &buf_transfer);
if (!data)
return;
 
pitch = buf_transfer->stride;
 
for (i = 0; i < zscan->blocks_per_line; ++i)
for (y = 0; y < VL_BLOCK_HEIGHT; ++y)
for (x = 0; x < VL_BLOCK_WIDTH; ++x)
data[i * VL_BLOCK_WIDTH + y * pitch + x] = matrix[x + y * VL_BLOCK_WIDTH];
 
pipe->transfer_unmap(pipe, buf_transfer);
}
 
void
vl_zscan_render(struct vl_zscan *zscan, struct vl_zscan_buffer *buffer, unsigned num_instances)
{
assert(buffer);
 
zscan->pipe->bind_rasterizer_state(zscan->pipe, zscan->rs_state);
zscan->pipe->bind_blend_state(zscan->pipe, zscan->blend);
zscan->pipe->bind_fragment_sampler_states(zscan->pipe, 3, zscan->samplers);
zscan->pipe->set_framebuffer_state(zscan->pipe, &buffer->fb_state);
zscan->pipe->set_viewport_states(zscan->pipe, 0, 1, &buffer->viewport);
zscan->pipe->set_fragment_sampler_views(zscan->pipe, 3, &buffer->src);
zscan->pipe->bind_vs_state(zscan->pipe, zscan->vs);
zscan->pipe->bind_fs_state(zscan->pipe, zscan->fs);
util_draw_arrays_instanced(zscan->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances);
}
/drivers/video/Gallium/auxiliary/vl/vl_zscan.h
0,0 → 1,100
/**************************************************************************
*
* Copyright 2011 Christian König
* 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.
*
**************************************************************************/
 
#ifndef vl_zscan_h
#define vl_zscan_h
 
#include "pipe/p_compiler.h"
#include "pipe/p_state.h"
 
/*
* shader based zscan and quantification
* expect usage of vl_vertex_buffers as a todo list
*/
struct vl_zscan
{
struct pipe_context *pipe;
 
unsigned buffer_width;
unsigned buffer_height;
 
unsigned num_channels;
 
unsigned blocks_per_line;
unsigned blocks_total;
 
void *rs_state;
void *blend;
 
void *samplers[3];
 
void *vs, *fs;
};
 
struct vl_zscan_buffer
{
struct pipe_viewport_state viewport;
struct pipe_framebuffer_state fb_state;
 
struct pipe_sampler_view *src, *layout, *quant;
struct pipe_surface *dst;
};
 
extern const int vl_zscan_linear[];
extern const int vl_zscan_normal[];
extern const int vl_zscan_alternate[];
 
struct pipe_sampler_view *
vl_zscan_layout(struct pipe_context *pipe, const int layout[64], unsigned blocks_per_line);
 
bool
vl_zscan_init(struct vl_zscan *zscan, struct pipe_context *pipe,
unsigned buffer_width, unsigned buffer_height,
unsigned blocks_per_line, unsigned blocks_total,
unsigned num_channels);
 
void
vl_zscan_cleanup(struct vl_zscan *zscan);
 
bool
vl_zscan_init_buffer(struct vl_zscan *zscan, struct vl_zscan_buffer *buffer,
struct pipe_sampler_view *src, struct pipe_surface *dst);
 
void
vl_zscan_cleanup_buffer(struct vl_zscan_buffer *buffer);
 
void
vl_zscan_set_layout(struct vl_zscan_buffer *buffer, struct pipe_sampler_view *layout);
 
void
vl_zscan_upload_quant(struct vl_zscan *zscan, struct vl_zscan_buffer *buffer,
const uint8_t matrix[64], bool intra);
 
void
vl_zscan_render(struct vl_zscan *zscan, struct vl_zscan_buffer *buffer, unsigned num_instances);
 
#endif