Merge remote branch 'origin/nvc0'
[mesa.git] / src / gallium / winsys / radeon / drm / radeon_r300.c
1 /*
2 * Copyright 2008 Corbin Simpson <MostAwesomeDude@gmail.com>
3 *
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:
10 *
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
13 * Software.
14 *
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 AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23 #include "radeon_drm_buffer.h"
24
25 #include "util/u_memory.h"
26 #include "pipebuffer/pb_bufmgr.h"
27
28 #include "radeon_cs_gem.h"
29 #include "state_tracker/drm_driver.h"
30
31 static unsigned get_pb_usage_from_create_flags(unsigned bind, unsigned usage,
32 enum r300_buffer_domain domain)
33 {
34 unsigned res = 0;
35
36 if (bind & (PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_RENDER_TARGET |
37 PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT))
38 res |= PB_USAGE_GPU_WRITE;
39
40 if (bind & PIPE_BIND_SAMPLER_VIEW)
41 res |= PB_USAGE_GPU_READ | PB_USAGE_GPU_WRITE;
42
43 if (bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER))
44 res |= PB_USAGE_GPU_READ;
45
46 if (bind & PIPE_BIND_TRANSFER_WRITE)
47 res |= PB_USAGE_CPU_WRITE;
48
49 if (bind & PIPE_BIND_TRANSFER_READ)
50 res |= PB_USAGE_CPU_READ;
51
52 /* Is usage of any use for us? Probably not. */
53
54 /* Now add driver-specific usage flags. */
55 if (bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER))
56 res |= RADEON_PB_USAGE_VERTEX;
57
58 if (domain & R300_DOMAIN_GTT)
59 res |= RADEON_PB_USAGE_DOMAIN_GTT;
60
61 if (domain & R300_DOMAIN_VRAM)
62 res |= RADEON_PB_USAGE_DOMAIN_VRAM;
63
64 return res;
65 }
66
67 static struct r300_winsys_buffer *
68 radeon_r300_winsys_buffer_create(struct r300_winsys_screen *rws,
69 unsigned size,
70 unsigned alignment,
71 unsigned bind,
72 unsigned usage,
73 enum r300_buffer_domain domain)
74 {
75 struct radeon_drm_winsys *ws = radeon_drm_winsys(rws);
76 struct pb_desc desc;
77 struct pb_manager *provider;
78 struct pb_buffer *buffer;
79
80 memset(&desc, 0, sizeof(desc));
81 desc.alignment = alignment;
82 desc.usage = get_pb_usage_from_create_flags(bind, usage, domain);
83
84 /* Assign a buffer manager. */
85 if (bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER))
86 provider = ws->cman;
87 else
88 provider = ws->kman;
89
90 buffer = provider->create_buffer(provider, size, &desc);
91 if (!buffer)
92 return NULL;
93
94 return (struct r300_winsys_buffer*)buffer;
95 }
96
97 static void radeon_r300_winsys_buffer_reference(struct r300_winsys_screen *rws,
98 struct r300_winsys_buffer **pdst,
99 struct r300_winsys_buffer *src)
100 {
101 struct pb_buffer *_src = radeon_pb_buffer(src);
102 struct pb_buffer *_dst = radeon_pb_buffer(*pdst);
103
104 pb_reference(&_dst, _src);
105
106 *pdst = (struct r300_winsys_buffer*)_dst;
107 }
108
109 static struct r300_winsys_buffer *radeon_r300_winsys_buffer_from_handle(struct r300_winsys_screen *rws,
110 struct winsys_handle *whandle,
111 unsigned *stride,
112 unsigned *size)
113 {
114 struct radeon_drm_winsys *ws = radeon_drm_winsys(rws);
115 struct pb_buffer *_buf;
116
117 _buf = radeon_drm_bufmgr_create_buffer_from_handle(ws->kman, whandle->handle);
118
119 if (stride)
120 *stride = whandle->stride;
121 if (size)
122 *size = _buf->base.size;
123
124 return (struct r300_winsys_buffer*)_buf;
125 }
126
127 static boolean radeon_r300_winsys_buffer_get_handle(struct r300_winsys_screen *rws,
128 struct r300_winsys_buffer *buffer,
129 unsigned stride,
130 struct winsys_handle *whandle)
131 {
132 struct pb_buffer *_buf = radeon_pb_buffer(buffer);
133 whandle->stride = stride;
134 return radeon_drm_bufmgr_get_handle(_buf, whandle);
135 }
136
137 static void radeon_r300_winsys_cs_set_flush(struct r300_winsys_cs *rcs,
138 void (*flush)(void *),
139 void *user)
140 {
141 struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
142 cs->flush_cs = flush;
143 cs->flush_data = user;
144 radeon_cs_space_set_flush(cs->cs, flush, user);
145 }
146
147 static boolean radeon_r300_winsys_cs_validate(struct r300_winsys_cs *rcs)
148 {
149 struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
150
151 return radeon_cs_space_check(cs->cs) >= 0;
152 }
153
154 static void radeon_r300_winsys_cs_reset_buffers(struct r300_winsys_cs *rcs)
155 {
156 struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
157 radeon_cs_space_reset_bos(cs->cs);
158 }
159
160 static void radeon_r300_winsys_cs_flush(struct r300_winsys_cs *rcs)
161 {
162 struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
163 int retval;
164
165 /* Don't flush a zero-sized CS. */
166 if (!cs->base.cdw) {
167 return;
168 }
169
170 cs->cs->cdw = cs->base.cdw;
171
172 radeon_drm_bufmgr_flush_maps(cs->ws->kman);
173
174 /* Emit the CS. */
175 retval = radeon_cs_emit(cs->cs);
176 if (retval) {
177 if (debug_get_bool_option("RADEON_DUMP_CS", FALSE)) {
178 fprintf(stderr, "radeon: The kernel rejected CS, dumping...\n");
179 radeon_cs_print(cs->cs, stderr);
180 } else {
181 fprintf(stderr, "radeon: The kernel rejected CS, "
182 "see dmesg for more information.\n");
183 }
184 }
185
186 /* Reset CS.
187 * Someday, when we care about performance, we should really find a way
188 * to rotate between two or three CS objects so that the GPU can be
189 * spinning through one CS while another one is being filled. */
190 radeon_cs_erase(cs->cs);
191
192 cs->base.buf = cs->cs->packets;
193 cs->base.cdw = cs->cs->cdw;
194 }
195
196 static uint32_t radeon_get_value(struct r300_winsys_screen *rws,
197 enum r300_value_id id)
198 {
199 struct radeon_drm_winsys *ws = (struct radeon_drm_winsys *)rws;
200
201 switch(id) {
202 case R300_VID_PCI_ID:
203 return ws->pci_id;
204 case R300_VID_GB_PIPES:
205 return ws->gb_pipes;
206 case R300_VID_Z_PIPES:
207 return ws->z_pipes;
208 case R300_VID_SQUARE_TILING_SUPPORT:
209 return ws->squaretiling;
210 case R300_VID_DRM_2_3_0:
211 return ws->drm_2_3_0;
212 case R300_VID_DRM_2_6_0:
213 return ws->drm_2_6_0;
214 case R300_VID_DRM_2_8_0:
215 return ws->drm_2_8_0;
216 case R300_CAN_HYPERZ:
217 return ws->hyperz;
218 }
219 return 0;
220 }
221
222 static struct r300_winsys_cs *radeon_r300_winsys_cs_create(struct r300_winsys_screen *rws)
223 {
224 struct radeon_drm_winsys *ws = radeon_drm_winsys(rws);
225 struct radeon_drm_cs *cs = CALLOC_STRUCT(radeon_drm_cs);
226
227 if (!cs)
228 return NULL;
229
230 /* Size limit on IBs is 64 kibibytes. */
231 cs->cs = radeon_cs_create(ws->csm, 1024 * 64 / 4);
232 if (!cs->cs) {
233 FREE(cs);
234 return NULL;
235 }
236
237 radeon_cs_set_limit(cs->cs,
238 RADEON_GEM_DOMAIN_GTT, ws->gart_size);
239 radeon_cs_set_limit(cs->cs,
240 RADEON_GEM_DOMAIN_VRAM, ws->vram_size);
241
242 cs->ws = ws;
243 cs->base.buf = cs->cs->packets;
244 cs->base.cdw = cs->cs->cdw;
245 return &cs->base;
246 }
247
248 static void radeon_r300_winsys_cs_destroy(struct r300_winsys_cs *rcs)
249 {
250 struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
251 radeon_cs_destroy(cs->cs);
252 FREE(cs);
253 }
254
255 void radeon_winsys_init_functions(struct radeon_drm_winsys *ws)
256 {
257 ws->base.get_value = radeon_get_value;
258 ws->base.buffer_create = radeon_r300_winsys_buffer_create;
259 ws->base.buffer_reference = radeon_r300_winsys_buffer_reference;
260 ws->base.buffer_from_handle = radeon_r300_winsys_buffer_from_handle;
261 ws->base.buffer_get_handle = radeon_r300_winsys_buffer_get_handle;
262 ws->base.cs_create = radeon_r300_winsys_cs_create;
263 ws->base.cs_destroy = radeon_r300_winsys_cs_destroy;
264 ws->base.cs_validate = radeon_r300_winsys_cs_validate;
265 ws->base.cs_flush = radeon_r300_winsys_cs_flush;
266 ws->base.cs_reset_buffers = radeon_r300_winsys_cs_reset_buffers;
267 ws->base.cs_set_flush = radeon_r300_winsys_cs_set_flush;
268 }