summaryrefslogtreecommitdiffstats
path: root/bltsville/gcbv/mirror/gcbuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'bltsville/gcbv/mirror/gcbuffer.c')
-rw-r--r--bltsville/gcbv/mirror/gcbuffer.c383
1 files changed, 383 insertions, 0 deletions
diff --git a/bltsville/gcbv/mirror/gcbuffer.c b/bltsville/gcbv/mirror/gcbuffer.c
new file mode 100644
index 0000000..7c77d4a
--- /dev/null
+++ b/bltsville/gcbv/mirror/gcbuffer.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright(c) 2012,
+ * Texas Instruments, Inc. and Vivante Corporation.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Vivante Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gcbv.h"
+
+#define GCZONE_NONE 0
+#define GCZONE_ALL (~0U)
+#define GCZONE_BATCH_ALLOC (1 << 0)
+#define GCZONE_BUFFER_ALLOC (1 << 1)
+#define GCZONE_FIXUP_ALLOC (1 << 2)
+#define GCZONE_FIXUP (1 << 3)
+
+GCDBG_FILTERDEF(buffer, GCZONE_NONE,
+ "batchalloc",
+ "bufferalloc"
+ "fixupalloc",
+ "fixup")
+
+
+/*******************************************************************************
+** Miscellaneous defines and macros.
+*/
+
+#define GC_BUFFER_INIT_SIZE \
+( \
+ GC_BUFFER_SIZE - max(sizeof(struct gcbuffer), GC_BUFFER_RESERVE) \
+)
+
+#define GC_BUFFER_RESERVE \
+( \
+ sizeof(struct gcmopipesel) + \
+ sizeof(struct gcmommumaster) + \
+ sizeof(struct gcmommuflush) + \
+ sizeof(struct gcmosignal) + \
+ sizeof(struct gccmdend) \
+)
+
+
+/*******************************************************************************
+ * Batch/command buffer management.
+ */
+
+enum bverror do_end(struct bvbltparams *bvbltparams,
+ struct gcbatch *gcbatch)
+{
+ return BVERR_NONE;
+}
+
+enum bverror allocate_batch(struct bvbltparams *bvbltparams,
+ struct gcbatch **gcbatch)
+{
+ enum bverror bverror;
+ struct gccontext *gccontext = get_context();
+ struct gcbatch *temp;
+ struct gcbuffer *gcbuffer;
+
+ GCENTER(GCZONE_BATCH_ALLOC);
+
+ /* Lock access to batch management. */
+ GCLOCK(&gccontext->batchlock);
+
+ if (list_empty(&gccontext->batchvac)) {
+ temp = gcalloc(struct gcbatch, sizeof(struct gcbatch));
+ if (temp == NULL) {
+ BVSETBLTERROR(BVERR_OOM,
+ "batch header allocation failed");
+ goto exit;
+ }
+
+ GCDBG(GCZONE_BATCH_ALLOC, "allocated new batch = 0x%08X\n",
+ (unsigned int) temp);
+ } else {
+ struct list_head *head;
+ head = gccontext->batchvac.next;
+ temp = list_entry(head, struct gcbatch, link);
+ list_del(head);
+
+ GCDBG(GCZONE_BATCH_ALLOC, "reusing batch = 0x%08X\n",
+ (unsigned int) temp);
+ }
+
+ memset(temp, 0, sizeof(struct gcbatch));
+ temp->structsize = sizeof(struct gcbatch);
+ temp->batchend = do_end;
+ INIT_LIST_HEAD(&temp->buffer);
+ INIT_LIST_HEAD(&temp->unmap);
+ INIT_LIST_HEAD(&temp->link);
+
+ bverror = append_buffer(bvbltparams, temp, &gcbuffer);
+ if (bverror != BVERR_NONE) {
+ free_batch(temp);
+ goto exit;
+ }
+
+ *gcbatch = temp;
+
+ GCDBG(GCZONE_BATCH_ALLOC, "batch allocated = 0x%08X\n",
+ (unsigned int) temp);
+
+exit:
+ /* Unlock access to batch management. */
+ GCUNLOCK(&gccontext->batchlock);
+
+ GCEXITARG(GCZONE_BATCH_ALLOC, "bv%s = %d\n",
+ (bverror == BVERR_NONE) ? "result" : "error", bverror);
+ return bverror;
+}
+
+void free_batch(struct gcbatch *gcbatch)
+{
+ struct list_head *head;
+ struct gccontext *gccontext = get_context();
+ struct gcbuffer *gcbuffer;
+
+ GCENTERARG(GCZONE_BATCH_ALLOC, "batch = 0x%08X\n",
+ (unsigned int) gcbatch);
+
+ /* Lock access. */
+ GCLOCK(&gccontext->batchlock);
+ GCLOCK(&gccontext->bufferlock);
+ GCLOCK(&gccontext->fixuplock);
+ GCLOCK(&gccontext->maplock);
+
+ /* Free implicit unmappings. */
+ list_splice_init(&gcbatch->unmap, &gccontext->unmapvac);
+
+ /* Free command buffers. */
+ while (!list_empty(&gcbatch->buffer)) {
+ head = gcbatch->buffer.next;
+ gcbuffer = list_entry(head, struct gcbuffer, link);
+
+ /* Free fixups. */
+ list_splice_init(&gcbuffer->fixup, &gccontext->fixupvac);
+
+ /* Free the command buffer. */
+ list_move(&gcbuffer->link, &gccontext->buffervac);
+ }
+
+ /* Free the batch. */
+ list_add(&gcbatch->link, &gccontext->batchvac);
+
+ /* Unlock access. */
+ GCUNLOCK(&gccontext->maplock);
+ GCUNLOCK(&gccontext->fixuplock);
+ GCUNLOCK(&gccontext->bufferlock);
+ GCUNLOCK(&gccontext->batchlock);
+
+ GCEXIT(GCZONE_BATCH_ALLOC);
+}
+
+enum bverror append_buffer(struct bvbltparams *bvbltparams,
+ struct gcbatch *gcbatch,
+ struct gcbuffer **gcbuffer)
+{
+ enum bverror bverror;
+ struct gccontext *gccontext = get_context();
+ struct gcbuffer *temp;
+
+ GCENTERARG(GCZONE_BUFFER_ALLOC, "batch = 0x%08X\n",
+ (unsigned int) gcbatch);
+
+ /* Lock access to buffer management. */
+ GCLOCK(&gccontext->bufferlock);
+
+ if (list_empty(&gccontext->buffervac)) {
+ temp = gcalloc(struct gcbuffer, GC_BUFFER_SIZE);
+ if (temp == NULL) {
+ BVSETBLTERROR(BVERR_OOM,
+ "command buffer allocation failed");
+ goto exit;
+ }
+
+ list_add_tail(&temp->link, &gcbatch->buffer);
+
+ GCDBG(GCZONE_BUFFER_ALLOC, "allocated new buffer = 0x%08X\n",
+ (unsigned int) temp);
+ } else {
+ struct list_head *head;
+ head = gccontext->buffervac.next;
+ temp = list_entry(head, struct gcbuffer, link);
+
+ list_move_tail(&temp->link, &gcbatch->buffer);
+
+ GCDBG(GCZONE_BUFFER_ALLOC, "reusing buffer = 0x%08X\n",
+ (unsigned int) temp);
+ }
+
+ INIT_LIST_HEAD(&temp->fixup);
+ temp->pixelcount = 0;
+ temp->head = temp->tail = (unsigned int *) (temp + 1);
+ temp->available = GC_BUFFER_INIT_SIZE;
+
+ GCDBG(GCZONE_BUFFER_ALLOC, "new buffer appended = 0x%08X\n",
+ (unsigned int) temp);
+
+ *gcbuffer = temp;
+ bverror = BVERR_NONE;
+
+exit:
+ /* Unlock access to buffer management. */
+ GCUNLOCK(&gccontext->bufferlock);
+
+ GCEXITARG(GCZONE_BUFFER_ALLOC, "bv%s = %d\n",
+ (bverror == BVERR_NONE) ? "result" : "error", bverror);
+ return bverror;
+}
+
+static enum bverror allocate_fixup(struct bvbltparams *bvbltparams,
+ struct gcbuffer *gcbuffer,
+ struct gcfixup **gcfixup)
+{
+ enum bverror bverror = BVERR_NONE;
+ struct gccontext *gccontext = get_context();
+ struct gcfixup *temp;
+
+ if (list_empty(&gccontext->fixupvac)) {
+ temp = gcalloc(struct gcfixup, sizeof(struct gcfixup));
+ if (temp == NULL) {
+ BVSETBLTERROR(BVERR_OOM, "fixup allocation failed");
+ goto exit;
+ }
+
+ list_add_tail(&temp->link, &gcbuffer->fixup);
+
+ GCDBG(GCZONE_FIXUP_ALLOC,
+ "new fixup struct allocated = 0x%08X\n",
+ (unsigned int) temp);
+ } else {
+ struct list_head *head;
+ head = gccontext->fixupvac.next;
+ temp = list_entry(head, struct gcfixup, link);
+
+ list_move_tail(&temp->link, &gcbuffer->fixup);
+
+ GCDBG(GCZONE_FIXUP_ALLOC, "fixup struct reused = 0x%08X\n",
+ (unsigned int) temp);
+ }
+
+ temp->count = 0;
+ *gcfixup = temp;
+
+exit:
+ return bverror;
+}
+
+enum bverror add_fixup(struct bvbltparams *bvbltparams,
+ struct gcbatch *gcbatch,
+ unsigned int *ptr,
+ unsigned int surfoffset)
+{
+ enum bverror bverror = BVERR_NONE;
+ struct gccontext *gccontext = get_context();
+ struct list_head *head;
+ struct gcbuffer *buffer;
+ struct gcfixup *gcfixup;
+
+ GCENTERARG(GCZONE_FIXUP, "batch = 0x%08X, fixup ptr = 0x%08X\n",
+ (unsigned int) gcbatch, (unsigned int) ptr);
+
+ /* Lock access to fixup management. */
+ GCLOCK(&gccontext->fixuplock);
+
+ /* Get the current command buffer. */
+ if (list_empty(&gcbatch->buffer)) {
+ GCERR("no command buffers are allocated");
+ goto exit;
+ }
+ head = gcbatch->buffer.prev;
+ buffer = list_entry(head, struct gcbuffer, link);
+
+ /* No fixups? Allocate one. */
+ if (list_empty(&buffer->fixup)) {
+ GCDBG(GCZONE_FIXUP_ALLOC, "no fixups allocated.\n");
+ bverror = allocate_fixup(bvbltparams, buffer, &gcfixup);
+ if (bverror != BVERR_NONE)
+ goto exit;
+ } else {
+ /* Get the current fixup. */
+ head = buffer->fixup.prev;
+ gcfixup = list_entry(head, struct gcfixup, link);
+
+ /* No more room? */
+ if (gcfixup->count == GC_FIXUP_MAX) {
+ GCDBG(GCZONE_FIXUP_ALLOC,
+ "out of room, allocating new.\n");
+ bverror = allocate_fixup(bvbltparams, buffer, &gcfixup);
+ if (bverror != BVERR_NONE)
+ goto exit;
+ }
+ }
+
+ GCDBG(GCZONE_FIXUP, "buffer = 0x%08X, fixup struct = 0x%08X\n",
+ (unsigned int) buffer, (unsigned int) gcfixup);
+
+ gcfixup->fixup[gcfixup->count].dataoffset = ptr - buffer->head;
+ gcfixup->fixup[gcfixup->count].surfoffset = surfoffset;
+ gcfixup->count += 1;
+
+ GCDBG(GCZONE_FIXUP, "fixup offset = 0x%08X\n", ptr - buffer->head);
+ GCDBG(GCZONE_FIXUP, "surface offset = 0x%08X\n", surfoffset);
+
+exit:
+ /* Unlock access to fixup management. */
+ GCUNLOCK(&gccontext->fixuplock);
+
+ GCEXITARG(GCZONE_FIXUP, "bv%s = %d\n",
+ (bverror == BVERR_NONE) ? "result" : "error", bverror);
+ return bverror;
+}
+
+enum bverror claim_buffer(struct bvbltparams *bvbltparams,
+ struct gcbatch *gcbatch,
+ unsigned int size,
+ void **buffer)
+{
+ enum bverror bverror;
+ struct list_head *head;
+ struct gcbuffer *gcbuffer;
+
+ GCENTERARG(GCZONE_BUFFER_ALLOC, "batch = 0x%08X, size = %d\n",
+ (unsigned int) gcbatch, size);
+
+ if (size > GC_BUFFER_INIT_SIZE) {
+ GCERR("requested size is too big.\n");
+ BVSETBLTERROR(BVERR_OOM,
+ "command buffer allocation failed");
+ goto exit;
+ }
+
+ /* Get the current command buffer. */
+ head = gcbatch->buffer.prev;
+ gcbuffer = list_entry(head, struct gcbuffer, link);
+
+ GCDBG(GCZONE_BUFFER_ALLOC, "buffer = 0x%08X, available = %d\n",
+ (unsigned int) gcbuffer, gcbuffer->available);
+
+ if (gcbuffer->available < size) {
+ bverror = append_buffer(bvbltparams, gcbatch, &gcbuffer);
+ if (bverror != BVERR_NONE)
+ goto exit;
+ }
+
+ *buffer = gcbuffer->tail;
+ gcbuffer->tail = (unsigned int *)
+ ((unsigned char *) gcbuffer->tail + size);
+ gcbuffer->available -= size;
+ gcbatch->size += size;
+ bverror = BVERR_NONE;
+
+exit:
+ GCEXITARG(GCZONE_BUFFER_ALLOC, "bv%s = %d\n",
+ (bverror == BVERR_NONE) ? "result" : "error", bverror);
+ return bverror;
+}