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 (at) 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 34 struct etna_context; 35 struct compiled_rs_state; 36 37 struct etna_coalesce { 38 uint32_t start; 39 uint32_t last_reg; 40 uint32_t last_fixp; 41 }; 42 43 static inline void 44 etna_emit_load_state(struct etna_cmd_stream *stream, const uint16_t offset, 45 const uint16_t count, const int fixp) 46 { 47 uint32_t v; 48 49 v = VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE | 50 COND(fixp, VIV_FE_LOAD_STATE_HEADER_FIXP) | 51 VIV_FE_LOAD_STATE_HEADER_OFFSET(offset) | 52 (VIV_FE_LOAD_STATE_HEADER_COUNT(count) & 53 VIV_FE_LOAD_STATE_HEADER_COUNT__MASK); 54 55 etna_cmd_stream_emit(stream, v); 56 } 57 58 static inline void 59 etna_set_state(struct etna_cmd_stream *stream, uint32_t address, uint32_t value) 60 { 61 etna_cmd_stream_reserve(stream, 2); 62 etna_emit_load_state(stream, address >> 2, 1, 0); 63 etna_cmd_stream_emit(stream, value); 64 } 65 66 static inline void 67 etna_set_state_reloc(struct etna_cmd_stream *stream, uint32_t address, 68 const struct etna_reloc *reloc) 69 { 70 etna_cmd_stream_reserve(stream, 2); 71 etna_emit_load_state(stream, address >> 2, 1, 0); 72 etna_cmd_stream_reloc(stream, reloc); 73 } 74 75 static inline void 76 etna_set_state_multi(struct etna_cmd_stream *stream, uint32_t base, 77 uint32_t num, const uint32_t *values) 78 { 79 if (num == 0) 80 return; 81 82 etna_cmd_stream_reserve(stream, 1 + num + 1); /* 1 extra for potential alignment */ 83 etna_emit_load_state(stream, base >> 2, num, 0); 84 85 for (uint32_t i = 0; i < num; i++) 86 etna_cmd_stream_emit(stream, values[i]); 87 88 /* add potential padding */ 89 if ((num % 2) == 0) 90 etna_cmd_stream_emit(stream, 0); 91 } 92 93 void 94 etna_stall(struct etna_cmd_stream *stream, uint32_t from, uint32_t to); 95 96 static inline void 97 etna_draw_primitives(struct etna_cmd_stream *stream, uint32_t primitive_type, 98 uint32_t start, uint32_t count) 99 { 100 etna_cmd_stream_reserve(stream, 4); 101 102 etna_cmd_stream_emit(stream, VIV_FE_DRAW_PRIMITIVES_HEADER_OP_DRAW_PRIMITIVES); 103 etna_cmd_stream_emit(stream, primitive_type); 104 etna_cmd_stream_emit(stream, start); 105 etna_cmd_stream_emit(stream, count); 106 } 107 108 static inline void 109 etna_draw_indexed_primitives(struct etna_cmd_stream *stream, 110 uint32_t primitive_type, uint32_t start, 111 uint32_t count, uint32_t offset) 112 { 113 etna_cmd_stream_reserve(stream, 5 + 1); 114 115 etna_cmd_stream_emit(stream, VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP_DRAW_INDEXED_PRIMITIVES); 116 etna_cmd_stream_emit(stream, primitive_type); 117 etna_cmd_stream_emit(stream, start); 118 etna_cmd_stream_emit(stream, count); 119 etna_cmd_stream_emit(stream, offset); 120 etna_cmd_stream_emit(stream, 0); 121 } 122 123 /* important: this takes a vertex count, not a primitive count */ 124 static inline void 125 etna_draw_instanced(struct etna_cmd_stream *stream, 126 uint32_t indexed, uint32_t primitive_type, 127 uint32_t instance_count, 128 uint32_t vertex_count, uint32_t offset) 129 { 130 etna_cmd_stream_reserve(stream, 3 + 1); 131 etna_cmd_stream_emit(stream, 132 VIV_FE_DRAW_INSTANCED_HEADER_OP_DRAW_INSTANCED | 133 COND(indexed, VIV_FE_DRAW_INSTANCED_HEADER_INDEXED) | 134 VIV_FE_DRAW_INSTANCED_HEADER_TYPE(primitive_type) | 135 VIV_FE_DRAW_INSTANCED_HEADER_INSTANCE_COUNT_LO(instance_count & 0xffff)); 136 etna_cmd_stream_emit(stream, 137 VIV_FE_DRAW_INSTANCED_COUNT_INSTANCE_COUNT_HI(instance_count >> 16) | 138 VIV_FE_DRAW_INSTANCED_COUNT_VERTEX_COUNT(vertex_count)); 139 etna_cmd_stream_emit(stream, 140 VIV_FE_DRAW_INSTANCED_START_INDEX(offset)); 141 etna_cmd_stream_emit(stream, 0); 142 } 143 144 static inline void 145 etna_coalesce_start(struct etna_cmd_stream *stream, 146 struct etna_coalesce *coalesce) 147 { 148 coalesce->start = etna_cmd_stream_offset(stream); 149 coalesce->last_reg = 0; 150 coalesce->last_fixp = 0; 151 } 152 153 static inline void 154 etna_coalesce_end(struct etna_cmd_stream *stream, 155 struct etna_coalesce *coalesce) 156 { 157 uint32_t end = etna_cmd_stream_offset(stream); 158 uint32_t size = end - coalesce->start; 159 160 if (size) { 161 uint32_t offset = coalesce->start - 1; 162 uint32_t value = etna_cmd_stream_get(stream, offset); 163 164 value |= VIV_FE_LOAD_STATE_HEADER_COUNT(size); 165 etna_cmd_stream_set(stream, offset, value); 166 } 167 168 /* append needed padding */ 169 if (end % 2 == 1) 170 etna_cmd_stream_emit(stream, 0xdeadbeef); 171 } 172 173 static inline void 174 check_coalsence(struct etna_cmd_stream *stream, struct etna_coalesce *coalesce, 175 uint32_t reg, uint32_t fixp) 176 { 177 if (coalesce->last_reg != 0) { 178 if (((coalesce->last_reg + 4) != reg) || (coalesce->last_fixp != fixp)) { 179 etna_coalesce_end(stream, coalesce); 180 etna_emit_load_state(stream, reg >> 2, 0, fixp); 181 coalesce->start = etna_cmd_stream_offset(stream); 182 } 183 } else { 184 etna_emit_load_state(stream, reg >> 2, 0, fixp); 185 coalesce->start = etna_cmd_stream_offset(stream); 186 } 187 188 coalesce->last_reg = reg; 189 coalesce->last_fixp = fixp; 190 } 191 192 static inline void 193 etna_coalsence_emit(struct etna_cmd_stream *stream, 194 struct etna_coalesce *coalesce, uint32_t reg, 195 uint32_t value) 196 { 197 check_coalsence(stream, coalesce, reg, 0); 198 etna_cmd_stream_emit(stream, value); 199 } 200 201 static inline void 202 etna_coalsence_emit_fixp(struct etna_cmd_stream *stream, 203 struct etna_coalesce *coalesce, uint32_t reg, 204 uint32_t value) 205 { 206 check_coalsence(stream, coalesce, reg, 1); 207 etna_cmd_stream_emit(stream, value); 208 } 209 210 static inline void 211 etna_coalsence_emit_reloc(struct etna_cmd_stream *stream, 212 struct etna_coalesce *coalesce, uint32_t reg, 213 const struct etna_reloc *r) 214 { 215 if (r->bo) { 216 check_coalsence(stream, coalesce, reg, 0); 217 etna_cmd_stream_reloc(stream, r); 218 } 219 } 220 221 void 222 etna_emit_state(struct etna_context *ctx); 223 224 #endif 225