Merge branch 'mesa_7_6_branch'
[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
37 static const char *radeon_get_name(struct pipe_winsys *ws)
38 {
39 return "Radeon/GEM+KMS";
40 }
41
42 static struct pipe_buffer *radeon_buffer_create(struct pipe_winsys *ws,
43 unsigned alignment,
44 unsigned usage,
45 unsigned size)
46 {
47 struct radeon_winsys *radeon_ws = (struct radeon_winsys *)ws;
48 struct radeon_pipe_buffer *radeon_buffer;
49 uint32_t domain;
50
51 radeon_buffer = CALLOC_STRUCT(radeon_pipe_buffer);
52 if (radeon_buffer == NULL) {
53 return NULL;
54 }
55
56 pipe_reference_init(&radeon_buffer->base.reference, 1);
57 radeon_buffer->base.alignment = alignment;
58 radeon_buffer->base.usage = usage;
59 radeon_buffer->base.size = size;
60
61 domain = 0;
62
63 if (usage & PIPE_BUFFER_USAGE_PIXEL) {
64 domain |= RADEON_GEM_DOMAIN_VRAM;
65 }
66 if (usage & PIPE_BUFFER_USAGE_VERTEX) {
67 domain |= RADEON_GEM_DOMAIN_GTT;
68 }
69 if (usage & PIPE_BUFFER_USAGE_INDEX) {
70 domain |= RADEON_GEM_DOMAIN_GTT;
71 }
72
73 radeon_buffer->bo = radeon_bo_open(radeon_ws->priv->bom, 0, size,
74 alignment, domain, 0);
75 if (radeon_buffer->bo == NULL) {
76 FREE(radeon_buffer);
77 return NULL;
78 }
79 return &radeon_buffer->base;
80 }
81
82 static struct pipe_buffer *radeon_buffer_user_create(struct pipe_winsys *ws,
83 void *ptr,
84 unsigned bytes)
85 {
86 struct radeon_pipe_buffer *radeon_buffer;
87
88 radeon_buffer =
89 (struct radeon_pipe_buffer*)radeon_buffer_create(ws, 0, 0, bytes);
90 if (radeon_buffer == NULL) {
91 return NULL;
92 }
93 radeon_bo_map(radeon_buffer->bo, 1);
94 memcpy(radeon_buffer->bo->ptr, ptr, bytes);
95 radeon_bo_unmap(radeon_buffer->bo);
96 return &radeon_buffer->base;
97 }
98
99 static struct pipe_buffer *radeon_surface_buffer_create(struct pipe_winsys *ws,
100 unsigned width,
101 unsigned height,
102 enum pipe_format format,
103 unsigned usage,
104 unsigned tex_usage,
105 unsigned *stride)
106 {
107 struct pipe_format_block block;
108 unsigned nblocksx, nblocksy, size;
109
110 pf_get_block(format, &block);
111
112 nblocksx = pf_get_nblocksx(&block, width);
113 nblocksy = pf_get_nblocksy(&block, height);
114
115 /* Radeons enjoy things in multiples of 32. */
116 /* XXX this can be 32 when POT */
117 *stride = (nblocksx * block.size + 63) & ~63;
118 size = *stride * nblocksy;
119
120 return radeon_buffer_create(ws, 64, usage, size);
121 }
122
123 static void radeon_buffer_del(struct pipe_buffer *buffer)
124 {
125 struct radeon_pipe_buffer *radeon_buffer =
126 (struct radeon_pipe_buffer*)buffer;
127
128 radeon_bo_unref(radeon_buffer->bo);
129 free(radeon_buffer);
130 }
131
132 static void *radeon_buffer_map(struct pipe_winsys *ws,
133 struct pipe_buffer *buffer,
134 unsigned flags)
135 {
136 struct radeon_pipe_buffer *radeon_buffer =
137 (struct radeon_pipe_buffer*)buffer;
138 int write = 0;
139
140 if (flags & PIPE_BUFFER_USAGE_DONTBLOCK) {
141 uint32_t domain;
142
143 if (radeon_bo_is_busy(radeon_buffer->bo, &domain))
144 return NULL;
145 }
146 if (flags & PIPE_BUFFER_USAGE_CPU_WRITE) {
147 write = 1;
148 }
149
150 if (radeon_bo_map(radeon_buffer->bo, write)) {
151 return NULL;
152 }
153
154 return radeon_buffer->bo->ptr;
155 }
156
157 static void radeon_buffer_unmap(struct pipe_winsys *ws,
158 struct pipe_buffer *buffer)
159 {
160 struct radeon_pipe_buffer *radeon_buffer =
161 (struct radeon_pipe_buffer*)buffer;
162
163 radeon_bo_unmap(radeon_buffer->bo);
164 }
165
166 static void radeon_fence_reference(struct pipe_winsys *ws,
167 struct pipe_fence_handle **ptr,
168 struct pipe_fence_handle *pfence)
169 {
170 }
171
172 static int radeon_fence_signalled(struct pipe_winsys *ws,
173 struct pipe_fence_handle *pfence,
174 unsigned flag)
175 {
176 return 1;
177 }
178
179 static int radeon_fence_finish(struct pipe_winsys *ws,
180 struct pipe_fence_handle *pfence,
181 unsigned flag)
182 {
183 return 0;
184 }
185
186 static void radeon_flush_frontbuffer(struct pipe_winsys *pipe_winsys,
187 struct pipe_surface *pipe_surface,
188 void *context_private)
189 {
190 /* XXX TODO: call dri2CopyRegion */
191 }
192
193 struct radeon_winsys* radeon_pipe_winsys(int fd)
194 {
195 struct radeon_winsys* radeon_ws;
196
197 radeon_ws = CALLOC_STRUCT(radeon_winsys);
198 if (radeon_ws == NULL) {
199 return NULL;
200 }
201
202 radeon_ws->priv = CALLOC_STRUCT(radeon_winsys_priv);
203 if (radeon_ws->priv == NULL) {
204 FREE(radeon_ws);
205 return NULL;
206 }
207
208 radeon_ws->priv->fd = fd;
209 radeon_ws->priv->bom = radeon_bo_manager_gem_ctor(fd);
210
211 radeon_ws->base.flush_frontbuffer = radeon_flush_frontbuffer;
212
213 radeon_ws->base.buffer_create = radeon_buffer_create;
214 radeon_ws->base.user_buffer_create = radeon_buffer_user_create;
215 radeon_ws->base.surface_buffer_create = radeon_surface_buffer_create;
216 radeon_ws->base.buffer_map = radeon_buffer_map;
217 radeon_ws->base.buffer_unmap = radeon_buffer_unmap;
218 radeon_ws->base.buffer_destroy = radeon_buffer_del;
219
220 radeon_ws->base.fence_reference = radeon_fence_reference;
221 radeon_ws->base.fence_signalled = radeon_fence_signalled;
222 radeon_ws->base.fence_finish = radeon_fence_finish;
223
224 radeon_ws->base.get_name = radeon_get_name;
225
226 return radeon_ws;
227 }
228 #if 0
229 static struct pipe_buffer *radeon_buffer_from_handle(struct radeon_screen *radeon_screen,
230 uint32_t handle)
231 {
232 struct radeon_pipe_buffer *radeon_buffer;
233 struct radeon_bo *bo = NULL;
234
235 bo = radeon_bo_open(radeon_screen->bom, handle, 0, 0, 0, 0);
236 if (bo == NULL) {
237 return NULL;
238 }
239 radeon_buffer = calloc(1, sizeof(struct radeon_pipe_buffer));
240 if (radeon_buffer == NULL) {
241 radeon_bo_unref(bo);
242 return NULL;
243 }
244 pipe_reference_init(&radeon_buffer->base.reference, 1);
245 radeon_buffer->base.usage = PIPE_BUFFER_USAGE_PIXEL;
246 radeon_buffer->bo = bo;
247 return &radeon_buffer->base;
248 }
249
250 struct pipe_surface *radeon_surface_from_handle(struct radeon_context *radeon_context,
251 uint32_t handle,
252 enum pipe_format format,
253 int w, int h, int pitch)
254 {
255 struct pipe_screen *pipe_screen = radeon_context->pipe_screen;
256 struct pipe_winsys *pipe_winsys = radeon_context->pipe_winsys;
257 struct pipe_texture tmpl;
258 struct pipe_surface *ps;
259 struct pipe_texture *pt;
260 struct pipe_buffer *pb;
261
262 pb = radeon_buffer_from_handle(radeon_context->radeon_screen, handle);
263 if (pb == NULL) {
264 return NULL;
265 }
266 memset(&tmpl, 0, sizeof(tmpl));
267 tmpl.tex_usage = PIPE_TEXTURE_USAGE_DISPLAY_TARGET;
268 tmpl.target = PIPE_TEXTURE_2D;
269 tmpl.width[0] = w;
270 tmpl.height[0] = h;
271 tmpl.depth[0] = 1;
272 tmpl.format = format;
273 pf_get_block(tmpl.format, &tmpl.block);
274 tmpl.nblocksx[0] = pf_get_nblocksx(&tmpl.block, w);
275 tmpl.nblocksy[0] = pf_get_nblocksy(&tmpl.block, h);
276
277 pt = pipe_screen->texture_blanket(pipe_screen, &tmpl, &pitch, pb);
278 if (pt == NULL) {
279 pipe_buffer_reference(&pb, NULL);
280 }
281 ps = pipe_screen->get_tex_surface(pipe_screen, pt, 0, 0, 0,
282 PIPE_BUFFER_USAGE_GPU_WRITE);
283 return ps;
284 }
285 #endif