[Mesa-dev] [PATCH 2/6] haiku: Add first Haiku renderer (softpipe)

Alexander von Gluck IV kallisti5 at unixzen.com
Fri Oct 4 10:36:03 PDT 2013


* This shared library gets parsed by the
  system as a system "add-on"
---
 .../targets/haiku-softpipe/GalliumContext.cpp      | 528 +++++++++++++++++++++
 .../targets/haiku-softpipe/GalliumContext.h        |  83 ++++
 .../targets/haiku-softpipe/GalliumFramebuffer.cpp  | 116 +++++
 .../targets/haiku-softpipe/GalliumFramebuffer.h    |  34 ++
 src/gallium/targets/haiku-softpipe/SConscript      |  31 +-
 .../targets/haiku-softpipe/SoftwareRenderer.cpp    | 363 ++++++++++++++
 .../targets/haiku-softpipe/SoftwareRenderer.h      |  59 +++
 .../targets/haiku-softpipe/SoftwareRenderer.rdef   |  39 ++
 src/gallium/winsys/sw/hgl/SConscript               |   1 -
 9 files changed, 1249 insertions(+), 5 deletions(-)
 create mode 100644 src/gallium/targets/haiku-softpipe/GalliumContext.cpp
 create mode 100644 src/gallium/targets/haiku-softpipe/GalliumContext.h
 create mode 100644 src/gallium/targets/haiku-softpipe/GalliumFramebuffer.cpp
 create mode 100644 src/gallium/targets/haiku-softpipe/GalliumFramebuffer.h
 create mode 100644 src/gallium/targets/haiku-softpipe/SoftwareRenderer.cpp
 create mode 100644 src/gallium/targets/haiku-softpipe/SoftwareRenderer.h
 create mode 100644 src/gallium/targets/haiku-softpipe/SoftwareRenderer.rdef

