blob: 7602dc2d1a00231ffd5786cf2af34499f43bdf0d [file] [log] [blame]
/*
* Copyright 2017 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "bs_drm.h"
struct draw_format_component {
float rgb_coeffs[3];
float value_offset;
uint32_t horizontal_subsample_rate;
uint32_t vertical_subsample_rate;
uint32_t pixel_skip;
uint32_t plane_index;
uint32_t plane_offset;
};
#define MAX_COMPONENTS 4
struct bs_draw_format {
uint32_t pixel_format;
const char *name;
size_t component_count;
struct draw_format_component components[MAX_COMPONENTS];
};
#define PIXEL_FORMAT_AND_NAME(x) GBM_FORMAT_##x, #x
static const struct bs_draw_format bs_draw_formats[] = {
{
PIXEL_FORMAT_AND_NAME(NV12),
3,
{
{ { 0.2567890625f, 0.50412890625f, 0.09790625f }, 16.0f, 1, 1, 1, 0, 0 },
{ { -0.14822265625f, -0.2909921875f, 0.43921484375f }, 128.0f, 2, 2, 1, 1, 0 },
{ { 0.43921484375f, -0.3677890625f, -0.07142578125f }, 128.0f, 2, 2, 1, 1, 1 },
},
},
{
PIXEL_FORMAT_AND_NAME(YVU420),
3,
{
{ { 0.2567890625f, 0.50412890625f, 0.09790625f }, 16.0f, 1, 1, 1, 0, 0 },
{ { 0.43921484375f, -0.3677890625f, -0.07142578125f }, 128.0f, 2, 2, 1, 1, 0 },
{ { -0.14822265625f, -0.2909921875f, 0.43921484375f }, 128.0f, 2, 2, 1, 2, 0 },
},
},
{
PIXEL_FORMAT_AND_NAME(XRGB8888),
3,
{
{ { 0.0f, 0.0f, 1.0f }, 0.0f, 1, 1, 4, 0, 0 },
{ { 0.0f, 1.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 1 },
{ { 1.0f, 0.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 2 },
},
},
{
PIXEL_FORMAT_AND_NAME(ARGB8888),
4,
{
{ { 0.0f, 0.0f, 1.0f }, 0.0f, 1, 1, 4, 0, 0 },
{ { 0.0f, 1.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 1 },
{ { 1.0f, 0.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 2 },
{ { 0.0f, 0.0f, 0.0f }, 255.0f, 1, 1, 4, 0, 3 },
},
},
{
PIXEL_FORMAT_AND_NAME(YUYV),
4,
{
{ { 0.43921484375f, -0.3677890625f, -0.07142578125f }, 128.0f, 1, 1, 4, 0, 0 },
{ { 0.2567890625f, 0.50412890625f, 0.09790625f }, 16.0f, 1, 1, 4, 0, 1 },
{ { -0.14822265625f, -0.2909921875f, 0.43921484375f }, 128.0f, 1, 1, 4, 0, 2 },
{ { 0.2567890625f, 0.50412890625f, 0.09790625f }, 16.0f, 1, 1, 4, 0, 3 },
},
},
};
struct draw_plane {
uint32_t row_stride;
uint8_t *ptr;
void *map_data;
};
static uint8_t clampbyte(float f)
{
if (f >= 255.0f)
return 255;
if (f <= 0.0f)
return 0;
return (uint8_t)f;
}
uint8_t static convert_color(const struct draw_format_component *comp, uint8_t r, uint8_t g,
uint8_t b)
{
return clampbyte(comp->value_offset + r * comp->rgb_coeffs[0] + g * comp->rgb_coeffs[1] +
b * comp->rgb_coeffs[2]);
}
static void unmmap_planes(struct bs_mapper *mapper, struct gbm_bo *bo, size_t num_planes,
struct draw_plane *planes)
{
for (uint32_t plane_index = 0; plane_index < num_planes; plane_index++)
bs_mapper_unmap(mapper, bo, planes[plane_index].map_data);
}
static size_t mmap_planes(struct bs_mapper *mapper, struct gbm_bo *bo,
struct draw_plane planes[GBM_MAX_PLANES])
{
size_t num_planes = gbm_bo_get_num_planes(bo);
for (size_t plane_index = 0; plane_index < num_planes; plane_index++) {
struct draw_plane *plane = &planes[plane_index];
plane->row_stride = gbm_bo_get_plane_stride(bo, plane_index);
plane->ptr = bs_mapper_map(mapper, bo, plane_index, &plane->map_data);
if (plane->ptr == MAP_FAILED) {
bs_debug_error("failed to mmap plane %zu of buffer object", plane_index);
unmmap_planes(mapper, bo, plane_index, planes);
return 0;
}
}
return num_planes;
}
bool bs_draw_pattern(struct bs_mapper *mapper, struct gbm_bo *bo,
const struct bs_draw_format *format)
{
const uint32_t width = gbm_bo_get_width(bo);
const uint32_t height = gbm_bo_get_height(bo);
const uint32_t striph = height / 4;
struct draw_plane planes[GBM_MAX_PLANES];
size_t num_planes = mmap_planes(mapper, bo, planes);
if (num_planes == 0) {
bs_debug_error("failed to prepare to draw pattern to buffer object");
return false;
}
for (uint32_t s = 0; s < 4; s++) {
uint8_t r = 0, g = 0, b = 0;
switch (s) {
case 0:
r = g = b = 1;
break;
case 1:
r = 1;
break;
case 2:
g = 1;
break;
case 3:
b = 1;
break;
default:
r = g = b = 0;
break;
}
for (uint32_t y = s * striph; y < (s + 1) * striph; y++) {
uint8_t *rows[MAX_COMPONENTS] = { 0 };
for (size_t comp_index = 0; comp_index < format->component_count;
comp_index++) {
const struct draw_format_component *comp =
&format->components[comp_index];
struct draw_plane *plane = &planes[comp->plane_index];
rows[comp_index] =
plane->ptr + comp->plane_offset +
plane->row_stride * (y / comp->vertical_subsample_rate);
}
for (uint32_t x = 0; x < width; x++) {
const float i = (float)x / (float)width * 256.0f;
for (size_t comp_index = 0; comp_index < format->component_count;
comp_index++) {
const struct draw_format_component *comp =
&format->components[comp_index];
if ((y % comp->vertical_subsample_rate) == 0 &&
(x % comp->horizontal_subsample_rate) == 0)
*(rows[comp_index] + x * comp->pixel_skip) =
convert_color(comp, r * i, g * i, b * i);
}
}
}
}
unmmap_planes(mapper, bo, num_planes, planes);
return true;
}
const struct bs_draw_format *bs_get_draw_format(uint32_t pixel_format)
{
for (size_t format_index = 0; format_index < BS_ARRAY_LEN(bs_draw_formats);
format_index++) {
const struct bs_draw_format *format = &bs_draw_formats[format_index];
if (format->pixel_format == pixel_format)
return format;
}
return NULL;
}
const struct bs_draw_format *bs_get_draw_format_from_name(const char *str)
{
for (size_t format_index = 0; format_index < BS_ARRAY_LEN(bs_draw_formats);
format_index++) {
const struct bs_draw_format *format = &bs_draw_formats[format_index];
if (!strcmp(str, format->name))
return format;
}
return NULL;
}
uint32_t bs_get_pixel_format(const struct bs_draw_format *format)
{
assert(format);
return format->pixel_format;
}
const char *bs_get_format_name(const struct bs_draw_format *format)
{
assert(format);
return format->name;
}