| /************************************************************************** |
| * |
| * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. |
| * All Rights Reserved. |
| * |
| * Copyright 2014, 2015 Intel Corporation |
| * All Rights Reserved. |
| * |
| * 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, sub license, 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 (including the |
| * next paragraph) 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 NON-INFRINGEMENT. |
| * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. |
| * |
| **************************************************************************/ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <assert.h> |
| |
| #include "intel_batchbuffer.h" |
| |
| void bb_area_emit(struct bb_area *a, uint32_t dword, item_type type, const char *str) |
| { |
| struct bb_item *item; |
| assert(a != NULL); |
| assert(a->num_items < MAX_ITEMS); |
| item = &a->item[a->num_items]; |
| |
| item->data = dword; |
| item->type = type; |
| strncpy(item->str, str, MAX_STRLEN); |
| item->str[MAX_STRLEN - 1] = 0; |
| |
| a->num_items++; |
| } |
| |
| void bb_area_emit_offset(struct bb_area *a, unsigned offset, uint32_t dword, item_type type, const char *str) |
| { |
| const unsigned i = offset / 4; |
| struct bb_item *item; |
| assert(a != NULL); |
| assert(a->num_items < MAX_ITEMS); |
| assert(i < a->num_items); |
| item = &a->item[i]; |
| |
| item->data = dword; |
| item->type = type; |
| strncpy(item->str, str, MAX_STRLEN); |
| item->str[MAX_STRLEN - 1] = 0; |
| } |
| |
| static struct bb_item *bb_area_get(struct bb_area *a, unsigned i) |
| { |
| assert (i < a->num_items); |
| return &a->item[i]; |
| } |
| |
| static unsigned bb_area_items(struct bb_area *a) |
| { |
| return a->num_items; |
| } |
| |
| static unsigned long bb_area_used(struct bb_area *a) |
| { |
| assert(a != NULL); |
| assert(a->num_items <= MAX_ITEMS); |
| |
| return a->num_items * 4; |
| } |
| |
| static unsigned long bb_area_room(struct bb_area *a) |
| { |
| assert (a != NULL); |
| assert (a->num_items <= MAX_ITEMS); |
| |
| return (MAX_ITEMS - a->num_items) * 4; |
| } |
| |
| struct intel_batchbuffer *intel_batchbuffer_create(void) |
| { |
| struct intel_batchbuffer *batch; |
| |
| batch = calloc(1, sizeof(*batch)); |
| if (batch == NULL) |
| return NULL; |
| |
| batch->cmds = calloc(1, sizeof(struct bb_area)); |
| if (batch->cmds == NULL) { |
| free(batch); |
| return NULL; |
| } |
| |
| batch->state = calloc(1, sizeof(struct bb_area)); |
| if (batch->state == NULL) { |
| free(batch->cmds); |
| free(batch); |
| return NULL; |
| } |
| |
| batch->state_start_offset = -1; |
| batch->cmds_end_offset = -1; |
| |
| return batch; |
| } |
| |
| static void bb_area_align(struct bb_area *a, unsigned align) |
| { |
| if (align == 0) |
| return; |
| |
| assert((align % 4) == 0); |
| |
| while ((a->num_items * 4) % align != 0) |
| bb_area_emit(a, 0, PAD, "align pad"); |
| } |
| |
| static int reloc_exists(struct intel_batchbuffer *batch, uint32_t offset) |
| { |
| int i; |
| |
| for (i = 0; i < batch->cmds->num_items; i++) |
| if ((batch->cmds->item[i].type == RELOC || |
| batch->cmds->item[i].type == RELOC_STATE) && |
| i * 4 == offset) |
| return 1; |
| |
| return 0; |
| } |
| |
| int intel_batch_is_reloc(struct intel_batchbuffer *batch, unsigned i) |
| { |
| return reloc_exists(batch, i * 4); |
| } |
| |
| static void intel_batch_cmd_align(struct intel_batchbuffer *batch, unsigned align) |
| { |
| bb_area_align(batch->cmds, align); |
| } |
| |
| static void intel_batch_state_align(struct intel_batchbuffer *batch, unsigned align) |
| { |
| bb_area_align(batch->state, align); |
| } |
| |
| unsigned intel_batch_num_cmds(struct intel_batchbuffer *batch) |
| { |
| return bb_area_items(batch->cmds); |
| } |
| |
| unsigned intel_batch_num_state(struct intel_batchbuffer *batch) |
| { |
| return bb_area_items(batch->state); |
| } |
| |
| struct bb_item *intel_batch_cmd_get(struct intel_batchbuffer *batch, unsigned i) |
| { |
| return bb_area_get(batch->cmds, i); |
| } |
| |
| struct bb_item *intel_batch_state_get(struct intel_batchbuffer *batch, unsigned i) |
| { |
| return bb_area_get(batch->state, i); |
| } |
| |
| uint32_t intel_batch_state_offset(struct intel_batchbuffer *batch, unsigned align) |
| { |
| intel_batch_state_align(batch, align); |
| return bb_area_used(batch->state); |
| } |
| |
| uint32_t intel_batch_state_alloc(struct intel_batchbuffer *batch, unsigned bytes, unsigned align, |
| const char *str) |
| { |
| unsigned offset; |
| unsigned dwords = bytes/4; |
| assert ((bytes % 4) == 0); |
| assert (bb_area_room(batch->state) >= bytes); |
| |
| offset = intel_batch_state_offset(batch, align); |
| |
| while (dwords--) |
| bb_area_emit(batch->state, 0, UNINITIALIZED, str); |
| |
| return offset; |
| } |
| |
| uint32_t intel_batch_state_copy(struct intel_batchbuffer *batch, |
| void *d, unsigned bytes, |
| unsigned align, |
| const char *str) |
| { |
| unsigned offset; |
| unsigned i; |
| unsigned dwords = bytes/4; |
| assert (d); |
| assert ((bytes % 4) == 0); |
| assert (bb_area_room(batch->state) >= bytes); |
| |
| offset = intel_batch_state_offset(batch, align); |
| |
| for (i = 0; i < dwords; i++) { |
| char offsetinside[80]; |
| uint32_t *s; |
| sprintf(offsetinside, "%s: 0x%x", str, i * 4); |
| |
| s = (uint32_t *)(uint8_t *)d + i; |
| bb_area_emit(batch->state, *s, STATE, offsetinside); |
| } |
| |
| return offset; |
| } |
| |
| void intel_batch_relocate_state(struct intel_batchbuffer *batch) |
| { |
| unsigned int i; |
| |
| assert (batch->state_start_offset == -1); |
| |
| batch->cmds_end_offset = bb_area_used(batch->cmds) - 4; |
| |
| /* Hardcoded, could track max align done also */ |
| intel_batch_cmd_align(batch, 64); |
| |
| batch->state_start_offset = bb_area_used(batch->cmds); |
| |
| for (i = 0; i < bb_area_items(batch->state); i++) { |
| const struct bb_item *s = bb_area_get(batch->state, i); |
| |
| bb_area_emit(batch->cmds, s->data, s->type, s->str); |
| } |
| |
| for (i = 0; i < bb_area_items(batch->cmds); i++) { |
| struct bb_item *s = bb_area_get(batch->cmds, i); |
| |
| if (s->type == STATE_OFFSET || s->type == RELOC_STATE) |
| s->data += batch->state_start_offset; |
| } |
| } |
| |
| const char *intel_batch_type_as_str(const struct bb_item *item) |
| { |
| switch (item->type) { |
| case UNINITIALIZED: |
| return "UNINITIALIZED"; |
| case CMD: |
| return "CMD"; |
| case STATE: |
| return "STATE"; |
| case PAD: |
| return "PAD"; |
| case RELOC: |
| return "RELOC"; |
| case RELOC_STATE: |
| return "RELOC_STATE"; |
| case STATE_OFFSET: |
| return "STATE_OFFSET"; |
| } |
| |
| return "UNKNOWN"; |
| } |
| |
| void intel_batch_cmd_emit_null(struct intel_batchbuffer *batch, |
| const int cmd, const int len, const int len_bias, |
| const char *str) |
| { |
| int i; |
| |
| assert(len > 1); |
| assert((len - len_bias) >= 0); |
| |
| bb_area_emit(batch->cmds, (cmd | (len - len_bias)), CMD, str); |
| |
| for (i = len_bias-1; i < len; i++) |
| OUT_BATCH(0); |
| } |