ilo: add command parser
authorChia-I Wu <olv@lunarg.com>
Wed, 12 Dec 2012 20:36:41 +0000 (04:36 +0800)
committerChia-I Wu <olvaffe@gmail.com>
Fri, 26 Apr 2013 08:16:42 +0000 (16:16 +0800)
The command parser manages batch buffers and command submissions.

src/gallium/drivers/ilo/Makefile.sources
src/gallium/drivers/ilo/ilo_cp.c [new file with mode: 0644]
src/gallium/drivers/ilo/ilo_cp.h [new file with mode: 0644]

index 157f6c748f12c649a8e821490992958bf63fbd8c..8911322e9cd95d82832cb85e1dd2359f2fe393a0 100644 (file)
@@ -2,6 +2,7 @@ C_SOURCES := \
        ilo_3d.c \
        ilo_blit.c \
        ilo_context.c \
+       ilo_cp.c \
        ilo_format.c \
        ilo_gpgpu.c \
        ilo_query.c \
diff --git a/src/gallium/drivers/ilo/ilo_cp.c b/src/gallium/drivers/ilo/ilo_cp.c
new file mode 100644 (file)
index 0000000..e0e53d9
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2012-2013 LunarG, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Chia-I Wu <olv@lunarg.com>
+ */
+
+#include "intel_reg.h" /* for MI_xxx */
+#include "intel_winsys.h"
+
+#include "ilo_cp.h"
+
+/* the size of the private space */
+static const int ilo_cp_private = 2;
+
+/**
+ * Dump the contents of the parser bo.  This must be called in a post-flush
+ * hook.
+ */
+void
+ilo_cp_dump(struct ilo_cp *cp)
+{
+   ilo_printf("dumping %d bytes\n", cp->used * 4);
+   if (cp->used)
+      cp->winsys->decode_commands(cp->winsys, cp->bo, cp->used * 4);
+}
+
+/**
+ * Save the command parser state for rewind.
+ *
+ * Note that this cannot rewind a flush, and the caller must make sure
+ * that does not happend.
+ */
+void
+ilo_cp_setjmp(struct ilo_cp *cp, struct ilo_cp_jmp_buf *jmp)
+{
+   jmp->id = pointer_to_intptr(cp->bo);
+
+   jmp->size = cp->size;
+   jmp->used = cp->used;
+   jmp->stolen = cp->stolen;
+   /* save reloc count to rewind ilo_cp_write_bo() */
+   jmp->reloc_count = cp->bo->get_reloc_count(cp->bo);
+}
+
+/**
+ * Rewind to the saved state.
+ */
+void
+ilo_cp_longjmp(struct ilo_cp *cp, const struct ilo_cp_jmp_buf *jmp)
+{
+   if (jmp->id != pointer_to_intptr(cp->bo)) {
+      assert(!"invalid use of CP longjmp");
+      return;
+   }
+
+   cp->size = jmp->size;
+   cp->used = jmp->used;
+   cp->stolen = jmp->stolen;
+   cp->bo->clear_relocs(cp->bo, jmp->reloc_count);
+}
+
+/**
+ * Clear the parser buffer.
+ */
+static void
+ilo_cp_clear_buffer(struct ilo_cp *cp)
+{
+   cp->cmd_cur = 0;
+   cp->cmd_end = 0;
+
+   cp->used = 0;
+   cp->stolen = 0;
+
+   /*
+    * Recalculate cp->size.  This is needed not only because cp->stolen is
+    * reset above, but also that we added cp->reserve_for_pre_flush and
+    * ilo_cp_private to cp->size in ilo_cp_flush().
+    */
+   cp->size = cp->bo_size - (cp->reserve_for_pre_flush + ilo_cp_private);
+}
+
+/**
+ * Add MI_BATCH_BUFFER_END to the private space of the parser buffer.
+ */
+static void
+ilo_cp_end_buffer(struct ilo_cp *cp)
+{
+   /* make the private space available */
+   cp->size += ilo_cp_private;
+
+   assert(cp->used + 2 <= cp->size);
+
+   cp->ptr[cp->used++] = MI_BATCH_BUFFER_END;
+
+   /*
+    * From the Sandy Bridge PRM, volume 1 part 1, page 107:
+    *
+    *     "The batch buffer must be QWord aligned and a multiple of QWords in
+    *      length."
+    */
+   if (cp->used & 1)
+      cp->ptr[cp->used++] = MI_NOOP;
+}
+
+/**
+ * Upload the parser buffer to the bo.
+ */
+static int
+ilo_cp_upload_buffer(struct ilo_cp *cp)
+{
+   int err;
+
+   err = cp->bo->pwrite(cp->bo, 0, cp->used * 4, cp->ptr);
+   if (likely(!err && cp->stolen)) {
+      const int offset = cp->bo_size - cp->stolen;
+
+      err = cp->bo->pwrite(cp->bo, offset * 4,
+            cp->stolen * 4, &cp->ptr[offset]);
+   }
+
+   return err;
+}
+
+/**
+ * Reallocate the parser bo.
+ */
+static void
+ilo_cp_realloc_bo(struct ilo_cp *cp)
+{
+   struct intel_bo *bo;
+
+   /*
+    * allocate the new bo before unreferencing the old one so that they
+    * won't point at the same address, which is needed for jmpbuf
+    */
+   bo = cp->winsys->alloc_buffer(cp->winsys,
+         "batch buffer", cp->bo_size * 4, 0);
+   if (unlikely(!bo))
+      return;
+
+   if (cp->bo)
+      cp->bo->unreference(cp->bo);
+   cp->bo = bo;
+
+   if (!cp->sys) {
+      cp->bo->map(cp->bo, true);
+      cp->ptr = cp->bo->get_virtual(cp->bo);
+   }
+}
+
+/**
+ * Execute the parser bo.
+ */
+static int
+ilo_cp_exec_bo(struct ilo_cp *cp)
+{
+   const bool do_exec = !(ilo_debug & ILO_DEBUG_NOHW);
+   unsigned long flags;
+   int err;
+
+   switch (cp->ring) {
+   case ILO_CP_RING_RENDER:
+      flags = INTEL_EXEC_RENDER;
+      break;
+   case ILO_CP_RING_BLT:
+      flags = INTEL_EXEC_BLT;
+      break;
+   default:
+      flags = 0;
+      break;
+   }
+
+   if (likely(do_exec))
+      err = cp->bo->exec(cp->bo, cp->used * 4, cp->hw_ctx, flags);
+   else
+      err = 0;
+
+   return err;
+}
+
+static void
+ilo_cp_call_hook(struct ilo_cp *cp, enum ilo_cp_hook hook)
+{
+   const bool no_implicit_flush = cp->no_implicit_flush;
+
+   if (!cp->hooks[hook].func)
+      return;
+
+   /* no implicit flush in hooks */
+   cp->no_implicit_flush = true;
+   cp->hooks[hook].func(cp, cp->hooks[hook].data);
+
+   cp->no_implicit_flush = no_implicit_flush;
+}
+
+/**
+ * Flush the command parser and execute the commands.  When the parser buffer
+ * is empty, the hooks are not invoked.
+ */
+void
+ilo_cp_flush(struct ilo_cp *cp)
+{
+   int err;
+
+   /* sanity check */
+   assert(cp->bo_size == cp->size +
+         cp->reserve_for_pre_flush + ilo_cp_private + cp->stolen);
+
+   if (!cp->used) {
+      ilo_cp_clear_buffer(cp);
+      return;
+   }
+
+   /* make the reserved space available temporarily */
+   cp->size += cp->reserve_for_pre_flush;
+   ilo_cp_call_hook(cp, ILO_CP_HOOK_PRE_FLUSH);
+
+   ilo_cp_end_buffer(cp);
+
+   if (cp->sys) {
+      err = ilo_cp_upload_buffer(cp);
+      if (likely(!err))
+         err = ilo_cp_exec_bo(cp);
+   }
+   else {
+      cp->bo->unmap(cp->bo);
+      err = ilo_cp_exec_bo(cp);
+   }
+
+   if (likely(!err)) {
+      ilo_cp_call_hook(cp, ILO_CP_HOOK_POST_FLUSH);
+      ilo_cp_clear_buffer(cp);
+   }
+   else {
+      /* reset first so that post-flush hook knows nothing was executed */
+      ilo_cp_clear_buffer(cp);
+      ilo_cp_call_hook(cp, ILO_CP_HOOK_POST_FLUSH);
+   }
+
+   ilo_cp_realloc_bo(cp);
+   ilo_cp_call_hook(cp, ILO_CP_HOOK_NEW_BATCH);
+}
+
+/**
+ * Destroy the command parser.
+ */
+void
+ilo_cp_destroy(struct ilo_cp *cp)
+{
+   if (cp->bo)
+      cp->bo->unreference(cp->bo);
+   if (cp->hw_ctx)
+      cp->winsys->destroy_context(cp->winsys, cp->hw_ctx);
+
+   FREE(cp->sys);
+   FREE(cp);
+}
+
+/**
+ * Create a command parser.
+ */
+struct ilo_cp *
+ilo_cp_create(struct intel_winsys *winsys, bool direct_map)
+{
+   struct ilo_cp *cp;
+
+   cp = CALLOC_STRUCT(ilo_cp);
+   if (!cp)
+      return NULL;
+
+   cp->winsys = winsys;
+   cp->hw_ctx = winsys->create_context(winsys);
+
+   cp->ring = ILO_CP_RING_RENDER;
+   cp->no_implicit_flush = false;
+   cp->reserve_for_pre_flush = 0;
+
+   memset(cp->hooks, 0, sizeof(cp->hooks));
+
+   cp->bo_size = 8192;
+
+   if (!direct_map) {
+      cp->sys = MALLOC(cp->bo_size * 4);
+      if (!cp->sys) {
+         FREE(cp);
+         return NULL;
+      }
+
+      cp->ptr = cp->sys;
+   }
+
+   ilo_cp_realloc_bo(cp);
+   if (!cp->bo) {
+      FREE(cp->sys);
+      FREE(cp);
+      return NULL;
+   }
+
+   ilo_cp_clear_buffer(cp);
+
+   return cp;
+}
diff --git a/src/gallium/drivers/ilo/ilo_cp.h b/src/gallium/drivers/ilo/ilo_cp.h
new file mode 100644 (file)
index 0000000..8f3bda4
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2012-2013 LunarG, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Chia-I Wu <olv@lunarg.com>
+ */
+
+#ifndef ILO_CP_H
+#define ILO_CP_H
+
+#include "intel_winsys.h"
+
+#include "ilo_common.h"
+
+struct ilo_cp;
+
+enum ilo_cp_ring {
+   ILO_CP_RING_RENDER,
+   ILO_CP_RING_BLT,
+
+   ILO_CP_RING_COUNT,
+};
+
+enum ilo_cp_hook {
+   ILO_CP_HOOK_NEW_BATCH,
+   ILO_CP_HOOK_PRE_FLUSH,
+   ILO_CP_HOOK_POST_FLUSH,
+
+   ILO_CP_HOOK_COUNT,
+};
+
+typedef void (*ilo_cp_hook_func)(struct ilo_cp *cp, void *data);
+
+/**
+ * Command parser.
+ */
+struct ilo_cp {
+   struct intel_winsys *winsys;
+   struct intel_context *hw_ctx;
+
+   enum ilo_cp_ring ring;
+   bool no_implicit_flush;
+   int reserve_for_pre_flush;
+
+   struct {
+      ilo_cp_hook_func func;
+      void *data;
+   } hooks[ILO_CP_HOOK_COUNT];
+
+   int bo_size;
+   struct intel_bo *bo;
+   uint32_t *sys;
+
+   uint32_t *ptr;
+   int size, used, stolen;
+
+   int cmd_cur, cmd_end;
+};
+
+/**
+ * Jump buffer to save command parser state for rewind.
+ */
+struct ilo_cp_jmp_buf {
+   intptr_t id;
+   int size, used, stolen;
+   int reloc_count;
+};
+
+struct ilo_cp *
+ilo_cp_create(struct intel_winsys *winsys, bool direct_map);
+
+void
+ilo_cp_destroy(struct ilo_cp *cp);
+
+void
+ilo_cp_flush(struct ilo_cp *cp);
+
+void
+ilo_cp_dump(struct ilo_cp *cp);
+
+void
+ilo_cp_setjmp(struct ilo_cp *cp, struct ilo_cp_jmp_buf *jmp);
+
+void
+ilo_cp_longjmp(struct ilo_cp *cp, const struct ilo_cp_jmp_buf *jmp);
+
+/**
+ * Return true if the parser buffer is empty.
+ */
+static inline bool
+ilo_cp_empty(struct ilo_cp *cp)
+{
+   return !cp->used;
+}
+
+/**
+ * Return the remaining space (in dwords) in the parser buffer.
+ */
+static inline int
+ilo_cp_space(struct ilo_cp *cp)
+{
+   return cp->size - cp->used;
+}
+
+/**
+ * Internal function called by functions that flush implicitly.
+ */
+static inline void
+ilo_cp_implicit_flush(struct ilo_cp *cp)
+{
+   if (cp->no_implicit_flush) {
+      assert(!"unexpected command parser flush");
+      /* discard the commands */
+      cp->used = 0;
+   }
+
+   ilo_cp_flush(cp);
+}
+
+/**
+ * Set the ring buffer.
+ */
+static inline void
+ilo_cp_set_ring(struct ilo_cp *cp, enum ilo_cp_ring ring)
+{
+   if (cp->ring != ring) {
+      ilo_cp_implicit_flush(cp);
+      cp->ring = ring;
+   }
+}
+
+/**
+ * Assert that no function should flush implicitly.
+ */
+static inline void
+ilo_cp_assert_no_implicit_flush(struct ilo_cp *cp, bool enable)
+{
+   cp->no_implicit_flush = enable;
+}
+
+/**
+ * Reserve the given size of space from the parser buffer.  The reserved space
+ * will be made available temporarily for the pre-flush hook.
+ *
+ * \param reserve size in dwords to reserve.  It may be negative.
+ */
+static inline void
+ilo_cp_reserve_for_pre_flush(struct ilo_cp *cp, int reserve)
+{
+   assert(cp->reserve_for_pre_flush + reserve >= 0);
+
+   if (cp->used > cp->size - reserve) {
+      ilo_cp_implicit_flush(cp);
+      assert(cp->used <= cp->size - reserve);
+   }
+
+   cp->size -= reserve;
+   cp->reserve_for_pre_flush += reserve;
+}
+
+/**
+ * Set a command parser hook.
+ */
+static inline void
+ilo_cp_set_hook(struct ilo_cp *cp, enum ilo_cp_hook hook,
+                ilo_cp_hook_func func, void *data)
+{
+   cp->hooks[hook].func = func;
+   cp->hooks[hook].data = data;
+}
+
+/**
+ * Begin writing a command.
+ */
+static inline void
+ilo_cp_begin(struct ilo_cp *cp, int cmd_size)
+{
+   if (cp->used + cmd_size > cp->size) {
+      ilo_cp_implicit_flush(cp);
+      assert(cp->used + cmd_size <= cp->size);
+   }
+
+   assert(cp->cmd_cur == cp->cmd_end);
+   cp->cmd_cur = cp->used;
+   cp->cmd_end = cp->cmd_cur + cmd_size;
+   cp->used = cp->cmd_end;
+}
+
+/**
+ * Begin writing data to a space stolen from the top of the parser buffer.
+ *
+ * \param desc informative description of the data to be written
+ * \param data_size in dwords
+ * \param align in dwords
+ * \param bo_offset in bytes to the stolen space
+ */
+static inline void
+ilo_cp_steal(struct ilo_cp *cp, const char *desc,
+             int data_size, int align, uint32_t *bo_offset)
+{
+   int pad, steal;
+
+   if (!align)
+      align = 1;
+
+   pad = (cp->bo_size - cp->stolen - data_size) % align;
+   steal = data_size + pad;
+
+   /* flush if there is not enough space after stealing */
+   if (cp->used > cp->size - steal) {
+      ilo_cp_implicit_flush(cp);
+
+      pad = (cp->bo_size - cp->stolen - data_size) % align;
+      steal = data_size + steal;
+
+      assert(cp->used <= cp->size - steal);
+   }
+
+   cp->size -= steal;
+   cp->stolen += steal;
+
+   assert(cp->cmd_cur == cp->cmd_end);
+   cp->cmd_cur = cp->bo_size - cp->stolen;
+   cp->cmd_end = cp->cmd_cur + data_size;
+
+   /* offset in cp->bo */
+   if (bo_offset)
+      *bo_offset = cp->cmd_cur * 4;
+}
+
+/**
+ * Write a dword to the parser buffer.  This function must be enclosed by
+ * ilo_cp_begin()/ilo_cp_steal() and ilo_cp_end().
+ */
+static inline void
+ilo_cp_write(struct ilo_cp *cp, uint32_t val)
+{
+   assert(cp->cmd_cur < cp->cmd_end);
+   cp->ptr[cp->cmd_cur++] = val;
+}
+
+/**
+ * Write multiple dwords to the parser buffer.
+ */
+static inline void
+ilo_cp_write_multi(struct ilo_cp *cp, const void *vals, int num_vals)
+{
+   assert(cp->cmd_cur + num_vals <= cp->cmd_end);
+   memcpy(cp->ptr + cp->cmd_cur, vals, num_vals * 4);
+   cp->cmd_cur += num_vals;
+}
+
+/**
+ * Write a bo to the parser buffer.  In addition to writing the offset of the
+ * bo to the buffer, it also emits a relocation.
+ */
+static inline void
+ilo_cp_write_bo(struct ilo_cp *cp, uint32_t val, struct intel_bo *bo,
+                uint32_t read_domains, uint32_t write_domain)
+{
+   if (bo) {
+      cp->bo->emit_reloc(cp->bo, cp->cmd_cur * 4,
+            bo, val, read_domains, write_domain);
+
+      ilo_cp_write(cp, val + bo->get_offset(bo));
+   }
+   else {
+      ilo_cp_write(cp, val);
+   }
+}
+
+/**
+ * End a command.  Every ilo_cp_begin() or ilo_cp_steal() must have a
+ * matching ilo_cp_end().
+ */
+static inline void
+ilo_cp_end(struct ilo_cp *cp)
+{
+   assert(cp->cmd_cur == cp->cmd_end);
+}
+
+/**
+ * A variant of ilo_cp_steal() where the data are written via the returned
+ * pointer.
+ *
+ * \return ptr pointer where the data are written to.  It is valid until any
+ *             change is made to the parser.
+ */
+static inline void *
+ilo_cp_steal_ptr(struct ilo_cp *cp, const char *desc,
+                 int data_size, int align, uint32_t *bo_offset)
+{
+   void *ptr;
+
+   ilo_cp_steal(cp, desc, data_size, align, bo_offset);
+
+   ptr = &cp->ptr[cp->cmd_cur];
+   cp->cmd_cur = cp->cmd_end;
+
+   ilo_cp_end(cp);
+
+   return ptr;
+}
+
+#endif /* ILO_CP_H */