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