#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include "drmtap.h"
#define INTEL_X_TILE_WIDTH 512
#define INTEL_X_TILE_HEIGHT 8
static int deswizzle_intel_x_tiled(const void *src, void *dst,
uint32_t width, uint32_t height,
uint32_t src_stride, uint32_t dst_stride) {
uint32_t bpp = 4;
uint32_t tile_w_bytes = INTEL_X_TILE_WIDTH;
uint32_t tile_h = INTEL_X_TILE_HEIGHT;
uint32_t tiles_x = (src_stride + tile_w_bytes - 1) / tile_w_bytes;
const uint8_t *s = (const uint8_t *)src;
uint8_t *d = (uint8_t *)dst;
for (uint32_t y = 0; y < height; y++) {
uint32_t tile_row = y / tile_h;
uint32_t tile_y = y % tile_h;
for (uint32_t x = 0; x < width; x++) {
uint32_t x_bytes = x * bpp;
uint32_t tile_col = x_bytes / tile_w_bytes;
uint32_t tile_x_bytes = x_bytes % tile_w_bytes;
uint32_t tile_idx = tile_row * tiles_x + tile_col;
uint32_t tile_size = tile_w_bytes * tile_h;
uint32_t src_off = tile_idx * tile_size +
tile_y * tile_w_bytes + tile_x_bytes;
memcpy(d + y * dst_stride + x * bpp,
s + src_off, bpp);
}
}
return 0;
}
#define INTEL_Y_TILE_WIDTH 128
#define INTEL_Y_TILE_HEIGHT 32
#define INTEL_Y_OWORD 16
static int deswizzle_intel_y_tiled(const void *src, void *dst,
uint32_t width, uint32_t height,
uint32_t src_stride, uint32_t dst_stride) {
uint32_t bpp = 4;
uint32_t tile_w_bytes = INTEL_Y_TILE_WIDTH;
uint32_t tile_h = INTEL_Y_TILE_HEIGHT;
uint32_t tiles_x = (src_stride + tile_w_bytes - 1) / tile_w_bytes;
uint32_t oword = INTEL_Y_OWORD;
uint32_t columns_per_tile = tile_w_bytes / oword;
const uint8_t *s = (const uint8_t *)src;
uint8_t *d = (uint8_t *)dst;
for (uint32_t y = 0; y < height; y++) {
uint32_t tile_row = y / tile_h;
uint32_t tile_y = y % tile_h;
for (uint32_t x = 0; x < width; x++) {
uint32_t x_bytes = x * bpp;
uint32_t tile_col = x_bytes / tile_w_bytes;
uint32_t in_tile_x = x_bytes % tile_w_bytes;
uint32_t column = in_tile_x / oword;
uint32_t column_offset = in_tile_x % oword;
uint32_t tile_idx = tile_row * tiles_x + tile_col;
uint32_t tile_size = tile_w_bytes * tile_h;
uint32_t src_off = tile_idx * tile_size +
column * (oword * tile_h) +
tile_y * oword +
column_offset;
memcpy(d + y * dst_stride + x * bpp,
s + src_off, bpp);
}
}
(void)columns_per_tile;
return 0;
}
#define NV_TILE_WIDTH 16
#define NV_TILE_HEIGHT 128
static int deswizzle_nvidia_x_tiled(const void *src, void *dst,
uint32_t width, uint32_t height,
uint32_t src_stride, uint32_t dst_stride) {
uint32_t bpp = 4;
uint32_t tile_w = NV_TILE_WIDTH;
uint32_t tile_h = NV_TILE_HEIGHT;
uint32_t tile_w_bytes = tile_w * bpp;
uint32_t tiles_x = (width + tile_w - 1) / tile_w;
(void)src_stride;
const uint8_t *s = (const uint8_t *)src;
uint8_t *d = (uint8_t *)dst;
for (uint32_t y = 0; y < height; y++) {
uint32_t tile_row = y / tile_h;
uint32_t tile_y = y % tile_h;
for (uint32_t tx = 0; tx < tiles_x; tx++) {
uint32_t tile_idx = tile_row * tiles_x + tx;
uint32_t tile_size = tile_w_bytes * tile_h;
uint32_t src_off = tile_idx * tile_size + tile_y * tile_w_bytes;
uint32_t dst_x = tx * tile_w;
uint32_t copy_w = (dst_x + tile_w > width)
? width - dst_x : tile_w;
memcpy(d + y * dst_stride + dst_x * bpp,
s + src_off, copy_w * bpp);
}
}
return 0;
}
static void convert_ar30_to_xrgb8888(const void *src, void *dst,
uint32_t width, uint32_t height,
uint32_t src_stride,
uint32_t dst_stride) {
for (uint32_t y = 0; y < height; y++) {
const uint32_t *s = (const uint32_t *)
((const uint8_t *)src + y * src_stride);
uint32_t *d = (uint32_t *)
((uint8_t *)dst + y * dst_stride);
for (uint32_t x = 0; x < width; x++) {
uint32_t pixel = s[x];
uint8_t r = (uint8_t)((pixel >> 22) & 0xFF);
uint8_t g = (uint8_t)((pixel >> 12) & 0xFF);
uint8_t b = (uint8_t)((pixel >> 2) & 0xFF);
d[x] = (0xFFu << 24) | ((uint32_t)r << 16) |
((uint32_t)g << 8) | b;
}
}
}
static void convert_abgr_to_argb(const void *src, void *dst,
uint32_t width, uint32_t height,
uint32_t src_stride, uint32_t dst_stride) {
for (uint32_t y = 0; y < height; y++) {
const uint32_t *s = (const uint32_t *)
((const uint8_t *)src + y * src_stride);
uint32_t *d = (uint32_t *)
((uint8_t *)dst + y * dst_stride);
for (uint32_t x = 0; x < width; x++) {
uint32_t pixel = s[x];
uint8_t a = (uint8_t)(pixel >> 24);
uint8_t b_ch = (uint8_t)(pixel >> 16);
uint8_t g = (uint8_t)(pixel >> 8);
uint8_t r = (uint8_t)(pixel);
d[x] = ((uint32_t)a << 24) | ((uint32_t)r << 16) |
((uint32_t)g << 8) | b_ch;
}
}
}
int drmtap_deswizzle(const void *src, void *dst,
uint32_t width, uint32_t height,
uint32_t src_stride, uint32_t dst_stride,
uint64_t modifier) {
if (!src || !dst || width == 0 || height == 0) {
return -EINVAL;
}
if (modifier == 0 ) {
for (uint32_t y = 0; y < height; y++) {
memcpy((uint8_t *)dst + y * dst_stride,
(const uint8_t *)src + y * src_stride,
width * 4);
}
return 0;
}
uint8_t vendor = (uint8_t)(modifier >> 56);
uint8_t mod_type = (uint8_t)(modifier & 0xFF);
if (vendor == 0x01) {
if (mod_type == 0x01) {
return deswizzle_intel_x_tiled(src, dst, width, height,
src_stride, dst_stride);
} else if (mod_type == 0x02 || mod_type == 0x03) {
return deswizzle_intel_y_tiled(src, dst, width, height,
src_stride, dst_stride);
} else if (mod_type == 0x05 || mod_type == 0x06 ||
mod_type == 0x07 || mod_type == 0x08) {
return -ENOTSUP;
}
}
if (vendor == 0x10) {
return deswizzle_nvidia_x_tiled(src, dst, width, height,
src_stride, dst_stride);
}
for (uint32_t y = 0; y < height; y++) {
memcpy((uint8_t *)dst + y * dst_stride,
(const uint8_t *)src + y * src_stride,
width * 4);
}
return 0;
}
int drmtap_convert_format(const void *src, void *dst,
uint32_t width, uint32_t height,
uint32_t src_stride, uint32_t dst_stride,
uint32_t src_format, uint32_t dst_format) {
if (!src || !dst || width == 0 || height == 0) {
return -EINVAL;
}
if (src_format == dst_format) {
for (uint32_t y = 0; y < height; y++) {
memcpy((uint8_t *)dst + y * dst_stride,
(const uint8_t *)src + y * src_stride,
width * 4);
}
return 0;
}
#define DRM_FMT_XRGB8888 0x34325258u
#define DRM_FMT_ARGB8888 0x34325241u
#define DRM_FMT_ABGR8888 0x34324241u
#define DRM_FMT_XRGB2101010 0x30335258u
#define DRM_FMT_ARGB2101010 0x30335241u
if ((src_format == DRM_FMT_XRGB2101010 ||
src_format == DRM_FMT_ARGB2101010) &&
(dst_format == DRM_FMT_XRGB8888 ||
dst_format == DRM_FMT_ARGB8888)) {
convert_ar30_to_xrgb8888(src, dst, width, height,
src_stride, dst_stride);
return 0;
}
if (src_format == DRM_FMT_ABGR8888 &&
(dst_format == DRM_FMT_ARGB8888 ||
dst_format == DRM_FMT_XRGB8888)) {
convert_abgr_to_argb(src, dst, width, height,
src_stride, dst_stride);
return 0;
}
return -ENOTSUP;
}
int drmtap_diff_frames(const void *frame_a, const void *frame_b,
uint32_t width, uint32_t height, uint32_t stride,
drmtap_rect *rects_out, int max_rects,
int tile_size) {
if (!frame_a || !frame_b || !rects_out || max_rects <= 0 || tile_size <= 0) {
return -EINVAL;
}
int dirty_count = 0;
uint32_t tiles_x = (width + (uint32_t)tile_size - 1) / (uint32_t)tile_size;
uint32_t tiles_y = (height + (uint32_t)tile_size - 1) / (uint32_t)tile_size;
for (uint32_t ty = 0; ty < tiles_y; ty++) {
for (uint32_t tx = 0; tx < tiles_x; tx++) {
uint32_t rx = tx * (uint32_t)tile_size;
uint32_t ry = ty * (uint32_t)tile_size;
uint32_t rw = (rx + (uint32_t)tile_size > width)
? width - rx : (uint32_t)tile_size;
uint32_t rh = (ry + (uint32_t)tile_size > height)
? height - ry : (uint32_t)tile_size;
int dirty = 0;
for (uint32_t row = ry; row < ry + rh && !dirty; row++) {
const uint8_t *a = (const uint8_t *)frame_a +
row * stride + rx * 4;
const uint8_t *b = (const uint8_t *)frame_b +
row * stride + rx * 4;
if (memcmp(a, b, rw * 4) != 0) {
dirty = 1;
}
}
if (dirty) {
if (dirty_count < max_rects) {
rects_out[dirty_count].x = rx;
rects_out[dirty_count].y = ry;
rects_out[dirty_count].w = rw;
rects_out[dirty_count].h = rh;
}
dirty_count++;
}
}
}
return dirty_count;
}