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