1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 2006-2012, Haiku, Inc. All rights reserved.
3bf215546Sopenharmony_ci * Distributed under the terms of the MIT License.
4bf215546Sopenharmony_ci *
5bf215546Sopenharmony_ci * Authors:
6bf215546Sopenharmony_ci *		Jérôme Duval, korli@users.berlios.de
7bf215546Sopenharmony_ci *		Philippe Houdoin, philippe.houdoin@free.fr
8bf215546Sopenharmony_ci *		Artur Wyszynski, harakash@gmail.com
9bf215546Sopenharmony_ci *		Alexander von Gluck IV, kallisti5@unixzen.com
10bf215546Sopenharmony_ci */
11bf215546Sopenharmony_ci
12bf215546Sopenharmony_ci
13bf215546Sopenharmony_ci#include "SoftwareRenderer.h"
14bf215546Sopenharmony_ci
15bf215546Sopenharmony_ci#include <Autolock.h>
16bf215546Sopenharmony_ci#include <interface/DirectWindowPrivate.h>
17bf215546Sopenharmony_ci#include <GraphicsDefs.h>
18bf215546Sopenharmony_ci#include <Screen.h>
19bf215546Sopenharmony_ci#include <stdio.h>
20bf215546Sopenharmony_ci#include <sys/time.h>
21bf215546Sopenharmony_ci#include <new>
22bf215546Sopenharmony_ci
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#ifdef DEBUG
25bf215546Sopenharmony_ci#	define TRACE(x...) printf("SoftwareRenderer: " x)
26bf215546Sopenharmony_ci#	define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
27bf215546Sopenharmony_ci#else
28bf215546Sopenharmony_ci#	define TRACE(x...)
29bf215546Sopenharmony_ci#	define CALLED()
30bf215546Sopenharmony_ci#endif
31bf215546Sopenharmony_ci#define ERROR(x...)	printf("SoftwareRenderer: " x)
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_ciextern const char* color_space_name(color_space space);
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ciextern "C" _EXPORT BGLRenderer*
38bf215546Sopenharmony_ciinstantiate_gl_renderer(BGLView *view, ulong opts)
39bf215546Sopenharmony_ci{
40bf215546Sopenharmony_ci	return new SoftwareRenderer(view, opts);
41bf215546Sopenharmony_ci}
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_cistruct RasBuf32
44bf215546Sopenharmony_ci{
45bf215546Sopenharmony_ci	int32 width, height, stride;
46bf215546Sopenharmony_ci	int32 orgX, orgY;
47bf215546Sopenharmony_ci	int32 *colors;
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci	RasBuf32(int32 width, int32 height, int32 stride, int32 orgX, int32 orgY, int32 *colors):
50bf215546Sopenharmony_ci		width(width), height(height), stride(stride), orgX(orgX), orgY(orgY), colors(colors)
51bf215546Sopenharmony_ci	{}
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci	RasBuf32(BBitmap *bmp)
54bf215546Sopenharmony_ci	{
55bf215546Sopenharmony_ci		width  = bmp->Bounds().IntegerWidth()  + 1;
56bf215546Sopenharmony_ci		height = bmp->Bounds().IntegerHeight() + 1;
57bf215546Sopenharmony_ci		stride = bmp->BytesPerRow()/4;
58bf215546Sopenharmony_ci		orgX   = 0;
59bf215546Sopenharmony_ci		orgY   = 0;
60bf215546Sopenharmony_ci		colors = (int32*)bmp->Bits();
61bf215546Sopenharmony_ci	}
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci	RasBuf32(direct_buffer_info *info)
64bf215546Sopenharmony_ci	{
65bf215546Sopenharmony_ci		width  = 0x7fffffff;
66bf215546Sopenharmony_ci		height = 0x7fffffff;
67bf215546Sopenharmony_ci		stride = info->bytes_per_row/4;
68bf215546Sopenharmony_ci		orgX   = 0;
69bf215546Sopenharmony_ci		orgY   = 0;
70bf215546Sopenharmony_ci		colors = (int32*)info->bits;
71bf215546Sopenharmony_ci	}
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci	void ClipSize(int32 x, int32 y, int32 w, int32 h)
74bf215546Sopenharmony_ci	{
75bf215546Sopenharmony_ci		if (x < 0) {w += x; x = 0;}
76bf215546Sopenharmony_ci		if (y < 0) {h += y; y = 0;}
77bf215546Sopenharmony_ci		if (x + w >  width) {w = width  - x;}
78bf215546Sopenharmony_ci		if (y + h > height) {h = height - y;}
79bf215546Sopenharmony_ci		if ((w > 0) && (h > 0)) {
80bf215546Sopenharmony_ci			colors += y*stride + x;
81bf215546Sopenharmony_ci			width  = w;
82bf215546Sopenharmony_ci			height = h;
83bf215546Sopenharmony_ci		} else {
84bf215546Sopenharmony_ci			width = 0; height = 0; colors = NULL;
85bf215546Sopenharmony_ci		}
86bf215546Sopenharmony_ci		if (x + orgX > 0) {orgX += x;} else {orgX = 0;}
87bf215546Sopenharmony_ci		if (y + orgY > 0) {orgY += y;} else {orgY = 0;}
88bf215546Sopenharmony_ci	}
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_ci	void ClipRect(int32 l, int32 t, int32 r, int32 b)
91bf215546Sopenharmony_ci	{
92bf215546Sopenharmony_ci		ClipSize(l, t, r - l, b - t);
93bf215546Sopenharmony_ci	}
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci	void Shift(int32 dx, int32 dy)
96bf215546Sopenharmony_ci	{
97bf215546Sopenharmony_ci		orgX += dx;
98bf215546Sopenharmony_ci		orgY += dy;
99bf215546Sopenharmony_ci	}
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci	void Clear(int32 color)
102bf215546Sopenharmony_ci	{
103bf215546Sopenharmony_ci		RasBuf32 dst = *this;
104bf215546Sopenharmony_ci		dst.stride -= dst.width;
105bf215546Sopenharmony_ci		for (; dst.height > 0; dst.height--) {
106bf215546Sopenharmony_ci			for (int32 i = dst.width; i > 0; i--)
107bf215546Sopenharmony_ci				*dst.colors++ = color;
108bf215546Sopenharmony_ci			dst.colors += dst.stride;
109bf215546Sopenharmony_ci		}
110bf215546Sopenharmony_ci	}
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci	void Blit(RasBuf32 src)
113bf215546Sopenharmony_ci	{
114bf215546Sopenharmony_ci		RasBuf32 dst = *this;
115bf215546Sopenharmony_ci		int32 x, y;
116bf215546Sopenharmony_ci		x = src.orgX - orgX;
117bf215546Sopenharmony_ci		y = src.orgY - orgY;
118bf215546Sopenharmony_ci		dst.ClipSize(x, y, src.width, src.height);
119bf215546Sopenharmony_ci		src.ClipSize(-x, -y, width, height);
120bf215546Sopenharmony_ci		for (; dst.height > 0; dst.height--) {
121bf215546Sopenharmony_ci			memcpy(dst.colors, src.colors, 4*dst.width);
122bf215546Sopenharmony_ci			dst.colors += dst.stride;
123bf215546Sopenharmony_ci			src.colors += src.stride;
124bf215546Sopenharmony_ci		}
125bf215546Sopenharmony_ci	}
126bf215546Sopenharmony_ci};
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ciSoftwareRenderer::SoftwareRenderer(BGLView *view, ulong options)
129bf215546Sopenharmony_ci	:
130bf215546Sopenharmony_ci	BGLRenderer(view, options),
131bf215546Sopenharmony_ci	fDirectModeEnabled(false),
132bf215546Sopenharmony_ci	fInfo(NULL),
133bf215546Sopenharmony_ci	fInfoLocker("info locker"),
134bf215546Sopenharmony_ci	fOptions(options),
135bf215546Sopenharmony_ci	fColorSpace(B_NO_COLOR_SPACE)
136bf215546Sopenharmony_ci{
137bf215546Sopenharmony_ci	CALLED();
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci	// Initialize the "Haiku Software GL Pipe"
140bf215546Sopenharmony_ci	time_t beg;
141bf215546Sopenharmony_ci	time_t end;
142bf215546Sopenharmony_ci	beg = time(NULL);
143bf215546Sopenharmony_ci	fContextObj = new GalliumContext(options);
144bf215546Sopenharmony_ci	end = time(NULL);
145bf215546Sopenharmony_ci	TRACE("Haiku Software GL Pipe initialization time: %f.\n",
146bf215546Sopenharmony_ci		difftime(end, beg));
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci	BRect b = view->Bounds();
149bf215546Sopenharmony_ci	fColorSpace = BScreen(view->Window()).ColorSpace();
150bf215546Sopenharmony_ci	TRACE("%s: Colorspace:\t%s\n", __func__, color_space_name(fColorSpace));
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci	fWidth = (GLint)b.IntegerWidth();
153bf215546Sopenharmony_ci	fHeight = (GLint)b.IntegerHeight();
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci	// Initialize the first "Haiku Software GL Pipe" context
156bf215546Sopenharmony_ci	beg = time(NULL);
157bf215546Sopenharmony_ci	fContextID = fContextObj->CreateContext(this);
158bf215546Sopenharmony_ci	end = time(NULL);
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci	if (fContextID < 0)
161bf215546Sopenharmony_ci		ERROR("%s: There was an error creating the context!\n", __func__);
162bf215546Sopenharmony_ci	else {
163bf215546Sopenharmony_ci		TRACE("%s: Haiku Software GL Pipe context creation time: %f.\n",
164bf215546Sopenharmony_ci			__func__, difftime(end, beg));
165bf215546Sopenharmony_ci	}
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_ci	if (!fContextObj->GetCurrentContext())
168bf215546Sopenharmony_ci		LockGL();
169bf215546Sopenharmony_ci}
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ciSoftwareRenderer::~SoftwareRenderer()
173bf215546Sopenharmony_ci{
174bf215546Sopenharmony_ci	CALLED();
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_ci	if (fContextObj)
177bf215546Sopenharmony_ci		delete fContextObj;
178bf215546Sopenharmony_ci}
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_civoid
182bf215546Sopenharmony_ciSoftwareRenderer::LockGL()
183bf215546Sopenharmony_ci{
184bf215546Sopenharmony_ci//	CALLED();
185bf215546Sopenharmony_ci	BGLRenderer::LockGL();
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci	color_space cs = BScreen(GLView()->Window()).ColorSpace();
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci	{
190bf215546Sopenharmony_ci		BAutolock lock(fInfoLocker);
191bf215546Sopenharmony_ci		if (fDirectModeEnabled && fInfo != NULL) {
192bf215546Sopenharmony_ci			fWidth = fInfo->window_bounds.right - fInfo->window_bounds.left;
193bf215546Sopenharmony_ci			fHeight = fInfo->window_bounds.bottom - fInfo->window_bounds.top;
194bf215546Sopenharmony_ci		}
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci		fContextObj->Validate(fWidth, fHeight);
197bf215546Sopenharmony_ci		fColorSpace = cs;
198bf215546Sopenharmony_ci	}
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci	// do not hold fInfoLocker here to avoid deadlock
201bf215546Sopenharmony_ci	fContextObj->SetCurrentContext(true, fContextID);
202bf215546Sopenharmony_ci}
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_civoid
206bf215546Sopenharmony_ciSoftwareRenderer::UnlockGL()
207bf215546Sopenharmony_ci{
208bf215546Sopenharmony_ci//	CALLED();
209bf215546Sopenharmony_ci	if ((fOptions & BGL_DOUBLE) == 0) {
210bf215546Sopenharmony_ci		SwapBuffers();
211bf215546Sopenharmony_ci	}
212bf215546Sopenharmony_ci	fContextObj->SetCurrentContext(false, fContextID);
213bf215546Sopenharmony_ci	BGLRenderer::UnlockGL();
214bf215546Sopenharmony_ci}
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_civoid
218bf215546Sopenharmony_ciSoftwareRenderer::Display(BBitmap *bitmap, BRect *updateRect)
219bf215546Sopenharmony_ci{
220bf215546Sopenharmony_ci//	CALLED();
221bf215546Sopenharmony_ci
222bf215546Sopenharmony_ci	if (!fDirectModeEnabled) {
223bf215546Sopenharmony_ci		// TODO: avoid timeout
224bf215546Sopenharmony_ci		if (GLView()->LockLooperWithTimeout(1000) == B_OK) {
225bf215546Sopenharmony_ci			GLView()->DrawBitmap(bitmap, B_ORIGIN);
226bf215546Sopenharmony_ci			GLView()->UnlockLooper();
227bf215546Sopenharmony_ci		}
228bf215546Sopenharmony_ci	} else {
229bf215546Sopenharmony_ci		BAutolock lock(fInfoLocker);
230bf215546Sopenharmony_ci		if (fInfo != NULL) {
231bf215546Sopenharmony_ci			RasBuf32 srcBuf(bitmap);
232bf215546Sopenharmony_ci			RasBuf32 dstBuf(fInfo);
233bf215546Sopenharmony_ci			for (uint32 i = 0; i < fInfo->clip_list_count; i++) {
234bf215546Sopenharmony_ci				clipping_rect *clip = &fInfo->clip_list[i];
235bf215546Sopenharmony_ci				RasBuf32 dstClip = dstBuf;
236bf215546Sopenharmony_ci				dstClip.ClipRect(clip->left, clip->top, clip->right + 1, clip->bottom + 1);
237bf215546Sopenharmony_ci				dstClip.Shift(-fInfo->window_bounds.left, -fInfo->window_bounds.top);
238bf215546Sopenharmony_ci				dstClip.Blit(srcBuf);
239bf215546Sopenharmony_ci			}
240bf215546Sopenharmony_ci		}
241bf215546Sopenharmony_ci	}
242bf215546Sopenharmony_ci}
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_civoid
246bf215546Sopenharmony_ciSoftwareRenderer::SwapBuffers(bool vsync)
247bf215546Sopenharmony_ci{
248bf215546Sopenharmony_ci	BScreen screen(GLView()->Window());
249bf215546Sopenharmony_ci	fContextObj->SwapBuffers(fContextID);
250bf215546Sopenharmony_ci	fContextObj->Validate(fWidth, fHeight);
251bf215546Sopenharmony_ci	if (vsync)
252bf215546Sopenharmony_ci		screen.WaitForRetrace();
253bf215546Sopenharmony_ci}
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_civoid
256bf215546Sopenharmony_ciSoftwareRenderer::Draw(BRect updateRect)
257bf215546Sopenharmony_ci{
258bf215546Sopenharmony_ci//	CALLED();
259bf215546Sopenharmony_ci	fContextObj->Draw(fContextID, updateRect);
260bf215546Sopenharmony_ci}
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_cistatus_t
264bf215546Sopenharmony_ciSoftwareRenderer::CopyPixelsOut(BPoint location, BBitmap *bitmap)
265bf215546Sopenharmony_ci{
266bf215546Sopenharmony_ci	CALLED();
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_ci	// TODO: implement
269bf215546Sopenharmony_ci	return B_ERROR;
270bf215546Sopenharmony_ci}
271bf215546Sopenharmony_ci
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_cistatus_t
274bf215546Sopenharmony_ciSoftwareRenderer::CopyPixelsIn(BBitmap *bitmap, BPoint location)
275bf215546Sopenharmony_ci{
276bf215546Sopenharmony_ci	CALLED();
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci	// TODO: implement
279bf215546Sopenharmony_ci	return B_ERROR;
280bf215546Sopenharmony_ci}
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_ci
283bf215546Sopenharmony_civoid
284bf215546Sopenharmony_ciSoftwareRenderer::EnableDirectMode(bool enabled)
285bf215546Sopenharmony_ci{
286bf215546Sopenharmony_ci	fDirectModeEnabled = enabled;
287bf215546Sopenharmony_ci}
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci
290bf215546Sopenharmony_civoid
291bf215546Sopenharmony_ciSoftwareRenderer::DirectConnected(direct_buffer_info *info)
292bf215546Sopenharmony_ci{
293bf215546Sopenharmony_ci//	CALLED();
294bf215546Sopenharmony_ci	BAutolock lock(fInfoLocker);
295bf215546Sopenharmony_ci	if (info) {
296bf215546Sopenharmony_ci		if (!fInfo) {
297bf215546Sopenharmony_ci			fInfo = (direct_buffer_info *)calloc(1,
298bf215546Sopenharmony_ci				DIRECT_BUFFER_INFO_AREA_SIZE);
299bf215546Sopenharmony_ci		}
300bf215546Sopenharmony_ci		memcpy(fInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
301bf215546Sopenharmony_ci	} else if (fInfo) {
302bf215546Sopenharmony_ci		free(fInfo);
303bf215546Sopenharmony_ci		fInfo = NULL;
304bf215546Sopenharmony_ci	}
305bf215546Sopenharmony_ci}
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_civoid
309bf215546Sopenharmony_ciSoftwareRenderer::FrameResized(float width, float height)
310bf215546Sopenharmony_ci{
311bf215546Sopenharmony_ci	TRACE("%s: %f x %f\n", __func__, width, height);
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci	BAutolock lock(fInfoLocker);
314bf215546Sopenharmony_ci	fWidth = (GLuint)width;
315bf215546Sopenharmony_ci	fHeight = (GLuint)height;
316bf215546Sopenharmony_ci}
317