1 /*
2  * Copyright 2006-2012, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Jérôme Duval, korli@users.berlios.de
7  *		Philippe Houdoin, philippe.houdoin@free.fr
8  *		Artur Wyszynski, harakash@gmail.com
9  *		Alexander von Gluck IV, kallisti5@unixzen.com
10  */
11 
12 
13 #include "SoftwareRenderer.h"
14 
15 #include <Autolock.h>
16 #include <interface/DirectWindowPrivate.h>
17 #include <GraphicsDefs.h>
18 #include <Screen.h>
19 #include <stdio.h>
20 #include <sys/time.h>
21 #include <new>
22 
23 
24 #ifdef DEBUG
25 #	define TRACE(x...) printf("SoftwareRenderer: " x)
26 #	define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
27 #else
28 #	define TRACE(x...)
29 #	define CALLED()
30 #endif
31 #define ERROR(x...)	printf("SoftwareRenderer: " x)
32 
33 
34 extern const char* color_space_name(color_space space);
35 
36 
37 extern "C" _EXPORT BGLRenderer*
instantiate_gl_renderer(BGLView * view,ulong opts,BGLDispatcher * dispatcher)38 instantiate_gl_renderer(BGLView *view, ulong opts, BGLDispatcher *dispatcher)
39 {
40 	return new SoftwareRenderer(view, opts, dispatcher);
41 }
42 
SoftwareRenderer(BGLView * view,ulong options,BGLDispatcher * dispatcher)43 SoftwareRenderer::SoftwareRenderer(BGLView *view, ulong options,
44 	BGLDispatcher* dispatcher)
45 	:
46 	BGLRenderer(view, options, dispatcher),
47 	fBitmap(NULL),
48 	fDirectModeEnabled(false),
49 	fInfo(NULL),
50 	fInfoLocker("info locker"),
51 	fOptions(options),
52 	fColorSpace(B_NO_COLOR_SPACE)
53 {
54 	CALLED();
55 
56 	// Disable double buffer for the moment.
57 	//options &= ~BGL_DOUBLE;
58 
59 	// Initialize the "Haiku Software GL Pipe"
60 	time_t beg;
61 	time_t end;
62 	beg = time(NULL);
63 	fContextObj = new GalliumContext(options);
64 	end = time(NULL);
65 	TRACE("Haiku Software GL Pipe initialization time: %f.\n",
66 		difftime(end, beg));
67 
68 	// Allocate a bitmap
69 	BRect b = view->Bounds();
70 	fColorSpace = BScreen(view->Window()).ColorSpace();
71 	TRACE("%s: Colorspace:\t%s\n", __func__, color_space_name(fColorSpace));
72 
73 	fWidth = (GLint)b.IntegerWidth();
74 	fHeight = (GLint)b.IntegerHeight();
75 
76 	_AllocateBitmap();
77 
78 	// Initialize the first "Haiku Software GL Pipe" context
79 	beg = time(NULL);
80 	fContextID = fContextObj->CreateContext(fBitmap);
81 	end = time(NULL);
82 
83 	if (fContextID < 0)
84 		ERROR("%s: There was an error creating the context!\n", __func__);
85 	else {
86 		TRACE("%s: Haiku Software GL Pipe context creation time: %f.\n",
87 			__func__, difftime(end, beg));
88 	}
89 
90 	if (!fContextObj->GetCurrentContext())
91 		LockGL();
92 }
93 
94 
~SoftwareRenderer()95 SoftwareRenderer::~SoftwareRenderer()
96 {
97 	CALLED();
98 
99 	if (fContextObj)
100 		delete fContextObj;
101 	if (fBitmap)
102 		delete fBitmap;
103 }
104 
105 
106 void
LockGL()107 SoftwareRenderer::LockGL()
108 {
109 //	CALLED();
110 	BGLRenderer::LockGL();
111 
112 	color_space cs = BScreen(GLView()->Window()).ColorSpace();
113 
114 	BAutolock lock(fInfoLocker);
115 	if (fDirectModeEnabled && fInfo != NULL) {
116 		fWidth = fInfo->window_bounds.right - fInfo->window_bounds.left;
117 		fHeight = fInfo->window_bounds.bottom - fInfo->window_bounds.top;
118 	}
119 
120 	if (fBitmap && cs == fColorSpace && fContextObj->Validate(fWidth, fHeight)) {
121 		fContextObj->SetCurrentContext(fBitmap, fContextID);
122 		return;
123 	}
124 
125 	fColorSpace = cs;
126 
127 	_AllocateBitmap();
128 	fContextObj->SetCurrentContext(fBitmap, fContextID);
129 }
130 
131 
132 void
UnlockGL()133 SoftwareRenderer::UnlockGL()
134 {
135 //	CALLED();
136 	if ((fOptions & BGL_DOUBLE) == 0) {
137 		SwapBuffers();
138 	}
139 	fContextObj->SetCurrentContext(NULL, fContextID);
140 	BGLRenderer::UnlockGL();
141 }
142 
143 
144 void
SwapBuffers(bool vsync)145 SoftwareRenderer::SwapBuffers(bool vsync)
146 {
147 //	CALLED();
148 	if (!fBitmap)
149 		return;
150 
151 	BScreen screen(GLView()->Window());
152 
153 	fContextObj->SwapBuffers(fContextID);
154 
155 	BAutolock lock(fInfoLocker);
156 
157 	if (!fDirectModeEnabled || fInfo == NULL) {
158 		if (GLView()->LockLooperWithTimeout(1000) == B_OK) {
159 			GLView()->DrawBitmap(fBitmap, B_ORIGIN);
160 			GLView()->UnlockLooper();
161 			if (vsync)
162 				screen.WaitForRetrace();
163 		}
164 		return;
165 	}
166 
167 	// check the bitmap size still matches the size
168 	if (fInfo->window_bounds.bottom - fInfo->window_bounds.top
169 			!= fBitmap->Bounds().IntegerHeight()
170 			|| fInfo->window_bounds.right - fInfo->window_bounds.left
171 			!= fBitmap->Bounds().IntegerWidth()) {
172 		ERROR("%s: Bitmap size doesn't match size!\n", __func__);
173 		return;
174 	}
175 
176 	uint32 bytesPerRow = fBitmap->BytesPerRow();
177 	uint8 bytesPerPixel = bytesPerRow / fBitmap->Bounds().IntegerWidth();
178 
179 	for (uint32 i = 0; i < fInfo->clip_list_count; i++) {
180 		clipping_rect *clip = &fInfo->clip_list[i];
181 		int32 height = clip->bottom - clip->top + 1;
182 		int32 bytesWidth
183 			= (clip->right - clip->left + 1) * bytesPerPixel;
184 		bytesWidth -= bytesPerPixel;
185 		uint8 *p = (uint8 *)fInfo->bits + clip->top
186 			* fInfo->bytes_per_row + clip->left * bytesPerPixel;
187 		uint8 *b = (uint8 *)fBitmap->Bits()
188 			+ (clip->top - fInfo->window_bounds.top) * bytesPerRow
189 			+ (clip->left - fInfo->window_bounds.left) * bytesPerPixel;
190 
191 		for (int y = 0; y < height - 1; y++) {
192 			memcpy(p, b, bytesWidth);
193 			p += fInfo->bytes_per_row;
194 			b += bytesPerRow;
195 		}
196 	}
197 
198 	if (vsync)
199 		screen.WaitForRetrace();
200 }
201 
202 
203 void
Draw(BRect updateRect)204 SoftwareRenderer::Draw(BRect updateRect)
205 {
206 //	CALLED();
207 	if ((!fDirectModeEnabled || fInfo == NULL) && fBitmap)
208 		GLView()->DrawBitmap(fBitmap, updateRect, updateRect);
209 }
210 
211 
212 status_t
CopyPixelsOut(BPoint location,BBitmap * bitmap)213 SoftwareRenderer::CopyPixelsOut(BPoint location, BBitmap *bitmap)
214 {
215 	CALLED();
216 	color_space scs = fBitmap->ColorSpace();
217 	color_space dcs = bitmap->ColorSpace();
218 
219 	if (scs != dcs && (scs != B_RGBA32 || dcs != B_RGB32)) {
220 		ERROR("%s::CopyPixelsOut(): incompatible color space: %s != %s\n",
221 			__PRETTY_FUNCTION__, color_space_name(scs), color_space_name(dcs));
222 		return B_BAD_TYPE;
223 	}
224 
225 	BRect sr = fBitmap->Bounds();
226 	BRect dr = bitmap->Bounds();
227 
228 //	int32 w1 = sr.IntegerWidth();
229 //	int32 h1 = sr.IntegerHeight();
230 //	int32 w2 = dr.IntegerWidth();
231 //	int32 h2 = dr.IntegerHeight();
232 
233 	sr = sr & dr.OffsetBySelf(location);
234 	dr = sr.OffsetByCopy(-location.x, -location.y);
235 
236 	uint8 *ps = (uint8 *) fBitmap->Bits();
237 	uint8 *pd = (uint8 *) bitmap->Bits();
238 	uint32 *s, *d;
239 	uint32 y;
240 	for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) {
241 		s = (uint32 *)(ps + y * fBitmap->BytesPerRow());
242 		s += (uint32) sr.left;
243 
244 		d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top))
245 			* bitmap->BytesPerRow());
246 		d += (uint32) dr.left;
247 		memcpy(d, s, dr.IntegerWidth() * 4);
248 	}
249 
250 	return B_OK;
251 }
252 
253 
254 status_t
CopyPixelsIn(BBitmap * bitmap,BPoint location)255 SoftwareRenderer::CopyPixelsIn(BBitmap *bitmap, BPoint location)
256 {
257 	CALLED();
258 
259 	color_space sourceCS = bitmap->ColorSpace();
260 	color_space destinationCS = fBitmap->ColorSpace();
261 
262 	if (sourceCS != destinationCS
263 		&& (sourceCS != B_RGB32 || destinationCS != B_RGBA32)) {
264 		ERROR("%s::CopyPixelsIn(): incompatible color space: %s != %s\n",
265 			__PRETTY_FUNCTION__, color_space_name(sourceCS),
266 			color_space_name(destinationCS));
267 		return B_BAD_TYPE;
268 	}
269 
270 	BRect sr = bitmap->Bounds();
271 	BRect dr = fBitmap->Bounds();
272 
273 	sr = sr & dr.OffsetBySelf(location);
274 	dr = sr.OffsetByCopy(-location.x, -location.y);
275 
276 	uint8 *ps = (uint8 *) bitmap->Bits();
277 	uint8 *pd = (uint8 *) fBitmap->Bits();
278 	uint32 *s, *d;
279 	uint32 y;
280 
281 	for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) {
282 		s = (uint32 *)(ps + y * bitmap->BytesPerRow());
283 		s += (uint32) sr.left;
284 
285 		d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top))
286 			* fBitmap->BytesPerRow());
287 		d += (uint32) dr.left;
288 
289 		memcpy(d, s, dr.IntegerWidth() * 4);
290 	}
291 
292 	return B_OK;
293 }
294 
295 
296 void
EnableDirectMode(bool enabled)297 SoftwareRenderer::EnableDirectMode(bool enabled)
298 {
299 	fDirectModeEnabled = enabled;
300 }
301 
302 
303 void
DirectConnected(direct_buffer_info * info)304 SoftwareRenderer::DirectConnected(direct_buffer_info *info)
305 {
306 //	CALLED();
307 	BAutolock lock(fInfoLocker);
308 	if (info) {
309 		if (!fInfo) {
310 			fInfo = (direct_buffer_info *)calloc(1,
311 				DIRECT_BUFFER_INFO_AREA_SIZE);
312 		}
313 		memcpy(fInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
314 	} else if (fInfo) {
315 		free(fInfo);
316 		fInfo = NULL;
317 	}
318 }
319 
320 
321 void
FrameResized(float width,float height)322 SoftwareRenderer::FrameResized(float width, float height)
323 {
324 	TRACE("%s: %f x %f\n", __func__, width, height);
325 
326 	BAutolock lock(fInfoLocker);
327 	fWidth = (GLuint)width;
328 	fHeight = (GLuint)height;
329 }
330 
331 
332 void
_AllocateBitmap()333 SoftwareRenderer::_AllocateBitmap()
334 {
335 //	CALLED();
336 
337 	// allocate new size of back buffer bitmap
338 	BAutolock lock(fInfoLocker);
339 	if (fBitmap)
340 		delete fBitmap;
341 
342 	if (fWidth < 1 || fHeight < 1) {
343 		TRACE("%s: Can't allocate bitmap of %dx%d\n", __func__,
344 			fWidth, fHeight);
345 		return;
346 	}
347 	BRect rect(0.0, 0.0, fWidth, fHeight);
348 	fBitmap = new (std::nothrow) BBitmap(rect, fColorSpace);
349 	if (fBitmap == NULL) {
350 		TRACE("%s: Can't create bitmap!\n", __func__);
351 		return;
352 	}
353 
354 	TRACE("%s: New bitmap size: %" B_PRId32 " x %" B_PRId32 "\n", __func__,
355 		fBitmap->Bounds().IntegerWidth(), fBitmap->Bounds().IntegerHeight());
356 
357 #if 0
358 	// debug..
359 	void *data = fBitmap->Bits();
360 	memset(data, 0xcc, fBitmap->BitsLength());
361 #endif
362 }
363