|
@@ -23,25 +23,29 @@
|
|
|
#include "qxl_drv.h"
|
|
|
#include "qxl_object.h"
|
|
|
|
|
|
+static int alloc_clips(struct qxl_device *qdev,
|
|
|
+ struct qxl_release *release,
|
|
|
+ unsigned num_clips,
|
|
|
+ struct qxl_bo **clips_bo)
|
|
|
+{
|
|
|
+ int size = sizeof(struct qxl_clip_rects) + sizeof(struct qxl_rect) * num_clips;
|
|
|
+
|
|
|
+ return qxl_alloc_bo_reserved(qdev, release, size, clips_bo);
|
|
|
+}
|
|
|
+
|
|
|
/* returns a pointer to the already allocated qxl_rect array inside
|
|
|
* the qxl_clip_rects. This is *not* the same as the memory allocated
|
|
|
* on the device, it is offset to qxl_clip_rects.chunk.data */
|
|
|
static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,
|
|
|
struct qxl_drawable *drawable,
|
|
|
unsigned num_clips,
|
|
|
- struct qxl_bo **clips_bo,
|
|
|
- struct qxl_release *release)
|
|
|
+ struct qxl_bo *clips_bo)
|
|
|
{
|
|
|
struct qxl_clip_rects *dev_clips;
|
|
|
int ret;
|
|
|
- int size = sizeof(*dev_clips) + sizeof(struct qxl_rect) * num_clips;
|
|
|
- ret = qxl_alloc_bo_reserved(qdev, size, clips_bo);
|
|
|
- if (ret)
|
|
|
- return NULL;
|
|
|
|
|
|
- ret = qxl_bo_kmap(*clips_bo, (void **)&dev_clips);
|
|
|
+ ret = qxl_bo_kmap(clips_bo, (void **)&dev_clips);
|
|
|
if (ret) {
|
|
|
- qxl_bo_unref(clips_bo);
|
|
|
return NULL;
|
|
|
}
|
|
|
dev_clips->num_rects = num_clips;
|
|
@@ -51,21 +55,35 @@ static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,
|
|
|
return (struct qxl_rect *)dev_clips->chunk.data;
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+alloc_drawable(struct qxl_device *qdev, struct qxl_release **release)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ ret = qxl_alloc_release_reserved(qdev, sizeof(struct qxl_drawable),
|
|
|
+ QXL_RELEASE_DRAWABLE, release,
|
|
|
+ NULL);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+free_drawable(struct qxl_device *qdev, struct qxl_release *release)
|
|
|
+{
|
|
|
+ qxl_release_free(qdev, release);
|
|
|
+}
|
|
|
+
|
|
|
+/* release needs to be reserved at this point */
|
|
|
static int
|
|
|
make_drawable(struct qxl_device *qdev, int surface, uint8_t type,
|
|
|
const struct qxl_rect *rect,
|
|
|
- struct qxl_release **release)
|
|
|
+ struct qxl_release *release)
|
|
|
{
|
|
|
struct qxl_drawable *drawable;
|
|
|
- int i, ret;
|
|
|
+ int i;
|
|
|
|
|
|
- ret = qxl_alloc_release_reserved(qdev, sizeof(*drawable),
|
|
|
- QXL_RELEASE_DRAWABLE, release,
|
|
|
- NULL);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
+ drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
|
|
|
+ if (!drawable)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- drawable = (struct qxl_drawable *)qxl_release_map(qdev, *release);
|
|
|
drawable->type = type;
|
|
|
|
|
|
drawable->surface_id = surface; /* Only primary for now */
|
|
@@ -91,14 +109,23 @@ make_drawable(struct qxl_device *qdev, int surface, uint8_t type,
|
|
|
drawable->bbox = *rect;
|
|
|
|
|
|
drawable->mm_time = qdev->rom->mm_clock;
|
|
|
- qxl_release_unmap(qdev, *release, &drawable->release_info);
|
|
|
+ qxl_release_unmap(qdev, release, &drawable->release_info);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int qxl_palette_create_1bit(struct qxl_bo **palette_bo,
|
|
|
+static int alloc_palette_object(struct qxl_device *qdev,
|
|
|
+ struct qxl_release *release,
|
|
|
+ struct qxl_bo **palette_bo)
|
|
|
+{
|
|
|
+ return qxl_alloc_bo_reserved(qdev, release,
|
|
|
+ sizeof(struct qxl_palette) + sizeof(uint32_t) * 2,
|
|
|
+ palette_bo);
|
|
|
+}
|
|
|
+
|
|
|
+static int qxl_palette_create_1bit(struct qxl_bo *palette_bo,
|
|
|
+ struct qxl_release *release,
|
|
|
const struct qxl_fb_image *qxl_fb_image)
|
|
|
{
|
|
|
- struct qxl_device *qdev = qxl_fb_image->qdev;
|
|
|
const struct fb_image *fb_image = &qxl_fb_image->fb_image;
|
|
|
uint32_t visual = qxl_fb_image->visual;
|
|
|
const uint32_t *pseudo_palette = qxl_fb_image->pseudo_palette;
|
|
@@ -108,12 +135,7 @@ static int qxl_palette_create_1bit(struct qxl_bo **palette_bo,
|
|
|
static uint64_t unique; /* we make no attempt to actually set this
|
|
|
* correctly globaly, since that would require
|
|
|
* tracking all of our palettes. */
|
|
|
-
|
|
|
- ret = qxl_alloc_bo_reserved(qdev,
|
|
|
- sizeof(struct qxl_palette) + sizeof(uint32_t) * 2,
|
|
|
- palette_bo);
|
|
|
-
|
|
|
- ret = qxl_bo_kmap(*palette_bo, (void **)&pal);
|
|
|
+ ret = qxl_bo_kmap(palette_bo, (void **)&pal);
|
|
|
pal->num_ents = 2;
|
|
|
pal->unique = unique++;
|
|
|
if (visual == FB_VISUAL_TRUECOLOR || visual == FB_VISUAL_DIRECTCOLOR) {
|
|
@@ -126,7 +148,7 @@ static int qxl_palette_create_1bit(struct qxl_bo **palette_bo,
|
|
|
}
|
|
|
pal->ents[0] = bgcolor;
|
|
|
pal->ents[1] = fgcolor;
|
|
|
- qxl_bo_kunmap(*palette_bo);
|
|
|
+ qxl_bo_kunmap(palette_bo);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -144,44 +166,63 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
|
|
|
const char *src = fb_image->data;
|
|
|
int depth = fb_image->depth;
|
|
|
struct qxl_release *release;
|
|
|
- struct qxl_bo *image_bo;
|
|
|
struct qxl_image *image;
|
|
|
int ret;
|
|
|
-
|
|
|
+ struct qxl_drm_image *dimage;
|
|
|
+ struct qxl_bo *palette_bo = NULL;
|
|
|
if (stride == 0)
|
|
|
stride = depth * width / 8;
|
|
|
|
|
|
+ ret = alloc_drawable(qdev, &release);
|
|
|
+ if (ret)
|
|
|
+ return;
|
|
|
+
|
|
|
+ ret = qxl_image_alloc_objects(qdev, release,
|
|
|
+ &dimage,
|
|
|
+ height, stride);
|
|
|
+ if (ret)
|
|
|
+ goto out_free_drawable;
|
|
|
+
|
|
|
+ if (depth == 1) {
|
|
|
+ ret = alloc_palette_object(qdev, release, &palette_bo);
|
|
|
+ if (ret)
|
|
|
+ goto out_free_image;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* do a reservation run over all the objects we just allocated */
|
|
|
+ ret = qxl_release_reserve_list(release, true);
|
|
|
+ if (ret)
|
|
|
+ goto out_free_palette;
|
|
|
+
|
|
|
rect.left = x;
|
|
|
rect.right = x + width;
|
|
|
rect.top = y;
|
|
|
rect.bottom = y + height;
|
|
|
|
|
|
- ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &rect, &release);
|
|
|
- if (ret)
|
|
|
- return;
|
|
|
+ ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &rect, release);
|
|
|
+ if (ret) {
|
|
|
+ qxl_release_backoff_reserve_list(release);
|
|
|
+ goto out_free_palette;
|
|
|
+ }
|
|
|
|
|
|
- ret = qxl_image_create(qdev, release, &image_bo,
|
|
|
- (const uint8_t *)src, 0, 0,
|
|
|
- width, height, depth, stride);
|
|
|
+ ret = qxl_image_init(qdev, release, dimage,
|
|
|
+ (const uint8_t *)src, 0, 0,
|
|
|
+ width, height, depth, stride);
|
|
|
if (ret) {
|
|
|
- qxl_release_unreserve(qdev, release);
|
|
|
+ qxl_release_backoff_reserve_list(release);
|
|
|
qxl_release_free(qdev, release);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (depth == 1) {
|
|
|
- struct qxl_bo *palette_bo;
|
|
|
void *ptr;
|
|
|
- ret = qxl_palette_create_1bit(&palette_bo, qxl_fb_image);
|
|
|
- qxl_release_add_res(qdev, release, palette_bo);
|
|
|
+ ret = qxl_palette_create_1bit(palette_bo, release, qxl_fb_image);
|
|
|
|
|
|
- ptr = qxl_bo_kmap_atomic_page(qdev, image_bo, 0);
|
|
|
+ ptr = qxl_bo_kmap_atomic_page(qdev, dimage->bo, 0);
|
|
|
image = ptr;
|
|
|
image->u.bitmap.palette =
|
|
|
qxl_bo_physical_address(qdev, palette_bo, 0);
|
|
|
- qxl_bo_kunmap_atomic_page(qdev, image_bo, ptr);
|
|
|
- qxl_bo_unreserve(palette_bo);
|
|
|
- qxl_bo_unref(&palette_bo);
|
|
|
+ qxl_bo_kunmap_atomic_page(qdev, dimage->bo, ptr);
|
|
|
}
|
|
|
|
|
|
drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
|
|
@@ -199,16 +240,20 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
|
|
|
drawable->u.copy.mask.bitmap = 0;
|
|
|
|
|
|
drawable->u.copy.src_bitmap =
|
|
|
- qxl_bo_physical_address(qdev, image_bo, 0);
|
|
|
+ qxl_bo_physical_address(qdev, dimage->bo, 0);
|
|
|
qxl_release_unmap(qdev, release, &drawable->release_info);
|
|
|
|
|
|
- qxl_release_add_res(qdev, release, image_bo);
|
|
|
- qxl_bo_unreserve(image_bo);
|
|
|
- qxl_bo_unref(&image_bo);
|
|
|
-
|
|
|
- qxl_fence_releaseable(qdev, release);
|
|
|
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
|
|
|
- qxl_release_unreserve(qdev, release);
|
|
|
+ qxl_release_fence_buffer_objects(release);
|
|
|
+
|
|
|
+out_free_palette:
|
|
|
+ if (palette_bo)
|
|
|
+ qxl_bo_unref(&palette_bo);
|
|
|
+out_free_image:
|
|
|
+ qxl_image_free_objects(qdev, dimage);
|
|
|
+out_free_drawable:
|
|
|
+ if (ret)
|
|
|
+ free_drawable(qdev, release);
|
|
|
}
|
|
|
|
|
|
/* push a draw command using the given clipping rectangles as
|
|
@@ -243,10 +288,14 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
|
|
|
int depth = qxl_fb->base.bits_per_pixel;
|
|
|
uint8_t *surface_base;
|
|
|
struct qxl_release *release;
|
|
|
- struct qxl_bo *image_bo;
|
|
|
struct qxl_bo *clips_bo;
|
|
|
+ struct qxl_drm_image *dimage;
|
|
|
int ret;
|
|
|
|
|
|
+ ret = alloc_drawable(qdev, &release);
|
|
|
+ if (ret)
|
|
|
+ return;
|
|
|
+
|
|
|
left = clips->x1;
|
|
|
right = clips->x2;
|
|
|
top = clips->y1;
|
|
@@ -263,36 +312,52 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
|
|
|
|
|
|
width = right - left;
|
|
|
height = bottom - top;
|
|
|
+
|
|
|
+ ret = alloc_clips(qdev, release, num_clips, &clips_bo);
|
|
|
+ if (ret)
|
|
|
+ goto out_free_drawable;
|
|
|
+
|
|
|
+ ret = qxl_image_alloc_objects(qdev, release,
|
|
|
+ &dimage,
|
|
|
+ height, stride);
|
|
|
+ if (ret)
|
|
|
+ goto out_free_clips;
|
|
|
+
|
|
|
+ /* do a reservation run over all the objects we just allocated */
|
|
|
+ ret = qxl_release_reserve_list(release, true);
|
|
|
+ if (ret)
|
|
|
+ goto out_free_image;
|
|
|
+
|
|
|
drawable_rect.left = left;
|
|
|
drawable_rect.right = right;
|
|
|
drawable_rect.top = top;
|
|
|
drawable_rect.bottom = bottom;
|
|
|
+
|
|
|
ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &drawable_rect,
|
|
|
- &release);
|
|
|
+ release);
|
|
|
if (ret)
|
|
|
- return;
|
|
|
+ goto out_release_backoff;
|
|
|
|
|
|
ret = qxl_bo_kmap(bo, (void **)&surface_base);
|
|
|
if (ret)
|
|
|
- goto out_unref;
|
|
|
+ goto out_release_backoff;
|
|
|
|
|
|
- ret = qxl_image_create(qdev, release, &image_bo, surface_base,
|
|
|
- left, top, width, height, depth, stride);
|
|
|
+
|
|
|
+ ret = qxl_image_init(qdev, release, dimage, surface_base,
|
|
|
+ left, top, width, height, depth, stride);
|
|
|
qxl_bo_kunmap(bo);
|
|
|
if (ret)
|
|
|
- goto out_unref;
|
|
|
+ goto out_release_backoff;
|
|
|
+
|
|
|
+ rects = drawable_set_clipping(qdev, drawable, num_clips, clips_bo);
|
|
|
+ if (!rects)
|
|
|
+ goto out_release_backoff;
|
|
|
|
|
|
- rects = drawable_set_clipping(qdev, drawable, num_clips, &clips_bo, release);
|
|
|
- if (!rects) {
|
|
|
- qxl_bo_unref(&image_bo);
|
|
|
- goto out_unref;
|
|
|
- }
|
|
|
drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
|
|
|
|
|
|
drawable->clip.type = SPICE_CLIP_TYPE_RECTS;
|
|
|
drawable->clip.data = qxl_bo_physical_address(qdev,
|
|
|
clips_bo, 0);
|
|
|
- qxl_release_add_res(qdev, release, clips_bo);
|
|
|
|
|
|
drawable->u.copy.src_area.top = 0;
|
|
|
drawable->u.copy.src_area.bottom = height;
|
|
@@ -306,11 +371,9 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
|
|
|
drawable->u.copy.mask.pos.y = 0;
|
|
|
drawable->u.copy.mask.bitmap = 0;
|
|
|
|
|
|
- drawable->u.copy.src_bitmap = qxl_bo_physical_address(qdev, image_bo, 0);
|
|
|
+ drawable->u.copy.src_bitmap = qxl_bo_physical_address(qdev, dimage->bo, 0);
|
|
|
qxl_release_unmap(qdev, release, &drawable->release_info);
|
|
|
- qxl_release_add_res(qdev, release, image_bo);
|
|
|
- qxl_bo_unreserve(image_bo);
|
|
|
- qxl_bo_unref(&image_bo);
|
|
|
+
|
|
|
clips_ptr = clips;
|
|
|
for (i = 0; i < num_clips; i++, clips_ptr += inc) {
|
|
|
rects[i].left = clips_ptr->x1;
|
|
@@ -319,17 +382,22 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
|
|
|
rects[i].bottom = clips_ptr->y2;
|
|
|
}
|
|
|
qxl_bo_kunmap(clips_bo);
|
|
|
- qxl_bo_unreserve(clips_bo);
|
|
|
- qxl_bo_unref(&clips_bo);
|
|
|
|
|
|
- qxl_fence_releaseable(qdev, release);
|
|
|
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
|
|
|
- qxl_release_unreserve(qdev, release);
|
|
|
- return;
|
|
|
+ qxl_release_fence_buffer_objects(release);
|
|
|
+
|
|
|
+out_release_backoff:
|
|
|
+ if (ret)
|
|
|
+ qxl_release_backoff_reserve_list(release);
|
|
|
+out_free_image:
|
|
|
+ qxl_image_free_objects(qdev, dimage);
|
|
|
+out_free_clips:
|
|
|
+ qxl_bo_unref(&clips_bo);
|
|
|
+out_free_drawable:
|
|
|
+ /* only free drawable on error */
|
|
|
+ if (ret)
|
|
|
+ free_drawable(qdev, release);
|
|
|
|
|
|
-out_unref:
|
|
|
- qxl_release_unreserve(qdev, release);
|
|
|
- qxl_release_free(qdev, release);
|
|
|
}
|
|
|
|
|
|
void qxl_draw_copyarea(struct qxl_device *qdev,
|
|
@@ -342,22 +410,36 @@ void qxl_draw_copyarea(struct qxl_device *qdev,
|
|
|
struct qxl_release *release;
|
|
|
int ret;
|
|
|
|
|
|
+ ret = alloc_drawable(qdev, &release);
|
|
|
+ if (ret)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* do a reservation run over all the objects we just allocated */
|
|
|
+ ret = qxl_release_reserve_list(release, true);
|
|
|
+ if (ret)
|
|
|
+ goto out_free_release;
|
|
|
+
|
|
|
rect.left = dx;
|
|
|
rect.top = dy;
|
|
|
rect.right = dx + width;
|
|
|
rect.bottom = dy + height;
|
|
|
- ret = make_drawable(qdev, 0, QXL_COPY_BITS, &rect, &release);
|
|
|
- if (ret)
|
|
|
- return;
|
|
|
+ ret = make_drawable(qdev, 0, QXL_COPY_BITS, &rect, release);
|
|
|
+ if (ret) {
|
|
|
+ qxl_release_backoff_reserve_list(release);
|
|
|
+ goto out_free_release;
|
|
|
+ }
|
|
|
|
|
|
drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
|
|
|
drawable->u.copy_bits.src_pos.x = sx;
|
|
|
drawable->u.copy_bits.src_pos.y = sy;
|
|
|
-
|
|
|
qxl_release_unmap(qdev, release, &drawable->release_info);
|
|
|
- qxl_fence_releaseable(qdev, release);
|
|
|
+
|
|
|
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
|
|
|
- qxl_release_unreserve(qdev, release);
|
|
|
+ qxl_release_fence_buffer_objects(release);
|
|
|
+
|
|
|
+out_free_release:
|
|
|
+ if (ret)
|
|
|
+ free_drawable(qdev, release);
|
|
|
}
|
|
|
|
|
|
void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)
|
|
@@ -370,10 +452,21 @@ void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)
|
|
|
struct qxl_release *release;
|
|
|
int ret;
|
|
|
|
|
|
- ret = make_drawable(qdev, 0, QXL_DRAW_FILL, &rect, &release);
|
|
|
+ ret = alloc_drawable(qdev, &release);
|
|
|
if (ret)
|
|
|
return;
|
|
|
|
|
|
+ /* do a reservation run over all the objects we just allocated */
|
|
|
+ ret = qxl_release_reserve_list(release, true);
|
|
|
+ if (ret)
|
|
|
+ goto out_free_release;
|
|
|
+
|
|
|
+ ret = make_drawable(qdev, 0, QXL_DRAW_FILL, &rect, release);
|
|
|
+ if (ret) {
|
|
|
+ qxl_release_backoff_reserve_list(release);
|
|
|
+ goto out_free_release;
|
|
|
+ }
|
|
|
+
|
|
|
drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
|
|
|
drawable->u.fill.brush.type = SPICE_BRUSH_TYPE_SOLID;
|
|
|
drawable->u.fill.brush.u.color = color;
|
|
@@ -384,7 +477,11 @@ void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)
|
|
|
drawable->u.fill.mask.bitmap = 0;
|
|
|
|
|
|
qxl_release_unmap(qdev, release, &drawable->release_info);
|
|
|
- qxl_fence_releaseable(qdev, release);
|
|
|
+
|
|
|
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
|
|
|
- qxl_release_unreserve(qdev, release);
|
|
|
+ qxl_release_fence_buffer_objects(release);
|
|
|
+
|
|
|
+out_free_release:
|
|
|
+ if (ret)
|
|
|
+ free_drawable(qdev, release);
|
|
|
}
|