[PATCH xserver v2] glamor: add support for NV12 in Xv
Julien Isorce
julien.isorce at gmail.com
Tue Sep 11 17:28:33 UTC 2018
Useful when video decoders only output NV12. Currently
glamor Xv only supports I420 and YV12.
Note that Intel's sna supports I420, YV12, YUY2, UYVY, NV12.
Test: xvinfo | grep NV12
Test: gst-launch-1.0 videotestsrc ! video/x-raw, format=NV12 ! xvimagesink
v2: Combine the two texture2Ds on u_sampler.
Signed-off-by: Julien Isorce <jisorce at oblong.com>
---
glamor/glamor_xv.c | 180 +++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 155 insertions(+), 25 deletions(-)
diff --git a/glamor/glamor_xv.c b/glamor/glamor_xv.c
index 62fc4ff..6fef6ed 100644
--- a/glamor/glamor_xv.c
+++ b/glamor/glamor_xv.c
@@ -59,8 +59,40 @@ typedef struct tagREF_TRANSFORM {
#define RTFContrast(a) (1.0 + ((a)*1.0)/1000.0)
#define RTFHue(a) (((a)*3.1416)/1000.0)
-static const glamor_facet glamor_facet_xv_planar = {
- .name = "xv_planar",
+static const glamor_facet glamor_facet_xv_planar_2 = {
+ .name = "xv_planar_2",
+
+ .version = 120,
+
+ .source_name = "v_texcoord0",
+ .vs_vars = ("attribute vec2 position;\n"
+ "attribute vec2 v_texcoord0;\n"
+ "varying vec2 tcs;\n"),
+ .vs_exec = (GLAMOR_POS(gl_Position, position)
+ " tcs = v_texcoord0;\n"),
+
+ .fs_vars = ("uniform sampler2D y_sampler;\n"
+ "uniform sampler2D u_sampler;\n"
+ "uniform vec4 offsetyco;\n"
+ "uniform vec4 ucogamma;\n"
+ "uniform vec4 vco;\n"
+ "varying vec2 tcs;\n"),
+ .fs_exec = (
+ " float sample;\n"
+ " vec2 sample_uv;\n"
+ " vec4 temp1;\n"
+ " sample = texture2D(y_sampler, tcs).w;\n"
+ " temp1.xyz = offsetyco.www * vec3(sample) + offsetyco.xyz;\n"
+ " sample_uv = texture2D(u_sampler, tcs).xy;\n"
+ " temp1.xyz = ucogamma.xyz * vec3(sample_uv.x) + temp1.xyz;\n"
+ " temp1.xyz = clamp(vco.xyz * vec3(sample_uv.y) + temp1.xyz, 0.0, 1.0);\n"
+ " temp1.w = 1.0;\n"
+ " gl_FragColor = temp1;\n"
+ ),
+};
+
+static const glamor_facet glamor_facet_xv_planar_3 = {
+ .name = "xv_planar_3",
.version = 120,
@@ -110,26 +142,50 @@ Atom glamorBrightness, glamorContrast, glamorSaturation, glamorHue,
XvImageRec glamor_xv_images[] = {
XVIMAGE_YV12,
XVIMAGE_I420,
+ XVIMAGE_NV12
};
int glamor_xv_num_images = ARRAY_SIZE(glamor_xv_images);
static void
-glamor_init_xv_shader(ScreenPtr screen)
+glamor_init_xv_shader(ScreenPtr screen, int id)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
GLint sampler_loc;
+ const glamor_facet *glamor_facet_xv_planar = NULL;
+
+ switch (id) {
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ glamor_facet_xv_planar = &glamor_facet_xv_planar_3;
+ break;
+ case FOURCC_NV12:
+ glamor_facet_xv_planar = &glamor_facet_xv_planar_2;
+ break;
+ default:
+ break;
+ }
glamor_build_program(screen,
&glamor_priv->xv_prog,
- &glamor_facet_xv_planar, NULL, NULL, NULL);
+ glamor_facet_xv_planar, NULL, NULL, NULL);
glUseProgram(glamor_priv->xv_prog.prog);
sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "y_sampler");
glUniform1i(sampler_loc, 0);
sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "u_sampler");
glUniform1i(sampler_loc, 1);
- sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "v_sampler");
- glUniform1i(sampler_loc, 2);
+
+ switch (id) {
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "v_sampler");
+ glUniform1i(sampler_loc, 2);
+ break;
+ case FOURCC_NV12:
+ break;
+ default:
+ break;
+ }
}
@@ -227,6 +283,21 @@ glamor_xv_query_image_attributes(int id,
offsets[2] = size;
size += tmp;
break;
+ case FOURCC_NV12:
+ *w = ALIGN(*w, 2);
+ *h = ALIGN(*h, 2);
+ size = ALIGN(*w, 4);
+ if (pitches)
+ pitches[0] = size;
+ size *= *h;
+ if (offsets)
+ offsets[1] = offsets[2] = size;
+ tmp = ALIGN(*w, 4);
+ if (pitches)
+ pitches[1] = pitches[2] = tmp;
+ tmp *= (*h >> 1);
+ size += tmp;
+ break;
}
return size;
}
@@ -240,7 +311,7 @@ static REF_TRANSFORM trans[2] = {
};
void
-glamor_xv_render(glamor_port_private *port_priv)
+glamor_xv_render(glamor_port_private *port_priv, int id)
{
ScreenPtr screen = port_priv->pPixmap->drawable.pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
@@ -264,7 +335,7 @@ glamor_xv_render(glamor_port_private *port_priv)
int dst_box_index;
if (!glamor_priv->xv_prog.prog)
- glamor_init_xv_shader(screen);
+ glamor_init_xv_shader(screen, id);
cont = RTFContrast(port_priv->contrast);
bright = RTFBrightness(port_priv->brightness);
@@ -293,6 +364,8 @@ glamor_xv_render(glamor_port_private *port_priv)
glamor_get_pixmap_private(port_priv->src_pix[i]);
pixmap_priv_get_scale(src_pixmap_priv[i], &src_xscale[i],
&src_yscale[i]);
+ } else {
+ src_pixmap_priv[i] = NULL;
}
}
glamor_make_current(glamor_priv);
@@ -319,12 +392,21 @@ glamor_xv_render(glamor_port_private *port_priv)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glActiveTexture(GL_TEXTURE2);
- glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[2]->fbo->tex);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ switch (id) {
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[2]->fbo->tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ break;
+ case FOURCC_NV12:
+ break;
+ default:
+ break;
+ }
glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
@@ -336,7 +418,7 @@ glamor_xv_render(glamor_port_private *port_priv)
/* Set up a single primitive covering the area being drawn. We'll
* clip it to port_priv->clip using GL scissors instead of just
* emitting a GL_QUAD per box, because this way we hopefully avoid
- * diagonal tearing between the two trangles used to rasterize a
+ * diagonal tearing between the two triangles used to rasterize a
* GL_QUAD.
*/
i = 0;
@@ -417,6 +499,7 @@ glamor_xv_put_image(glamor_port_private *port_priv,
RegionPtr clipBoxes)
{
ScreenPtr pScreen = pDrawable->pScreen;
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
int srcPitch, srcPitch2;
int top, nlines;
int s2offset, s3offset, tmp;
@@ -425,9 +508,16 @@ glamor_xv_put_image(glamor_port_private *port_priv,
s2offset = s3offset = srcPitch2 = 0;
if (!port_priv->src_pix[0] ||
- (width != port_priv->src_pix_w || height != port_priv->src_pix_h)) {
+ (width != port_priv->src_pix_w || height != port_priv->src_pix_h) ||
+ (port_priv->src_pix[2] && id == FOURCC_NV12) ||
+ (!port_priv->src_pix[2] && id != FOURCC_NV12)) {
int i;
+ if (glamor_priv->xv_prog.prog) {
+ glDeleteProgram(glamor_priv->xv_prog.prog);
+ glamor_priv->xv_prog.prog = 0;
+ }
+
for (i = 0; i < 3; i++)
if (port_priv->src_pix[i])
glamor_destroy_pixmap(port_priv->src_pix[i]);
@@ -435,17 +525,34 @@ glamor_xv_put_image(glamor_port_private *port_priv,
port_priv->src_pix[0] =
glamor_create_pixmap(pScreen, width, height, 8,
GLAMOR_CREATE_FBO_NO_FBO);
- port_priv->src_pix[1] =
- glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
- GLAMOR_CREATE_FBO_NO_FBO);
- port_priv->src_pix[2] =
- glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
- GLAMOR_CREATE_FBO_NO_FBO);
+
+ switch (id) {
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ port_priv->src_pix[1] =
+ glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
+ GLAMOR_CREATE_FBO_NO_FBO);
+ port_priv->src_pix[2] =
+ glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
+ GLAMOR_CREATE_FBO_NO_FBO);
+ if (!port_priv->src_pix[2])
+ return BadAlloc;
+ break;
+ case FOURCC_NV12:
+ port_priv->src_pix[1] =
+ glamor_create_pixmap(pScreen, width >> 1, height >> 1, 16,
+ GLAMOR_CREATE_FBO_NO_FBO |
+ GLAMOR_CREATE_FORMAT_CBCR);
+ port_priv->src_pix[2] = NULL;
+ break;
+ default:
+ return BadMatch;
+ }
+
port_priv->src_pix_w = width;
port_priv->src_pix_h = height;
- if (!port_priv->src_pix[0] || !port_priv->src_pix[1] ||
- !port_priv->src_pix[2])
+ if (!port_priv->src_pix[0] || !port_priv->src_pix[1])
return BadAlloc;
}
@@ -489,6 +596,29 @@ glamor_xv_put_image(glamor_port_private *port_priv,
0, 0, 0, 0,
buf + s3offset, srcPitch2);
break;
+ case FOURCC_NV12:
+ srcPitch = ALIGN(width, 4);
+ s2offset = srcPitch * height;
+ s2offset += ((top >> 1) * srcPitch);
+
+ full_box.x1 = 0;
+ full_box.y1 = 0;
+ full_box.x2 = width;
+ full_box.y2 = nlines;
+
+ half_box.x1 = 0;
+ half_box.y1 = 0;
+ half_box.x2 = width;
+ half_box.y2 = (nlines + 1) >> 1;
+
+ glamor_upload_boxes(port_priv->src_pix[0], &full_box, 1,
+ 0, 0, 0, 0,
+ buf + (top * srcPitch), srcPitch);
+
+ glamor_upload_boxes(port_priv->src_pix[1], &half_box, 1,
+ 0, 0, 0, 0,
+ buf + s2offset, srcPitch);
+ break;
default:
return BadMatch;
}
@@ -511,7 +641,7 @@ glamor_xv_put_image(glamor_port_private *port_priv,
port_priv->w = width;
port_priv->h = height;
port_priv->pDraw = pDrawable;
- glamor_xv_render(port_priv);
+ glamor_xv_render(port_priv, id);
return Success;
}
--
2.7.4
More information about the xorg-devel
mailing list