(Stephane Marchesin, me) add hyperz support to radeon and r200 drivers. Only fast...
[mesa.git] / src / mesa / drivers / dri / savage / savagedma.c
1 /*
2 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
3 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <X11/Xlibint.h>
26 #include <stdio.h>
27 #include "savageioctl.h"
28 #include "savagedma.h"
29 #include "savage_bci.h"
30 #include <time.h>
31 #include <unistd.h>
32
33 /* Commit does not depend on whether we use real DMA or fake it via the BCI */
34 void savageDMACommit (savageContextPtr imesa, void *endPtr) {
35 DMABufferPtr dmaBuff = &imesa->DMABuf;
36 GLuint end = (GLuint)endPtr;
37
38 /* make sure that enough space was allocated */
39 assert (end <= dmaBuff->allocEnd);
40
41 dmaBuff->allocEnd = dmaBuff->end = end;
42
43 /* TODO: check commands, either here or in flush */
44 }
45
46 #if SAVAGE_CMD_DMA
47 /* flag =
48 0 return -1 if no available page
49 1 wait until a page be available */
50 static GLuint getDMAPage (savageContextPtr imesa, int flag) {
51 DMABufferPtr dmaBuff = &imesa->DMABuf;
52 GLuint page;
53 GLuint eventTag1;
54
55 if (dmaBuff->kickFlag == GL_FALSE)
56 return dmaBuff->usingPage;
57
58 page = dmaBuff->usingPage + 1;
59
60 /* overflow */
61 if (page >= (dmaBuff->buf->size * dmaBuff->buf->type)/DMA_PAGE_SIZE)
62 page = 0;
63
64 eventTag1 = GET_EVENTTAG;
65 if ( eventTag1 == page) { /* is kicking off */
66 if (flag == 1)
67 while (GET_EVENTTAG == page); /* FIXME: add a max loop count? */
68 else
69 return -1;
70 }
71
72 /* ok, that's it */
73 dmaBuff->usingPage = page;
74 dmaBuff->start = dmaBuff->end = dmaBuff->allocEnd =
75 (dmaBuff->buf->linear + DMA_PAGE_SIZE * page);
76 dmaBuff->kickFlag = GL_FALSE;
77
78 return page;
79 }
80
81 /* Allocate space in a real DMA buffer */
82 void *savageDMAAlloc (savageContextPtr imesa, GLuint size) {
83 DMABufferPtr dmaBuff = &imesa->DMABuf;
84
85 /* make sure that everything has been filled in and committed */
86 assert (dmaBuff->end == dmaBuff->allocEnd);
87
88 size *= sizeof (uint32_t); /* size in bytes */
89 if (dmaBuff->kickFlag == GL_TRUE) {
90 if (size > DMA_PAGE_SIZE)
91 return NULL;
92 getDMAPage (imesa, 1);
93 } else if (dmaBuff->end + size >=
94 dmaBuff->buf->linear + DMA_PAGE_SIZE*(dmaBuff->usingPage+1)) {
95 /* need kick off */
96 savageDMAFlush (imesa);
97 getDMAPage (imesa, 1);
98 }
99 dmaBuff->allocEnd = dmaBuff->end + size;
100 return (void *)dmaBuff->end;
101 }
102
103 /* Flush DMA buffer via DMA */
104 void savageDMAFlush (savageContextPtr imesa) {
105 volatile uint32_t* BCIbase;
106 DMABufferPtr dmaBuff = &imesa->DMABuf;
107 uint32_t phyAddress;
108 GLuint dmaCount, dmaCount1, remain;
109 int i;
110
111 /* make sure that everything has been filled in and committed */
112 assert (dmaBuff->allocEnd == dmaBuff->end);
113
114 if (dmaBuff->kickFlag == GL_TRUE) /* has been kicked off? */
115 return;
116 if (dmaBuff->start == dmaBuff->end) /* no command? */
117 return;
118
119 /* get bci base */
120 BCIbase = (volatile uint32_t *)SAVAGE_GET_BCI_POINTER(imesa,4);
121
122 /* set the eventtag */
123 *BCIbase = (dmaBuff->usingPage & 0xffffL) | (CMD_UpdateShadowStat << 27)
124 | (1 << 22);
125 *BCIbase = 0x96010051; /* set register x51*/
126 /* set the DMA buffer address */
127 phyAddress = (dmaBuff->buf->phyaddress + dmaBuff->usingPage*DMA_PAGE_SIZE)
128 & MDT_SRCADD_ALIGMENT;
129 if (dmaBuff->buf->location == DRM_SAVAGE_MEM_LOCATION_AGP)
130 *BCIbase = (phyAddress) | MDT_SRC_AGP;
131 else
132 *BCIbase = (phyAddress) | MDT_SRC_PCI;
133
134 /* pad with noops to multiple of 32 bytes */
135 dmaCount = (GLuint)(dmaBuff->end - dmaBuff->start);
136 dmaCount1 = (dmaCount + 31UL) & ~31UL;
137 remain = (dmaCount1 - dmaCount) >> 2;
138 for (i = 0; i < remain; i++) {
139 *((uint32_t *)dmaBuff->end) = 0x40000000L;
140 dmaBuff->end+=4;
141 }
142 dmaCount = (dmaCount1 >> 3) - 1;
143 dmaBuff->allocEnd = dmaBuff->end;
144
145 /* kick off */
146 *BCIbase = (0xA8000000L)|dmaCount;
147 dmaBuff->kickFlag = GL_TRUE;
148 }
149
150 /* Init real DMA */
151 int savageDMAInit (savageContextPtr imesa)
152 {
153 DMABufferPtr dmaBuff = &imesa->DMABuf;
154 drm_savage_alloc_cont_mem_t * req;
155 int i;
156 long ret;
157
158 req = (drm_savage_alloc_cont_mem_t *)
159 malloc (sizeof(drm_savage_alloc_cont_mem_t));
160 if (!req)
161 return GL_FALSE;
162
163 req->type = DRM_SAVAGE_MEM_PAGE;
164 req->linear = 0;
165
166 /* try agp first */
167 req->phyaddress = imesa->sarea->agp_offset;
168 if (req->phyaddress) {
169 if (drmMap (imesa->driFd,
170 req->phyaddress,
171 DRM_SAVAGE_DMA_AGP_SIZE,
172 (drmAddressPtr)&req->linear) < 0) {
173 fprintf (stderr, "AGP map error.\n");
174 goto dma;
175 }
176 if (0) fprintf (stderr,"Using AGP dma|\n");
177 req->location = DRM_SAVAGE_MEM_LOCATION_AGP;
178 req->size = DRM_SAVAGE_DMA_AGP_SIZE/DRM_SAVAGE_MEM_PAGE;
179 }
180
181 dma:
182 if (!req->linear) {
183 req->size = DMA_BUFFER_SIZE/DRM_SAVAGE_MEM_PAGE;
184 for (i = 0; i < DMA_TRY_COUNT; i++) {
185 if ((ret = savageAllocDMABuffer (imesa, req)) != 0)
186 break;
187 req->size = req->size/2;
188 }
189
190 if (ret <= 0) {
191 fprintf(stderr, "Can't alloc DMA memory(system and agp)\n");
192 return GL_FALSE;
193 }
194 req->location = DRM_SAVAGE_MEM_LOCATION_PCI;
195 }
196
197 dmaBuff->buf = req;
198
199 dmaBuff->start = dmaBuff->end = dmaBuff->allocEnd = req->linear;
200 dmaBuff->usingPage = 0;
201 dmaBuff->kickFlag = GL_FALSE;
202
203 return GL_TRUE;
204 }
205
206 /* Close real DMA */
207 int savageDMAClose (savageContextPtr imesa)
208 {
209 DMABufferPtr dmaBuff = &imesa->DMABuf;
210 drm_savage_alloc_cont_mem_t * req = dmaBuff->buf;
211
212 if(req->location == DRM_SAVAGE_MEM_LOCATION_PCI)
213 savageFreeDMABuffer (imesa, req);
214 else { /* AGP memory */
215 drmUnmap ((drmAddress)req->linear, req->size*req->type);
216 drmRmMap (imesa->driFd, req->phyaddress);
217 }
218 free (req);
219
220 return GL_TRUE;
221 }
222 #else
223 /* Allocate space in faked DMA buffer */
224 void *savageDMAAlloc (savageContextPtr imesa, GLuint size) {
225 DMABufferPtr dmaBuff = &imesa->DMABuf;
226
227 /* make sure that everything has been filled in and committed */
228 assert (dmaBuff->end == dmaBuff->allocEnd);
229
230 size *= sizeof (uint32_t); /* size in bytes */
231 if (dmaBuff->end + size >= dmaBuff->buf->linear + DMA_PAGE_SIZE) {
232 /* need kick off */
233 savageDMAFlush (imesa);
234 }
235 dmaBuff->allocEnd = dmaBuff->end + size;
236 return (void *)dmaBuff->end;
237 }
238
239 /* Flush DMA buffer via BCI (faked DMA) */
240 void savageDMAFlush(savageContextPtr imesa) {
241 volatile uint32_t* BCIbase;
242 DMABufferPtr dmaBuff = &imesa->DMABuf;
243 uint32_t *entry;
244
245 /* make sure that everything has been filled in and committed */
246 assert (dmaBuff->allocEnd == dmaBuff->end);
247
248 if (dmaBuff->start == dmaBuff->end) /* no command? */
249 return;
250
251 /* get bci base */
252 BCIbase = (volatile uint32_t *)SAVAGE_GET_BCI_POINTER(
253 imesa, (dmaBuff->end - dmaBuff->start) / sizeof (uint32_t));
254
255 for (entry = (uint32_t *)dmaBuff->start;
256 entry < (uint32_t *)dmaBuff->end; ++entry)
257 *BCIbase = *entry;
258
259 dmaBuff->end = dmaBuff->allocEnd = dmaBuff->start;
260 }
261
262 /* Init faked DMA */
263 int savageDMAInit (savageContextPtr imesa) {
264 DMABufferPtr dmaBuff = &imesa->DMABuf;
265 drm_savage_alloc_cont_mem_t * req;
266
267 req = (drm_savage_alloc_cont_mem_t *)
268 malloc (sizeof(drm_savage_alloc_cont_mem_t));
269 if (!req)
270 return GL_FALSE;
271
272 req->linear = (GLuint)malloc (DMA_PAGE_SIZE);
273 if (!req->linear) {
274 free (req);
275 return GL_FALSE;
276 }
277
278 dmaBuff->buf = req;
279
280 dmaBuff->start = dmaBuff->end = dmaBuff->allocEnd = req->linear;
281 dmaBuff->usingPage = 0;
282 dmaBuff->kickFlag = GL_FALSE;
283
284 return GL_TRUE;
285 }
286
287 /* Close faked DMA */
288 int savageDMAClose (savageContextPtr imesa) {
289 DMABufferPtr dmaBuff = &imesa->DMABuf;
290 drm_savage_alloc_cont_mem_t * req = dmaBuff->buf;
291
292 free ((void *)req->linear);
293 free (req);
294
295 return GL_TRUE;
296 }
297
298 #endif
299
300 /* Faked vertex buffers
301 *
302 * This is a dirty hack, knowing that it will go away soon when real
303 * vertex DMA is implemented and eventually moved to the DRM.
304 */
305
306 static uint32_t vertex_data[16384]; /* 64KB */
307 static drmBuf vertex_buffer = {
308 0, /* idx */
309 65536, /* total = 64KB */
310 0, /* used */
311 (drmAddress)vertex_data /* address */
312 };
313
314 void savageFakeVertices (savageContextPtr imesa, drmBufPtr buffer) {
315 GLuint vertexStride = imesa->vertex_size; /* stride in dwords */
316 GLuint vertexSize = imesa->vertex_size; /* the real vertex size in dwords */
317 GLuint nVertices = buffer->used / (vertexStride*4);
318 uint32_t *data = (uint32_t*)buffer->address;
319 uint32_t vertexFormat = imesa->DrawPrimitiveCmd & SAVAGE_HW_SKIPFLAGS;
320 GLuint i, j, left;
321
322 /* we have the monopoly on vertex buffers ;-) */
323 assert (buffer == &vertex_buffer);
324 assert (buffer->used % (vertexStride*4) == 0); /* whole vertices */
325 assert (nVertices % 3 == 0); /* triangle lists */
326
327 /* Flush (pseodo) DMA before accessing the BCI directly. */
328 savageDMAFlush(imesa);
329
330 left = nVertices;
331 while (left != 0) {
332 /* Can emit up to 255 vertices (85 triangles) with one command. */
333 GLuint count = left > 255 ? 255 : left;
334 /* Don't go through another buffering mechanism, copy to BCI
335 * directly. */
336 volatile uint32_t *vb = SAVAGE_GET_BCI_POINTER(imesa,
337 count*vertexSize + 1);
338
339 WRITE_CMD (vb, SAVAGE_DRAW_PRIMITIVE(
340 count, SAVAGE_HW_TRIANGLE_LIST | vertexFormat, 0),
341 uint32_t);
342 for (i = 0; i < count; ++i) {
343 for (j = 0; j < vertexSize; ++j)
344 WRITE_CMD (vb, data[j], uint32_t);
345 data += vertexStride;
346 }
347 left -= count;
348 }
349
350 /* clear the vertex buffer for the next set of vertices */
351 vertex_buffer.used = 0;
352 }
353
354 drmBufPtr savageFakeGetBuffer (savageContextPtr imesa) {
355 assert (vertex_buffer.used == 0); /* has been flushed */
356 return &vertex_buffer;
357 }