diff options
author | Alexander von Gluck IV <[email protected]> | 2013-10-03 01:22:48 +0000 |
---|---|---|
committer | Alexander von Gluck IV <[email protected]> | 2013-10-04 18:20:09 -0500 |
commit | 8730236d1a900c9512a9ef92c08034f0223bcf92 (patch) | |
tree | 9d4ec570b0604811cc4431f0e0f5cab292939021 /src/gallium/targets | |
parent | c9f1217e1f2c309cfd8770940773f1f35582a795 (diff) |
haiku: Add first Haiku renderer (softpipe)
* This shared library gets parsed by the
system as a system "add-on"
Diffstat (limited to 'src/gallium/targets')
8 files changed, 1249 insertions, 4 deletions
diff --git a/src/gallium/targets/haiku-softpipe/GalliumContext.cpp b/src/gallium/targets/haiku-softpipe/GalliumContext.cpp new file mode 100644 index 00000000000..b7dd6855dc0 --- /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, [email protected] + * Alexander von Gluck IV, [email protected] + */ + + +#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 00000000000..88e9f81238e --- /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, [email protected] + */ +#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 00000000000..48af2c57495 --- /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, [email protected] + * Alexander von Gluck IV, [email protected] + */ + + +#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 00000000000..11e6b736571 --- /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, [email protected] + */ +#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 72a5ba79627..0a99976aef5 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 00000000000..16752c6237c --- /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, [email protected] + * Philippe Houdoin, [email protected] + * Artur Wyszynski, [email protected] + * Alexander von Gluck IV, [email protected] + */ + + +#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 00000000000..8427ce171fe --- /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, [email protected] + * Philippe Houdoin, [email protected] + * Artur Wyszynski, [email protected] + * Alexander von Gluck IV, [email protected] + */ +#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 00000000000..f9d01b2609a --- /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" +}; |