1 /* 2 * Copyright 2006, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "accelerant.h" 11 #include "accelerant_protos.h" 12 #include "commands.h" 13 14 15 //#define TRACE_ENGINE 16 #ifdef TRACE_ENGINE 17 extern "C" void _sPrintf(const char *format, ...); 18 # define TRACE(x) _sPrintf x 19 #else 20 # define TRACE(x) ; 21 #endif 22 23 24 static engine_token sEngineToken = {1, 0 /*B_2D_ACCELERATION*/, NULL}; 25 26 27 QueueCommands::QueueCommands(ring_buffer &ring) 28 : 29 fRingBuffer(ring) 30 { 31 acquire_lock(&fRingBuffer.lock); 32 } 33 34 35 QueueCommands::~QueueCommands() 36 { 37 if (fRingBuffer.position & 0x07) { 38 // make sure the command is properly aligned 39 _Write(COMMAND_NOOP); 40 } 41 42 // We must make sure memory is written back in case the ring buffer 43 // is in write combining mode - releasing the lock does this, as the 44 // buffer is flushed on a locked memory operation (which is what this 45 // benaphore does), but it must happen before writing the new tail... 46 int32 flush; 47 atomic_add(&flush, 1); 48 49 write32(fRingBuffer.register_base + RING_BUFFER_TAIL, fRingBuffer.position); 50 51 release_lock(&fRingBuffer.lock); 52 } 53 54 55 void 56 QueueCommands::Put(struct command &command, size_t size) 57 { 58 uint32 count = size / sizeof(uint32); 59 uint32 *data = command.Data(); 60 61 _MakeSpace(count); 62 63 for (uint32 i = 0; i < count; i++) { 64 _Write(data[i]); 65 } 66 } 67 68 69 void 70 QueueCommands::PutFlush() 71 { 72 _MakeSpace(2); 73 74 _Write(COMMAND_FLUSH); 75 _Write(COMMAND_NOOP); 76 } 77 78 79 void 80 QueueCommands::PutWaitFor(uint32 event) 81 { 82 _MakeSpace(2); 83 84 _Write(COMMAND_WAIT_FOR_EVENT | event); 85 _Write(COMMAND_NOOP); 86 } 87 88 89 void 90 QueueCommands::PutOverlayFlip(uint32 mode, bool updateCoefficients) 91 { 92 _MakeSpace(2); 93 94 _Write(COMMAND_OVERLAY_FLIP | mode); 95 _Write((uint32)gInfo->shared_info->physical_overlay_registers 96 | (updateCoefficients ? OVERLAY_UPDATE_COEFFICIENTS : 0)); 97 } 98 99 100 void 101 QueueCommands::_MakeSpace(uint32 size) 102 { 103 // TODO: make sure there is enough room to write the command! 104 } 105 106 107 void 108 QueueCommands::_Write(uint32 data) 109 { 110 uint32 *target = (uint32 *)(fRingBuffer.base + fRingBuffer.position); 111 *target = data; 112 113 fRingBuffer.position = (fRingBuffer.position + sizeof(uint32)) & (fRingBuffer.size - 1); 114 } 115 116 117 // #pragma mark - 118 119 120 void 121 uninit_ring_buffer(ring_buffer &ringBuffer) 122 { 123 uninit_lock(&ringBuffer.lock); 124 write32(ringBuffer.register_base + RING_BUFFER_CONTROL, 0); 125 } 126 127 128 void 129 setup_ring_buffer(ring_buffer &ringBuffer, const char *name) 130 { 131 TRACE(("Setup ring buffer %s, offset %lx, size %lx\n", name, ringBuffer.offset, 132 ringBuffer.size)); 133 134 if (init_lock(&ringBuffer.lock, name) < B_OK) { 135 // disable ring buffer 136 ringBuffer.size = 0; 137 return; 138 } 139 140 uint32 ring = ringBuffer.register_base; 141 write32(ring + RING_BUFFER_TAIL, 0); 142 write32(ring + RING_BUFFER_START, ringBuffer.offset); 143 write32(ring + RING_BUFFER_CONTROL, 144 ((ringBuffer.size - B_PAGE_SIZE) & INTEL_RING_BUFFER_SIZE_MASK) 145 | INTEL_RING_BUFFER_ENABLED); 146 } 147 148 149 // #pragma mark - engine management 150 151 152 /** Return number of hardware engines */ 153 154 uint32 155 intel_accelerant_engine_count(void) 156 { 157 TRACE(("intel_accelerant_engine_count()\n")); 158 return 1; 159 } 160 161 162 status_t 163 intel_acquire_engine(uint32 capabilities, uint32 maxWait, sync_token *syncToken, 164 engine_token **_engineToken) 165 { 166 TRACE(("intel_acquire_engine()\n")); 167 *_engineToken = &sEngineToken; 168 169 if (acquire_lock(&gInfo->shared_info->engine_lock) != B_OK) 170 return B_ERROR; 171 172 if (syncToken) 173 intel_sync_to_token(syncToken); 174 175 return B_OK; 176 } 177 178 179 status_t 180 intel_release_engine(engine_token *engineToken, sync_token *syncToken) 181 { 182 TRACE(("intel_release_engine()\n")); 183 if (syncToken != NULL) 184 syncToken->engine_id = engineToken->engine_id; 185 186 release_lock(&gInfo->shared_info->engine_lock); 187 return B_OK; 188 } 189 190 191 void 192 intel_wait_engine_idle(void) 193 { 194 TRACE(("intel_wait_engine_idle()\n")); 195 196 { 197 QueueCommands queue(gInfo->shared_info->primary_ring_buffer); 198 queue.PutFlush(); 199 } 200 201 // TODO: this should only be a temporary solution! 202 // a better way to do this would be to acquire the engine's lock and 203 // sync to the latest token 204 205 ring_buffer &ring = gInfo->shared_info->primary_ring_buffer; 206 uint32 head, tail; 207 do { 208 head = read32(ring.register_base + RING_BUFFER_HEAD) & INTEL_RING_BUFFER_HEAD_MASK; 209 tail = read32(ring.register_base + RING_BUFFER_TAIL) & INTEL_RING_BUFFER_HEAD_MASK; 210 211 //snooze(100); 212 // Isn't a snooze() a bit too slow? At least it's called *very* often in Haiku... 213 } while (head != tail); 214 } 215 216 217 status_t 218 intel_get_sync_token(engine_token *engineToken, sync_token *syncToken) 219 { 220 TRACE(("intel_get_sync_token()\n")); 221 return B_OK; 222 } 223 224 225 status_t 226 intel_sync_to_token(sync_token *syncToken) 227 { 228 TRACE(("intel_sync_to_token()\n")); 229 intel_wait_engine_idle(); 230 return B_OK; 231 } 232 233 234 // #pragma mark - engine acceleration 235 236 237 void 238 intel_screen_to_screen_blit(engine_token *token, blit_params *params, uint32 count) 239 { 240 QueueCommands queue(gInfo->shared_info->primary_ring_buffer); 241 242 for (uint32 i = 0; i < count; i++) { 243 xy_source_blit_command blit; 244 blit.source_left = params[i].src_left; 245 blit.source_top = params[i].src_top; 246 blit.dest_left = params[i].dest_left; 247 blit.dest_top = params[i].dest_top; 248 blit.dest_right = params[i].dest_left + params[i].width + 1; 249 blit.dest_bottom = params[i].dest_top + params[i].height + 1; 250 251 queue.Put(blit, sizeof(blit)); 252 } 253 } 254 255 256 void 257 intel_fill_rectangle(engine_token *token, uint32 color, fill_rect_params *params, 258 uint32 count) 259 { 260 QueueCommands queue(gInfo->shared_info->primary_ring_buffer); 261 262 for (uint32 i = 0; i < count; i++) { 263 xy_color_blit_command blit(false); 264 blit.dest_left = params[i].left; 265 blit.dest_top = params[i].top; 266 blit.dest_right = params[i].right + 1; 267 blit.dest_bottom = params[i].bottom + 1; 268 blit.color = color; 269 270 queue.Put(blit, sizeof(blit)); 271 } 272 } 273 274 275 void 276 intel_invert_rectangle(engine_token *token, fill_rect_params *params, uint32 count) 277 { 278 QueueCommands queue(gInfo->shared_info->primary_ring_buffer); 279 280 for (uint32 i = 0; i < count; i++) { 281 xy_color_blit_command blit(true); 282 blit.dest_left = params[i].left; 283 blit.dest_top = params[i].top; 284 blit.dest_right = params[i].right + 1; 285 blit.dest_bottom = params[i].bottom + 1; 286 blit.color = 0xffffffff; 287 288 queue.Put(blit, sizeof(blit)); 289 } 290 } 291 292 293 void 294 intel_fill_span(engine_token *token, uint32 color, uint16* _params, uint32 count) 295 { 296 struct params { 297 uint16 top; 298 uint16 left; 299 uint16 right; 300 } *params = (struct params *)_params; 301 302 QueueCommands queue(gInfo->shared_info->primary_ring_buffer); 303 304 xy_setup_mono_pattern_command setup; 305 setup.background_color = color; 306 setup.pattern = 0; 307 queue.Put(setup, sizeof(setup)); 308 309 for (uint32 i = 0; i < count; i++) { 310 xy_scanline_blit_command blit; 311 blit.dest_left = params[i].left; 312 blit.dest_top = params[i].top; 313 blit.dest_right = params[i].right; 314 blit.dest_bottom = params[i].top; 315 } 316 } 317