2 * Copyright © 2008 Nicolai Haehnle
3 * Copyright © 2008 Jérôme Glisse
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * 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:
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
28 * Aapo Tahkola <aet@rasterburn.org>
29 * Nicolai Haehnle <prefect_@gmx.net>
30 * Jérôme Glisse <glisse@freedesktop.org>
34 #include "r300_emit.h"
35 #include "r300_cmdbuf.h"
36 #include "radeon_cs.h"
37 #include "radeon_cs_legacy.h"
38 #include "radeon_bo_legacy.h"
39 #include "radeon_context.h"
41 struct cs_manager_legacy
{
42 struct radeon_cs_manager base
;
43 struct radeon_context
*ctx
;
44 /* hack for scratch stuff */
46 uint32_t pending_count
;
49 struct cs_reloc_legacy
{
50 struct radeon_cs_reloc base
;
56 static struct radeon_cs
*cs_create(struct radeon_cs_manager
*csm
,
61 cs
= (struct radeon_cs
*)calloc(1, sizeof(struct radeon_cs
));
66 cs
->ndw
= (ndw
+ 0x3FF) & (~0x3FF);
67 cs
->packets
= (uint32_t*)malloc(4*cs
->ndw
);
68 if (cs
->packets
== NULL
) {
72 cs
->relocs_total_size
= 0;
76 static int cs_write_dword(struct radeon_cs
*cs
, uint32_t dword
)
78 if (cs
->cdw
>= cs
->ndw
) {
80 tmp
= (cs
->cdw
+ 1 + 0x3FF) & (~0x3FF);
81 ptr
= (uint32_t*)realloc(cs
->packets
, 4 * tmp
);
88 cs
->packets
[cs
->cdw
++] = dword
;
95 static int cs_write_reloc(struct radeon_cs
*cs
,
97 uint32_t start_offset
,
100 uint32_t write_domain
,
103 struct cs_reloc_legacy
*relocs
;
106 relocs
= (struct cs_reloc_legacy
*)cs
->relocs
;
108 if ((read_domain
&& write_domain
) || (!read_domain
&& !write_domain
)) {
109 /* in one CS a bo can only be in read or write domain but not
110 * in read & write domain at the same sime
114 if (read_domain
== RADEON_GEM_DOMAIN_CPU
) {
117 if (write_domain
== RADEON_GEM_DOMAIN_CPU
) {
120 /* check reloc window */
121 if (end_offset
> bo
->size
) {
124 if (start_offset
> end_offset
) {
127 /* check if bo is already referenced */
128 for(i
= 0; i
< cs
->crelocs
; i
++) {
131 if (relocs
[i
].base
.bo
->handle
== bo
->handle
) {
132 /* update start and end offset */
133 if (start_offset
< relocs
[i
].base
.start_offset
) {
134 relocs
[i
].base
.start_offset
= start_offset
;
136 if (end_offset
> relocs
[i
].base
.end_offset
) {
137 relocs
[i
].base
.end_offset
= end_offset
;
139 /* Check domains must be in read or write. As we check already
140 * checked that in argument one of the read or write domain was
141 * set we only need to check that if previous reloc as the read
142 * domain set then the read_domain should also be set for this
145 if (relocs
[i
].base
.read_domain
&& !read_domain
) {
148 if (relocs
[i
].base
.write_domain
&& !write_domain
) {
151 relocs
[i
].base
.read_domain
|= read_domain
;
152 relocs
[i
].base
.write_domain
|= write_domain
;
154 relocs
[i
].cindices
+= 1;
155 indices
= (uint32_t*)realloc(relocs
[i
].indices
,
156 relocs
[i
].cindices
* 4);
157 if (indices
== NULL
) {
158 relocs
[i
].cindices
-= 1;
161 relocs
[i
].indices
= indices
;
162 relocs
[i
].indices
[relocs
[i
].cindices
- 1] = cs
->cdw
- 1;
166 /* add bo to reloc */
167 relocs
= (struct cs_reloc_legacy
*)
169 sizeof(struct cs_reloc_legacy
) * (cs
->crelocs
+ 1));
170 if (relocs
== NULL
) {
174 relocs
[cs
->crelocs
].base
.bo
= bo
;
175 relocs
[cs
->crelocs
].base
.start_offset
= start_offset
;
176 relocs
[cs
->crelocs
].base
.end_offset
= end_offset
;
177 relocs
[cs
->crelocs
].base
.read_domain
= read_domain
;
178 relocs
[cs
->crelocs
].base
.write_domain
= write_domain
;
179 relocs
[cs
->crelocs
].base
.flags
= flags
;
180 relocs
[cs
->crelocs
].indices
= (uint32_t*)malloc(4);
181 if (relocs
[cs
->crelocs
].indices
== NULL
) {
184 relocs
[cs
->crelocs
].indices
[0] = cs
->cdw
- 1;
185 relocs
[cs
->crelocs
].cindices
= 1;
186 cs
->relocs_total_size
+= radeon_bo_legacy_relocs_size(bo
);
192 static int cs_begin(struct radeon_cs
*cs
,
199 fprintf(stderr
, "CS already in a section(%s,%s,%d)\n",
200 cs
->section_file
, cs
->section_func
, cs
->section_line
);
201 fprintf(stderr
, "CS can't start section(%s,%s,%d)\n",
206 cs
->section_ndw
= ndw
;
208 cs
->section_file
= file
;
209 cs
->section_func
= func
;
210 cs
->section_line
= line
;
214 static int cs_end(struct radeon_cs
*cs
,
221 fprintf(stderr
, "CS no section to end at (%s,%s,%d)\n",
226 if (cs
->section_ndw
!= cs
->section_cdw
) {
227 fprintf(stderr
, "CS section size missmatch start at (%s,%s,%d)\n",
228 cs
->section_file
, cs
->section_func
, cs
->section_line
);
229 fprintf(stderr
, "CS section end at (%s,%s,%d)\n",
236 static int cs_process_relocs(struct radeon_cs
*cs
)
238 struct cs_manager_legacy
*csm
= (struct cs_manager_legacy
*)cs
->csm
;
239 struct cs_reloc_legacy
*relocs
;
242 if (!IS_R300_CLASS(csm
->ctx
->radeonScreen
)) {
243 /* FIXME: r300 only right now */
246 csm
= (struct cs_manager_legacy
*)cs
->csm
;
247 relocs
= (struct cs_reloc_legacy
*)cs
->relocs
;
248 for (i
= 0; i
< cs
->crelocs
; i
++) {
249 for (j
= 0; j
< relocs
[i
].cindices
; j
++) {
250 uint32_t soffset
, eoffset
;
252 soffset
= relocs
[i
].base
.start_offset
;
253 eoffset
= relocs
[i
].base
.end_offset
;
254 r
= radeon_bo_legacy_validate(relocs
[i
].base
.bo
,
257 fprintf(stderr
, "validated %p [0x%08X, 0x%08X]\n",
258 relocs
[i
].base
.bo
, soffset
, eoffset
);
261 cs
->packets
[relocs
[i
].indices
[j
]] += soffset
;
262 if (cs
->packets
[relocs
[i
].indices
[j
]] >= eoffset
) {
263 radeon_bo_debug(relocs
[i
].base
.bo
, 12);
264 fprintf(stderr
, "validated %p [0x%08X, 0x%08X]\n",
265 relocs
[i
].base
.bo
, soffset
, eoffset
);
266 fprintf(stderr
, "above end: %p 0x%08X 0x%08X\n",
268 cs
->packets
[relocs
[i
].indices
[j
]],
278 static int cs_set_age(struct radeon_cs
*cs
)
280 struct cs_manager_legacy
*csm
= (struct cs_manager_legacy
*)cs
->csm
;
281 struct cs_reloc_legacy
*relocs
;
284 relocs
= (struct cs_reloc_legacy
*)cs
->relocs
;
285 for (i
= 0; i
< cs
->crelocs
; i
++) {
286 radeon_bo_legacy_pending(relocs
[i
].base
.bo
, csm
->pending_age
);
287 radeon_bo_unref(relocs
[i
].base
.bo
);
292 static int cs_emit(struct radeon_cs
*cs
)
294 struct cs_manager_legacy
*csm
= (struct cs_manager_legacy
*)cs
->csm
;
295 drm_radeon_cmd_buffer_t cmd
;
296 drm_r300_cmd_header_t age
;
300 /* please flush pipe do all pending work */
301 cs_write_dword(cs
, cmdpacket0(csm
->ctx
->radeonScreen
,
302 R300_SC_SCREENDOOR
, 1));
303 cs_write_dword(cs
, 0x0);
304 cs_write_dword(cs
, cmdpacket0(csm
->ctx
->radeonScreen
,
305 R300_SC_SCREENDOOR
, 1));
306 cs_write_dword(cs
, 0x00FFFFFF);
307 cs_write_dword(cs
, cmdpacket0(csm
->ctx
->radeonScreen
,
309 cs_write_dword(cs
, 0x0);
310 cs_write_dword(cs
, cmdpacket0(csm
->ctx
->radeonScreen
,
312 cs_write_dword(cs
, 0x0);
313 cs_write_dword(cs
, cmdpacket0(csm
->ctx
->radeonScreen
,
315 cs_write_dword(cs
, 0x0);
316 cs_write_dword(cs
, cmdwait(csm
->ctx
->radeonScreen
, R300_WAIT_3D
));
317 cs_write_dword(cs
, cmdpacket0(csm
->ctx
->radeonScreen
,
318 R300_RB3D_DSTCACHE_CTLSTAT
, 1));
319 cs_write_dword(cs
, R300_RB3D_DSTCACHE_CTLSTAT_DC_FLUSH_FLUSH_DIRTY_3D
);
320 cs_write_dword(cs
, cmdpacket0(csm
->ctx
->radeonScreen
,
321 R300_ZB_ZCACHE_CTLSTAT
, 1));
322 cs_write_dword(cs
, R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_FLUSH_AND_FREE
);
323 cs_write_dword(cs
, cmdwait(csm
->ctx
->radeonScreen
,
324 R300_WAIT_3D
| R300_WAIT_3D_CLEAN
));
326 /* append buffer age */
327 age
.scratch
.cmd_type
= R300_CMD_SCRATCH
;
328 /* Scratch register 2 corresponds to what radeonGetAge polls */
329 csm
->pending_age
= 0;
330 csm
->pending_count
= 1;
331 ull
= (uint64_t) (intptr_t) &csm
->pending_age
;
333 age
.scratch
.n_bufs
= 1;
334 age
.scratch
.flags
= 0;
335 radeon_cs_write_dword(cs
, age
.u
);
336 radeon_cs_write_dword(cs
, ull
& 0xffffffff);
337 radeon_cs_write_dword(cs
, ull
>> 32);
338 radeon_cs_write_dword(cs
, 0);
340 r
= cs_process_relocs(cs
);
345 cmd
.buf
= (char *)cs
->packets
;
346 cmd
.bufsz
= cs
->cdw
* 4;
347 if (csm
->ctx
->state
.scissor
.enabled
) {
348 cmd
.nbox
= csm
->ctx
->state
.scissor
.numClipRects
;
349 cmd
.boxes
= (drm_clip_rect_t
*) csm
->ctx
->state
.scissor
.pClipRects
;
351 cmd
.nbox
= csm
->ctx
->numClipRects
;
352 cmd
.boxes
= (drm_clip_rect_t
*) csm
->ctx
->pClipRects
;
355 r
= drmCommandWrite(cs
->csm
->fd
, DRM_RADEON_CMDBUF
, &cmd
, sizeof(cmd
));
363 static int cs_destroy(struct radeon_cs
*cs
)
371 static int cs_erase(struct radeon_cs
*cs
)
374 cs
->relocs_total_size
= 0;
382 static int cs_need_flush(struct radeon_cs
*cs
)
384 /* FIXME: we should get the texture heap size */
385 return (cs
->relocs_total_size
> (7*1024*1024));
388 static struct radeon_cs_funcs radeon_cs_legacy_funcs
= {
400 struct radeon_cs_manager
*radeon_cs_manager_legacy_ctor(struct radeon_context
*ctx
)
402 struct cs_manager_legacy
*csm
;
404 csm
= (struct cs_manager_legacy
*)
405 calloc(1, sizeof(struct cs_manager_legacy
));
409 csm
->base
.funcs
= &radeon_cs_legacy_funcs
;
410 csm
->base
.fd
= ctx
->dri
.fd
;
412 csm
->pending_age
= 1;
413 return (struct radeon_cs_manager
*)csm
;
416 void radeon_cs_manager_legacy_dtor(struct radeon_cs_manager
*csm
)