1/*
2 * Copyright 2006-2011, 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, kallisti5@unixzen.com
10 */
11/*
12 * Mesa 3-D graphics library
13 * Version:  6.1
14 *
15 * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
16 */
17
18
19#include "MesaSoftwareRenderer.h"
20
21#include <Autolock.h>
22#include <DirectWindowPrivate.h>
23#include <GraphicsDefs.h>
24#include <Screen.h>
25#include <stdio.h>
26#include <string.h>
27
28extern "C" {
29#include "extensions.h"
30#include "drivers/common/driverfuncs.h"
31#include "drivers/common/meta.h"
32#include "main/colormac.h"
33#include "main/cpuinfo.h"
34#include "main/buffers.h"
35#include "main/formats.h"
36#include "main/framebuffer.h"
37#include "main/renderbuffer.h"
38#include "swrast/swrast.h"
39#include "swrast_setup/swrast_setup.h"
40#include "tnl/tnl.h"
41#include "tnl/t_context.h"
42#include "tnl/t_pipeline.h"
43#include "vbo/vbo.h"
44
45
46//#define TRACE_SOFTGL
47#ifdef TRACE_SOFTGL
48#	define TRACE(x...) printf("MesaSoftwareRenderer: " x)
49#	define CALLED() printf("MesaSoftwareRenderer: %s\n", __PRETTY_FUNCTION__)
50#else
51#	define TRACE(x...)
52#	define CALLED()
53#endif
54
55#define ERROR(x...) printf("MesaSoftwareRenderer: " x)
56}
57
58
59extern const char* color_space_name(color_space space);
60
61
62// BeOS component ordering for B_RGBA32 bitmap format
63#if B_HOST_IS_LENDIAN
64#define BE_RCOMP 2
65#define BE_GCOMP 1
66#define BE_BCOMP 0
67#define BE_ACOMP 3
68#else
69// Big Endian B_RGBA32 bitmap format
70#define BE_RCOMP 1
71#define BE_GCOMP 2
72#define BE_BCOMP 3
73#define BE_ACOMP 0
74#endif
75
76
77/**********************************************************************/
78/*****        Read/write spans/arrays of pixels                   *****/
79/**********************************************************************/
80extern "C" {
81
82/* 32-bit RGBA */
83#define NAME(PREFIX) PREFIX##_RGBA32
84#define RB_TYPE GLubyte
85#define SPAN_VARS \
86	MesaSoftwareRenderer* mr = (MesaSoftwareRenderer*)ctx->DriverCtx;
87#define INIT_PIXEL_PTR(P, X, Y) \
88	GLubyte* P = ((GLubyte**)mr->GetRows())[Y] + (X) * 4
89#define INC_PIXEL_PTR(P) P += 4
90#define STORE_PIXEL(DST, X, Y, VALUE) \
91	DST[BE_RCOMP] = VALUE[RCOMP];  \
92	DST[BE_GCOMP] = VALUE[GCOMP];  \
93	DST[BE_BCOMP] = VALUE[BCOMP];  \
94	DST[BE_ACOMP] = VALUE[ACOMP]
95#define STORE_PIXEL_RGB(DST, X, Y, VALUE) \
96	DST[BE_RCOMP] = VALUE[RCOMP];  \
97	DST[BE_GCOMP] = VALUE[GCOMP];  \
98	DST[BE_BCOMP] = VALUE[BCOMP];  \
99	DST[BE_ACOMP] = 255
100#define FETCH_PIXEL(DST, SRC) \
101	DST[RCOMP] = SRC[BE_RCOMP];  \
102	DST[GCOMP] = SRC[BE_GCOMP];  \
103	DST[BCOMP] = SRC[BE_BCOMP];  \
104	DST[ACOMP] = SRC[BE_ACOMP]
105#include "swrast/s_spantemp.h"
106
107/* 32-bit RGB */
108#define NAME(PREFIX) PREFIX##_RGB32
109#define RB_TYPE GLubyte
110#define SPAN_VARS \
111	MesaSoftwareRenderer* mr = (MesaSoftwareRenderer*)ctx->DriverCtx;
112#define INIT_PIXEL_PTR(P, X, Y) \
113	GLuint* P = (GLuint*)(((GLubyte**)mr->GetRows())[Y] + (X) * 4)
114#define INC_PIXEL_PTR(P) P += 1
115#define STORE_PIXEL(DST, X, Y, VALUE) \
116	*DST = ( ((VALUE[RCOMP]) << 16) | \
117		((VALUE[GCOMP]) << 8) | \
118		((VALUE[BCOMP]) ) )
119#define FETCH_PIXEL(DST, SRC) \
120	DST[RCOMP] = ((*SRC & 0x00ff0000) >> 16);  \
121	DST[GCOMP] = ((*SRC & 0x0000ff00) >> 8);  \
122	DST[BCOMP] = ((*SRC & 0x000000ff)); \
123	DST[ACOMP] = 0xff;
124#include "swrast/s_spantemp.h"
125
126/* 24-bit RGB */
127#define NAME(PREFIX) PREFIX##_RGB24
128#define RB_TYPE GLubyte
129#define SPAN_VARS \
130	MesaSoftwareRenderer* mr = (MesaSoftwareRenderer*)ctx->DriverCtx;
131#define INIT_PIXEL_PTR(P, X, Y) \
132	GLubyte* P = ((GLubyte**)mr->GetRows())[Y] + (X) * 3
133#define INC_PIXEL_PTR(P) P += 3
134#define STORE_PIXEL(DST, X, Y, VALUE) \
135	DST[BE_RCOMP] = VALUE[RCOMP]; \
136	DST[BE_GCOMP] = VALUE[GCOMP]; \
137	DST[BE_BCOMP] = VALUE[BCOMP];
138#define FETCH_PIXEL(DST, SRC) \
139	DST[RCOMP] = SRC[BE_RCOMP];  \
140	DST[GCOMP] = SRC[BE_GCOMP];  \
141	DST[BCOMP] = SRC[BE_BCOMP]; \
142	DST[ACOMP] = 0xff;
143#include "swrast/s_spantemp.h"
144
145/* 16-bit RGB */
146#define NAME(PREFIX) PREFIX##_RGB16
147#define RB_TYPE GLubyte
148#define SPAN_VARS \
149	MesaSoftwareRenderer* mr = (MesaSoftwareRenderer*)ctx->DriverCtx;
150#define INIT_PIXEL_PTR(P, X, Y) \
151	GLushort* P = (GLushort*)(((GLubyte**)mr->GetRows())[Y] + (X) * 2)
152#define INC_PIXEL_PTR(P) P += 1
153#define STORE_PIXEL(DST, X, Y, VALUE) \
154	*DST = ( (((VALUE[RCOMP]) & 0xf8) << 8) | \
155		(((VALUE[GCOMP]) & 0xfc) << 3) | \
156		(((VALUE[BCOMP])       ) >> 3) )
157#define FETCH_PIXEL(DST, SRC) \
158	DST[RCOMP] = ((*SRC & 0xf800) >> 8); \
159	DST[GCOMP] = ((*SRC & 0x07e0) >> 3); \
160	DST[BCOMP] = ((*SRC & 0x001f) << 3); \
161	DST[ACOMP] = 0xff
162#include "swrast/s_spantemp.h"
163
164/* 15-bit RGB */
165#define NAME(PREFIX) PREFIX##_RGB15
166#define RB_TYPE GLubyte
167#define SPAN_VARS \
168	MesaSoftwareRenderer* mr = (MesaSoftwareRenderer*)ctx->DriverCtx;
169#define INIT_PIXEL_PTR(P, X, Y) \
170	GLushort* P = (GLushort*)(((GLubyte**)mr->GetRows())[Y] + (X) * 2)
171#define INC_PIXEL_PTR(P) P += 1
172#define STORE_PIXEL(DST, X, Y, VALUE) \
173	*DST = ( (((VALUE[RCOMP]) & 0xf8) << 7) | \
174		(((VALUE[GCOMP]) & 0xf8) << 2) | \
175		(((VALUE[BCOMP])       ) >> 3) )
176#define FETCH_PIXEL(DST, SRC) \
177	DST[RCOMP] = ((*SRC & 0x7c00) >> 7); \
178	DST[GCOMP] = ((*SRC & 0x03e0) >> 2); \
179	DST[BCOMP] = ((*SRC & 0x001f) << 3); \
180	DST[ACOMP] = 0xff
181#include "swrast/s_spantemp.h"
182}
183
184
185extern "C" _EXPORT BGLRenderer*
186instantiate_gl_renderer(BGLView* view, ulong options,
187	BGLDispatcher* dispatcher)
188{
189	return new MesaSoftwareRenderer(view, options, dispatcher);
190}
191
192
193MesaSoftwareRenderer::MesaSoftwareRenderer(BGLView* view, ulong options,
194	BGLDispatcher* dispatcher)
195	: BGLRenderer(view, options, dispatcher),
196	fBitmap(NULL),
197	fDirectModeEnabled(false),
198	fInfo(NULL),
199	fInfoLocker("info locker"),
200	fContext(NULL),
201	fVisual(NULL),
202	fFrameBuffer(NULL),
203	fFrontRenderBuffer(NULL),
204	fBackRenderBuffer(NULL),
205	fColorSpace(B_NO_COLOR_SPACE)
206{
207	CALLED();
208
209	fClearColor[BE_RCOMP] = 0;
210	fClearColor[BE_GCOMP] = 0;
211	fClearColor[BE_BCOMP] = 0;
212	fClearColor[BE_ACOMP] = 0;
213
214	fClearIndex = 0;
215
216	fColorSpace = BScreen(GLView()->Window()).ColorSpace();
217
218	// We force single buffering for the time being
219	options &= ~BGL_DOUBLE;
220
221	const GLboolean rgbFlag = ((options & BGL_INDEX) == 0);
222	const GLboolean alphaFlag = ((options & BGL_ALPHA) == BGL_ALPHA);
223	const GLboolean dblFlag = ((options & BGL_DOUBLE) == BGL_DOUBLE);
224	const GLboolean stereoFlag = false;
225	const GLint depth = (options & BGL_DEPTH) ? 16 : 0;
226	const GLint stencil = (options & BGL_STENCIL) ? 8 : 0;
227	const GLint accum = (options & BGL_ACCUM) ? 16 : 0;
228	const GLint red = rgbFlag ? 8 : 0;
229	const GLint green = rgbFlag ? 8 : 0;
230	const GLint blue = rgbFlag ? 8 : 0;
231	const GLint alpha = alphaFlag ? 8 : 0;
232
233	fOptions = options; // | BGL_INDIRECT;
234	struct dd_function_table functions;
235
236	fVisual = _mesa_create_visual(dblFlag, stereoFlag, red, green,
237		blue, alpha, depth, stencil, accum, accum, accum,
238		alpha ? accum : 0, 1);
239
240	// Initialize device driver function table
241	_mesa_init_driver_functions(&functions);
242
243	functions.GetString 	= _GetString;
244	functions.UpdateState 	= _UpdateState;
245	functions.GetBufferSize = NULL;
246	functions.Error			= _Error;
247	functions.Viewport		= _Viewport;
248	functions.Flush			= _Flush;
249
250	// create core context
251	fContext = _mesa_create_context(fVisual, NULL, &functions, this);
252
253	if (!fContext) {
254		ERROR("%s: Failed to create Mesa context!\n", __func__);
255		_mesa_destroy_visual(fVisual);
256		return;
257	}
258
259	/* Initialize the software rasterizer and helper modules. */
260	_swrast_CreateContext(fContext);
261	_vbo_CreateContext(fContext);
262	_tnl_CreateContext(fContext);
263	_swsetup_CreateContext(fContext);
264	_swsetup_Wakeup(fContext);
265
266	// Use default TCL pipeline
267	TNL_CONTEXT(fContext)->Driver.RunPipeline = _tnl_run_pipeline;
268
269	_mesa_meta_init(fContext);
270	_mesa_enable_sw_extensions(fContext);
271	_mesa_enable_1_3_extensions(fContext);
272	_mesa_enable_1_4_extensions(fContext);
273	_mesa_enable_1_5_extensions(fContext);
274	_mesa_enable_2_0_extensions(fContext);
275	_mesa_enable_2_1_extensions(fContext);
276
277	// create core framebuffer
278	fFrameBuffer = (struct msr_framebuffer*)calloc(1,
279		sizeof(*fFrameBuffer));
280	if (fFrameBuffer == NULL) {
281		ERROR("%s: Unable to calloc GL FrameBuffer!\n", __func__);
282		_mesa_destroy_visual(fVisual);
283		return;
284	}
285	_mesa_initialize_window_framebuffer(&fFrameBuffer->base, fVisual);
286
287	// Setup front render buffer
288	fFrontRenderBuffer = _NewRenderBuffer(true);
289	if (fFrontRenderBuffer == NULL) {
290		ERROR("%s: FrontRenderBuffer is requested but unallocated!\n",
291			__func__);
292		_mesa_destroy_visual(fVisual);
293		free(fFrameBuffer);
294		return;
295	}
296	_mesa_add_renderbuffer(&fFrameBuffer->base, BUFFER_FRONT_LEFT,
297		&fFrontRenderBuffer->base);
298
299	// Setup back render buffer (if requested)
300	if (fVisual->doubleBufferMode) {
301		fBackRenderBuffer = _NewRenderBuffer(false);
302		if (fBackRenderBuffer == NULL) {
303			ERROR("%s: BackRenderBuffer is requested but unallocated!\n",
304				__func__);
305			_mesa_destroy_visual(fVisual);
306			free(fFrameBuffer);
307			return;
308		}
309		_mesa_add_renderbuffer(&fFrameBuffer->base, BUFFER_BACK_LEFT,
310			&fBackRenderBuffer->base);
311	}
312
313	_mesa_add_soft_renderbuffers(&fFrameBuffer->base, GL_FALSE,
314		fVisual->haveDepthBuffer, fVisual->haveStencilBuffer,
315		fVisual->haveAccumBuffer, alphaFlag, GL_FALSE);
316
317	BRect bounds = view->Bounds();
318	fWidth = fNewWidth = (GLint)bounds.Width();
319	fHeight = fNewHeight = (GLint)bounds.Height();
320
321	// some stupid applications (Quake2) don't even think about calling LockGL()
322	// before using glGetString and its glGet*() friends...
323	// so make sure there is at least a valid context.
324
325	if (!_mesa_get_current_context()) {
326		LockGL();
327		// not needed, we don't have a looper yet: UnlockLooper();
328	}
329}
330
331
332MesaSoftwareRenderer::~MesaSoftwareRenderer()
333{
334	CALLED();
335	_swsetup_DestroyContext(fContext);
336	_swrast_DestroyContext(fContext);
337	_tnl_DestroyContext(fContext);
338	_vbo_DestroyContext(fContext);
339	_mesa_destroy_visual(fVisual);
340	_mesa_destroy_framebuffer(&fFrameBuffer->base);
341	_mesa_destroy_context(fContext);
342
343	free(fInfo);
344	free(fFrameBuffer);
345
346	delete fBitmap;
347}
348
349
350void
351MesaSoftwareRenderer::LockGL()
352{
353	CALLED();
354	BGLRenderer::LockGL();
355
356	_mesa_make_current(fContext, &fFrameBuffer->base, &fFrameBuffer->base);
357
358	color_space colorSpace = BScreen(GLView()->Window()).ColorSpace();
359
360	BAutolock lock(fInfoLocker);
361	if (fDirectModeEnabled && fInfo != NULL) {
362		fNewWidth = fInfo->window_bounds.right
363			- fInfo->window_bounds.left + 1;
364		fNewHeight = fInfo->window_bounds.bottom
365			- fInfo->window_bounds.top + 1;
366	}
367
368	if (fColorSpace != colorSpace) {
369		fColorSpace = colorSpace;
370		_SetupRenderBuffer(fFrontRenderBuffer, fColorSpace);
371		if (fVisual->doubleBufferMode)
372			_SetupRenderBuffer(fBackRenderBuffer, fColorSpace);
373	}
374
375	_CheckResize();
376}
377
378
379void
380MesaSoftwareRenderer::UnlockGL()
381{
382	CALLED();
383	_mesa_make_current(fContext, NULL, NULL);
384	BGLRenderer::UnlockGL();
385}
386
387
388void
389MesaSoftwareRenderer::SwapBuffers(bool VSync)
390{
391	CALLED();
392
393	if (!fBitmap)
394		return;
395
396	if (fVisual->doubleBufferMode)
397		_mesa_notifySwapBuffers(fContext);
398
399	if (!fDirectModeEnabled || fInfo == NULL) {
400		if (GLView()->LockLooperWithTimeout(1000) == B_OK) {
401			GLView()->DrawBitmap(fBitmap, B_ORIGIN);
402			GLView()->UnlockLooper();
403		}
404	} else {
405		// TODO: Here the BGLView needs to be drawlocked.
406		_CopyToDirect();
407	}
408
409	if (VSync) {
410		BScreen screen(GLView()->Window());
411		screen.WaitForRetrace();
412	}
413}
414
415
416void
417MesaSoftwareRenderer::Draw(BRect updateRect)
418{
419	CALLED();
420	if (fBitmap && (!fDirectModeEnabled || (fInfo == NULL)))
421		GLView()->DrawBitmap(fBitmap, updateRect, updateRect);
422}
423
424
425status_t
426MesaSoftwareRenderer::CopyPixelsOut(BPoint location, BBitmap* bitmap)
427{
428	CALLED();
429	color_space scs = fBitmap->ColorSpace();
430	color_space dcs = bitmap->ColorSpace();
431
432	if (scs != dcs && (scs != B_RGBA32 || dcs != B_RGB32)) {
433		fprintf(stderr, "CopyPixelsOut(): incompatible color space: %s != %s\n",
434			color_space_name(scs),
435			color_space_name(dcs));
436		return B_BAD_TYPE;
437	}
438
439	BRect sr = fBitmap->Bounds();
440	BRect dr = bitmap->Bounds();
441
442	sr = sr & dr.OffsetBySelf(location);
443	dr = sr.OffsetByCopy(-location.x, -location.y);
444
445	uint8* ps = (uint8*) fBitmap->Bits();
446	uint8* pd = (uint8*) bitmap->Bits();
447	uint32* s;
448	uint32* d;
449	uint32 y;
450	for (y = (uint32) sr.top; y <= (uint32)sr.bottom; y++) {
451		s = (uint32*)(ps + y * fBitmap->BytesPerRow());
452		s += (uint32) sr.left;
453
454		d = (uint32*)(pd + (y + (uint32)(dr.top - sr.top))
455			* bitmap->BytesPerRow());
456		d += (uint32) dr.left;
457
458		memcpy(d, s, dr.IntegerWidth() * 4);
459	}
460	return B_OK;
461}
462
463
464status_t
465MesaSoftwareRenderer::CopyPixelsIn(BBitmap* bitmap, BPoint location)
466{
467	CALLED();
468	color_space scs = bitmap->ColorSpace();
469	color_space dcs = fBitmap->ColorSpace();
470
471	if (scs != dcs && (dcs != B_RGBA32 || scs != B_RGB32)) {
472		fprintf(stderr, "CopyPixelsIn(): incompatible color space: %s != %s\n",
473			color_space_name(scs),
474			color_space_name(dcs));
475		return B_BAD_TYPE;
476	}
477
478	BRect sr = bitmap->Bounds();
479	BRect dr = fBitmap->Bounds();
480
481	sr = sr & dr.OffsetBySelf(location);
482	dr = sr.OffsetByCopy(-location.x, -location.y);
483
484	uint8* ps = (uint8*) bitmap->Bits();
485	uint8* pd = (uint8*) fBitmap->Bits();
486	uint32* s;
487	uint32* d;
488	uint32 y;
489	for (y = (uint32) sr.top; y <= (uint32)sr.bottom; y++) {
490		s = (uint32*)(ps + y * bitmap->BytesPerRow());
491		s += (uint32) sr.left;
492
493		d = (uint32*)(pd + (y + (uint32)(dr.top - sr.top))
494			* fBitmap->BytesPerRow());
495		d += (uint32) dr.left;
496
497		memcpy(d, s, dr.IntegerWidth() * 4);
498	}
499	return B_OK;
500}
501
502
503void
504MesaSoftwareRenderer::EnableDirectMode(bool enabled)
505{
506	fDirectModeEnabled = enabled;
507}
508
509
510void
511MesaSoftwareRenderer::DirectConnected(direct_buffer_info* info)
512{
513	// TODO: I'm not sure we need to do this: BGLView already
514	// keeps a local copy of the direct_buffer_info passed by
515	// BDirectWindow::DirectConnected().
516	BAutolock lock(fInfoLocker);
517	if (info) {
518		if (!fInfo) {
519			fInfo = (direct_buffer_info*)malloc(DIRECT_BUFFER_INFO_AREA_SIZE);
520			if (!fInfo)
521				return;
522		}
523		memcpy(fInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
524	} else if (fInfo) {
525		free(fInfo);
526		fInfo = NULL;
527	}
528}
529
530
531void
532MesaSoftwareRenderer::FrameResized(float width, float height)
533{
534	BAutolock lock(fInfoLocker);
535	fNewWidth = (GLuint)width;
536	fNewHeight = (GLuint)height;
537	_CheckResize();
538}
539
540
541void
542MesaSoftwareRenderer::_CheckResize()
543{
544	CALLED();
545
546	if (fBitmap && fNewWidth == fWidth
547		&& fNewHeight == fHeight) {
548		return;
549	}
550
551	fHeight = fNewHeight;
552	fWidth = fNewWidth;
553	_mesa_resize_framebuffer(fContext, &fFrameBuffer->base, fWidth, fHeight);
554
555	_AllocateBitmap();
556}
557
558
559void
560MesaSoftwareRenderer::_AllocateBitmap()
561{
562	CALLED();
563	// allocate new size of back buffer bitmap
564	delete fBitmap;
565	fBitmap = NULL;
566
567	if (fWidth < 1 || fHeight < 1) {
568		TRACE("%s: Cannot allocate bitmap < 1x1!\n", __func__);
569		return;
570	}
571
572	BRect rect(0.0, 0.0, fWidth - 1, fHeight - 1);
573	fBitmap = new BBitmap(rect, fColorSpace);
574	for (uint i = 0; i < fHeight; i++) {
575		fRowAddr[fHeight - i - 1] = (GLvoid *)((GLubyte *)fBitmap->Bits()
576			+ i * fBitmap->BytesPerRow());
577	}
578
579	fFrontRenderBuffer->size = fBitmap->BitsLength();
580	if (fVisual->doubleBufferMode)
581		fBackRenderBuffer->size = fBitmap->BitsLength();
582	fFrameBuffer->width = fWidth;
583	fFrameBuffer->height = fHeight;
584	TRACE("%s: Bitmap Size: %" B_PRIu32 "\n", __func__, fBitmap->BitsLength());
585
586	fFrontRenderBuffer->base.Data = fBitmap->Bits();
587}
588
589
590// #pragma mark - static
591
592
593void
594MesaSoftwareRenderer::_Error(gl_context* ctx)
595{
596	MesaSoftwareRenderer* mr = (MesaSoftwareRenderer*)ctx->DriverCtx;
597	if (mr && mr->GLView())
598		mr->GLView()->ErrorCallback((unsigned long)ctx->ErrorValue);
599}
600
601
602const GLubyte*
603MesaSoftwareRenderer::_GetString(gl_context* ctx, GLenum name)
604{
605
606	switch (name) {
607		case GL_VENDOR:
608			return (const GLubyte*) "Mesa Project";
609		case GL_RENDERER: {
610			_mesa_get_cpu_features();
611			static char buffer[256] = { '\0' };
612
613			if (!buffer[0]) {
614				char* cpuInfo = _mesa_get_cpu_string();
615				// Let's build an renderer string
616				sprintf(buffer, "Software Rasterizer for %s", cpuInfo);
617				free(cpuInfo);
618			}
619			return (const GLubyte*) buffer;
620		}
621		default:
622			// Let core library handle all other cases
623			return NULL;
624	}
625}
626
627
628void
629MesaSoftwareRenderer::_Viewport(gl_context* ctx, GLint x, GLint y, GLsizei w,
630	GLsizei h)
631{
632	CALLED();
633
634	gl_framebuffer* draw = ctx->WinSysDrawBuffer;
635	gl_framebuffer* read = ctx->WinSysReadBuffer;
636	struct msr_framebuffer* msr = msr_framebuffer(draw);
637
638	_mesa_resize_framebuffer(ctx, draw, msr->width, msr->height);
639	_mesa_resize_framebuffer(ctx, read, msr->width, msr->height);
640}
641
642
643void
644MesaSoftwareRenderer::_UpdateState(gl_context* ctx, GLuint new_state)
645{
646	if (!ctx)
647		return;
648
649	CALLED();
650	_swrast_InvalidateState(ctx, new_state);
651	_swsetup_InvalidateState(ctx, new_state);
652	_vbo_InvalidateState(ctx, new_state);
653	_tnl_InvalidateState(ctx, new_state);
654}
655
656
657void
658MesaSoftwareRenderer::_ClearFront(gl_context* ctx)
659{
660	CALLED();
661
662	MesaSoftwareRenderer* mr = (MesaSoftwareRenderer*)ctx->DriverCtx;
663	BGLView* bglview = mr->GLView();
664	assert(bglview);
665	BBitmap* bitmap = mr->fBitmap;
666	assert(bitmap);
667	GLuint* start = (GLuint*)bitmap->Bits();
668	size_t pixelSize = 0;
669	get_pixel_size_for(bitmap->ColorSpace(), &pixelSize, NULL, NULL);
670	const GLuint* clearPixelPtr = (const GLuint*)mr->fClearColor;
671	const GLuint clearPixel = B_LENDIAN_TO_HOST_INT32(*clearPixelPtr);
672
673	int x = ctx->DrawBuffer->_Xmin;
674	int y = ctx->DrawBuffer->_Ymin;
675	uint32 width = ctx->DrawBuffer->_Xmax - x;
676	uint32 height = ctx->DrawBuffer->_Ymax - y;
677	GLboolean all = (width == ctx->DrawBuffer->Width
678		&& height == ctx->DrawBuffer->Height);
679
680	if (all) {
681		const int numPixels = mr->fWidth * mr->fHeight;
682		if (clearPixel == 0) {
683			memset(start, 0, numPixels * pixelSize);
684		} else {
685			for (int i = 0; i < numPixels; i++) {
686				start[i] = clearPixel;
687			}
688		}
689	} else {
690		// XXX untested
691		start += y * mr->fWidth + x;
692		for (uint32 i = 0; i < height; i++) {
693			for (uint32 j = 0; j < width; j++) {
694				start[j] = clearPixel;
695			}
696			start += mr->fWidth;
697		}
698	}
699}
700
701
702GLboolean
703MesaSoftwareRenderer::_FrontRenderbufferStorage(gl_context* ctx,
704	struct gl_renderbuffer* render, GLenum internalFormat,
705	GLuint width, GLuint height)
706{
707	CALLED();
708
709	render->Data = NULL;
710	render->Width = width;
711	render->Height = height;
712
713	return GL_TRUE;
714}
715
716
717GLboolean
718MesaSoftwareRenderer::_BackRenderbufferStorage(gl_context* ctx,
719	struct gl_renderbuffer* render, GLenum internalFormat,
720	GLuint width, GLuint height)
721{
722	CALLED();
723	struct msr_renderbuffer* mrb = msr_renderbuffer(render);
724
725	free(render->Data);
726	_FrontRenderbufferStorage(ctx, render, internalFormat, width, height);
727
728	if (mrb->size)
729		ERROR("%s: suspicious malloc of 0 bytes.\n", __func__);
730	render->Data = malloc(mrb->size);
731
732	return GL_TRUE;
733}
734
735
736void
737MesaSoftwareRenderer::_Flush(gl_context* ctx)
738{
739	CALLED();
740	MesaSoftwareRenderer* mr = (MesaSoftwareRenderer*)ctx->DriverCtx;
741	if ((mr->fOptions & BGL_DOUBLE) == 0) {
742		// TODO: SwapBuffers() can call _CopyToDirect(), which should
743		// be always called with with the BGLView drawlocked.
744		// This is not always the case if called from here.
745		mr->SwapBuffers();
746	}
747}
748
749
750struct msr_renderbuffer*
751MesaSoftwareRenderer::_NewRenderBuffer(bool front)
752{
753	CALLED();
754	struct msr_renderbuffer *msr
755		= (struct msr_renderbuffer*)calloc(1, sizeof *msr);
756
757	if (!msr) {
758		ERROR("%s: Failed calloc RenderBuffer\n", __func__);
759		return NULL;
760	}
761
762	_mesa_init_renderbuffer(&msr->base, 0);
763
764	if (_SetupRenderBuffer(msr, fColorSpace) != B_OK) {
765		free(msr);
766		return NULL;
767	}
768
769	if (front)
770		msr->base.AllocStorage = _FrontRenderbufferStorage;
771	else {
772		msr->base.AllocStorage = _BackRenderbufferStorage;
773		msr->base.Delete = _DeleteBackBuffer;
774	}
775
776	return msr;
777}
778
779
780status_t
781MesaSoftwareRenderer::_SetupRenderBuffer(
782	struct msr_renderbuffer* buffer, color_space colorSpace)
783{
784	CALLED();
785
786	buffer->base.DataType = GL_UNSIGNED_BYTE;
787	buffer->base.Data = NULL;
788
789	switch (colorSpace) {
790		case B_RGBA32:
791			buffer->base._BaseFormat = GL_RGBA;
792			buffer->base.Format = MESA_FORMAT_ARGB8888;
793
794			buffer->base.GetRow = get_row_RGBA32;
795			buffer->base.GetValues = get_values_RGBA32;
796			buffer->base.PutRow = put_row_RGBA32;
797			buffer->base.PutValues = put_values_RGBA32;
798			buffer->base.PutRowRGB = put_row_rgb_RGBA32;
799			buffer->base.PutMonoRow = put_mono_row_RGBA32;
800			buffer->base.PutMonoValues = put_values_RGBA32;
801			break;
802		case B_RGB32:
803			buffer->base._BaseFormat = GL_RGB;
804			buffer->base.Format = MESA_FORMAT_ARGB8888;
805
806			buffer->base.GetRow = get_row_RGB32;
807			buffer->base.GetValues = get_values_RGB32;
808			buffer->base.PutRow = put_row_RGB32;
809			buffer->base.PutValues = put_values_RGB32;
810			buffer->base.PutRowRGB = put_row_rgb_RGB32;
811			buffer->base.PutMonoRow = put_mono_row_RGB32;
812			buffer->base.PutMonoValues = put_values_RGB32;
813			break;
814		case B_RGB24:
815			buffer->base._BaseFormat = GL_RGB;
816			buffer->base.Format = MESA_FORMAT_RGB888;
817
818			buffer->base.GetRow = get_row_RGB24;
819			buffer->base.GetValues = get_values_RGB24;
820			buffer->base.PutRow = put_row_RGB24;
821			buffer->base.PutValues = put_values_RGB24;
822			buffer->base.PutRowRGB = put_row_rgb_RGB24;
823			buffer->base.PutMonoRow = put_mono_row_RGB24;
824			buffer->base.PutMonoValues = put_values_RGB24;
825			break;
826		case B_RGB16:
827			buffer->base._BaseFormat = GL_RGB;
828			buffer->base.Format = MESA_FORMAT_RGB565;
829
830			buffer->base.GetRow = get_row_RGB16;
831			buffer->base.GetValues = get_values_RGB16;
832			buffer->base.PutRow = put_row_RGB16;
833			buffer->base.PutValues = put_values_RGB16;
834			buffer->base.PutRowRGB = put_row_rgb_RGB16;
835			buffer->base.PutMonoRow = put_mono_row_RGB16;
836			buffer->base.PutMonoValues = put_values_RGB16;
837			break;
838		case B_RGB15:
839			buffer->base._BaseFormat = GL_RGB;
840			buffer->base.Format = MESA_FORMAT_ARGB1555;
841
842			buffer->base.GetRow = get_row_RGB15;
843			buffer->base.GetValues = get_values_RGB15;
844			buffer->base.PutRow = put_row_RGB15;
845			buffer->base.PutValues = put_values_RGB15;
846			buffer->base.PutRowRGB = put_row_rgb_RGB15;
847			buffer->base.PutMonoRow = put_mono_row_RGB15;
848			buffer->base.PutMonoValues = put_values_RGB15;
849			break;
850		default:
851			fprintf(stderr, "Unsupported screen color space %s\n",
852				color_space_name(fColorSpace));
853			debugger("Unsupported OpenGL color space");
854			return B_ERROR;
855	}
856	return B_OK;
857}
858
859
860void
861MesaSoftwareRenderer::_DeleteBackBuffer(struct gl_renderbuffer* rb)
862{
863	CALLED();
864	free(rb->Data);
865	free(rb);
866}
867
868
869void
870MesaSoftwareRenderer::_CopyToDirect()
871{
872	BAutolock lock(fInfoLocker);
873
874	// check the bitmap size still matches the size
875	if (fInfo->window_bounds.bottom - fInfo->window_bounds.top
876		!= fBitmap->Bounds().IntegerHeight()
877		|| fInfo->window_bounds.right - fInfo->window_bounds.left
878			!= fBitmap->Bounds().IntegerWidth())
879		return;
880
881	uint8 bytesPerPixel = fInfo->bits_per_pixel / 8;
882	uint32 bytesPerRow = fBitmap->BytesPerRow();
883	for (uint32 i = 0; i < fInfo->clip_list_count; i++) {
884		clipping_rect *clip = &fInfo->clip_list[i];
885		int32 height = clip->bottom - clip->top + 1;
886		int32 bytesWidth
887			= (clip->right - clip->left + 1) * bytesPerPixel;
888		uint8* p = (uint8*)fInfo->bits + clip->top
889			* fInfo->bytes_per_row + clip->left * bytesPerPixel;
890		uint8* b = (uint8*)fBitmap->Bits()
891			+ (clip->top - fInfo->window_bounds.top) * bytesPerRow
892			+ (clip->left - fInfo->window_bounds.left)
893				* bytesPerPixel;
894
895		for (int y = 0; y < height; y++) {
896			memcpy(p, b, bytesWidth);
897			p += fInfo->bytes_per_row;
898			b += bytesPerRow;
899		}
900	}
901}
902