b8be059ce86dc698e80d4b958ad04357fd71a628
[mesa.git] / src / gallium / winsys / drm / radeon / core / radeon_buffer.c
1 /*
2 * Copyright © 2008 Jérôme Glisse
3 * 2009 Corbin Simpson
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
18 * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * The above copyright notice and this permission notice (including the
24 * next paragraph) shall be included in all copies or substantial portions
25 * of the Software.
26 */
27 /*
28 * Authors:
29 * Jérôme Glisse <glisse@freedesktop.org>
30 * Corbin Simpson <MostAwesomeDude@gmail.com>
31 */
32
33 #include "radeon_buffer.h"
34
35 #include "radeon_bo_gem.h"
36 #include "softpipe/sp_texture.h"
37 #include "r300_context.h"
38 #include "util/u_format.h"
39 #include "util/u_math.h"
40 #include <X11/Xutil.h>
41
42 struct radeon_vl_context
43 {
44 Display *display;
45 int screen;
46 Drawable drawable;
47 };
48
49 static const char *radeon_get_name(struct pipe_winsys *ws)
50 {
51 return "Radeon/GEM+KMS";
52 }
53
54 static struct pipe_buffer *radeon_buffer_create(struct pipe_winsys *ws,
55 unsigned alignment,
56 unsigned usage,
57 unsigned size)
58 {
59 struct radeon_winsys *radeon_ws = (struct radeon_winsys *)ws;
60 struct radeon_pipe_buffer *radeon_buffer;
61 uint32_t domain;
62
63 radeon_buffer = CALLOC_STRUCT(radeon_pipe_buffer);
64 if (radeon_buffer == NULL) {
65 return NULL;
66 }
67
68 pipe_reference_init(&radeon_buffer->base.reference, 1);
69 radeon_buffer->base.alignment = alignment;
70 radeon_buffer->base.usage = usage;
71 radeon_buffer->base.size = size;
72
73 domain = 0;
74
75 if (usage & PIPE_BUFFER_USAGE_PIXEL) {
76 domain |= RADEON_GEM_DOMAIN_VRAM;
77 }
78 if (usage & PIPE_BUFFER_USAGE_VERTEX) {
79 domain |= RADEON_GEM_DOMAIN_GTT;
80 }
81 if (usage & PIPE_BUFFER_USAGE_INDEX) {
82 domain |= RADEON_GEM_DOMAIN_GTT;
83 }
84
85 radeon_buffer->ws = radeon_ws;
86 radeon_buffer->bo = radeon_bo_open(radeon_ws->priv->bom, 0, size,
87 alignment, domain, 0);
88 if (radeon_buffer->bo == NULL) {
89 FREE(radeon_buffer);
90 return NULL;
91 }
92 return &radeon_buffer->base;
93 }
94
95 static struct pipe_buffer *radeon_buffer_user_create(struct pipe_winsys *ws,
96 void *ptr,
97 unsigned bytes)
98 {
99 struct radeon_pipe_buffer *radeon_buffer;
100
101 radeon_buffer =
102 (struct radeon_pipe_buffer*)radeon_buffer_create(ws, 0, 0, bytes);
103 if (radeon_buffer == NULL) {
104 return NULL;
105 }
106 radeon_bo_map(radeon_buffer->bo, 1);
107 memcpy(radeon_buffer->bo->ptr, ptr, bytes);
108 radeon_bo_unmap(radeon_buffer->bo);
109 return &radeon_buffer->base;
110 }
111
112 static struct pipe_buffer *radeon_surface_buffer_create(struct pipe_winsys *ws,
113 unsigned width,
114 unsigned height,
115 enum pipe_format format,
116 unsigned usage,
117 unsigned tex_usage,
118 unsigned *stride)
119 {
120 /* Radeons enjoy things in multiples of 32. */
121 /* XXX this can be 32 when POT */
122 const unsigned alignment = 64;
123 unsigned nblocksy, size;
124
125 nblocksy = util_format_get_nblocksy(format, height);
126 *stride = align(util_format_get_stride(format, width), alignment);
127 size = *stride * nblocksy;
128
129 return radeon_buffer_create(ws, 64, usage, size);
130 }
131
132 static void radeon_buffer_del(struct pipe_buffer *buffer)
133 {
134 struct radeon_pipe_buffer *radeon_buffer =
135 (struct radeon_pipe_buffer*)buffer;
136 struct radeon_winsys_priv *priv = radeon_buffer->ws->priv;
137
138 if (radeon_bo_is_referenced_by_cs(radeon_buffer->bo, priv->cs)) {
139 priv->flush_cb(priv->flush_data);
140 }
141
142 radeon_bo_unref(radeon_buffer->bo);
143 free(radeon_buffer);
144 }
145
146 static void *radeon_buffer_map(struct pipe_winsys *ws,
147 struct pipe_buffer *buffer,
148 unsigned flags)
149 {
150 struct radeon_winsys_priv *priv = ((struct radeon_winsys *)ws)->priv;
151 struct radeon_pipe_buffer *radeon_buffer =
152 (struct radeon_pipe_buffer*)buffer;
153 int write = 0;
154
155 if (radeon_bo_is_referenced_by_cs(radeon_buffer->bo, priv->cs)) {
156 priv->flush_cb(priv->flush_data);
157 }
158
159 if (flags & PIPE_BUFFER_USAGE_DONTBLOCK) {
160 uint32_t domain;
161
162 if (radeon_bo_is_busy(radeon_buffer->bo, &domain))
163 return NULL;
164 }
165 if (flags & PIPE_BUFFER_USAGE_CPU_WRITE) {
166 write = 1;
167 }
168
169 if (radeon_bo_map(radeon_buffer->bo, write)) {
170 return NULL;
171 }
172
173 return radeon_buffer->bo->ptr;
174 }
175
176 static void radeon_buffer_unmap(struct pipe_winsys *ws,
177 struct pipe_buffer *buffer)
178 {
179 struct radeon_pipe_buffer *radeon_buffer =
180 (struct radeon_pipe_buffer*)buffer;
181
182 radeon_bo_unmap(radeon_buffer->bo);
183 }
184
185 static void radeon_fence_reference(struct pipe_winsys *ws,
186 struct pipe_fence_handle **ptr,
187 struct pipe_fence_handle *pfence)
188 {
189 }
190
191 static int radeon_fence_signalled(struct pipe_winsys *ws,
192 struct pipe_fence_handle *pfence,
193 unsigned flag)
194 {
195 return 1;
196 }
197
198 static int radeon_fence_finish(struct pipe_winsys *ws,
199 struct pipe_fence_handle *pfence,
200 unsigned flag)
201 {
202 return 0;
203 }
204
205 static void radeon_display_surface(struct pipe_winsys *pws,
206 struct pipe_surface *psurf,
207 struct radeon_vl_context *rvl_ctx)
208 {
209 struct r300_texture *r300tex = (struct r300_texture *)(psurf->texture);
210 XImage *ximage;
211 void *data;
212
213 ximage = XCreateImage(rvl_ctx->display,
214 XDefaultVisual(rvl_ctx->display, rvl_ctx->screen),
215 XDefaultDepth(rvl_ctx->display, rvl_ctx->screen),
216 ZPixmap, 0, /* format, offset */
217 NULL, /* data */
218 0, 0, /* size */
219 32, /* bitmap_pad */
220 0); /* bytes_per_line */
221
222 assert(ximage->format);
223 assert(ximage->bitmap_unit);
224
225 data = pws->buffer_map(pws, r300tex->buffer, 0);
226
227 /* update XImage's fields */
228 ximage->data = data;
229 ximage->width = psurf->width;
230 ximage->height = psurf->height;
231 ximage->bytes_per_line = psurf->width * (ximage->bits_per_pixel >> 3);
232
233 XPutImage(rvl_ctx->display, rvl_ctx->drawable,
234 XDefaultGC(rvl_ctx->display, rvl_ctx->screen),
235 ximage, 0, 0, 0, 0, psurf->width, psurf->height);
236
237 XSync(rvl_ctx->display, 0);
238
239 ximage->data = NULL;
240 XDestroyImage(ximage);
241
242 pws->buffer_unmap(pws, r300tex->buffer);
243 }
244
245 static void radeon_flush_frontbuffer(struct pipe_winsys *pipe_winsys,
246 struct pipe_surface *pipe_surface,
247 void *context_private)
248 {
249 struct radeon_vl_context *rvl_ctx;
250 rvl_ctx = (struct radeon_vl_context *) context_private;
251 radeon_display_surface(pipe_winsys, pipe_surface, rvl_ctx);
252 }
253
254 struct radeon_winsys* radeon_pipe_winsys(int fd)
255 {
256 struct radeon_winsys* radeon_ws;
257
258 radeon_ws = CALLOC_STRUCT(radeon_winsys);
259 if (radeon_ws == NULL) {
260 return NULL;
261 }
262
263 radeon_ws->priv = CALLOC_STRUCT(radeon_winsys_priv);
264 if (radeon_ws->priv == NULL) {
265 FREE(radeon_ws);
266 return NULL;
267 }
268
269 radeon_ws->priv->fd = fd;
270 radeon_ws->priv->bom = radeon_bo_manager_gem_ctor(fd);
271
272 radeon_ws->base.flush_frontbuffer = radeon_flush_frontbuffer;
273
274 radeon_ws->base.buffer_create = radeon_buffer_create;
275 radeon_ws->base.user_buffer_create = radeon_buffer_user_create;
276 radeon_ws->base.surface_buffer_create = radeon_surface_buffer_create;
277 radeon_ws->base.buffer_map = radeon_buffer_map;
278 radeon_ws->base.buffer_unmap = radeon_buffer_unmap;
279 radeon_ws->base.buffer_destroy = radeon_buffer_del;
280
281 radeon_ws->base.fence_reference = radeon_fence_reference;
282 radeon_ws->base.fence_signalled = radeon_fence_signalled;
283 radeon_ws->base.fence_finish = radeon_fence_finish;
284
285 radeon_ws->base.get_name = radeon_get_name;
286
287 return radeon_ws;
288 }
289 #if 0
290 static struct pipe_buffer *radeon_buffer_from_handle(struct radeon_screen *radeon_screen,
291 uint32_t handle)
292 {
293 struct radeon_pipe_buffer *radeon_buffer;
294 struct radeon_bo *bo = NULL;
295
296 bo = radeon_bo_open(radeon_screen->bom, handle, 0, 0, 0, 0);
297 if (bo == NULL) {
298 return NULL;
299 }
300 radeon_buffer = calloc(1, sizeof(struct radeon_pipe_buffer));
301 if (radeon_buffer == NULL) {
302 radeon_bo_unref(bo);
303 return NULL;
304 }
305 pipe_reference_init(&radeon_buffer->base.reference, 1);
306 radeon_buffer->base.usage = PIPE_BUFFER_USAGE_PIXEL;
307 radeon_buffer->bo = bo;
308 return &radeon_buffer->base;
309 }
310
311 struct pipe_surface *radeon_surface_from_handle(struct radeon_context *radeon_context,
312 uint32_t handle,
313 enum pipe_format format,
314 int w, int h, int pitch)
315 {
316 struct pipe_screen *pipe_screen = radeon_context->pipe_screen;
317 struct pipe_winsys *pipe_winsys = radeon_context->pipe_winsys;
318 struct pipe_texture tmpl;
319 struct pipe_surface *ps;
320 struct pipe_texture *pt;
321 struct pipe_buffer *pb;
322
323 pb = radeon_buffer_from_handle(radeon_context->radeon_screen, handle);
324 if (pb == NULL) {
325 return NULL;
326 }
327 memset(&tmpl, 0, sizeof(tmpl));
328 tmpl.tex_usage = PIPE_TEXTURE_USAGE_DISPLAY_TARGET;
329 tmpl.target = PIPE_TEXTURE_2D;
330 tmpl.width0 = w;
331 tmpl.height0 = h;
332 tmpl.depth0 = 1;
333 tmpl.format = format;
334
335 pt = pipe_screen->texture_blanket(pipe_screen, &tmpl, &pitch, pb);
336 if (pt == NULL) {
337 pipe_buffer_reference(&pb, NULL);
338 }
339 ps = pipe_screen->get_tex_surface(pipe_screen, pt, 0, 0, 0,
340 PIPE_BUFFER_USAGE_GPU_WRITE);
341 return ps;
342 }
343 #endif