int evdi_handle_damage(struct evdi_framebuffer *fb, int x, int y, int width, int height) { struct drm_device *dev = fb->base.dev; struct evdi_device *evdi = dev->dev_private; EVDI_CHECKPT(); if (!fb->obj->vmapping) { if (evdi_gem_vmap(fb->obj) == -ENOMEM) { DRM_ERROR("failed to vmap fb\n"); return 0; } if (!fb->obj->vmapping) { DRM_ERROR("failed to vmapping\n"); return 0; } } { const int line_offset = fb->base.pitches[0] * y; const int byte_offset = line_offset + (x * 4); //RG24 const char* pix = (char*)fb->obj->vmapping + byte_offset; EVDI_VERBOSE("%p %d,%d-%dx%d %02x%02x%02x%02x%02x%02x%02x%02x\n", fb, x, y, width, height, ((int)(pix[0])&0xff), ((int)(pix[1])&0xff), ((int)(pix[2])&0xff), ((int)(pix[3])&0xff), ((int)(pix[4])&0xff), ((int)(pix[5])&0xff), ((int)(pix[6])&0xff), ((int)(pix[7])&0xff)); } { struct drm_clip_rect rect = { x, y, x + width, y + height }; evdi_painter_mark_dirty(evdi, fb, &rect); } return 0; }
int evdi_painter_grabpix_ioctl(struct drm_device *drm_dev, void *data, __always_unused struct drm_file *file) { struct evdi_device *evdi = drm_dev->dev_private; struct evdi_painter *painter = evdi->painter; struct drm_evdi_grabpix *cmd = data; struct drm_framebuffer *fb = NULL; struct evdi_framebuffer *efb = NULL; struct evdi_cursor *cursor_copy = NULL; int err = 0; EVDI_CHECKPT(); if (!painter) return -ENODEV; mutex_lock(&drm_dev->struct_mutex); if (evdi_cursor_alloc(&cursor_copy) == 0) evdi_cursor_copy(cursor_copy, evdi->cursor); mutex_unlock(&drm_dev->struct_mutex); painter_lock(painter); efb = painter->scanout_fb; if (!efb) { EVDI_ERROR("Scanout buffer not set\n"); err = -EAGAIN; goto unlock; } if (painter->was_update_requested) { EVDI_WARN("(dev=%d) Update ready not sent,", evdi->dev_index); EVDI_WARN(" but pixels are grabbed.\n"); } fb = &efb->base; if (!efb->obj->vmapping) { if (evdi_gem_vmap(efb->obj) == -ENOMEM) { EVDI_ERROR("Failed to map scanout buffer\n"); err = -EFAULT; goto unlock; } if (!efb->obj->vmapping) { EVDI_ERROR("Failed to map scanout buffer\n"); err = -EFAULT; goto unlock; } } if (cmd->buf_width != fb->width || cmd->buf_height != fb->height) { EVDI_ERROR("Invalid buffer dimension\n"); err = -EINVAL; goto unlock; } if (cmd->num_rects < 1) { EVDI_ERROR("No space for clip rects\n"); err = -EINVAL; goto unlock; } if (cmd->mode == EVDI_GRABPIX_MODE_DIRTY) { if (painter->num_dirts < 0) { err = -EAGAIN; goto unlock; } merge_dirty_rects(&painter->dirty_rects[0], &painter->num_dirts); if (painter->num_dirts > cmd->num_rects) collapse_dirty_rects(&painter->dirty_rects[0], &painter->num_dirts); cmd->num_rects = painter->num_dirts; if (copy_to_user(cmd->rects, painter->dirty_rects, cmd->num_rects * sizeof(cmd->rects[0]))) err = -EFAULT; else err = copy_pixels(efb, cmd->buffer, cmd->buf_byte_stride, painter->num_dirts, painter->dirty_rects, cmd->buf_width, cmd->buf_height, cursor_copy); painter->num_dirts = 0; } unlock: painter_unlock(painter); if (cursor_copy) evdi_cursor_free(cursor_copy); return err; }
static int evdifb_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { struct evdi_fbdev *ufbdev = (struct evdi_fbdev *)helper; struct drm_device *dev = ufbdev->helper.dev; struct fb_info *info; struct device *device = dev->dev; struct drm_framebuffer *fb; struct drm_mode_fb_cmd2 mode_cmd; struct evdi_gem_object *obj; uint32_t size; int ret = 0; if (sizes->surface_bpp == 24) { sizes->surface_bpp = 32; } else if (sizes->surface_bpp != 32) { EVDI_ERROR("Not supported pixel format (bpp=%d)\n", sizes->surface_bpp); return -EINVAL; } mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height; mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8); mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); size = mode_cmd.pitches[0] * mode_cmd.height; size = ALIGN(size, PAGE_SIZE); obj = evdi_gem_alloc_object(dev, size); if (!obj) goto out; ret = evdi_gem_vmap(obj); if (ret) { DRM_ERROR("failed to vmap fb\n"); goto out_gfree; } info = framebuffer_alloc(0, device); if (!info) { ret = -ENOMEM; goto out_gfree; } info->par = ufbdev; ret = evdi_framebuffer_init(dev, &ufbdev->ufb, &mode_cmd, obj); if (ret) goto out_gfree; fb = &ufbdev->ufb.base; ufbdev->helper.fb = fb; ufbdev->helper.fbdev = info; strcpy(info->fix.id, "evdidrmfb"); info->screen_base = ufbdev->ufb.obj->vmapping; info->fix.smem_len = size; info->fix.smem_start = (unsigned long)ufbdev->ufb.obj->vmapping; info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; info->fbops = &evdifb_ops; drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(info, &ufbdev->helper, sizes->fb_width, sizes->fb_height); ret = fb_alloc_cmap(&info->cmap, 256, 0); if (ret) { ret = -ENOMEM; goto out_gfree; } DRM_DEBUG_KMS("allocated %dx%d vmal %p\n", fb->width, fb->height, ufbdev->ufb.obj->vmapping); return ret; out_gfree: drm_gem_object_unreference(&ufbdev->ufb.obj->base); out: return ret; }