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 <drm/drm_fourcc.h>
26 #include "qxl_object.h"
28 static int alloc_clips(struct qxl_device
*qdev
,
29 struct qxl_release
*release
,
30 unsigned int num_clips
,
31 struct qxl_bo
**clips_bo
)
33 int size
= sizeof(struct qxl_clip_rects
) + sizeof(struct qxl_rect
) * num_clips
;
35 return qxl_alloc_bo_reserved(qdev
, release
, size
, clips_bo
);
38 /* returns a pointer to the already allocated qxl_rect array inside
39 * the qxl_clip_rects. This is *not* the same as the memory allocated
40 * on the device, it is offset to qxl_clip_rects.chunk.data */
41 static struct qxl_rect
*drawable_set_clipping(struct qxl_device
*qdev
,
42 unsigned int num_clips
,
43 struct qxl_bo
*clips_bo
)
45 struct qxl_clip_rects
*dev_clips
;
48 ret
= qxl_bo_kmap(clips_bo
, (void **)&dev_clips
);
52 dev_clips
->num_rects
= num_clips
;
53 dev_clips
->chunk
.next_chunk
= 0;
54 dev_clips
->chunk
.prev_chunk
= 0;
55 dev_clips
->chunk
.data_size
= sizeof(struct qxl_rect
) * num_clips
;
56 return (struct qxl_rect
*)dev_clips
->chunk
.data
;
60 alloc_drawable(struct qxl_device
*qdev
, struct qxl_release
**release
)
62 return qxl_alloc_release_reserved(qdev
, sizeof(struct qxl_drawable
),
63 QXL_RELEASE_DRAWABLE
, release
, NULL
);
67 free_drawable(struct qxl_device
*qdev
, struct qxl_release
*release
)
69 qxl_release_free(qdev
, release
);
72 /* release needs to be reserved at this point */
74 make_drawable(struct qxl_device
*qdev
, int surface
, uint8_t type
,
75 const struct qxl_rect
*rect
,
76 struct qxl_release
*release
)
78 struct qxl_drawable
*drawable
;
81 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
85 drawable
->type
= type
;
87 drawable
->surface_id
= surface
; /* Only primary for now */
88 drawable
->effect
= QXL_EFFECT_OPAQUE
;
89 drawable
->self_bitmap
= 0;
90 drawable
->self_bitmap_area
.top
= 0;
91 drawable
->self_bitmap_area
.left
= 0;
92 drawable
->self_bitmap_area
.bottom
= 0;
93 drawable
->self_bitmap_area
.right
= 0;
94 /* FIXME: add clipping */
95 drawable
->clip
.type
= SPICE_CLIP_TYPE_NONE
;
98 * surfaces_dest[i] should apparently be filled out with the
99 * surfaces that we depend on, and surface_rects should be
100 * filled with the rectangles of those surfaces that we
103 for (i
= 0; i
< 3; ++i
)
104 drawable
->surfaces_dest
[i
] = -1;
107 drawable
->bbox
= *rect
;
109 drawable
->mm_time
= qdev
->rom
->mm_clock
;
110 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
114 /* push a draw command using the given clipping rectangles as
115 * the sources from the shadow framebuffer.
117 * Right now implementing with a single draw and a clip list. Clip
118 * lists are known to be a problem performance wise, this can be solved
119 * by treating them differently in the server.
121 void qxl_draw_dirty_fb(struct qxl_device
*qdev
,
122 struct drm_framebuffer
*fb
,
124 unsigned int flags
, unsigned int color
,
125 struct drm_clip_rect
*clips
,
126 unsigned int num_clips
, int inc
,
127 uint32_t dumb_shadow_offset
)
130 * TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should
131 * send a fill command instead, much cheaper.
133 * See include/drm/drm_mode.h
135 struct drm_clip_rect
*clips_ptr
;
137 int left
, right
, top
, bottom
;
139 struct qxl_drawable
*drawable
;
140 struct qxl_rect drawable_rect
;
141 struct qxl_rect
*rects
;
142 int stride
= fb
->pitches
[0];
143 /* depth is not actually interesting, we don't mask with it */
144 int depth
= fb
->format
->cpp
[0] * 8;
145 uint8_t *surface_base
;
146 struct qxl_release
*release
;
147 struct qxl_bo
*clips_bo
;
148 struct qxl_drm_image
*dimage
;
151 ret
= alloc_drawable(qdev
, &release
);
155 clips
->x1
+= dumb_shadow_offset
;
156 clips
->x2
+= dumb_shadow_offset
;
163 /* skip the first clip rect */
164 for (i
= 1, clips_ptr
= clips
+ inc
;
165 i
< num_clips
; i
++, clips_ptr
+= inc
) {
166 left
= min_t(int, left
, (int)clips_ptr
->x1
);
167 right
= max_t(int, right
, (int)clips_ptr
->x2
);
168 top
= min_t(int, top
, (int)clips_ptr
->y1
);
169 bottom
= max_t(int, bottom
, (int)clips_ptr
->y2
);
172 width
= right
- left
;
173 height
= bottom
- top
;
175 ret
= alloc_clips(qdev
, release
, num_clips
, &clips_bo
);
177 goto out_free_drawable
;
179 ret
= qxl_image_alloc_objects(qdev
, release
,
185 /* do a reservation run over all the objects we just allocated */
186 ret
= qxl_release_reserve_list(release
, true);
190 drawable_rect
.left
= left
;
191 drawable_rect
.right
= right
;
192 drawable_rect
.top
= top
;
193 drawable_rect
.bottom
= bottom
;
195 ret
= make_drawable(qdev
, 0, QXL_DRAW_COPY
, &drawable_rect
,
198 goto out_release_backoff
;
200 ret
= qxl_bo_kmap(bo
, (void **)&surface_base
);
202 goto out_release_backoff
;
204 ret
= qxl_image_init(qdev
, release
, dimage
, surface_base
,
205 left
- dumb_shadow_offset
,
206 top
, width
, height
, depth
, stride
);
209 goto out_release_backoff
;
211 rects
= drawable_set_clipping(qdev
, num_clips
, clips_bo
);
213 goto out_release_backoff
;
215 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
217 drawable
->clip
.type
= SPICE_CLIP_TYPE_RECTS
;
218 drawable
->clip
.data
= qxl_bo_physical_address(qdev
,
221 drawable
->u
.copy
.src_area
.top
= 0;
222 drawable
->u
.copy
.src_area
.bottom
= height
;
223 drawable
->u
.copy
.src_area
.left
= 0;
224 drawable
->u
.copy
.src_area
.right
= width
;
226 drawable
->u
.copy
.rop_descriptor
= SPICE_ROPD_OP_PUT
;
227 drawable
->u
.copy
.scale_mode
= 0;
228 drawable
->u
.copy
.mask
.flags
= 0;
229 drawable
->u
.copy
.mask
.pos
.x
= 0;
230 drawable
->u
.copy
.mask
.pos
.y
= 0;
231 drawable
->u
.copy
.mask
.bitmap
= 0;
233 drawable
->u
.copy
.src_bitmap
= qxl_bo_physical_address(qdev
, dimage
->bo
, 0);
234 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
237 for (i
= 0; i
< num_clips
; i
++, clips_ptr
+= inc
) {
238 rects
[i
].left
= clips_ptr
->x1
;
239 rects
[i
].right
= clips_ptr
->x2
;
240 rects
[i
].top
= clips_ptr
->y1
;
241 rects
[i
].bottom
= clips_ptr
->y2
;
243 qxl_bo_kunmap(clips_bo
);
245 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
246 qxl_release_fence_buffer_objects(release
);
250 qxl_release_backoff_reserve_list(release
);
252 qxl_image_free_objects(qdev
, dimage
);
254 qxl_bo_unref(&clips_bo
);
256 /* only free drawable on error */
258 free_drawable(qdev
, release
);