xref: /haiku/src/add-ons/accelerants/intel_extreme/engine.cpp (revision c90684742e7361651849be4116d0e5de3a817194)
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