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