diff --git a/src/gallium/targets/haiku-softpipe/GalliumContext.cpp b/src/gallium/targets/haiku-softpipe/GalliumContext.cpp
new file mode 100644
index 0000000..b7dd685
--- /dev/null
+++ b/src/gallium/targets/haiku-softpipe/GalliumContext.cpp
@@ -0,0 +1,528 @@
+/*
+ * Copyright 2012, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Artur Wyszynski, harakash at gmail.com
+ *		Alexander von Gluck IV, kallisti5 at unixzen.com
+ */
+
+
+#include "GalliumContext.h"
+
+#include "GLView.h"
+
+#include "bitmap_wrapper.h"
+#include "hgl_sw_winsys.h"
+extern "C" {
+#include "glapi/glapi.h"
+#include "main/context.h"
+#include "main/framebuffer.h"
+#include "main/renderbuffer.h"
+#include "pipe/p_format.h"
+#include "state_tracker/st_cb_fbo.h"
+#include "state_tracker/st_cb_flush.h"
+#include "state_tracker/st_context.h"
+#include "state_tracker/st_gl_api.h"
+#include "state_tracker/st_manager.h"
+#include "state_tracker/sw_winsys.h"
+#ifdef HAVE_LLVM
+#include "llvmpipe/lp_public.h"
+#else
+#include "softpipe/sp_public.h"
+#endif
+}
+
+
+#define TRACE_CONTEXT
+#ifdef TRACE_CONTEXT
+#	define TRACE(x...) printf("GalliumContext: " x)
+#	define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
+#else
+#	define TRACE(x...)
+#	define CALLED()
+#endif
+#define ERROR(x...) printf("GalliumContext: " x)
+
+
+static void
+hgl_viewport(struct gl_context* glContext, GLint x, GLint y,
+	GLsizei width, GLsizei height)
+{
+	TRACE("%s(glContext: %p, x: %d, y: %d, w: %d, h: %d\n", __func__,
+		glContext, x, y, width, height);
+
+	struct gl_framebuffer *draw = glContext->WinSysDrawBuffer;
+	struct gl_framebuffer *read = glContext->WinSysReadBuffer;
+
+	// TODO: SLOW! We need to check for changes in bitmap vs gl_framebuffer
+	// size before doing a _mesa_resize_framebuffer.
+	if (draw)
+		_mesa_resize_framebuffer(glContext, draw, width, height);
+	if (read)
+		_mesa_resize_framebuffer(glContext, read, width, height);
+}
+
+
+static st_visual*
+hgl_fill_st_visual(gl_config* glVisual)
+{
+	struct st_visual* stVisual = CALLOC_STRUCT(st_visual);
+	if (!stVisual) {
+		ERROR("%s: Couldn't allocate st_visual\n", __func__);
+		return NULL;
+	}
+
+	// Determine color format
+	if (glVisual->redBits == 8) {
+		if (glVisual->alphaBits == 8)
+			stVisual->color_format = PIPE_FORMAT_B8G8R8A8_UNORM;
+		else
+			stVisual->color_format = PIPE_FORMAT_B8G8R8X8_UNORM;
+	} else {
+		stVisual->color_format = PIPE_FORMAT_B5G6R5_UNORM;
+	}
+
+	// Determine depth stencil format
+	switch (glVisual->depthBits) {
+		default:
+		case 0:
+			stVisual->depth_stencil_format = PIPE_FORMAT_NONE;
+			break;
+		case 16:
+			stVisual->depth_stencil_format = PIPE_FORMAT_Z16_UNORM;
+			break;
+		case 24:
+			if (glVisual->stencilBits == 0) {
+				stVisual->depth_stencil_format = PIPE_FORMAT_Z24X8_UNORM;
+				// or PIPE_FORMAT_X8Z24_UNORM?
+			} else {
+				stVisual->depth_stencil_format = PIPE_FORMAT_Z24_UNORM_S8_UINT;
+				// or PIPE_FORMAT_S8_UINT_Z24_UNORM?
+			}
+			break;
+		case 32:
+			stVisual->depth_stencil_format = PIPE_FORMAT_Z32_UNORM;
+			break;
+	}
+
+	stVisual->accum_format = (glVisual->haveAccumBuffer)
+		? PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE;
+
+	stVisual->buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK;
+	stVisual->render_buffer = ST_ATTACHMENT_FRONT_LEFT;
+	if (glVisual->doubleBufferMode) {
+		stVisual->buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
+		stVisual->render_buffer = ST_ATTACHMENT_BACK_LEFT;
+	}
+
+	if (glVisual->stereoMode) {
+		stVisual->buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK;
+		if (glVisual->doubleBufferMode)
+			stVisual->buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK;
+	}
+
+	if (glVisual->haveDepthBuffer || glVisual->haveStencilBuffer)
+		stVisual->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK;
+
+	return stVisual;
+}
+
+
+static INLINE unsigned
+round_up(unsigned n, unsigned multiple)
+{
+	return (n + multiple - 1) & ~(multiple - 1);
+}
+
+
+static int
+hook_stm_get_param(struct st_manager *smapi, enum st_manager_param param)
+{
+	CALLED();
+
+	switch (param) {
+		case ST_MANAGER_BROKEN_INVALIDATE:
+			TRACE("%s: TODO: How should we handle BROKEN_INVALIDATE calls?\n",
+				__func__);
+			// For now we force validation of the framebuffer.
+			return 1;
+	}
+
+	return 0;
+}
+
+
+GalliumContext::GalliumContext(ulong options)
+	:
+	fOptions(options),
+	fCurrentContext(0),
+	fScreen(NULL)
+{
+	CALLED();
+
+	// Make all contexts a known value
+	for (context_id i = 0; i < CONTEXT_MAX; i++)
+		fContext[i] = NULL;
+
+	CreateScreen();
+
+	pipe_mutex_init(fMutex);
+}
+
+
+GalliumContext::~GalliumContext()
+{
+	CALLED();
+
+	// Destroy our contexts
+	pipe_mutex_lock(fMutex);
+	for (context_id i = 0; i < CONTEXT_MAX; i++)
+		DestroyContext(i);
+	pipe_mutex_unlock(fMutex);
+
+	pipe_mutex_destroy(fMutex);
+
+	// TODO: Destroy fScreen
+}
+
+
+status_t
+GalliumContext::CreateScreen()
+{
+	CALLED();
+
+	// Allocate winsys and attach callback hooks
+	struct sw_winsys* winsys = hgl_create_sw_winsys();
+
+	if (!winsys) {
+		ERROR("%s: Couldn't allocate sw_winsys!\n", __func__);
+		return B_ERROR;
+	}
+
+	#ifdef HAVE_LLVM
+	fScreen = llvmpipe_create_screen(winsys);
+	#else
+	fScreen = softpipe_create_screen(winsys);
+	#endif
+
+	if (fScreen == NULL) {
+		ERROR("%s: Couldn't create screen!\n", __FUNCTION__);
+		FREE(winsys);
+		return B_ERROR;
+	}
+
+	const char* driverName = fScreen->get_name(fScreen);
+	ERROR("%s: Using %s driver.\n", __func__, driverName);
+
+	return B_OK;
+}
+
+
+context_id
+GalliumContext::CreateContext(Bitmap *bitmap)
+{
+	CALLED();
+
+	struct hgl_context* context = CALLOC_STRUCT(hgl_context);
+
+	if (!context) {
+		ERROR("%s: Couldn't create pipe context!\n", __FUNCTION__);
+		return 0;
+	}
+
+	// Set up the initial things our context needs
+	context->bitmap = bitmap;
+	context->colorSpace = get_bitmap_color_space(bitmap);
+	context->draw = NULL;
+	context->read = NULL;
+	context->st = NULL;
+
+	context->api = st_gl_api_create();
+	if (!context->api) {
+		ERROR("%s: Couldn't obtain Mesa state tracker API!\n", __func__);
+		return -1;
+	}
+
+	context->manager = CALLOC_STRUCT(st_manager);
+	if (!context->manager) {
+		ERROR("%s: Couldn't allocate Mesa state tracker manager!\n", __func__);
+		return -1;
+	}
+	context->manager->get_param = hook_stm_get_param;
+
+	// Calculate visual configuration
+	const GLboolean rgbFlag		= ((fOptions & BGL_INDEX) == 0);
+	const GLboolean alphaFlag	= ((fOptions & BGL_ALPHA) == BGL_ALPHA);
+	const GLboolean dblFlag		= ((fOptions & BGL_DOUBLE) == BGL_DOUBLE);
+	const GLboolean stereoFlag	= false;
+	const GLint depth			= (fOptions & BGL_DEPTH) ? 24 : 0;
+	const GLint stencil			= (fOptions & BGL_STENCIL) ? 8 : 0;
+	const GLint accum			= 0;		// (options & BGL_ACCUM) ? 16 : 0;
+	const GLint red				= rgbFlag ? 8 : 0;
+	const GLint green			= rgbFlag ? 8 : 0;
+	const GLint blue			= rgbFlag ? 8 : 0;
+	const GLint alpha			= alphaFlag ? 8 : 0;
+
+	TRACE("rgb      :\t%d\n", (bool)rgbFlag);
+	TRACE("alpha    :\t%d\n", (bool)alphaFlag);
+	TRACE("dbl      :\t%d\n", (bool)dblFlag);
+	TRACE("stereo   :\t%d\n", (bool)stereoFlag);
+	TRACE("depth    :\t%d\n", depth);
+	TRACE("stencil  :\t%d\n", stencil);
+	TRACE("accum    :\t%d\n", accum);
+	TRACE("red      :\t%d\n", red);
+	TRACE("green    :\t%d\n", green);
+	TRACE("blue     :\t%d\n", blue);
+	TRACE("alpha    :\t%d\n", alpha);
+
+	gl_config* glVisual = _mesa_create_visual(dblFlag, stereoFlag, red, green,
+		blue, alpha, depth, stencil, accum, accum, accum, alpha ? accum : 0, 1);
+
+	if (!glVisual) {
+		ERROR("%s: Couldn't create Mesa visual!\n", __func__);
+		return -1;
+	}
+
+	TRACE("depthBits   :\t%d\n", glVisual->depthBits);
+	TRACE("stencilBits :\t%d\n", glVisual->stencilBits);
+
+	// Convert Mesa calculated visual into state tracker visual
+	context->stVisual = hgl_fill_st_visual(glVisual);
+
+	context->draw = new GalliumFramebuffer(context->stVisual, (void*)this);
+	context->read = new GalliumFramebuffer(context->stVisual, (void*)this);
+
+	if (!context->draw || !context->read) {
+		ERROR("%s: Problem allocating framebuffer!\n", __func__);
+		_mesa_destroy_visual(glVisual);
+		return -1;
+	}
+
+	// We need to assign the screen *before* calling st_api create_context
+	context->manager->screen = fScreen;
+
+	// Build state tracker attributes
+	struct st_context_attribs attribs;
+	memset(&attribs, 0, sizeof(attribs));
+	attribs.options.force_glsl_extensions_warn = false;
+	attribs.profile = ST_PROFILE_DEFAULT;
+	attribs.visual = *context->stVisual;
+	attribs.major = 1;
+	attribs.minor = 0;
+	//attribs.flags |= ST_CONTEXT_FLAG_DEBUG;
+
+	struct st_api* api = context->api;
+
+	// Create context using state tracker api call
+	enum st_context_error result;
+	context->st = api->create_context(api, context->manager, &attribs,
+		&result, context->st);
+
+	if (!context->st) {
+		ERROR("%s: Couldn't create mesa state tracker context!\n",
+			__func__);
+		switch (result) {
+			case ST_CONTEXT_SUCCESS:
+				ERROR("%s: State tracker error: SUCCESS?\n", __func__);
+				break;
+			case ST_CONTEXT_ERROR_NO_MEMORY:
+				ERROR("%s: State tracker error: NO_MEMORY\n", __func__);
+				break;
+			case ST_CONTEXT_ERROR_BAD_API:
+				ERROR("%s: State tracker error: BAD_API\n", __func__);
+				break;
+			case ST_CONTEXT_ERROR_BAD_VERSION:
+				ERROR("%s: State tracker error: BAD_VERSION\n", __func__);
+				break;
+			case ST_CONTEXT_ERROR_BAD_FLAG:
+				ERROR("%s: State tracker error: BAD_FLAG\n", __func__);
+				break;
+			case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE:
+				ERROR("%s: State tracker error: BAD_ATTRIBUTE\n", __func__);
+				break;
+			case ST_CONTEXT_ERROR_UNKNOWN_FLAG:
+				ERROR("%s: State tracker error: UNKNOWN_FLAG\n", __func__);
+				break;
+		}
+
+		FREE(context);
+		return -1;
+	}
+
+	// Init Gallium3D Post Processing
+	//context->postProcess = pp_init(fScreen, context->postProcessEnable);
+
+	assert(!context->st->st_manager_private);
+	context->st->st_manager_private = (void*)this;
+
+	struct st_context *stContext = (struct st_context*)context->st;
+	
+	stContext->ctx->Driver.Viewport = hgl_viewport;
+
+	// TODO: Closely review this next context logic...
+	context_id contextNext = -1;
+
+	pipe_mutex_lock(fMutex);
+	for (context_id i = 0; i < CONTEXT_MAX; i++) {
+		if (fContext[i] == NULL) {
+			fContext[i] = context;
+			contextNext = i;
+			break;
+		}
+	}
+	pipe_mutex_unlock(fMutex);
+
+	if (contextNext < 0) {
+		ERROR("%s: The next context is invalid... something went wrong!\n",
+			__func__);
+		//st_destroy_context(context->st);
+		FREE(context);
+		_mesa_destroy_visual(glVisual);
+		return -1;
+	}
+
+	TRACE("%s: context #%" B_PRIu64 " is the next available context\n",
+		__func__, contextNext);
+
+	return contextNext;
+}
+
+
+void
+GalliumContext::DestroyContext(context_id contextID)
+{
+	// fMutex should be locked *before* calling DestoryContext
+
+	// See if context is used
+	if (!fContext[contextID])
+		return;
+
+	if (fContext[contextID]->st) {
+		fContext[contextID]->st->flush(fContext[contextID]->st, 0, NULL);
+		fContext[contextID]->st->destroy(fContext[contextID]->st);
+	}
+
+	if (fContext[contextID]->postProcess)
+		pp_free(fContext[contextID]->postProcess);
+
+	// Delete framebuffer objects
+	if (fContext[contextID]->read)
+		delete fContext[contextID]->read;
+	if (fContext[contextID]->draw)
+		delete fContext[contextID]->draw;
+
+	if (fContext[contextID]->stVisual)
+		FREE(fContext[contextID]->stVisual);
+
+	if (fContext[contextID]->manager)
+		FREE(fContext[contextID]->manager);
+
+	FREE(fContext[contextID]);
+}
+
+
+status_t
+GalliumContext::SetCurrentContext(Bitmap *bitmap, context_id contextID)
+{
+	CALLED();
+
+	if (contextID < 0 || contextID > CONTEXT_MAX) {
+		ERROR("%s: Invalid context ID range!\n", __func__);
+		return B_ERROR;
+	}
+
+	pipe_mutex_lock(fMutex);
+	context_id oldContextID = fCurrentContext;
+	struct hgl_context* context = fContext[contextID];
+	pipe_mutex_unlock(fMutex);
+
+	if (!context) {
+		ERROR("%s: Invalid context provided (#%" B_PRIu64 ")!\n",
+			__func__, contextID);
+		return B_ERROR;
+	}
+
+	struct st_api* api = context->api;
+
+	if (!bitmap) {
+		api->make_current(context->api, NULL, NULL, NULL);
+		return B_OK;
+	}
+
+	// Everything seems valid, lets set the new context.
+	fCurrentContext = contextID;
+
+	if (oldContextID > 0 && oldContextID != contextID) {
+		fContext[oldContextID]->st->flush(fContext[oldContextID]->st,
+			ST_FLUSH_FRONT, NULL);
+	}
+
+	// We need to lock and unlock framebuffers before accessing them
+	context->draw->Lock();
+	context->read->Lock();
+	api->make_current(context->api, context->st, context->draw->fBuffer,
+		context->read->fBuffer);
+	context->draw->Unlock();
+	context->read->Unlock();
+
+	// TODO: Init textures before post-processing them
+	#if 0
+	pp_init_fbos(context->postProcess,
+		context->textures[ST_ATTACHMENT_BACK_LEFT]->width0,
+		context->textures[ST_ATTACHMENT_BACK_LEFT]->height0);
+	#endif
+
+	context->bitmap = bitmap;
+	//context->st->pipe->priv = context;
+
+	return B_OK;
+}
+
+
+status_t
+GalliumContext::SwapBuffers(context_id contextID)
+{
+	CALLED();
+
+	pipe_mutex_lock(fMutex);
+	struct hgl_context *context = fContext[contextID];
+	pipe_mutex_unlock(fMutex);
+
+	if (!context) {
+		ERROR("%s: context not found\n", __func__);
+		return B_ERROR;
+	}
+
+	// TODO: Where did st_notify_swapbuffers go?
+	//st_notify_swapbuffers(context->draw->stfb);
+
+	context->st->flush(context->st, ST_FLUSH_FRONT, NULL);
+
+	struct st_context *stContext = (struct st_context*)context->st;
+
+	unsigned nColorBuffers = stContext->state.framebuffer.nr_cbufs;
+	for (unsigned i = 0; i < nColorBuffers; i++) {
+		pipe_surface* surface = stContext->state.framebuffer.cbufs[i];
+		if (!surface) {
+			ERROR("%s: Color buffer %d invalid!\n", __func__, i);
+			continue;
+		}
+
+		TRACE("%s: Flushing color buffer #%d\n", __func__, i);
+
+		// We pass our destination bitmap to flush_fronbuffer which passes it
+		// to the private winsys display call.
+		fScreen->flush_frontbuffer(fScreen, surface->texture, 0, 0,
+			context->bitmap);
+	}
+
+	#if 0
+	// TODO... should we flush the z stencil buffer?
+	pipe_surface* zSurface = stContext->state.framebuffer.zsbuf;
+	fScreen->flush_frontbuffer(fScreen, surface->texture, 0, 0,
+		context->bitmap);
+	#endif
+
+	return B_OK;
+}
diff --git a/src/gallium/targets/haiku-softpipe/GalliumContext.h b/src/gallium/targets/haiku-softpipe/GalliumContext.h
new file mode 100644
index 0000000..88e9f81
--- /dev/null
+++ b/src/gallium/targets/haiku-softpipe/GalliumContext.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2009, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Alexander von Gluck IV, kallisti5 at unixzen.com
+ */
+#ifndef GALLIUMCONTEXT_H
+#define GALLIUMCONTEXT_H
+
+
+#include <stddef.h>
+#include <kernel/image.h>
+
+extern "C" {
+#include "state_tracker/st_api.h"
+#include "pipe/p_compiler.h"
+#include "pipe/p_screen.h"
+#include "postprocess/filters.h"
+#include "os/os_thread.h"
+}
+#include "bitmap_wrapper.h"
+#include "GalliumFramebuffer.h"
+
+
+#define CONTEXT_MAX 32
+
+
+typedef int64 context_id;
+
+struct hgl_context
+{
+	struct st_api* api;
+		// State Tracker API
+	struct st_manager* manager;
+		// State Tracker Manager
+	struct st_context_iface* st;
+		// State Tracker Interface Object
+	struct st_visual* stVisual;
+		// State Tracker Visual
+
+	struct pipe_resource* textures[ST_ATTACHMENT_COUNT];
+
+	// Post processing
+	struct pp_queue_t* postProcess;
+	unsigned int postProcessEnable[PP_FILTERS];
+
+	Bitmap* bitmap;
+	color_space colorSpace;
+
+	GalliumFramebuffer* draw;
+	GalliumFramebuffer* read;
+};
+
+
+class GalliumContext {
+public:
+							GalliumContext(ulong options);
+							~GalliumContext();
+
+		context_id			CreateContext(Bitmap* bitmap);
+		void				DestroyContext(context_id contextID);
+		context_id			GetCurrentContext() { return fCurrentContext; };
+		status_t			SetCurrentContext(Bitmap *bitmap,
+								context_id contextID);
+
+		status_t			SwapBuffers(context_id contextID);
+
+private:
+		status_t			CreateScreen();
+		void				Flush();
+
+		ulong				fOptions;
+
+		struct hgl_context*	fContext[CONTEXT_MAX];
+		context_id			fCurrentContext;
+		
+		struct pipe_screen*	fScreen;
+		pipe_mutex			fMutex;
+};
+	
+
+#endif /* GALLIUMCONTEXT_H */
diff --git a/src/gallium/targets/haiku-softpipe/GalliumFramebuffer.cpp b/src/gallium/targets/haiku-softpipe/GalliumFramebuffer.cpp
new file mode 100644
index 0000000..48af2c5
--- /dev/null
+++ b/src/gallium/targets/haiku-softpipe/GalliumFramebuffer.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2012-2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *      Artur Wyszynski, harakash at gmail.com
+ *      Alexander von Gluck IV, kallisti5 at unixzen.com
+ */
+
+
+#include "GalliumFramebuffer.h"
+
+extern "C" {
+#include "main/context.h"
+#include "main/framebuffer.h"
+#include "main/renderbuffer.h"
+#include "pipe/p_format.h"
+}
+
+
+#define TRACE_FRAMEBUFFER
+#ifdef TRACE_FRAEMBUFFER
+#   define TRACE(x...) printf("GalliumFramebuffer: " x)
+#   define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
+#else
+#   define TRACE(x...)
+#   define CALLED()
+#endif
+#define ERROR(x...) printf("GalliumFramebuffer: " x)
+
+
+static boolean
+hgl_framebuffer_flush_front(struct st_context_iface *stctx,
+	struct st_framebuffer_iface* stfb, enum st_attachment_type statt)
+{
+	CALLED();
+	// TODO: I have *NO* idea how we are going to access this data...
+
+	#if 0
+	struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
+	pipe_mutex_lock(stwfb->fb->mutex);
+
+	struct pipe_resource* resource = textures[statt];
+	if (resource)
+		stw_framebuffer_present_locked(...);
+	#endif
+
+	return TRUE;
+}
+
+
+static boolean
+hgl_framebuffer_validate(struct st_context_iface* stctx,
+	struct st_framebuffer_iface* stfb,
+	const enum st_attachment_type* statts, unsigned count,
+	struct pipe_resource** out)
+{
+	CALLED();
+
+	return TRUE;
+}
+
+
+GalliumFramebuffer::GalliumFramebuffer(struct st_visual* visual,
+	void* privateContext)
+	:
+	fBuffer(NULL)
+{
+	CALLED();
+	fBuffer = CALLOC_STRUCT(st_framebuffer_iface);
+	if (!fBuffer) {
+		ERROR("%s: Couldn't calloc framebuffer!\n", __func__);
+		return;
+	}
+	fBuffer->visual = visual;
+	fBuffer->flush_front = hgl_framebuffer_flush_front;
+	fBuffer->validate = hgl_framebuffer_validate;
+	fBuffer->st_manager_private = privateContext;
+
+	pipe_mutex_init(fMutex);
+}
+
+
+GalliumFramebuffer::~GalliumFramebuffer()
+{
+	CALLED();
+	// We lock and unlock to try and make sure we wait for anything
+	// using the framebuffer to finish
+	Lock();
+	if (!fBuffer) {
+		ERROR("%s: Strange, no Gallium Framebuffer to free?\n", __func__);
+		return;
+	}
+	FREE(fBuffer);
+	Unlock();
+
+	pipe_mutex_destroy(fMutex);
+}
+
+
+status_t
+GalliumFramebuffer::Lock()
+{
+	CALLED();
+	pipe_mutex_lock(fMutex);
+	return B_OK;
+}
+
+
+status_t
+GalliumFramebuffer::Unlock()
+{
+	CALLED();
+	pipe_mutex_unlock(fMutex);
+	return B_OK;
+}
diff --git a/src/gallium/targets/haiku-softpipe/GalliumFramebuffer.h b/src/gallium/targets/haiku-softpipe/GalliumFramebuffer.h
new file mode 100644
index 0000000..11e6b73
--- /dev/null
+++ b/src/gallium/targets/haiku-softpipe/GalliumFramebuffer.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *      Alexander von Gluck IV, kallisti5 at unixzen.com
+ */
+#ifndef GALLIUMFRAMEBUFFER_H
+#define GALLIUMFRAMEBUFFER_H
+
+
+extern "C" {
+#include "os/os_thread.h"
+#include "pipe/p_screen.h"
+#include "state_tracker/st_api.h"
+}
+
+
+class GalliumFramebuffer {
+public:
+							GalliumFramebuffer(struct st_visual* visual,
+								void* privateContext);
+							~GalliumFramebuffer();
+		status_t			Lock();
+		status_t			Unlock();
+
+		struct st_framebuffer_iface* fBuffer;
+
+private:
+		pipe_mutex			fMutex;
+};
+
+
+#endif /* GALLIUMFRAMEBUFFER_H */
diff --git a/src/gallium/targets/haiku-softpipe/SConscript b/src/gallium/targets/haiku-softpipe/SConscript
index 72a5ba7..0a99976 100644
--- a/src/gallium/targets/haiku-softpipe/SConscript
+++ b/src/gallium/targets/haiku-softpipe/SConscript
@@ -1,21 +1,44 @@
 Import('*')
 
