2 * Copyright 2011 Red Hat, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 #include <linux/dma-buf-map.h>
25 #include <drm/drm_fourcc.h>
28 #include "qxl_object.h"
30 static int alloc_clips(struct qxl_device
*qdev
,
31 struct qxl_release
*release
,
32 unsigned int num_clips
,
33 struct qxl_bo
**clips_bo
)
35 int size
= sizeof(struct qxl_clip_rects
) + sizeof(struct qxl_rect
) * num_clips
;
37 return qxl_alloc_bo_reserved(qdev
, release
, size
, clips_bo
);
40 /* returns a pointer to the already allocated qxl_rect array inside
41 * the qxl_clip_rects. This is *not* the same as the memory allocated
42 * on the device, it is offset to qxl_clip_rects.chunk.data */
43 static struct qxl_rect
*drawable_set_clipping(struct qxl_device
*qdev
,
44 unsigned int num_clips
,
45 struct qxl_bo
*clips_bo
)
47 struct dma_buf_map map
;
48 struct qxl_clip_rects
*dev_clips
;
51 ret
= qxl_bo_kmap(clips_bo
, &map
);
54 dev_clips
= map
.vaddr
; /* TODO: Use mapping abstraction properly */
56 dev_clips
->num_rects
= num_clips
;
57 dev_clips
->chunk
.next_chunk
= 0;
58 dev_clips
->chunk
.prev_chunk
= 0;
59 dev_clips
->chunk
.data_size
= sizeof(struct qxl_rect
) * num_clips
;
60 return (struct qxl_rect
*)dev_clips
->chunk
.data
;
64 alloc_drawable(struct qxl_device
*qdev
, struct qxl_release
**release
)
66 return qxl_alloc_release_reserved(qdev
, sizeof(struct qxl_drawable
),
67 QXL_RELEASE_DRAWABLE
, release
, NULL
);
71 free_drawable(struct qxl_device
*qdev
, struct qxl_release
*release
)
73 qxl_release_free(qdev
, release
);
76 /* release needs to be reserved at this point */
78 make_drawable(struct qxl_device
*qdev
, int surface
, uint8_t type
,
79 const struct qxl_rect
*rect
,
80 struct qxl_release
*release
)
82 struct qxl_drawable
*drawable
;
85 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
89 drawable
->type
= type
;
91 drawable
->surface_id
= surface
; /* Only primary for now */
92 drawable
->effect
= QXL_EFFECT_OPAQUE
;
93 drawable
->self_bitmap
= 0;
94 drawable
->self_bitmap_area
.top
= 0;
95 drawable
->self_bitmap_area
.left
= 0;
96 drawable
->self_bitmap_area
.bottom
= 0;
97 drawable
->self_bitmap_area
.right
= 0;
98 /* FIXME: add clipping */
99 drawable
->clip
.type
= SPICE_CLIP_TYPE_NONE
;
102 * surfaces_dest[i] should apparently be filled out with the
103 * surfaces that we depend on, and surface_rects should be
104 * filled with the rectangles of those surfaces that we
107 for (i
= 0; i
< 3; ++i
)
108 drawable
->surfaces_dest
[i
] = -1;
111 drawable
->bbox
= *rect
;
113 drawable
->mm_time
= qdev
->rom
->mm_clock
;
114 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
118 /* push a draw command using the given clipping rectangles as
119 * the sources from the shadow framebuffer.
121 * Right now implementing with a single draw and a clip list. Clip
122 * lists are known to be a problem performance wise, this can be solved
123 * by treating them differently in the server.
125 void qxl_draw_dirty_fb(struct qxl_device
*qdev
,
126 struct drm_framebuffer
*fb
,
128 unsigned int flags
, unsigned int color
,
129 struct drm_clip_rect
*clips
,
130 unsigned int num_clips
, int inc
,
131 uint32_t dumb_shadow_offset
)
134 * TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should
135 * send a fill command instead, much cheaper.
137 * See include/drm/drm_mode.h
139 struct drm_clip_rect
*clips_ptr
;
141 int left
, right
, top
, bottom
;
143 struct qxl_drawable
*drawable
;
144 struct qxl_rect drawable_rect
;
145 struct qxl_rect
*rects
;
146 int stride
= fb
->pitches
[0];
147 /* depth is not actually interesting, we don't mask with it */
148 int depth
= fb
->format
->cpp
[0] * 8;
149 struct dma_buf_map surface_map
;
150 uint8_t *surface_base
;
151 struct qxl_release
*release
;
152 struct qxl_bo
*clips_bo
;
153 struct qxl_drm_image
*dimage
;
156 ret
= alloc_drawable(qdev
, &release
);
160 clips
->x1
+= dumb_shadow_offset
;
161 clips
->x2
+= dumb_shadow_offset
;
168 /* skip the first clip rect */
169 for (i
= 1, clips_ptr
= clips
+ inc
;
170 i
< num_clips
; i
++, clips_ptr
+= inc
) {
171 left
= min_t(int, left
, (int)clips_ptr
->x1
);
172 right
= max_t(int, right
, (int)clips_ptr
->x2
);
173 top
= min_t(int, top
, (int)clips_ptr
->y1
);
174 bottom
= max_t(int, bottom
, (int)clips_ptr
->y2
);
177 width
= right
- left
;
178 height
= bottom
- top
;
180 ret
= alloc_clips(qdev
, release
, num_clips
, &clips_bo
);
182 goto out_free_drawable
;
184 ret
= qxl_image_alloc_objects(qdev
, release
,
190 /* do a reservation run over all the objects we just allocated */
191 ret
= qxl_release_reserve_list(release
, true);
195 drawable_rect
.left
= left
;
196 drawable_rect
.right
= right
;
197 drawable_rect
.top
= top
;
198 drawable_rect
.bottom
= bottom
;
200 ret
= make_drawable(qdev
, 0, QXL_DRAW_COPY
, &drawable_rect
,
203 goto out_release_backoff
;
205 ret
= qxl_bo_kmap(bo
, &surface_map
);
207 goto out_release_backoff
;
208 surface_base
= surface_map
.vaddr
; /* TODO: Use mapping abstraction properly */
210 ret
= qxl_image_init(qdev
, release
, dimage
, surface_base
,
211 left
- dumb_shadow_offset
,
212 top
, width
, height
, depth
, stride
);
215 goto out_release_backoff
;
217 rects
= drawable_set_clipping(qdev
, num_clips
, clips_bo
);
220 goto out_release_backoff
;
222 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
224 drawable
->clip
.type
= SPICE_CLIP_TYPE_RECTS
;
225 drawable
->clip
.data
= qxl_bo_physical_address(qdev
,
228 drawable
->u
.copy
.src_area
.top
= 0;
229 drawable
->u
.copy
.src_area
.bottom
= height
;
230 drawable
->u
.copy
.src_area
.left
= 0;
231 drawable
->u
.copy
.src_area
.right
= width
;
233 drawable
->u
.copy
.rop_descriptor
= SPICE_ROPD_OP_PUT
;
234 drawable
->u
.copy
.scale_mode
= 0;
235 drawable
->u
.copy
.mask
.flags
= 0;
236 drawable
->u
.copy
.mask
.pos
.x
= 0;
237 drawable
->u
.copy
.mask
.pos
.y
= 0;
238 drawable
->u
.copy
.mask
.bitmap
= 0;
240 drawable
->u
.copy
.src_bitmap
= qxl_bo_physical_address(qdev
, dimage
->bo
, 0);
241 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
244 for (i
= 0; i
< num_clips
; i
++, clips_ptr
+= inc
) {
245 rects
[i
].left
= clips_ptr
->x1
;
246 rects
[i
].right
= clips_ptr
->x2
;
247 rects
[i
].top
= clips_ptr
->y1
;
248 rects
[i
].bottom
= clips_ptr
->y2
;
250 qxl_bo_kunmap(clips_bo
);
252 qxl_release_fence_buffer_objects(release
);
253 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
257 qxl_release_backoff_reserve_list(release
);
259 qxl_image_free_objects(qdev
, dimage
);
261 qxl_bo_unref(&clips_bo
);
263 /* only free drawable on error */
265 free_drawable(qdev
, release
);