aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/gcx/gcbv/gcbv.c')
-rw-r--r--drivers/misc/gcx/gcbv/gcbv.c2178
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
72GCDBG_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
91struct 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
109static 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
149static 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) \
193do { \
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
213struct bvsurferrorid {
214 char *id;
215 enum bverror base;
216};
217
218struct bvsurferror {
219 unsigned int offset;
220 char *message;
221};
222
223static 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
252static struct bvsurferrorid g_destsurferr = { "dst", BVERR_DSTDESC };
253static struct bvsurferrorid g_src1surferr = { "src1", BVERR_SRC1DESC };
254static struct bvsurferrorid g_src2surferr = { "src2", BVERR_SRC2DESC };
255static struct bvsurferrorid g_masksurferr = { "mask", BVERR_MASKDESC };
256
257
258/*******************************************************************************
259 * Callback info management.
260 */
261
262/* BLTsville callback function. */
263struct 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. */
272struct 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. */
281struct 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
294static 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
321exit:
322 /* Unlock access to callback info lists. */
323 GCUNLOCK(&gccontext->callbacklock);
324
325 return bverror;
326}
327
328static 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
341void 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
360void 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
384enum 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
432exit:
433 GCEXIT(GCZONE_TEMP);
434 return bverror;
435}
436
437enum 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
492exit:
493 return bverror;
494}
495
496
497/*******************************************************************************
498 * Program the destination.
499 */
500
501enum 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
547exit:
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
558enum 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
633exit:
634 GCEXITARG(GCZONE_BLEND, "bv%s = %d\n",
635 (bverror == BVERR_NONE) ? "result" : "error", bverror);
636 return bverror;
637}
638
639enum 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
720exit:
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
730void 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
809enum 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
902exit:
903 GCEXITARG(GCZONE_SRC, "bv%s = %d\n",
904 (bverror == BVERR_NONE) ? "result" : "error", bverror);
905 return bverror;
906}
907
908enum 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
1015exit:
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
1026static 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. */
1045static 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
1091static 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
1128static 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
1257void 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
1336void 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
1403enum 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
1423exit:
1424 GCEXITARG(GCZONE_MAPPING, "bv%s = %d\n",
1425 (bverror == BVERR_NONE) ? "result" : "error", bverror);
1426 return bverror;
1427}
1428
1429enum 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
1554exit:
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
1563enum 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
2035exit:
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
2046enum 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
2173exit:
2174 if (bverror != BVERR_NONE)
2175 GCERR("bverror = %d\n", bverror);
2176
2177 return bverror;
2178}