Files
luwh0708 fb419b8121 bugfix: tde repaint double fini region
Change-Id: I27738582e84a7a97ab144f8ee3be26c77b1b7fd4
Signed-off-by: luwh0708 <1632083718@qq.com>
2021-11-30 16:23:50 +08:00

676 lines
22 KiB
C++
Executable File

/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "tde-render-part.h"
#include <sstream>
#include <unistd.h>
#include <vector>
#include <display_gfx.h>
#include <idisplay_gralloc.h>
extern "C" {
#include <securec.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <drm.h>
#include <drm/drm_fourcc.h>
#include <linux-dmabuf.h>
#include <linux-dmabuf-unstable-v1-server-protocol.h>
#include <linux-explicit-synchronization.h>
#include <sys/mman.h>
#include "libweston/weston-log.h"
#include "shared/helpers.h"
#include "pixman-renderer-protected.h"
#define virtual __keyword__virtual
#include <drm-internal.h>
#undef virtual
}
#include "libweston/trace.h"
DEFINE_LOG_LABEL("TDERenderer");
struct tde_image_t {
int32_t width;
int32_t height;
uint32_t format;
int n_planes; // 默认为1,引入plane是为了保证方案的通用性
__u64 phyaddr; // 物理地址
int fd[MAX_DMABUF_PLANES];
uint32_t offset[MAX_DMABUF_PLANES];
uint32_t stride[MAX_DMABUF_PLANES];
};
struct fill_rect_call {
ISurface surface;
IRect rect;
uint32_t color;
GfxOpt opt;
};
struct tde_output_state_t {
int32_t draw_count;
std::vector<struct fill_rect_call> calls;
};
struct tde_surface_state_t {
struct tde_image_t image;
struct linux_dmabuf_buffer *buffer;
struct tde_renderer_t *renderer;
};
struct tde_renderer_t {
GfxFuncs *gfx_funcs;
::OHOS::HDI::Display::V1_0::IDisplayGralloc *display_gralloc;
void *module;
int use_tde;
int use_dmabuf;
};
struct drm_hisilicon_phy_addr {
uint64_t phyaddr; // return the phy addr
int fd; // dmabuf file descriptor
};
#define LIB_GFX_NAME "libdisplay_gfx.z.so"
#define LIB_GFX_FUNC_NAME_INIT "GfxInitialize"
#define LIB_GFX_FUNC_NAME_DEINIT "GfxUninitialize"
#define DRM_HISILICON_GEM_FD_TO_PHYADDR (0x1)
#define DRM_IOCTL_HISILICON_GEM_FD_TO_PHYADDR \
(DRM_IOWR(DRM_COMMAND_BASE + DRM_HISILICON_GEM_FD_TO_PHYADDR, \
struct drm_hisilicon_phy_addr))
static uint64_t dst_image_phyaddr(struct weston_output *wo)
{
struct drm_output *output = to_drm_output(wo);
struct drm_backend *backend = to_drm_backend(wo->compositor);
int prime_fd;
drmPrimeHandleToFD(backend->drm.fd,
output->dumb[output->current_image]->handles[0],
DRM_CLOEXEC, &prime_fd);
struct drm_hisilicon_phy_addr args = { .fd = prime_fd };
ioctl(backend->drm.fd, DRM_IOCTL_HISILICON_GEM_FD_TO_PHYADDR, &args);
close(prime_fd);
return args.phyaddr;
}
static void src_surface_init(ISurface *surface, struct tde_image_t buffer)
{
surface->width = buffer.width;
surface->height = buffer.height;
surface->phyAddr = buffer.phyaddr;
surface->stride = buffer.stride[0];
surface->enColorFmt = PIXEL_FMT_RGBA_8888;
surface->bAlphaExt1555 = true;
surface->bAlphaMax255 = true;
surface->alpha0 = 0XFF;
surface->alpha1 = 0XFF;
}
static void dst_surface_init(ISurface *surface, pixman_image_t *target_image,
struct weston_output *output)
{
surface->width = pixman_image_get_width(target_image);
surface->height = pixman_image_get_height(target_image);
surface->phyAddr = dst_image_phyaddr(output);
surface->enColorFmt = PIXEL_FMT_BGRA_8888;
surface->stride = pixman_image_get_stride(target_image);
surface->bAlphaExt1555 = true;
surface->bAlphaMax255 = true;
surface->alpha0 = 0XFF;
surface->alpha1 = 0XFF;
}
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
typedef void(*weston_view_compute_global_region_func)(struct weston_view *view,
float x, float y, float *vx, float *vy);
static void
weston_view_compute_global_region(struct weston_view *view,
pixman_region32_t *outr,
pixman_region32_t *inr,
weston_view_compute_global_region_func fn)
{
float min_x = HUGE_VALF, min_y = HUGE_VALF;
float max_x = -HUGE_VALF, max_y = -HUGE_VALF;
pixman_box32_t *inbox = pixman_region32_extents(inr);
int32_t vs[4][2] = {
{ inbox->x1, inbox->y1 },
{ inbox->x1, inbox->y2 },
{ inbox->x2, inbox->y1 },
{ inbox->x2, inbox->y2 },
};
if (inbox->x1 == inbox->x2 || inbox->y1 == inbox->y2) {
pixman_region32_init(outr);
return;
}
for (int i = 0; i < 4; i++) {
float x, y;
fn(view, vs[i][0], vs[i][1], &x, &y);
min_x = min(min_x, x);
max_x = max(max_x, x);
min_y = min(min_y, y);
max_y = max(max_y, y);
}
float int_x = floorf(min_x);
float int_y = floorf(min_y);
pixman_region32_init_rect(outr, int_x, int_y,
ceilf(max_x) - int_x, ceilf(max_y) - int_y);
}
#undef min
#undef max
static void
weston_view_to_global_region(struct weston_view *view,
pixman_region32_t *outr,
pixman_region32_t *inr)
{
weston_view_compute_global_region(view, outr, inr, weston_view_to_global_float);
}
static void
weston_view_from_global_region(struct weston_view *view,
pixman_region32_t *outr,
pixman_region32_t *inr)
{
weston_view_compute_global_region(view, outr, inr, weston_view_from_global_float);
}
static void dump_to_file(struct pixman_surface_state *ps)
{
if (access("/data/tde_dump", F_OK) == -1) {
return;
}
struct timeval now;
gettimeofday(&now, nullptr);
constexpr int secToUsec = 1000 * 1000;
int64_t nowVal = (int64_t)now.tv_sec * secToUsec + (int64_t)now.tv_usec;
std::stringstream ss;
ss << "/data/tde-dumpimage-" << nowVal << ".raw";
auto fp = fopen(ss.str().c_str(), "a+");
if (fp == nullptr) {
return;
}
void *viraddr = pixman_image_get_data(ps->image);
int32_t size = pixman_image_get_stride(ps->image) * pixman_image_get_height(ps->image);
fwrite(viraddr, size, 1, fp);
fclose(fp);
}
static int tde_repaint_region(struct weston_view *ev,
struct weston_output *output,
pixman_region32_t *buffer_region,
pixman_region32_t *output_damage)
{
struct pixman_renderer *renderer = (struct pixman_renderer *)output->compositor->renderer;
struct pixman_surface_state *surface = get_surface_state(ev->surface);
dump_to_file(surface);
struct pixman_output_state *output_state = get_output_state(output);
pixman_image_t *target_image = output_state->hw_buffer;
if (output_state->shadow_image) {
target_image = output_state->shadow_image;
}
GfxOpt opt = {
.enPixelAlpha = true,
.blendType = output_state->tde->draw_count ? BLEND_SRCOVER : BLEND_SRC,
.enableScale = true,
};
// region calc
pixman_region32_t global_repaint_region;
pixman_region32_t buffer_repaint_region;
{
pixman_region32_t surface_region;
pixman_region32_init_rect(&surface_region, 0, 0, ev->surface->width, ev->surface->height);
pixman_region32_t repaint_output;
pixman_region32_init(&repaint_output);
pixman_region32_copy(&repaint_output, output_damage);
if (output->zoom.active) {
weston_matrix_transform_region(&repaint_output, &output->matrix, &repaint_output);
} else {
pixman_region32_translate(&repaint_output, -output->x, -output->y);
weston_transformed_region(output->width, output->height,
static_cast<enum wl_output_transform>(output->transform),
output->current_scale,
&repaint_output, &repaint_output);
}
LOG_REGION(1, &surface_region);
LOG_REGION(2, &repaint_output);
struct weston_matrix matrix = output->inverse_matrix;
if (ev->transform.enabled) {
weston_matrix_multiply(&matrix, &ev->transform.inverse);
LOG_INFO("transform enabled");
} else {
weston_matrix_translate(&matrix,
-ev->geometry.x, -ev->geometry.y, 0);
LOG_INFO("transform disabled");
}
weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
if (matrix.d[0] == matrix.d[5] && matrix.d[0] == 0) {
if (matrix.d[4] > 0 && matrix.d[1] > 0) {
LOG_INFO("90 mirror");
opt.rotateType = ROTATE_90;
opt.mirrorType = MIRROR_LR;
} else if (matrix.d[4] < 0 && matrix.d[1] > 0) {
LOG_INFO("90");
opt.rotateType = ROTATE_90;
} else if (matrix.d[4] < 0 && matrix.d[1] < 0) {
LOG_INFO("270 mirror");
opt.rotateType = ROTATE_270;
opt.mirrorType = MIRROR_LR;
} else if (matrix.d[4] > 0 && matrix.d[1] < 0) {
LOG_INFO("270");
opt.rotateType = ROTATE_270;
}
} else {
if (matrix.d[0] > 0 && matrix.d[5] > 0) {
LOG_INFO("0");
opt.rotateType = ROTATE_NONE;
} else if (matrix.d[0] < 0 && matrix.d[5] < 0) {
LOG_INFO("180");
opt.rotateType = ROTATE_180;
} else if (matrix.d[0] < 0 && matrix.d[5] > 0) {
LOG_INFO("0 mirror");
opt.rotateType = ROTATE_NONE;
opt.mirrorType = MIRROR_LR;
} else if (matrix.d[0] > 0 && matrix.d[5] < 0) {
LOG_INFO("180 mirror");
opt.rotateType = ROTATE_180;
opt.mirrorType = MIRROR_LR;
}
}
LOG_INFO("%f %f %f %f", matrix.d[0], matrix.d[1], matrix.d[2], matrix.d[3]);
LOG_INFO("%f %f %f %f", matrix.d[4], matrix.d[5], matrix.d[6], matrix.d[7]);
LOG_INFO("%f %f %f %f", matrix.d[8], matrix.d[9], matrix.d[10], matrix.d[11]);
LOG_INFO("%f %f %f %f", matrix.d[12], matrix.d[13], matrix.d[14], matrix.d[15]);
LOG_INFO("%d %d", ev->surface->width, ev->surface->height);
weston_view_to_global_region(ev, &global_repaint_region, &surface_region);
pixman_region32_intersect(&global_repaint_region, &global_repaint_region, &repaint_output);
LOG_REGION(3, &global_repaint_region);
pixman_region32_t surface_repaint_region;
pixman_region32_init(&surface_repaint_region);
weston_view_from_global_region(ev, &surface_repaint_region, &global_repaint_region);
LOG_REGION(4, &surface_repaint_region);
pixman_region32_init(&buffer_repaint_region);
weston_surface_to_buffer_region(ev->surface, &surface_repaint_region, &buffer_repaint_region);
LOG_REGION(5, &buffer_repaint_region);
pixman_region32_fini(&surface_repaint_region);
pixman_region32_fini(&surface_region);
pixman_region32_fini(&repaint_output);
}
pixman_box32_t *global_box = pixman_region32_extents(&global_repaint_region);
IRect dstRect = {
.x = global_box->x1, .y = global_box->y1,
.w = global_box->x2 - global_box->x1,
.h = global_box->y2 - global_box->y1
};
pixman_box32_t *buffer_box = pixman_region32_extents(&buffer_repaint_region);
IRect srcRect = {
.x = buffer_box->x1, .y = buffer_box->y1,
.w = buffer_box->x2 - buffer_box->x1,
.h = buffer_box->y2 - buffer_box->y1
};
pixman_region32_fini(&global_repaint_region);
pixman_region32_fini(&buffer_repaint_region);
// tde
ISurface dstSurface = {};
dst_surface_init(&dstSurface, target_image, output);
ISurface srcSurface = {};
src_surface_init(&srcSurface, surface->tde->image);
if (ev->surface->type == WL_SURFACE_TYPE_VIDEO) {
opt.blendType = BLEND_SRC;
struct fill_rect_call call = {
.surface = dstSurface,
.rect = dstRect,
.color = 0x00000000,
.opt = opt,
};
output_state->tde->calls.push_back(call);
return 0;
} else {
if (renderer->tde->gfx_funcs->InitGfx() != 0) {
weston_log("tde_repaint_region InitGfx failed");
return -1;
}
output_state->tde->draw_count++;
renderer->tde->gfx_funcs->Blit(&srcSurface, &srcRect, &dstSurface, &dstRect, &opt);
weston_log("Blit dst(%{public}d, %{public}d) %{public}dx%{public}d",
dstRect.x, dstRect.y, dstRect.w, dstRect.h);
weston_log("Blit src(%{public}d, %{public}d) %{public}dx%{public}d",
srcRect.x, srcRect.y, srcRect.w, srcRect.h);
renderer->tde->gfx_funcs->DeinitGfx();
}
return 0;
}
void tde_repaint_finish_hook(struct weston_output *output)
{
struct pixman_renderer *renderer = (struct pixman_renderer *)output->compositor->renderer;
struct pixman_output_state *output_state = get_output_state(output);
for (auto &call : output_state->tde->calls) {
if (renderer->tde->gfx_funcs->InitGfx() != 0) {
weston_log("tde_repaint_finish_hook InitGfx failed");
continue;
}
renderer->tde->gfx_funcs->FillRect(&call.surface, &call.rect, call.color, &call.opt);
weston_log("FillRect (%{public}d, %{public}d) %{public}dx%{public}d",
call.rect.x, call.rect.y, call.rect.w, call.rect.h);
renderer->tde->gfx_funcs->DeinitGfx();
}
}
static bool import_dmabuf(struct weston_compositor *ec,
struct linux_dmabuf_buffer *dmabuf)
{
return true;
}
static void query_dmabuf_formats(struct weston_compositor *wc,
int **formats, int *num_formats)
{
static const int fallback_formats[] = {
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_YUYV,
DRM_FORMAT_NV12,
DRM_FORMAT_YUV420,
DRM_FORMAT_YUV444,
};
int num = ARRAY_LENGTH(fallback_formats);
if (num > 0) {
*formats = (int *)calloc(num, sizeof(int));
}
memcpy_s(*formats, num * sizeof(int), fallback_formats, sizeof(fallback_formats));
*num_formats = num;
}
static void query_dmabuf_modifiers(struct weston_compositor *wc, int format,
uint64_t **modifiers, int *num_modifiers)
{
*modifiers = NULL;
*num_modifiers = 0;
}
static int32_t tde_render_gfx_init(struct tde_renderer_t *tde)
{
tde->module = dlopen(LIB_GFX_NAME, RTLD_NOW | RTLD_NOLOAD);
if (tde->module) {
weston_log("Module '%{public}s' already loaded\n", LIB_GFX_NAME);
} else {
weston_log("Loading module '%{public}s'\n", LIB_GFX_NAME);
tde->module = dlopen(LIB_GFX_NAME, RTLD_NOW);
if (!tde->module) {
weston_log("Failed to load module: %{public}s\n", dlerror());
return DISPLAY_FAILURE;
}
}
auto func = (int32_t(*)(GfxFuncs **funcs))dlsym(tde->module, LIB_GFX_FUNC_NAME_INIT);
if (!func) {
weston_log("Failed to lookup %{public}s function: %s\n", LIB_GFX_FUNC_NAME_INIT, dlerror());
dlclose(tde->module);
return DISPLAY_FAILURE;
}
return func(&tde->gfx_funcs);
}
static int32_t tde_render_gfx_deinit(struct tde_renderer_t *tde)
{
int32_t ret = DISPLAY_FAILURE;
if (tde->module) {
auto func = (int32_t(*)(GfxFuncs *funcs))dlsym(tde->module, LIB_GFX_FUNC_NAME_DEINIT);
if (!func) {
weston_log("Failed to lookup %{public}s function: %s\n", LIB_GFX_FUNC_NAME_DEINIT, dlerror());
} else {
ret = func(tde->gfx_funcs);
}
dlclose(tde->module);
}
return ret;
}
int tde_renderer_alloc_hook(struct pixman_renderer *renderer, struct weston_compositor *ec)
{
renderer->tde = (struct tde_renderer_t *)zalloc(sizeof(*renderer->tde));
if (renderer->tde == NULL) {
return -1;
}
// Gfx Init
int ret = tde_render_gfx_init(renderer->tde);
if (ret == DISPLAY_SUCCESS && renderer->tde->gfx_funcs != NULL) {
renderer->tde->use_tde = 1;
weston_log("use tde");
} else {
renderer->tde->use_tde = 0;
weston_log("use no tde");
}
// Gralloc Init
renderer->tde->display_gralloc = ::OHOS::HDI::Display::V1_0::IDisplayGralloc::Get();
if (renderer->tde->display_gralloc != NULL) {
renderer->tde->use_dmabuf = 1;
weston_log("use dmabuf");
} else {
renderer->tde->use_tde = 0;
weston_log("use no tde");
renderer->tde->use_dmabuf = 0;
weston_log("use no dmabuf");
}
renderer->base.import_dmabuf = import_dmabuf;
renderer->base.query_dmabuf_formats = query_dmabuf_formats;
renderer->base.query_dmabuf_modifiers = query_dmabuf_modifiers;
return 0;
}
int tde_renderer_free_hook(struct pixman_renderer *renderer)
{
tde_render_gfx_deinit(renderer->tde);
delete renderer->tde->display_gralloc;
free(renderer->tde);
return 0;
}
int tde_output_state_alloc_hook(struct pixman_output_state *state)
{
state->tde = (struct tde_output_state_t *)zalloc(sizeof(*state->tde));
return 0;
}
int tde_output_state_init_hook(struct pixman_output_state *state)
{
state->tde->draw_count = 0;
state->tde->calls.clear();
return 0;
}
int tde_output_state_free_hook(struct pixman_output_state *state)
{
free(state->tde);
return 0;
}
int tde_surface_state_alloc_hook(struct pixman_surface_state *state)
{
state->tde = (struct tde_surface_state_t *)zalloc(sizeof(*state->tde));
return 0;
}
int tde_surface_state_free_hook(struct pixman_surface_state *state)
{
free(state->tde);
return 0;
}
static void buffer_state_handle_buffer_destroy(struct wl_listener *listener,
void *data)
{
struct pixman_surface_state *ps = container_of(listener,
struct pixman_surface_state, buffer_destroy_listener);
if (ps->image) {
tde_unref_image_hook(ps);
pixman_image_unref(ps->image);
ps->image = NULL;
}
ps->buffer_destroy_listener.notify = NULL;
}
int tde_render_attach_hook(struct weston_surface *es, struct weston_buffer *buffer)
{
if (buffer == NULL) {
return -1;
}
struct linux_dmabuf_buffer *dmabuf = linux_dmabuf_buffer_get(buffer->resource);
if (dmabuf == NULL) {
return -1;
}
struct pixman_surface_state *ps = get_surface_state(es);
ps->tde->renderer = get_renderer(es->compositor)->tde;
if (ps->tde->renderer->use_dmabuf != 1) {
return -1;
}
void *ptr = ps->tde->renderer->display_gralloc->Mmap(*dmabuf->attributes.buffer_handle);
if (ptr == NULL) {
return -1;
}
weston_buffer_reference(&ps->buffer_ref, buffer);
weston_buffer_release_reference(&ps->buffer_release_ref,
es->buffer_release_ref.buffer_release);
if (ps->buffer_destroy_listener.notify) {
wl_list_remove(&ps->buffer_destroy_listener.link);
ps->buffer_destroy_listener.notify = NULL;
}
if (ps->image) {
tde_unref_image_hook(ps);
pixman_image_unref(ps->image);
ps->image = NULL;
}
pixman_format_code_t pixman_format = PIXMAN_a8b8g8r8;
buffer->legacy_buffer = NULL;
buffer->width = dmabuf->attributes.width;
buffer->height = dmabuf->attributes.height;
ps->tde->image.width = dmabuf->attributes.width;
ps->tde->image.height = dmabuf->attributes.height;
ps->tde->image.stride[0] = dmabuf->attributes.stride[0];
ps->tde->image.format = dmabuf->attributes.format;
ps->tde->image.fd[0] = dmabuf->attributes.fd[0];
ps->tde->buffer = dmabuf;
ps->tde->image.phyaddr = dmabuf->attributes.buffer_handle->phyAddr;
if (ps->tde->image.phyaddr == 0) {
weston_log("tde-renderer: phyAddr is invalid.\n");
}
ps->image = pixman_image_create_bits(pixman_format,
buffer->width, buffer->height,
(uint32_t *)dmabuf->attributes.buffer_handle->virAddr,
dmabuf->attributes.stride[0]);
ps->buffer_destroy_listener.notify = buffer_state_handle_buffer_destroy;
wl_signal_add(&buffer->destroy_signal, &ps->buffer_destroy_listener);
return 0;
}
int tde_repaint_region_hook(struct weston_view *ev, struct weston_output *output,
pixman_region32_t *buffer_region, pixman_region32_t *repaint_output)
{
struct pixman_renderer *renderer = (struct pixman_renderer *)output->compositor->renderer;
if (!renderer->tde->use_tde) {
return -1;
}
return tde_repaint_region(ev, output, buffer_region, repaint_output);
}
int tde_unref_image_hook(struct pixman_surface_state *ps)
{
if (ps == NULL) {
return 0;
}
if (ps->tde == NULL) {
return 0;
}
struct tde_surface_state_t *tss = ps->tde;
if (tss->renderer == NULL || tss->buffer == NULL) {
return 0;
}
BufferHandle *bh = tss->buffer->attributes.buffer_handle;
if (bh == NULL || bh->virAddr == NULL) {
return 0;
}
if (tss->renderer->use_dmabuf == 1) {
tss->renderer->display_gralloc->Unmap(*bh);
}
return 0;
}