@@ -74,7 +74,7 @@ static struct format_desc_struct {
/* helpers to create nice-looking framebuffers */
-static int create_bo_for_fb(int fd, int width, int height, int bpp,
+static int create_bo_for_fb(int fd, int width, int height, int bpp, int bpp2,
uint64_t tiling, unsigned bo_size,
uint32_t *gem_handle_ret,
unsigned *size_ret,
@@ -99,13 +99,17 @@ static int create_bo_for_fb(int fd, int width, int height, int bpp,
for (stride = 512; stride < v; stride *= 2)
;
- v = stride * height;
+ /* planar formats height is 1.5x */
+ v = stride * (bpp2 ? (height * 3) / 2 : height);
+
for (size = 1024*1024; size < v; size *= 2)
;
} else {
/* Scan-out has a 64 byte alignment restriction */
stride = (width * (bpp / 8) + 63) & ~63;
- size = stride * height;
+
+ /* planar formats height is 1.5x */
+ size = stride * (bpp2 ? (height * 3) / 2 : height);
}
if (bo_size == 0)
@@ -393,6 +397,75 @@ void igt_paint_image(cairo_t *cr, const char *filename,
}
/**
+ * igt_get_image_size:
+ * @filename: filename of the png image
+ * @width: width of the image
+ * @height: height of the image
+ *
+ * This function returns @width and @height of the png image in @filename,
+ * which is loaded from the package data directory.
+ */
+void
+igt_get_image_size(const char *filename, int *width, int *height)
+{
+ cairo_surface_t *image;
+ FILE* f;
+
+ f = igt_fopen_data(filename);
+
+ image = cairo_image_surface_create_from_png_stream(&stdio_read_func, f);
+ igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
+
+ *width = cairo_image_surface_get_width(image);
+ *height = cairo_image_surface_get_height(image);
+
+ cairo_surface_destroy(image);
+
+ fclose(f);
+}
+
+
+/**
+ * igt_fb_calc_uv:
+ * @fb: pointer to an #igt_fb structure
+ *
+ * This function calculates UV offset in bytes and UV starting line number
+ * for requested NV12 @fb.
+ */
+void
+igt_fb_calc_uv(struct igt_fb *fb)
+{
+ if (fb->drm_format != DRM_FORMAT_NV12)
+ return;
+
+ switch (fb->tiling) {
+ case LOCAL_DRM_FORMAT_MOD_NONE:
+ fb->uv_y_start = fb->height;
+ break;
+ case LOCAL_I915_FORMAT_MOD_X_TILED:
+ fb->uv_y_start = fb->height;
+ break;
+ case LOCAL_I915_FORMAT_MOD_Y_TILED:
+ fb->uv_y_start = fb->height;
+ break;
+ case LOCAL_I915_FORMAT_MOD_Yf_TILED:
+ /* tile-Yf requires uv to start on a new tile row */
+ if (fb->height % 64)
+ fb->uv_y_start = (fb->height + 63) & ~63;
+ else
+ fb->uv_y_start = fb->height;
+ break;
+ default:
+ igt_assert(0);
+ }
+
+ fb->uv_offset = fb->uv_y_start * fb->stride;
+
+ /* assert that fb has enough lines to hold y and uv sub-planes */
+ igt_assert(fb->size / fb->stride >= fb->uv_y_start + fb->height / 2);
+}
+
+/**
* igt_create_fb_with_bo_size:
* @fd: open i915 drm file descriptor
* @width: width of the framebuffer in pixel
@@ -418,24 +491,32 @@ igt_create_fb_with_bo_size(int fd, int width, int height,
struct igt_fb *fb, unsigned bo_size)
{
uint32_t fb_id;
- int bpp;
+ int bpp, bpp2;
memset(fb, 0, sizeof(*fb));
- bpp = igt_drm_format_to_bpp(format);
+ bpp = igt_drm_format_to_bpp(format, 0);
+ bpp2 = igt_drm_format_to_bpp(format, 1);
- igt_debug("%s(width=%d, height=%d, format=0x%x [bpp=%d], tiling=0x%"PRIx64", size=%d\n",
- __func__, width, height, format, bpp, tiling, bo_size);
- do_or_die(create_bo_for_fb(fd, width, height, bpp, tiling, bo_size,
+ igt_debug("%s(width=%d, height=%d, format=0x%x [bpp=%d, %d], tiling=0x%"PRIx64", size=%d\n",
+ __func__, width, height, format, bpp, bpp2, tiling, bo_size);
+ do_or_die(create_bo_for_fb(fd, width, height, bpp, bpp2, tiling, bo_size,
&fb->gem_handle, &fb->size, &fb->stride));
igt_debug("%s(handle=%d, pitch=%d)\n",
__func__, fb->gem_handle, fb->stride);
+ fb->width = width;
+ fb->height = height;
+ fb->tiling = tiling;
+ fb->drm_format = format;
+
+ igt_fb_calc_uv(fb);
+
if (tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
tiling != LOCAL_I915_FORMAT_MOD_X_TILED) {
do_or_die(__kms_addfb(fd, fb->gem_handle, width, height,
- fb->stride, format, tiling,
+ fb->stride, format, tiling, fb->uv_offset,
LOCAL_DRM_MODE_FB_MODIFIERS, &fb_id));
} else {
uint32_t handles[4];
@@ -449,21 +530,213 @@ igt_create_fb_with_bo_size(int fd, int width, int height,
handles[0] = fb->gem_handle;
pitches[0] = fb->stride;
+ if (format == DRM_FORMAT_NV12) {
+ handles[1] = fb->gem_handle;
+ pitches[1] = fb->stride;
+ offsets[1] = fb->uv_offset;
+ }
+
do_or_die(drmModeAddFB2(fd, width, height, format,
handles, pitches, offsets,
&fb_id, 0));
}
- fb->width = width;
- fb->height = height;
- fb->tiling = tiling;
- fb->drm_format = format;
fb->fb_id = fb_id;
return fb_id;
}
/**
+ * igt_fb_gem_mmap:
+ * @fd: open i915 drm file descriptor
+ * @fb: pointer to an #igt_fb structure
+ *
+ * This function memory maps gem buffer for cpu access and saves mmap pointer
+ * in @fb.
+ */
+void
+igt_fb_gem_mmap(int fd, struct igt_fb *fb)
+{
+ if (!fb->mmap_gtt)
+ fb->mmap_gtt = gem_mmap__gtt(fd, fb->gem_handle, fb->size,
+ PROT_READ | PROT_WRITE);
+ igt_assert(fb->mmap_gtt);
+}
+
+/**
+ * igt_fb_csc_xrgb_to_nv12:
+ * @fd: open i915 drm file descriptor
+ * @width: width of the framebuffer to be converted
+ * @height: height of the framebuffer to be converted
+ * @dst: pointer to an #igt_fb structure holding destination framebuffer
+ * @src: pointer to an #igt_fb structure holding source framebuffer
+ *
+ * This function converts source framebuffer into destination framebuffer
+ * format. It also mmaps the underlying gem buffer if it isn't mmaped
+ * before.
+ *
+ * For now:
+ * - it expects both src and dst fbs are same size and tiling
+ */
+void
+igt_fb_csc_xrgb_to_nv12(int fd, struct igt_fb *dst_fb, struct igt_fb *src_fb)
+{
+ unsigned char *nv12;
+ unsigned char *xrgb;
+ unsigned char y, v, u;
+ float yf, vf, uf;
+ unsigned char r, g, b;
+ int i, j;
+ int xrgb_pos;
+ int y_pos;
+ int uv_pos;
+ int uv_base;
+ unsigned int obj_tiling;
+ struct igt_fb *temp_src_fb, *temp_dst_fb;
+ struct igt_fb fb1, fb2;
+ int temp_src_id, temp_dst_id;
+
+ igt_assert(dst_fb);
+ igt_assert(src_fb);
+ igt_assert(dst_fb->width == src_fb->width);
+ igt_assert(dst_fb->height == src_fb->height);
+ igt_assert(src_fb->tiling == dst_fb->tiling);
+
+ igt_assert(src_fb->drm_format == DRM_FORMAT_XRGB8888);
+ igt_assert(dst_fb->drm_format == DRM_FORMAT_NV12);
+
+ /*
+ * Steps: Not the best approach but gets job done for igt
+ * (1) create linear temp_src, temp_dst
+ * (2) fast blit src --> temp src
+ * (3) gem map temp_src, temp_dst
+ * (4) host conversion & copy from temp src --> temp dst
+ * (5) fast blit temp dst --> dst
+ * (6) free temp fbs
+ *
+ * For Linear/X:
+ * perform 3 & 4 only
+ * For Y/Yf:
+ * perform all steps
+ */
+
+ if (src_fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
+ src_fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED) {
+
+ temp_src_fb = &fb1;
+ temp_dst_fb = &fb2;
+
+ /* (1) create linear temp_src, temp_dst */
+ temp_src_id = igt_create_fb(fd,
+ src_fb->width, src_fb->height,
+ src_fb->drm_format,
+ LOCAL_DRM_FORMAT_MOD_NONE,
+ temp_src_fb);
+ igt_assert(temp_src_id);
+
+ temp_dst_id = igt_create_fb(fd,
+ dst_fb->width, dst_fb->height,
+ dst_fb->drm_format,
+ LOCAL_DRM_FORMAT_MOD_NONE,
+ temp_dst_fb);
+ igt_assert(temp_dst_id);
+
+ if (src_fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED)
+ obj_tiling = I915_TILING_Y;
+ else
+ obj_tiling = I915_TILING_Yf;
+
+ /* (2) fast blit src --> temp src */
+ igt_blitter_fast_copy__raw(fd,
+ src_fb->gem_handle,
+ src_fb->stride,
+ obj_tiling,
+ 0, 0,
+ temp_src_fb->width, temp_src_fb->height,
+ igt_drm_format_to_bpp(temp_src_fb->drm_format, 0),
+ temp_src_fb->gem_handle,
+ temp_src_fb->stride,
+ I915_TILING_NONE,
+ 0, 0);
+ } else {
+ temp_src_fb = src_fb;
+ temp_dst_fb = dst_fb;
+ }
+
+ /* (3) gem map temp_src, temp_dst */
+ igt_fb_gem_mmap(fd, temp_src_fb);
+ igt_fb_gem_mmap(fd, temp_dst_fb);
+
+ /* (4) host conversion & copy from temp src --> temp dst */
+ xrgb = (unsigned char *) temp_src_fb->mmap_gtt;
+ nv12 = (unsigned char *) temp_dst_fb->mmap_gtt;
+ uv_base = temp_dst_fb->stride * temp_dst_fb->height;
+
+ for (i = 0; i < temp_src_fb->height; i++) {
+ xrgb_pos = i * temp_src_fb->stride;
+ y_pos = i * temp_dst_fb->stride;
+ uv_pos = temp_dst_fb->stride * i / 2;
+ for (j = 0; j < temp_src_fb->width; j++) {
+ b = xrgb[xrgb_pos++];
+ g = xrgb[xrgb_pos++];
+ r = xrgb[xrgb_pos++];
+ xrgb_pos++;
+
+ /* use floats for intermediate calcs, to get better results */
+ yf = (0.257 * r) + (0.504 * g) + (0.098 * b) + 16;
+ uf = -(0.148 * r) - (0.291 * g) + (0.439 * b) + 128;
+ vf = (0.439 * r) - (0.368 * g) - (0.071 * b) + 128;
+
+ y = (unsigned char) yf;
+ u = (unsigned char) uf;
+ v = (unsigned char) vf;
+
+ nv12[y_pos++] = y;
+
+ if (!(j % 2) && !(i % 2)) {
+ nv12[uv_base + uv_pos++] = u;
+ nv12[uv_base + uv_pos++] = v;
+ }
+ }
+ }
+
+ /* (5) fast blit temp dst --> dst */
+ if (dst_fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
+ dst_fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED) {
+
+ /* blit y-plane */
+ igt_blitter_fast_copy__raw(fd,
+ temp_dst_fb->gem_handle,
+ temp_dst_fb->stride,
+ I915_TILING_NONE,
+ 0, 0,
+ dst_fb->width, dst_fb->height,
+ igt_drm_format_to_bpp(dst_fb->drm_format, 0),
+ dst_fb->gem_handle,
+ dst_fb->stride,
+ obj_tiling,
+ 0, 0);
+
+ /* blit uv-plane */
+ igt_blitter_fast_copy__raw(fd,
+ temp_dst_fb->gem_handle,
+ temp_dst_fb->stride,
+ I915_TILING_NONE,
+ 0, temp_dst_fb->uv_y_start,
+ dst_fb->width, dst_fb->height,
+ igt_drm_format_to_bpp(dst_fb->drm_format, 1),
+ dst_fb->gem_handle,
+ dst_fb->stride,
+ obj_tiling,
+ 0, dst_fb->uv_y_start);
+
+ /* (6) free temp fbs */
+ igt_remove_fb(fd, temp_src_fb);
+ igt_remove_fb(fd, temp_dst_fb);
+ }
+}
+
+/**
* igt_create_fb:
* @fd: open i915 drm file descriptor
* @width: width of the framebuffer in pixel
@@ -686,6 +959,7 @@ static void destroy_cairo_surface__blit(void *arg)
I915_TILING_NONE,
0, 0, /* src_x, src_y */
fb->width, fb->height,
+ 0,
fb->gem_handle,
fb->stride,
obj_tiling,
@@ -712,8 +986,8 @@ static void create_cairo_surface__blit(int fd, struct igt_fb *fb)
* cairo). This linear bo will be then blitted to its final
* destination, tiling it at the same time.
*/
- bpp = igt_drm_format_to_bpp(fb->drm_format);
- ret = create_bo_for_fb(fd, fb->width, fb->height, bpp,
+ bpp = igt_drm_format_to_bpp(fb->drm_format, 0);
+ ret = create_bo_for_fb(fd, fb->width, fb->height, bpp, 0,
LOCAL_DRM_FORMAT_MOD_NONE, 0,
&blit->linear.handle,
&blit->linear.size,
@@ -734,6 +1008,7 @@ static void create_cairo_surface__blit(int fd, struct igt_fb *fb)
obj_tiling,
0, 0, /* src_x, src_y */
fb->width, fb->height,
+ bpp,
blit->linear.handle,
blit->linear.stride,
I915_TILING_NONE,
@@ -893,15 +1168,24 @@ uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth)
/**
* igt_drm_format_to_bpp:
* @drm_format: drm fourcc pixel format code
+ * @plane: plane id
*
* Returns:
* The bits per pixel for the given drm fourcc pixel format code. Fails hard if
* no match was found.
*/
-uint32_t igt_drm_format_to_bpp(uint32_t drm_format)
+uint32_t igt_drm_format_to_bpp(uint32_t drm_format, int plane)
{
struct format_desc_struct *f;
+ if (drm_format == DRM_FORMAT_NV12 && plane == 0)
+ return 8;
+ if (drm_format == DRM_FORMAT_NV12 && plane == 1)
+ return 16;
+
+ if (plane)
+ return 0;
+
for_each_format(f)
if (f->drm_id == drm_format)
return f->bpp;
@@ -54,10 +54,13 @@ struct igt_fb {
uint64_t tiling;
unsigned size;
cairo_surface_t *cairo_surface;
+ void *mmap_gtt;
uint32_t src_x;
uint32_t src_y;
uint32_t src_w;
uint32_t src_h;
+ uint32_t uv_y_start;
+ uint32_t uv_offset;
};
enum igt_text_align {
@@ -82,6 +85,9 @@ unsigned int igt_create_color_fb(int fd, int width, int height,
unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
uint32_t format, uint64_t tiling);
void igt_remove_fb(int fd, struct igt_fb *fb);
+void igt_fb_gem_mmap(int fd, struct igt_fb *fb);
+void igt_fb_csc_xrgb_to_nv12(int fd, struct igt_fb *dst, struct igt_fb *src);
+void igt_fb_calc_uv(struct igt_fb *fb);
/* cairo-based painting */
cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb);
@@ -98,10 +104,11 @@ void igt_write_fb_to_png(int fd, struct igt_fb *fb, const char *filename);
int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
double yspacing, const char *fmt, ...)
__attribute__((format (printf, 4, 5)));
+void igt_get_image_size(const char *filename, int *width, int *height);
/* helpers to handle drm fourcc codes */
uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth);
-uint32_t igt_drm_format_to_bpp(uint32_t drm_format);
+uint32_t igt_drm_format_to_bpp(uint32_t drm_format, int plane);
const char *igt_format_str(uint32_t drm_format);
void igt_get_all_formats(const uint32_t **formats, int *format_count);
@@ -519,7 +519,7 @@ static uint32_t fast_copy_dword0(unsigned int src_tiling,
}
static uint32_t fast_copy_dword1(unsigned int src_tiling,
- unsigned int dst_tiling)
+ unsigned int dst_tiling, uint32_t color_depth)
{
uint32_t dword1 = 0;
@@ -528,7 +528,10 @@ static uint32_t fast_copy_dword1(unsigned int src_tiling,
if (dst_tiling == I915_TILING_Yf)
dword1 |= XY_FAST_COPY_DST_TILING_Yf;
- dword1 |= XY_FAST_COPY_COLOR_DEPTH_32;
+ if (color_depth == 8)
+ dword1 |= XY_FAST_COPY_COLOR_DEPTH_8;
+ else
+ dword1 |= XY_FAST_COPY_COLOR_DEPTH_32;
return dword1;
}
@@ -586,6 +589,7 @@ static void exec_blit(int fd,
* @src_y: Y coordinate of the source region to copy
* @width: Width of the region to copy
* @height: Height of the region to copy
+ * @color_depth: Color depth of the buffer
* @dst_handle: GEM handle of the source buffer
* @dst_stride: Stride (in bytes) of the destination buffer
* @dst_tiling: Tiling mode of the destination buffer
@@ -603,6 +607,7 @@ void igt_blitter_fast_copy__raw(int fd,
/* size */
unsigned int width, unsigned int height,
+ uint32_t color_depth,
/* dst */
uint32_t dst_handle,
@@ -621,7 +626,7 @@ void igt_blitter_fast_copy__raw(int fd,
src_pitch = fast_copy_pitch(src_stride, src_tiling);
dst_pitch = fast_copy_pitch(dst_stride, dst_tiling);
dword0 = fast_copy_dword0(src_tiling, dst_tiling);
- dword1 = fast_copy_dword1(src_tiling, dst_tiling);
+ dword1 = fast_copy_dword1(src_tiling, dst_tiling, color_depth);
#define CHECK_RANGE(x) ((x) >= 0 && (x) < (1 << 15))
assert(CHECK_RANGE(src_x) && CHECK_RANGE(src_y) &&
@@ -671,6 +676,7 @@ void igt_blitter_fast_copy__raw(int fd,
* @src_y: source pixel y-coordination
* @width: width of the copied rectangle
* @height: height of the copied rectangle
+ * @color_depth: Color depth of the buffer
* @dst: destination i-g-t buffer object
* @dst_x: destination pixel x-coordination
* @dst_y: destination pixel y-coordination
@@ -681,7 +687,7 @@ void igt_blitter_fast_copy__raw(int fd,
*/
void igt_blitter_fast_copy(struct intel_batchbuffer *batch,
struct igt_buf *src, unsigned src_x, unsigned src_y,
- unsigned width, unsigned height,
+ unsigned width, unsigned height, uint32_t color_depth,
struct igt_buf *dst, unsigned dst_x, unsigned dst_y)
{
uint32_t src_pitch, dst_pitch;
@@ -690,7 +696,7 @@ void igt_blitter_fast_copy(struct intel_batchbuffer *batch,
src_pitch = fast_copy_pitch(src->stride, src->tiling);
dst_pitch = fast_copy_pitch(dst->stride, src->tiling);
dword0 = fast_copy_dword0(src->tiling, dst->tiling);
- dword1 = fast_copy_dword1(src->tiling, dst->tiling);
+ dword1 = fast_copy_dword1(src->tiling, dst->tiling, color_depth);
#define CHECK_RANGE(x) ((x) >= 0 && (x) < (1 << 15))
assert(CHECK_RANGE(src_x) && CHECK_RANGE(src_y) &&
@@ -227,7 +227,7 @@ unsigned igt_buf_height(struct igt_buf *buf);
void igt_blitter_fast_copy(struct intel_batchbuffer *batch,
struct igt_buf *src, unsigned src_x, unsigned src_y,
- unsigned width, unsigned height,
+ unsigned width, unsigned height, uint32_t color_depth,
struct igt_buf *dst, unsigned dst_x, unsigned dst_y);
void igt_blitter_fast_copy__raw(int fd,
@@ -239,6 +239,7 @@ void igt_blitter_fast_copy__raw(int fd,
/* size */
unsigned int width, unsigned int height,
+ uint32_t color_depth,
/* dst */
uint32_t dst_handle,
@@ -2530,6 +2530,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/* dword 1 */
#define XY_FAST_COPY_SRC_TILING_Yf (1 << 31)
#define XY_FAST_COPY_DST_TILING_Yf (1 << 30)
+#define XY_FAST_COPY_COLOR_DEPTH_8 (0 << 24)
#define XY_FAST_COPY_COLOR_DEPTH_32 (3 << 24)
#define MI_STORE_DWORD_IMM ((0x20<<23)|2)
@@ -54,6 +54,7 @@
#include "intel_chipset.h"
#include "intel_io.h"
#include "igt_debugfs.h"
+#include "igt_fb.h"
#include "config.h"
#include "ioctl_wrappers.h"
@@ -1221,7 +1222,7 @@ void igt_require_fb_modifiers(int fd)
int __kms_addfb(int fd, uint32_t handle, uint32_t width, uint32_t height,
uint32_t stride, uint32_t pixel_format, uint64_t modifier,
- uint32_t flags, uint32_t *buf_id)
+ uint32_t uv_offset, uint32_t flags, uint32_t *buf_id)
{
struct local_drm_mode_fb_cmd2 f;
int ret;
@@ -1238,6 +1239,13 @@ int __kms_addfb(int fd, uint32_t handle, uint32_t width, uint32_t height,
f.pitches[0] = stride;
f.modifier[0] = modifier;
+ if (pixel_format == DRM_FORMAT_NV12) {
+ f.handles[1] = handle;
+ f.pitches[1] = stride;
+ f.offsets[1] = uv_offset;
+ f.modifier[1] = modifier;
+ }
+
ret = drmIoctl(fd, LOCAL_DRM_IOCTL_MODE_ADDFB2, &f);
*buf_id = f.fb_id;
@@ -176,6 +176,6 @@ void igt_require_fb_modifiers(int fd);
*/
int __kms_addfb(int fd, uint32_t handle, uint32_t width, uint32_t height,
uint32_t stride, uint32_t pixel_format, uint64_t modifier,
- uint32_t flags, uint32_t *buf_id);
+ uint32_t uv_offset, uint32_t flags, uint32_t *buf_id);
#endif /* IOCTL_WRAPPERS_H */
@@ -78,8 +78,8 @@ static void gpu_blit(struct igt_fb *dst_fb, struct igt_fb *src_fb)
igt_assert(dst_fb->drm_format == src_fb->drm_format);
igt_assert(src_fb->drm_format == DRM_FORMAT_RGB565 ||
- igt_drm_format_to_bpp(src_fb->drm_format) != 16);
- bpp = igt_drm_format_to_bpp(src_fb->drm_format);
+ igt_drm_format_to_bpp(src_fb->drm_format, 0) != 16);
+ bpp = igt_drm_format_to_bpp(src_fb->drm_format, 0);
dst_bo = gem_handle_to_libdrm_bo(bufmgr, drm_fd, "destination",
dst_fb->gem_handle);
igt_assert(dst_bo);