intel: implement command buffer create/begin/end/reset
diff --git a/icd/intel/cmd.c b/icd/intel/cmd.c
index 6af4a6b..389f2d4 100644
--- a/icd/intel/cmd.c
+++ b/icd/intel/cmd.c
@@ -22,33 +22,202 @@
* DEALINGS IN THE SOFTWARE.
*/
+#include "genhw/genhw.h"
+#include "kmd/winsys.h"
+#include "dev.h"
+#include "obj.h"
#include "cmd.h"
+/* reserved space used for intel_cmd_end() */
+static const XGL_UINT intel_cmd_reserved = 2;
+
+static XGL_RESULT cmd_alloc_and_map(struct intel_cmd *cmd, XGL_SIZE bo_size)
+{
+ struct intel_winsys *winsys = cmd->dev->winsys;
+ struct intel_bo *bo;
+ void *ptr;
+
+ bo = intel_winsys_alloc_buffer(winsys,
+ "batch buffer", bo_size, INTEL_DOMAIN_CPU);
+ if (!bo)
+ return XGL_ERROR_OUT_OF_GPU_MEMORY;
+
+ ptr = intel_bo_map(bo, true);
+ if (!bo) {
+ intel_bo_unreference(bo);
+ return XGL_ERROR_MEMORY_MAP_FAILED;
+ }
+
+ cmd->bo_size = bo_size;
+ cmd->bo = bo;
+ cmd->ptr = ptr;
+ cmd->size = bo_size / sizeof(uint32_t) - intel_cmd_reserved;
+
+ return XGL_SUCCESS;
+}
+
+static void cmd_unmap(struct intel_cmd *cmd)
+{
+ intel_bo_unmap(cmd->bo);
+ cmd->ptr = NULL;
+}
+
+static void cmd_free(struct intel_cmd *cmd)
+{
+ intel_bo_unreference(cmd->bo);
+ cmd->bo = NULL;
+}
+
+static void cmd_reset(struct intel_cmd *cmd)
+{
+ if (cmd->ptr)
+ cmd_unmap(cmd);
+ if (cmd->bo)
+ cmd_free(cmd);
+
+ cmd->used = 0;
+ cmd->size = 0;
+ cmd->grow_failed = false;
+}
+
+static void cmd_destroy(struct intel_obj *obj)
+{
+ struct intel_cmd *cmd = intel_cmd_from_obj(obj);
+
+ intel_cmd_destroy(cmd);
+}
+
+XGL_RESULT intel_cmd_create(struct intel_dev *dev,
+ const XGL_CMD_BUFFER_CREATE_INFO *info,
+ struct intel_cmd **cmd_ret)
+{
+ struct intel_cmd *cmd;
+
+ cmd = (struct intel_cmd *) intel_base_create(dev, sizeof(*cmd),
+ dev->base.dbg, XGL_DBG_OBJECT_CMD_BUFFER, info, 0);
+ if (!cmd)
+ return XGL_ERROR_OUT_OF_MEMORY;
+
+ cmd->obj.destroy = cmd_destroy;
+
+ cmd->dev = dev;
+
+ *cmd_ret = cmd;
+
+ return XGL_SUCCESS;
+}
+
+void intel_cmd_destroy(struct intel_cmd *cmd)
+{
+ cmd_reset(cmd);
+ intel_base_destroy(&cmd->obj.base);
+}
+
+XGL_RESULT intel_cmd_begin(struct intel_cmd *cmd, XGL_FLAGS flags)
+{
+ XGL_SIZE bo_size = cmd->bo_size;
+
+ cmd_reset(cmd);
+
+ if (cmd->flags != flags || !bo_size) {
+ cmd->flags = flags;
+
+ bo_size = cmd->dev->gpu->batch_buffer_size;
+ if (flags & XGL_CMD_BUFFER_OPTIMIZE_GPU_SMALL_BATCH_BIT)
+ bo_size /= 2;
+
+ bo_size &= ~(sizeof(uint32_t) - 1);
+ }
+
+ return cmd_alloc_and_map(cmd, bo_size);
+}
+
+XGL_RESULT intel_cmd_end(struct intel_cmd *cmd)
+{
+ struct intel_winsys *winsys = cmd->dev->winsys;
+
+ /* reclaim the reserved space */
+ cmd->size += intel_cmd_reserved;
+
+ cmd->ptr[cmd->used++] = GEN_MI_CMD(MI_BATCH_BUFFER_END);
+
+ /* pad to even dwords */
+ if (cmd->used & 1)
+ cmd->ptr[cmd->used++] = GEN_MI_CMD(MI_NOOP);
+
+ assert(cmd->used <= cmd->size);
+
+ cmd_unmap(cmd);
+
+ if (cmd->grow_failed)
+ return XGL_ERROR_OUT_OF_GPU_MEMORY;
+ else if (intel_winsys_can_submit_bo(winsys, &cmd->bo, 1))
+ return XGL_SUCCESS;
+ else
+ return XGL_ERROR_TOO_MANY_MEMORY_REFERENCES;
+}
+
+void intel_cmd_grow(struct intel_cmd *cmd)
+{
+ const XGL_SIZE bo_size = cmd->bo_size << 1;
+ struct intel_bo *old_bo = cmd->bo;
+ uint32_t *old_ptr = cmd->ptr;
+
+ if (bo_size >= cmd->bo_size &&
+ cmd_alloc_and_map(cmd, bo_size) == XGL_SUCCESS) {
+ memcpy(cmd->ptr, old_ptr, cmd->used * sizeof(uint32_t));
+ /* XXX winsys does not let us copy relocs */
+ cmd->grow_failed = true;
+
+ intel_bo_unmap(old_bo);
+ intel_bo_unreference(old_bo);
+ } else {
+ intel_dev_log(cmd->dev, XGL_DBG_MSG_ERROR,
+ XGL_VALIDATION_LEVEL_0, XGL_NULL_HANDLE, 0, 0,
+ "failed to grow command buffer of size %u", cmd->bo_size);
+
+ /* wrap it and fail silently */
+ cmd->used = 0;
+ cmd->grow_failed = true;
+ }
+}
+
XGL_RESULT XGLAPI intelCreateCommandBuffer(
XGL_DEVICE device,
const XGL_CMD_BUFFER_CREATE_INFO* pCreateInfo,
XGL_CMD_BUFFER* pCmdBuffer)
{
- return XGL_ERROR_UNAVAILABLE;
+ struct intel_dev *dev = intel_dev(device);
+
+ return intel_cmd_create(dev, pCreateInfo,
+ (struct intel_cmd **) pCmdBuffer);
}
XGL_RESULT XGLAPI intelBeginCommandBuffer(
XGL_CMD_BUFFER cmdBuffer,
XGL_FLAGS flags)
{
- return XGL_ERROR_UNAVAILABLE;
+ struct intel_cmd *cmd = intel_cmd(cmdBuffer);
+
+ return intel_cmd_begin(cmd, flags);
}
XGL_RESULT XGLAPI intelEndCommandBuffer(
XGL_CMD_BUFFER cmdBuffer)
{
- return XGL_ERROR_UNAVAILABLE;
+ struct intel_cmd *cmd = intel_cmd(cmdBuffer);
+
+ return intel_cmd_end(cmd);
}
XGL_RESULT XGLAPI intelResetCommandBuffer(
XGL_CMD_BUFFER cmdBuffer)
{
- return XGL_ERROR_UNAVAILABLE;
+ struct intel_cmd *cmd = intel_cmd(cmdBuffer);
+
+ cmd_reset(cmd);
+
+ return XGL_SUCCESS;
}
XGL_VOID XGLAPI intelCmdBindPipeline(