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