mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-24 08:30:16 +00:00
Support YV12
Only I420 and YZ12 are available on xwayland. Support it
This commit is contained in:
parent
9c4fde00ce
commit
a86e8e0f36
@ -83,6 +83,10 @@ typedef struct xv
|
||||
|
||||
void (*render_func)(struct xv*, const void *frame,
|
||||
unsigned width, unsigned height, unsigned pitch);
|
||||
|
||||
void (*render_glyph)(struct xv*, int base_x, int base_y,
|
||||
const uint8_t *glyph, int atlas_width,
|
||||
int glyph_width, int glyph_height);
|
||||
} xv_t;
|
||||
|
||||
static void xv_set_nonblock_state(void *data, bool state, bool c, unsigned d)
|
||||
@ -295,34 +299,242 @@ static void render32_uyvy(xv_t *xv, const void *input_,
|
||||
}
|
||||
}
|
||||
|
||||
static void render32_yuv12(xv_t *xv, const void *input_,
|
||||
unsigned width, unsigned height, unsigned pitch)
|
||||
{
|
||||
unsigned x, y;
|
||||
const uint32_t *input = (const uint32_t*)input_;
|
||||
unsigned w0 = xv->width >> 1;
|
||||
unsigned w1 = w0 << 1;
|
||||
unsigned h0 = xv->height >> 1;
|
||||
uint8_t *output = (uint8_t*)xv->image->data;
|
||||
uint8_t *outputu = (uint8_t*)xv->image->data + 4 * w0 * h0;
|
||||
uint8_t *outputv = (uint8_t*)xv->image->data + 5 * w0 * h0;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
uint8_t y0, u, v;
|
||||
unsigned img_width;
|
||||
uint32_t p = *input++;
|
||||
p = ((p >> 8) & 0xf800) | ((p >> 5) & 0x07e0)
|
||||
| ((p >> 3) & 0x1f); /* ARGB -> RGB16 */
|
||||
|
||||
y0 = xv->ytable[p];
|
||||
u = xv->utable[p];
|
||||
v = xv->vtable[p];
|
||||
|
||||
output[0] = output[w1] = y0;
|
||||
output[1] = output[w1+1] = y0;
|
||||
output+=2;
|
||||
*outputu++ = u;
|
||||
*outputv++ = v;
|
||||
}
|
||||
|
||||
input += (pitch >> 2) - width;
|
||||
output += 4 * w0 - 2 * width;
|
||||
outputu += (w0 - width);
|
||||
outputv += (w0 - width);
|
||||
}
|
||||
}
|
||||
|
||||
static void render16_yuv12(xv_t *xv, const void *input_,
|
||||
unsigned width, unsigned height, unsigned pitch)
|
||||
{
|
||||
unsigned x, y;
|
||||
const uint16_t *input = (const uint16_t*)input_;
|
||||
unsigned w0 = xv->width >> 1;
|
||||
unsigned w1 = w0 << 1;
|
||||
unsigned h0 = xv->height >> 1;
|
||||
uint8_t *output = (uint8_t*)xv->image->data;
|
||||
uint8_t *outputu = (uint8_t*)xv->image->data + 4 * w0 * h0;
|
||||
uint8_t *outputv = (uint8_t*)xv->image->data + 5 * w0 * h0;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
uint16_t p = *input++;
|
||||
uint8_t y0 = xv->ytable[p];
|
||||
uint8_t u = xv->utable[p];
|
||||
uint8_t v = xv->vtable[p];
|
||||
|
||||
output[0] = output[w1] = y0;
|
||||
output[1] = output[w1+1] = y0;
|
||||
output+=2;
|
||||
*outputu++ = u;
|
||||
*outputv++ = v;
|
||||
}
|
||||
|
||||
input += (pitch >> 1) - width;
|
||||
output += 4 * w0 - 2 * width;
|
||||
outputu += (w0 - width);
|
||||
outputv += (w0 - width);
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void render_glyph_yuv12(xv_t *xv, int base_x, int base_y,
|
||||
const uint8_t *glyph, int atlas_width,
|
||||
int glyph_width, int glyph_height)
|
||||
{
|
||||
uint8_t *out_luma, *out_u, *out_v;
|
||||
int x, y, i;
|
||||
|
||||
out_luma = (uint8_t*)xv->image->data + base_y * xv->width + (base_x);
|
||||
out_u = (uint8_t*)xv->image->data + xv->width * xv->height + (base_y / 2) * xv->width / 2 + (base_x / 2);
|
||||
out_v= (uint8_t*)xv->image->data + xv->width * xv->height * 5 / 4 + (base_y / 2) * xv->width / 2 + (base_x / 2);
|
||||
|
||||
for (y = 0; y < glyph_height; y++, glyph += atlas_width, out_luma += xv->width)
|
||||
{
|
||||
/* 2 input pixels => 4 bytes (2Y, 1U, 1V). */
|
||||
|
||||
for (x = 0; x < glyph_width; x += 2)
|
||||
{
|
||||
unsigned alpha[2], alpha_sub, blended;
|
||||
|
||||
alpha[0] = glyph[x + 0];
|
||||
alpha[1] = 0;
|
||||
|
||||
if (x + 1 < glyph_width)
|
||||
alpha[1] = glyph[x + 1];
|
||||
|
||||
/* Blended alpha for the sub-sampled U/V channels. */
|
||||
alpha_sub = (alpha[0] + alpha[1]) >> 1;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
unsigned blended = (xv->font_y * alpha[i]
|
||||
+ ((256 - alpha[i]) * out_luma[x+i])) >> 8;
|
||||
out_luma[x+i] = blended;
|
||||
}
|
||||
|
||||
/* Blend chroma channels */
|
||||
if (y & 1)
|
||||
{
|
||||
blended = (xv->font_u * alpha_sub
|
||||
+ ((256 - alpha_sub) * out_u[x/2])) >> 8;
|
||||
out_u[x / 2] = blended;
|
||||
|
||||
blended = (xv->font_v * alpha_sub
|
||||
+ ((256 - alpha_sub) * out_v[x/2])) >> 8;
|
||||
out_v[x/2] = blended;
|
||||
}
|
||||
}
|
||||
|
||||
if (y & 1)
|
||||
{
|
||||
out_u += xv->width / 2;
|
||||
out_v += xv->width / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void render_glyph_yuv_packed(xv_t *xv, int base_x, int base_y,
|
||||
const uint8_t *glyph, int atlas_width,
|
||||
int glyph_width, int glyph_height)
|
||||
{
|
||||
uint8_t *out = NULL;
|
||||
int x, y, i;
|
||||
unsigned luma_index[2], pitch;
|
||||
unsigned chroma_u_index, chroma_v_index;
|
||||
|
||||
luma_index[0] = xv->luma_index[0];
|
||||
luma_index[1] = xv->luma_index[1];
|
||||
|
||||
chroma_u_index = xv->chroma_u_index;
|
||||
chroma_v_index = xv->chroma_v_index;
|
||||
|
||||
pitch = xv->width << 1; /* YUV formats used are 16 bpp. */
|
||||
out = (uint8_t*)xv->image->data + base_y * pitch + (base_x << 1);
|
||||
|
||||
for (y = 0; y < glyph_height; y++, glyph += atlas_width, out += pitch)
|
||||
{
|
||||
/* 2 input pixels => 4 bytes (2Y, 1U, 1V). */
|
||||
|
||||
for (x = 0; x < glyph_width; x += 2)
|
||||
{
|
||||
unsigned alpha[2], alpha_sub, blended;
|
||||
int out_x = x << 1;
|
||||
|
||||
alpha[0] = glyph[x + 0];
|
||||
alpha[1] = 0;
|
||||
|
||||
if (x + 1 < glyph_width)
|
||||
alpha[1] = glyph[x + 1];
|
||||
|
||||
/* Blended alpha for the sub-sampled U/V channels. */
|
||||
alpha_sub = (alpha[0] + alpha[1]) >> 1;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
unsigned blended = (xv->font_y * alpha[i]
|
||||
+ ((256 - alpha[i]) * out[out_x + luma_index[i]])) >> 8;
|
||||
out[out_x + luma_index[i]] = blended;
|
||||
}
|
||||
|
||||
/* Blend chroma channels */
|
||||
blended = (xv->font_u * alpha_sub
|
||||
+ ((256 - alpha_sub) * out[out_x + chroma_u_index])) >> 8;
|
||||
out[out_x + chroma_u_index] = blended;
|
||||
|
||||
blended = (xv->font_v * alpha_sub
|
||||
+ ((256 - alpha_sub) * out[out_x + chroma_v_index])) >> 8;
|
||||
out[out_x + chroma_v_index] = blended;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct format_desc
|
||||
{
|
||||
void (*render_16)(xv_t *xv, const void *input,
|
||||
unsigned width, unsigned height, unsigned pitch);
|
||||
void (*render_32)(xv_t *xv, const void *input,
|
||||
unsigned width, unsigned height, unsigned pitch);
|
||||
void (*render_glyph)(xv_t *xv, int base_x, int base_y,
|
||||
const uint8_t *glyph, int atlas_width,
|
||||
int glyph_width, int glyph_height);
|
||||
char components[4];
|
||||
unsigned luma_index[2];
|
||||
unsigned u_index;
|
||||
unsigned v_index;
|
||||
unsigned bits;
|
||||
int format;
|
||||
};
|
||||
|
||||
static const struct format_desc formats[] = {
|
||||
{
|
||||
render16_yuy2,
|
||||
render32_yuy2,
|
||||
render_glyph_yuv_packed,
|
||||
{ 'Y', 'U', 'Y', 'V' },
|
||||
{ 0, 2 },
|
||||
1,
|
||||
3,
|
||||
16,
|
||||
XvPacked
|
||||
},
|
||||
{
|
||||
render16_uyvy,
|
||||
render32_uyvy,
|
||||
render_glyph_yuv_packed,
|
||||
{ 'U', 'Y', 'V', 'Y' },
|
||||
{ 1, 3 },
|
||||
0,
|
||||
2,
|
||||
16,
|
||||
XvPacked
|
||||
},
|
||||
{
|
||||
render16_yuv12,
|
||||
render32_yuv12,
|
||||
render_glyph_yuv12,
|
||||
{ 'Y', 'U', 'V', 0 },
|
||||
{ 1, 3 },
|
||||
0,
|
||||
2,
|
||||
12,
|
||||
XvPlanar
|
||||
},
|
||||
};
|
||||
|
||||
@ -343,8 +555,8 @@ static bool xv_adaptor_set_format(xv_t *xv, Display *dpy,
|
||||
for (j = 0; j < ARRAY_SIZE(formats); j++)
|
||||
{
|
||||
if (format[i].type == XvYUV
|
||||
&& format[i].bits_per_pixel == 16
|
||||
&& format[i].format == XvPacked)
|
||||
&& format[i].bits_per_pixel == formats[j].bits
|
||||
&& format[i].format == formats[j].format)
|
||||
{
|
||||
if (format[i].component_order[0] == formats[j].components[0] &&
|
||||
format[i].component_order[1] == formats[j].components[1] &&
|
||||
@ -354,6 +566,7 @@ static bool xv_adaptor_set_format(xv_t *xv, Display *dpy,
|
||||
xv->fourcc = format[i].id;
|
||||
xv->render_func = video->rgb32
|
||||
? formats[j].render_32 : formats[j].render_16;
|
||||
xv->render_glyph = formats[j].render_glyph;
|
||||
|
||||
xv->luma_index[0] = formats[j].luma_index[0];
|
||||
xv->luma_index[1] = formats[j].luma_index[1];
|
||||
@ -724,9 +937,7 @@ static bool xv_check_resize(xv_t *xv, unsigned width, unsigned height)
|
||||
static void xv_render_msg(xv_t *xv, const char *msg,
|
||||
unsigned width, unsigned height)
|
||||
{
|
||||
int x, y, msg_base_x, msg_base_y;
|
||||
unsigned i, luma_index[2], pitch;
|
||||
unsigned chroma_u_index, chroma_v_index;
|
||||
int msg_base_x, msg_base_y;
|
||||
const struct font_atlas *atlas = NULL;
|
||||
settings_t *settings = config_get_ptr();
|
||||
float video_msg_pos_x = settings->floats.video_msg_pos_x;
|
||||
@ -740,19 +951,10 @@ static void xv_render_msg(xv_t *xv, const char *msg,
|
||||
msg_base_x = video_msg_pos_x * width;
|
||||
msg_base_y = height * (1.0f - video_msg_pos_y);
|
||||
|
||||
luma_index[0] = xv->luma_index[0];
|
||||
luma_index[1] = xv->luma_index[1];
|
||||
|
||||
chroma_u_index = xv->chroma_u_index;
|
||||
chroma_v_index = xv->chroma_v_index;
|
||||
|
||||
pitch = width << 1; /* YUV formats used are 16 bpp. */
|
||||
|
||||
for (; *msg; msg++)
|
||||
{
|
||||
int base_x, base_y, glyph_width, glyph_height, max_width, max_height;
|
||||
const uint8_t *src = NULL;
|
||||
uint8_t *out = NULL;
|
||||
const struct font_glyph *glyph =
|
||||
xv->font_driver->get_glyph(xv->font, (uint8_t)*msg);
|
||||
|
||||
@ -795,43 +997,7 @@ static void xv_render_msg(xv_t *xv, const char *msg,
|
||||
if (glyph_height > max_height)
|
||||
glyph_height = max_height;
|
||||
|
||||
out = (uint8_t*)xv->image->data + base_y * pitch + (base_x << 1);
|
||||
|
||||
for (y = 0; y < glyph_height; y++, src += atlas->width, out += pitch)
|
||||
{
|
||||
/* 2 input pixels => 4 bytes (2Y, 1U, 1V). */
|
||||
|
||||
for (x = 0; x < glyph_width; x += 2)
|
||||
{
|
||||
unsigned alpha[2], alpha_sub, blended;
|
||||
int out_x = x << 1;
|
||||
|
||||
alpha[0] = src[x + 0];
|
||||
alpha[1] = 0;
|
||||
|
||||
if (x + 1 < glyph_width)
|
||||
alpha[1] = src[x + 1];
|
||||
|
||||
/* Blended alpha for the sub-sampled U/V channels. */
|
||||
alpha_sub = (alpha[0] + alpha[1]) >> 1;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
unsigned blended = (xv->font_y * alpha[i]
|
||||
+ ((256 - alpha[i]) * out[out_x + luma_index[i]])) >> 8;
|
||||
out[out_x + luma_index[i]] = blended;
|
||||
}
|
||||
|
||||
/* Blend chroma channels */
|
||||
blended = (xv->font_u * alpha_sub
|
||||
+ ((256 - alpha_sub) * out[out_x + chroma_u_index])) >> 8;
|
||||
out[out_x + chroma_u_index] = blended;
|
||||
|
||||
blended = (xv->font_v * alpha_sub
|
||||
+ ((256 - alpha_sub) * out[out_x + chroma_v_index])) >> 8;
|
||||
out[out_x + chroma_v_index] = blended;
|
||||
}
|
||||
}
|
||||
xv->render_glyph(xv, base_x, base_y, src, atlas->width, glyph_width, glyph_height);
|
||||
|
||||
msg_base_x += glyph->advance_x;
|
||||
msg_base_y += glyph->advance_y;
|
||||
|
Loading…
Reference in New Issue
Block a user