diff options
Diffstat (limited to 'drivers/misc/gcx/gcbv/gcbv.c')
-rw-r--r-- | drivers/misc/gcx/gcbv/gcbv.c | 2178 |
1 files changed, 2178 insertions, 0 deletions
diff --git a/drivers/misc/gcx/gcbv/gcbv.c b/drivers/misc/gcx/gcbv/gcbv.c new file mode 100644 index 00000000000..de4d074d508 --- /dev/null +++ b/drivers/misc/gcx/gcbv/gcbv.c | |||
@@ -0,0 +1,2178 @@ | |||
1 | /* | ||
2 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
3 | * redistributing this file, you may do so under either license. | ||
4 | * | ||
5 | * GPL LICENSE SUMMARY | ||
6 | * | ||
7 | * Copyright(c) 2012 Vivante Corporation. All rights reserved. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | * | ||
22 | * The full GNU General Public License is included in this distribution in | ||
23 | * the file called "COPYING". | ||
24 | * | ||
25 | * BSD LICENSE | ||
26 | * | ||
27 | * Copyright(c) 2012 Vivante Corporation. All rights reserved. | ||
28 | * | ||
29 | * Redistribution and use in source and binary forms, with or without | ||
30 | * modification, are permitted provided that the following conditions are met: | ||
31 | * | ||
32 | * * Redistributions of source code must retain the above copyright | ||
33 | * notice, this list of conditions and the following disclaimer. | ||
34 | * * Redistributions in binary form must reproduce the above copyright | ||
35 | * notice, this list of conditions and the following disclaimer in | ||
36 | * the documentation and/or other materials provided with the | ||
37 | * distribution. | ||
38 | * * Neither the name of Vivante Corporation nor the names of its | ||
39 | * contributors may be used to endorse or promote products derived | ||
40 | * from this software without specific prior written permission. | ||
41 | * | ||
42 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
43 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
44 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
45 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
46 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
47 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
48 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
49 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
50 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
51 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
52 | * POSSIBILITY OF SUCH DAMAGE. | ||
53 | */ | ||
54 | |||
55 | #include "gcbv.h" | ||
56 | |||
57 | #define GCZONE_NONE 0 | ||
58 | #define GCZONE_ALL (~0U) | ||
59 | #define GCZONE_INIT (1 << 0) | ||
60 | #define GCZONE_MAPPING (1 << 1) | ||
61 | #define GCZONE_BUFFER (1 << 2) | ||
62 | #define GCZONE_DEST (1 << 3) | ||
63 | #define GCZONE_SRC (1 << 4) | ||
64 | #define GCZONE_MASK (1 << 5) | ||
65 | #define GCZONE_BATCH (1 << 6) | ||
66 | #define GCZONE_BLIT (1 << 7) | ||
67 | #define GCZONE_CACHE (1 << 8) | ||
68 | #define GCZONE_CALLBACK (1 << 9) | ||
69 | #define GCZONE_TEMP (1 << 10) | ||
70 | #define GCZONE_BLEND (1 << 11) | ||
71 | |||
72 | GCDBG_FILTERDEF(bv, GCZONE_NONE, | ||
73 | "init", | ||
74 | "mapping", | ||
75 | "buffer", | ||
76 | "dest", | ||
77 | "source", | ||
78 | "mask", | ||
79 | "batch", | ||
80 | "blit", | ||
81 | "cache", | ||
82 | "callback", | ||
83 | "tempbuffer", | ||
84 | "blending") | ||
85 | |||
86 | |||
87 | /******************************************************************************* | ||
88 | ** Global driver data access. | ||
89 | */ | ||
90 | |||
91 | struct gccontext *get_context(void) | ||
92 | { | ||
93 | static struct gccontext gccontext; | ||
94 | return &gccontext; | ||
95 | } | ||
96 | |||
97 | |||
98 | /******************************************************************************* | ||
99 | * Debugging. | ||
100 | */ | ||
101 | |||
102 | #if GCDEBUG_ENABLE | ||
103 | #define GCDUMPBATCH(batch) \ | ||
104 | dumpbatch(batch) | ||
105 | |||
106 | #define GCVERIFYBATCH(changeflags, prevrect, currrect) \ | ||
107 | verify_batch(changeflags, prevrect, currrect) | ||
108 | |||
109 | static void dumpbatch(struct gcbatch *gcbatch) | ||
110 | { | ||
111 | struct list_head *gcbufferhead; | ||
112 | struct gcbuffer *gcbuffer; | ||
113 | struct list_head *gcfixuphead; | ||
114 | struct gcfixup *gcfixup; | ||
115 | unsigned int i, size; | ||
116 | |||
117 | if ((GCDBGFILTER.zone & (GCZONE_BUFFER)) == 0) | ||
118 | return; | ||
119 | |||
120 | GCDBG(GCZONE_BUFFER, "BATCH DUMP (0x%08X)\n", | ||
121 | (unsigned int) gcbatch); | ||
122 | |||
123 | list_for_each(gcbufferhead, &gcbatch->buffer) { | ||
124 | gcbuffer = list_entry(gcbufferhead, struct gcbuffer, link); | ||
125 | |||
126 | list_for_each(gcfixuphead, &gcbuffer->fixup) { | ||
127 | gcfixup = list_entry(gcfixuphead, struct gcfixup, link); | ||
128 | |||
129 | GCDBG(GCZONE_BUFFER, | ||
130 | " Fixup table @ 0x%08X, count = %d:\n", | ||
131 | (unsigned int) gcfixup, gcfixup->count); | ||
132 | |||
133 | for (i = 0; i < gcfixup->count; i += 1) { | ||
134 | GCDBG(GCZONE_BUFFER, " [%02d]" | ||
135 | " buffer offset = 0x%08X," | ||
136 | " surface offset = 0x%08X\n", | ||
137 | i, | ||
138 | gcfixup->fixup[i].dataoffset * 4, | ||
139 | gcfixup->fixup[i].surfoffset); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | size = (unsigned char *) gcbuffer->tail | ||
144 | - (unsigned char *) gcbuffer->head; | ||
145 | GCDUMPBUFFER(GCZONE_BUFFER, gcbuffer->head, 0, size); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void verify_batch(unsigned int changeflags, | ||
150 | struct bvrect *prevrect, | ||
151 | struct bvrect *currrect) | ||
152 | { | ||
153 | if ((changeflags & 1) == 0) { | ||
154 | /* Origin did not change. */ | ||
155 | if ((prevrect->left != currrect->left) || | ||
156 | (prevrect->top != currrect->top)) { | ||
157 | GCERR("origin changed\n"); | ||
158 | GCERR(" previous = %d,%d\n", | ||
159 | prevrect->left, prevrect->top); | ||
160 | GCERR(" current = %d,%d\n", | ||
161 | currrect->left, currrect->top); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | if ((changeflags & 2) == 0) { | ||
166 | /* Size did not change. */ | ||
167 | if ((prevrect->width != currrect->width) || | ||
168 | (prevrect->height != currrect->height)) { | ||
169 | GCERR("size changed\n"); | ||
170 | GCERR(" previous = %dx%d\n", | ||
171 | prevrect->width, prevrect->height); | ||
172 | GCERR(" current = %dx%d\n", | ||
173 | currrect->width, currrect->height); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | prevrect->left = currrect->left; | ||
178 | prevrect->top = currrect->top; | ||
179 | prevrect->width = currrect->width; | ||
180 | prevrect->height = currrect->height; | ||
181 | } | ||
182 | #else | ||
183 | #define GCDUMPBATCH(...) | ||
184 | #define GCVERIFYBATCH(...) | ||
185 | #endif | ||
186 | |||
187 | |||
188 | /******************************************************************************* | ||
189 | * Error handling. | ||
190 | */ | ||
191 | |||
192 | #define BVSETBLTSURFERROR(errorid, errordesc) \ | ||
193 | do { \ | ||
194 | struct gccontext *tmpcontext = get_context(); \ | ||
195 | snprintf(tmpcontext->bverrorstr, sizeof(tmpcontext->bverrorstr), \ | ||
196 | g_surferr[errorid].message, errordesc.id); \ | ||
197 | GCDUMPSTRING("%s(%d): [ERROR] %s\n", __func__, __LINE__, \ | ||
198 | tmpcontext->bverrorstr); \ | ||
199 | bverror = errordesc.base + g_surferr[errorid].offset; \ | ||
200 | bvbltparams->errdesc = tmpcontext->bverrorstr; \ | ||
201 | } while (0) | ||
202 | |||
203 | #define GCBVERR_DESC 0 | ||
204 | #define GCBVERR_DESC_VERS 1 | ||
205 | #define GCBVERR_DESC_VIRTADDR 2 | ||
206 | #define GCBVERR_TILE 3 | ||
207 | #define GCBVERR_TILE_VERS 4 | ||
208 | #define GCBVERR_TILE_VIRTADDR 5 | ||
209 | #define GCBVERR_GEOM 6 | ||
210 | #define GCBVERR_GEOM_VERS 7 | ||
211 | #define GCBVERR_GEOM_FORMAT 8 | ||
212 | |||
213 | struct bvsurferrorid { | ||
214 | char *id; | ||
215 | enum bverror base; | ||
216 | }; | ||
217 | |||
218 | struct bvsurferror { | ||
219 | unsigned int offset; | ||
220 | char *message; | ||
221 | }; | ||
222 | |||
223 | static struct bvsurferror g_surferr[] = { | ||
224 | /* GCBVERR_DESC */ | ||
225 | { 0, "%s desc structure is not set" }, | ||
226 | |||
227 | /* GCBVERR_DESC_VERS */ | ||
228 | { 100, "%s desc structure has invalid size" }, | ||
229 | |||
230 | /* GCBVERR_DESC_VIRTADDR */ | ||
231 | { 200, "%s desc virtual pointer is not set" }, | ||
232 | |||
233 | /* GCBVERR_TILE: FIXME/TODO define error code */ | ||
234 | { 0, "%s tileparams structure is not set" }, | ||
235 | |||
236 | /* GCBVERR_TILE_VERS */ | ||
237 | { 3000, "%s tileparams structure has invalid size" }, | ||
238 | |||
239 | /* GCBVERR_TILE_VIRTADDR: FIXME/TODO define error code */ | ||
240 | { 200, "%s tileparams virtual pointer is not set" }, | ||
241 | |||
242 | /* GCBVERR_GEOM */ | ||
243 | { 1000, "%s geom structure is not set" }, | ||
244 | |||
245 | /* GCBVERR_GEOM_VERS */ | ||
246 | { 1100, "%s geom structure has invalid size" }, | ||
247 | |||
248 | /* GCBVERR_GEOM_FORMAT */ | ||
249 | { 1200, "%s invalid format specified" }, | ||
250 | }; | ||
251 | |||
252 | static struct bvsurferrorid g_destsurferr = { "dst", BVERR_DSTDESC }; | ||
253 | static struct bvsurferrorid g_src1surferr = { "src1", BVERR_SRC1DESC }; | ||
254 | static struct bvsurferrorid g_src2surferr = { "src2", BVERR_SRC2DESC }; | ||
255 | static struct bvsurferrorid g_masksurferr = { "mask", BVERR_MASKDESC }; | ||
256 | |||
257 | |||
258 | /******************************************************************************* | ||
259 | * Callback info management. | ||
260 | */ | ||
261 | |||
262 | /* BLTsville callback function. */ | ||
263 | struct gccallbackbltsville { | ||
264 | /* Function pointer. */ | ||
265 | void (*fn) (struct bvcallbackerror *err, unsigned long callbackdata); | ||
266 | |||
267 | /* Callback data. */ | ||
268 | unsigned long data; | ||
269 | }; | ||
270 | |||
271 | /* Information for freeing a surface. */ | ||
272 | struct gccallbackfreesurface { | ||
273 | /* Pointer to the buffer descriptor. */ | ||
274 | struct bvbuffdesc *desc; | ||
275 | |||
276 | /* Pointer to the buffer. */ | ||
277 | void *ptr; | ||
278 | }; | ||
279 | |||
280 | /* Callback information. */ | ||
281 | struct gccallbackinfo { | ||
282 | union { | ||
283 | /* BLTsville callback function. */ | ||
284 | struct gccallbackbltsville callback; | ||
285 | |||
286 | /* Information for freeing a surface. */ | ||
287 | struct gccallbackfreesurface freesurface; | ||
288 | } info; | ||
289 | |||
290 | /* Previous/next callback information. */ | ||
291 | struct list_head link; | ||
292 | }; | ||
293 | |||
294 | static enum bverror get_callbackinfo(struct gccallbackinfo **gccallbackinfo) | ||
295 | { | ||
296 | enum bverror bverror; | ||
297 | struct gccontext *gccontext = get_context(); | ||
298 | struct gccallbackinfo *temp; | ||
299 | |||
300 | /* Lock access to callback info lists. */ | ||
301 | GCLOCK(&gccontext->callbacklock); | ||
302 | |||
303 | if (list_empty(&gccontext->callbackvac)) { | ||
304 | temp = gcalloc(struct gccallbackinfo, | ||
305 | sizeof(struct gccallbackinfo)); | ||
306 | if (temp == NULL) { | ||
307 | bverror = BVERR_OOM; | ||
308 | goto exit; | ||
309 | } | ||
310 | list_add(&temp->link, &gccontext->callbacklist); | ||
311 | } else { | ||
312 | struct list_head *head; | ||
313 | head = gccontext->callbackvac.next; | ||
314 | temp = list_entry(head, struct gccallbackinfo, link); | ||
315 | list_move(head, &gccontext->callbacklist); | ||
316 | } | ||
317 | |||
318 | *gccallbackinfo = temp; | ||
319 | bverror = BVERR_NONE; | ||
320 | |||
321 | exit: | ||
322 | /* Unlock access to callback info lists. */ | ||
323 | GCUNLOCK(&gccontext->callbacklock); | ||
324 | |||
325 | return bverror; | ||
326 | } | ||
327 | |||
328 | static void free_callback(struct gccallbackinfo *gccallbackinfo) | ||
329 | { | ||
330 | struct gccontext *gccontext = get_context(); | ||
331 | |||
332 | /* Lock access to callback info lists. */ | ||
333 | GCLOCK(&gccontext->callbacklock); | ||
334 | |||
335 | list_move(&gccallbackinfo->link, &gccontext->callbackvac); | ||
336 | |||
337 | /* Unlock access to callback info lists. */ | ||
338 | GCUNLOCK(&gccontext->callbacklock); | ||
339 | } | ||
340 | |||
341 | void callbackbltsville(void *callbackinfo) | ||
342 | { | ||
343 | struct gccallbackinfo *gccallbackinfo; | ||
344 | |||
345 | GCENTER(GCZONE_CALLBACK); | ||
346 | |||
347 | gccallbackinfo = (struct gccallbackinfo *) callbackinfo; | ||
348 | GCDBG(GCZONE_CALLBACK, "bltsville_callback = 0x%08X\n", | ||
349 | (unsigned int) gccallbackinfo->info.callback.fn); | ||
350 | GCDBG(GCZONE_CALLBACK, "bltsville_param = 0x%08X\n", | ||
351 | (unsigned int) gccallbackinfo->info.callback.data); | ||
352 | |||
353 | gccallbackinfo->info.callback.fn(NULL, | ||
354 | gccallbackinfo->info.callback.data); | ||
355 | free_callback(gccallbackinfo); | ||
356 | |||
357 | GCEXIT(GCZONE_CALLBACK); | ||
358 | } | ||
359 | |||
360 | void callbackfreesurface(void *callbackinfo) | ||
361 | { | ||
362 | struct gccallbackinfo *gccallbackinfo; | ||
363 | |||
364 | GCENTER(GCZONE_CALLBACK); | ||
365 | |||
366 | gccallbackinfo = (struct gccallbackinfo *) callbackinfo; | ||
367 | GCDBG(GCZONE_CALLBACK, "freeing descriptir @ 0x%08X\n", | ||
368 | (unsigned int) gccallbackinfo->info.freesurface.desc); | ||
369 | GCDBG(GCZONE_CALLBACK, "freeing memory @ 0x%08X\n", | ||
370 | (unsigned int) gccallbackinfo->info.freesurface.ptr); | ||
371 | |||
372 | free_surface(gccallbackinfo->info.freesurface.desc, | ||
373 | gccallbackinfo->info.freesurface.ptr); | ||
374 | free_callback(gccallbackinfo); | ||
375 | |||
376 | GCEXIT(GCZONE_CALLBACK); | ||
377 | } | ||
378 | |||
379 | |||
380 | /******************************************************************************* | ||
381 | * Temporary buffer management. | ||
382 | */ | ||
383 | |||
384 | enum bverror allocate_temp(struct bvbltparams *bvbltparams, | ||
385 | unsigned int size) | ||
386 | { | ||
387 | enum bverror bverror; | ||
388 | struct gccontext *gccontext = get_context(); | ||
389 | |||
390 | GCENTER(GCZONE_TEMP); | ||
391 | |||
392 | /* Existing buffer too small? */ | ||
393 | if ((gccontext->tmpbuffdesc != NULL) && | ||
394 | (gccontext->tmpbuffdesc->length < size)) { | ||
395 | GCDBG(GCZONE_TEMP, "freeing current buffer.\n"); | ||
396 | bverror = free_temp(true); | ||
397 | if (bverror != BVERR_NONE) { | ||
398 | bvbltparams->errdesc = gccontext->bverrorstr; | ||
399 | goto exit; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | /* Allocate new buffer if necessary. */ | ||
404 | if ((size > 0) && (gccontext->tmpbuffdesc == NULL)) { | ||
405 | /* Allocate temporary surface. */ | ||
406 | bverror = allocate_surface(&gccontext->tmpbuffdesc, | ||
407 | &gccontext->tmpbuff, | ||
408 | size); | ||
409 | if (bverror != BVERR_NONE) { | ||
410 | bvbltparams->errdesc = gccontext->bverrorstr; | ||
411 | goto exit; | ||
412 | } | ||
413 | |||
414 | GCDBG(GCZONE_TEMP, "buffdesc @ 0x%08X\n", | ||
415 | gccontext->tmpbuffdesc); | ||
416 | GCDBG(GCZONE_TEMP, "allocated @ 0x%08X\n", | ||
417 | gccontext->tmpbuff); | ||
418 | GCDBG(GCZONE_TEMP, "size = %d\n", | ||
419 | size); | ||
420 | |||
421 | /* Map the buffer explicitly. */ | ||
422 | bverror = bv_map(gccontext->tmpbuffdesc); | ||
423 | if (bverror != BVERR_NONE) { | ||
424 | bvbltparams->errdesc = gccontext->bverrorstr; | ||
425 | goto exit; | ||
426 | } | ||
427 | } | ||
428 | |||
429 | /* Success. */ | ||
430 | bverror = BVERR_NONE; | ||
431 | |||
432 | exit: | ||
433 | GCEXIT(GCZONE_TEMP); | ||
434 | return bverror; | ||
435 | } | ||
436 | |||
437 | enum bverror free_temp(bool schedule) | ||
438 | { | ||
439 | enum bverror bverror; | ||
440 | struct gccontext *gccontext = get_context(); | ||
441 | struct gccallbackinfo *gccallbackinfo; | ||
442 | struct gcicallbackarm gcicallbackarm; | ||
443 | |||
444 | /* Is the buffer allocated? */ | ||
445 | if (gccontext->tmpbuffdesc == NULL) { | ||
446 | bverror = BVERR_NONE; | ||
447 | goto exit; | ||
448 | } | ||
449 | |||
450 | /* Unmap the buffer. */ | ||
451 | bverror = bv_unmap(gccontext->tmpbuffdesc); | ||
452 | if (bverror != BVERR_NONE) | ||
453 | goto exit; | ||
454 | |||
455 | /* Cannot be mapped. */ | ||
456 | if (gccontext->tmpbuffdesc->map != NULL) { | ||
457 | BVSETERROR(BVERR_OOM, "temporary buffer is still mapped"); | ||
458 | goto exit; | ||
459 | } | ||
460 | |||
461 | /* Free the buffer. */ | ||
462 | if (schedule) { | ||
463 | bverror = get_callbackinfo(&gccallbackinfo); | ||
464 | if (bverror != BVERR_NONE) { | ||
465 | BVSETERROR(BVERR_OOM, | ||
466 | "callback allocation failed"); | ||
467 | goto exit; | ||
468 | } | ||
469 | |||
470 | gccallbackinfo->info.freesurface.desc = gccontext->tmpbuffdesc; | ||
471 | gccallbackinfo->info.freesurface.ptr = gccontext->tmpbuff; | ||
472 | gcicallbackarm.callback = callbackfreesurface; | ||
473 | gcicallbackarm.callbackparam = gccallbackinfo; | ||
474 | |||
475 | /* Schedule to free the buffer. */ | ||
476 | gc_callback_wrapper(&gcicallbackarm); | ||
477 | |||
478 | /* Error? */ | ||
479 | if (gcicallbackarm.gcerror != GCERR_NONE) { | ||
480 | BVSETERROR(BVERR_OOM, "unable to schedule callback"); | ||
481 | goto exit; | ||
482 | } | ||
483 | } else { | ||
484 | /* Free the buffer immediately. */ | ||
485 | free_surface(gccontext->tmpbuffdesc, gccontext->tmpbuff); | ||
486 | } | ||
487 | |||
488 | /* Reset the buffer descriptor. */ | ||
489 | gccontext->tmpbuffdesc = NULL; | ||
490 | gccontext->tmpbuff = NULL; | ||
491 | |||
492 | exit: | ||
493 | return bverror; | ||
494 | } | ||
495 | |||
496 | |||
497 | /******************************************************************************* | ||
498 | * Program the destination. | ||
499 | */ | ||
500 | |||
501 | enum bverror set_dst(struct bvbltparams *bvbltparams, | ||
502 | struct gcbatch *batch, | ||
503 | struct bvbuffmap *dstmap) | ||
504 | { | ||
505 | enum bverror bverror = BVERR_NONE; | ||
506 | struct gcsurface *dstinfo; | ||
507 | struct gcmodst *gcmodst; | ||
508 | |||
509 | GCENTER(GCZONE_DEST); | ||
510 | |||
511 | /* Get a shortcut to the destination surface descriptor. */ | ||
512 | dstinfo = &batch->dstinfo; | ||
513 | |||
514 | /* Did destination surface change? */ | ||
515 | if (dstinfo->surfdirty) { | ||
516 | /* Allocate command buffer. */ | ||
517 | bverror = claim_buffer(bvbltparams, batch, | ||
518 | sizeof(struct gcmodst), | ||
519 | (void **) &gcmodst); | ||
520 | if (bverror != BVERR_NONE) | ||
521 | goto exit; | ||
522 | |||
523 | /* Add the address fixup. */ | ||
524 | add_fixup(bvbltparams, batch, &gcmodst->address, | ||
525 | dstinfo->bytealign1); | ||
526 | |||
527 | /* Set surface parameters. */ | ||
528 | gcmodst->config_ldst = gcmodst_config_ldst; | ||
529 | gcmodst->address = GET_MAP_HANDLE(dstmap); | ||
530 | gcmodst->stride = dstinfo->stride1; | ||
531 | |||
532 | /* Set surface width and height. */ | ||
533 | gcmodst->rotation.raw = 0; | ||
534 | gcmodst->rotation.reg.surf_width = dstinfo->physwidth; | ||
535 | gcmodst->rotationheight_ldst = gcmodst_rotationheight_ldst; | ||
536 | gcmodst->rotationheight.raw = 0; | ||
537 | gcmodst->rotationheight.reg.height = dstinfo->physheight; | ||
538 | |||
539 | /* Disable hardware clipping. */ | ||
540 | gcmodst->clip_ldst = gcmodst_clip_ldst; | ||
541 | gcmodst->cliplt.raw = 0; | ||
542 | gcmodst->cliprb.raw = 0; | ||
543 | gcmodst->cliprb.reg.right = GC_CLIP_RESET_RIGHT; | ||
544 | gcmodst->cliprb.reg.bottom = GC_CLIP_RESET_BOTTOM; | ||
545 | } | ||
546 | |||
547 | exit: | ||
548 | GCEXITARG(GCZONE_DEST, "bv%s = %d\n", | ||
549 | (bverror == BVERR_NONE) ? "result" : "error", bverror); | ||
550 | return bverror; | ||
551 | } | ||
552 | |||
553 | |||
554 | /******************************************************************************* | ||
555 | * Program blending. | ||
556 | */ | ||
557 | |||
558 | enum bverror set_blending(struct bvbltparams *bvbltparams, | ||
559 | struct gcbatch *batch, | ||
560 | struct gcsurface *srcinfo) | ||
561 | { | ||
562 | enum bverror bverror = BVERR_NONE; | ||
563 | struct gcmoalphaoff *gcmoalphaoff; | ||
564 | struct gcmoalpha *gcmoalpha; | ||
565 | struct gcmoglobal *gcmoglobal; | ||
566 | struct gcalpha *gca; | ||
567 | |||
568 | GCENTER(GCZONE_BLEND); | ||
569 | |||
570 | gca = srcinfo->gca; | ||
571 | if (gca == NULL) { | ||
572 | bverror = claim_buffer(bvbltparams, batch, | ||
573 | sizeof(struct gcmoalphaoff), | ||
574 | (void **) &gcmoalphaoff); | ||
575 | if (bverror != BVERR_NONE) | ||
576 | goto exit; | ||
577 | |||
578 | gcmoalphaoff->control_ldst = gcmoalphaoff_control_ldst[0]; | ||
579 | gcmoalphaoff->control.reg = gcregalpha_off; | ||
580 | |||
581 | GCDBG(GCZONE_BLEND, "blending disabled.\n"); | ||
582 | } else { | ||
583 | bverror = claim_buffer(bvbltparams, batch, | ||
584 | sizeof(struct gcmoalpha), | ||
585 | (void **) &gcmoalpha); | ||
586 | if (bverror != BVERR_NONE) | ||
587 | goto exit; | ||
588 | |||
589 | gcmoalpha->config_ldst = gcmoalpha_config_ldst; | ||
590 | gcmoalpha->control.reg = gcregalpha_on; | ||
591 | |||
592 | gcmoalpha->mode.raw = 0; | ||
593 | gcmoalpha->mode.reg.src_global_alpha_mode | ||
594 | = srcinfo->srcglobalmode; | ||
595 | gcmoalpha->mode.reg.dst_global_alpha_mode | ||
596 | = srcinfo->dstglobalmode; | ||
597 | |||
598 | gcmoalpha->mode.reg.src_blend | ||
599 | = gca->srcconfig->factor_mode; | ||
600 | gcmoalpha->mode.reg.src_color_reverse | ||
601 | = gca->srcconfig->color_reverse; | ||
602 | |||
603 | gcmoalpha->mode.reg.dst_blend | ||
604 | = gca->dstconfig->factor_mode; | ||
605 | gcmoalpha->mode.reg.dst_color_reverse | ||
606 | = gca->dstconfig->color_reverse; | ||
607 | |||
608 | GCDBG(GCZONE_BLEND, "dst blend:\n"); | ||
609 | GCDBG(GCZONE_BLEND, " factor = %d\n", | ||
610 | gcmoalpha->mode.reg.dst_blend); | ||
611 | GCDBG(GCZONE_BLEND, " inverse = %d\n", | ||
612 | gcmoalpha->mode.reg.dst_color_reverse); | ||
613 | |||
614 | GCDBG(GCZONE_BLEND, "src blend:\n"); | ||
615 | GCDBG(GCZONE_BLEND, " factor = %d\n", | ||
616 | gcmoalpha->mode.reg.src_blend); | ||
617 | GCDBG(GCZONE_BLEND, " inverse = %d\n", | ||
618 | gcmoalpha->mode.reg.src_color_reverse); | ||
619 | } | ||
620 | |||
621 | if (srcinfo->globalcolorenable) { | ||
622 | bverror = claim_buffer(bvbltparams, batch, | ||
623 | sizeof(struct gcmoglobal), | ||
624 | (void **) &gcmoglobal); | ||
625 | if (bverror != BVERR_NONE) | ||
626 | goto exit; | ||
627 | |||
628 | gcmoglobal->color_ldst = gcmoglobal_color_ldst; | ||
629 | gcmoglobal->srcglobal.raw = srcinfo->globalcolor; | ||
630 | gcmoglobal->dstglobal.raw = srcinfo->globalcolor; | ||
631 | } | ||
632 | |||
633 | exit: | ||
634 | GCEXITARG(GCZONE_BLEND, "bv%s = %d\n", | ||
635 | (bverror == BVERR_NONE) ? "result" : "error", bverror); | ||
636 | return bverror; | ||
637 | } | ||
638 | |||
639 | enum bverror set_blending_index(struct bvbltparams *bvbltparams, | ||
640 | struct gcbatch *batch, | ||
641 | struct gcsurface *srcinfo, | ||
642 | unsigned int index) | ||
643 | { | ||
644 | enum bverror bverror = BVERR_NONE; | ||
645 | struct gcmoalphaoff *gcmoalphaoff; | ||
646 | struct gcmoxsrcalpha *gcmoxsrcalpha; | ||
647 | struct gcmoxsrcglobal *gcmoxsrcglobal; | ||
648 | struct gcalpha *gca; | ||
649 | |||
650 | GCENTER(GCZONE_BLEND); | ||
651 | |||
652 | gca = srcinfo->gca; | ||
653 | if (gca == NULL) { | ||
654 | bverror = claim_buffer(bvbltparams, batch, | ||
655 | sizeof(struct gcmoalphaoff), | ||
656 | (void **) &gcmoalphaoff); | ||
657 | if (bverror != BVERR_NONE) | ||
658 | goto exit; | ||
659 | |||
660 | gcmoalphaoff->control_ldst = gcmoalphaoff_control_ldst[index]; | ||
661 | gcmoalphaoff->control.reg = gcregalpha_off; | ||
662 | |||
663 | GCDBG(GCZONE_BLEND, "blending disabled.\n"); | ||
664 | } else { | ||
665 | bverror = claim_buffer(bvbltparams, batch, | ||
666 | sizeof(struct gcmoxsrcalpha), | ||
667 | (void **) &gcmoxsrcalpha); | ||
668 | if (bverror != BVERR_NONE) | ||
669 | goto exit; | ||
670 | |||
671 | gcmoxsrcalpha->control_ldst = gcmoxsrcalpha_control_ldst[index]; | ||
672 | gcmoxsrcalpha->control.reg = gcregalpha_on; | ||
673 | |||
674 | gcmoxsrcalpha->mode_ldst = gcmoxsrcalpha_mode_ldst[index]; | ||
675 | gcmoxsrcalpha->mode.raw = 0; | ||
676 | gcmoxsrcalpha->mode.reg.src_global_alpha_mode | ||
677 | = srcinfo->srcglobalmode; | ||
678 | gcmoxsrcalpha->mode.reg.dst_global_alpha_mode | ||
679 | = srcinfo->dstglobalmode; | ||
680 | |||
681 | gcmoxsrcalpha->mode.reg.src_blend | ||
682 | = gca->srcconfig->factor_mode; | ||
683 | gcmoxsrcalpha->mode.reg.src_color_reverse | ||
684 | = gca->srcconfig->color_reverse; | ||
685 | |||
686 | gcmoxsrcalpha->mode.reg.dst_blend | ||
687 | = gca->dstconfig->factor_mode; | ||
688 | gcmoxsrcalpha->mode.reg.dst_color_reverse | ||
689 | = gca->dstconfig->color_reverse; | ||
690 | |||
691 | GCDBG(GCZONE_BLEND, "dst blend:\n"); | ||
692 | GCDBG(GCZONE_BLEND, " factor = %d\n", | ||
693 | gcmoxsrcalpha->mode.reg.dst_blend); | ||
694 | GCDBG(GCZONE_BLEND, " inverse = %d\n", | ||
695 | gcmoxsrcalpha->mode.reg.dst_color_reverse); | ||
696 | |||
697 | GCDBG(GCZONE_BLEND, "src blend:\n"); | ||
698 | GCDBG(GCZONE_BLEND, " factor = %d\n", | ||
699 | gcmoxsrcalpha->mode.reg.src_blend); | ||
700 | GCDBG(GCZONE_BLEND, " inverse = %d\n", | ||
701 | gcmoxsrcalpha->mode.reg.src_color_reverse); | ||
702 | } | ||
703 | |||
704 | if (srcinfo->globalcolorenable) { | ||
705 | bverror = claim_buffer(bvbltparams, batch, | ||
706 | sizeof(struct gcmoxsrcglobal), | ||
707 | (void **) &gcmoxsrcglobal); | ||
708 | if (bverror != BVERR_NONE) | ||
709 | goto exit; | ||
710 | |||
711 | gcmoxsrcglobal->srcglobal_ldst | ||
712 | = gcmoxsrcglobal_srcglobal_ldst[index]; | ||
713 | gcmoxsrcglobal->srcglobal.raw = srcinfo->globalcolor; | ||
714 | |||
715 | gcmoxsrcglobal->dstglobal_ldst | ||
716 | = gcmoxsrcglobal_dstglobal_ldst[index]; | ||
717 | gcmoxsrcglobal->dstglobal.raw = srcinfo->globalcolor; | ||
718 | } | ||
719 | |||
720 | exit: | ||
721 | GCEXITARG(GCZONE_BLEND, "bv%s = %d\n", | ||
722 | (bverror == BVERR_NONE) ? "result" : "error", bverror); | ||
723 | return bverror; | ||
724 | } | ||
725 | |||
726 | /******************************************************************************* | ||
727 | * Program YUV source. | ||
728 | */ | ||
729 | |||
730 | void set_computeyuv(struct gcsurface *srcinfo, int x, int y) | ||
731 | { | ||
732 | int pixalign, bytealign; | ||
733 | unsigned int height1, size1; | ||
734 | unsigned int height2, size2; | ||
735 | unsigned int origin; | ||
736 | int ssX, ssY; | ||
737 | |||
738 | GCENTER(GCZONE_SRC); | ||
739 | |||
740 | /* Compute base address alignment. */ | ||
741 | pixalign = get_pixel_offset(srcinfo, 0); | ||
742 | bytealign = (pixalign * (int) srcinfo->format.bitspp) / 8; | ||
743 | |||
744 | /* Determine the physical height of the first plane. */ | ||
745 | height1 = ((srcinfo->angle % 2) == 0) | ||
746 | ? srcinfo->height | ||
747 | : srcinfo->width; | ||
748 | |||
749 | /* Determine the size of the first plane. */ | ||
750 | size1 = srcinfo->stride1 * height1; | ||
751 | |||
752 | /* Determine the stride of the second plane. */ | ||
753 | srcinfo->stride2 = srcinfo->stride1 | ||
754 | / srcinfo->format.cs.yuv.xsample; | ||
755 | |||
756 | /* Determine subsample pixel position. */ | ||
757 | ssX = x / srcinfo->format.cs.yuv.xsample; | ||
758 | ssY = y / srcinfo->format.cs.yuv.ysample; | ||
759 | |||
760 | switch (srcinfo->format.cs.yuv.planecount) { | ||
761 | case 2: | ||
762 | /* U and V are interleaved in one plane. */ | ||
763 | ssX *= 2; | ||
764 | srcinfo->stride2 *= 2; | ||
765 | |||
766 | /* Determnine the origin offset. */ | ||
767 | origin = ssY * srcinfo->stride2 + ssX; | ||
768 | |||
769 | /* Compute the alignment of the second plane. */ | ||
770 | srcinfo->bytealign2 = bytealign + size1 + origin; | ||
771 | |||
772 | GCDBG(GCZONE_SRC, "plane2 offset (bytes) = 0x%08X\n", | ||
773 | srcinfo->bytealign2); | ||
774 | GCDBG(GCZONE_SRC, "plane2 stride = %d\n", | ||
775 | srcinfo->stride2); | ||
776 | break; | ||
777 | |||
778 | case 3: | ||
779 | /* Determine the physical height of the U/V planes. */ | ||
780 | height2 = height1 / srcinfo->format.cs.yuv.ysample; | ||
781 | |||
782 | /* Determine the size of the U/V planes. */ | ||
783 | size2 = srcinfo->stride2 * height2; | ||
784 | |||
785 | /* Determnine the origin offset. */ | ||
786 | origin = ssY * srcinfo->stride2 + ssX; | ||
787 | |||
788 | /* Compute the alignment of the U/V planes. */ | ||
789 | srcinfo->bytealign2 = bytealign + size1 + origin; | ||
790 | srcinfo->bytealign3 = bytealign + size1 + size2 + origin; | ||
791 | |||
792 | /* Determine the stride of the U/V planes. */ | ||
793 | srcinfo->stride3 = srcinfo->stride2; | ||
794 | |||
795 | GCDBG(GCZONE_SRC, "plane2 offset (bytes) = 0x%08X\n", | ||
796 | srcinfo->bytealign2); | ||
797 | GCDBG(GCZONE_SRC, "plane2 stride = %d\n", | ||
798 | srcinfo->stride2); | ||
799 | GCDBG(GCZONE_SRC, "plane3 offset (bytes) = 0x%08X\n", | ||
800 | srcinfo->bytealign3); | ||
801 | GCDBG(GCZONE_SRC, "plane3 stride = %d\n", | ||
802 | srcinfo->stride3); | ||
803 | break; | ||
804 | } | ||
805 | |||
806 | GCEXIT(GCZONE_SRC); | ||
807 | } | ||
808 | |||
809 | enum bverror set_yuvsrc(struct bvbltparams *bvbltparams, | ||
810 | struct gcbatch *batch, | ||
811 | struct gcsurface *srcinfo, | ||
812 | struct bvbuffmap *srcmap) | ||
813 | { | ||
814 | enum bverror bverror = BVERR_NONE; | ||
815 | struct gcmoyuv1 *gcmoyuv1; | ||
816 | struct gcmoyuv2 *gcmoyuv2; | ||
817 | struct gcmoyuv3 *gcmoyuv3; | ||
818 | |||
819 | GCENTER(GCZONE_SRC); | ||
820 | |||
821 | GCDBG(GCZONE_SRC, "plane count %d.\n", | ||
822 | srcinfo->format.cs.yuv.planecount); | ||
823 | |||
824 | switch (srcinfo->format.cs.yuv.planecount) { | ||
825 | case 1: | ||
826 | bverror = claim_buffer(bvbltparams, batch, | ||
827 | sizeof(struct gcmoyuv1), | ||
828 | (void **) &gcmoyuv1); | ||
829 | if (bverror != BVERR_NONE) | ||
830 | goto exit; | ||
831 | |||
832 | /* Set YUV parameters. */ | ||
833 | gcmoyuv1->pectrl_ldst = gcmoyuv_pectrl_ldst; | ||
834 | gcmoyuv1->pectrl.raw = 0; | ||
835 | gcmoyuv1->pectrl.reg.standard | ||
836 | = srcinfo->format.cs.yuv.std; | ||
837 | gcmoyuv1->pectrl.reg.swizzle | ||
838 | = srcinfo->format.swizzle; | ||
839 | gcmoyuv1->pectrl.reg.convert | ||
840 | = GCREG_PE_CONTROL_YUVRGB_DISABLED; | ||
841 | break; | ||
842 | |||
843 | case 2: | ||
844 | bverror = claim_buffer(bvbltparams, batch, | ||
845 | sizeof(struct gcmoyuv2), | ||
846 | (void **) &gcmoyuv2); | ||
847 | if (bverror != BVERR_NONE) | ||
848 | goto exit; | ||
849 | |||
850 | /* Set YUV parameters. */ | ||
851 | gcmoyuv2->pectrl_ldst = gcmoyuv_pectrl_ldst; | ||
852 | gcmoyuv2->pectrl.raw = 0; | ||
853 | gcmoyuv2->pectrl.reg.standard | ||
854 | = srcinfo->format.cs.yuv.std; | ||
855 | gcmoyuv2->pectrl.reg.swizzle | ||
856 | = srcinfo->format.swizzle; | ||
857 | gcmoyuv2->pectrl.reg.convert | ||
858 | = GCREG_PE_CONTROL_YUVRGB_DISABLED; | ||
859 | |||
860 | /* Program U/V plane. */ | ||
861 | add_fixup(bvbltparams, batch, &gcmoyuv2->uplaneaddress, | ||
862 | srcinfo->bytealign2); | ||
863 | gcmoyuv2->plane_ldst = gcmoyuv2_plane_ldst; | ||
864 | gcmoyuv2->uplaneaddress = GET_MAP_HANDLE(srcmap); | ||
865 | gcmoyuv2->uplanestride = srcinfo->stride2; | ||
866 | break; | ||
867 | |||
868 | case 3: | ||
869 | bverror = claim_buffer(bvbltparams, batch, | ||
870 | sizeof(struct gcmoyuv3), | ||
871 | (void **) &gcmoyuv3); | ||
872 | if (bverror != BVERR_NONE) | ||
873 | goto exit; | ||
874 | |||
875 | /* Set YUV parameters. */ | ||
876 | gcmoyuv3->pectrl_ldst = gcmoyuv_pectrl_ldst; | ||
877 | gcmoyuv3->pectrl.raw = 0; | ||
878 | gcmoyuv3->pectrl.reg.standard | ||
879 | = srcinfo->format.cs.yuv.std; | ||
880 | gcmoyuv3->pectrl.reg.swizzle | ||
881 | = srcinfo->format.swizzle; | ||
882 | gcmoyuv3->pectrl.reg.convert | ||
883 | = GCREG_PE_CONTROL_YUVRGB_DISABLED; | ||
884 | |||
885 | /* Program U/V planes. */ | ||
886 | add_fixup(bvbltparams, batch, &gcmoyuv3->uplaneaddress, | ||
887 | srcinfo->bytealign2); | ||
888 | add_fixup(bvbltparams, batch, &gcmoyuv3->vplaneaddress, | ||
889 | srcinfo->bytealign3); | ||
890 | gcmoyuv3->plane_ldst = gcmoyuv3_plane_ldst; | ||
891 | gcmoyuv3->uplaneaddress = GET_MAP_HANDLE(srcmap); | ||
892 | gcmoyuv3->uplanestride = srcinfo->stride2; | ||
893 | gcmoyuv3->vplaneaddress = GET_MAP_HANDLE(srcmap); | ||
894 | gcmoyuv3->vplanestride = srcinfo->stride3; | ||
895 | break; | ||
896 | |||
897 | default: | ||
898 | GCERR("invlaid plane count %d.\n", | ||
899 | srcinfo->format.cs.yuv.planecount); | ||
900 | } | ||
901 | |||
902 | exit: | ||
903 | GCEXITARG(GCZONE_SRC, "bv%s = %d\n", | ||
904 | (bverror == BVERR_NONE) ? "result" : "error", bverror); | ||
905 | return bverror; | ||
906 | } | ||
907 | |||
908 | enum bverror set_yuvsrc_index(struct bvbltparams *bvbltparams, | ||
909 | struct gcbatch *batch, | ||
910 | struct gcsurface *srcinfo, | ||
911 | struct bvbuffmap *srcmap, | ||
912 | unsigned int index) | ||
913 | { | ||
914 | enum bverror bverror = BVERR_NONE; | ||
915 | struct gcmoxsrcyuv1 *gcmoxsrcyuv1; | ||
916 | struct gcmoxsrcyuv2 *gcmoxsrcyuv2; | ||
917 | struct gcmoxsrcyuv3 *gcmoxsrcyuv3; | ||
918 | |||
919 | GCENTER(GCZONE_SRC); | ||
920 | |||
921 | GCDBG(GCZONE_SRC, "plane count %d.\n", | ||
922 | srcinfo->format.cs.yuv.planecount); | ||
923 | |||
924 | switch (srcinfo->format.cs.yuv.planecount) { | ||
925 | case 1: | ||
926 | bverror = claim_buffer(bvbltparams, batch, | ||
927 | sizeof(struct gcmoxsrcyuv1), | ||
928 | (void **) &gcmoxsrcyuv1); | ||
929 | if (bverror != BVERR_NONE) | ||
930 | goto exit; | ||
931 | |||
932 | /* Set YUV parameters. */ | ||
933 | gcmoxsrcyuv1->pectrl_ldst | ||
934 | = gcmoxsrcyuv_pectrl_ldst[index]; | ||
935 | gcmoxsrcyuv1->pectrl.raw = 0; | ||
936 | gcmoxsrcyuv1->pectrl.reg.standard | ||
937 | = srcinfo->format.cs.yuv.std; | ||
938 | gcmoxsrcyuv1->pectrl.reg.swizzle | ||
939 | = srcinfo->format.swizzle; | ||
940 | gcmoxsrcyuv1->pectrl.reg.convert | ||
941 | = GCREG_PE_CONTROL_YUVRGB_DISABLED; | ||
942 | break; | ||
943 | |||
944 | case 2: | ||
945 | bverror = claim_buffer(bvbltparams, batch, | ||
946 | sizeof(struct gcmoxsrcyuv2), | ||
947 | (void **) &gcmoxsrcyuv2); | ||
948 | if (bverror != BVERR_NONE) | ||
949 | goto exit; | ||
950 | |||
951 | /* Set YUV parameters. */ | ||
952 | gcmoxsrcyuv2->pectrl_ldst | ||
953 | = gcmoxsrcyuv_pectrl_ldst[index]; | ||
954 | gcmoxsrcyuv2->pectrl.raw = 0; | ||
955 | gcmoxsrcyuv2->pectrl.reg.standard | ||
956 | = srcinfo->format.cs.yuv.std; | ||
957 | gcmoxsrcyuv2->pectrl.reg.swizzle | ||
958 | = srcinfo->format.swizzle; | ||
959 | gcmoxsrcyuv2->pectrl.reg.convert | ||
960 | = GCREG_PE_CONTROL_YUVRGB_DISABLED; | ||
961 | |||
962 | /* Program U/V plane. */ | ||
963 | add_fixup(bvbltparams, batch, &gcmoxsrcyuv2->uplaneaddress, | ||
964 | srcinfo->bytealign2); | ||
965 | gcmoxsrcyuv2->uplaneaddress_ldst | ||
966 | = gcmoxsrcyuv_uplaneaddress_ldst[index]; | ||
967 | gcmoxsrcyuv2->uplaneaddress = GET_MAP_HANDLE(srcmap); | ||
968 | gcmoxsrcyuv2->uplanestride_ldst | ||
969 | = gcmoxsrcyuv_uplanestride_ldst[index]; | ||
970 | gcmoxsrcyuv2->uplanestride = srcinfo->stride2; | ||
971 | break; | ||
972 | |||
973 | case 3: | ||
974 | bverror = claim_buffer(bvbltparams, batch, | ||
975 | sizeof(struct gcmoxsrcyuv3), | ||
976 | (void **) &gcmoxsrcyuv3); | ||
977 | if (bverror != BVERR_NONE) | ||
978 | goto exit; | ||
979 | |||
980 | /* Set YUV parameters. */ | ||
981 | gcmoxsrcyuv3->pectrl_ldst | ||
982 | = gcmoxsrcyuv_pectrl_ldst[index]; | ||
983 | gcmoxsrcyuv3->pectrl.raw = 0; | ||
984 | gcmoxsrcyuv3->pectrl.reg.standard | ||
985 | = srcinfo->format.cs.yuv.std; | ||
986 | gcmoxsrcyuv3->pectrl.reg.swizzle | ||
987 | = srcinfo->format.swizzle; | ||
988 | gcmoxsrcyuv3->pectrl.reg.convert | ||
989 | = GCREG_PE_CONTROL_YUVRGB_DISABLED; | ||
990 | |||
991 | /* Program U/V planes. */ | ||
992 | add_fixup(bvbltparams, batch, &gcmoxsrcyuv3->uplaneaddress, | ||
993 | srcinfo->bytealign2); | ||
994 | add_fixup(bvbltparams, batch, &gcmoxsrcyuv3->vplaneaddress, | ||
995 | srcinfo->bytealign3); | ||
996 | gcmoxsrcyuv3->uplaneaddress_ldst | ||
997 | = gcmoxsrcyuv_uplaneaddress_ldst[index]; | ||
998 | gcmoxsrcyuv3->uplaneaddress = GET_MAP_HANDLE(srcmap); | ||
999 | gcmoxsrcyuv3->uplanestride_ldst | ||
1000 | = gcmoxsrcyuv_uplanestride_ldst[index]; | ||
1001 | gcmoxsrcyuv3->uplanestride = srcinfo->stride2; | ||
1002 | gcmoxsrcyuv3->vplaneaddress_ldst | ||
1003 | = gcmoxsrcyuv_vplaneaddress_ldst[index]; | ||
1004 | gcmoxsrcyuv3->vplaneaddress = GET_MAP_HANDLE(srcmap); | ||
1005 | gcmoxsrcyuv3->vplanestride_ldst | ||
1006 | = gcmoxsrcyuv_vplanestride_ldst[index]; | ||
1007 | gcmoxsrcyuv3->vplanestride = srcinfo->stride3; | ||
1008 | break; | ||
1009 | |||
1010 | default: | ||
1011 | GCERR("invlaid plane count %d.\n", | ||
1012 | srcinfo->format.cs.yuv.planecount); | ||
1013 | } | ||
1014 | |||
1015 | exit: | ||
1016 | GCEXITARG(GCZONE_SRC, "bv%s = %d\n", | ||
1017 | (bverror == BVERR_NONE) ? "result" : "error", bverror); | ||
1018 | return bverror; | ||
1019 | } | ||
1020 | |||
1021 | |||
1022 | /******************************************************************************* | ||
1023 | * Surface compare and validation. | ||
1024 | */ | ||
1025 | |||
1026 | static inline bool equal_rects(struct bvrect *rect1, struct bvrect *rect2) | ||
1027 | { | ||
1028 | if (rect1->left != rect2->left) | ||
1029 | return false; | ||
1030 | |||
1031 | if (rect1->top != rect2->top) | ||
1032 | return false; | ||
1033 | |||
1034 | if (rect1->width != rect2->width) | ||
1035 | return false; | ||
1036 | |||
1037 | if (rect1->height != rect2->height) | ||
1038 | return false; | ||
1039 | |||
1040 | return true; | ||
1041 | } | ||
1042 | |||
1043 | /* The function verifies whether the two buffer descriptors and rectangles | ||
1044 | define the same physical area. */ | ||
1045 | static bool same_phys_area(struct bvbuffdesc *surf1, struct bvrect *rect1, | ||
1046 | struct bvbuffdesc *surf2, struct bvrect *rect2) | ||
1047 | { | ||
1048 | struct bvphysdesc *physdesc1; | ||
1049 | struct bvphysdesc *physdesc2; | ||
1050 | |||
1051 | /* If pointers are the same, things are much easier. */ | ||
1052 | if (surf1 == surf2) | ||
1053 | /* Compare the rectangles. For simplicity we don't consider | ||
1054 | cases with partially overlapping rectangles at this time. */ | ||
1055 | return equal_rects(rect1, rect2); | ||
1056 | |||
1057 | /* Assume diffrent areas if the types are different. */ | ||
1058 | if (surf1->auxtype != surf2->auxtype) | ||
1059 | return false; | ||
1060 | |||
1061 | if (surf1->auxtype == BVAT_PHYSDESC) { | ||
1062 | physdesc1 = (struct bvphysdesc *) surf1->auxptr; | ||
1063 | physdesc2 = (struct bvphysdesc *) surf2->auxptr; | ||
1064 | |||
1065 | /* Same physical descriptor? */ | ||
1066 | if (physdesc1 == physdesc2) | ||
1067 | return equal_rects(rect1, rect2); | ||
1068 | |||
1069 | /* Same page array? */ | ||
1070 | if (physdesc1->pagearray == physdesc2->pagearray) | ||
1071 | return equal_rects(rect1, rect2); | ||
1072 | |||
1073 | /* Pageoffsets must match since different buffers | ||
1074 | * can share the same first page (eg nv12). | ||
1075 | */ | ||
1076 | if (physdesc1->pageoffset != physdesc2->pageoffset) | ||
1077 | return false; | ||
1078 | |||
1079 | /* Assume the same surface if first pages match. */ | ||
1080 | if (physdesc1->pagearray[0] == physdesc2->pagearray[0]) | ||
1081 | return equal_rects(rect1, rect2); | ||
1082 | |||
1083 | } else { | ||
1084 | if (surf1->virtaddr == surf2->virtaddr) | ||
1085 | return equal_rects(rect1, rect2); | ||
1086 | } | ||
1087 | |||
1088 | return false; | ||
1089 | } | ||
1090 | |||
1091 | static int verify_surface(unsigned int tile, | ||
1092 | union bvinbuff *surf, | ||
1093 | struct bvsurfgeom *geom) | ||
1094 | { | ||
1095 | if (tile) { | ||
1096 | if (surf->tileparams == NULL) | ||
1097 | return GCBVERR_TILE; | ||
1098 | |||
1099 | if (surf->tileparams->structsize < | ||
1100 | STRUCTSIZE(surf->tileparams, srcheight)) | ||
1101 | return GCBVERR_TILE_VERS; | ||
1102 | |||
1103 | /* FIXME/TODO */ | ||
1104 | return GCBVERR_TILE; | ||
1105 | } else { | ||
1106 | if (surf->desc == NULL) | ||
1107 | return GCBVERR_DESC; | ||
1108 | |||
1109 | if (surf->desc->structsize < STRUCTSIZE(surf->desc, map)) | ||
1110 | return GCBVERR_DESC_VERS; | ||
1111 | } | ||
1112 | |||
1113 | if (geom == NULL) | ||
1114 | return GCBVERR_GEOM; | ||
1115 | |||
1116 | if (geom->structsize < STRUCTSIZE(geom, palette)) | ||
1117 | return GCBVERR_GEOM_VERS; | ||
1118 | |||
1119 | /* Validation successful. */ | ||
1120 | return -1; | ||
1121 | } | ||
1122 | |||
1123 | |||
1124 | /******************************************************************************* | ||
1125 | * Operation. | ||
1126 | */ | ||
1127 | |||
1128 | static enum bverror do_op(struct bvbltparams *bvbltparams, | ||
1129 | struct gcbatch *gcbatch, | ||
1130 | int srccount, | ||
1131 | struct gcsurface *srcinfo, | ||
1132 | struct gcalpha *gca) | ||
1133 | { | ||
1134 | enum bverror bverror = BVERR_NONE; | ||
1135 | struct gcsurface *dstinfo; | ||
1136 | int sw, sh, dw, dh; | ||
1137 | |||
1138 | GCDBG(GCZONE_BLIT, "processing source %d.\n", srcinfo->index + 1); | ||
1139 | |||
1140 | if (gca == NULL) { | ||
1141 | GCDBG(GCZONE_BLIT, | ||
1142 | " blending disabled.\n"); | ||
1143 | |||
1144 | srcinfo->gca = NULL; | ||
1145 | srcinfo->globalcolorenable = false; | ||
1146 | srcinfo->srcglobalpremul = GCREG_SRC_GLOBAL_PREMULTIPLY_DISABLE; | ||
1147 | srcinfo->srcglobalmode = GCREG_GLOBAL_ALPHA_MODE_NORMAL; | ||
1148 | srcinfo->dstglobalmode = GCREG_GLOBAL_ALPHA_MODE_NORMAL; | ||
1149 | } else { | ||
1150 | if (srcinfo->index == 0) { | ||
1151 | /* First source. */ | ||
1152 | |||
1153 | if (srccount == 1) { | ||
1154 | /* Only one source. */ | ||
1155 | GCDBG(GCZONE_BLIT, | ||
1156 | " enabling blending.\n"); | ||
1157 | |||
1158 | srcinfo->gca = gca; | ||
1159 | gca->srcconfig = gca->k1; | ||
1160 | gca->dstconfig = gca->k2; | ||
1161 | |||
1162 | } else { | ||
1163 | /* Two sources. */ | ||
1164 | GCDBG(GCZONE_BLIT, | ||
1165 | " disabling blending for src1.\n"); | ||
1166 | |||
1167 | srcinfo->gca = NULL; | ||
1168 | } | ||
1169 | |||
1170 | if (gca->globalcolorenable) { | ||
1171 | srcinfo->globalcolorenable = true; | ||
1172 | srcinfo->globalcolor = gca->globalcolor; | ||
1173 | srcinfo->srcglobalpremul | ||
1174 | = GCREG_SRC_GLOBAL_PREMULTIPLY_ALPHA; | ||
1175 | srcinfo->srcglobalmode | ||
1176 | = GCREG_GLOBAL_ALPHA_MODE_SCALED; | ||
1177 | srcinfo->dstglobalmode | ||
1178 | = GCREG_GLOBAL_ALPHA_MODE_NORMAL; | ||
1179 | } else { | ||
1180 | srcinfo->globalcolorenable = false; | ||
1181 | srcinfo->srcglobalpremul | ||
1182 | = GCREG_SRC_GLOBAL_PREMULTIPLY_DISABLE; | ||
1183 | srcinfo->srcglobalmode | ||
1184 | = GCREG_GLOBAL_ALPHA_MODE_NORMAL; | ||
1185 | srcinfo->dstglobalmode | ||
1186 | = GCREG_GLOBAL_ALPHA_MODE_NORMAL; | ||
1187 | } | ||
1188 | } else { | ||
1189 | /* Second source. */ | ||
1190 | GCDBG(GCZONE_BLIT, | ||
1191 | " enabling blending.\n"); | ||
1192 | |||
1193 | srcinfo->gca = gca; | ||
1194 | gca->srcconfig = gca->k2; | ||
1195 | gca->dstconfig = gca->k1; | ||
1196 | |||
1197 | if (gca->globalcolorenable) { | ||
1198 | srcinfo->globalcolorenable = true; | ||
1199 | srcinfo->globalcolor = gca->globalcolor; | ||
1200 | srcinfo->srcglobalpremul | ||
1201 | = GCREG_SRC_GLOBAL_PREMULTIPLY_DISABLE; | ||
1202 | srcinfo->srcglobalmode | ||
1203 | = GCREG_GLOBAL_ALPHA_MODE_NORMAL; | ||
1204 | srcinfo->dstglobalmode | ||
1205 | = GCREG_GLOBAL_ALPHA_MODE_SCALED; | ||
1206 | } else { | ||
1207 | srcinfo->globalcolorenable = false; | ||
1208 | srcinfo->srcglobalpremul | ||
1209 | = GCREG_SRC_GLOBAL_PREMULTIPLY_DISABLE; | ||
1210 | srcinfo->srcglobalmode | ||
1211 | = GCREG_GLOBAL_ALPHA_MODE_NORMAL; | ||
1212 | srcinfo->dstglobalmode | ||
1213 | = GCREG_GLOBAL_ALPHA_MODE_NORMAL; | ||
1214 | } | ||
1215 | } | ||
1216 | } | ||
1217 | |||
1218 | sw = srcinfo->rect.orig.right - srcinfo->rect.orig.left; | ||
1219 | sh = srcinfo->rect.orig.bottom - srcinfo->rect.orig.top; | ||
1220 | |||
1221 | dw = bvbltparams->dstrect.width; | ||
1222 | dh = bvbltparams->dstrect.height; | ||
1223 | |||
1224 | GCDBG(GCZONE_BLIT, " srcsize %dx%d.\n", sw, sh); | ||
1225 | GCDBG(GCZONE_BLIT, " dstsize %dx%d.\n", dw, dh); | ||
1226 | |||
1227 | if ((sw == 0) || (sh == 0)) { | ||
1228 | GCDBG(GCZONE_BLIT, " empty source, skipping.\n"); | ||
1229 | } else if ((dw == 0) || (dh == 0)) { | ||
1230 | GCDBG(GCZONE_BLIT, " empty destination, skipping.\n"); | ||
1231 | } else if ((sw == 1) && (sh == 1) && (srcinfo->buf.desc->virtaddr)) { | ||
1232 | GCDBG(GCZONE_BLIT, " op: fill.\n"); | ||
1233 | bverror = do_fill(bvbltparams, gcbatch, srcinfo); | ||
1234 | } else if ((sw == dw) && (sh == dh)) { | ||
1235 | GCDBG(GCZONE_BLIT, " op: bitblit.\n"); | ||
1236 | bverror = do_blit(bvbltparams, gcbatch, srcinfo); | ||
1237 | } else { | ||
1238 | GCDBG(GCZONE_BLIT, " op: filter.\n"); | ||
1239 | bverror = do_filter(bvbltparams, gcbatch, srcinfo); | ||
1240 | } | ||
1241 | |||
1242 | /* Reset dirty flags. */ | ||
1243 | dstinfo = &gcbatch->dstinfo; | ||
1244 | dstinfo->surfdirty = false; | ||
1245 | dstinfo->rectdirty = false; | ||
1246 | dstinfo->cliprectdirty = false; | ||
1247 | dstinfo->destrectdirty = false; | ||
1248 | |||
1249 | return bverror; | ||
1250 | } | ||
1251 | |||
1252 | |||
1253 | /******************************************************************************* | ||
1254 | * Library constructor and destructor. | ||
1255 | */ | ||
1256 | |||
1257 | void bv_init(void) | ||
1258 | { | ||
1259 | struct gccontext *gccontext = get_context(); | ||
1260 | struct gcicaps gcicaps; | ||
1261 | unsigned i, j; | ||
1262 | |||
1263 | GCDBG_REGISTER(bv, ~GCZONE_BUFFER); | ||
1264 | GCDBG_REGISTER(parser, GCZONE_ALL); | ||
1265 | GCDBG_REGISTER(map, GCZONE_NONE); | ||
1266 | GCDBG_REGISTER(buffer, GCZONE_NONE); | ||
1267 | GCDBG_REGISTER(fill, GCZONE_ALL); | ||
1268 | GCDBG_REGISTER(blit, GCZONE_ALL); | ||
1269 | GCDBG_REGISTER(filter, GCZONE_ALL); | ||
1270 | |||
1271 | gcbv_debug_init(); | ||
1272 | |||
1273 | GCLOCK_INIT(&gccontext->batchlock); | ||
1274 | GCLOCK_INIT(&gccontext->bufferlock); | ||
1275 | GCLOCK_INIT(&gccontext->fixuplock); | ||
1276 | GCLOCK_INIT(&gccontext->maplock); | ||
1277 | GCLOCK_INIT(&gccontext->callbacklock); | ||
1278 | |||
1279 | INIT_LIST_HEAD(&gccontext->unmapvac); | ||
1280 | INIT_LIST_HEAD(&gccontext->buffervac); | ||
1281 | INIT_LIST_HEAD(&gccontext->fixupvac); | ||
1282 | INIT_LIST_HEAD(&gccontext->batchvac); | ||
1283 | INIT_LIST_HEAD(&gccontext->callbacklist); | ||
1284 | INIT_LIST_HEAD(&gccontext->callbackvac); | ||
1285 | |||
1286 | /* Initialize the filter cache. */ | ||
1287 | for (i = 0; i < GC_FILTER_COUNT; i += 1) | ||
1288 | for (j = 0; j < GC_TAP_COUNT; j += 1) | ||
1289 | INIT_LIST_HEAD(&gccontext->filtercache[i][j].list); | ||
1290 | |||
1291 | /* Query hardware caps. */ | ||
1292 | gc_getcaps_wrapper(&gcicaps); | ||
1293 | if (gcicaps.gcerror == GCERR_NONE) { | ||
1294 | gccontext->gcmodel = gcicaps.gcmodel; | ||
1295 | gccontext->gcrevision = gcicaps.gcrevision; | ||
1296 | gccontext->gcdate = gcicaps.gcdate; | ||
1297 | gccontext->gctime = gcicaps.gctime; | ||
1298 | |||
1299 | gccontext->gccaps.l2cachefor420 | ||
1300 | = (gcicaps.gcfeatures2.reg.l2cachefor420 != 0); | ||
1301 | |||
1302 | if (gcicaps.gcfeatures3.reg.newfeatures0) { | ||
1303 | gccontext->gccaps.maxsource = 8; | ||
1304 | gccontext->gccaps.strictalign = false; | ||
1305 | } else { | ||
1306 | gccontext->gccaps.maxsource = 4; | ||
1307 | gccontext->gccaps.strictalign = true; | ||
1308 | } | ||
1309 | |||
1310 | gccontext->gccaps.swizzlefixed | ||
1311 | = (gcicaps.gcfeatures3.reg.deenhancements1 != 0); | ||
1312 | |||
1313 | GCDBG(GCZONE_INIT, "chip model: %X\n", | ||
1314 | gccontext->gcmodel); | ||
1315 | GCDBG(GCZONE_INIT, "chip revision: %X\n", | ||
1316 | gccontext->gcrevision); | ||
1317 | GCDBG(GCZONE_INIT, "chip date: %X\n", | ||
1318 | gccontext->gcdate); | ||
1319 | GCDBG(GCZONE_INIT, "chip time: %X\n", | ||
1320 | gccontext->gctime); | ||
1321 | GCDBG(GCZONE_INIT, "max source: %d\n", | ||
1322 | gccontext->gccaps.maxsource); | ||
1323 | GCDBG(GCZONE_INIT, "strict alignment: %d\n", | ||
1324 | gccontext->gccaps.strictalign); | ||
1325 | GCDBG(GCZONE_INIT, "swizzle fixed: %d\n", | ||
1326 | gccontext->gccaps.swizzlefixed); | ||
1327 | } else { | ||
1328 | GCERR("failed to get chip caps.\n"); | ||
1329 | gccontext->gccaps.l2cachefor420 = false; | ||
1330 | gccontext->gccaps.maxsource = 4; | ||
1331 | gccontext->gccaps.strictalign = true; | ||
1332 | gccontext->gccaps.swizzlefixed = false; | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | void bv_exit(void) | ||
1337 | { | ||
1338 | struct gccontext *gccontext = get_context(); | ||
1339 | struct bvbuffmap *bvbuffmap; | ||
1340 | struct list_head *head; | ||
1341 | struct gcschedunmap *gcschedunmap; | ||
1342 | struct gcbuffer *gcbuffer; | ||
1343 | struct gcfixup *gcfixup; | ||
1344 | struct gcbatch *gcbatch; | ||
1345 | struct gccallbackinfo *gccallbackinfo; | ||
1346 | |||
1347 | while (gccontext->buffmapvac != NULL) { | ||
1348 | bvbuffmap = gccontext->buffmapvac; | ||
1349 | gccontext->buffmapvac = bvbuffmap->nextmap; | ||
1350 | gcfree(bvbuffmap); | ||
1351 | } | ||
1352 | |||
1353 | while (!list_empty(&gccontext->unmapvac)) { | ||
1354 | head = gccontext->unmapvac.next; | ||
1355 | gcschedunmap = list_entry(head, struct gcschedunmap, link); | ||
1356 | list_del(head); | ||
1357 | gcfree(gcschedunmap); | ||
1358 | } | ||
1359 | |||
1360 | while (!list_empty(&gccontext->buffervac)) { | ||
1361 | head = gccontext->buffervac.next; | ||
1362 | gcbuffer = list_entry(head, struct gcbuffer, link); | ||
1363 | list_del(head); | ||
1364 | gcfree(gcbuffer); | ||
1365 | } | ||
1366 | |||
1367 | while (!list_empty(&gccontext->fixupvac)) { | ||
1368 | head = gccontext->fixupvac.next; | ||
1369 | gcfixup = list_entry(head, struct gcfixup, link); | ||
1370 | list_del(head); | ||
1371 | gcfree(gcfixup); | ||
1372 | } | ||
1373 | |||
1374 | while (!list_empty(&gccontext->batchvac)) { | ||
1375 | head = gccontext->batchvac.next; | ||
1376 | gcbatch = list_entry(head, struct gcbatch, link); | ||
1377 | list_del(head); | ||
1378 | gcfree(gcbatch); | ||
1379 | } | ||
1380 | |||
1381 | while (!list_empty(&gccontext->callbacklist)) { | ||
1382 | head = gccontext->callbacklist.next; | ||
1383 | list_move(head, &gccontext->callbackvac); | ||
1384 | } | ||
1385 | |||
1386 | while (!list_empty(&gccontext->callbackvac)) { | ||
1387 | head = gccontext->callbackvac.next; | ||
1388 | gccallbackinfo = list_entry(head, struct gccallbackinfo, link); | ||
1389 | list_del(head); | ||
1390 | gcfree(gccallbackinfo); | ||
1391 | } | ||
1392 | |||
1393 | free_temp(false); | ||
1394 | |||
1395 | gcbv_debug_shutdown(); | ||
1396 | } | ||
1397 | |||
1398 | |||
1399 | /******************************************************************************* | ||
1400 | * Library API. | ||
1401 | */ | ||
1402 | |||
1403 | enum bverror bv_map(struct bvbuffdesc *bvbuffdesc) | ||
1404 | { | ||
1405 | enum bverror bverror; | ||
1406 | struct bvbuffmap *bvbuffmap; | ||
1407 | |||
1408 | GCENTERARG(GCZONE_MAPPING, "bvbuffdesc = 0x%08X\n", | ||
1409 | (unsigned int) bvbuffdesc); | ||
1410 | |||
1411 | if (bvbuffdesc == NULL) { | ||
1412 | BVSETERROR(BVERR_BUFFERDESC, "bvbuffdesc is NULL"); | ||
1413 | goto exit; | ||
1414 | } | ||
1415 | |||
1416 | if (bvbuffdesc->structsize < STRUCTSIZE(bvbuffdesc, map)) { | ||
1417 | BVSETERROR(BVERR_BUFFERDESC_VERS, "argument has invalid size"); | ||
1418 | goto exit; | ||
1419 | } | ||
1420 | |||
1421 | bverror = do_map(bvbuffdesc, NULL, &bvbuffmap); | ||
1422 | |||
1423 | exit: | ||
1424 | GCEXITARG(GCZONE_MAPPING, "bv%s = %d\n", | ||
1425 | (bverror == BVERR_NONE) ? "result" : "error", bverror); | ||
1426 | return bverror; | ||
1427 | } | ||
1428 | |||
1429 | enum bverror bv_unmap(struct bvbuffdesc *bvbuffdesc) | ||
1430 | { | ||
1431 | enum bverror bverror = BVERR_NONE; | ||
1432 | enum bverror otherbverror = BVERR_NONE; | ||
1433 | struct gccontext *gccontext = get_context(); | ||
1434 | struct bvbuffmap *prev = NULL; | ||
1435 | struct bvbuffmap *bvbuffmap; | ||
1436 | struct bvbuffmapinfo *bvbuffmapinfo; | ||
1437 | struct gcimap gcimap; | ||
1438 | |||
1439 | GCENTERARG(GCZONE_MAPPING, "bvbuffdesc = 0x%08X\n", | ||
1440 | (unsigned int) bvbuffdesc); | ||
1441 | |||
1442 | /* Lock access to the mapping list. */ | ||
1443 | GCLOCK(&gccontext->maplock); | ||
1444 | |||
1445 | if (bvbuffdesc == NULL) { | ||
1446 | BVSETERROR(BVERR_BUFFERDESC, "bvbuffdesc is NULL"); | ||
1447 | goto exit; | ||
1448 | } | ||
1449 | |||
1450 | if (bvbuffdesc->structsize < STRUCTSIZE(bvbuffdesc, map)) { | ||
1451 | BVSETERROR(BVERR_BUFFERDESC_VERS, "argument has invalid size"); | ||
1452 | goto exit; | ||
1453 | } | ||
1454 | |||
1455 | /* Is the buffer mapped? */ | ||
1456 | bvbuffmap = bvbuffdesc->map; | ||
1457 | if (bvbuffmap == NULL) { | ||
1458 | GCDBG(GCZONE_MAPPING, "buffer isn't mapped.\n"); | ||
1459 | goto exit; | ||
1460 | } | ||
1461 | |||
1462 | /* Try to find our mapping. */ | ||
1463 | while (bvbuffmap != NULL) { | ||
1464 | if (bvbuffmap->bv_unmap == bv_unmap) | ||
1465 | break; | ||
1466 | prev = bvbuffmap; | ||
1467 | bvbuffmap = bvbuffmap->nextmap; | ||
1468 | } | ||
1469 | |||
1470 | /* Are there other implementations? */ | ||
1471 | if ((prev != NULL) || (bvbuffmap->nextmap != NULL)) { | ||
1472 | GCDBG(GCZONE_MAPPING, | ||
1473 | "have mappings from other implementations.\n"); | ||
1474 | |||
1475 | /* Was our mapping found? */ | ||
1476 | if (bvbuffmap == NULL) { | ||
1477 | GCDBG(GCZONE_MAPPING, | ||
1478 | "no mapping from our implementation.\n"); | ||
1479 | |||
1480 | /* No, call other implementations. */ | ||
1481 | bverror = bvbuffdesc->map->bv_unmap(bvbuffdesc); | ||
1482 | goto exit; | ||
1483 | } | ||
1484 | |||
1485 | if (bvbuffmap->structsize | ||
1486 | < STRUCTSIZE(bvbuffmap, nextmap)) { | ||
1487 | BVSETERROR(BVERR_BUFFERDESC_VERS, | ||
1488 | "unsupported bvbuffdesc version"); | ||
1489 | goto exit; | ||
1490 | } | ||
1491 | |||
1492 | /* Remove our mapping. */ | ||
1493 | if (prev == NULL) | ||
1494 | bvbuffdesc->map = bvbuffmap->nextmap; | ||
1495 | else | ||
1496 | prev->nextmap = bvbuffmap->nextmap; | ||
1497 | |||
1498 | /* Call other implementation. */ | ||
1499 | otherbverror = bvbuffdesc->map->bv_unmap(bvbuffdesc); | ||
1500 | |||
1501 | /* Add our mapping back. */ | ||
1502 | bvbuffmap->nextmap = bvbuffdesc->map; | ||
1503 | bvbuffdesc->map = bvbuffmap; | ||
1504 | prev = NULL; | ||
1505 | } else { | ||
1506 | GCDBG(GCZONE_MAPPING, | ||
1507 | "no mappings from other implementations.\n"); | ||
1508 | } | ||
1509 | |||
1510 | /* Get the info structure. */ | ||
1511 | bvbuffmapinfo = (struct bvbuffmapinfo *) bvbuffmap->handle; | ||
1512 | |||
1513 | GCDBG(GCZONE_MAPPING, "bvbuffmap = 0x%08X\n", (unsigned int) bvbuffmap); | ||
1514 | GCDBG(GCZONE_MAPPING, "handle = 0x%08X\n", bvbuffmapinfo->handle); | ||
1515 | |||
1516 | /* Explicit unmapping. */ | ||
1517 | if (bvbuffmapinfo->usermap == 0) | ||
1518 | GCERR("explicit count is already zero.\n"); | ||
1519 | bvbuffmapinfo->usermap = 0; | ||
1520 | |||
1521 | GCDBG(GCZONE_MAPPING, "explicit count = %d\n", | ||
1522 | bvbuffmapinfo->usermap); | ||
1523 | GCDBG(GCZONE_MAPPING, "implicit count = %d\n", | ||
1524 | bvbuffmapinfo->automap); | ||
1525 | |||
1526 | /* Do we have implicit mappings? */ | ||
1527 | if (bvbuffmapinfo->automap > 0) { | ||
1528 | GCDBG(GCZONE_MAPPING, "have implicit unmappings.\n"); | ||
1529 | goto exit; | ||
1530 | } | ||
1531 | |||
1532 | /* Unmap the buffer. */ | ||
1533 | memset(&gcimap, 0, sizeof(gcimap)); | ||
1534 | gcimap.handle = bvbuffmapinfo->handle; | ||
1535 | gc_unmap_wrapper(&gcimap); | ||
1536 | if (gcimap.gcerror != GCERR_NONE) { | ||
1537 | BVSETERROR(BVERR_OOM, "unable to free gccore memory"); | ||
1538 | goto exit; | ||
1539 | } | ||
1540 | |||
1541 | /* Remove from the buffer descriptor list. */ | ||
1542 | if (prev == NULL) | ||
1543 | bvbuffdesc->map = bvbuffmap->nextmap; | ||
1544 | else | ||
1545 | prev->nextmap = bvbuffmap->nextmap; | ||
1546 | |||
1547 | /* Invalidate the record. */ | ||
1548 | bvbuffmap->structsize = 0; | ||
1549 | |||
1550 | /* Add to the vacant list. */ | ||
1551 | bvbuffmap->nextmap = gccontext->buffmapvac; | ||
1552 | gccontext->buffmapvac = bvbuffmap; | ||
1553 | |||
1554 | exit: | ||
1555 | /* Unlock access to the mapping list. */ | ||
1556 | GCUNLOCK(&gccontext->maplock); | ||
1557 | |||
1558 | GCEXITARG(GCZONE_MAPPING, "bv%s = %d\n", | ||
1559 | (bverror == BVERR_NONE) ? "result" : "error", bverror); | ||
1560 | return bverror; | ||
1561 | } | ||
1562 | |||
1563 | enum bverror bv_blt(struct bvbltparams *bvbltparams) | ||
1564 | { | ||
1565 | enum bverror bverror = BVERR_NONE; | ||
1566 | struct gccontext *gccontext = get_context(); | ||
1567 | struct gcalpha *gca = NULL; | ||
1568 | struct gcalpha _gca; | ||
1569 | unsigned int op, type, blend, format; | ||
1570 | unsigned int batchexec = 0; | ||
1571 | bool nop = false; | ||
1572 | struct gcbatch *gcbatch; | ||
1573 | struct gcsurface *dstinfo; | ||
1574 | struct bvrect *dstrect; | ||
1575 | bool dstonly, src1used, src2used, maskused; | ||
1576 | struct gcsurface srcinfo[2]; | ||
1577 | unsigned short rop; | ||
1578 | struct gcicommit gcicommit; | ||
1579 | int i, srccount, res; | ||
1580 | |||
1581 | GCENTERARG(GCZONE_BLIT, "bvbltparams = 0x%08X\n", | ||
1582 | (unsigned int) bvbltparams); | ||
1583 | |||
1584 | /* Verify blt parameters structure. */ | ||
1585 | if (bvbltparams == NULL) { | ||
1586 | BVSETERROR(BVERR_BLTPARAMS_VERS, "bvbltparams is NULL"); | ||
1587 | goto exit; | ||
1588 | } | ||
1589 | |||
1590 | if (bvbltparams->structsize < STRUCTSIZE(bvbltparams, callbackdata)) { | ||
1591 | BVSETERROR(BVERR_BLTPARAMS_VERS, "argument has invalid size"); | ||
1592 | goto exit; | ||
1593 | } | ||
1594 | |||
1595 | /* Reset the error message. */ | ||
1596 | bvbltparams->errdesc = NULL; | ||
1597 | |||
1598 | /* Verify the destination parameters structure. */ | ||
1599 | res = verify_surface(0, (union bvinbuff *) &bvbltparams->dstdesc, | ||
1600 | bvbltparams->dstgeom); | ||
1601 | if (res != -1) { | ||
1602 | BVSETBLTSURFERROR(res, g_destsurferr); | ||
1603 | goto exit; | ||
1604 | } | ||
1605 | |||
1606 | /* Extract the operation flags. */ | ||
1607 | op = (bvbltparams->flags & BVFLAG_OP_MASK) >> BVFLAG_OP_SHIFT; | ||
1608 | type = (bvbltparams->flags & BVFLAG_BATCH_MASK) >> BVFLAG_BATCH_SHIFT; | ||
1609 | GCDBG(GCZONE_BLIT, "op = %d\n", op); | ||
1610 | GCDBG(GCZONE_BLIT, "type = %d\n", type); | ||
1611 | |||
1612 | switch (type) { | ||
1613 | case (BVFLAG_BATCH_NONE >> BVFLAG_BATCH_SHIFT): | ||
1614 | bverror = allocate_batch(bvbltparams, &gcbatch); | ||
1615 | if (bverror != BVERR_NONE) { | ||
1616 | bvbltparams->errdesc = gccontext->bverrorstr; | ||
1617 | goto exit; | ||
1618 | } | ||
1619 | |||
1620 | batchexec = 1; | ||
1621 | gcbatch->batchflags = 0x7FFFFFFF; | ||
1622 | |||
1623 | GCDBG(GCZONE_BATCH, "BVFLAG_BATCH_NONE(0x%08X)\n", | ||
1624 | (unsigned int) gcbatch); | ||
1625 | break; | ||
1626 | |||
1627 | case (BVFLAG_BATCH_BEGIN >> BVFLAG_BATCH_SHIFT): | ||
1628 | bverror = allocate_batch(bvbltparams, &gcbatch); | ||
1629 | if (bverror != BVERR_NONE) { | ||
1630 | bvbltparams->errdesc = gccontext->bverrorstr; | ||
1631 | goto exit; | ||
1632 | } | ||
1633 | |||
1634 | bvbltparams->batch = (struct bvbatch *) gcbatch; | ||
1635 | |||
1636 | batchexec = 0; | ||
1637 | bvbltparams->batchflags = | ||
1638 | gcbatch->batchflags = 0x7FFFFFFF; | ||
1639 | |||
1640 | GCDBG(GCZONE_BATCH, "BVFLAG_BATCH_BEGIN(0x%08X)\n", | ||
1641 | (unsigned int) gcbatch); | ||
1642 | break; | ||
1643 | |||
1644 | case (BVFLAG_BATCH_CONTINUE >> BVFLAG_BATCH_SHIFT): | ||
1645 | gcbatch = (struct gcbatch *) bvbltparams->batch; | ||
1646 | if (gcbatch == NULL) { | ||
1647 | BVSETBLTERROR(BVERR_BATCH, "batch is not initialized"); | ||
1648 | goto exit; | ||
1649 | } | ||
1650 | |||
1651 | if (gcbatch->structsize < STRUCTSIZE(gcbatch, unmap)) { | ||
1652 | BVSETBLTERROR(BVERR_BATCH, "invalid batch"); | ||
1653 | goto exit; | ||
1654 | } | ||
1655 | |||
1656 | batchexec = 0; | ||
1657 | gcbatch->batchflags = bvbltparams->batchflags; | ||
1658 | |||
1659 | GCDBG(GCZONE_BATCH, "BVFLAG_BATCH_CONTINUE(0x%08X)\n", | ||
1660 | (unsigned int) gcbatch); | ||
1661 | break; | ||
1662 | |||
1663 | case (BVFLAG_BATCH_END >> BVFLAG_BATCH_SHIFT): | ||
1664 | gcbatch = (struct gcbatch *) bvbltparams->batch; | ||
1665 | if (gcbatch == NULL) { | ||
1666 | BVSETBLTERROR(BVERR_BATCH, "batch is not initialized"); | ||
1667 | goto exit; | ||
1668 | } | ||
1669 | |||
1670 | if (gcbatch->structsize < STRUCTSIZE(gcbatch, unmap)) { | ||
1671 | BVSETBLTERROR(BVERR_BATCH, "invalid batch"); | ||
1672 | goto exit; | ||
1673 | } | ||
1674 | |||
1675 | batchexec = 1; | ||
1676 | nop = (bvbltparams->batchflags & BVBATCH_ENDNOP) != 0; | ||
1677 | gcbatch->batchflags = bvbltparams->batchflags; | ||
1678 | |||
1679 | GCDBG(GCZONE_BATCH, "BVFLAG_BATCH_END(0x%08X)\n", | ||
1680 | (unsigned int) gcbatch); | ||
1681 | break; | ||
1682 | |||
1683 | default: | ||
1684 | BVSETBLTERROR(BVERR_BATCH, "unrecognized batch type"); | ||
1685 | goto exit; | ||
1686 | } | ||
1687 | |||
1688 | GCDBG(GCZONE_BATCH, "batchflags=0x%08X\n", | ||
1689 | (unsigned int) gcbatch->batchflags); | ||
1690 | |||
1691 | if (!nop) { | ||
1692 | /* Get a shortcut to the destination rectangle. */ | ||
1693 | dstrect = &bvbltparams->dstrect; | ||
1694 | |||
1695 | /* Verify the batch change flags. */ | ||
1696 | GCVERIFYBATCH(gcbatch->batchflags >> 12, | ||
1697 | &gcbatch->prevdstrect, dstrect); | ||
1698 | |||
1699 | switch (op) { | ||
1700 | case (BVFLAG_ROP >> BVFLAG_OP_SHIFT): | ||
1701 | GCDBG(GCZONE_BLIT, "BVFLAG_ROP\n"); | ||
1702 | |||
1703 | rop = bvbltparams->op.rop; | ||
1704 | dstonly = (rop == 0x0000) | (rop == 0x5555) | ||
1705 | | (rop == 0xAAAA) | (rop == 0xFFFF); | ||
1706 | src1used = ((((rop & 0xCCCC) >> 2) | ||
1707 | ^ (rop & 0x3333)) != 0); | ||
1708 | src2used = ((((rop & 0xF0F0) >> 4) | ||
1709 | ^ (rop & 0x0F0F)) != 0); | ||
1710 | maskused = ((((rop & 0xFF00) >> 8) | ||
1711 | ^ (rop & 0x00FF)) != 0); | ||
1712 | break; | ||
1713 | |||
1714 | case (BVFLAG_BLEND >> BVFLAG_OP_SHIFT): | ||
1715 | GCDBG(GCZONE_BLIT, "BVFLAG_BLEND\n"); | ||
1716 | |||
1717 | blend = bvbltparams->op.blend; | ||
1718 | format = blend & BVBLENDDEF_FORMAT_MASK; | ||
1719 | maskused = (blend & BVBLENDDEF_REMOTE) != 0; | ||
1720 | rop = 0xCCCC; | ||
1721 | |||
1722 | GCDBG(GCZONE_BLIT, "blend = 0x%08X (%s)\n", | ||
1723 | blend, gc_bvblend_name(blend)); | ||
1724 | |||
1725 | if (format != BVBLENDDEF_FORMAT_CLASSIC) { | ||
1726 | BVSETBLTERROR(BVERR_BLEND, | ||
1727 | "unrecognized blend format"); | ||
1728 | goto exit; | ||
1729 | } | ||
1730 | |||
1731 | if (blend == BVBLEND_CLEAR) { | ||
1732 | dstonly = true; | ||
1733 | src1used = false; | ||
1734 | src2used = false; | ||
1735 | } else { | ||
1736 | bverror = parse_blend(bvbltparams, blend, | ||
1737 | &_gca); | ||
1738 | if (bverror != BVERR_NONE) | ||
1739 | goto exit; | ||
1740 | |||
1741 | gca = &_gca; | ||
1742 | |||
1743 | dstonly = false; | ||
1744 | src1used = gca->src1used; | ||
1745 | src2used = gca->src2used; | ||
1746 | } | ||
1747 | break; | ||
1748 | |||
1749 | case (BVFLAG_FILTER >> BVFLAG_OP_SHIFT): | ||
1750 | GCDBG(GCZONE_BLIT, "BVFLAG_FILTER\n"); | ||
1751 | BVSETBLTERROR(BVERR_OP, | ||
1752 | "filter operation not supported"); | ||
1753 | goto exit; | ||
1754 | |||
1755 | default: | ||
1756 | BVSETBLTERROR(BVERR_OP, "unrecognized operation"); | ||
1757 | goto exit; | ||
1758 | } | ||
1759 | |||
1760 | /* Reset the number of sources. */ | ||
1761 | srccount = 0; | ||
1762 | |||
1763 | /* Determine what's changed in the destination. */ | ||
1764 | dstinfo = &gcbatch->dstinfo; | ||
1765 | dstinfo->surfdirty | ||
1766 | = ((gcbatch->batchflags & BVBATCH_DST) != 0); | ||
1767 | dstinfo->cliprectdirty | ||
1768 | = ((gcbatch->batchflags & BVBATCH_CLIPRECT) != 0); | ||
1769 | dstinfo->destrectdirty | ||
1770 | = ((gcbatch->batchflags & BVBATCH_DESTRECT) != 0); | ||
1771 | dstinfo->rectdirty | ||
1772 | = dstinfo->cliprectdirty || dstinfo->destrectdirty; | ||
1773 | |||
1774 | /* Verify the src1 parameters structure. */ | ||
1775 | if (src1used) { | ||
1776 | GCDBG(GCZONE_SRC, "source #1: used\n"); | ||
1777 | res = verify_surface( | ||
1778 | bvbltparams->flags & BVBATCH_TILE_SRC1, | ||
1779 | &bvbltparams->src1, bvbltparams->src1geom); | ||
1780 | if (res != -1) { | ||
1781 | BVSETBLTSURFERROR(res, g_src1surferr); | ||
1782 | goto exit; | ||
1783 | } | ||
1784 | |||
1785 | /* Verify the batch change flags. */ | ||
1786 | GCVERIFYBATCH(gcbatch->batchflags >> 14, | ||
1787 | &gcbatch->prevsrc1rect, | ||
1788 | &bvbltparams->src1rect); | ||
1789 | |||
1790 | /* Same as the destination? */ | ||
1791 | if (same_phys_area(bvbltparams->src1.desc, | ||
1792 | &bvbltparams->src1rect, | ||
1793 | bvbltparams->dstdesc, | ||
1794 | dstrect)) { | ||
1795 | GCDBG(GCZONE_BLIT, | ||
1796 | " src1 same as destination\n"); | ||
1797 | } else { | ||
1798 | bverror = parse_source(bvbltparams, | ||
1799 | gcbatch, | ||
1800 | &srcinfo[srccount], | ||
1801 | 0, rop); | ||
1802 | if (bverror != BVERR_NONE) | ||
1803 | goto exit; | ||
1804 | |||
1805 | srccount += 1; | ||
1806 | } | ||
1807 | } | ||
1808 | |||
1809 | /* Verify the src2 parameters structure. */ | ||
1810 | if (src2used) { | ||
1811 | GCDBG(GCZONE_SRC, "source #2: used\n"); | ||
1812 | res = verify_surface( | ||
1813 | bvbltparams->flags & BVBATCH_TILE_SRC2, | ||
1814 | &bvbltparams->src2, bvbltparams->src2geom); | ||
1815 | if (res != -1) { | ||
1816 | BVSETBLTSURFERROR(res, g_src2surferr); | ||
1817 | goto exit; | ||
1818 | } | ||
1819 | |||
1820 | /* Verify the batch change flags. */ | ||
1821 | GCVERIFYBATCH(gcbatch->batchflags >> 16, | ||
1822 | &gcbatch->prevsrc2rect, | ||
1823 | &bvbltparams->src2rect); | ||
1824 | |||
1825 | /* Same as the destination? */ | ||
1826 | if (same_phys_area(bvbltparams->src2.desc, | ||
1827 | &bvbltparams->src2rect, | ||
1828 | bvbltparams->dstdesc, | ||
1829 | dstrect)) { | ||
1830 | GCDBG(GCZONE_BLIT, | ||
1831 | " src2 same as destination\n"); | ||
1832 | } else { | ||
1833 | bverror = parse_source(bvbltparams, | ||
1834 | gcbatch, | ||
1835 | &srcinfo[srccount], | ||
1836 | 1, rop); | ||
1837 | if (bverror != BVERR_NONE) | ||
1838 | goto exit; | ||
1839 | |||
1840 | srccount += 1; | ||
1841 | } | ||
1842 | } | ||
1843 | |||
1844 | /* Verify the mask parameters structure. */ | ||
1845 | if (maskused) { | ||
1846 | GCDBG(GCZONE_MASK, "mask: used\n"); | ||
1847 | res = verify_surface( | ||
1848 | bvbltparams->flags & BVBATCH_TILE_MASK, | ||
1849 | &bvbltparams->mask, bvbltparams->maskgeom); | ||
1850 | if (res != -1) { | ||
1851 | BVSETBLTSURFERROR(res, g_masksurferr); | ||
1852 | goto exit; | ||
1853 | } | ||
1854 | |||
1855 | /* Verify the batch change flags. */ | ||
1856 | GCVERIFYBATCH(gcbatch->batchflags >> 18, | ||
1857 | &gcbatch->prevmaskrect, | ||
1858 | &bvbltparams->maskrect); | ||
1859 | |||
1860 | BVSETBLTERROR(BVERR_OP, | ||
1861 | "operation with mask not supported"); | ||
1862 | goto exit; | ||
1863 | } | ||
1864 | |||
1865 | /* Destination only? */ | ||
1866 | if (dstonly) { | ||
1867 | static unsigned int pixel[8]; | ||
1868 | static struct bvbuffdesc dummysrcdesc; | ||
1869 | static struct gcsurface dummysrcinfo; | ||
1870 | static bool dummyinit; | ||
1871 | |||
1872 | GCDBG(GCZONE_BLIT, "target only operation.\n"); | ||
1873 | |||
1874 | if (!dummyinit) { | ||
1875 | GCDBG(GCZONE_BLIT, | ||
1876 | "initializing dummy source.\n"); | ||
1877 | |||
1878 | dummysrcdesc.structsize | ||
1879 | = sizeof(struct bvbuffdesc); | ||
1880 | dummysrcdesc.virtaddr = pixel; | ||
1881 | dummysrcdesc.length = sizeof(pixel); | ||
1882 | |||
1883 | dummysrcinfo.buf.desc = &dummysrcdesc; | ||
1884 | dummysrcinfo.width = 1; | ||
1885 | dummysrcinfo.height = 1; | ||
1886 | dummysrcinfo.stride1 = sizeof(pixel); | ||
1887 | dummysrcinfo.rect.orig.right = 1; | ||
1888 | dummysrcinfo.rect.orig.bottom = 1; | ||
1889 | |||
1890 | parse_format(bvbltparams, OCDFMT_RGBA24, | ||
1891 | &dummysrcinfo.format); | ||
1892 | |||
1893 | dummyinit = true; | ||
1894 | } | ||
1895 | |||
1896 | dummysrcinfo.rop = rop; | ||
1897 | bverror = do_op(bvbltparams, gcbatch, | ||
1898 | 1, &dummysrcinfo, NULL); | ||
1899 | if (bverror != BVERR_NONE) | ||
1900 | goto exit; | ||
1901 | } else { | ||
1902 | GCDBG(GCZONE_BLIT, "srccount = %d\n", srccount); | ||
1903 | |||
1904 | if (srccount == 0) { | ||
1905 | BVSETBLTERROR(BVERR_OP, | ||
1906 | "operation not supported"); | ||
1907 | goto exit; | ||
1908 | } | ||
1909 | |||
1910 | for (i = 0; i < srccount; i += 1) { | ||
1911 | bverror = do_op(bvbltparams, gcbatch, | ||
1912 | srccount, &srcinfo[i], gca); | ||
1913 | if (bverror != BVERR_NONE) | ||
1914 | goto exit; | ||
1915 | } | ||
1916 | } | ||
1917 | } | ||
1918 | |||
1919 | if (batchexec) { | ||
1920 | struct gcmoflush *flush; | ||
1921 | |||
1922 | GCDBG(GCZONE_BLIT, "preparing to submit the batch.\n"); | ||
1923 | |||
1924 | /* Finalize the current operation. */ | ||
1925 | bverror = gcbatch->batchend(bvbltparams, gcbatch); | ||
1926 | if (bverror != BVERR_NONE) | ||
1927 | goto exit; | ||
1928 | |||
1929 | /* Add PE flush. */ | ||
1930 | GCDBG(GCZONE_BLIT, "appending the flush.\n"); | ||
1931 | bverror = claim_buffer(bvbltparams, gcbatch, | ||
1932 | sizeof(struct gcmoflush), | ||
1933 | (void **) &flush); | ||
1934 | if (bverror != BVERR_NONE) | ||
1935 | goto exit; | ||
1936 | |||
1937 | flush->flush_ldst = gcmoflush_flush_ldst; | ||
1938 | flush->flush.reg = gcregflush_pe2D; | ||
1939 | |||
1940 | /* Process asynchronous operation. */ | ||
1941 | if ((bvbltparams->flags & BVFLAG_ASYNC) == 0) { | ||
1942 | GCDBG(GCZONE_BLIT, "synchronous batch.\n"); | ||
1943 | gcicommit.callback = NULL; | ||
1944 | gcicommit.callbackparam = NULL; | ||
1945 | gcicommit.asynchronous = false; | ||
1946 | } else { | ||
1947 | struct gccallbackinfo *gccallbackinfo; | ||
1948 | |||
1949 | GCDBG(GCZONE_BLIT, "asynchronous batch (0x%08X):\n", | ||
1950 | bvbltparams->flags); | ||
1951 | |||
1952 | if (bvbltparams->callbackfn == NULL) { | ||
1953 | GCDBG(GCZONE_BLIT, "no callback given.\n"); | ||
1954 | gcicommit.callback = NULL; | ||
1955 | gcicommit.callbackparam = NULL; | ||
1956 | } else { | ||
1957 | bverror = get_callbackinfo(&gccallbackinfo); | ||
1958 | if (bverror != BVERR_NONE) { | ||
1959 | BVSETBLTERROR(BVERR_OOM, | ||
1960 | "callback allocation " | ||
1961 | "failed"); | ||
1962 | goto exit; | ||
1963 | } | ||
1964 | |||
1965 | gccallbackinfo->info.callback.fn | ||
1966 | = bvbltparams->callbackfn; | ||
1967 | gccallbackinfo->info.callback.data | ||
1968 | = bvbltparams->callbackdata; | ||
1969 | |||
1970 | gcicommit.callback = callbackbltsville; | ||
1971 | gcicommit.callbackparam = gccallbackinfo; | ||
1972 | |||
1973 | GCDBG(GCZONE_BLIT, | ||
1974 | "gcbv_callback = 0x%08X\n", | ||
1975 | (unsigned int) gcicommit.callback); | ||
1976 | GCDBG(GCZONE_BLIT, | ||
1977 | "gcbv_param = 0x%08X\n", | ||
1978 | (unsigned int) gcicommit.callbackparam); | ||
1979 | GCDBG(GCZONE_BLIT, | ||
1980 | "bltsville_callback = 0x%08X\n", | ||
1981 | (unsigned int) | ||
1982 | gccallbackinfo->info.callback.fn); | ||
1983 | GCDBG(GCZONE_BLIT, | ||
1984 | "bltsville_param = 0x%08X\n", | ||
1985 | (unsigned int) | ||
1986 | gccallbackinfo->info.callback.data); | ||
1987 | } | ||
1988 | |||
1989 | gcicommit.asynchronous = true; | ||
1990 | } | ||
1991 | |||
1992 | /* Process scheduled unmappings. */ | ||
1993 | do_unmap_implicit(gcbatch); | ||
1994 | |||
1995 | INIT_LIST_HEAD(&gcicommit.unmap); | ||
1996 | list_splice_init(&gcbatch->unmap, &gcicommit.unmap); | ||
1997 | |||
1998 | /* Pass the batch for execution. */ | ||
1999 | GCDUMPBATCH(gcbatch); | ||
2000 | |||
2001 | gcicommit.gcerror = GCERR_NONE; | ||
2002 | gcicommit.entrypipe = GCPIPE_2D; | ||
2003 | gcicommit.exitpipe = GCPIPE_2D; | ||
2004 | |||
2005 | INIT_LIST_HEAD(&gcicommit.buffer); | ||
2006 | list_splice_init(&gcbatch->buffer, &gcicommit.buffer); | ||
2007 | |||
2008 | GCDBG(GCZONE_BLIT, "submitting the batch.\n"); | ||
2009 | gc_commit_wrapper(&gcicommit); | ||
2010 | |||
2011 | /* Move the lists back to the batch. */ | ||
2012 | list_splice_init(&gcicommit.buffer, &gcbatch->buffer); | ||
2013 | list_splice_init(&gcicommit.unmap, &gcbatch->unmap); | ||
2014 | |||
2015 | /* Error? */ | ||
2016 | if (gcicommit.gcerror != GCERR_NONE) { | ||
2017 | switch (gcicommit.gcerror) { | ||
2018 | case GCERR_OODM: | ||
2019 | case GCERR_CTX_ALLOC: | ||
2020 | BVSETBLTERROR(BVERR_OOM, | ||
2021 | "unable to allocate gccore " | ||
2022 | "memory"); | ||
2023 | goto exit; | ||
2024 | default: | ||
2025 | BVSETBLTERROR(BVERR_RSRC, | ||
2026 | "gccore error"); | ||
2027 | |||
2028 | goto exit; | ||
2029 | } | ||
2030 | } | ||
2031 | |||
2032 | GCDBG(GCZONE_BLIT, "batch is submitted.\n"); | ||
2033 | } | ||
2034 | |||
2035 | exit: | ||
2036 | if ((gcbatch != NULL) && batchexec) { | ||
2037 | free_batch(gcbatch); | ||
2038 | bvbltparams->batch = NULL; | ||
2039 | } | ||
2040 | |||
2041 | GCEXITARG(GCZONE_BLIT, "bv%s = %d\n", | ||
2042 | (bverror == BVERR_NONE) ? "result" : "error", bverror); | ||
2043 | return bverror; | ||
2044 | } | ||
2045 | |||
2046 | enum bverror bv_cache(struct bvcopparams *copparams) | ||
2047 | { | ||
2048 | enum bverror bverror = BVERR_NONE; | ||
2049 | unsigned int bytespp = 0; /* bytes per pixel */ | ||
2050 | unsigned long vert_offset, horiz_offset; | ||
2051 | unsigned int true_width, true_height; | ||
2052 | |||
2053 | struct c2dmrgn rgn[3]; | ||
2054 | int container_size = 0; | ||
2055 | |||
2056 | unsigned long subsample; | ||
2057 | unsigned long vendor; | ||
2058 | unsigned long layout; | ||
2059 | unsigned long size; | ||
2060 | unsigned long container; | ||
2061 | |||
2062 | subsample = copparams->geom->format & OCDFMTDEF_SUBSAMPLE_MASK; | ||
2063 | vendor = copparams->geom->format & OCDFMTDEF_VENDOR_MASK; | ||
2064 | layout = copparams->geom->format & OCDFMTDEF_LAYOUT_MASK; | ||
2065 | size = copparams->geom->format & OCDFMTDEF_COMPONENTSIZEMINUS1_MASK; | ||
2066 | container = copparams->geom->format & OCDFMTDEF_CONTAINER_MASK; | ||
2067 | |||
2068 | if (vendor != OCDFMTDEF_VENDOR_ALL) { | ||
2069 | bverror = BVERR_FORMAT; | ||
2070 | goto exit; | ||
2071 | } | ||
2072 | |||
2073 | if (copparams->geom->orientation % 180 != 0) { | ||
2074 | true_width = copparams->rect->height; | ||
2075 | true_height = copparams->rect->width; | ||
2076 | } else { | ||
2077 | true_width = copparams->rect->width; | ||
2078 | true_height = copparams->rect->height; | ||
2079 | } | ||
2080 | |||
2081 | switch (container) { | ||
2082 | case OCDFMTDEF_CONTAINER_8BIT: | ||
2083 | container_size = 8; | ||
2084 | break; | ||
2085 | |||
2086 | case OCDFMTDEF_CONTAINER_16BIT: | ||
2087 | container_size = 16; | ||
2088 | break; | ||
2089 | |||
2090 | case OCDFMTDEF_CONTAINER_24BIT: | ||
2091 | container_size = 24; | ||
2092 | break; | ||
2093 | |||
2094 | case OCDFMTDEF_CONTAINER_32BIT: | ||
2095 | container_size = 32; | ||
2096 | break; | ||
2097 | |||
2098 | case OCDFMTDEF_CONTAINER_48BIT: | ||
2099 | container_size = 48; | ||
2100 | break; | ||
2101 | |||
2102 | case OCDFMTDEF_CONTAINER_64BIT: | ||
2103 | container_size = 64; | ||
2104 | break; | ||
2105 | } | ||
2106 | |||
2107 | switch (layout) { | ||
2108 | case OCDFMTDEF_PACKED: | ||
2109 | switch (subsample) { | ||
2110 | case OCDFMTDEF_SUBSAMPLE_NONE: | ||
2111 | if (size >= 8) { | ||
2112 | bytespp = container_size / 8; | ||
2113 | } else { | ||
2114 | GCERR("format not supported.\n"); | ||
2115 | bverror = BVERR_FORMAT; | ||
2116 | goto exit; | ||
2117 | } | ||
2118 | break; | ||
2119 | |||
2120 | case OCDFMTDEF_SUBSAMPLE_422_YCbCr: | ||
2121 | bytespp = (container_size / 2) / 8; | ||
2122 | break; | ||
2123 | |||
2124 | default: | ||
2125 | bverror = BVERR_FORMAT; | ||
2126 | goto exit; | ||
2127 | } | ||
2128 | |||
2129 | rgn[0].span = true_width * bytespp; | ||
2130 | rgn[0].lines = true_height; | ||
2131 | rgn[0].stride = copparams->geom->virtstride; | ||
2132 | horiz_offset = copparams->rect->left * bytespp; | ||
2133 | vert_offset = copparams->rect->top; | ||
2134 | |||
2135 | rgn[0].start = (void *) ((unsigned long) | ||
2136 | copparams->desc->virtaddr + | ||
2137 | vert_offset * rgn[0].stride + | ||
2138 | horiz_offset); | ||
2139 | |||
2140 | gcbvcacheop(1, rgn, copparams->cacheop); | ||
2141 | break; | ||
2142 | |||
2143 | case OCDFMTDEF_2_PLANE_YCbCr: | ||
2144 | /* 1 byte per pixel */ | ||
2145 | rgn[0].span = true_width; | ||
2146 | rgn[0].lines = true_height; | ||
2147 | rgn[0].stride = copparams->geom->virtstride; | ||
2148 | rgn[0].start = (void *) | ||
2149 | ((unsigned long) copparams->desc->virtaddr + | ||
2150 | copparams->rect->top * rgn[0].stride + | ||
2151 | copparams->rect->left); | ||
2152 | |||
2153 | rgn[1].span = true_width; | ||
2154 | rgn[1].lines = true_height / 2; | ||
2155 | rgn[1].stride = copparams->geom->virtstride; | ||
2156 | rgn[1].start = rgn[0].start + | ||
2157 | copparams->geom->height * rgn[0].stride; | ||
2158 | |||
2159 | GCDBG(GCZONE_CACHE, | ||
2160 | "virtaddr %p start[0] 0x%08x start[1] 0x%08x\n", | ||
2161 | copparams->desc->virtaddr, rgn[0].start, rgn[1].start); | ||
2162 | |||
2163 | gcbvcacheop(2, rgn, copparams->cacheop); | ||
2164 | break; | ||
2165 | |||
2166 | default: | ||
2167 | GCERR("format 0x%x (%d) not supported.\n", | ||
2168 | copparams->geom->format, copparams->geom->format); | ||
2169 | bverror = BVERR_FORMAT; | ||
2170 | break; | ||
2171 | } | ||
2172 | |||
2173 | exit: | ||
2174 | if (bverror != BVERR_NONE) | ||
2175 | GCERR("bverror = %d\n", bverror); | ||
2176 | |||
2177 | return bverror; | ||
2178 | } | ||