1/* 2 * Copyright (c) 2012-2015 Etnaviv Project 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sub license, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the 12 * next paragraph) shall be included in all copies or substantial portions 13 * of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: 24 * Wladimir J. van der Laan <laanwj@gmail.com> 25 */ 26 27#ifndef H_ETNA_EMIT 28#define H_ETNA_EMIT 29 30#include "etnaviv_screen.h" 31#include "etnaviv_util.h" 32#include "hw/cmdstream.xml.h" 33 34struct etna_context; 35 36struct etna_coalesce { 37 uint32_t start; 38 uint32_t last_reg; 39 uint32_t last_fixp; 40}; 41 42static inline void 43etna_emit_load_state(struct etna_cmd_stream *stream, const uint16_t offset, 44 const uint16_t count, const int fixp) 45{ 46 uint32_t v; 47 48 v = VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE | 49 COND(fixp, VIV_FE_LOAD_STATE_HEADER_FIXP) | 50 VIV_FE_LOAD_STATE_HEADER_OFFSET(offset) | 51 (VIV_FE_LOAD_STATE_HEADER_COUNT(count) & 52 VIV_FE_LOAD_STATE_HEADER_COUNT__MASK); 53 54 etna_cmd_stream_emit(stream, v); 55} 56 57static inline void 58etna_set_state(struct etna_cmd_stream *stream, uint32_t address, uint32_t value) 59{ 60 etna_cmd_stream_reserve(stream, 2); 61 etna_emit_load_state(stream, address >> 2, 1, 0); 62 etna_cmd_stream_emit(stream, value); 63} 64 65static inline void 66etna_set_state_reloc(struct etna_cmd_stream *stream, uint32_t address, 67 const struct etna_reloc *reloc) 68{ 69 etna_cmd_stream_reserve(stream, 2); 70 etna_emit_load_state(stream, address >> 2, 1, 0); 71 etna_cmd_stream_reloc(stream, reloc); 72} 73 74static inline void 75etna_set_state_multi(struct etna_cmd_stream *stream, uint32_t base, 76 uint32_t num, const uint32_t *values) 77{ 78 if (num == 0) 79 return; 80 81 etna_cmd_stream_reserve(stream, 1 + num + 1); /* 1 extra for potential alignment */ 82 etna_emit_load_state(stream, base >> 2, num, 0); 83 84 for (uint32_t i = 0; i < num; i++) 85 etna_cmd_stream_emit(stream, values[i]); 86 87 /* add potential padding */ 88 if ((num % 2) == 0) 89 etna_cmd_stream_emit(stream, 0); 90} 91 92void 93etna_stall(struct etna_cmd_stream *stream, uint32_t from, uint32_t to); 94 95static inline void 96etna_draw_primitives(struct etna_cmd_stream *stream, uint32_t primitive_type, 97 uint32_t start, uint32_t count) 98{ 99 etna_cmd_stream_reserve(stream, 4); 100 101 etna_cmd_stream_emit(stream, VIV_FE_DRAW_PRIMITIVES_HEADER_OP_DRAW_PRIMITIVES); 102 etna_cmd_stream_emit(stream, primitive_type); 103 etna_cmd_stream_emit(stream, start); 104 etna_cmd_stream_emit(stream, count); 105} 106 107static inline void 108etna_draw_indexed_primitives(struct etna_cmd_stream *stream, 109 uint32_t primitive_type, uint32_t start, 110 uint32_t count, uint32_t offset) 111{ 112 etna_cmd_stream_reserve(stream, 5 + 1); 113 114 etna_cmd_stream_emit(stream, VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP_DRAW_INDEXED_PRIMITIVES); 115 etna_cmd_stream_emit(stream, primitive_type); 116 etna_cmd_stream_emit(stream, start); 117 etna_cmd_stream_emit(stream, count); 118 etna_cmd_stream_emit(stream, offset); 119 etna_cmd_stream_emit(stream, 0); 120} 121 122/* important: this takes a vertex count, not a primitive count */ 123static inline void 124etna_draw_instanced(struct etna_cmd_stream *stream, 125 uint32_t indexed, uint32_t primitive_type, 126 uint32_t instance_count, 127 uint32_t vertex_count, uint32_t offset) 128{ 129 etna_cmd_stream_reserve(stream, 3 + 1); 130 etna_cmd_stream_emit(stream, 131 VIV_FE_DRAW_INSTANCED_HEADER_OP_DRAW_INSTANCED | 132 COND(indexed, VIV_FE_DRAW_INSTANCED_HEADER_INDEXED) | 133 VIV_FE_DRAW_INSTANCED_HEADER_TYPE(primitive_type) | 134 VIV_FE_DRAW_INSTANCED_HEADER_INSTANCE_COUNT_LO(instance_count & 0xffff)); 135 etna_cmd_stream_emit(stream, 136 VIV_FE_DRAW_INSTANCED_COUNT_INSTANCE_COUNT_HI(instance_count >> 16) | 137 VIV_FE_DRAW_INSTANCED_COUNT_VERTEX_COUNT(vertex_count)); 138 etna_cmd_stream_emit(stream, 139 VIV_FE_DRAW_INSTANCED_START_INDEX(offset)); 140 etna_cmd_stream_emit(stream, 0); 141} 142 143static inline void 144etna_coalesce_start(struct etna_cmd_stream *stream, 145 struct etna_coalesce *coalesce) 146{ 147 coalesce->start = etna_cmd_stream_offset(stream); 148 coalesce->last_reg = 0; 149 coalesce->last_fixp = 0; 150} 151 152static inline void 153etna_coalesce_end(struct etna_cmd_stream *stream, 154 struct etna_coalesce *coalesce) 155{ 156 uint32_t end = etna_cmd_stream_offset(stream); 157 uint32_t size = end - coalesce->start; 158 159 if (size) { 160 uint32_t offset = coalesce->start - 1; 161 uint32_t value = etna_cmd_stream_get(stream, offset); 162 163 value |= VIV_FE_LOAD_STATE_HEADER_COUNT(size); 164 etna_cmd_stream_set(stream, offset, value); 165 } 166 167 /* append needed padding */ 168 if (end % 2 == 1) 169 etna_cmd_stream_emit(stream, 0xdeadbeef); 170} 171 172static inline void 173check_coalsence(struct etna_cmd_stream *stream, struct etna_coalesce *coalesce, 174 uint32_t reg, uint32_t fixp) 175{ 176 if (coalesce->last_reg != 0) { 177 if (((coalesce->last_reg + 4) != reg) || (coalesce->last_fixp != fixp)) { 178 etna_coalesce_end(stream, coalesce); 179 etna_emit_load_state(stream, reg >> 2, 0, fixp); 180 coalesce->start = etna_cmd_stream_offset(stream); 181 } 182 } else { 183 etna_emit_load_state(stream, reg >> 2, 0, fixp); 184 coalesce->start = etna_cmd_stream_offset(stream); 185 } 186 187 coalesce->last_reg = reg; 188 coalesce->last_fixp = fixp; 189} 190 191static inline void 192etna_coalsence_emit(struct etna_cmd_stream *stream, 193 struct etna_coalesce *coalesce, uint32_t reg, 194 uint32_t value) 195{ 196 check_coalsence(stream, coalesce, reg, 0); 197 etna_cmd_stream_emit(stream, value); 198} 199 200static inline void 201etna_coalsence_emit_fixp(struct etna_cmd_stream *stream, 202 struct etna_coalesce *coalesce, uint32_t reg, 203 uint32_t value) 204{ 205 check_coalsence(stream, coalesce, reg, 1); 206 etna_cmd_stream_emit(stream, value); 207} 208 209static inline void 210etna_coalsence_emit_reloc(struct etna_cmd_stream *stream, 211 struct etna_coalesce *coalesce, uint32_t reg, 212 const struct etna_reloc *r) 213{ 214 if (r->bo) { 215 check_coalsence(stream, coalesce, reg, 0); 216 etna_cmd_stream_reloc(stream, r); 217 } 218} 219 220void 221etna_emit_state(struct etna_context *ctx); 222 223#endif 224