+env.Prepend(LIBS = [
+    ws_haiku,
+    trace,
+    rbug,
+    mesa,
+    glsl,
+    gallium
+])
+
 if True:
     env.Append(CPPDEFINES = [
         'GALLIUM_SOFTPIPE',
         'GALLIUM_RBUG',
         'GALLIUM_TRACE',
     ])
+    env.Prepend(LIBS = [softpipe])
+
+env.Append(CPPPATH = [
+    '#/src/mapi',
+    '#/src/mesa',
+    '#/src/mesa/main',
+    '#/src/gallium/winsys/sw/hgl',
+    '/boot/system/develop/headers/private',
+])
 
 if env['llvm']:
     env.Append(CPPDEFINES = 'HAVE_LLVMPIPE')
 
 softpipe_sources = [
-    'haiku-softpipe.c'
+    'haiku-softpipe.c',
+    'GalliumContext.cpp',
+    'GalliumFramebuffer.cpp',
+    'SoftwareRenderer.cpp'
 ]
 
-module = env.StaticLibrary(
-    target ='swpipe_haiku.a',
+# libswpipe gets turned into "Software Renderer" by the haiku package system
+module = env.SharedLibrary(
+    target ='swpipe',
     source = softpipe_sources,
-    SHLIBPREFIX = '',
 )
+
+env.Alias('softpipe-haiku', module)
diff --git a/src/gallium/targets/haiku-softpipe/SoftwareRenderer.cpp b/src/gallium/targets/haiku-softpipe/SoftwareRenderer.cpp
new file mode 100644
index 0000000..16752c6
--- /dev/null
+++ b/src/gallium/targets/haiku-softpipe/SoftwareRenderer.cpp
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2006-2012, Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Jérôme Duval, korli at users.berlios.de
+ *		Philippe Houdoin, philippe.houdoin at free.fr
+ *		Artur Wyszynski, harakash at gmail.com
+ *		Alexander von Gluck IV, kallisti5 at unixzen.com
+ */
+
+
+#include "SoftwareRenderer.h"
+
+#include <Autolock.h>
+#include <interface/DirectWindowPrivate.h>
+#include <GraphicsDefs.h>
+#include <Screen.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <new>
+
+
+#define TRACE_SOFTWARE
+#ifdef TRACE_SOFTWARE
+#	define TRACE(x...) printf("SoftwareRenderer: " x)
+#	define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
+#else
+#	define TRACE(x...)
+#	define CALLED()
+#endif
+#define ERROR(x...)	printf("SoftwareRenderer: " x)
+
+
+extern const char* color_space_name(color_space space);
+
+
+extern "C" _EXPORT BGLRenderer*
+instantiate_gl_renderer(BGLView *view, ulong opts, BGLDispatcher *dispatcher)
+{
+	return new SoftwareRenderer(view, opts, dispatcher);
+}
+
+SoftwareRenderer::SoftwareRenderer(BGLView *view, ulong options,
+	BGLDispatcher* dispatcher)
+	:
+	BGLRenderer(view, options, dispatcher),
+	fBitmap(NULL),
+	fDirectModeEnabled(false),
+	fInfo(NULL),
+	fInfoLocker("info locker"),
+	fOptions(options),
+	fColorSpace(B_NO_COLOR_SPACE)
+{
+	CALLED();
+
+	// Disable double buffer for the moment.
+	options &= ~BGL_DOUBLE;
+
+	// Initialize the "Haiku Software GL Pipe"
+	time_t beg;
+	time_t end;
+	beg = time(NULL);
+	fContextObj = new GalliumContext(options);
+	end = time(NULL);
+	TRACE("Haiku Software GL Pipe initialization time: %f.\n",
+		difftime(end, beg));
+
+	// Allocate a bitmap
+	BRect b = view->Bounds();
+	fColorSpace = BScreen(view->Window()).ColorSpace();
+	TRACE("%s: Colorspace:\t%s\n", __func__, color_space_name(fColorSpace));
+
+	fWidth = (GLint)b.IntegerWidth();
+	fHeight = (GLint)b.IntegerHeight();
+	fNewWidth = fWidth;
+	fNewHeight = fHeight;
+
+	_AllocateBitmap();
+
+	// Initialize the first "Haiku Software GL Pipe" context
+	beg = time(NULL);
+	fContextID = fContextObj->CreateContext(fBitmap);
+	end = time(NULL);
+
+	if (fContextID < 0)
+		ERROR("%s: There was an error creating the context!\n", __func__);
+	else {
+		TRACE("%s: Haiku Software GL Pipe context creation time: %f.\n",
+			__func__, difftime(end, beg));
+	}
+
+	if (!fContextObj->GetCurrentContext())
+		LockGL();
+}
+
+
+SoftwareRenderer::~SoftwareRenderer()
+{
+	CALLED();
+
+	if (fContextObj)
+		delete fContextObj;
+	if (fBitmap)
+		delete fBitmap;
+}
+
+
+void
+SoftwareRenderer::LockGL()
+{
+//	CALLED();
+	BGLRenderer::LockGL();
+
+	color_space cs = BScreen(GLView()->Window()).ColorSpace();
+
+	BAutolock lock(fInfoLocker);
+	if (fDirectModeEnabled && fInfo != NULL) {
+		fNewWidth = fInfo->window_bounds.right - fInfo->window_bounds.left;
+			// + 1;
+		fNewHeight = fInfo->window_bounds.bottom - fInfo->window_bounds.top;
+			// + 1;
+	}
+
+	if (fBitmap && cs == fColorSpace && fNewWidth == fWidth
+		&& fNewHeight == fHeight) {
+		fContextObj->SetCurrentContext(fBitmap, fContextID);
+		return;
+	}
+
+	fColorSpace = cs;
+	fWidth = fNewWidth;
+	fHeight = fNewHeight;
+
+	_AllocateBitmap();
+	fContextObj->SetCurrentContext(fBitmap, fContextID);
+}
+
+
+void
+SoftwareRenderer::UnlockGL()
+{
+//	CALLED();
+	if ((fOptions & BGL_DOUBLE) == 0) {
+		SwapBuffers();
+	}
+	fContextObj->SetCurrentContext(NULL, fContextID);
+	BGLRenderer::UnlockGL();
+}
+
+
+void
+SoftwareRenderer::SwapBuffers(bool vsync)
+{
+//	CALLED();
+	if (!fBitmap)
+		return;
+
+	BScreen screen(GLView()->Window());
+
+	fContextObj->SwapBuffers(fContextID);
+
+	BAutolock lock(fInfoLocker);
+
+	if (!fDirectModeEnabled || fInfo == NULL) {
+		if (GLView()->LockLooperWithTimeout(1000) == B_OK) {
+			GLView()->DrawBitmap(fBitmap, B_ORIGIN);
+			GLView()->UnlockLooper();
+			if (vsync)
+				screen.WaitForRetrace();
+		}
+		return;
+	}
+
+	// check the bitmap size still matches the size
+	if (fInfo->window_bounds.bottom - fInfo->window_bounds.top
+			!= fBitmap->Bounds().IntegerHeight()
+			|| fInfo->window_bounds.right - fInfo->window_bounds.left
+			!= fBitmap->Bounds().IntegerWidth()) {
+		ERROR("%s: Bitmap size doesn't match size!\n", __func__);
+		return;
+	}
+	uint8 bytesPerPixel = fInfo->bits_per_pixel / 8;
+	uint32 bytesPerRow = fBitmap->BytesPerRow();
+	for (uint32 i = 0; i < fInfo->clip_list_count; i++) {
+		clipping_rect *clip = &fInfo->clip_list[i];
+		int32 height = clip->bottom - clip->top + 1;
+		int32 bytesWidth
+			= (clip->right - clip->left + 1) * bytesPerPixel;
+		bytesWidth -= bytesPerPixel;
+		uint8 *p = (uint8 *)fInfo->bits + clip->top
+			* fInfo->bytes_per_row + clip->left * bytesPerPixel;
+		uint8 *b = (uint8 *)fBitmap->Bits()
+			+ (clip->top - fInfo->window_bounds.top) * bytesPerRow
+			+ (clip->left - fInfo->window_bounds.left) * bytesPerPixel;
+
+		for (int y = 0; y < height - 1; y++) {
+			memcpy(p, b, bytesWidth);
+			p += fInfo->bytes_per_row;
+			b += bytesPerRow;
+		}
+	}
+
+	if (vsync)
+		screen.WaitForRetrace();
+}
+
+
+void
+SoftwareRenderer::Draw(BRect updateRect)
+{
+//	CALLED();
+	if ((!fDirectModeEnabled || fInfo == NULL) && fBitmap)
+		GLView()->DrawBitmap(fBitmap, updateRect, updateRect);
+}
+
+
+status_t
+SoftwareRenderer::CopyPixelsOut(BPoint location, BBitmap *bitmap)
+{
+	CALLED();
+	color_space scs = fBitmap->ColorSpace();
+	color_space dcs = bitmap->ColorSpace();
+
+	if (scs != dcs && (scs != B_RGBA32 || dcs != B_RGB32)) {
+		ERROR("%s::CopyPixelsOut(): incompatible color space: %s != %s\n",
+			__PRETTY_FUNCTION__, color_space_name(scs), color_space_name(dcs));
+		return B_BAD_TYPE;
+	}
+
+	BRect sr = fBitmap->Bounds();
+	BRect dr = bitmap->Bounds();
+
+//	int32 w1 = sr.IntegerWidth();
+//	int32 h1 = sr.IntegerHeight();
+//	int32 w2 = dr.IntegerWidth();
+//	int32 h2 = dr.IntegerHeight();
+
+	sr = sr & dr.OffsetBySelf(location);
+	dr = sr.OffsetByCopy(-location.x, -location.y);
+
+	uint8 *ps = (uint8 *) fBitmap->Bits();
+	uint8 *pd = (uint8 *) bitmap->Bits();
+	uint32 *s, *d;
+	uint32 y;
+	for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) {
+		s = (uint32 *)(ps + y * fBitmap->BytesPerRow());
+		s += (uint32) sr.left;
+
+		d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top))
+			* bitmap->BytesPerRow());
+		d += (uint32) dr.left;
+		memcpy(d, s, dr.IntegerWidth() * 4);
+	}
+
+	return B_OK;
+}
+
+
+status_t
+SoftwareRenderer::CopyPixelsIn(BBitmap *bitmap, BPoint location)
+{
+	CALLED();
+
+	color_space sourceCS = bitmap->ColorSpace();
+	color_space destinationCS = fBitmap->ColorSpace();
+
+	if (sourceCS != destinationCS
+		&& (sourceCS != B_RGB32 || destinationCS != B_RGBA32)) {
+		ERROR("%s::CopyPixelsIn(): incompatible color space: %s != %s\n",
+			__PRETTY_FUNCTION__, color_space_name(sourceCS),
+			color_space_name(destinationCS));
+		return B_BAD_TYPE;
+	}
+
+	BRect sr = bitmap->Bounds();
+	BRect dr = fBitmap->Bounds();
+
+	sr = sr & dr.OffsetBySelf(location);
+	dr = sr.OffsetByCopy(-location.x, -location.y);
+
+	uint8 *ps = (uint8 *) bitmap->Bits();
+	uint8 *pd = (uint8 *) fBitmap->Bits();
+	uint32 *s, *d;
+	uint32 y;
+
+	for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) {
+		s = (uint32 *)(ps + y * bitmap->BytesPerRow());
+		s += (uint32) sr.left;
+
+		d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top))
+			* fBitmap->BytesPerRow());
+		d += (uint32) dr.left;
+
+		memcpy(d, s, dr.IntegerWidth() * 4);
+	}
+
+	return B_OK;
+}
+
+
+void
+SoftwareRenderer::EnableDirectMode(bool enabled)
+{
+	fDirectModeEnabled = enabled;
+}
+
+
+void
+SoftwareRenderer::DirectConnected(direct_buffer_info *info)
+{
+//	CALLED();
+	BAutolock lock(fInfoLocker);
+	if (info) {
+		if (!fInfo) {
+			fInfo = (direct_buffer_info *)calloc(1,
+				DIRECT_BUFFER_INFO_AREA_SIZE);
+		}
+		memcpy(fInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
+	} else if (fInfo) {
+		free(fInfo);
+		fInfo = NULL;
+	}
+}
+
+
+void
+SoftwareRenderer::FrameResized(float width, float height)
+{
+//	CALLED();
+	BAutolock lock(fInfoLocker);
+	fNewWidth = (GLuint)width;
+	fNewHeight = (GLuint)height;
+}
+
+
+void
+SoftwareRenderer::_AllocateBitmap()
+{
+//	CALLED();
+
+	// allocate new size of back buffer bitmap
+	BAutolock lock(fInfoLocker);
+	delete fBitmap;
+	fBitmap = NULL;
+	if (fWidth < 1 || fHeight < 1) {
+		TRACE("%s: Can't allocate bitmap of %dx%d\n", __func__,
+			fWidth, fHeight);
+		return;
+	}
+	BRect rect(0.0, 0.0, fWidth, fHeight);
+	fBitmap = new (std::nothrow) BBitmap(rect, fColorSpace);
+	if (fBitmap == NULL) {
+		TRACE("%s: Can't create bitmap!\n", __func__);
+		return;
+	}
+
+#if 0
+	// debug..
+	void *data = fBitmap->Bits();
+	memset(data, 0xcc, fBitmap->BitsLength());
+#endif
+}
diff --git a/src/gallium/targets/haiku-softpipe/SoftwareRenderer.h b/src/gallium/targets/haiku-softpipe/SoftwareRenderer.h
new file mode 100644
index 0000000..8427ce1
--- /dev/null
+++ b/src/gallium/targets/haiku-softpipe/SoftwareRenderer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2006-2012, Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Jérôme Duval, korli at users.berlios.de
+ * 		Philippe Houdoin, philippe.houdoin at free.fr
+ * 		Artur Wyszynski, harakash at gmail.com
+ *		Alexander von Gluck IV, kallisti5 at unixzen.com
+ */
+#ifndef SOFTWARERENDERER_H
+#define SOFTWARERENDERER_H
+
+
+#include <kernel/image.h>
+
+#include "GLRenderer.h"
+#include "GalliumContext.h"
+
+
+class SoftwareRenderer : public BGLRenderer {
+public:
+								SoftwareRenderer(BGLView *view,
+									ulong bgl_options,
+									BGLDispatcher *dispatcher);
+	virtual						~SoftwareRenderer();
+
+	virtual	void				LockGL();
+	virtual	void				UnlockGL();
+
+	virtual	void				SwapBuffers(bool vsync = false);
+	virtual	void				Draw(BRect updateRect);
+	virtual	status_t			CopyPixelsOut(BPoint source, BBitmap *dest);
+	virtual	status_t			CopyPixelsIn(BBitmap *source, BPoint dest);
+	virtual	void				FrameResized(float width, float height);
+
+	virtual	void				EnableDirectMode(bool enabled);
+	virtual	void				DirectConnected(direct_buffer_info *info);
+
+private:
+
+			void				_AllocateBitmap();
+
+			GalliumContext*		fContextObj;
+			BBitmap*			fBitmap;
+			context_id			fContextID;
+
+			bool				fDirectModeEnabled;
+			direct_buffer_info*	fInfo;
+			BLocker				fInfoLocker;
+			ulong				fOptions;			
+			GLuint				fWidth;
+			GLuint				fHeight;
+			GLuint				fNewWidth;
+			GLuint				fNewHeight;
+			color_space			fColorSpace;
+};
+
+#endif	// SOFTPIPERENDERER_H
diff --git a/src/gallium/targets/haiku-softpipe/SoftwareRenderer.rdef b/src/gallium/targets/haiku-softpipe/SoftwareRenderer.rdef
new file mode 100644
index 0000000..f9d01b2
--- /dev/null
+++ b/src/gallium/targets/haiku-softpipe/SoftwareRenderer.rdef
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012, Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+
+resource app_signature "application/x-vnd.Haiku-swpipe";
+
+resource app_version {
+    major  = 9,
+    middle = 0,
+    minor  = 0,
+    variety = 0,
+    internal = 0,
+    short_info = "Software Renderer",
+    long_info = "Haiku Gallium Software GL Renderer"
+};
+
+resource vector_icon {
+	$"6E6369660A0200140294A9FF18020014028DFFFF97058C0500020006023B10B7"
+	$"37F036BA1A993D466848C719BEBE2000919292FFD5D5D5020016023900000000"
+	$"000000003EE0004AE00048E0005EF884C702000203392E8D383001BAD97F3C12"
+	$"8B4786BD48B8AD0D97BBFFFF7B4168DBE9FF4168DB97020002023A0C1238D099"
+	$"BE44203F4BD14B38844678240DF56A7D9FE1EA064CC704016B0500090A044024"
+	$"2438404C5C380A044028243C40505C3C0A042438243B5C3C5C380608BFBE4D59"
+	$"4D59515957575659585560406044603C5E3A5C3CCB4FBFBA5E3ECA9DC11F564B"
+	$"584A544C504C0606AF0F2F3D2F3D393D4034BF593542324130432F42364432C0"
+	$"3FBC5A2F48354A2F480608AE9A22303EB5BD3AB42542B755422E412F3C29322D"
+	$"32223C0204263726372538263F253E263F304430443143303C313D303C02043D"
+	$"423D423C433D4A3C493D4A495049504A4F49474A484947060DAEAAAE014E445A"
+	$"3456365E325E3D5D3F5A3A5542544E4D573A4E364439463342324A2242310A0A"
+	$"0002020102403CA00C88888C8CC1401673C40D6544F2950A01010002403CA000"
+	$"0000000000401673C40D65446CF80A08020304023EC16A0000000000003EC16A"
+	$"45DD1844C6550A030105123EC16A0000000000003EC16A45DD1844C655011784"
+	$"22040A040105023EC16A0000000000003EC16A45DD1844C6550A030108123EC1"
+	$"6A0000000000003EC16A45DD1844C65501178422040A0503080706023EC16A00"
+	$"00000000003EC16A45DD1844C6550A030206071A3EC16A0000000000003EC16A"
+	$"45DD1844C65510FF0215810004178222040A060106023EC16A0000000000003E"
+	$"C16A45DD1844C6550A070107023EC16A0000000000003EC16A45DD1844C655"
+};
diff --git a/src/gallium/winsys/sw/hgl/SConscript b/src/gallium/winsys/sw/hgl/SConscript
index e881257..44080a6 100644
--- a/src/gallium/winsys/sw/hgl/SConscript
+++ b/src/gallium/winsys/sw/hgl/SConscript
@@ -21,5 +21,4 @@ if env['platform'] in ('haiku'):
            'bitmap_wrapper.cpp',
         ]
     )
-    env.Alias('ws_haiku', ws_haiku)
     Export('ws_haiku')
-- 
1.8.4



More information about the mesa-dev mailing list