1848b8605Smrg/*
2848b8605Smrg * Copyright 2006-2012, Haiku, Inc. All rights reserved.
3848b8605Smrg * Distributed under the terms of the MIT License.
4848b8605Smrg *
5848b8605Smrg * Authors:
6848b8605Smrg *		Jérôme Duval, korli@users.berlios.de
7848b8605Smrg *		Philippe Houdoin, philippe.houdoin@free.fr
8848b8605Smrg *		Artur Wyszynski, harakash@gmail.com
9848b8605Smrg *		Alexander von Gluck IV, kallisti5@unixzen.com
10848b8605Smrg */
11848b8605Smrg
12848b8605Smrg
13848b8605Smrg#include "SoftwareRenderer.h"
14848b8605Smrg
15848b8605Smrg#include <Autolock.h>
16848b8605Smrg#include <interface/DirectWindowPrivate.h>
17848b8605Smrg#include <GraphicsDefs.h>
18848b8605Smrg#include <Screen.h>
19848b8605Smrg#include <stdio.h>
20848b8605Smrg#include <sys/time.h>
21848b8605Smrg#include <new>
22848b8605Smrg
23848b8605Smrg
24848b8605Smrg#ifdef DEBUG
25848b8605Smrg#	define TRACE(x...) printf("SoftwareRenderer: " x)
26848b8605Smrg#	define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
27848b8605Smrg#else
28848b8605Smrg#	define TRACE(x...)
29848b8605Smrg#	define CALLED()
30848b8605Smrg#endif
31848b8605Smrg#define ERROR(x...)	printf("SoftwareRenderer: " x)
32848b8605Smrg
33848b8605Smrg
34848b8605Smrgextern const char* color_space_name(color_space space);
35848b8605Smrg
36848b8605Smrg
37848b8605Smrgextern "C" _EXPORT BGLRenderer*
38848b8605Smrginstantiate_gl_renderer(BGLView *view, ulong opts, BGLDispatcher *dispatcher)
39848b8605Smrg{
40848b8605Smrg	return new SoftwareRenderer(view, opts, dispatcher);
41848b8605Smrg}
42848b8605Smrg
43848b8605SmrgSoftwareRenderer::SoftwareRenderer(BGLView *view, ulong options,
44848b8605Smrg	BGLDispatcher* dispatcher)
45848b8605Smrg	:
46848b8605Smrg	BGLRenderer(view, options, dispatcher),
47848b8605Smrg	fBitmap(NULL),
48848b8605Smrg	fDirectModeEnabled(false),
49848b8605Smrg	fInfo(NULL),
50848b8605Smrg	fInfoLocker("info locker"),
51848b8605Smrg	fOptions(options),
52848b8605Smrg	fColorSpace(B_NO_COLOR_SPACE)
53848b8605Smrg{
54848b8605Smrg	CALLED();
55848b8605Smrg
56848b8605Smrg	// Disable double buffer for the moment.
57b8e80941Smrg	//options &= ~BGL_DOUBLE;
58848b8605Smrg
59848b8605Smrg	// Initialize the "Haiku Software GL Pipe"
60848b8605Smrg	time_t beg;
61848b8605Smrg	time_t end;
62848b8605Smrg	beg = time(NULL);
63848b8605Smrg	fContextObj = new GalliumContext(options);
64848b8605Smrg	end = time(NULL);
65848b8605Smrg	TRACE("Haiku Software GL Pipe initialization time: %f.\n",
66848b8605Smrg		difftime(end, beg));
67848b8605Smrg
68848b8605Smrg	// Allocate a bitmap
69848b8605Smrg	BRect b = view->Bounds();
70848b8605Smrg	fColorSpace = BScreen(view->Window()).ColorSpace();
71848b8605Smrg	TRACE("%s: Colorspace:\t%s\n", __func__, color_space_name(fColorSpace));
72848b8605Smrg
73848b8605Smrg	fWidth = (GLint)b.IntegerWidth();
74848b8605Smrg	fHeight = (GLint)b.IntegerHeight();
75848b8605Smrg
76848b8605Smrg	_AllocateBitmap();
77848b8605Smrg
78848b8605Smrg	// Initialize the first "Haiku Software GL Pipe" context
79848b8605Smrg	beg = time(NULL);
80848b8605Smrg	fContextID = fContextObj->CreateContext(fBitmap);
81848b8605Smrg	end = time(NULL);
82848b8605Smrg
83848b8605Smrg	if (fContextID < 0)
84848b8605Smrg		ERROR("%s: There was an error creating the context!\n", __func__);
85848b8605Smrg	else {
86848b8605Smrg		TRACE("%s: Haiku Software GL Pipe context creation time: %f.\n",
87848b8605Smrg			__func__, difftime(end, beg));
88848b8605Smrg	}
89848b8605Smrg
90848b8605Smrg	if (!fContextObj->GetCurrentContext())
91848b8605Smrg		LockGL();
92848b8605Smrg}
93848b8605Smrg
94848b8605Smrg
95848b8605SmrgSoftwareRenderer::~SoftwareRenderer()
96848b8605Smrg{
97848b8605Smrg	CALLED();
98848b8605Smrg
99848b8605Smrg	if (fContextObj)
100848b8605Smrg		delete fContextObj;
101848b8605Smrg	if (fBitmap)
102848b8605Smrg		delete fBitmap;
103848b8605Smrg}
104848b8605Smrg
105848b8605Smrg
106848b8605Smrgvoid
107848b8605SmrgSoftwareRenderer::LockGL()
108848b8605Smrg{
109848b8605Smrg//	CALLED();
110848b8605Smrg	BGLRenderer::LockGL();
111848b8605Smrg
112848b8605Smrg	color_space cs = BScreen(GLView()->Window()).ColorSpace();
113848b8605Smrg
114848b8605Smrg	BAutolock lock(fInfoLocker);
115848b8605Smrg	if (fDirectModeEnabled && fInfo != NULL) {
116b8e80941Smrg		fWidth = fInfo->window_bounds.right - fInfo->window_bounds.left;
117b8e80941Smrg		fHeight = fInfo->window_bounds.bottom - fInfo->window_bounds.top;
118848b8605Smrg	}
119848b8605Smrg
120b8e80941Smrg	if (fBitmap && cs == fColorSpace && fContextObj->Validate(fWidth, fHeight)) {
121848b8605Smrg		fContextObj->SetCurrentContext(fBitmap, fContextID);
122848b8605Smrg		return;
123848b8605Smrg	}
124848b8605Smrg
125848b8605Smrg	fColorSpace = cs;
126848b8605Smrg
127848b8605Smrg	_AllocateBitmap();
128848b8605Smrg	fContextObj->SetCurrentContext(fBitmap, fContextID);
129848b8605Smrg}
130848b8605Smrg
131848b8605Smrg
132848b8605Smrgvoid
133848b8605SmrgSoftwareRenderer::UnlockGL()
134848b8605Smrg{
135848b8605Smrg//	CALLED();
136848b8605Smrg	if ((fOptions & BGL_DOUBLE) == 0) {
137848b8605Smrg		SwapBuffers();
138848b8605Smrg	}
139848b8605Smrg	fContextObj->SetCurrentContext(NULL, fContextID);
140848b8605Smrg	BGLRenderer::UnlockGL();
141848b8605Smrg}
142848b8605Smrg
143848b8605Smrg
144848b8605Smrgvoid
145848b8605SmrgSoftwareRenderer::SwapBuffers(bool vsync)
146848b8605Smrg{
147848b8605Smrg//	CALLED();
148848b8605Smrg	if (!fBitmap)
149848b8605Smrg		return;
150848b8605Smrg
151848b8605Smrg	BScreen screen(GLView()->Window());
152848b8605Smrg
153848b8605Smrg	fContextObj->SwapBuffers(fContextID);
154848b8605Smrg
155848b8605Smrg	BAutolock lock(fInfoLocker);
156848b8605Smrg
157848b8605Smrg	if (!fDirectModeEnabled || fInfo == NULL) {
158848b8605Smrg		if (GLView()->LockLooperWithTimeout(1000) == B_OK) {
159848b8605Smrg			GLView()->DrawBitmap(fBitmap, B_ORIGIN);
160848b8605Smrg			GLView()->UnlockLooper();
161848b8605Smrg			if (vsync)
162848b8605Smrg				screen.WaitForRetrace();
163848b8605Smrg		}
164848b8605Smrg		return;
165848b8605Smrg	}
166848b8605Smrg
167848b8605Smrg	// check the bitmap size still matches the size
168848b8605Smrg	if (fInfo->window_bounds.bottom - fInfo->window_bounds.top
169848b8605Smrg			!= fBitmap->Bounds().IntegerHeight()
170848b8605Smrg			|| fInfo->window_bounds.right - fInfo->window_bounds.left
171848b8605Smrg			!= fBitmap->Bounds().IntegerWidth()) {
172848b8605Smrg		ERROR("%s: Bitmap size doesn't match size!\n", __func__);
173848b8605Smrg		return;
174848b8605Smrg	}
175848b8605Smrg
176848b8605Smrg	uint32 bytesPerRow = fBitmap->BytesPerRow();
177848b8605Smrg	uint8 bytesPerPixel = bytesPerRow / fBitmap->Bounds().IntegerWidth();
178848b8605Smrg
179848b8605Smrg	for (uint32 i = 0; i < fInfo->clip_list_count; i++) {
180848b8605Smrg		clipping_rect *clip = &fInfo->clip_list[i];
181848b8605Smrg		int32 height = clip->bottom - clip->top + 1;
182848b8605Smrg		int32 bytesWidth
183848b8605Smrg			= (clip->right - clip->left + 1) * bytesPerPixel;
184848b8605Smrg		bytesWidth -= bytesPerPixel;
185848b8605Smrg		uint8 *p = (uint8 *)fInfo->bits + clip->top
186848b8605Smrg			* fInfo->bytes_per_row + clip->left * bytesPerPixel;
187848b8605Smrg		uint8 *b = (uint8 *)fBitmap->Bits()
188848b8605Smrg			+ (clip->top - fInfo->window_bounds.top) * bytesPerRow
189848b8605Smrg			+ (clip->left - fInfo->window_bounds.left) * bytesPerPixel;
190848b8605Smrg
191848b8605Smrg		for (int y = 0; y < height - 1; y++) {
192848b8605Smrg			memcpy(p, b, bytesWidth);
193848b8605Smrg			p += fInfo->bytes_per_row;
194848b8605Smrg			b += bytesPerRow;
195848b8605Smrg		}
196848b8605Smrg	}
197848b8605Smrg
198848b8605Smrg	if (vsync)
199848b8605Smrg		screen.WaitForRetrace();
200848b8605Smrg}
201848b8605Smrg
202848b8605Smrg
203848b8605Smrgvoid
204848b8605SmrgSoftwareRenderer::Draw(BRect updateRect)
205848b8605Smrg{
206848b8605Smrg//	CALLED();
207848b8605Smrg	if ((!fDirectModeEnabled || fInfo == NULL) && fBitmap)
208848b8605Smrg		GLView()->DrawBitmap(fBitmap, updateRect, updateRect);
209848b8605Smrg}
210848b8605Smrg
211848b8605Smrg
212848b8605Smrgstatus_t
213848b8605SmrgSoftwareRenderer::CopyPixelsOut(BPoint location, BBitmap *bitmap)
214848b8605Smrg{
215848b8605Smrg	CALLED();
216848b8605Smrg	color_space scs = fBitmap->ColorSpace();
217848b8605Smrg	color_space dcs = bitmap->ColorSpace();
218848b8605Smrg
219848b8605Smrg	if (scs != dcs && (scs != B_RGBA32 || dcs != B_RGB32)) {
220848b8605Smrg		ERROR("%s::CopyPixelsOut(): incompatible color space: %s != %s\n",
221848b8605Smrg			__PRETTY_FUNCTION__, color_space_name(scs), color_space_name(dcs));
222848b8605Smrg		return B_BAD_TYPE;
223848b8605Smrg	}
224848b8605Smrg
225848b8605Smrg	BRect sr = fBitmap->Bounds();
226848b8605Smrg	BRect dr = bitmap->Bounds();
227848b8605Smrg
228848b8605Smrg//	int32 w1 = sr.IntegerWidth();
229848b8605Smrg//	int32 h1 = sr.IntegerHeight();
230848b8605Smrg//	int32 w2 = dr.IntegerWidth();
231848b8605Smrg//	int32 h2 = dr.IntegerHeight();
232848b8605Smrg
233848b8605Smrg	sr = sr & dr.OffsetBySelf(location);
234848b8605Smrg	dr = sr.OffsetByCopy(-location.x, -location.y);
235848b8605Smrg
236848b8605Smrg	uint8 *ps = (uint8 *) fBitmap->Bits();
237848b8605Smrg	uint8 *pd = (uint8 *) bitmap->Bits();
238848b8605Smrg	uint32 *s, *d;
239848b8605Smrg	uint32 y;
240848b8605Smrg	for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) {
241848b8605Smrg		s = (uint32 *)(ps + y * fBitmap->BytesPerRow());
242848b8605Smrg		s += (uint32) sr.left;
243848b8605Smrg
244848b8605Smrg		d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top))
245848b8605Smrg			* bitmap->BytesPerRow());
246848b8605Smrg		d += (uint32) dr.left;
247848b8605Smrg		memcpy(d, s, dr.IntegerWidth() * 4);
248848b8605Smrg	}
249848b8605Smrg
250848b8605Smrg	return B_OK;
251848b8605Smrg}
252848b8605Smrg
253848b8605Smrg
254848b8605Smrgstatus_t
255848b8605SmrgSoftwareRenderer::CopyPixelsIn(BBitmap *bitmap, BPoint location)
256848b8605Smrg{
257848b8605Smrg	CALLED();
258848b8605Smrg
259848b8605Smrg	color_space sourceCS = bitmap->ColorSpace();
260848b8605Smrg	color_space destinationCS = fBitmap->ColorSpace();
261848b8605Smrg
262848b8605Smrg	if (sourceCS != destinationCS
263848b8605Smrg		&& (sourceCS != B_RGB32 || destinationCS != B_RGBA32)) {
264848b8605Smrg		ERROR("%s::CopyPixelsIn(): incompatible color space: %s != %s\n",
265848b8605Smrg			__PRETTY_FUNCTION__, color_space_name(sourceCS),
266848b8605Smrg			color_space_name(destinationCS));
267848b8605Smrg		return B_BAD_TYPE;
268848b8605Smrg	}
269848b8605Smrg
270848b8605Smrg	BRect sr = bitmap->Bounds();
271848b8605Smrg	BRect dr = fBitmap->Bounds();
272848b8605Smrg
273848b8605Smrg	sr = sr & dr.OffsetBySelf(location);
274848b8605Smrg	dr = sr.OffsetByCopy(-location.x, -location.y);
275848b8605Smrg
276848b8605Smrg	uint8 *ps = (uint8 *) bitmap->Bits();
277848b8605Smrg	uint8 *pd = (uint8 *) fBitmap->Bits();
278848b8605Smrg	uint32 *s, *d;
279848b8605Smrg	uint32 y;
280848b8605Smrg
281848b8605Smrg	for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) {
282848b8605Smrg		s = (uint32 *)(ps + y * bitmap->BytesPerRow());
283848b8605Smrg		s += (uint32) sr.left;
284848b8605Smrg
285848b8605Smrg		d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top))
286848b8605Smrg			* fBitmap->BytesPerRow());
287848b8605Smrg		d += (uint32) dr.left;
288848b8605Smrg
289848b8605Smrg		memcpy(d, s, dr.IntegerWidth() * 4);
290848b8605Smrg	}
291848b8605Smrg
292848b8605Smrg	return B_OK;
293848b8605Smrg}
294848b8605Smrg
295848b8605Smrg
296848b8605Smrgvoid
297848b8605SmrgSoftwareRenderer::EnableDirectMode(bool enabled)
298848b8605Smrg{
299848b8605Smrg	fDirectModeEnabled = enabled;
300848b8605Smrg}
301848b8605Smrg
302848b8605Smrg
303848b8605Smrgvoid
304848b8605SmrgSoftwareRenderer::DirectConnected(direct_buffer_info *info)
305848b8605Smrg{
306848b8605Smrg//	CALLED();
307848b8605Smrg	BAutolock lock(fInfoLocker);
308848b8605Smrg	if (info) {
309848b8605Smrg		if (!fInfo) {
310848b8605Smrg			fInfo = (direct_buffer_info *)calloc(1,
311848b8605Smrg				DIRECT_BUFFER_INFO_AREA_SIZE);
312848b8605Smrg		}
313848b8605Smrg		memcpy(fInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
314848b8605Smrg	} else if (fInfo) {
315848b8605Smrg		free(fInfo);
316848b8605Smrg		fInfo = NULL;
317848b8605Smrg	}
318848b8605Smrg}
319848b8605Smrg
320848b8605Smrg
321848b8605Smrgvoid
322848b8605SmrgSoftwareRenderer::FrameResized(float width, float height)
323848b8605Smrg{
324848b8605Smrg	TRACE("%s: %f x %f\n", __func__, width, height);
325848b8605Smrg
326848b8605Smrg	BAutolock lock(fInfoLocker);
327b8e80941Smrg	fWidth = (GLuint)width;
328b8e80941Smrg	fHeight = (GLuint)height;
329848b8605Smrg}
330848b8605Smrg
331848b8605Smrg
332848b8605Smrgvoid
333848b8605SmrgSoftwareRenderer::_AllocateBitmap()
334848b8605Smrg{
335848b8605Smrg//	CALLED();
336848b8605Smrg
337848b8605Smrg	// allocate new size of back buffer bitmap
338848b8605Smrg	BAutolock lock(fInfoLocker);
339b8e80941Smrg	if (fBitmap)
340b8e80941Smrg		delete fBitmap;
341b8e80941Smrg
342848b8605Smrg	if (fWidth < 1 || fHeight < 1) {
343848b8605Smrg		TRACE("%s: Can't allocate bitmap of %dx%d\n", __func__,
344848b8605Smrg			fWidth, fHeight);
345848b8605Smrg		return;
346848b8605Smrg	}
347848b8605Smrg	BRect rect(0.0, 0.0, fWidth, fHeight);
348848b8605Smrg	fBitmap = new (std::nothrow) BBitmap(rect, fColorSpace);
349848b8605Smrg	if (fBitmap == NULL) {
350848b8605Smrg		TRACE("%s: Can't create bitmap!\n", __func__);
351848b8605Smrg		return;
352848b8605Smrg	}
353848b8605Smrg
354b8e80941Smrg	TRACE("%s: New bitmap size: %" B_PRId32 " x %" B_PRId32 "\n", __func__,
355848b8605Smrg		fBitmap->Bounds().IntegerWidth(), fBitmap->Bounds().IntegerHeight());
356848b8605Smrg
357848b8605Smrg#if 0
358848b8605Smrg	// debug..
359848b8605Smrg	void *data = fBitmap->Bits();
360848b8605Smrg	memset(data, 0xcc, fBitmap->BitsLength());
361848b8605Smrg#endif
362848b8605Smrg}
363